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() {
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();
1053 skipCommentTokens(token);
1054 if (features_.failIfExtra_) {
1055 if ((features_.strictRoot_ || token.type_ != tokenError) &&
1056 token.type_ != tokenEndOfStream) {
1057 addError(
"Extra non-whitespace after JSON value.", token);
1061 if (collectComments_ && !commentsBefore_.empty())
1063 if (features_.strictRoot_) {
1064 if (!root.isArray() && !root.isObject()) {
1067 token.type_ = tokenError;
1068 token.start_ = beginDoc;
1069 token.end_ = endDoc;
1071 "A valid JSON document must be either an array or an object value.",
1079 bool OurReader::readValue() {
1081 if (nodes_.size() > features_.stackLimit_)
1084 skipCommentTokens(token);
1085 bool successful =
true;
1087 if (collectComments_ && !commentsBefore_.empty()) {
1089 commentsBefore_.clear();
1092 switch (token.type_) {
1093 case tokenObjectBegin:
1094 successful = readObject(token);
1095 currentValue().setOffsetLimit(current_ - begin_);
1097 case tokenArrayBegin:
1098 successful = readArray(token);
1099 currentValue().setOffsetLimit(current_ - begin_);
1102 successful = decodeNumber(token);
1105 successful = decodeString(token);
1109 currentValue().swapPayload(v);
1110 currentValue().setOffsetStart(token.start_ - begin_);
1111 currentValue().setOffsetLimit(token.end_ - begin_);
1115 currentValue().swapPayload(v);
1116 currentValue().setOffsetStart(token.start_ - begin_);
1117 currentValue().setOffsetLimit(token.end_ - begin_);
1121 currentValue().swapPayload(v);
1122 currentValue().setOffsetStart(token.start_ - begin_);
1123 currentValue().setOffsetLimit(token.end_ - begin_);
1126 Value v(std::numeric_limits<double>::quiet_NaN());
1127 currentValue().swapPayload(v);
1128 currentValue().setOffsetStart(token.start_ - begin_);
1129 currentValue().setOffsetLimit(token.end_ - begin_);
1132 Value v(std::numeric_limits<double>::infinity());
1133 currentValue().swapPayload(v);
1134 currentValue().setOffsetStart(token.start_ - begin_);
1135 currentValue().setOffsetLimit(token.end_ - begin_);
1138 Value v(-std::numeric_limits<double>::infinity());
1139 currentValue().swapPayload(v);
1140 currentValue().setOffsetStart(token.start_ - begin_);
1141 currentValue().setOffsetLimit(token.end_ - begin_);
1143 case tokenArraySeparator:
1144 case tokenObjectEnd:
1146 if (features_.allowDroppedNullPlaceholders_) {
1151 currentValue().swapPayload(v);
1152 currentValue().setOffsetStart(current_ - begin_ - 1);
1153 currentValue().setOffsetLimit(current_ - begin_);
1157 currentValue().setOffsetStart(token.start_ - begin_);
1158 currentValue().setOffsetLimit(token.end_ - begin_);
1159 return addError(
"Syntax error: value, object or array expected.", token);
1162 if (collectComments_) {
1163 lastValueEnd_ = current_;
1164 lastValue_ = ¤tValue();
1170 void OurReader::skipCommentTokens(Token& token) {
1171 if (features_.allowComments_) {
1174 }
while (token.type_ == tokenComment);
1180 bool OurReader::readToken(Token& token) {
1182 token.start_ = current_;
1183 Char c = getNextChar();
1187 token.type_ = tokenObjectBegin;
1190 token.type_ = tokenObjectEnd;
1193 token.type_ = tokenArrayBegin;
1196 token.type_ = tokenArrayEnd;
1199 token.type_ = tokenString;
1203 if (features_.allowSingleQuotes_) {
1204 token.type_ = tokenString;
1205 ok = readStringSingleQuote();
1209 token.type_ = tokenComment;
1222 token.type_ = tokenNumber;
1226 if (readNumber(
true)) {
1227 token.type_ = tokenNumber;
1229 token.type_ = tokenNegInf;
1230 ok = features_.allowSpecialFloats_ && match(
"nfinity", 7);
1234 token.type_ = tokenTrue;
1235 ok = match(
"rue", 3);
1238 token.type_ = tokenFalse;
1239 ok = match(
"alse", 4);
1242 token.type_ = tokenNull;
1243 ok = match(
"ull", 3);
1246 if (features_.allowSpecialFloats_) {
1247 token.type_ = tokenNaN;
1248 ok = match(
"aN", 2);
1254 if (features_.allowSpecialFloats_) {
1255 token.type_ = tokenPosInf;
1256 ok = match(
"nfinity", 7);
1262 token.type_ = tokenArraySeparator;
1265 token.type_ = tokenMemberSeparator;
1268 token.type_ = tokenEndOfStream;
1275 token.type_ = tokenError;
1276 token.end_ = current_;
1280 void OurReader::skipSpaces() {
1281 while (current_ != end_) {
1283 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n')
1290 bool OurReader::match(Location pattern,
int patternLength) {
1291 if (end_ - current_ < patternLength)
1293 int index = patternLength;
1295 if (current_[index] != pattern[index])
1297 current_ += patternLength;
1301 bool OurReader::readComment() {
1302 Location commentBegin = current_ - 1;
1303 Char c = getNextChar();
1304 bool successful =
false;
1306 successful = readCStyleComment();
1308 successful = readCppStyleComment();
1312 if (collectComments_) {
1314 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
1315 if (c !=
'*' || !containsNewLine(commentBegin, current_))
1319 addComment(commentBegin, current_, placement);
1324 String OurReader::normalizeEOL(OurReader::Location begin,
1325 OurReader::Location end) {
1327 normalized.reserve(static_cast<size_t>(end - begin));
1328 OurReader::Location current = begin;
1329 while (current != end) {
1330 char c = *current++;
1332 if (current != end && *current ==
'\n')
1344 void OurReader::addComment(Location begin,
1347 assert(collectComments_);
1348 const String& normalized = normalizeEOL(begin, end);
1350 assert(lastValue_ !=
nullptr);
1351 lastValue_->setComment(normalized, placement);
1353 commentsBefore_ += normalized;
1357 bool OurReader::readCStyleComment() {
1358 while ((current_ + 1) < end_) {
1359 Char c = getNextChar();
1360 if (c ==
'*' && *current_ ==
'/')
1363 return getNextChar() ==
'/';
1366 bool OurReader::readCppStyleComment() {
1367 while (current_ != end_) {
1368 Char c = getNextChar();
1373 if (current_ != end_ && *current_ ==
'\n')
1382 bool OurReader::readNumber(
bool checkInf) {
1383 const char* p = current_;
1384 if (checkInf && p != end_ && *p ==
'I') {
1390 while (c >=
'0' && c <=
'9')
1391 c = (current_ = p) < end_ ? *p++ :
'\0';
1394 c = (current_ = p) < end_ ? *p++ :
'\0';
1395 while (c >=
'0' && c <=
'9')
1396 c = (current_ = p) < end_ ? *p++ :
'\0';
1399 if (c ==
'e' || c ==
'E') {
1400 c = (current_ = p) < end_ ? *p++ :
'\0';
1401 if (c ==
'+' || c ==
'-')
1402 c = (current_ = p) < end_ ? *p++ :
'\0';
1403 while (c >=
'0' && c <=
'9')
1404 c = (current_ = p) < end_ ? *p++ :
'\0';
1408 bool OurReader::readString() {
1410 while (current_ != end_) {
1420 bool OurReader::readStringSingleQuote() {
1422 while (current_ != end_) {
1432 bool OurReader::readObject(Token& token) {
1436 currentValue().swapPayload(init);
1437 currentValue().setOffsetStart(token.start_ - begin_);
1438 while (readToken(tokenName)) {
1439 bool initialTokenOk =
true;
1440 while (tokenName.type_ == tokenComment && initialTokenOk)
1441 initialTokenOk = readToken(tokenName);
1442 if (!initialTokenOk)
1444 if (tokenName.type_ == tokenObjectEnd && name.empty())
1447 if (tokenName.type_ == tokenString) {
1448 if (!decodeString(tokenName, name))
1449 return recoverFromError(tokenObjectEnd);
1450 }
else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1452 if (!decodeNumber(tokenName, numberName))
1453 return recoverFromError(tokenObjectEnd);
1454 name = numberName.asString();
1458 if (name.length() >= (1U << 30))
1460 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1461 String msg =
"Duplicate key: '" + name +
"'";
1462 return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
1466 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1467 return addErrorAndRecover(
"Missing ':' after object member name", colon,
1470 Value& value = currentValue()[name];
1471 nodes_.push(&value);
1472 bool ok = readValue();
1475 return recoverFromError(tokenObjectEnd);
1478 if (!readToken(comma) ||
1479 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1480 comma.type_ != tokenComment)) {
1481 return addErrorAndRecover(
"Missing ',' or '}' in object declaration",
1482 comma, tokenObjectEnd);
1484 bool finalizeTokenOk =
true;
1485 while (comma.type_ == tokenComment && finalizeTokenOk)
1486 finalizeTokenOk = readToken(comma);
1487 if (comma.type_ == tokenObjectEnd)
1490 return addErrorAndRecover(
"Missing '}' or object member name", tokenName,
1494 bool OurReader::readArray(Token& token) {
1496 currentValue().swapPayload(init);
1497 currentValue().setOffsetStart(token.start_ - begin_);
1499 if (current_ != end_ && *current_ ==
']')
1502 readToken(endArray);
1507 Value& value = currentValue()[index++];
1508 nodes_.push(&value);
1509 bool ok = readValue();
1512 return recoverFromError(tokenArrayEnd);
1516 ok = readToken(currentToken);
1517 while (currentToken.type_ == tokenComment && ok) {
1518 ok = readToken(currentToken);
1520 bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
1521 currentToken.type_ != tokenArrayEnd);
1522 if (!ok || badTokenType) {
1523 return addErrorAndRecover(
"Missing ',' or ']' in array declaration",
1524 currentToken, tokenArrayEnd);
1526 if (currentToken.type_ == tokenArrayEnd)
1532 bool OurReader::decodeNumber(Token& token) {
1534 if (!decodeNumber(token, decoded))
1536 currentValue().swapPayload(decoded);
1537 currentValue().setOffsetStart(token.start_ - begin_);
1538 currentValue().setOffsetLimit(token.end_ - begin_);
1542 bool OurReader::decodeNumber(Token& token, Value& decoded) {
1546 Location current = token.start_;
1547 bool isNegative = *current ==
'-';
1554 static const auto negative_threshold =
1556 static const auto negative_last_digit =
1559 const auto threshold = isNegative ? negative_threshold : positive_threshold;
1560 const auto last_digit =
1561 isNegative ? negative_last_digit : positive_last_digit;
1564 while (current < token.end_) {
1565 Char c = *current++;
1566 if (c < '0' || c >
'9')
1567 return decodeDouble(token, decoded);
1569 const auto digit(static_cast<Value::UInt>(c -
'0'));
1570 if (value >= threshold) {
1576 if (value > threshold || current != token.end_ || digit > last_digit) {
1577 return decodeDouble(token, decoded);
1580 value = value * 10 + digit;
1593 bool OurReader::decodeDouble(Token& token) {
1595 if (!decodeDouble(token, decoded))
1597 currentValue().swapPayload(decoded);
1598 currentValue().setOffsetStart(token.start_ - begin_);
1599 currentValue().setOffsetLimit(token.end_ - begin_);
1603 bool OurReader::decodeDouble(Token& token, Value& decoded) {
1605 const int bufferSize = 32;
1607 ptrdiff_t
const length = token.end_ - token.start_;
1611 return addError(
"Unable to parse token length", token);
1613 auto const ulength = static_cast<size_t>(length);
1620 char format[] =
"%lf";
1622 if (length <= bufferSize) {
1623 Char buffer[bufferSize + 1];
1624 memcpy(buffer, token.start_, ulength);
1627 count = sscanf(buffer, format, &value);
1629 String buffer(token.start_, token.end_);
1630 count = sscanf(buffer.c_str(), format, &value);
1635 "'" +
String(token.start_, token.end_) +
"' is not a number.", token);
1640 bool OurReader::decodeString(Token& token) {
1642 if (!decodeString(token, decoded_string))
1644 Value decoded(decoded_string);
1645 currentValue().swapPayload(decoded);
1646 currentValue().setOffsetStart(token.start_ - begin_);
1647 currentValue().setOffsetLimit(token.end_ - begin_);
1651 bool OurReader::decodeString(Token& token,
String& decoded) {
1652 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
1653 Location current = token.start_ + 1;
1654 Location end = token.end_ - 1;
1655 while (current != end) {
1656 Char c = *current++;
1659 else if (c ==
'\\') {
1661 return addError(
"Empty escape sequence in string", token, current);
1662 Char escape = *current++;
1689 unsigned int unicode;
1690 if (!decodeUnicodeCodePoint(token, current, end, unicode))
1695 return addError(
"Bad escape sequence in string", token, current);
1704 bool OurReader::decodeUnicodeCodePoint(Token& token,
1707 unsigned int& unicode) {
1709 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1711 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1713 if (end - current < 6)
1715 "additional six characters expected to parse unicode surrogate pair.",
1717 if (*(current++) ==
'\\' && *(current++) ==
'u') {
1718 unsigned int surrogatePair;
1719 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1720 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1724 return addError(
"expecting another \\u token to begin the second half of " 1725 "a unicode surrogate pair",
1731 bool OurReader::decodeUnicodeEscapeSequence(Token& token,
1734 unsigned int& ret_unicode) {
1735 if (end - current < 4)
1737 "Bad unicode escape sequence in string: four digits expected.", token,
1740 for (
int index = 0; index < 4; ++index) {
1741 Char c = *current++;
1743 if (c >=
'0' && c <=
'9')
1745 else if (c >=
'a' && c <=
'f')
1746 unicode += c -
'a' + 10;
1747 else if (c >=
'A' && c <=
'F')
1748 unicode += c -
'A' + 10;
1751 "Bad unicode escape sequence in string: hexadecimal digit expected.",
1754 ret_unicode = static_cast<unsigned int>(unicode);
1758 bool OurReader::addError(
const String& message, Token& token, Location extra) {
1760 info.token_ = token;
1761 info.message_ = message;
1762 info.extra_ = extra;
1763 errors_.push_back(info);
1767 bool OurReader::recoverFromError(TokenType skipUntilToken) {
1768 size_t errorCount = errors_.size();
1771 if (!readToken(skip))
1772 errors_.resize(errorCount);
1773 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
1776 errors_.resize(errorCount);
1780 bool OurReader::addErrorAndRecover(
const String& message,
1782 TokenType skipUntilToken) {
1783 addError(message, token);
1784 return recoverFromError(skipUntilToken);
1787 Value& OurReader::currentValue() {
return *(nodes_.top()); }
1789 OurReader::Char OurReader::getNextChar() {
1790 if (current_ == end_)
1795 void OurReader::getLocationLineAndColumn(Location location,
1797 int& column)
const {
1798 Location current = begin_;
1799 Location lastLineStart = current;
1801 while (current < location && current != end_) {
1802 Char c = *current++;
1804 if (*current ==
'\n')
1806 lastLineStart = current;
1808 }
else if (c ==
'\n') {
1809 lastLineStart = current;
1814 column = int(location - lastLineStart) + 1;
1818 String OurReader::getLocationLineAndColumn(Location location)
const {
1820 getLocationLineAndColumn(location, line, column);
1821 char buffer[18 + 16 + 16 + 1];
1822 jsoncpp_snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
1826 String OurReader::getFormattedErrorMessages()
const {
1828 for (
const auto& error : errors_) {
1830 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
1831 formattedMessage +=
" " + error.message_ +
"\n";
1834 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
1836 return formattedMessage;
1839 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors()
const {
1840 std::vector<OurReader::StructuredError> allErrors;
1841 for (
const auto& error : errors_) {
1842 OurReader::StructuredError structured;
1843 structured.offset_start = error.token_.start_ - begin_;
1844 structured.offset_limit = error.token_.end_ - begin_;
1845 structured.message = error.message_;
1846 allErrors.push_back(structured);
1851 bool OurReader::pushError(
const Value& value,
const String& message) {
1852 ptrdiff_t length = end_ - begin_;
1853 if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
1856 token.type_ = tokenError;
1857 token.start_ = begin_ + value.getOffsetStart();
1858 token.end_ = begin_ + value.getOffsetLimit();
1860 info.token_ = token;
1861 info.message_ = message;
1862 info.extra_ =
nullptr;
1863 errors_.push_back(info);
1867 bool OurReader::pushError(
const Value& value,
1869 const Value& extra) {
1870 ptrdiff_t length = end_ - begin_;
1871 if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
1872 extra.getOffsetLimit() > length)
1875 token.type_ = tokenError;
1876 token.start_ = begin_ + value.getOffsetStart();
1877 token.end_ = begin_ + value.getOffsetLimit();
1879 info.token_ = token;
1880 info.message_ = message;
1881 info.extra_ = begin_ + extra.getOffsetStart();
1882 errors_.push_back(info);
1886 bool OurReader::good()
const {
return errors_.empty(); }
1888 class OurCharReader :
public CharReader {
1889 bool const collectComments_;
1893 OurCharReader(
bool collectComments, OurFeatures
const& features)
1894 : collectComments_(collectComments), reader_(features) {}
1895 bool parse(
char const* beginDoc,
1899 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1901 *errs = reader_.getFormattedErrorMessages();
1911 OurFeatures features = OurFeatures::all();
1914 features.allowDroppedNullPlaceholders_ =
1917 features.allowSingleQuotes_ =
settings_[
"allowSingleQuotes"].
asBool();
1921 features.stackLimit_ = static_cast<size_t>(
settings_[
"stackLimit"].asUInt());
1924 features.allowSpecialFloats_ =
settings_[
"allowSpecialFloats"].
asBool();
1925 return new OurCharReader(collectComments, features);
1928 valid_keys->clear();
1929 valid_keys->insert(
"collectComments");
1930 valid_keys->insert(
"allowComments");
1931 valid_keys->insert(
"strictRoot");
1932 valid_keys->insert(
"allowDroppedNullPlaceholders");
1933 valid_keys->insert(
"allowNumericKeys");
1934 valid_keys->insert(
"allowSingleQuotes");
1935 valid_keys->insert(
"stackLimit");
1936 valid_keys->insert(
"failIfExtra");
1937 valid_keys->insert(
"rejectDupKeys");
1938 valid_keys->insert(
"allowSpecialFloats");
1943 invalid = &my_invalid;
1945 std::set<String> valid_keys;
1948 size_t n = keys.size();
1949 for (
size_t i = 0; i < n; ++i) {
1950 String const& key = keys[i];
1951 if (valid_keys.find(key) == valid_keys.end()) {
1963 (*settings)[
"allowComments"] =
false;
1964 (*settings)[
"strictRoot"] =
true;
1965 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1966 (*settings)[
"allowNumericKeys"] =
false;
1967 (*settings)[
"allowSingleQuotes"] =
false;
1968 (*settings)[
"stackLimit"] = 1000;
1969 (*settings)[
"failIfExtra"] =
true;
1970 (*settings)[
"rejectDupKeys"] =
true;
1971 (*settings)[
"allowSpecialFloats"] =
false;
1977 (*settings)[
"collectComments"] =
true;
1978 (*settings)[
"allowComments"] =
true;
1979 (*settings)[
"strictRoot"] =
false;
1980 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1981 (*settings)[
"allowNumericKeys"] =
false;
1982 (*settings)[
"allowSingleQuotes"] =
false;
1983 (*settings)[
"stackLimit"] = 1000;
1984 (*settings)[
"failIfExtra"] =
false;
1985 (*settings)[
"rejectDupKeys"] =
false;
1986 (*settings)[
"allowSpecialFloats"] =
false;
1998 ssin << sin.rdbuf();
2000 char const* begin = doc.data();
2001 char const* end = begin + doc.size();
2004 return reader->parse(begin, end, root, 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)
void throwRuntimeError(String const &msg)
used internally
#define JSONCPP_DEPRECATED_STACK_LIMIT
bool parseFromStream(CharReader::Factory const &, IStream &, Value *root, String *errs)
Consume entire stream and use its begin/end.
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
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.