6 #if !defined(JSON_IS_AMALGAMATION)
11 #endif // if !defined(JSON_IS_AMALGAMATION)
21 #if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
22 #define snprintf _snprintf
25 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
27 #pragma warning(disable : 4996)
41 : allowComments_(true), strictRoot_(false)
56 for (; begin < end; ++begin)
57 if (*begin ==
'\n' || *begin ==
'\r')
66 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
67 lastValue_(), commentsBefore_(), features_(
Features::all()),
71 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
72 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
78 const char* begin = document_.c_str();
79 const char* end = begin + document_.length();
80 return parse(begin, end, root, collectComments);
92 std::getline(sin, doc, (
char)EOF);
93 return parse(doc, root, collectComments);
99 bool collectComments) {
101 collectComments =
false;
106 collectComments_ = collectComments;
110 commentsBefore_ =
"";
112 while (!nodes_.empty())
117 bool successful = readValue();
119 skipCommentTokens(token);
120 if (collectComments_ && !commentsBefore_.empty())
126 token.type_ = tokenError;
127 token.start_ = beginDoc;
130 "A valid JSON document must be either an array or an object value.",
138 bool Reader::readValue() {
147 skipCommentTokens(token);
148 bool successful =
true;
150 if (collectComments_ && !commentsBefore_.empty()) {
152 commentsBefore_ =
"";
155 switch (token.type_) {
156 case tokenObjectBegin:
157 successful = readObject(token);
159 case tokenArrayBegin:
160 successful = readArray(token);
163 successful = decodeNumber(token);
166 successful = decodeString(token);
188 return addError(
"Syntax error: value, object or array expected.", token);
191 if (collectComments_) {
192 lastValueEnd_ = current_;
193 lastValue_ = ¤tValue();
200 void Reader::skipCommentTokens(Token& token) {
204 }
while (token.type_ == tokenComment);
210 bool Reader::readToken(Token& token) {
212 token.start_ = current_;
213 Char c = getNextChar();
217 token.type_ = tokenObjectBegin;
220 token.type_ = tokenObjectEnd;
223 token.type_ = tokenArrayBegin;
226 token.type_ = tokenArrayEnd;
229 token.type_ = tokenString;
233 token.type_ = tokenComment;
247 token.type_ = tokenNumber;
251 token.type_ = tokenTrue;
252 ok = match(
"rue", 3);
255 token.type_ = tokenFalse;
256 ok = match(
"alse", 4);
259 token.type_ = tokenNull;
260 ok = match(
"ull", 3);
263 token.type_ = tokenArraySeparator;
266 token.type_ = tokenMemberSeparator;
269 token.type_ = tokenEndOfStream;
276 token.type_ = tokenError;
277 token.end_ = current_;
281 void Reader::skipSpaces() {
282 while (current_ != end_) {
284 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n')
291 bool Reader::match(Location pattern,
int patternLength) {
292 if (end_ - current_ < patternLength)
294 int index = patternLength;
296 if (current_[index] != pattern[index])
298 current_ += patternLength;
302 bool Reader::readComment() {
303 Location commentBegin = current_ - 1;
304 Char c = getNextChar();
305 bool successful =
false;
307 successful = readCStyleComment();
309 successful = readCppStyleComment();
313 if (collectComments_) {
320 addComment(commentBegin, current_, placement);
326 std::string normalized;
327 normalized.reserve(end - begin);
329 while (current != end) {
332 if (current != end && *current ==
'\n')
345 Reader::addComment(Location begin, Location end,
CommentPlacement placement) {
346 assert(collectComments_);
347 const std::string& normalized =
normalizeEOL(begin, end);
349 assert(lastValue_ != 0);
350 lastValue_->
setComment(normalized, placement);
352 commentsBefore_ += normalized;
356 bool Reader::readCStyleComment() {
357 while (current_ != end_) {
358 Char c = getNextChar();
359 if (c ==
'*' && *current_ ==
'/')
362 return getNextChar() ==
'/';
365 bool Reader::readCppStyleComment() {
366 while (current_ != end_) {
367 Char c = getNextChar();
372 if (current_ != end_ && *current_ ==
'\n')
381 void Reader::readNumber() {
382 const char *p = current_;
385 while (c >=
'0' && c <=
'9')
386 c = (current_ = p) < end_ ? *p++ : 0;
389 c = (current_ = p) < end_ ? *p++ : 0;
390 while (c >=
'0' && c <=
'9')
391 c = (current_ = p) < end_ ? *p++ : 0;
394 if (c ==
'e' || c ==
'E') {
395 c = (current_ = p) < end_ ? *p++ : 0;
396 if (c ==
'+' || c ==
'-')
397 c = (current_ = p) < end_ ? *p++ : 0;
398 while (c >=
'0' && c <=
'9')
399 c = (current_ = p) < end_ ? *p++ : 0;
403 bool Reader::readString() {
405 while (current_ != end_) {
415 bool Reader::readObject(Token& ) {
420 while (readToken(tokenName)) {
421 bool initialTokenOk =
true;
422 while (tokenName.type_ == tokenComment && initialTokenOk)
423 initialTokenOk = readToken(tokenName);
426 if (tokenName.type_ == tokenObjectEnd && name.empty())
429 if (tokenName.type_ == tokenString) {
430 if (!decodeString(tokenName, name))
431 return recoverFromError(tokenObjectEnd);
437 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
438 return addErrorAndRecover(
439 "Missing ':' after object member name", colon, tokenObjectEnd);
441 Value& value = currentValue()[name];
443 bool ok = readValue();
446 return recoverFromError(tokenObjectEnd);
449 if (!readToken(comma) ||
450 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
451 comma.type_ != tokenComment)) {
452 return addErrorAndRecover(
453 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
455 bool finalizeTokenOk =
true;
456 while (comma.type_ == tokenComment && finalizeTokenOk)
457 finalizeTokenOk = readToken(comma);
458 if (comma.type_ == tokenObjectEnd)
461 return addErrorAndRecover(
462 "Missing '}' or object member name", tokenName, tokenObjectEnd);
465 bool Reader::readArray(Token& ) {
469 if (*current_ ==
']')
477 Value& value = currentValue()[index++];
479 bool ok = readValue();
482 return recoverFromError(tokenArrayEnd);
486 ok = readToken(token);
487 while (token.type_ == tokenComment && ok) {
488 ok = readToken(token);
491 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
492 if (!ok || badTokenType) {
493 return addErrorAndRecover(
494 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
496 if (token.type_ == tokenArrayEnd)
502 bool Reader::decodeNumber(Token& token) {
504 if (!decodeNumber(token, decoded))
510 bool Reader::decodeNumber(Token& token, Value& decoded) {
515 bool isNegative = *current ==
'-';
521 : Value::maxLargestUInt;
522 Value::LargestUInt threshold = maxIntegerValue / 10;
523 Value::LargestUInt value = 0;
524 while (current < token.end_) {
526 if (c < '0' || c >
'9')
527 return decodeDouble(token, decoded);
529 if (value >= threshold) {
534 if (value > threshold || current != token.end_ ||
535 digit > maxIntegerValue % 10) {
536 return decodeDouble(token, decoded);
539 value = value * 10 + digit;
550 bool Reader::decodeDouble(Token& token) {
552 if (!decodeDouble(token, decoded))
558 bool Reader::decodeDouble(Token& token, Value& decoded) {
560 std::string buffer(token.start_, token.end_);
561 std::istringstream is(buffer);
563 return addError(
"'" + std::string(token.start_, token.end_) +
564 "' is not a number.",
570 bool Reader::decodeString(Token& token) {
571 std::string decoded_string;
572 if (!decodeString(token, decoded_string))
574 Value decoded(decoded_string);
579 bool Reader::decodeString(Token& token, std::string& decoded) {
580 decoded.reserve(token.end_ - token.start_ - 2);
581 Location current = token.start_ + 1;
583 while (current != end) {
587 else if (c ==
'\\') {
589 return addError(
"Empty escape sequence in string", token, current);
590 Char escape = *current++;
617 unsigned int unicode;
618 if (!decodeUnicodeCodePoint(token, current, end, unicode))
623 return addError(
"Bad escape sequence in string", token, current);
632 bool Reader::decodeUnicodeCodePoint(Token& token,
635 unsigned int& unicode) {
637 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
639 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
641 if (end - current < 6)
643 "additional six characters expected to parse unicode surrogate pair.",
646 unsigned int surrogatePair;
647 if (*(current++) ==
'\\' && *(current++) ==
'u') {
648 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
649 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
653 return addError(
"expecting another \\u token to begin the second half of "
654 "a unicode surrogate pair",
661 bool Reader::decodeUnicodeEscapeSequence(Token& token,
664 unsigned int& unicode) {
665 if (end - current < 4)
667 "Bad unicode escape sequence in string: four digits expected.",
671 for (
int index = 0; index < 4; ++index) {
674 if (c >=
'0' && c <=
'9')
676 else if (c >=
'a' && c <=
'f')
677 unicode += c -
'a' + 10;
678 else if (c >=
'A' && c <=
'F')
679 unicode += c -
'A' + 10;
682 "Bad unicode escape sequence in string: hexadecimal digit expected.",
690 Reader::addError(
const std::string& message, Token& token, Location extra) {
693 info.message_ = message;
695 errors_.push_back(info);
699 bool Reader::recoverFromError(TokenType skipUntilToken) {
700 int errorCount = int(errors_.size());
703 if (!readToken(skip))
704 errors_.resize(errorCount);
705 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
708 errors_.resize(errorCount);
712 bool Reader::addErrorAndRecover(
const std::string& message,
714 TokenType skipUntilToken) {
715 addError(message, token);
716 return recoverFromError(skipUntilToken);
719 Value& Reader::currentValue() {
return *(nodes_.top()); }
722 if (current_ == end_)
727 void Reader::getLocationLineAndColumn(Location location,
733 while (current < location && current != end_) {
736 if (*current ==
'\n')
738 lastLineStart = current;
740 }
else if (c ==
'\n') {
741 lastLineStart = current;
746 column = int(location - lastLineStart) + 1;
750 std::string Reader::getLocationLineAndColumn(Location location)
const {
752 getLocationLineAndColumn(location, line, column);
753 char buffer[18 + 16 + 16 + 1];
754 #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
756 _snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
758 sprintf_s(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
761 snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
772 std::string formattedMessage;
773 for (Errors::const_iterator itError = errors_.begin();
774 itError != errors_.end();
776 const ErrorInfo& error = *itError;
778 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
779 formattedMessage +=
" " + error.message_ +
"\n";
782 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
784 return formattedMessage;
793 static OurFeatures all();
797 bool allowDroppedNullPlaceholders_;
798 bool allowNumericKeys_;
799 bool allowSingleQuotes_;
808 OurFeatures::OurFeatures()
809 : allowComments_(true), strictRoot_(false)
810 , allowDroppedNullPlaceholders_(false), allowNumericKeys_(false)
811 , allowSingleQuotes_(false)
812 , failIfExtra_(false)
816 OurFeatures OurFeatures::all() {
return OurFeatures(); }
825 typedef const Char* Location;
826 struct StructuredError {
832 OurReader(OurFeatures
const& features);
833 bool parse(
const char* beginDoc,
836 bool collectComments =
true);
837 std::string getFormattedErrorMessages()
const;
840 OurReader(OurReader
const&);
841 void operator=(OurReader
const&);
844 tokenEndOfStream = 0,
855 tokenMemberSeparator,
870 std::string message_;
874 typedef std::deque<ErrorInfo> Errors;
876 bool readToken(Token& token);
878 bool match(Location pattern,
int patternLength);
880 bool readCStyleComment();
881 bool readCppStyleComment();
883 bool readStringSingleQuote();
886 bool readObject(Token& token);
887 bool readArray(Token& token);
888 bool decodeNumber(Token& token);
889 bool decodeNumber(Token& token, Value& decoded);
890 bool decodeString(Token& token);
891 bool decodeString(Token& token, std::string& decoded);
892 bool decodeDouble(Token& token);
893 bool decodeDouble(Token& token, Value& decoded);
894 bool decodeUnicodeCodePoint(Token& token,
897 unsigned int& unicode);
898 bool decodeUnicodeEscapeSequence(Token& token,
901 unsigned int& unicode);
902 bool addError(
const std::string& message, Token& token, Location extra = 0);
903 bool recoverFromError(TokenType skipUntilToken);
904 bool addErrorAndRecover(
const std::string& message,
906 TokenType skipUntilToken);
907 void skipUntilSpace();
908 Value& currentValue();
911 getLocationLineAndColumn(Location location,
int& line,
int& column)
const;
912 std::string getLocationLineAndColumn(Location location)
const;
914 void skipCommentTokens(Token& token);
916 typedef std::stack<Value*> Nodes;
919 std::string document_;
923 Location lastValueEnd_;
925 std::string commentsBefore_;
928 OurFeatures
const features_;
929 bool collectComments_;
934 OurReader::OurReader(OurFeatures
const& features)
935 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
936 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
939 bool OurReader::parse(
const char* beginDoc,
942 bool collectComments) {
943 if (!features_.allowComments_) {
944 collectComments =
false;
949 collectComments_ = collectComments;
953 commentsBefore_ =
"";
955 while (!nodes_.empty())
960 bool successful = readValue();
962 skipCommentTokens(token);
963 if (features_.failIfExtra_) {
964 if (token.type_ != tokenError && token.type_ != tokenEndOfStream) {
965 addError(
"Extra non-whitespace after JSON value.", token);
969 if (collectComments_ && !commentsBefore_.empty())
971 if (features_.strictRoot_) {
972 if (!root.isArray() && !root.isObject()) {
975 token.type_ = tokenError;
976 token.start_ = beginDoc;
979 "A valid JSON document must be either an array or an object value.",
987 bool OurReader::readValue() {
988 if (stackDepth_ >= features_.stackLimit_)
throwRuntimeError(
"Exceeded stackLimit in readValue().");
991 skipCommentTokens(token);
992 bool successful =
true;
994 if (collectComments_ && !commentsBefore_.empty()) {
996 commentsBefore_ =
"";
999 switch (token.type_) {
1000 case tokenObjectBegin:
1001 successful = readObject(token);
1003 case tokenArrayBegin:
1004 successful = readArray(token);
1007 successful = decodeNumber(token);
1010 successful = decodeString(token);
1015 currentValue().swapPayload(v);
1021 currentValue().swapPayload(v);
1027 currentValue().swapPayload(v);
1030 case tokenArraySeparator:
1031 case tokenObjectEnd:
1033 if (features_.allowDroppedNullPlaceholders_) {
1038 currentValue().swapPayload(v);
1042 return addError(
"Syntax error: value, object or array expected.", token);
1045 if (collectComments_) {
1046 lastValueEnd_ = current_;
1047 lastValue_ = ¤tValue();
1054 void OurReader::skipCommentTokens(Token& token) {
1055 if (features_.allowComments_) {
1058 }
while (token.type_ == tokenComment);
1064 bool OurReader::readToken(Token& token) {
1066 token.start_ = current_;
1067 Char c = getNextChar();
1071 token.type_ = tokenObjectBegin;
1074 token.type_ = tokenObjectEnd;
1077 token.type_ = tokenArrayBegin;
1080 token.type_ = tokenArrayEnd;
1083 token.type_ = tokenString;
1087 if (features_.allowSingleQuotes_) {
1088 token.type_ = tokenString;
1089 ok = readStringSingleQuote();
1093 token.type_ = tokenComment;
1107 token.type_ = tokenNumber;
1111 token.type_ = tokenTrue;
1112 ok = match(
"rue", 3);
1115 token.type_ = tokenFalse;
1116 ok = match(
"alse", 4);
1119 token.type_ = tokenNull;
1120 ok = match(
"ull", 3);
1123 token.type_ = tokenArraySeparator;
1126 token.type_ = tokenMemberSeparator;
1129 token.type_ = tokenEndOfStream;
1136 token.type_ = tokenError;
1137 token.end_ = current_;
1141 void OurReader::skipSpaces() {
1142 while (current_ != end_) {
1144 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n')
1151 bool OurReader::match(Location pattern,
int patternLength) {
1152 if (end_ - current_ < patternLength)
1154 int index = patternLength;
1156 if (current_[index] != pattern[index])
1158 current_ += patternLength;
1162 bool OurReader::readComment() {
1163 Location commentBegin = current_ - 1;
1164 Char c = getNextChar();
1165 bool successful =
false;
1167 successful = readCStyleComment();
1169 successful = readCppStyleComment();
1173 if (collectComments_) {
1180 addComment(commentBegin, current_, placement);
1186 OurReader::addComment(Location begin, Location end,
CommentPlacement placement) {
1187 assert(collectComments_);
1188 const std::string& normalized =
normalizeEOL(begin, end);
1190 assert(lastValue_ != 0);
1191 lastValue_->setComment(normalized, placement);
1193 commentsBefore_ += normalized;
1197 bool OurReader::readCStyleComment() {
1198 while (current_ != end_) {
1199 Char c = getNextChar();
1200 if (c ==
'*' && *current_ ==
'/')
1203 return getNextChar() ==
'/';
1206 bool OurReader::readCppStyleComment() {
1207 while (current_ != end_) {
1208 Char c = getNextChar();
1213 if (current_ != end_ && *current_ ==
'\n')
1222 void OurReader::readNumber() {
1223 const char *p = current_;
1226 while (c >=
'0' && c <=
'9')
1227 c = (current_ = p) < end_ ? *p++ : 0;
1230 c = (current_ = p) < end_ ? *p++ : 0;
1231 while (c >=
'0' && c <=
'9')
1232 c = (current_ = p) < end_ ? *p++ : 0;
1235 if (c ==
'e' || c ==
'E') {
1236 c = (current_ = p) < end_ ? *p++ : 0;
1237 if (c ==
'+' || c ==
'-')
1238 c = (current_ = p) < end_ ? *p++ : 0;
1239 while (c >=
'0' && c <=
'9')
1240 c = (current_ = p) < end_ ? *p++ : 0;
1243 bool OurReader::readString() {
1245 while (current_ != end_) {
1256 bool OurReader::readStringSingleQuote() {
1258 while (current_ != end_) {
1268 bool OurReader::readObject(Token& ) {
1272 currentValue().swapPayload(init);
1273 while (readToken(tokenName)) {
1274 bool initialTokenOk =
true;
1275 while (tokenName.type_ == tokenComment && initialTokenOk)
1276 initialTokenOk = readToken(tokenName);
1277 if (!initialTokenOk)
1279 if (tokenName.type_ == tokenObjectEnd && name.empty())
1282 if (tokenName.type_ == tokenString) {
1283 if (!decodeString(tokenName, name))
1284 return recoverFromError(tokenObjectEnd);
1285 }
else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1287 if (!decodeNumber(tokenName, numberName))
1288 return recoverFromError(tokenObjectEnd);
1289 name = numberName.asString();
1295 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1296 return addErrorAndRecover(
1297 "Missing ':' after object member name", colon, tokenObjectEnd);
1300 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1301 std::string msg =
"Duplicate key: '" + name +
"'";
1302 return addErrorAndRecover(
1303 msg, tokenName, tokenObjectEnd);
1305 Value& value = currentValue()[name];
1306 nodes_.push(&value);
1307 bool ok = readValue();
1310 return recoverFromError(tokenObjectEnd);
1313 if (!readToken(comma) ||
1314 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1315 comma.type_ != tokenComment)) {
1316 return addErrorAndRecover(
1317 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
1319 bool finalizeTokenOk =
true;
1320 while (comma.type_ == tokenComment && finalizeTokenOk)
1321 finalizeTokenOk = readToken(comma);
1322 if (comma.type_ == tokenObjectEnd)
1325 return addErrorAndRecover(
1326 "Missing '}' or object member name", tokenName, tokenObjectEnd);
1329 bool OurReader::readArray(Token& ) {
1331 currentValue().swapPayload(init);
1333 if (*current_ ==
']')
1336 readToken(endArray);
1341 Value& value = currentValue()[index++];
1342 nodes_.push(&value);
1343 bool ok = readValue();
1346 return recoverFromError(tokenArrayEnd);
1350 ok = readToken(token);
1351 while (token.type_ == tokenComment && ok) {
1352 ok = readToken(token);
1355 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
1356 if (!ok || badTokenType) {
1357 return addErrorAndRecover(
1358 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
1360 if (token.type_ == tokenArrayEnd)
1366 bool OurReader::decodeNumber(Token& token) {
1368 if (!decodeNumber(token, decoded))
1370 currentValue().swapPayload(decoded);
1374 bool OurReader::decodeNumber(Token& token, Value& decoded) {
1378 Location current = token.start_;
1379 bool isNegative = *current ==
'-';
1383 Value::LargestUInt maxIntegerValue =
1385 : Value::maxLargestUInt;
1386 Value::LargestUInt threshold = maxIntegerValue / 10;
1387 Value::LargestUInt value = 0;
1388 while (current < token.end_) {
1389 Char c = *current++;
1390 if (c < '0' || c >
'9')
1391 return decodeDouble(token, decoded);
1393 if (value >= threshold) {
1398 if (value > threshold || current != token.end_ ||
1399 digit > maxIntegerValue % 10) {
1400 return decodeDouble(token, decoded);
1403 value = value * 10 + digit;
1414 bool OurReader::decodeDouble(Token& token) {
1416 if (!decodeDouble(token, decoded))
1418 currentValue().swapPayload(decoded);
1422 bool OurReader::decodeDouble(Token& token, Value& decoded) {
1424 const int bufferSize = 32;
1426 int length = int(token.end_ - token.start_);
1430 return addError(
"Unable to parse token length", token);
1438 char format[] =
"%lf";
1440 if (length <= bufferSize) {
1441 Char buffer[bufferSize + 1];
1442 memcpy(buffer, token.start_, length);
1444 count = sscanf(buffer, format, &value);
1446 std::string buffer(token.start_, token.end_);
1447 count = sscanf(buffer.c_str(), format, &value);
1451 return addError(
"'" + std::string(token.start_, token.end_) +
1452 "' is not a number.",
1458 bool OurReader::decodeString(Token& token) {
1459 std::string decoded_string;
1460 if (!decodeString(token, decoded_string))
1462 Value decoded(decoded_string);
1463 currentValue().swapPayload(decoded);
1467 bool OurReader::decodeString(Token& token, std::string& decoded) {
1468 decoded.reserve(token.end_ - token.start_ - 2);
1469 Location current = token.start_ + 1;
1470 Location end = token.end_ - 1;
1471 while (current != end) {
1472 Char c = *current++;
1475 else if (c ==
'\\') {
1477 return addError(
"Empty escape sequence in string", token, current);
1478 Char escape = *current++;
1505 unsigned int unicode;
1506 if (!decodeUnicodeCodePoint(token, current, end, unicode))
1511 return addError(
"Bad escape sequence in string", token, current);
1520 bool OurReader::decodeUnicodeCodePoint(Token& token,
1523 unsigned int& unicode) {
1525 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1527 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1529 if (end - current < 6)
1531 "additional six characters expected to parse unicode surrogate pair.",
1534 unsigned int surrogatePair;
1535 if (*(current++) ==
'\\' && *(current++) ==
'u') {
1536 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1537 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1541 return addError(
"expecting another \\u token to begin the second half of "
1542 "a unicode surrogate pair",
1549 bool OurReader::decodeUnicodeEscapeSequence(Token& token,
1552 unsigned int& unicode) {
1553 if (end - current < 4)
1555 "Bad unicode escape sequence in string: four digits expected.",
1559 for (
int index = 0; index < 4; ++index) {
1560 Char c = *current++;
1562 if (c >=
'0' && c <=
'9')
1564 else if (c >=
'a' && c <=
'f')
1565 unicode += c -
'a' + 10;
1566 else if (c >=
'A' && c <=
'F')
1567 unicode += c -
'A' + 10;
1570 "Bad unicode escape sequence in string: hexadecimal digit expected.",
1578 OurReader::addError(
const std::string& message, Token& token, Location extra) {
1580 info.token_ = token;
1581 info.message_ = message;
1582 info.extra_ = extra;
1583 errors_.push_back(info);
1587 bool OurReader::recoverFromError(TokenType skipUntilToken) {
1588 int errorCount = int(errors_.size());
1591 if (!readToken(skip))
1592 errors_.resize(errorCount);
1593 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
1596 errors_.resize(errorCount);
1600 bool OurReader::addErrorAndRecover(
const std::string& message,
1602 TokenType skipUntilToken) {
1603 addError(message, token);
1604 return recoverFromError(skipUntilToken);
1607 Value& OurReader::currentValue() {
return *(nodes_.top()); }
1609 OurReader::Char OurReader::getNextChar() {
1610 if (current_ == end_)
1615 void OurReader::getLocationLineAndColumn(Location location,
1617 int& column)
const {
1618 Location current = begin_;
1619 Location lastLineStart = current;
1621 while (current < location && current != end_) {
1622 Char c = *current++;
1624 if (*current ==
'\n')
1626 lastLineStart = current;
1628 }
else if (c ==
'\n') {
1629 lastLineStart = current;
1634 column = int(location - lastLineStart) + 1;
1638 std::string OurReader::getLocationLineAndColumn(Location location)
const {
1640 getLocationLineAndColumn(location, line, column);
1641 char buffer[18 + 16 + 16 + 1];
1642 #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
1644 _snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
1646 sprintf_s(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
1649 snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
1654 std::string OurReader::getFormattedErrorMessages()
const {
1655 std::string formattedMessage;
1656 for (Errors::const_iterator itError = errors_.begin();
1657 itError != errors_.end();
1659 const ErrorInfo& error = *itError;
1661 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
1662 formattedMessage +=
" " + error.message_ +
"\n";
1665 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
1667 return formattedMessage;
1671 class OurCharReader :
public CharReader {
1672 bool const collectComments_;
1676 bool collectComments,
1677 OurFeatures
const& features)
1678 : collectComments_(collectComments)
1682 char const* beginDoc,
char const* endDoc,
1683 Value* root, std::string* errs) {
1684 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1686 *errs = reader_.getFormattedErrorMessages();
1701 OurFeatures features = OurFeatures::all();
1704 features.allowDroppedNullPlaceholders_ =
settings_[
"allowDroppedNullPlaceholders"].
asBool();
1706 features.allowSingleQuotes_ =
settings_[
"allowSingleQuotes"].
asBool();
1710 return new OurCharReader(collectComments, features);
1714 valid_keys->clear();
1715 valid_keys->insert(
"collectComments");
1716 valid_keys->insert(
"allowComments");
1717 valid_keys->insert(
"strictRoot");
1718 valid_keys->insert(
"allowDroppedNullPlaceholders");
1719 valid_keys->insert(
"allowNumericKeys");
1720 valid_keys->insert(
"allowSingleQuotes");
1721 valid_keys->insert(
"stackLimit");
1722 valid_keys->insert(
"failIfExtra");
1723 valid_keys->insert(
"rejectDupKeys");
1728 if (!invalid) invalid = &my_invalid;
1730 std::set<std::string> valid_keys;
1733 size_t n = keys.size();
1734 for (
size_t i = 0; i < n; ++i) {
1735 std::string
const& key = keys[i];
1736 if (valid_keys.find(key) == valid_keys.end()) {
1740 return 0u == inv.
size();
1750 (*settings)[
"allowComments"] =
false;
1751 (*settings)[
"strictRoot"] =
true;
1752 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1753 (*settings)[
"allowNumericKeys"] =
false;
1754 (*settings)[
"allowSingleQuotes"] =
false;
1755 (*settings)[
"failIfExtra"] =
true;
1756 (*settings)[
"rejectDupKeys"] =
true;
1763 (*settings)[
"collectComments"] =
true;
1764 (*settings)[
"allowComments"] =
true;
1765 (*settings)[
"strictRoot"] =
false;
1766 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1767 (*settings)[
"allowNumericKeys"] =
false;
1768 (*settings)[
"allowSingleQuotes"] =
false;
1769 (*settings)[
"stackLimit"] = 1000;
1770 (*settings)[
"failIfExtra"] =
false;
1771 (*settings)[
"rejectDupKeys"] =
false;
1780 Value* root, std::string* errs)
1782 std::ostringstream ssin;
1783 ssin << sin.rdbuf();
1784 std::string doc = ssin.str();
1785 char const* begin = doc.data();
1786 char const* end = begin + doc.size();
1789 return reader->parse(begin, end, root, errs);
1798 "Error from reader: %s",
static std::string codePointToUTF8(unsigned int cp)
Converts a unicode code-point to UTF-8.
std::vector< std::string > Members
virtual CharReader * newCharReader() const
Allocate a CharReader via operator new().
static void strictMode(Json::Value *settings)
Same as old Features::strictMode().
array value (ordered list)
std::auto_ptr< CharReader > CharReaderPtr
bool parseFromStream(CharReader::Factory const &, std::istream &, Value *root, std::string *errs)
Consume entire stream and use its begin/end.
Json::Value settings_
Configuration of this builder.
object value (collection of name/value pairs).
std::istream & operator>>(std::istream &, Value &)
Read from 'sin' into 'root'.
std::string getFormatedErrorMessages() const
Returns a user friendly string that list errors in the parsed document.
void swapPayload(Value &other)
Swap values but leave comments and source offsets in place.
Value & operator[](std::string key)
A simple way to update a specific setting.
static const Int maxInt
Maximum signed int value that can be stored in a Json::Value.
Json::LargestUInt LargestUInt
Features()
Initialize the configuration like JsonConfig::allFeatures;.
void setComment(const char *comment, CommentPlacement placement)
static const LargestInt minLargestInt
Minimum signed integer value that can be stored in a Json::Value.
bool allowComments_
true if comments are allowed. Default: true.
bool parse(const std::string &document, Value &root, bool collectComments=true)
Read a Value from a JSON document.
Members getMemberNames() const
Return a list of the member names.
bool validate(Json::Value *invalid) const
Json::LargestInt LargestInt
static int const stackLimit_g
void throwRuntimeError(std::string const &msg)
used internally
static void setDefaults(Json::Value *settings)
Called by ctor, but you can use this to reset settings_.
Interface for reading JSON from a char array.
ArrayIndex size() const
Number of values in array or object.
virtual ~CharReaderBuilder()
static Features all()
A configuration that allows all features and assumes all strings are UTF-8.
static std::string normalizeEOL(Reader::Location begin, Reader::Location end)
a comment on the line after a value (only make sense for
static Features strictMode()
A configuration that is strictly compatible with the JSON specification.
bool strictRoot_
true if root must be either an array or an object value.
Build a CharReader implementation.
static void getValidReaderKeys(std::set< std::string > *valid_keys)
static bool containsNewLine(Reader::Location begin, Reader::Location end)
Configuration passed to reader and writer.
virtual CharReader * newCharReader() const =0
Allocate a CharReader via operator new().
a comment placed on the line before a value
Reader()
Constructs a Reader allowing all features for parsing.
std::string getFormattedErrorMessages() const
Returns a user friendly string that list errors in the parsed document.
a comment just after a value on the same line