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)
35 #if __cplusplus >= 201103L
45 : allowComments_(true), strictRoot_(false),
46 allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
63 for (; begin < end; ++begin)
64 if (*begin ==
'\n' || *begin ==
'\r')
73 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
74 lastValue_(), commentsBefore_(), features_(
Features::all()),
78 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
79 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
85 const char* begin = document_.c_str();
86 const char* end = begin + document_.length();
87 return parse(begin, end, root, collectComments);
99 std::getline(sin, doc, (
char)EOF);
100 return parse(doc, root, collectComments);
106 bool collectComments) {
108 collectComments =
false;
113 collectComments_ = collectComments;
117 commentsBefore_ =
"";
119 while (!nodes_.empty())
124 bool successful = readValue();
126 skipCommentTokens(token);
127 if (collectComments_ && !commentsBefore_.empty())
133 token.type_ = tokenError;
134 token.start_ = beginDoc;
137 "A valid JSON document must be either an array or an object value.",
145 bool Reader::readValue() {
154 skipCommentTokens(token);
155 bool successful =
true;
157 if (collectComments_ && !commentsBefore_.empty()) {
159 commentsBefore_ =
"";
162 switch (token.type_) {
163 case tokenObjectBegin:
164 successful = readObject(token);
167 case tokenArrayBegin:
168 successful = readArray(token);
172 successful = decodeNumber(token);
175 successful = decodeString(token);
201 case tokenArraySeparator:
217 return addError(
"Syntax error: value, object or array expected.", token);
220 if (collectComments_) {
221 lastValueEnd_ = current_;
222 lastValue_ = ¤tValue();
229 void Reader::skipCommentTokens(Token& token) {
233 }
while (token.type_ == tokenComment);
239 bool Reader::readToken(Token& token) {
241 token.start_ = current_;
242 Char c = getNextChar();
246 token.type_ = tokenObjectBegin;
249 token.type_ = tokenObjectEnd;
252 token.type_ = tokenArrayBegin;
255 token.type_ = tokenArrayEnd;
258 token.type_ = tokenString;
262 token.type_ = tokenComment;
276 token.type_ = tokenNumber;
280 token.type_ = tokenTrue;
281 ok = match(
"rue", 3);
284 token.type_ = tokenFalse;
285 ok = match(
"alse", 4);
288 token.type_ = tokenNull;
289 ok = match(
"ull", 3);
292 token.type_ = tokenArraySeparator;
295 token.type_ = tokenMemberSeparator;
298 token.type_ = tokenEndOfStream;
305 token.type_ = tokenError;
306 token.end_ = current_;
310 void Reader::skipSpaces() {
311 while (current_ != end_) {
313 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n')
320 bool Reader::match(Location pattern,
int patternLength) {
321 if (end_ - current_ < patternLength)
323 int index = patternLength;
325 if (current_[index] != pattern[index])
327 current_ += patternLength;
331 bool Reader::readComment() {
332 Location commentBegin = current_ - 1;
333 Char c = getNextChar();
334 bool successful =
false;
336 successful = readCStyleComment();
338 successful = readCppStyleComment();
342 if (collectComments_) {
349 addComment(commentBegin, current_, placement);
355 std::string normalized;
356 normalized.reserve(end - begin);
358 while (current != end) {
361 if (current != end && *current ==
'\n')
374 Reader::addComment(Location begin, Location end,
CommentPlacement placement) {
375 assert(collectComments_);
376 const std::string& normalized =
normalizeEOL(begin, end);
378 assert(lastValue_ != 0);
379 lastValue_->
setComment(normalized, placement);
381 commentsBefore_ += normalized;
385 bool Reader::readCStyleComment() {
386 while (current_ != end_) {
387 Char c = getNextChar();
388 if (c ==
'*' && *current_ ==
'/')
391 return getNextChar() ==
'/';
394 bool Reader::readCppStyleComment() {
395 while (current_ != end_) {
396 Char c = getNextChar();
401 if (current_ != end_ && *current_ ==
'\n')
410 void Reader::readNumber() {
411 const char *p = current_;
414 while (c >=
'0' && c <=
'9')
415 c = (current_ = p) < end_ ? *p++ : 0;
418 c = (current_ = p) < end_ ? *p++ : 0;
419 while (c >=
'0' && c <=
'9')
420 c = (current_ = p) < end_ ? *p++ : 0;
423 if (c ==
'e' || c ==
'E') {
424 c = (current_ = p) < end_ ? *p++ : 0;
425 if (c ==
'+' || c ==
'-')
426 c = (current_ = p) < end_ ? *p++ : 0;
427 while (c >=
'0' && c <=
'9')
428 c = (current_ = p) < end_ ? *p++ : 0;
432 bool Reader::readString() {
434 while (current_ != end_) {
444 bool Reader::readObject(Token& tokenStart) {
450 while (readToken(tokenName)) {
451 bool initialTokenOk =
true;
452 while (tokenName.type_ == tokenComment && initialTokenOk)
453 initialTokenOk = readToken(tokenName);
456 if (tokenName.type_ == tokenObjectEnd && name.empty())
459 if (tokenName.type_ == tokenString) {
460 if (!decodeString(tokenName, name))
461 return recoverFromError(tokenObjectEnd);
464 if (!decodeNumber(tokenName, numberName))
465 return recoverFromError(tokenObjectEnd);
466 name = numberName.asString();
472 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
473 return addErrorAndRecover(
474 "Missing ':' after object member name", colon, tokenObjectEnd);
476 Value& value = currentValue()[name];
478 bool ok = readValue();
481 return recoverFromError(tokenObjectEnd);
484 if (!readToken(comma) ||
485 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
486 comma.type_ != tokenComment)) {
487 return addErrorAndRecover(
488 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
490 bool finalizeTokenOk =
true;
491 while (comma.type_ == tokenComment && finalizeTokenOk)
492 finalizeTokenOk = readToken(comma);
493 if (comma.type_ == tokenObjectEnd)
496 return addErrorAndRecover(
497 "Missing '}' or object member name", tokenName, tokenObjectEnd);
500 bool Reader::readArray(Token& tokenStart) {
505 if (*current_ ==
']')
513 Value& value = currentValue()[index++];
515 bool ok = readValue();
518 return recoverFromError(tokenArrayEnd);
522 ok = readToken(token);
523 while (token.type_ == tokenComment && ok) {
524 ok = readToken(token);
527 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
528 if (!ok || badTokenType) {
529 return addErrorAndRecover(
530 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
532 if (token.type_ == tokenArrayEnd)
538 bool Reader::decodeNumber(Token& token) {
540 if (!decodeNumber(token, decoded))
548 bool Reader::decodeNumber(Token& token, Value& decoded) {
553 bool isNegative = *current ==
'-';
559 : Value::maxLargestUInt;
560 Value::LargestUInt threshold = maxIntegerValue / 10;
561 Value::LargestUInt value = 0;
562 while (current < token.end_) {
564 if (c < '0' || c >
'9')
565 return decodeDouble(token, decoded);
567 if (value >= threshold) {
572 if (value > threshold || current != token.end_ ||
573 digit > maxIntegerValue % 10) {
574 return decodeDouble(token, decoded);
577 value = value * 10 + digit;
588 bool Reader::decodeDouble(Token& token) {
590 if (!decodeDouble(token, decoded))
598 bool Reader::decodeDouble(Token& token, Value& decoded) {
600 const int bufferSize = 32;
602 int length = int(token.end_ - token.start_);
606 return addError(
"Unable to parse token length", token);
614 char format[] =
"%lf";
616 if (length <= bufferSize) {
617 Char buffer[bufferSize + 1];
618 memcpy(buffer, token.start_, length);
620 count = sscanf(buffer, format, &value);
622 std::string buffer(token.start_, token.end_);
623 count = sscanf(buffer.c_str(), format, &value);
627 return addError(
"'" + std::string(token.start_, token.end_) +
628 "' is not a number.",
634 bool Reader::decodeString(Token& token) {
635 std::string decoded_string;
636 if (!decodeString(token, decoded_string))
638 Value decoded(decoded_string);
645 bool Reader::decodeString(Token& token, std::string& decoded) {
646 decoded.reserve(token.end_ - token.start_ - 2);
647 Location current = token.start_ + 1;
649 while (current != end) {
653 else if (c ==
'\\') {
655 return addError(
"Empty escape sequence in string", token, current);
656 Char escape = *current++;
683 unsigned int unicode;
684 if (!decodeUnicodeCodePoint(token, current, end, unicode))
689 return addError(
"Bad escape sequence in string", token, current);
698 bool Reader::decodeUnicodeCodePoint(Token& token,
701 unsigned int& unicode) {
703 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
705 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
707 if (end - current < 6)
709 "additional six characters expected to parse unicode surrogate pair.",
712 unsigned int surrogatePair;
713 if (*(current++) ==
'\\' && *(current++) ==
'u') {
714 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
715 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
719 return addError(
"expecting another \\u token to begin the second half of "
720 "a unicode surrogate pair",
727 bool Reader::decodeUnicodeEscapeSequence(Token& token,
730 unsigned int& unicode) {
731 if (end - current < 4)
733 "Bad unicode escape sequence in string: four digits expected.",
737 for (
int index = 0; index < 4; ++index) {
740 if (c >=
'0' && c <=
'9')
742 else if (c >=
'a' && c <=
'f')
743 unicode += c -
'a' + 10;
744 else if (c >=
'A' && c <=
'F')
745 unicode += c -
'A' + 10;
748 "Bad unicode escape sequence in string: hexadecimal digit expected.",
756 Reader::addError(
const std::string& message, Token& token, Location extra) {
759 info.message_ = message;
761 errors_.push_back(info);
765 bool Reader::recoverFromError(TokenType skipUntilToken) {
766 int errorCount = int(errors_.size());
769 if (!readToken(skip))
770 errors_.resize(errorCount);
771 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
774 errors_.resize(errorCount);
778 bool Reader::addErrorAndRecover(
const std::string& message,
780 TokenType skipUntilToken) {
781 addError(message, token);
782 return recoverFromError(skipUntilToken);
785 Value& Reader::currentValue() {
return *(nodes_.top()); }
788 if (current_ == end_)
793 void Reader::getLocationLineAndColumn(Location location,
799 while (current < location && current != end_) {
802 if (*current ==
'\n')
804 lastLineStart = current;
806 }
else if (c ==
'\n') {
807 lastLineStart = current;
812 column = int(location - lastLineStart) + 1;
816 std::string Reader::getLocationLineAndColumn(Location location)
const {
818 getLocationLineAndColumn(location, line, column);
819 char buffer[18 + 16 + 16 + 1];
820 #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
822 _snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
824 sprintf_s(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
827 snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
838 std::string formattedMessage;
839 for (Errors::const_iterator itError = errors_.begin();
840 itError != errors_.end();
842 const ErrorInfo& error = *itError;
844 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
845 formattedMessage +=
" " + error.message_ +
"\n";
848 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
850 return formattedMessage;
854 std::vector<Reader::StructuredError> allErrors;
855 for (Errors::const_iterator itError = errors_.begin();
856 itError != errors_.end();
858 const ErrorInfo& error = *itError;
862 structured.
message = error.message_;
863 allErrors.push_back(structured);
869 size_t length = end_ - begin_;
874 token.type_ = tokenError;
879 info.message_ = message;
881 errors_.push_back(info);
886 size_t length = end_ - begin_;
892 token.type_ = tokenError;
897 info.message_ = message;
899 errors_.push_back(info);
904 return !errors_.size();
910 static OurFeatures all();
914 bool allowDroppedNullPlaceholders_;
915 bool allowNumericKeys_;
916 bool allowSingleQuotes_;
925 OurFeatures::OurFeatures()
926 : allowComments_(true), strictRoot_(false)
927 , allowDroppedNullPlaceholders_(false), allowNumericKeys_(false)
928 , allowSingleQuotes_(false)
929 , failIfExtra_(false)
933 OurFeatures OurFeatures::all() {
return OurFeatures(); }
942 typedef const Char* Location;
943 struct StructuredError {
949 OurReader(OurFeatures
const& features);
950 bool parse(
const char* beginDoc,
953 bool collectComments =
true);
954 std::string getFormattedErrorMessages()
const;
955 std::vector<StructuredError> getStructuredErrors()
const;
956 bool pushError(
const Value& value,
const std::string& message);
957 bool pushError(
const Value& value,
const std::string& message,
const Value& extra);
961 OurReader(OurReader
const&);
962 void operator=(OurReader
const&);
965 tokenEndOfStream = 0,
976 tokenMemberSeparator,
991 std::string message_;
995 typedef std::deque<ErrorInfo> Errors;
997 bool readToken(Token& token);
999 bool match(Location pattern,
int patternLength);
1001 bool readCStyleComment();
1002 bool readCppStyleComment();
1004 bool readStringSingleQuote();
1007 bool readObject(Token& token);
1008 bool readArray(Token& token);
1009 bool decodeNumber(Token& token);
1010 bool decodeNumber(Token& token, Value& decoded);
1011 bool decodeString(Token& token);
1012 bool decodeString(Token& token, std::string& decoded);
1013 bool decodeDouble(Token& token);
1014 bool decodeDouble(Token& token, Value& decoded);
1015 bool decodeUnicodeCodePoint(Token& token,
1018 unsigned int& unicode);
1019 bool decodeUnicodeEscapeSequence(Token& token,
1022 unsigned int& unicode);
1023 bool addError(
const std::string& message, Token& token, Location extra = 0);
1024 bool recoverFromError(TokenType skipUntilToken);
1025 bool addErrorAndRecover(
const std::string& message,
1027 TokenType skipUntilToken);
1028 void skipUntilSpace();
1029 Value& currentValue();
1032 getLocationLineAndColumn(Location location,
int& line,
int& column)
const;
1033 std::string getLocationLineAndColumn(Location location)
const;
1035 void skipCommentTokens(Token& token);
1037 typedef std::stack<Value*> Nodes;
1040 std::string document_;
1044 Location lastValueEnd_;
1046 std::string commentsBefore_;
1049 OurFeatures
const features_;
1050 bool collectComments_;
1055 OurReader::OurReader(OurFeatures
const& features)
1056 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
1057 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
1060 bool OurReader::parse(
const char* beginDoc,
1063 bool collectComments) {
1064 if (!features_.allowComments_) {
1065 collectComments =
false;
1070 collectComments_ = collectComments;
1074 commentsBefore_ =
"";
1076 while (!nodes_.empty())
1081 bool successful = readValue();
1083 skipCommentTokens(token);
1084 if (features_.failIfExtra_) {
1085 if (token.type_ != tokenError && token.type_ != tokenEndOfStream) {
1086 addError(
"Extra non-whitespace after JSON value.", token);
1090 if (collectComments_ && !commentsBefore_.empty())
1092 if (features_.strictRoot_) {
1093 if (!root.isArray() && !root.isObject()) {
1096 token.type_ = tokenError;
1097 token.start_ = beginDoc;
1098 token.end_ = endDoc;
1100 "A valid JSON document must be either an array or an object value.",
1108 bool OurReader::readValue() {
1109 if (stackDepth_ >= features_.stackLimit_)
throwRuntimeError(
"Exceeded stackLimit in readValue().");
1112 skipCommentTokens(token);
1113 bool successful =
true;
1115 if (collectComments_ && !commentsBefore_.empty()) {
1117 commentsBefore_ =
"";
1120 switch (token.type_) {
1121 case tokenObjectBegin:
1122 successful = readObject(token);
1123 currentValue().setOffsetLimit(current_ - begin_);
1125 case tokenArrayBegin:
1126 successful = readArray(token);
1127 currentValue().setOffsetLimit(current_ - begin_);
1130 successful = decodeNumber(token);
1133 successful = decodeString(token);
1138 currentValue().swapPayload(v);
1139 currentValue().setOffsetStart(token.start_ - begin_);
1140 currentValue().setOffsetLimit(token.end_ - begin_);
1146 currentValue().swapPayload(v);
1147 currentValue().setOffsetStart(token.start_ - begin_);
1148 currentValue().setOffsetLimit(token.end_ - begin_);
1154 currentValue().swapPayload(v);
1155 currentValue().setOffsetStart(token.start_ - begin_);
1156 currentValue().setOffsetLimit(token.end_ - begin_);
1159 case tokenArraySeparator:
1160 case tokenObjectEnd:
1162 if (features_.allowDroppedNullPlaceholders_) {
1167 currentValue().swapPayload(v);
1168 currentValue().setOffsetStart(current_ - begin_ - 1);
1169 currentValue().setOffsetLimit(current_ - begin_);
1173 currentValue().setOffsetStart(token.start_ - begin_);
1174 currentValue().setOffsetLimit(token.end_ - begin_);
1175 return addError(
"Syntax error: value, object or array expected.", token);
1178 if (collectComments_) {
1179 lastValueEnd_ = current_;
1180 lastValue_ = ¤tValue();
1187 void OurReader::skipCommentTokens(Token& token) {
1188 if (features_.allowComments_) {
1191 }
while (token.type_ == tokenComment);
1197 bool OurReader::readToken(Token& token) {
1199 token.start_ = current_;
1200 Char c = getNextChar();
1204 token.type_ = tokenObjectBegin;
1207 token.type_ = tokenObjectEnd;
1210 token.type_ = tokenArrayBegin;
1213 token.type_ = tokenArrayEnd;
1216 token.type_ = tokenString;
1220 if (features_.allowSingleQuotes_) {
1221 token.type_ = tokenString;
1222 ok = readStringSingleQuote();
1226 token.type_ = tokenComment;
1240 token.type_ = tokenNumber;
1244 token.type_ = tokenTrue;
1245 ok = match(
"rue", 3);
1248 token.type_ = tokenFalse;
1249 ok = match(
"alse", 4);
1252 token.type_ = tokenNull;
1253 ok = match(
"ull", 3);
1256 token.type_ = tokenArraySeparator;
1259 token.type_ = tokenMemberSeparator;
1262 token.type_ = tokenEndOfStream;
1269 token.type_ = tokenError;
1270 token.end_ = current_;
1274 void OurReader::skipSpaces() {
1275 while (current_ != end_) {
1277 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n')
1284 bool OurReader::match(Location pattern,
int patternLength) {
1285 if (end_ - current_ < patternLength)
1287 int index = patternLength;
1289 if (current_[index] != pattern[index])
1291 current_ += patternLength;
1295 bool OurReader::readComment() {
1296 Location commentBegin = current_ - 1;
1297 Char c = getNextChar();
1298 bool successful =
false;
1300 successful = readCStyleComment();
1302 successful = readCppStyleComment();
1306 if (collectComments_) {
1313 addComment(commentBegin, current_, placement);
1319 OurReader::addComment(Location begin, Location end,
CommentPlacement placement) {
1320 assert(collectComments_);
1321 const std::string& normalized =
normalizeEOL(begin, end);
1323 assert(lastValue_ != 0);
1324 lastValue_->setComment(normalized, placement);
1326 commentsBefore_ += normalized;
1330 bool OurReader::readCStyleComment() {
1331 while (current_ != end_) {
1332 Char c = getNextChar();
1333 if (c ==
'*' && *current_ ==
'/')
1336 return getNextChar() ==
'/';
1339 bool OurReader::readCppStyleComment() {
1340 while (current_ != end_) {
1341 Char c = getNextChar();
1346 if (current_ != end_ && *current_ ==
'\n')
1355 void OurReader::readNumber() {
1356 const char *p = current_;
1359 while (c >=
'0' && c <=
'9')
1360 c = (current_ = p) < end_ ? *p++ : 0;
1363 c = (current_ = p) < end_ ? *p++ : 0;
1364 while (c >=
'0' && c <=
'9')
1365 c = (current_ = p) < end_ ? *p++ : 0;
1368 if (c ==
'e' || c ==
'E') {
1369 c = (current_ = p) < end_ ? *p++ : 0;
1370 if (c ==
'+' || c ==
'-')
1371 c = (current_ = p) < end_ ? *p++ : 0;
1372 while (c >=
'0' && c <=
'9')
1373 c = (current_ = p) < end_ ? *p++ : 0;
1376 bool OurReader::readString() {
1378 while (current_ != end_) {
1389 bool OurReader::readStringSingleQuote() {
1391 while (current_ != end_) {
1401 bool OurReader::readObject(Token& tokenStart) {
1405 currentValue().swapPayload(init);
1406 currentValue().setOffsetStart(tokenStart.start_ - begin_);
1407 while (readToken(tokenName)) {
1408 bool initialTokenOk =
true;
1409 while (tokenName.type_ == tokenComment && initialTokenOk)
1410 initialTokenOk = readToken(tokenName);
1411 if (!initialTokenOk)
1413 if (tokenName.type_ == tokenObjectEnd && name.empty())
1416 if (tokenName.type_ == tokenString) {
1417 if (!decodeString(tokenName, name))
1418 return recoverFromError(tokenObjectEnd);
1419 }
else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1421 if (!decodeNumber(tokenName, numberName))
1422 return recoverFromError(tokenObjectEnd);
1423 name = numberName.asString();
1429 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1430 return addErrorAndRecover(
1431 "Missing ':' after object member name", colon, tokenObjectEnd);
1434 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1435 std::string msg =
"Duplicate key: '" + name +
"'";
1436 return addErrorAndRecover(
1437 msg, tokenName, tokenObjectEnd);
1439 Value& value = currentValue()[name];
1440 nodes_.push(&value);
1441 bool ok = readValue();
1444 return recoverFromError(tokenObjectEnd);
1447 if (!readToken(comma) ||
1448 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1449 comma.type_ != tokenComment)) {
1450 return addErrorAndRecover(
1451 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
1453 bool finalizeTokenOk =
true;
1454 while (comma.type_ == tokenComment && finalizeTokenOk)
1455 finalizeTokenOk = readToken(comma);
1456 if (comma.type_ == tokenObjectEnd)
1459 return addErrorAndRecover(
1460 "Missing '}' or object member name", tokenName, tokenObjectEnd);
1463 bool OurReader::readArray(Token& tokenStart) {
1465 currentValue().swapPayload(init);
1466 currentValue().setOffsetStart(tokenStart.start_ - begin_);
1468 if (*current_ ==
']')
1471 readToken(endArray);
1476 Value& value = currentValue()[index++];
1477 nodes_.push(&value);
1478 bool ok = readValue();
1481 return recoverFromError(tokenArrayEnd);
1485 ok = readToken(token);
1486 while (token.type_ == tokenComment && ok) {
1487 ok = readToken(token);
1490 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
1491 if (!ok || badTokenType) {
1492 return addErrorAndRecover(
1493 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
1495 if (token.type_ == tokenArrayEnd)
1501 bool OurReader::decodeNumber(Token& token) {
1503 if (!decodeNumber(token, decoded))
1505 currentValue().swapPayload(decoded);
1506 currentValue().setOffsetStart(token.start_ - begin_);
1507 currentValue().setOffsetLimit(token.end_ - begin_);
1511 bool OurReader::decodeNumber(Token& token, Value& decoded) {
1515 Location current = token.start_;
1516 bool isNegative = *current ==
'-';
1520 Value::LargestUInt maxIntegerValue =
1522 : Value::maxLargestUInt;
1523 Value::LargestUInt threshold = maxIntegerValue / 10;
1524 Value::LargestUInt value = 0;
1525 while (current < token.end_) {
1526 Char c = *current++;
1527 if (c < '0' || c >
'9')
1528 return decodeDouble(token, decoded);
1530 if (value >= threshold) {
1535 if (value > threshold || current != token.end_ ||
1536 digit > maxIntegerValue % 10) {
1537 return decodeDouble(token, decoded);
1540 value = value * 10 + digit;
1551 bool OurReader::decodeDouble(Token& token) {
1553 if (!decodeDouble(token, decoded))
1555 currentValue().swapPayload(decoded);
1556 currentValue().setOffsetStart(token.start_ - begin_);
1557 currentValue().setOffsetLimit(token.end_ - begin_);
1561 bool OurReader::decodeDouble(Token& token, Value& decoded) {
1563 const int bufferSize = 32;
1565 int length = int(token.end_ - token.start_);
1569 return addError(
"Unable to parse token length", token);
1577 char format[] =
"%lf";
1579 if (length <= bufferSize) {
1580 Char buffer[bufferSize + 1];
1581 memcpy(buffer, token.start_, length);
1583 count = sscanf(buffer, format, &value);
1585 std::string buffer(token.start_, token.end_);
1586 count = sscanf(buffer.c_str(), format, &value);
1590 return addError(
"'" + std::string(token.start_, token.end_) +
1591 "' is not a number.",
1597 bool OurReader::decodeString(Token& token) {
1598 std::string decoded_string;
1599 if (!decodeString(token, decoded_string))
1601 Value decoded(decoded_string);
1602 currentValue().swapPayload(decoded);
1603 currentValue().setOffsetStart(token.start_ - begin_);
1604 currentValue().setOffsetLimit(token.end_ - begin_);
1608 bool OurReader::decodeString(Token& token, std::string& decoded) {
1609 decoded.reserve(token.end_ - token.start_ - 2);
1610 Location current = token.start_ + 1;
1611 Location end = token.end_ - 1;
1612 while (current != end) {
1613 Char c = *current++;
1616 else if (c ==
'\\') {
1618 return addError(
"Empty escape sequence in string", token, current);
1619 Char escape = *current++;
1646 unsigned int unicode;
1647 if (!decodeUnicodeCodePoint(token, current, end, unicode))
1652 return addError(
"Bad escape sequence in string", token, current);
1661 bool OurReader::decodeUnicodeCodePoint(Token& token,
1664 unsigned int& unicode) {
1666 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1668 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1670 if (end - current < 6)
1672 "additional six characters expected to parse unicode surrogate pair.",
1675 unsigned int surrogatePair;
1676 if (*(current++) ==
'\\' && *(current++) ==
'u') {
1677 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1678 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1682 return addError(
"expecting another \\u token to begin the second half of "
1683 "a unicode surrogate pair",
1690 bool OurReader::decodeUnicodeEscapeSequence(Token& token,
1693 unsigned int& unicode) {
1694 if (end - current < 4)
1696 "Bad unicode escape sequence in string: four digits expected.",
1700 for (
int index = 0; index < 4; ++index) {
1701 Char c = *current++;
1703 if (c >=
'0' && c <=
'9')
1705 else if (c >=
'a' && c <=
'f')
1706 unicode += c -
'a' + 10;
1707 else if (c >=
'A' && c <=
'F')
1708 unicode += c -
'A' + 10;
1711 "Bad unicode escape sequence in string: hexadecimal digit expected.",
1719 OurReader::addError(
const std::string& message, Token& token, Location extra) {
1721 info.token_ = token;
1722 info.message_ = message;
1723 info.extra_ = extra;
1724 errors_.push_back(info);
1728 bool OurReader::recoverFromError(TokenType skipUntilToken) {
1729 int errorCount = int(errors_.size());
1732 if (!readToken(skip))
1733 errors_.resize(errorCount);
1734 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
1737 errors_.resize(errorCount);
1741 bool OurReader::addErrorAndRecover(
const std::string& message,
1743 TokenType skipUntilToken) {
1744 addError(message, token);
1745 return recoverFromError(skipUntilToken);
1748 Value& OurReader::currentValue() {
return *(nodes_.top()); }
1750 OurReader::Char OurReader::getNextChar() {
1751 if (current_ == end_)
1756 void OurReader::getLocationLineAndColumn(Location location,
1758 int& column)
const {
1759 Location current = begin_;
1760 Location lastLineStart = current;
1762 while (current < location && current != end_) {
1763 Char c = *current++;
1765 if (*current ==
'\n')
1767 lastLineStart = current;
1769 }
else if (c ==
'\n') {
1770 lastLineStart = current;
1775 column = int(location - lastLineStart) + 1;
1779 std::string OurReader::getLocationLineAndColumn(Location location)
const {
1781 getLocationLineAndColumn(location, line, column);
1782 char buffer[18 + 16 + 16 + 1];
1783 #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
1785 _snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
1787 sprintf_s(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
1790 snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
1795 std::string OurReader::getFormattedErrorMessages()
const {
1796 std::string formattedMessage;
1797 for (Errors::const_iterator itError = errors_.begin();
1798 itError != errors_.end();
1800 const ErrorInfo& error = *itError;
1802 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
1803 formattedMessage +=
" " + error.message_ +
"\n";
1806 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
1808 return formattedMessage;
1811 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors()
const {
1812 std::vector<OurReader::StructuredError> allErrors;
1813 for (Errors::const_iterator itError = errors_.begin();
1814 itError != errors_.end();
1816 const ErrorInfo& error = *itError;
1817 OurReader::StructuredError structured;
1818 structured.offset_start = error.token_.start_ - begin_;
1819 structured.offset_limit = error.token_.end_ - begin_;
1820 structured.message = error.message_;
1821 allErrors.push_back(structured);
1826 bool OurReader::pushError(
const Value& value,
const std::string& message) {
1827 size_t length = end_ - begin_;
1828 if(value.getOffsetStart() > length
1829 || value.getOffsetLimit() > length)
1832 token.type_ = tokenError;
1833 token.start_ = begin_ + value.getOffsetStart();
1834 token.end_ = end_ + value.getOffsetLimit();
1836 info.token_ = token;
1837 info.message_ = message;
1839 errors_.push_back(info);
1843 bool OurReader::pushError(
const Value& value,
const std::string& message,
const Value& extra) {
1844 size_t length = end_ - begin_;
1845 if(value.getOffsetStart() > length
1846 || value.getOffsetLimit() > length
1847 || extra.getOffsetLimit() > length)
1850 token.type_ = tokenError;
1851 token.start_ = begin_ + value.getOffsetStart();
1852 token.end_ = begin_ + value.getOffsetLimit();
1854 info.token_ = token;
1855 info.message_ = message;
1856 info.extra_ = begin_ + extra.getOffsetStart();
1857 errors_.push_back(info);
1861 bool OurReader::good()
const {
1862 return !errors_.size();
1866 class OurCharReader :
public CharReader {
1867 bool const collectComments_;
1871 bool collectComments,
1872 OurFeatures
const& features)
1873 : collectComments_(collectComments)
1877 char const* beginDoc,
char const* endDoc,
1878 Value* root, std::string* errs) {
1879 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1881 *errs = reader_.getFormattedErrorMessages();
1896 OurFeatures features = OurFeatures::all();
1899 features.allowDroppedNullPlaceholders_ =
settings_[
"allowDroppedNullPlaceholders"].
asBool();
1901 features.allowSingleQuotes_ =
settings_[
"allowSingleQuotes"].
asBool();
1905 return new OurCharReader(collectComments, features);
1909 valid_keys->clear();
1910 valid_keys->insert(
"collectComments");
1911 valid_keys->insert(
"allowComments");
1912 valid_keys->insert(
"strictRoot");
1913 valid_keys->insert(
"allowDroppedNullPlaceholders");
1914 valid_keys->insert(
"allowNumericKeys");
1915 valid_keys->insert(
"allowSingleQuotes");
1916 valid_keys->insert(
"stackLimit");
1917 valid_keys->insert(
"failIfExtra");
1918 valid_keys->insert(
"rejectDupKeys");
1923 if (!invalid) invalid = &my_invalid;
1925 std::set<std::string> valid_keys;
1928 size_t n = keys.size();
1929 for (
size_t i = 0; i < n; ++i) {
1930 std::string
const& key = keys[i];
1931 if (valid_keys.find(key) == valid_keys.end()) {
1935 return 0u == inv.
size();
1945 (*settings)[
"allowComments"] =
false;
1946 (*settings)[
"strictRoot"] =
true;
1947 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1948 (*settings)[
"allowNumericKeys"] =
false;
1949 (*settings)[
"allowSingleQuotes"] =
false;
1950 (*settings)[
"failIfExtra"] =
true;
1951 (*settings)[
"rejectDupKeys"] =
true;
1958 (*settings)[
"collectComments"] =
true;
1959 (*settings)[
"allowComments"] =
true;
1960 (*settings)[
"strictRoot"] =
false;
1961 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1962 (*settings)[
"allowNumericKeys"] =
false;
1963 (*settings)[
"allowSingleQuotes"] =
false;
1964 (*settings)[
"stackLimit"] = 1000;
1965 (*settings)[
"failIfExtra"] =
false;
1966 (*settings)[
"rejectDupKeys"] =
false;
1975 Value* root, std::string* errs)
1977 std::ostringstream ssin;
1978 ssin << sin.rdbuf();
1979 std::string doc = ssin.str();
1980 char const* begin = doc.data();
1981 char const* end = begin + doc.size();
1984 return reader->parse(begin, end, root, errs);
1993 "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.
void setOffsetStart(size_t start)
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;.
An error tagged with where in the JSON text it was encountered.
std::vector< StructuredError > getStructuredErrors() const
Returns a vector of structured erros encounted while parsing.
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 allowNumericKeys_
true if numeric object key are allowed. Default: false.
size_t getOffsetLimit() const
bool good() const
Return whether there are any errors.
bool parse(const std::string &document, Value &root, bool collectComments=true)
Read a Value from a JSON document.
JSON (JavaScript Object Notation).
Members getMemberNames() const
Return a list of the member names.
bool allowDroppedNullPlaceholders_
true if dropped null placeholders are allowed. Default: false.
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()
void setOffsetLimit(size_t limit)
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
bool pushError(const Value &value, const std::string &message)
Add a semantic error message.
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.
size_t getOffsetStart() const
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