7 #if !defined(JSON_IS_AMALGAMATION) 12 #endif // if !defined(JSON_IS_AMALGAMATION) 24 #if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above 25 #define snprintf sprintf_s 26 #elif _MSC_VER >= 1900 // VC++ 14.0 and above 27 #define snprintf std::snprintf 29 #define snprintf _snprintf 31 #elif defined(__ANDROID__) || defined(__QNXNTO__) 32 #define snprintf snprintf 33 #elif __cplusplus >= 201103L 34 #if !defined(__MINGW32__) && !defined(__CYGWIN__) 35 #define snprintf std::snprintf 39 #if defined(__QNXNTO__) 40 #define sscanf std::sscanf 43 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 45 #pragma warning(disable : 4996) 49 #if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) 50 #define JSONCPP_DEPRECATED_STACK_LIMIT 1000 57 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) 67 : allowComments_(true), strictRoot_(false),
68 allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
85 for (; begin < end; ++begin)
86 if (*begin ==
'\n' || *begin ==
'\r')
95 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
96 lastValue_(), commentsBefore_(), features_(
Features::all()),
100 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
101 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
106 document_.assign(document.begin(), document.end());
107 const char* begin = document_.c_str();
108 const char* end = begin + document_.length();
109 return parse(begin, end, root, collectComments);
121 std::getline(sin, doc, (
char)EOF);
122 return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
128 bool collectComments) {
130 collectComments =
false;
135 collectComments_ = collectComments;
139 commentsBefore_.clear();
141 while (!nodes_.empty())
145 bool successful = readValue();
147 skipCommentTokens(token);
148 if (collectComments_ && !commentsBefore_.empty())
154 token.type_ = tokenError;
155 token.start_ = beginDoc;
158 "A valid JSON document must be either an array or an object value.",
166 bool Reader::readValue() {
170 if (nodes_.size() >
stackLimit_g) throwRuntimeError(
"Exceeded stackLimit in readValue().");
173 skipCommentTokens(token);
174 bool successful =
true;
176 if (collectComments_ && !commentsBefore_.empty()) {
178 commentsBefore_.clear();
181 switch (token.type_) {
182 case tokenObjectBegin:
183 successful = readObject(token);
186 case tokenArrayBegin:
187 successful = readArray(token);
191 successful = decodeNumber(token);
194 successful = decodeString(token);
220 case tokenArraySeparator:
236 return addError(
"Syntax error: value, object or array expected.", token);
239 if (collectComments_) {
240 lastValueEnd_ = current_;
241 lastValue_ = ¤tValue();
247 void Reader::skipCommentTokens(Token& token) {
251 }
while (token.type_ == tokenComment);
257 bool Reader::readToken(Token& token) {
259 token.start_ = current_;
260 Char c = getNextChar();
264 token.type_ = tokenObjectBegin;
267 token.type_ = tokenObjectEnd;
270 token.type_ = tokenArrayBegin;
273 token.type_ = tokenArrayEnd;
276 token.type_ = tokenString;
280 token.type_ = tokenComment;
294 token.type_ = tokenNumber;
298 token.type_ = tokenTrue;
299 ok = match(
"rue", 3);
302 token.type_ = tokenFalse;
303 ok = match(
"alse", 4);
306 token.type_ = tokenNull;
307 ok = match(
"ull", 3);
310 token.type_ = tokenArraySeparator;
313 token.type_ = tokenMemberSeparator;
316 token.type_ = tokenEndOfStream;
323 token.type_ = tokenError;
324 token.end_ = current_;
328 void Reader::skipSpaces() {
329 while (current_ != end_) {
331 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n')
338 bool Reader::match(Location pattern,
int patternLength) {
339 if (end_ - current_ < patternLength)
341 int index = patternLength;
343 if (current_[index] != pattern[index])
345 current_ += patternLength;
349 bool Reader::readComment() {
350 Location commentBegin = current_ - 1;
351 Char c = getNextChar();
352 bool successful =
false;
354 successful = readCStyleComment();
356 successful = readCppStyleComment();
360 if (collectComments_) {
362 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
363 if (c !=
'*' || !containsNewLine(commentBegin, current_))
367 addComment(commentBegin, current_, placement);
374 normalized.reserve(static_cast<size_t>(end - begin));
376 while (current != end) {
379 if (current != end && *current ==
'\n')
392 Reader::addComment(Location begin, Location end,
CommentPlacement placement) {
393 assert(collectComments_);
396 assert(lastValue_ != 0);
397 lastValue_->
setComment(normalized, placement);
399 commentsBefore_ += normalized;
403 bool Reader::readCStyleComment() {
404 while ((current_ + 1) < end_) {
405 Char c = getNextChar();
406 if (c ==
'*' && *current_ ==
'/')
409 return getNextChar() ==
'/';
412 bool Reader::readCppStyleComment() {
413 while (current_ != end_) {
414 Char c = getNextChar();
419 if (current_ != end_ && *current_ ==
'\n')
428 void Reader::readNumber() {
429 const char *p = current_;
432 while (c >=
'0' && c <=
'9')
433 c = (current_ = p) < end_ ? *p++ :
'\0';
436 c = (current_ = p) < end_ ? *p++ :
'\0';
437 while (c >=
'0' && c <=
'9')
438 c = (current_ = p) < end_ ? *p++ :
'\0';
441 if (c ==
'e' || c ==
'E') {
442 c = (current_ = p) < end_ ? *p++ :
'\0';
443 if (c ==
'+' || c ==
'-')
444 c = (current_ = p) < end_ ? *p++ :
'\0';
445 while (c >=
'0' && c <=
'9')
446 c = (current_ = p) < end_ ? *p++ :
'\0';
450 bool Reader::readString() {
452 while (current_ != end_) {
462 bool Reader::readObject(Token& tokenStart) {
468 while (readToken(tokenName)) {
469 bool initialTokenOk =
true;
470 while (tokenName.type_ == tokenComment && initialTokenOk)
471 initialTokenOk = readToken(tokenName);
474 if (tokenName.type_ == tokenObjectEnd && name.empty())
477 if (tokenName.type_ == tokenString) {
478 if (!decodeString(tokenName, name))
479 return recoverFromError(tokenObjectEnd);
482 if (!decodeNumber(tokenName, numberName))
483 return recoverFromError(tokenObjectEnd);
490 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
491 return addErrorAndRecover(
492 "Missing ':' after object member name", colon, tokenObjectEnd);
494 Value& value = currentValue()[name];
496 bool ok = readValue();
499 return recoverFromError(tokenObjectEnd);
502 if (!readToken(comma) ||
503 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
504 comma.type_ != tokenComment)) {
505 return addErrorAndRecover(
506 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
508 bool finalizeTokenOk =
true;
509 while (comma.type_ == tokenComment && finalizeTokenOk)
510 finalizeTokenOk = readToken(comma);
511 if (comma.type_ == tokenObjectEnd)
514 return addErrorAndRecover(
515 "Missing '}' or object member name", tokenName, tokenObjectEnd);
518 bool Reader::readArray(Token& tokenStart) {
523 if (current_ != end_ && *current_ ==
']')
531 Value& value = currentValue()[index++];
533 bool ok = readValue();
536 return recoverFromError(tokenArrayEnd);
540 ok = readToken(token);
541 while (token.type_ == tokenComment && ok) {
542 ok = readToken(token);
545 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
546 if (!ok || badTokenType) {
547 return addErrorAndRecover(
548 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
550 if (token.type_ == tokenArrayEnd)
556 bool Reader::decodeNumber(Token& token) {
558 if (!decodeNumber(token, decoded))
566 bool Reader::decodeNumber(Token& token, Value& decoded) {
571 bool isNegative = *current ==
'-';
580 while (current < token.end_) {
582 if (c < '0' || c >
'9')
583 return decodeDouble(token, decoded);
584 Value::UInt digit(static_cast<Value::UInt>(c -
'0'));
585 if (value >= threshold) {
590 if (value > threshold || current != token.end_ ||
591 digit > maxIntegerValue % 10) {
592 return decodeDouble(token, decoded);
595 value = value * 10 + digit;
597 if (isNegative && value == maxIntegerValue)
608 bool Reader::decodeDouble(Token& token) {
610 if (!decodeDouble(token, decoded))
618 bool Reader::decodeDouble(Token& token, Value& decoded) {
624 "' is not a number.",
630 bool Reader::decodeString(Token& token) {
632 if (!decodeString(token, decoded_string))
634 Value decoded(decoded_string);
641 bool Reader::decodeString(Token& token,
JSONCPP_STRING& decoded) {
642 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
643 Location current = token.start_ + 1;
645 while (current != end) {
649 else if (c ==
'\\') {
651 return addError(
"Empty escape sequence in string", token, current);
652 Char escape = *current++;
679 unsigned int unicode;
680 if (!decodeUnicodeCodePoint(token, current, end, unicode))
685 return addError(
"Bad escape sequence in string", token, current);
694 bool Reader::decodeUnicodeCodePoint(Token& token,
697 unsigned int& unicode) {
699 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
701 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
703 if (end - current < 6)
705 "additional six characters expected to parse unicode surrogate pair.",
708 unsigned int surrogatePair;
709 if (*(current++) ==
'\\' && *(current++) ==
'u') {
710 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
711 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
715 return addError(
"expecting another \\u token to begin the second half of " 716 "a unicode surrogate pair",
723 bool Reader::decodeUnicodeEscapeSequence(Token& token,
726 unsigned int& ret_unicode) {
727 if (end - current < 4)
729 "Bad unicode escape sequence in string: four digits expected.",
733 for (
int index = 0; index < 4; ++index) {
736 if (c >=
'0' && c <=
'9')
738 else if (c >=
'a' && c <=
'f')
739 unicode += c -
'a' + 10;
740 else if (c >=
'A' && c <=
'F')
741 unicode += c -
'A' + 10;
744 "Bad unicode escape sequence in string: hexadecimal digit expected.",
748 ret_unicode =
static_cast<unsigned int>(unicode);
753 Reader::addError(
const JSONCPP_STRING& message, Token& token, Location extra) {
756 info.message_ = message;
758 errors_.push_back(info);
762 bool Reader::recoverFromError(TokenType skipUntilToken) {
763 size_t const errorCount = errors_.size();
766 if (!readToken(skip))
767 errors_.resize(errorCount);
768 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
771 errors_.resize(errorCount);
777 TokenType skipUntilToken) {
778 addError(message, token);
779 return recoverFromError(skipUntilToken);
782 Value& Reader::currentValue() {
return *(nodes_.top()); }
785 if (current_ == end_)
790 void Reader::getLocationLineAndColumn(Location location,
796 while (current < location && current != end_) {
799 if (*current ==
'\n')
801 lastLineStart = current;
803 }
else if (c ==
'\n') {
804 lastLineStart = current;
809 column = int(location - lastLineStart) + 1;
813 JSONCPP_STRING Reader::getLocationLineAndColumn(Location location)
const {
815 getLocationLineAndColumn(location, line, column);
816 char buffer[18 + 16 + 16 + 1];
817 snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
828 for (Errors::const_iterator itError = errors_.begin();
829 itError != errors_.end();
831 const ErrorInfo& error = *itError;
833 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
834 formattedMessage +=
" " + error.message_ +
"\n";
837 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
839 return formattedMessage;
843 std::vector<Reader::StructuredError> allErrors;
844 for (Errors::const_iterator itError = errors_.begin();
845 itError != errors_.end();
847 const ErrorInfo& error = *itError;
851 structured.
message = error.message_;
852 allErrors.push_back(structured);
858 ptrdiff_t
const length = end_ - begin_;
863 token.type_ = tokenError;
868 info.message_ = message;
870 errors_.push_back(info);
875 ptrdiff_t
const length = end_ - begin_;
881 token.type_ = tokenError;
886 info.message_ = message;
888 errors_.push_back(info);
893 return !errors_.size();
899 static OurFeatures all();
902 bool allowDroppedNullPlaceholders_;
903 bool allowNumericKeys_;
904 bool allowSingleQuotes_;
907 bool allowSpecialFloats_;
914 OurFeatures OurFeatures::all() {
return OurFeatures(); }
923 typedef const Char* Location;
924 struct StructuredError {
925 ptrdiff_t offset_start;
926 ptrdiff_t offset_limit;
930 OurReader(OurFeatures
const& features);
931 bool parse(
const char* beginDoc,
934 bool collectComments =
true);
936 std::vector<StructuredError> getStructuredErrors()
const;
937 bool pushError(
const Value& value,
const JSONCPP_STRING& message);
938 bool pushError(
const Value& value,
const JSONCPP_STRING& message,
const Value& extra);
942 OurReader(OurReader
const&);
943 void operator=(OurReader
const&);
946 tokenEndOfStream = 0,
960 tokenMemberSeparator,
979 typedef std::deque<ErrorInfo> Errors;
981 bool readToken(Token& token);
983 bool match(Location pattern,
int patternLength);
985 bool readCStyleComment();
986 bool readCppStyleComment();
988 bool readStringSingleQuote();
989 bool readNumber(
bool checkInf);
991 bool readObject(Token& token);
992 bool readArray(Token& token);
993 bool decodeNumber(Token& token);
994 bool decodeNumber(Token& token, Value& decoded);
995 bool decodeString(Token& token);
997 bool decodeDouble(Token& token);
998 bool decodeDouble(Token& token, Value& decoded);
999 bool decodeUnicodeCodePoint(Token& token,
1002 unsigned int& unicode);
1003 bool decodeUnicodeEscapeSequence(Token& token,
1006 unsigned int& unicode);
1007 bool addError(
const JSONCPP_STRING& message, Token& token, Location extra = 0);
1008 bool recoverFromError(TokenType skipUntilToken);
1011 TokenType skipUntilToken);
1012 void skipUntilSpace();
1013 Value& currentValue();
1016 getLocationLineAndColumn(Location location,
int& line,
int& column)
const;
1017 JSONCPP_STRING getLocationLineAndColumn(Location location)
const;
1019 void skipCommentTokens(Token& token);
1021 static JSONCPP_STRING normalizeEOL(Location begin, Location end);
1022 static bool containsNewLine(Location begin, Location end);
1024 typedef std::stack<Value*> Nodes;
1031 Location lastValueEnd_;
1035 OurFeatures
const features_;
1036 bool collectComments_;
1041 bool OurReader::containsNewLine(OurReader::Location begin, OurReader::Location end) {
1042 for (; begin < end; ++begin)
1043 if (*begin ==
'\n' || *begin ==
'\r')
1048 OurReader::OurReader(OurFeatures
const& features)
1049 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
1050 lastValue_(), commentsBefore_(),
1051 features_(features), collectComments_() {
1054 bool OurReader::parse(
const char* beginDoc,
1057 bool collectComments) {
1058 if (!features_.allowComments_) {
1059 collectComments =
false;
1064 collectComments_ = collectComments;
1068 commentsBefore_.clear();
1070 while (!nodes_.empty())
1074 bool successful = readValue();
1076 skipCommentTokens(token);
1077 if (features_.failIfExtra_) {
1078 if ((features_.strictRoot_ || token.type_ != tokenError) && token.type_ != tokenEndOfStream) {
1079 addError(
"Extra non-whitespace after JSON value.", token);
1083 if (collectComments_ && !commentsBefore_.empty())
1085 if (features_.strictRoot_) {
1086 if (!root.isArray() && !root.isObject()) {
1089 token.type_ = tokenError;
1090 token.start_ = beginDoc;
1091 token.end_ = endDoc;
1093 "A valid JSON document must be either an array or an object value.",
1101 bool OurReader::readValue() {
1103 if (static_cast<int>(nodes_.size()) > features_.stackLimit_) throwRuntimeError(
"Exceeded stackLimit in readValue().");
1105 skipCommentTokens(token);
1106 bool successful =
true;
1108 if (collectComments_ && !commentsBefore_.empty()) {
1110 commentsBefore_.clear();
1113 switch (token.type_) {
1114 case tokenObjectBegin:
1115 successful = readObject(token);
1116 currentValue().setOffsetLimit(current_ - begin_);
1118 case tokenArrayBegin:
1119 successful = readArray(token);
1120 currentValue().setOffsetLimit(current_ - begin_);
1123 successful = decodeNumber(token);
1126 successful = decodeString(token);
1131 currentValue().swapPayload(v);
1132 currentValue().setOffsetStart(token.start_ - begin_);
1133 currentValue().setOffsetLimit(token.end_ - begin_);
1139 currentValue().swapPayload(v);
1140 currentValue().setOffsetStart(token.start_ - begin_);
1141 currentValue().setOffsetLimit(token.end_ - begin_);
1147 currentValue().swapPayload(v);
1148 currentValue().setOffsetStart(token.start_ - begin_);
1149 currentValue().setOffsetLimit(token.end_ - begin_);
1154 Value v(std::numeric_limits<double>::quiet_NaN());
1155 currentValue().swapPayload(v);
1156 currentValue().setOffsetStart(token.start_ - begin_);
1157 currentValue().setOffsetLimit(token.end_ - begin_);
1162 Value v(std::numeric_limits<double>::infinity());
1163 currentValue().swapPayload(v);
1164 currentValue().setOffsetStart(token.start_ - begin_);
1165 currentValue().setOffsetLimit(token.end_ - begin_);
1170 Value v(-std::numeric_limits<double>::infinity());
1171 currentValue().swapPayload(v);
1172 currentValue().setOffsetStart(token.start_ - begin_);
1173 currentValue().setOffsetLimit(token.end_ - begin_);
1176 case tokenArraySeparator:
1177 case tokenObjectEnd:
1179 if (features_.allowDroppedNullPlaceholders_) {
1184 currentValue().swapPayload(v);
1185 currentValue().setOffsetStart(current_ - begin_ - 1);
1186 currentValue().setOffsetLimit(current_ - begin_);
1190 currentValue().setOffsetStart(token.start_ - begin_);
1191 currentValue().setOffsetLimit(token.end_ - begin_);
1192 return addError(
"Syntax error: value, object or array expected.", token);
1195 if (collectComments_) {
1196 lastValueEnd_ = current_;
1197 lastValue_ = ¤tValue();
1203 void OurReader::skipCommentTokens(Token& token) {
1204 if (features_.allowComments_) {
1207 }
while (token.type_ == tokenComment);
1213 bool OurReader::readToken(Token& token) {
1215 token.start_ = current_;
1216 Char c = getNextChar();
1220 token.type_ = tokenObjectBegin;
1223 token.type_ = tokenObjectEnd;
1226 token.type_ = tokenArrayBegin;
1229 token.type_ = tokenArrayEnd;
1232 token.type_ = tokenString;
1236 if (features_.allowSingleQuotes_) {
1237 token.type_ = tokenString;
1238 ok = readStringSingleQuote();
1242 token.type_ = tokenComment;
1255 token.type_ = tokenNumber;
1259 if (readNumber(
true)) {
1260 token.type_ = tokenNumber;
1262 token.type_ = tokenNegInf;
1263 ok = features_.allowSpecialFloats_ && match(
"nfinity", 7);
1267 token.type_ = tokenTrue;
1268 ok = match(
"rue", 3);
1271 token.type_ = tokenFalse;
1272 ok = match(
"alse", 4);
1275 token.type_ = tokenNull;
1276 ok = match(
"ull", 3);
1279 if (features_.allowSpecialFloats_) {
1280 token.type_ = tokenNaN;
1281 ok = match(
"aN", 2);
1287 if (features_.allowSpecialFloats_) {
1288 token.type_ = tokenPosInf;
1289 ok = match(
"nfinity", 7);
1295 token.type_ = tokenArraySeparator;
1298 token.type_ = tokenMemberSeparator;
1301 token.type_ = tokenEndOfStream;
1308 token.type_ = tokenError;
1309 token.end_ = current_;
1313 void OurReader::skipSpaces() {
1314 while (current_ != end_) {
1316 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n')
1323 bool OurReader::match(Location pattern,
int patternLength) {
1324 if (end_ - current_ < patternLength)
1326 int index = patternLength;
1328 if (current_[index] != pattern[index])
1330 current_ += patternLength;
1334 bool OurReader::readComment() {
1335 Location commentBegin = current_ - 1;
1336 Char c = getNextChar();
1337 bool successful =
false;
1339 successful = readCStyleComment();
1341 successful = readCppStyleComment();
1345 if (collectComments_) {
1347 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
1348 if (c !=
'*' || !containsNewLine(commentBegin, current_))
1352 addComment(commentBegin, current_, placement);
1357 JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin, OurReader::Location end) {
1359 normalized.reserve(static_cast<size_t>(end - begin));
1360 OurReader::Location current = begin;
1361 while (current != end) {
1362 char c = *current++;
1364 if (current != end && *current ==
'\n')
1377 OurReader::addComment(Location begin, Location end,
CommentPlacement placement) {
1378 assert(collectComments_);
1381 assert(lastValue_ != 0);
1382 lastValue_->setComment(normalized, placement);
1384 commentsBefore_ += normalized;
1388 bool OurReader::readCStyleComment() {
1389 while ((current_ + 1) < end_) {
1390 Char c = getNextChar();
1391 if (c ==
'*' && *current_ ==
'/')
1394 return getNextChar() ==
'/';
1397 bool OurReader::readCppStyleComment() {
1398 while (current_ != end_) {
1399 Char c = getNextChar();
1404 if (current_ != end_ && *current_ ==
'\n')
1413 bool OurReader::readNumber(
bool checkInf) {
1414 const char *p = current_;
1415 if (checkInf && p != end_ && *p ==
'I') {
1421 while (c >=
'0' && c <=
'9')
1422 c = (current_ = p) < end_ ? *p++ :
'\0';
1425 c = (current_ = p) < end_ ? *p++ :
'\0';
1426 while (c >=
'0' && c <=
'9')
1427 c = (current_ = p) < end_ ? *p++ :
'\0';
1430 if (c ==
'e' || c ==
'E') {
1431 c = (current_ = p) < end_ ? *p++ :
'\0';
1432 if (c ==
'+' || c ==
'-')
1433 c = (current_ = p) < end_ ? *p++ :
'\0';
1434 while (c >=
'0' && c <=
'9')
1435 c = (current_ = p) < end_ ? *p++ :
'\0';
1439 bool OurReader::readString() {
1441 while (current_ != end_) {
1452 bool OurReader::readStringSingleQuote() {
1454 while (current_ != end_) {
1464 bool OurReader::readObject(Token& tokenStart) {
1468 currentValue().swapPayload(init);
1469 currentValue().setOffsetStart(tokenStart.start_ - begin_);
1470 while (readToken(tokenName)) {
1471 bool initialTokenOk =
true;
1472 while (tokenName.type_ == tokenComment && initialTokenOk)
1473 initialTokenOk = readToken(tokenName);
1474 if (!initialTokenOk)
1476 if (tokenName.type_ == tokenObjectEnd && name.empty())
1479 if (tokenName.type_ == tokenString) {
1480 if (!decodeString(tokenName, name))
1481 return recoverFromError(tokenObjectEnd);
1482 }
else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1484 if (!decodeNumber(tokenName, numberName))
1485 return recoverFromError(tokenObjectEnd);
1486 name = numberName.asString();
1492 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1493 return addErrorAndRecover(
1494 "Missing ':' after object member name", colon, tokenObjectEnd);
1496 if (name.length() >= (1U<<30)) throwRuntimeError(
"keylength >= 2^30");
1497 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1499 return addErrorAndRecover(
1500 msg, tokenName, tokenObjectEnd);
1502 Value& value = currentValue()[name];
1503 nodes_.push(&value);
1504 bool ok = readValue();
1507 return recoverFromError(tokenObjectEnd);
1510 if (!readToken(comma) ||
1511 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1512 comma.type_ != tokenComment)) {
1513 return addErrorAndRecover(
1514 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
1516 bool finalizeTokenOk =
true;
1517 while (comma.type_ == tokenComment && finalizeTokenOk)
1518 finalizeTokenOk = readToken(comma);
1519 if (comma.type_ == tokenObjectEnd)
1522 return addErrorAndRecover(
1523 "Missing '}' or object member name", tokenName, tokenObjectEnd);
1526 bool OurReader::readArray(Token& tokenStart) {
1528 currentValue().swapPayload(init);
1529 currentValue().setOffsetStart(tokenStart.start_ - begin_);
1531 if (current_ != end_ && *current_ ==
']')
1534 readToken(endArray);
1539 Value& value = currentValue()[index++];
1540 nodes_.push(&value);
1541 bool ok = readValue();
1544 return recoverFromError(tokenArrayEnd);
1548 ok = readToken(token);
1549 while (token.type_ == tokenComment && ok) {
1550 ok = readToken(token);
1553 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
1554 if (!ok || badTokenType) {
1555 return addErrorAndRecover(
1556 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
1558 if (token.type_ == tokenArrayEnd)
1564 bool OurReader::decodeNumber(Token& token) {
1566 if (!decodeNumber(token, decoded))
1568 currentValue().swapPayload(decoded);
1569 currentValue().setOffsetStart(token.start_ - begin_);
1570 currentValue().setOffsetLimit(token.end_ - begin_);
1574 bool OurReader::decodeNumber(Token& token, Value& decoded) {
1578 Location current = token.start_;
1579 bool isNegative = *current ==
'-';
1585 : Value::maxLargestUInt;
1588 while (current < token.end_) {
1589 Char c = *current++;
1590 if (c < '0' || c >
'9')
1591 return decodeDouble(token, decoded);
1592 Value::UInt digit(static_cast<Value::UInt>(c -
'0'));
1593 if (value >= threshold) {
1598 if (value > threshold || current != token.end_ ||
1599 digit > maxIntegerValue % 10) {
1600 return decodeDouble(token, decoded);
1603 value = value * 10 + digit;
1614 bool OurReader::decodeDouble(Token& token) {
1616 if (!decodeDouble(token, decoded))
1618 currentValue().swapPayload(decoded);
1619 currentValue().setOffsetStart(token.start_ - begin_);
1620 currentValue().setOffsetLimit(token.end_ - begin_);
1624 bool OurReader::decodeDouble(Token& token, Value& decoded) {
1626 const int bufferSize = 32;
1628 ptrdiff_t
const length = token.end_ - token.start_;
1632 return addError(
"Unable to parse token length", token);
1634 size_t const ulength =
static_cast<size_t>(length);
1641 char format[] =
"%lf";
1643 if (length <= bufferSize) {
1644 Char buffer[bufferSize + 1];
1645 memcpy(buffer, token.start_, ulength);
1648 count = sscanf(buffer, format, &value);
1651 count = sscanf(buffer.c_str(), format, &value);
1656 "' is not a number.",
1662 bool OurReader::decodeString(Token& token) {
1664 if (!decodeString(token, decoded_string))
1666 Value decoded(decoded_string);
1667 currentValue().swapPayload(decoded);
1668 currentValue().setOffsetStart(token.start_ - begin_);
1669 currentValue().setOffsetLimit(token.end_ - begin_);
1673 bool OurReader::decodeString(Token& token,
JSONCPP_STRING& decoded) {
1674 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
1675 Location current = token.start_ + 1;
1676 Location end = token.end_ - 1;
1677 while (current != end) {
1678 Char c = *current++;
1681 else if (c ==
'\\') {
1683 return addError(
"Empty escape sequence in string", token, current);
1684 Char escape = *current++;
1711 unsigned int unicode;
1712 if (!decodeUnicodeCodePoint(token, current, end, unicode))
1717 return addError(
"Bad escape sequence in string", token, current);
1726 bool OurReader::decodeUnicodeCodePoint(Token& token,
1729 unsigned int& unicode) {
1731 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1733 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1735 if (end - current < 6)
1737 "additional six characters expected to parse unicode surrogate pair.",
1740 unsigned int surrogatePair;
1741 if (*(current++) ==
'\\' && *(current++) ==
'u') {
1742 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1743 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1747 return addError(
"expecting another \\u token to begin the second half of " 1748 "a unicode surrogate pair",
1755 bool OurReader::decodeUnicodeEscapeSequence(Token& token,
1758 unsigned int& ret_unicode) {
1759 if (end - current < 4)
1761 "Bad unicode escape sequence in string: four digits expected.",
1765 for (
int index = 0; index < 4; ++index) {
1766 Char c = *current++;
1768 if (c >=
'0' && c <=
'9')
1770 else if (c >=
'a' && c <=
'f')
1771 unicode += c -
'a' + 10;
1772 else if (c >=
'A' && c <=
'F')
1773 unicode += c -
'A' + 10;
1776 "Bad unicode escape sequence in string: hexadecimal digit expected.",
1780 ret_unicode =
static_cast<unsigned int>(unicode);
1785 OurReader::addError(
const JSONCPP_STRING& message, Token& token, Location extra) {
1787 info.token_ = token;
1788 info.message_ = message;
1789 info.extra_ = extra;
1790 errors_.push_back(info);
1794 bool OurReader::recoverFromError(TokenType skipUntilToken) {
1795 size_t errorCount = errors_.size();
1798 if (!readToken(skip))
1799 errors_.resize(errorCount);
1800 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
1803 errors_.resize(errorCount);
1807 bool OurReader::addErrorAndRecover(
const JSONCPP_STRING& message,
1809 TokenType skipUntilToken) {
1810 addError(message, token);
1811 return recoverFromError(skipUntilToken);
1814 Value& OurReader::currentValue() {
return *(nodes_.top()); }
1816 OurReader::Char OurReader::getNextChar() {
1817 if (current_ == end_)
1822 void OurReader::getLocationLineAndColumn(Location location,
1824 int& column)
const {
1825 Location current = begin_;
1826 Location lastLineStart = current;
1828 while (current < location && current != end_) {
1829 Char c = *current++;
1831 if (*current ==
'\n')
1833 lastLineStart = current;
1835 }
else if (c ==
'\n') {
1836 lastLineStart = current;
1841 column = int(location - lastLineStart) + 1;
1845 JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location)
const {
1847 getLocationLineAndColumn(location, line, column);
1848 char buffer[18 + 16 + 16 + 1];
1849 snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
1855 for (Errors::const_iterator itError = errors_.begin();
1856 itError != errors_.end();
1858 const ErrorInfo& error = *itError;
1860 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
1861 formattedMessage +=
" " + error.message_ +
"\n";
1864 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
1866 return formattedMessage;
1869 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors()
const {
1870 std::vector<OurReader::StructuredError> allErrors;
1871 for (Errors::const_iterator itError = errors_.begin();
1872 itError != errors_.end();
1874 const ErrorInfo& error = *itError;
1875 OurReader::StructuredError structured;
1876 structured.offset_start = error.token_.start_ - begin_;
1877 structured.offset_limit = error.token_.end_ - begin_;
1878 structured.message = error.message_;
1879 allErrors.push_back(structured);
1884 bool OurReader::pushError(
const Value& value,
const JSONCPP_STRING& message) {
1885 ptrdiff_t length = end_ - begin_;
1886 if(value.getOffsetStart() > length
1887 || value.getOffsetLimit() > length)
1890 token.type_ = tokenError;
1891 token.start_ = begin_ + value.getOffsetStart();
1892 token.end_ = end_ + value.getOffsetLimit();
1894 info.token_ = token;
1895 info.message_ = message;
1897 errors_.push_back(info);
1901 bool OurReader::pushError(
const Value& value,
const JSONCPP_STRING& message,
const Value& extra) {
1902 ptrdiff_t length = end_ - begin_;
1903 if(value.getOffsetStart() > length
1904 || value.getOffsetLimit() > length
1905 || extra.getOffsetLimit() > length)
1908 token.type_ = tokenError;
1909 token.start_ = begin_ + value.getOffsetStart();
1910 token.end_ = begin_ + value.getOffsetLimit();
1912 info.token_ = token;
1913 info.message_ = message;
1914 info.extra_ = begin_ + extra.getOffsetStart();
1915 errors_.push_back(info);
1919 bool OurReader::good()
const {
1920 return !errors_.size();
1924 class OurCharReader :
public CharReader {
1925 bool const collectComments_;
1929 bool collectComments,
1930 OurFeatures
const& features)
1931 : collectComments_(collectComments)
1935 char const* beginDoc,
char const* endDoc,
1937 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1939 *errs = reader_.getFormattedErrorMessages();
1954 OurFeatures features = OurFeatures::all();
1957 features.allowDroppedNullPlaceholders_ =
settings_[
"allowDroppedNullPlaceholders"].
asBool();
1959 features.allowSingleQuotes_ =
settings_[
"allowSingleQuotes"].
asBool();
1963 features.allowSpecialFloats_ =
settings_[
"allowSpecialFloats"].
asBool();
1964 return new OurCharReader(collectComments, features);
1968 valid_keys->clear();
1969 valid_keys->insert(
"collectComments");
1970 valid_keys->insert(
"allowComments");
1971 valid_keys->insert(
"strictRoot");
1972 valid_keys->insert(
"allowDroppedNullPlaceholders");
1973 valid_keys->insert(
"allowNumericKeys");
1974 valid_keys->insert(
"allowSingleQuotes");
1975 valid_keys->insert(
"stackLimit");
1976 valid_keys->insert(
"failIfExtra");
1977 valid_keys->insert(
"rejectDupKeys");
1978 valid_keys->insert(
"allowSpecialFloats");
1983 if (!invalid) invalid = &my_invalid;
1985 std::set<JSONCPP_STRING> valid_keys;
1988 size_t n = keys.size();
1989 for (
size_t i = 0; i < n; ++i) {
1991 if (valid_keys.find(key) == valid_keys.end()) {
1995 return 0u == inv.
size();
2005 (*settings)[
"allowComments"] =
false;
2006 (*settings)[
"strictRoot"] =
true;
2007 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
2008 (*settings)[
"allowNumericKeys"] =
false;
2009 (*settings)[
"allowSingleQuotes"] =
false;
2010 (*settings)[
"stackLimit"] = 1000;
2011 (*settings)[
"failIfExtra"] =
true;
2012 (*settings)[
"rejectDupKeys"] =
true;
2013 (*settings)[
"allowSpecialFloats"] =
false;
2020 (*settings)[
"collectComments"] =
true;
2021 (*settings)[
"allowComments"] =
true;
2022 (*settings)[
"strictRoot"] =
false;
2023 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
2024 (*settings)[
"allowNumericKeys"] =
false;
2025 (*settings)[
"allowSingleQuotes"] =
false;
2026 (*settings)[
"stackLimit"] = 1000;
2027 (*settings)[
"failIfExtra"] =
false;
2028 (*settings)[
"rejectDupKeys"] =
false;
2029 (*settings)[
"allowSpecialFloats"] =
false;
2041 ssin << sin.rdbuf();
2043 char const* begin = doc.data();
2044 char const* end = begin + doc.size();
2047 return reader->parse(begin, end, root, errs);
2055 throwRuntimeError(errs);
#define JSONCPP_OSTRINGSTREAM
std::vector< StructuredError > getStructuredErrors() const
Returns a vector of structured erros encounted while parsing.
static void strictMode(Json::Value *settings)
Same as old Features::strictMode().
array value (ordered list)
CharReader * newCharReader() const
Allocate a CharReader via operator new().
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.
Members getMemberNames() const
Return a list of the member names.
object value (collection of name/value pairs).
std::istream & operator>>(std::istream &, Value &)
Read from 'sin' into 'root'.
void swapPayload(Value &other)
Swap values but leave comments and source offsets in place.
Value & operator[](std::string key)
A simple way to update a specific setting.
static JSONCPP_STRING codePointToUTF8(unsigned int cp)
Converts a unicode code-point to UTF-8.
static const Int maxInt
Maximum signed int value that can be stored in a Json::Value.
ptrdiff_t getOffsetStart() const
Json::LargestUInt LargestUInt
Features()
Initialize the configuration like JsonConfig::allFeatures;.
std::string getFormatedErrorMessages() const
Returns a user friendly string that list errors in the parsed document.
An error tagged with where in the JSON text it was encountered.
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.
static void fixNumericLocaleInput(char *begin, char *end)
bool allowNumericKeys_
true if numeric object key are allowed. Default: false.
static size_t const stackLimit_g
ArrayIndex size() const
Number of values in array or object.
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.
Json::LargestInt LargestInt
ptrdiff_t getOffsetLimit() const
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.
std::string getFormattedErrorMessages() const
Returns a user friendly string that list errors in the parsed document.
void setOffsetStart(ptrdiff_t start)
#define JSONCPP_ISTRINGSTREAM
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
bool pushError(const Value &value, const std::string &message)
Add a semantic error message.
#define JSONCPP_DEPRECATED_STACK_LIMIT
void setOffsetLimit(ptrdiff_t limit)
std::vector< std::string > Members
static Features strictMode()
A configuration that is strictly compatible with the JSON specification.
bool strictRoot_
true if root must be either an array or an object value.
Build a CharReader implementation.
static void getValidReaderKeys(std::set< std::string > *valid_keys)
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.
a comment just after a value on the same line
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.