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 JSONCPP_STRING documentCopy(document.data(), document.data() + document.capacity());
107 std::swap(documentCopy, document_);
108 const char* begin = document_.c_str();
109 const char* end = begin + document_.length();
110 return parse(begin, end, root, collectComments);
122 std::getline(sin, doc, (
char)EOF);
123 return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
129 bool collectComments) {
131 collectComments =
false;
136 collectComments_ = collectComments;
140 commentsBefore_.clear();
142 while (!nodes_.empty())
146 bool successful = readValue();
148 skipCommentTokens(token);
149 if (collectComments_ && !commentsBefore_.empty())
155 token.type_ = tokenError;
156 token.start_ = beginDoc;
159 "A valid JSON document must be either an array or an object value.",
167 bool Reader::readValue() {
171 if (nodes_.size() >
stackLimit_g) throwRuntimeError(
"Exceeded stackLimit in readValue().");
174 skipCommentTokens(token);
175 bool successful =
true;
177 if (collectComments_ && !commentsBefore_.empty()) {
179 commentsBefore_.clear();
182 switch (token.type_) {
183 case tokenObjectBegin:
184 successful = readObject(token);
187 case tokenArrayBegin:
188 successful = readArray(token);
192 successful = decodeNumber(token);
195 successful = decodeString(token);
221 case tokenArraySeparator:
237 return addError(
"Syntax error: value, object or array expected.", token);
240 if (collectComments_) {
241 lastValueEnd_ = current_;
242 lastValue_ = ¤tValue();
248 void Reader::skipCommentTokens(Token& token) {
252 }
while (token.type_ == tokenComment);
258 bool Reader::readToken(Token& token) {
260 token.start_ = current_;
261 Char c = getNextChar();
265 token.type_ = tokenObjectBegin;
268 token.type_ = tokenObjectEnd;
271 token.type_ = tokenArrayBegin;
274 token.type_ = tokenArrayEnd;
277 token.type_ = tokenString;
281 token.type_ = tokenComment;
295 token.type_ = tokenNumber;
299 token.type_ = tokenTrue;
300 ok = match(
"rue", 3);
303 token.type_ = tokenFalse;
304 ok = match(
"alse", 4);
307 token.type_ = tokenNull;
308 ok = match(
"ull", 3);
311 token.type_ = tokenArraySeparator;
314 token.type_ = tokenMemberSeparator;
317 token.type_ = tokenEndOfStream;
324 token.type_ = tokenError;
325 token.end_ = current_;
329 void Reader::skipSpaces() {
330 while (current_ != end_) {
332 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n')
339 bool Reader::match(
Location pattern,
int patternLength) {
340 if (end_ - current_ < patternLength)
342 int index = patternLength;
344 if (current_[index] != pattern[index])
346 current_ += patternLength;
350 bool Reader::readComment() {
351 Location commentBegin = current_ - 1;
352 Char c = getNextChar();
353 bool successful =
false;
355 successful = readCStyleComment();
357 successful = readCppStyleComment();
361 if (collectComments_) {
368 addComment(commentBegin, current_, placement);
375 normalized.reserve(static_cast<size_t>(end - begin));
377 while (current != end) {
380 if (current != end && *current ==
'\n')
394 assert(collectComments_);
397 assert(lastValue_ != 0);
398 lastValue_->
setComment(normalized, placement);
400 commentsBefore_ += normalized;
404 bool Reader::readCStyleComment() {
405 while ((current_ + 1) < end_) {
406 Char c = getNextChar();
407 if (c ==
'*' && *current_ ==
'/')
410 return getNextChar() ==
'/';
413 bool Reader::readCppStyleComment() {
414 while (current_ != end_) {
415 Char c = getNextChar();
420 if (current_ != end_ && *current_ ==
'\n')
429 void Reader::readNumber() {
430 const char *p = current_;
433 while (c >=
'0' && c <=
'9')
434 c = (current_ = p) < end_ ? *p++ :
'\0';
437 c = (current_ = p) < end_ ? *p++ :
'\0';
438 while (c >=
'0' && c <=
'9')
439 c = (current_ = p) < end_ ? *p++ :
'\0';
442 if (c ==
'e' || c ==
'E') {
443 c = (current_ = p) < end_ ? *p++ :
'\0';
444 if (c ==
'+' || c ==
'-')
445 c = (current_ = p) < end_ ? *p++ :
'\0';
446 while (c >=
'0' && c <=
'9')
447 c = (current_ = p) < end_ ? *p++ :
'\0';
451 bool Reader::readString() {
453 while (current_ != end_) {
463 bool Reader::readObject(Token& tokenStart) {
469 while (readToken(tokenName)) {
470 bool initialTokenOk =
true;
471 while (tokenName.type_ == tokenComment && initialTokenOk)
472 initialTokenOk = readToken(tokenName);
475 if (tokenName.type_ == tokenObjectEnd && name.empty())
478 if (tokenName.type_ == tokenString) {
479 if (!decodeString(tokenName, name))
480 return recoverFromError(tokenObjectEnd);
483 if (!decodeNumber(tokenName, numberName))
484 return recoverFromError(tokenObjectEnd);
491 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
492 return addErrorAndRecover(
493 "Missing ':' after object member name", colon, tokenObjectEnd);
495 Value& value = currentValue()[name];
497 bool ok = readValue();
500 return recoverFromError(tokenObjectEnd);
503 if (!readToken(comma) ||
504 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
505 comma.type_ != tokenComment)) {
506 return addErrorAndRecover(
507 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
509 bool finalizeTokenOk =
true;
510 while (comma.type_ == tokenComment && finalizeTokenOk)
511 finalizeTokenOk = readToken(comma);
512 if (comma.type_ == tokenObjectEnd)
515 return addErrorAndRecover(
516 "Missing '}' or object member name", tokenName, tokenObjectEnd);
519 bool Reader::readArray(Token& tokenStart) {
524 if (current_ != end_ && *current_ ==
']')
532 Value& value = currentValue()[index++];
534 bool ok = readValue();
537 return recoverFromError(tokenArrayEnd);
541 ok = readToken(token);
542 while (token.type_ == tokenComment && ok) {
543 ok = readToken(token);
546 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
547 if (!ok || badTokenType) {
548 return addErrorAndRecover(
549 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
551 if (token.type_ == tokenArrayEnd)
557 bool Reader::decodeNumber(Token& token) {
559 if (!decodeNumber(token, decoded))
567 bool Reader::decodeNumber(Token& token,
Value& decoded) {
572 bool isNegative = *current ==
'-';
581 while (current < token.end_) {
583 if (c < '0' || c >
'9')
584 return decodeDouble(token, decoded);
585 Value::UInt digit(static_cast<Value::UInt>(c -
'0'));
586 if (value >= threshold) {
591 if (value > threshold || current != token.end_ ||
592 digit > maxIntegerValue % 10) {
593 return decodeDouble(token, decoded);
596 value = value * 10 + digit;
598 if (isNegative && value == maxIntegerValue)
609 bool Reader::decodeDouble(Token& token) {
611 if (!decodeDouble(token, decoded))
619 bool Reader::decodeDouble(Token& token,
Value& decoded) {
625 "' is not a number.",
631 bool Reader::decodeString(Token& token) {
633 if (!decodeString(token, decoded_string))
635 Value decoded(decoded_string);
642 bool Reader::decodeString(Token& token,
JSONCPP_STRING& decoded) {
643 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
644 Location current = token.start_ + 1;
646 while (current != end) {
650 else if (c ==
'\\') {
652 return addError(
"Empty escape sequence in string", token, current);
653 Char escape = *current++;
680 unsigned int unicode;
681 if (!decodeUnicodeCodePoint(token, current, end, unicode))
686 return addError(
"Bad escape sequence in string", token, current);
695 bool Reader::decodeUnicodeCodePoint(Token& token,
698 unsigned int& unicode) {
700 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
702 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
704 if (end - current < 6)
706 "additional six characters expected to parse unicode surrogate pair.",
709 unsigned int surrogatePair;
710 if (*(current++) ==
'\\' && *(current++) ==
'u') {
711 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
712 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
716 return addError(
"expecting another \\u token to begin the second half of " 717 "a unicode surrogate pair",
724 bool Reader::decodeUnicodeEscapeSequence(Token& token,
727 unsigned int& ret_unicode) {
728 if (end - current < 4)
730 "Bad unicode escape sequence in string: four digits expected.",
734 for (
int index = 0; index < 4; ++index) {
737 if (c >=
'0' && c <=
'9')
739 else if (c >=
'a' && c <=
'f')
740 unicode += c -
'a' + 10;
741 else if (c >=
'A' && c <=
'F')
742 unicode += c -
'A' + 10;
745 "Bad unicode escape sequence in string: hexadecimal digit expected.",
749 ret_unicode =
static_cast<unsigned int>(unicode);
757 info.message_ = message;
759 errors_.push_back(info);
763 bool Reader::recoverFromError(TokenType skipUntilToken) {
764 size_t const errorCount = errors_.size();
767 if (!readToken(skip))
768 errors_.resize(errorCount);
769 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
772 errors_.resize(errorCount);
778 TokenType skipUntilToken) {
779 addError(message, token);
780 return recoverFromError(skipUntilToken);
783 Value& Reader::currentValue() {
return *(nodes_.top()); }
786 if (current_ == end_)
791 void Reader::getLocationLineAndColumn(
Location location,
797 while (current < location && current != end_) {
800 if (*current ==
'\n')
802 lastLineStart = current;
804 }
else if (c ==
'\n') {
805 lastLineStart = current;
810 column = int(location - lastLineStart) + 1;
816 getLocationLineAndColumn(location, line, column);
817 char buffer[18 + 16 + 16 + 1];
818 snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
829 for (Errors::const_iterator itError = errors_.begin();
830 itError != errors_.end();
832 const ErrorInfo& error = *itError;
834 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
835 formattedMessage +=
" " + error.message_ +
"\n";
838 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
840 return formattedMessage;
844 std::vector<Reader::StructuredError> allErrors;
845 for (Errors::const_iterator itError = errors_.begin();
846 itError != errors_.end();
848 const ErrorInfo& error = *itError;
852 structured.
message = error.message_;
853 allErrors.push_back(structured);
859 ptrdiff_t
const length = end_ - begin_;
864 token.type_ = tokenError;
869 info.message_ = message;
871 errors_.push_back(info);
876 ptrdiff_t
const length = end_ - begin_;
882 token.type_ = tokenError;
887 info.message_ = message;
889 errors_.push_back(info);
894 return !errors_.size();
900 static OurFeatures all();
903 bool allowDroppedNullPlaceholders_;
904 bool allowNumericKeys_;
905 bool allowSingleQuotes_;
908 bool allowSpecialFloats_;
915 OurFeatures OurFeatures::all() {
return OurFeatures(); }
926 ptrdiff_t offset_start;
927 ptrdiff_t offset_limit;
931 OurReader(OurFeatures
const& features);
932 bool parse(
const char* beginDoc,
935 bool collectComments =
true);
943 OurReader(OurReader
const&);
944 void operator=(OurReader
const&);
947 tokenEndOfStream = 0,
961 tokenMemberSeparator,
980 typedef std::deque<ErrorInfo> Errors;
982 bool readToken(Token& token);
984 bool match(Location pattern,
int patternLength);
986 bool readCStyleComment();
987 bool readCppStyleComment();
989 bool readStringSingleQuote();
990 bool readNumber(
bool checkInf);
992 bool readObject(Token& token);
993 bool readArray(Token& token);
994 bool decodeNumber(Token& token);
995 bool decodeNumber(Token& token,
Value& decoded);
996 bool decodeString(Token& token);
998 bool decodeDouble(Token& token);
999 bool decodeDouble(Token& token,
Value& decoded);
1000 bool decodeUnicodeCodePoint(Token& token,
1003 unsigned int& unicode);
1004 bool decodeUnicodeEscapeSequence(Token& token,
1007 unsigned int& unicode);
1008 bool addError(
const JSONCPP_STRING& message, Token& token, Location extra = 0);
1009 bool recoverFromError(TokenType skipUntilToken);
1012 TokenType skipUntilToken);
1013 void skipUntilSpace();
1014 Value& currentValue();
1017 getLocationLineAndColumn(Location location,
int& line,
int& column)
const;
1018 JSONCPP_STRING getLocationLineAndColumn(Location location)
const;
1020 void skipCommentTokens(Token& token);
1022 typedef std::stack<Value*> Nodes;
1029 Location lastValueEnd_;
1033 OurFeatures
const features_;
1034 bool collectComments_;
1039 OurReader::OurReader(OurFeatures
const& features)
1040 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
1041 lastValue_(), commentsBefore_(),
1042 features_(features), collectComments_() {
1045 bool OurReader::parse(
const char* beginDoc,
1048 bool collectComments) {
1049 if (!features_.allowComments_) {
1050 collectComments =
false;
1055 collectComments_ = collectComments;
1059 commentsBefore_.clear();
1061 while (!nodes_.empty())
1065 bool successful = readValue();
1067 skipCommentTokens(token);
1068 if (features_.failIfExtra_) {
1069 if ((features_.strictRoot_ || token.type_ != tokenError) && token.type_ != tokenEndOfStream) {
1070 addError(
"Extra non-whitespace after JSON value.", token);
1074 if (collectComments_ && !commentsBefore_.empty())
1076 if (features_.strictRoot_) {
1080 token.type_ = tokenError;
1081 token.start_ = beginDoc;
1082 token.end_ = endDoc;
1084 "A valid JSON document must be either an array or an object value.",
1092 bool OurReader::readValue() {
1094 if (static_cast<int>(nodes_.size()) > features_.stackLimit_) throwRuntimeError(
"Exceeded stackLimit in readValue().");
1096 skipCommentTokens(token);
1097 bool successful =
true;
1099 if (collectComments_ && !commentsBefore_.empty()) {
1101 commentsBefore_.clear();
1104 switch (token.type_) {
1105 case tokenObjectBegin:
1106 successful = readObject(token);
1107 currentValue().setOffsetLimit(current_ - begin_);
1109 case tokenArrayBegin:
1110 successful = readArray(token);
1111 currentValue().setOffsetLimit(current_ - begin_);
1114 successful = decodeNumber(token);
1117 successful = decodeString(token);
1122 currentValue().swapPayload(v);
1123 currentValue().setOffsetStart(token.start_ - begin_);
1124 currentValue().setOffsetLimit(token.end_ - begin_);
1130 currentValue().swapPayload(v);
1131 currentValue().setOffsetStart(token.start_ - begin_);
1132 currentValue().setOffsetLimit(token.end_ - begin_);
1139 currentValue().setOffsetStart(token.start_ - begin_);
1140 currentValue().setOffsetLimit(token.end_ - begin_);
1145 Value v(std::numeric_limits<double>::quiet_NaN());
1146 currentValue().swapPayload(v);
1147 currentValue().setOffsetStart(token.start_ - begin_);
1148 currentValue().setOffsetLimit(token.end_ - begin_);
1153 Value v(std::numeric_limits<double>::infinity());
1154 currentValue().swapPayload(v);
1155 currentValue().setOffsetStart(token.start_ - begin_);
1156 currentValue().setOffsetLimit(token.end_ - begin_);
1161 Value v(-std::numeric_limits<double>::infinity());
1162 currentValue().swapPayload(v);
1163 currentValue().setOffsetStart(token.start_ - begin_);
1164 currentValue().setOffsetLimit(token.end_ - begin_);
1167 case tokenArraySeparator:
1168 case tokenObjectEnd:
1170 if (features_.allowDroppedNullPlaceholders_) {
1176 currentValue().setOffsetStart(current_ - begin_ - 1);
1177 currentValue().setOffsetLimit(current_ - begin_);
1181 currentValue().setOffsetStart(token.start_ - begin_);
1182 currentValue().setOffsetLimit(token.end_ - begin_);
1183 return addError(
"Syntax error: value, object or array expected.", token);
1186 if (collectComments_) {
1187 lastValueEnd_ = current_;
1188 lastValue_ = ¤tValue();
1194 void OurReader::skipCommentTokens(Token& token) {
1195 if (features_.allowComments_) {
1198 }
while (token.type_ == tokenComment);
1204 bool OurReader::readToken(Token& token) {
1206 token.start_ = current_;
1207 Char c = getNextChar();
1211 token.type_ = tokenObjectBegin;
1214 token.type_ = tokenObjectEnd;
1217 token.type_ = tokenArrayBegin;
1220 token.type_ = tokenArrayEnd;
1223 token.type_ = tokenString;
1227 if (features_.allowSingleQuotes_) {
1228 token.type_ = tokenString;
1229 ok = readStringSingleQuote();
1233 token.type_ = tokenComment;
1246 token.type_ = tokenNumber;
1250 if (readNumber(
true)) {
1251 token.type_ = tokenNumber;
1253 token.type_ = tokenNegInf;
1254 ok = features_.allowSpecialFloats_ && match(
"nfinity", 7);
1258 token.type_ = tokenTrue;
1259 ok = match(
"rue", 3);
1262 token.type_ = tokenFalse;
1263 ok = match(
"alse", 4);
1266 token.type_ = tokenNull;
1267 ok = match(
"ull", 3);
1270 if (features_.allowSpecialFloats_) {
1271 token.type_ = tokenNaN;
1272 ok = match(
"aN", 2);
1278 if (features_.allowSpecialFloats_) {
1279 token.type_ = tokenPosInf;
1280 ok = match(
"nfinity", 7);
1286 token.type_ = tokenArraySeparator;
1289 token.type_ = tokenMemberSeparator;
1292 token.type_ = tokenEndOfStream;
1299 token.type_ = tokenError;
1300 token.end_ = current_;
1304 void OurReader::skipSpaces() {
1305 while (current_ != end_) {
1307 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n')
1314 bool OurReader::match(
Location pattern,
int patternLength) {
1315 if (end_ - current_ < patternLength)
1317 int index = patternLength;
1319 if (current_[index] != pattern[index])
1321 current_ += patternLength;
1325 bool OurReader::readComment() {
1326 Location commentBegin = current_ - 1;
1327 Char c = getNextChar();
1328 bool successful =
false;
1330 successful = readCStyleComment();
1332 successful = readCppStyleComment();
1336 if (collectComments_) {
1343 addComment(commentBegin, current_, placement);
1350 assert(collectComments_);
1353 assert(lastValue_ != 0);
1354 lastValue_->setComment(normalized, placement);
1356 commentsBefore_ += normalized;
1360 bool OurReader::readCStyleComment() {
1361 while ((current_ + 1) < end_) {
1362 Char c = getNextChar();
1363 if (c ==
'*' && *current_ ==
'/')
1366 return getNextChar() ==
'/';
1369 bool OurReader::readCppStyleComment() {
1370 while (current_ != end_) {
1371 Char c = getNextChar();
1376 if (current_ != end_ && *current_ ==
'\n')
1385 bool OurReader::readNumber(
bool checkInf) {
1386 const char *p = current_;
1387 if (checkInf && p != end_ && *p ==
'I') {
1393 while (c >=
'0' && c <=
'9')
1394 c = (current_ = p) < end_ ? *p++ :
'\0';
1397 c = (current_ = p) < end_ ? *p++ :
'\0';
1398 while (c >=
'0' && c <=
'9')
1399 c = (current_ = p) < end_ ? *p++ :
'\0';
1402 if (c ==
'e' || c ==
'E') {
1403 c = (current_ = p) < end_ ? *p++ :
'\0';
1404 if (c ==
'+' || c ==
'-')
1405 c = (current_ = p) < end_ ? *p++ :
'\0';
1406 while (c >=
'0' && c <=
'9')
1407 c = (current_ = p) < end_ ? *p++ :
'\0';
1411 bool OurReader::readString() {
1413 while (current_ != end_) {
1424 bool OurReader::readStringSingleQuote() {
1426 while (current_ != end_) {
1436 bool OurReader::readObject(Token& tokenStart) {
1440 currentValue().swapPayload(init);
1441 currentValue().setOffsetStart(tokenStart.start_ - begin_);
1442 while (readToken(tokenName)) {
1443 bool initialTokenOk =
true;
1444 while (tokenName.type_ == tokenComment && initialTokenOk)
1445 initialTokenOk = readToken(tokenName);
1446 if (!initialTokenOk)
1448 if (tokenName.type_ == tokenObjectEnd && name.empty())
1451 if (tokenName.type_ == tokenString) {
1452 if (!decodeString(tokenName, name))
1453 return recoverFromError(tokenObjectEnd);
1454 }
else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1456 if (!decodeNumber(tokenName, numberName))
1457 return recoverFromError(tokenObjectEnd);
1464 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1465 return addErrorAndRecover(
1466 "Missing ':' after object member name", colon, tokenObjectEnd);
1468 if (name.length() >= (1U<<30)) throwRuntimeError(
"keylength >= 2^30");
1469 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1471 return addErrorAndRecover(
1472 msg, tokenName, tokenObjectEnd);
1474 Value& value = currentValue()[name];
1475 nodes_.push(&value);
1476 bool ok = readValue();
1479 return recoverFromError(tokenObjectEnd);
1482 if (!readToken(comma) ||
1483 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1484 comma.type_ != tokenComment)) {
1485 return addErrorAndRecover(
1486 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
1488 bool finalizeTokenOk =
true;
1489 while (comma.type_ == tokenComment && finalizeTokenOk)
1490 finalizeTokenOk = readToken(comma);
1491 if (comma.type_ == tokenObjectEnd)
1494 return addErrorAndRecover(
1495 "Missing '}' or object member name", tokenName, tokenObjectEnd);
1498 bool OurReader::readArray(Token& tokenStart) {
1500 currentValue().swapPayload(init);
1501 currentValue().setOffsetStart(tokenStart.start_ - begin_);
1503 if (current_ != end_ && *current_ ==
']')
1506 readToken(endArray);
1511 Value& value = currentValue()[index++];
1512 nodes_.push(&value);
1513 bool ok = readValue();
1516 return recoverFromError(tokenArrayEnd);
1520 ok = readToken(token);
1521 while (token.type_ == tokenComment && ok) {
1522 ok = readToken(token);
1525 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
1526 if (!ok || badTokenType) {
1527 return addErrorAndRecover(
1528 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
1530 if (token.type_ == tokenArrayEnd)
1536 bool OurReader::decodeNumber(Token& token) {
1538 if (!decodeNumber(token, decoded))
1541 currentValue().setOffsetStart(token.start_ - begin_);
1542 currentValue().setOffsetLimit(token.end_ - begin_);
1546 bool OurReader::decodeNumber(Token& token,
Value& decoded) {
1551 bool isNegative = *current ==
'-';
1558 Value::LargestUInt threshold = maxIntegerValue / 10;
1559 Value::LargestUInt value = 0;
1560 while (current < token.end_) {
1561 Char c = *current++;
1562 if (c < '0' || c >
'9')
1563 return decodeDouble(token, decoded);
1564 Value::UInt digit(static_cast<Value::UInt>(c -
'0'));
1565 if (value >= threshold) {
1570 if (value > threshold || current != token.end_ ||
1571 digit > maxIntegerValue % 10) {
1572 return decodeDouble(token, decoded);
1575 value = value * 10 + digit;
1586 bool OurReader::decodeDouble(Token& token) {
1588 if (!decodeDouble(token, decoded))
1591 currentValue().setOffsetStart(token.start_ - begin_);
1592 currentValue().setOffsetLimit(token.end_ - begin_);
1596 bool OurReader::decodeDouble(Token& token,
Value& decoded) {
1598 const int bufferSize = 32;
1600 ptrdiff_t
const length = token.end_ - token.start_;
1604 return addError(
"Unable to parse token length", token);
1606 size_t const ulength =
static_cast<size_t>(length);
1613 char format[] =
"%lf";
1615 if (length <= bufferSize) {
1616 Char buffer[bufferSize + 1];
1617 memcpy(buffer, token.start_, ulength);
1620 count = sscanf(buffer, format, &value);
1623 count = sscanf(buffer.c_str(), format, &value);
1628 "' is not a number.",
1634 bool OurReader::decodeString(Token& token) {
1636 if (!decodeString(token, decoded_string))
1638 Value decoded(decoded_string);
1639 currentValue().swapPayload(decoded);
1640 currentValue().setOffsetStart(token.start_ - begin_);
1641 currentValue().setOffsetLimit(token.end_ - begin_);
1645 bool OurReader::decodeString(Token& token,
JSONCPP_STRING& decoded) {
1646 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
1647 Location current = token.start_ + 1;
1649 while (current != end) {
1650 Char c = *current++;
1653 else if (c ==
'\\') {
1655 return addError(
"Empty escape sequence in string", token, current);
1656 Char escape = *current++;
1683 unsigned int unicode;
1684 if (!decodeUnicodeCodePoint(token, current, end, unicode))
1689 return addError(
"Bad escape sequence in string", token, current);
1698 bool OurReader::decodeUnicodeCodePoint(Token& token,
1701 unsigned int& unicode) {
1703 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1705 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1707 if (end - current < 6)
1709 "additional six characters expected to parse unicode surrogate pair.",
1712 unsigned int surrogatePair;
1713 if (*(current++) ==
'\\' && *(current++) ==
'u') {
1714 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1715 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1719 return addError(
"expecting another \\u token to begin the second half of " 1720 "a unicode surrogate pair",
1727 bool OurReader::decodeUnicodeEscapeSequence(Token& token,
1730 unsigned int& ret_unicode) {
1731 if (end - current < 4)
1733 "Bad unicode escape sequence in string: four digits expected.",
1737 for (
int index = 0; index < 4; ++index) {
1738 Char c = *current++;
1740 if (c >=
'0' && c <=
'9')
1742 else if (c >=
'a' && c <=
'f')
1743 unicode += c -
'a' + 10;
1744 else if (c >=
'A' && c <=
'F')
1745 unicode += c -
'A' + 10;
1748 "Bad unicode escape sequence in string: hexadecimal digit expected.",
1752 ret_unicode =
static_cast<unsigned int>(unicode);
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 JSONCPP_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 {
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;
1819 getLocationLineAndColumn(location, line, column);
1820 char buffer[18 + 16 + 16 + 1];
1821 snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
1827 for (Errors::const_iterator itError = errors_.begin();
1828 itError != errors_.end();
1830 const ErrorInfo& error = *itError;
1832 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
1833 formattedMessage +=
" " + error.message_ +
"\n";
1836 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
1838 return formattedMessage;
1841 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors()
const {
1842 std::vector<OurReader::StructuredError> allErrors;
1843 for (Errors::const_iterator itError = errors_.begin();
1844 itError != errors_.end();
1846 const ErrorInfo& error = *itError;
1847 OurReader::StructuredError structured;
1848 structured.offset_start = error.token_.start_ - begin_;
1849 structured.offset_limit = error.token_.end_ - begin_;
1850 structured.message = error.message_;
1851 allErrors.push_back(structured);
1857 ptrdiff_t length = end_ - begin_;
1862 token.type_ = tokenError;
1866 info.token_ = token;
1867 info.message_ = message;
1869 errors_.push_back(info);
1874 ptrdiff_t length = end_ - begin_;
1880 token.type_ = tokenError;
1884 info.token_ = token;
1885 info.message_ = message;
1887 errors_.push_back(info);
1891 bool OurReader::good()
const {
1892 return !errors_.size();
1897 bool const collectComments_;
1901 bool collectComments,
1902 OurFeatures
const& features)
1903 : collectComments_(collectComments)
1907 char const* beginDoc,
char const* endDoc,
1909 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1911 *errs = reader_.getFormattedErrorMessages();
1919 setDefaults(&settings_);
1925 bool collectComments = settings_[
"collectComments"].asBool();
1926 OurFeatures features = OurFeatures::all();
1927 features.allowComments_ = settings_[
"allowComments"].asBool();
1928 features.strictRoot_ = settings_[
"strictRoot"].asBool();
1929 features.allowDroppedNullPlaceholders_ = settings_[
"allowDroppedNullPlaceholders"].asBool();
1930 features.allowNumericKeys_ = settings_[
"allowNumericKeys"].asBool();
1931 features.allowSingleQuotes_ = settings_[
"allowSingleQuotes"].asBool();
1932 features.stackLimit_ = settings_[
"stackLimit"].asInt();
1933 features.failIfExtra_ = settings_[
"failIfExtra"].asBool();
1934 features.rejectDupKeys_ = settings_[
"rejectDupKeys"].asBool();
1935 features.allowSpecialFloats_ = settings_[
"allowSpecialFloats"].asBool();
1936 return new OurCharReader(collectComments, features);
1940 valid_keys->clear();
1941 valid_keys->insert(
"collectComments");
1942 valid_keys->insert(
"allowComments");
1943 valid_keys->insert(
"strictRoot");
1944 valid_keys->insert(
"allowDroppedNullPlaceholders");
1945 valid_keys->insert(
"allowNumericKeys");
1946 valid_keys->insert(
"allowSingleQuotes");
1947 valid_keys->insert(
"stackLimit");
1948 valid_keys->insert(
"failIfExtra");
1949 valid_keys->insert(
"rejectDupKeys");
1950 valid_keys->insert(
"allowSpecialFloats");
1955 if (!invalid) invalid = &my_invalid;
1957 std::set<JSONCPP_STRING> valid_keys;
1960 size_t n = keys.size();
1961 for (
size_t i = 0; i < n; ++i) {
1963 if (valid_keys.find(key) == valid_keys.end()) {
1964 inv[key] = settings_[key];
1967 return 0u == inv.
size();
1971 return settings_[key];
1977 (*settings)[
"allowComments"] =
false;
1978 (*settings)[
"strictRoot"] =
true;
1979 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1980 (*settings)[
"allowNumericKeys"] =
false;
1981 (*settings)[
"allowSingleQuotes"] =
false;
1982 (*settings)[
"stackLimit"] = 1000;
1983 (*settings)[
"failIfExtra"] =
true;
1984 (*settings)[
"rejectDupKeys"] =
true;
1985 (*settings)[
"allowSpecialFloats"] =
false;
1992 (*settings)[
"collectComments"] =
true;
1993 (*settings)[
"allowComments"] =
true;
1994 (*settings)[
"strictRoot"] =
false;
1995 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1996 (*settings)[
"allowNumericKeys"] =
false;
1997 (*settings)[
"allowSingleQuotes"] =
false;
1998 (*settings)[
"stackLimit"] = 1000;
1999 (*settings)[
"failIfExtra"] =
false;
2000 (*settings)[
"rejectDupKeys"] =
false;
2001 (*settings)[
"allowSpecialFloats"] =
false;
2013 ssin << sin.rdbuf();
2015 char const* begin = doc.data();
2016 char const* end = begin + doc.size();
2019 return reader->parse(begin, end, root, errs);
2028 "Error from reader: %s",
2031 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.
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.
const char * asCString() const
Embedded zeroes could cause you trouble!
bool parse(const std::string &document, Value &root, bool collectComments=true)
Read a Value from a JSON document.
std::string asString() const
Embedded zeroes are possible.
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.
static std::string normalizeEOL(Reader::Location begin, Reader::Location end)
a comment on the line after a value (only make sense for
bool pushError(const Value &value, const std::string &message)
Add a semantic error message.
#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)
static bool containsNewLine(Reader::Location begin, Reader::Location end)
Configuration passed to reader and writer.
virtual CharReader * newCharReader() const =0
Allocate a CharReader via operator new().
a comment placed on the line before a value
Reader()
Constructs a Reader allowing all features for parsing.
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.