7 #if !defined(JSON_IS_AMALGAMATION) 12 #endif // if !defined(JSON_IS_AMALGAMATION) 23 #if __cplusplus >= 201103L 26 #define sscanf std::sscanf 32 #if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) 33 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 34 #endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 39 #pragma warning(disable : 4996) 44 #if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) 45 #define JSONCPP_DEPRECATED_STACK_LIMIT 1000 53 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) 79 for (; begin < end; ++begin)
80 if (*begin ==
'\n' || *begin ==
'\r')
89 : errors_(), document_(), commentsBefore_(), features_(Features::all()) {}
91 Reader::Reader(
const Features& features)
92 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
93 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
98 bool collectComments) {
99 document_.assign(document.begin(), document.end());
100 const char* begin = document_.c_str();
101 const char* end = begin + document_.length();
102 return parse(begin, end, root, collectComments);
114 std::getline(is, doc, (
char)EOF);
115 return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
121 bool collectComments) {
123 collectComments =
false;
128 collectComments_ = collectComments;
130 lastValueEnd_ =
nullptr;
131 lastValue_ =
nullptr;
132 commentsBefore_.clear();
134 while (!nodes_.empty())
138 bool successful = readValue();
140 skipCommentTokens(token);
141 if (collectComments_ && !commentsBefore_.empty())
147 token.type_ = tokenError;
148 token.start_ = beginDoc;
151 "A valid JSON document must be either an array or an object value.",
159 bool Reader::readValue() {
165 throwRuntimeError(
"Exceeded stackLimit in readValue().");
168 skipCommentTokens(token);
169 bool successful =
true;
171 if (collectComments_ && !commentsBefore_.empty()) {
173 commentsBefore_.clear();
176 switch (token.type_) {
177 case tokenObjectBegin:
178 successful = readObject(token);
181 case tokenArrayBegin:
182 successful = readArray(token);
186 successful = decodeNumber(token);
189 successful = decodeString(token);
209 case tokenArraySeparator:
225 return addError(
"Syntax error: value, object or array expected.", token);
228 if (collectComments_) {
229 lastValueEnd_ = current_;
230 lastValue_ = ¤tValue();
236 void Reader::skipCommentTokens(Token& token) {
240 }
while (token.type_ == tokenComment);
246 bool Reader::readToken(Token& token) {
248 token.start_ = current_;
249 Char c = getNextChar();
253 token.type_ = tokenObjectBegin;
256 token.type_ = tokenObjectEnd;
259 token.type_ = tokenArrayBegin;
262 token.type_ = tokenArrayEnd;
265 token.type_ = tokenString;
269 token.type_ = tokenComment;
283 token.type_ = tokenNumber;
287 token.type_ = tokenTrue;
288 ok = match(
"rue", 3);
291 token.type_ = tokenFalse;
292 ok = match(
"alse", 4);
295 token.type_ = tokenNull;
296 ok = match(
"ull", 3);
299 token.type_ = tokenArraySeparator;
302 token.type_ = tokenMemberSeparator;
305 token.type_ = tokenEndOfStream;
312 token.type_ = tokenError;
313 token.end_ = current_;
317 void Reader::skipSpaces() {
318 while (current_ != end_) {
320 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n')
327 bool Reader::match(Location pattern,
int patternLength) {
328 if (end_ - current_ < patternLength)
330 int index = patternLength;
332 if (current_[index] != pattern[index])
334 current_ += patternLength;
338 bool Reader::readComment() {
339 Location commentBegin = current_ - 1;
340 Char c = getNextChar();
341 bool successful =
false;
343 successful = readCStyleComment();
345 successful = readCppStyleComment();
349 if (collectComments_) {
351 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
352 if (c !=
'*' || !containsNewLine(commentBegin, current_))
356 addComment(commentBegin, current_, placement);
363 normalized.reserve(static_cast<size_t>(end - begin));
365 while (current != end) {
368 if (current != end && *current ==
'\n')
380 void Reader::addComment(Location begin,
383 assert(collectComments_);
384 const String& normalized = normalizeEOL(begin, end);
386 assert(lastValue_ !=
nullptr);
387 lastValue_->
setComment(normalized, placement);
389 commentsBefore_ += normalized;
393 bool Reader::readCStyleComment() {
394 while ((current_ + 1) < end_) {
395 Char c = getNextChar();
396 if (c ==
'*' && *current_ ==
'/')
399 return getNextChar() ==
'/';
402 bool Reader::readCppStyleComment() {
403 while (current_ != end_) {
404 Char c = getNextChar();
409 if (current_ != end_ && *current_ ==
'\n')
418 void Reader::readNumber() {
419 const char* p = current_;
422 while (c >=
'0' && c <=
'9')
423 c = (current_ = p) < end_ ? *p++ :
'\0';
426 c = (current_ = p) < end_ ? *p++ :
'\0';
427 while (c >=
'0' && c <=
'9')
428 c = (current_ = p) < end_ ? *p++ :
'\0';
431 if (c ==
'e' || c ==
'E') {
432 c = (current_ = p) < end_ ? *p++ :
'\0';
433 if (c ==
'+' || c ==
'-')
434 c = (current_ = p) < end_ ? *p++ :
'\0';
435 while (c >=
'0' && c <=
'9')
436 c = (current_ = p) < end_ ? *p++ :
'\0';
440 bool Reader::readString() {
442 while (current_ != end_) {
452 bool Reader::readObject(Token& token) {
458 while (readToken(tokenName)) {
459 bool initialTokenOk =
true;
460 while (tokenName.type_ == tokenComment && initialTokenOk)
461 initialTokenOk = readToken(tokenName);
464 if (tokenName.type_ == tokenObjectEnd && name.empty())
467 if (tokenName.type_ == tokenString) {
468 if (!decodeString(tokenName, name))
469 return recoverFromError(tokenObjectEnd);
472 if (!decodeNumber(tokenName, numberName))
473 return recoverFromError(tokenObjectEnd);
474 name =
String(numberName.asCString());
480 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
481 return addErrorAndRecover(
"Missing ':' after object member name", colon,
484 Value& value = currentValue()[name];
486 bool ok = readValue();
489 return recoverFromError(tokenObjectEnd);
492 if (!readToken(comma) ||
493 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
494 comma.type_ != tokenComment)) {
495 return addErrorAndRecover(
"Missing ',' or '}' in object declaration",
496 comma, tokenObjectEnd);
498 bool finalizeTokenOk =
true;
499 while (comma.type_ == tokenComment && finalizeTokenOk)
500 finalizeTokenOk = readToken(comma);
501 if (comma.type_ == tokenObjectEnd)
504 return addErrorAndRecover(
"Missing '}' or object member name", tokenName,
508 bool Reader::readArray(Token& token) {
513 if (current_ != end_ && *current_ ==
']')
521 Value& value = currentValue()[index++];
523 bool ok = readValue();
526 return recoverFromError(tokenArrayEnd);
530 ok = readToken(currentToken);
531 while (currentToken.type_ == tokenComment && ok) {
532 ok = readToken(currentToken);
534 bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
535 currentToken.type_ != tokenArrayEnd);
536 if (!ok || badTokenType) {
537 return addErrorAndRecover(
"Missing ',' or ']' in array declaration",
538 currentToken, tokenArrayEnd);
540 if (currentToken.type_ == tokenArrayEnd)
546 bool Reader::decodeNumber(Token& token) {
548 if (!decodeNumber(token, decoded))
556 bool Reader::decodeNumber(Token& token, Value& decoded) {
561 bool isNegative = *current ==
'-';
571 while (current < token.end_) {
573 if (c < '0' || c >
'9')
574 return decodeDouble(token, decoded);
575 auto digit(static_cast<Value::UInt>(c -
'0'));
576 if (value >= threshold) {
581 if (value > threshold || current != token.end_ ||
582 digit > maxIntegerValue % 10) {
583 return decodeDouble(token, decoded);
586 value = value * 10 + digit;
588 if (isNegative && value == maxIntegerValue)
599 bool Reader::decodeDouble(Token& token) {
601 if (!decodeDouble(token, decoded))
609 bool Reader::decodeDouble(Token& token, Value& decoded) {
611 String buffer(token.start_, token.end_);
615 "'" +
String(token.start_, token.end_) +
"' is not a number.", token);
620 bool Reader::decodeString(Token& token) {
622 if (!decodeString(token, decoded_string))
624 Value decoded(decoded_string);
631 bool Reader::decodeString(Token& token,
String& decoded) {
632 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
633 Location current = token.start_ + 1;
635 while (current != end) {
639 else if (c ==
'\\') {
641 return addError(
"Empty escape sequence in string", token, current);
642 Char escape = *current++;
669 unsigned int unicode;
670 if (!decodeUnicodeCodePoint(token, current, end, unicode))
675 return addError(
"Bad escape sequence in string", token, current);
684 bool Reader::decodeUnicodeCodePoint(Token& token,
687 unsigned int& unicode) {
689 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
691 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
693 if (end - current < 6)
695 "additional six characters expected to parse unicode surrogate pair.",
697 if (*(current++) ==
'\\' && *(current++) ==
'u') {
698 unsigned int surrogatePair;
699 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
700 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
704 return addError(
"expecting another \\u token to begin the second half of " 705 "a unicode surrogate pair",
711 bool Reader::decodeUnicodeEscapeSequence(Token& token,
714 unsigned int& ret_unicode) {
715 if (end - current < 4)
717 "Bad unicode escape sequence in string: four digits expected.", token,
720 for (
int index = 0; index < 4; ++index) {
723 if (c >=
'0' && c <=
'9')
725 else if (c >=
'a' && c <=
'f')
726 unicode += c -
'a' + 10;
727 else if (c >=
'A' && c <=
'F')
728 unicode += c -
'A' + 10;
731 "Bad unicode escape sequence in string: hexadecimal digit expected.",
734 ret_unicode =
static_cast<unsigned int>(unicode);
738 bool Reader::addError(
const String& message, Token& token, Location extra) {
741 info.message_ = message;
743 errors_.push_back(info);
747 bool Reader::recoverFromError(TokenType skipUntilToken) {
748 size_t const errorCount = errors_.size();
751 if (!readToken(skip))
752 errors_.resize(errorCount);
753 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
756 errors_.resize(errorCount);
760 bool Reader::addErrorAndRecover(
const String& message,
762 TokenType skipUntilToken) {
763 addError(message, token);
764 return recoverFromError(skipUntilToken);
767 Value& Reader::currentValue() {
return *(nodes_.top()); }
770 if (current_ == end_)
775 void Reader::getLocationLineAndColumn(Location location,
781 while (current < location && current != end_) {
784 if (*current ==
'\n')
786 lastLineStart = current;
788 }
else if (c ==
'\n') {
789 lastLineStart = current;
794 column = int(location - lastLineStart) + 1;
798 String Reader::getLocationLineAndColumn(Location location)
const {
800 getLocationLineAndColumn(location, line, column);
801 char buffer[18 + 16 + 16 + 1];
802 jsoncpp_snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
807 String Reader::getFormatedErrorMessages()
const {
813 for (
const auto& error : errors_) {
815 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
816 formattedMessage +=
" " + error.message_ +
"\n";
819 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
821 return formattedMessage;
825 std::vector<Reader::StructuredError> allErrors;
826 for (
const auto& error : errors_) {
830 structured.
message = error.message_;
831 allErrors.push_back(structured);
837 ptrdiff_t
const length = end_ - begin_;
841 token.type_ = tokenError;
846 info.message_ = message;
847 info.extra_ =
nullptr;
848 errors_.push_back(info);
854 const Value& extra) {
855 ptrdiff_t
const length = end_ - begin_;
860 token.type_ = tokenError;
865 info.message_ = message;
867 errors_.push_back(info);
877 static OurFeatures all();
880 bool allowDroppedNullPlaceholders_;
881 bool allowNumericKeys_;
882 bool allowSingleQuotes_;
885 bool allowSpecialFloats_;
889 OurFeatures OurFeatures::all() {
return {}; }
899 typedef const Char* Location;
900 struct StructuredError {
901 ptrdiff_t offset_start;
902 ptrdiff_t offset_limit;
906 OurReader(OurFeatures
const& features);
907 bool parse(
const char* beginDoc,
910 bool collectComments =
true);
911 String getFormattedErrorMessages()
const;
912 std::vector<StructuredError> getStructuredErrors()
const;
913 bool pushError(
const Value& value,
const String& message);
914 bool pushError(
const Value& value,
const String& message,
const Value& extra);
918 OurReader(OurReader
const&);
919 void operator=(OurReader
const&);
922 tokenEndOfStream = 0,
936 tokenMemberSeparator,
955 typedef std::deque<ErrorInfo> Errors;
957 bool readToken(Token& token);
959 bool match(Location pattern,
int patternLength);
961 bool readCStyleComment();
962 bool readCppStyleComment();
964 bool readStringSingleQuote();
965 bool readNumber(
bool checkInf);
967 bool readObject(Token& token);
968 bool readArray(Token& token);
969 bool decodeNumber(Token& token);
970 bool decodeNumber(Token& token, Value& decoded);
971 bool decodeString(Token& token);
972 bool decodeString(Token& token,
String& decoded);
973 bool decodeDouble(Token& token);
974 bool decodeDouble(Token& token, Value& decoded);
975 bool decodeUnicodeCodePoint(Token& token,
978 unsigned int& unicode);
979 bool decodeUnicodeEscapeSequence(Token& token,
982 unsigned int& unicode);
983 bool addError(
const String& message, Token& token, Location extra =
nullptr);
984 bool recoverFromError(TokenType skipUntilToken);
985 bool addErrorAndRecover(
const String& message,
987 TokenType skipUntilToken);
988 void skipUntilSpace();
989 Value& currentValue();
992 getLocationLineAndColumn(Location location,
int& line,
int& column)
const;
993 String getLocationLineAndColumn(Location location)
const;
995 void skipCommentTokens(Token& token);
997 static String normalizeEOL(Location begin, Location end);
998 static bool containsNewLine(Location begin, Location end);
1000 typedef std::stack<Value*> Nodes;
1007 Location lastValueEnd_;
1011 OurFeatures
const features_;
1012 bool collectComments_;
1017 bool OurReader::containsNewLine(OurReader::Location begin,
1018 OurReader::Location end) {
1019 for (; begin < end; ++begin)
1020 if (*begin ==
'\n' || *begin ==
'\r')
1025 OurReader::OurReader(OurFeatures
const& features)
1026 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
1027 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
1030 bool OurReader::parse(
const char* beginDoc,
1033 bool collectComments) {
1034 if (!features_.allowComments_) {
1035 collectComments =
false;
1040 collectComments_ = collectComments;
1042 lastValueEnd_ =
nullptr;
1043 lastValue_ =
nullptr;
1044 commentsBefore_.clear();
1046 while (!nodes_.empty())
1050 bool successful = readValue();
1052 skipCommentTokens(token);
1053 if (features_.failIfExtra_) {
1054 if ((features_.strictRoot_ || token.type_ != tokenError) &&
1055 token.type_ != tokenEndOfStream) {
1056 addError(
"Extra non-whitespace after JSON value.", token);
1060 if (collectComments_ && !commentsBefore_.empty())
1062 if (features_.strictRoot_) {
1063 if (!root.isArray() && !root.isObject()) {
1066 token.type_ = tokenError;
1067 token.start_ = beginDoc;
1068 token.end_ = endDoc;
1070 "A valid JSON document must be either an array or an object value.",
1078 bool OurReader::readValue() {
1080 if (nodes_.size() > features_.stackLimit_)
1081 throwRuntimeError(
"Exceeded stackLimit in readValue().");
1083 skipCommentTokens(token);
1084 bool successful =
true;
1086 if (collectComments_ && !commentsBefore_.empty()) {
1088 commentsBefore_.clear();
1091 switch (token.type_) {
1092 case tokenObjectBegin:
1093 successful = readObject(token);
1094 currentValue().setOffsetLimit(current_ - begin_);
1096 case tokenArrayBegin:
1097 successful = readArray(token);
1098 currentValue().setOffsetLimit(current_ - begin_);
1101 successful = decodeNumber(token);
1104 successful = decodeString(token);
1108 currentValue().swapPayload(v);
1109 currentValue().setOffsetStart(token.start_ - begin_);
1110 currentValue().setOffsetLimit(token.end_ - begin_);
1114 currentValue().swapPayload(v);
1115 currentValue().setOffsetStart(token.start_ - begin_);
1116 currentValue().setOffsetLimit(token.end_ - begin_);
1120 currentValue().swapPayload(v);
1121 currentValue().setOffsetStart(token.start_ - begin_);
1122 currentValue().setOffsetLimit(token.end_ - begin_);
1125 Value v(std::numeric_limits<double>::quiet_NaN());
1126 currentValue().swapPayload(v);
1127 currentValue().setOffsetStart(token.start_ - begin_);
1128 currentValue().setOffsetLimit(token.end_ - begin_);
1131 Value v(std::numeric_limits<double>::infinity());
1132 currentValue().swapPayload(v);
1133 currentValue().setOffsetStart(token.start_ - begin_);
1134 currentValue().setOffsetLimit(token.end_ - begin_);
1137 Value v(-std::numeric_limits<double>::infinity());
1138 currentValue().swapPayload(v);
1139 currentValue().setOffsetStart(token.start_ - begin_);
1140 currentValue().setOffsetLimit(token.end_ - begin_);
1142 case tokenArraySeparator:
1143 case tokenObjectEnd:
1145 if (features_.allowDroppedNullPlaceholders_) {
1150 currentValue().swapPayload(v);
1151 currentValue().setOffsetStart(current_ - begin_ - 1);
1152 currentValue().setOffsetLimit(current_ - begin_);
1156 currentValue().setOffsetStart(token.start_ - begin_);
1157 currentValue().setOffsetLimit(token.end_ - begin_);
1158 return addError(
"Syntax error: value, object or array expected.", token);
1161 if (collectComments_) {
1162 lastValueEnd_ = current_;
1163 lastValue_ = ¤tValue();
1169 void OurReader::skipCommentTokens(Token& token) {
1170 if (features_.allowComments_) {
1173 }
while (token.type_ == tokenComment);
1179 bool OurReader::readToken(Token& token) {
1181 token.start_ = current_;
1182 Char c = getNextChar();
1186 token.type_ = tokenObjectBegin;
1189 token.type_ = tokenObjectEnd;
1192 token.type_ = tokenArrayBegin;
1195 token.type_ = tokenArrayEnd;
1198 token.type_ = tokenString;
1202 if (features_.allowSingleQuotes_) {
1203 token.type_ = tokenString;
1204 ok = readStringSingleQuote();
1208 token.type_ = tokenComment;
1221 token.type_ = tokenNumber;
1225 if (readNumber(
true)) {
1226 token.type_ = tokenNumber;
1228 token.type_ = tokenNegInf;
1229 ok = features_.allowSpecialFloats_ && match(
"nfinity", 7);
1233 token.type_ = tokenTrue;
1234 ok = match(
"rue", 3);
1237 token.type_ = tokenFalse;
1238 ok = match(
"alse", 4);
1241 token.type_ = tokenNull;
1242 ok = match(
"ull", 3);
1245 if (features_.allowSpecialFloats_) {
1246 token.type_ = tokenNaN;
1247 ok = match(
"aN", 2);
1253 if (features_.allowSpecialFloats_) {
1254 token.type_ = tokenPosInf;
1255 ok = match(
"nfinity", 7);
1261 token.type_ = tokenArraySeparator;
1264 token.type_ = tokenMemberSeparator;
1267 token.type_ = tokenEndOfStream;
1274 token.type_ = tokenError;
1275 token.end_ = current_;
1279 void OurReader::skipSpaces() {
1280 while (current_ != end_) {
1282 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n')
1289 bool OurReader::match(Location pattern,
int patternLength) {
1290 if (end_ - current_ < patternLength)
1292 int index = patternLength;
1294 if (current_[index] != pattern[index])
1296 current_ += patternLength;
1300 bool OurReader::readComment() {
1301 Location commentBegin = current_ - 1;
1302 Char c = getNextChar();
1303 bool successful =
false;
1305 successful = readCStyleComment();
1307 successful = readCppStyleComment();
1311 if (collectComments_) {
1313 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
1314 if (c !=
'*' || !containsNewLine(commentBegin, current_))
1318 addComment(commentBegin, current_, placement);
1323 String OurReader::normalizeEOL(OurReader::Location begin,
1324 OurReader::Location end) {
1326 normalized.reserve(static_cast<size_t>(end - begin));
1327 OurReader::Location current = begin;
1328 while (current != end) {
1329 char c = *current++;
1331 if (current != end && *current ==
'\n')
1343 void OurReader::addComment(Location begin,
1346 assert(collectComments_);
1347 const String& normalized = normalizeEOL(begin, end);
1349 assert(lastValue_ !=
nullptr);
1350 lastValue_->setComment(normalized, placement);
1352 commentsBefore_ += normalized;
1356 bool OurReader::readCStyleComment() {
1357 while ((current_ + 1) < end_) {
1358 Char c = getNextChar();
1359 if (c ==
'*' && *current_ ==
'/')
1362 return getNextChar() ==
'/';
1365 bool OurReader::readCppStyleComment() {
1366 while (current_ != end_) {
1367 Char c = getNextChar();
1372 if (current_ != end_ && *current_ ==
'\n')
1381 bool OurReader::readNumber(
bool checkInf) {
1382 const char* p = current_;
1383 if (checkInf && p != end_ && *p ==
'I') {
1389 while (c >=
'0' && c <=
'9')
1390 c = (current_ = p) < end_ ? *p++ :
'\0';
1393 c = (current_ = p) < end_ ? *p++ :
'\0';
1394 while (c >=
'0' && c <=
'9')
1395 c = (current_ = p) < end_ ? *p++ :
'\0';
1398 if (c ==
'e' || c ==
'E') {
1399 c = (current_ = p) < end_ ? *p++ :
'\0';
1400 if (c ==
'+' || c ==
'-')
1401 c = (current_ = p) < end_ ? *p++ :
'\0';
1402 while (c >=
'0' && c <=
'9')
1403 c = (current_ = p) < end_ ? *p++ :
'\0';
1407 bool OurReader::readString() {
1409 while (current_ != end_) {
1419 bool OurReader::readStringSingleQuote() {
1421 while (current_ != end_) {
1431 bool OurReader::readObject(Token& token) {
1435 currentValue().swapPayload(init);
1436 currentValue().setOffsetStart(token.start_ - begin_);
1437 while (readToken(tokenName)) {
1438 bool initialTokenOk =
true;
1439 while (tokenName.type_ == tokenComment && initialTokenOk)
1440 initialTokenOk = readToken(tokenName);
1441 if (!initialTokenOk)
1443 if (tokenName.type_ == tokenObjectEnd && name.empty())
1446 if (tokenName.type_ == tokenString) {
1447 if (!decodeString(tokenName, name))
1448 return recoverFromError(tokenObjectEnd);
1449 }
else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1451 if (!decodeNumber(tokenName, numberName))
1452 return recoverFromError(tokenObjectEnd);
1453 name = numberName.asString();
1457 if (name.length() >= (1U << 30))
1458 throwRuntimeError(
"keylength >= 2^30");
1459 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1460 String msg =
"Duplicate key: '" + name +
"'";
1461 return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
1465 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1466 return addErrorAndRecover(
"Missing ':' after object member name", colon,
1469 Value& value = currentValue()[name];
1470 nodes_.push(&value);
1471 bool ok = readValue();
1474 return recoverFromError(tokenObjectEnd);
1477 if (!readToken(comma) ||
1478 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1479 comma.type_ != tokenComment)) {
1480 return addErrorAndRecover(
"Missing ',' or '}' in object declaration",
1481 comma, tokenObjectEnd);
1483 bool finalizeTokenOk =
true;
1484 while (comma.type_ == tokenComment && finalizeTokenOk)
1485 finalizeTokenOk = readToken(comma);
1486 if (comma.type_ == tokenObjectEnd)
1489 return addErrorAndRecover(
"Missing '}' or object member name", tokenName,
1493 bool OurReader::readArray(Token& token) {
1495 currentValue().swapPayload(init);
1496 currentValue().setOffsetStart(token.start_ - begin_);
1498 if (current_ != end_ && *current_ ==
']')
1501 readToken(endArray);
1506 Value& value = currentValue()[index++];
1507 nodes_.push(&value);
1508 bool ok = readValue();
1511 return recoverFromError(tokenArrayEnd);
1515 ok = readToken(currentToken);
1516 while (currentToken.type_ == tokenComment && ok) {
1517 ok = readToken(currentToken);
1519 bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
1520 currentToken.type_ != tokenArrayEnd);
1521 if (!ok || badTokenType) {
1522 return addErrorAndRecover(
"Missing ',' or ']' in array declaration",
1523 currentToken, tokenArrayEnd);
1525 if (currentToken.type_ == tokenArrayEnd)
1531 bool OurReader::decodeNumber(Token& token) {
1533 if (!decodeNumber(token, decoded))
1535 currentValue().swapPayload(decoded);
1536 currentValue().setOffsetStart(token.start_ - begin_);
1537 currentValue().setOffsetLimit(token.end_ - begin_);
1541 bool OurReader::decodeNumber(Token& token, Value& decoded) {
1545 Location current = token.start_;
1546 bool isNegative = *current ==
'-';
1553 static const auto negative_threshold =
1555 static const auto negative_last_digit =
1558 const auto threshold = isNegative ? negative_threshold : positive_threshold;
1559 const auto last_digit =
1560 isNegative ? negative_last_digit : positive_last_digit;
1563 while (current < token.end_) {
1564 Char c = *current++;
1565 if (c < '0' || c >
'9')
1566 return decodeDouble(token, decoded);
1568 const auto digit(static_cast<Value::UInt>(c -
'0'));
1569 if (value >= threshold) {
1575 if (value > threshold || current != token.end_ || digit > last_digit) {
1576 return decodeDouble(token, decoded);
1579 value = value * 10 + digit;
1592 bool OurReader::decodeDouble(Token& token) {
1594 if (!decodeDouble(token, decoded))
1596 currentValue().swapPayload(decoded);
1597 currentValue().setOffsetStart(token.start_ - begin_);
1598 currentValue().setOffsetLimit(token.end_ - begin_);
1602 bool OurReader::decodeDouble(Token& token, Value& decoded) {
1604 const int bufferSize = 32;
1606 ptrdiff_t
const length = token.end_ - token.start_;
1610 return addError(
"Unable to parse token length", token);
1612 auto const ulength =
static_cast<size_t>(length);
1619 char format[] =
"%lf";
1621 if (length <= bufferSize) {
1622 Char buffer[bufferSize + 1];
1623 memcpy(buffer, token.start_, ulength);
1626 count = sscanf(buffer, format, &value);
1628 String buffer(token.start_, token.end_);
1629 count = sscanf(buffer.c_str(), format, &value);
1634 "'" +
String(token.start_, token.end_) +
"' is not a number.", token);
1639 bool OurReader::decodeString(Token& token) {
1641 if (!decodeString(token, decoded_string))
1643 Value decoded(decoded_string);
1644 currentValue().swapPayload(decoded);
1645 currentValue().setOffsetStart(token.start_ - begin_);
1646 currentValue().setOffsetLimit(token.end_ - begin_);
1650 bool OurReader::decodeString(Token& token,
String& decoded) {
1651 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
1652 Location current = token.start_ + 1;
1653 Location end = token.end_ - 1;
1654 while (current != end) {
1655 Char c = *current++;
1658 else if (c ==
'\\') {
1660 return addError(
"Empty escape sequence in string", token, current);
1661 Char escape = *current++;
1688 unsigned int unicode;
1689 if (!decodeUnicodeCodePoint(token, current, end, unicode))
1694 return addError(
"Bad escape sequence in string", token, current);
1703 bool OurReader::decodeUnicodeCodePoint(Token& token,
1706 unsigned int& unicode) {
1708 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1710 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1712 if (end - current < 6)
1714 "additional six characters expected to parse unicode surrogate pair.",
1716 if (*(current++) ==
'\\' && *(current++) ==
'u') {
1717 unsigned int surrogatePair;
1718 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1719 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1723 return addError(
"expecting another \\u token to begin the second half of " 1724 "a unicode surrogate pair",
1730 bool OurReader::decodeUnicodeEscapeSequence(Token& token,
1733 unsigned int& ret_unicode) {
1734 if (end - current < 4)
1736 "Bad unicode escape sequence in string: four digits expected.", token,
1739 for (
int index = 0; index < 4; ++index) {
1740 Char c = *current++;
1742 if (c >=
'0' && c <=
'9')
1744 else if (c >=
'a' && c <=
'f')
1745 unicode += c -
'a' + 10;
1746 else if (c >=
'A' && c <=
'F')
1747 unicode += c -
'A' + 10;
1750 "Bad unicode escape sequence in string: hexadecimal digit expected.",
1753 ret_unicode =
static_cast<unsigned int>(unicode);
1757 bool OurReader::addError(
const String& message, Token& token, Location extra) {
1759 info.token_ = token;
1760 info.message_ = message;
1761 info.extra_ = extra;
1762 errors_.push_back(info);
1766 bool OurReader::recoverFromError(TokenType skipUntilToken) {
1767 size_t errorCount = errors_.size();
1770 if (!readToken(skip))
1771 errors_.resize(errorCount);
1772 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
1775 errors_.resize(errorCount);
1779 bool OurReader::addErrorAndRecover(
const String& message,
1781 TokenType skipUntilToken) {
1782 addError(message, token);
1783 return recoverFromError(skipUntilToken);
1786 Value& OurReader::currentValue() {
return *(nodes_.top()); }
1788 OurReader::Char OurReader::getNextChar() {
1789 if (current_ == end_)
1794 void OurReader::getLocationLineAndColumn(Location location,
1796 int& column)
const {
1797 Location current = begin_;
1798 Location lastLineStart = current;
1800 while (current < location && current != end_) {
1801 Char c = *current++;
1803 if (*current ==
'\n')
1805 lastLineStart = current;
1807 }
else if (c ==
'\n') {
1808 lastLineStart = current;
1813 column = int(location - lastLineStart) + 1;
1817 String OurReader::getLocationLineAndColumn(Location location)
const {
1819 getLocationLineAndColumn(location, line, column);
1820 char buffer[18 + 16 + 16 + 1];
1821 jsoncpp_snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
1825 String OurReader::getFormattedErrorMessages()
const {
1827 for (
const auto& error : errors_) {
1829 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
1830 formattedMessage +=
" " + error.message_ +
"\n";
1833 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
1835 return formattedMessage;
1838 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors()
const {
1839 std::vector<OurReader::StructuredError> allErrors;
1840 for (
const auto& error : errors_) {
1841 OurReader::StructuredError structured;
1842 structured.offset_start = error.token_.start_ - begin_;
1843 structured.offset_limit = error.token_.end_ - begin_;
1844 structured.message = error.message_;
1845 allErrors.push_back(structured);
1850 bool OurReader::pushError(
const Value& value,
const String& message) {
1851 ptrdiff_t length = end_ - begin_;
1852 if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
1855 token.type_ = tokenError;
1856 token.start_ = begin_ + value.getOffsetStart();
1857 token.end_ = begin_ + value.getOffsetLimit();
1859 info.token_ = token;
1860 info.message_ = message;
1861 info.extra_ =
nullptr;
1862 errors_.push_back(info);
1866 bool OurReader::pushError(
const Value& value,
1868 const Value& extra) {
1869 ptrdiff_t length = end_ - begin_;
1870 if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
1871 extra.getOffsetLimit() > length)
1874 token.type_ = tokenError;
1875 token.start_ = begin_ + value.getOffsetStart();
1876 token.end_ = begin_ + value.getOffsetLimit();
1878 info.token_ = token;
1879 info.message_ = message;
1880 info.extra_ = begin_ + extra.getOffsetStart();
1881 errors_.push_back(info);
1885 bool OurReader::good()
const {
return errors_.empty(); }
1887 class OurCharReader :
public CharReader {
1888 bool const collectComments_;
1892 OurCharReader(
bool collectComments, OurFeatures
const& features)
1893 : collectComments_(collectComments), reader_(features) {}
1894 bool parse(
char const* beginDoc,
1898 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1900 *errs = reader_.getFormattedErrorMessages();
1910 OurFeatures features = OurFeatures::all();
1913 features.allowDroppedNullPlaceholders_ =
1916 features.allowSingleQuotes_ =
settings_[
"allowSingleQuotes"].
asBool();
1920 features.stackLimit_ =
static_cast<size_t>(
settings_[
"stackLimit"].
asUInt());
1923 features.allowSpecialFloats_ =
settings_[
"allowSpecialFloats"].
asBool();
1924 return new OurCharReader(collectComments, features);
1927 valid_keys->clear();
1928 valid_keys->insert(
"collectComments");
1929 valid_keys->insert(
"allowComments");
1930 valid_keys->insert(
"strictRoot");
1931 valid_keys->insert(
"allowDroppedNullPlaceholders");
1932 valid_keys->insert(
"allowNumericKeys");
1933 valid_keys->insert(
"allowSingleQuotes");
1934 valid_keys->insert(
"stackLimit");
1935 valid_keys->insert(
"failIfExtra");
1936 valid_keys->insert(
"rejectDupKeys");
1937 valid_keys->insert(
"allowSpecialFloats");
1942 invalid = &my_invalid;
1944 std::set<String> valid_keys;
1947 size_t n = keys.size();
1948 for (
size_t i = 0; i < n; ++i) {
1949 String const& key = keys[i];
1950 if (valid_keys.find(key) == valid_keys.end()) {
1962 (*settings)[
"allowComments"] =
false;
1963 (*settings)[
"strictRoot"] =
true;
1964 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1965 (*settings)[
"allowNumericKeys"] =
false;
1966 (*settings)[
"allowSingleQuotes"] =
false;
1967 (*settings)[
"stackLimit"] = 1000;
1968 (*settings)[
"failIfExtra"] =
true;
1969 (*settings)[
"rejectDupKeys"] =
true;
1970 (*settings)[
"allowSpecialFloats"] =
false;
1976 (*settings)[
"collectComments"] =
true;
1977 (*settings)[
"allowComments"] =
true;
1978 (*settings)[
"strictRoot"] =
false;
1979 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1980 (*settings)[
"allowNumericKeys"] =
false;
1981 (*settings)[
"allowSingleQuotes"] =
false;
1982 (*settings)[
"stackLimit"] = 1000;
1983 (*settings)[
"failIfExtra"] =
false;
1984 (*settings)[
"rejectDupKeys"] =
false;
1985 (*settings)[
"allowSpecialFloats"] =
false;
1997 ssin << sin.rdbuf();
1999 char const* begin = doc.data();
2000 char const* end = begin + doc.size();
2003 return reader->parse(begin, end, root, errs);
2011 throwRuntimeError(errs);
std::vector< String > Members
static String codePointToUTF8(unsigned int cp)
Converts a unicode code-point to UTF-8.
std::vector< StructuredError > getStructuredErrors() const
Returns a vector of structured erros encounted while parsing.
void fixNumericLocaleInput(Iter begin, Iter end)
static void strictMode(Json::Value *settings)
Same as old Features::strictMode().
array value (ordered list)
std::auto_ptr< CharReader > CharReaderPtr
std::basic_istringstream< String::value_type, String::traits_type, String::allocator_type > IStringStream
Json::Value settings_
Configuration of this builder.
bool empty() const
Return true if empty array, empty object, or null; otherwise, false.
Members getMemberNames() const
Return a list of the member names.
void setComment(const char *comment, size_t len, CommentPlacement placement)
Comments must be //... or /* ... */.
object value (collection of name/value pairs).
void swapPayload(Value &other)
Swap values but leave comments and source offsets in place.
static const Int maxInt
Maximum signed int value that can be stored in a Json::Value.
ptrdiff_t getOffsetStart() const
Json::LargestUInt LargestUInt
CharReader * newCharReader() const override
Allocate a CharReader via operator new().
Features()
Initialize the configuration like JsonConfig::allFeatures;.
An error tagged with where in the JSON text it was encountered.
static const LargestInt minLargestInt
Minimum signed integer value that can be stored in a Json::Value.
IStream & operator>>(IStream &, Value &)
Read from 'sin' into 'root'.
bool allowComments_
true if comments are allowed. Default: true.
std::basic_ostringstream< String::value_type, String::traits_type, String::allocator_type > OStringStream
bool allowNumericKeys_
true if numeric object key are allowed. Default: false.
static size_t const stackLimit_g
bool parse(const std::string &document, Value &root, bool collectComments=true)
Read a Value from a JSON document.
JSON (JavaScript Object Notation).
bool allowDroppedNullPlaceholders_
true if dropped null placeholders are allowed. Default: false.
bool pushError(const Value &value, const String &message)
Add a semantic error message.
Json::LargestInt LargestInt
ptrdiff_t getOffsetLimit() const
~CharReaderBuilder() override
bool good() const
Return whether there are any errors.
static void setDefaults(Json::Value *settings)
Called by ctor, but you can use this to reset settings_.
bool validate(Json::Value *invalid) const
Interface for reading JSON from a char array.
void setOffsetStart(ptrdiff_t start)
static Features all()
A configuration that allows all features and assumes all strings are UTF-8.
a comment on the line after a value (only make sense for
static void getValidReaderKeys(std::set< String > *valid_keys)
#define JSONCPP_DEPRECATED_STACK_LIMIT
void setOffsetLimit(ptrdiff_t limit)
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.
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
a comment just after a value on the same line
bool parseFromStream(CharReader::Factory const &, IStream &, Value *root, std::string *errs)
Consume entire stream and use its begin/end.
Value & operator[](const String &key)
A simple way to update a specific setting.
std::basic_string< char, std::char_traits< char >, Allocator< char > > String
String getFormattedErrorMessages() const
Returns a user friendly string that list errors in the parsed document.
static const LargestInt maxLargestInt
Maximum signed integer value that can be stored in a Json::Value.
static const LargestUInt maxLargestUInt
Maximum unsigned integer value that can be stored in a Json::Value.