7 #if !defined(JSON_IS_AMALGAMATION)
12 #endif // if !defined(JSON_IS_AMALGAMATION)
25 #if __cplusplus >= 201103L
28 #define sscanf std::sscanf
34 #if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
35 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
36 #endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
41 #pragma warning(disable : 4996)
46 #if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
47 #define JSONCPP_DEPRECATED_STACK_LIMIT 1000
55 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
80 bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
81 return std::any_of(begin, end, [](
char b) {
return b ==
'\n' || b ==
'\r'; });
87 Reader::Reader() : features_(Features::all()) {}
89 Reader::Reader(
const Features& features) : features_(features) {}
91 bool Reader::parse(
const std::string& document, Value& root,
92 bool collectComments) {
93 document_.assign(document.begin(), document.end());
94 const char* begin = document_.c_str();
95 const char* end = begin + document_.length();
96 return parse(begin, end, root, collectComments);
99 bool Reader::parse(std::istream& is, Value& root,
bool collectComments) {
108 std::getline(is, doc,
static_cast<char> EOF);
109 return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
112 bool Reader::parse(
const char* beginDoc,
const char* endDoc, Value& root,
113 bool collectComments) {
114 if (!features_.allowComments_) {
115 collectComments =
false;
120 collectComments_ = collectComments;
122 lastValueEnd_ =
nullptr;
123 lastValue_ =
nullptr;
124 commentsBefore_.clear();
126 while (!nodes_.empty())
130 bool successful = readValue();
132 skipCommentTokens(token);
133 if (collectComments_ && !commentsBefore_.empty())
135 if (features_.strictRoot_) {
136 if (!root.isArray() && !root.isObject()) {
139 token.type_ = tokenError;
140 token.start_ = beginDoc;
143 "A valid JSON document must be either an array or an object value.",
151 bool Reader::readValue() {
157 throwRuntimeError(
"Exceeded stackLimit in readValue().");
160 skipCommentTokens(token);
161 bool successful =
true;
163 if (collectComments_ && !commentsBefore_.empty()) {
165 commentsBefore_.clear();
168 switch (token.type_) {
169 case tokenObjectBegin:
170 successful = readObject(token);
171 currentValue().setOffsetLimit(current_ - begin_);
173 case tokenArrayBegin:
174 successful = readArray(token);
175 currentValue().setOffsetLimit(current_ - begin_);
178 successful = decodeNumber(token);
181 successful = decodeString(token);
185 currentValue().swapPayload(v);
186 currentValue().setOffsetStart(token.start_ - begin_);
187 currentValue().setOffsetLimit(token.end_ - begin_);
191 currentValue().swapPayload(v);
192 currentValue().setOffsetStart(token.start_ - begin_);
193 currentValue().setOffsetLimit(token.end_ - begin_);
197 currentValue().swapPayload(v);
198 currentValue().setOffsetStart(token.start_ - begin_);
199 currentValue().setOffsetLimit(token.end_ - begin_);
201 case tokenArraySeparator:
204 if (features_.allowDroppedNullPlaceholders_) {
209 currentValue().swapPayload(v);
210 currentValue().setOffsetStart(current_ - begin_ - 1);
211 currentValue().setOffsetLimit(current_ - begin_);
215 currentValue().setOffsetStart(token.start_ - begin_);
216 currentValue().setOffsetLimit(token.end_ - begin_);
217 return addError(
"Syntax error: value, object or array expected.", token);
220 if (collectComments_) {
221 lastValueEnd_ = current_;
222 lastValue_ = ¤tValue();
228 void Reader::skipCommentTokens(Token& token) {
229 if (features_.allowComments_) {
232 }
while (token.type_ == tokenComment);
238 bool Reader::readToken(Token& token) {
240 token.start_ = current_;
241 Char c = getNextChar();
245 token.type_ = tokenObjectBegin;
248 token.type_ = tokenObjectEnd;
251 token.type_ = tokenArrayBegin;
254 token.type_ = tokenArrayEnd;
257 token.type_ = tokenString;
261 token.type_ = tokenComment;
275 token.type_ = tokenNumber;
279 token.type_ = tokenTrue;
280 ok = match(
"rue", 3);
283 token.type_ = tokenFalse;
284 ok = match(
"alse", 4);
287 token.type_ = tokenNull;
288 ok = match(
"ull", 3);
291 token.type_ = tokenArraySeparator;
294 token.type_ = tokenMemberSeparator;
297 token.type_ = tokenEndOfStream;
304 token.type_ = tokenError;
305 token.end_ = current_;
309 void Reader::skipSpaces() {
310 while (current_ != end_) {
312 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n')
319 bool Reader::match(
const Char* pattern,
int patternLength) {
320 if (end_ - current_ < patternLength)
322 int index = patternLength;
324 if (current_[index] != pattern[index])
326 current_ += patternLength;
330 bool Reader::readComment() {
331 Location commentBegin = current_ - 1;
332 Char c = getNextChar();
333 bool successful =
false;
335 successful = readCStyleComment();
337 successful = readCppStyleComment();
341 if (collectComments_) {
343 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
344 if (c !=
'*' || !containsNewLine(commentBegin, current_))
348 addComment(commentBegin, current_, placement);
353 String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {
355 normalized.reserve(
static_cast<size_t>(end - begin));
356 Reader::Location current = begin;
357 while (current != end) {
360 if (current != end && *current ==
'\n')
372 void Reader::addComment(Location begin, Location end,
374 assert(collectComments_);
375 const String& normalized = normalizeEOL(begin, end);
377 assert(lastValue_ !=
nullptr);
378 lastValue_->setComment(normalized, placement);
380 commentsBefore_ += normalized;
384 bool Reader::readCStyleComment() {
385 while ((current_ + 1) < end_) {
386 Char c = getNextChar();
387 if (c ==
'*' && *current_ ==
'/')
390 return getNextChar() ==
'/';
393 bool Reader::readCppStyleComment() {
394 while (current_ != end_) {
395 Char c = getNextChar();
400 if (current_ != end_ && *current_ ==
'\n')
409 void Reader::readNumber() {
410 Location p = current_;
413 while (c >=
'0' && c <=
'9')
414 c = (current_ = p) < end_ ? *p++ :
'\0';
417 c = (current_ = p) < end_ ? *p++ :
'\0';
418 while (c >=
'0' && c <=
'9')
419 c = (current_ = p) < end_ ? *p++ :
'\0';
422 if (c ==
'e' || c ==
'E') {
423 c = (current_ = p) < end_ ? *p++ :
'\0';
424 if (c ==
'+' || c ==
'-')
425 c = (current_ = p) < end_ ? *p++ :
'\0';
426 while (c >=
'0' && c <=
'9')
427 c = (current_ = p) < end_ ? *p++ :
'\0';
431 bool Reader::readString() {
433 while (current_ != end_) {
443 bool Reader::readObject(Token& token) {
447 currentValue().swapPayload(init);
448 currentValue().setOffsetStart(token.start_ - begin_);
449 while (readToken(tokenName)) {
450 bool initialTokenOk =
true;
451 while (tokenName.type_ == tokenComment && initialTokenOk)
452 initialTokenOk = readToken(tokenName);
455 if (tokenName.type_ == tokenObjectEnd && name.empty())
458 if (tokenName.type_ == tokenString) {
459 if (!decodeString(tokenName, name))
460 return recoverFromError(tokenObjectEnd);
461 }
else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
463 if (!decodeNumber(tokenName, numberName))
464 return recoverFromError(tokenObjectEnd);
465 name = numberName.asString();
471 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
472 return addErrorAndRecover(
"Missing ':' after object member name", colon,
475 Value& value = currentValue()[name];
477 bool ok = readValue();
480 return recoverFromError(tokenObjectEnd);
483 if (!readToken(comma) ||
484 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
485 comma.type_ != tokenComment)) {
486 return addErrorAndRecover(
"Missing ',' or '}' in object declaration",
487 comma, tokenObjectEnd);
489 bool finalizeTokenOk =
true;
490 while (comma.type_ == tokenComment && finalizeTokenOk)
491 finalizeTokenOk = readToken(comma);
492 if (comma.type_ == tokenObjectEnd)
495 return addErrorAndRecover(
"Missing '}' or object member name", tokenName,
499 bool Reader::readArray(Token& token) {
501 currentValue().swapPayload(init);
502 currentValue().setOffsetStart(token.start_ - begin_);
504 if (current_ != end_ && *current_ ==
']')
512 Value& value = currentValue()[index++];
514 bool ok = readValue();
517 return recoverFromError(tokenArrayEnd);
521 ok = readToken(currentToken);
522 while (currentToken.type_ == tokenComment && ok) {
523 ok = readToken(currentToken);
525 bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
526 currentToken.type_ != tokenArrayEnd);
527 if (!ok || badTokenType) {
528 return addErrorAndRecover(
"Missing ',' or ']' in array declaration",
529 currentToken, tokenArrayEnd);
531 if (currentToken.type_ == tokenArrayEnd)
537 bool Reader::decodeNumber(Token& token) {
539 if (!decodeNumber(token, decoded))
541 currentValue().swapPayload(decoded);
542 currentValue().setOffsetStart(token.start_ - begin_);
543 currentValue().setOffsetLimit(token.end_ - begin_);
547 bool Reader::decodeNumber(Token& token, Value& decoded) {
551 Location current = token.start_;
552 bool isNegative = *current ==
'-';
562 while (current < token.end_) {
564 if (c < '0' || c >
'9')
565 return decodeDouble(token, decoded);
567 if (value >= threshold) {
572 if (value > threshold || current != token.end_ ||
573 digit > maxIntegerValue % 10) {
574 return decodeDouble(token, decoded);
577 value = value * 10 + digit;
579 if (isNegative && value == maxIntegerValue)
590 bool Reader::decodeDouble(Token& token) {
592 if (!decodeDouble(token, decoded))
594 currentValue().swapPayload(decoded);
595 currentValue().setOffsetStart(token.start_ - begin_);
596 currentValue().setOffsetLimit(token.end_ - begin_);
600 bool Reader::decodeDouble(Token& token, Value& decoded) {
602 String buffer(token.start_, token.end_);
606 "'" +
String(token.start_, token.end_) +
"' is not a number.", token);
611 bool Reader::decodeString(Token& token) {
613 if (!decodeString(token, decoded_string))
615 Value decoded(decoded_string);
616 currentValue().swapPayload(decoded);
617 currentValue().setOffsetStart(token.start_ - begin_);
618 currentValue().setOffsetLimit(token.end_ - begin_);
622 bool Reader::decodeString(Token& token,
String& decoded) {
623 decoded.reserve(
static_cast<size_t>(token.end_ - token.start_ - 2));
624 Location current = token.start_ + 1;
625 Location end = token.end_ - 1;
626 while (current != end) {
632 return addError(
"Empty escape sequence in string", token, current);
633 Char escape = *current++;
660 unsigned int unicode;
661 if (!decodeUnicodeCodePoint(token, current, end, unicode))
666 return addError(
"Bad escape sequence in string", token, current);
675 bool Reader::decodeUnicodeCodePoint(Token& token, Location& current,
676 Location end,
unsigned int& unicode) {
678 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
680 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
682 if (end - current < 6)
684 "additional six characters expected to parse unicode surrogate pair.",
686 if (*(current++) ==
'\\' && *(current++) ==
'u') {
687 unsigned int surrogatePair;
688 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
689 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
693 return addError(
"expecting another \\u token to begin the second half of "
694 "a unicode surrogate pair",
700 bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current,
702 unsigned int& ret_unicode) {
703 if (end - current < 4)
705 "Bad unicode escape sequence in string: four digits expected.", token,
708 for (
int index = 0; index < 4; ++index) {
711 if (c >=
'0' && c <=
'9')
713 else if (c >=
'a' && c <=
'f')
714 unicode += c -
'a' + 10;
715 else if (c >=
'A' && c <=
'F')
716 unicode += c -
'A' + 10;
719 "Bad unicode escape sequence in string: hexadecimal digit expected.",
722 ret_unicode =
static_cast<unsigned int>(unicode);
726 bool Reader::addError(
const String& message, Token& token, Location extra) {
729 info.message_ = message;
731 errors_.push_back(info);
735 bool Reader::recoverFromError(TokenType skipUntilToken) {
736 size_t const errorCount = errors_.size();
739 if (!readToken(skip))
740 errors_.resize(errorCount);
741 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
744 errors_.resize(errorCount);
748 bool Reader::addErrorAndRecover(
const String& message, Token& token,
749 TokenType skipUntilToken) {
750 addError(message, token);
751 return recoverFromError(skipUntilToken);
754 Value& Reader::currentValue() {
return *(nodes_.top()); }
756 Reader::Char Reader::getNextChar() {
757 if (current_ == end_)
762 void Reader::getLocationLineAndColumn(Location location,
int& line,
764 Location current = begin_;
765 Location lastLineStart = current;
767 while (current < location && current != end_) {
770 if (*current ==
'\n')
772 lastLineStart = current;
774 }
else if (c ==
'\n') {
775 lastLineStart = current;
780 column = int(location - lastLineStart) + 1;
784 String Reader::getLocationLineAndColumn(Location location)
const {
786 getLocationLineAndColumn(location, line, column);
787 char buffer[18 + 16 + 16 + 1];
788 jsoncpp_snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
793 String Reader::getFormatedErrorMessages()
const {
794 return getFormattedErrorMessages();
797 String Reader::getFormattedErrorMessages()
const {
799 for (
const auto& error : errors_) {
801 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
802 formattedMessage +=
" " + error.message_ +
"\n";
805 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
807 return formattedMessage;
810 std::vector<Reader::StructuredError> Reader::getStructuredErrors()
const {
811 std::vector<Reader::StructuredError> allErrors;
812 for (
const auto& error : errors_) {
813 Reader::StructuredError structured;
814 structured.offset_start = error.token_.start_ - begin_;
815 structured.offset_limit = error.token_.end_ - begin_;
816 structured.message = error.message_;
817 allErrors.push_back(structured);
822 bool Reader::pushError(
const Value& value,
const String& message) {
823 ptrdiff_t
const length = end_ - begin_;
824 if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
827 token.type_ = tokenError;
828 token.start_ = begin_ + value.getOffsetStart();
829 token.end_ = begin_ + value.getOffsetLimit();
832 info.message_ = message;
833 info.extra_ =
nullptr;
834 errors_.push_back(info);
838 bool Reader::pushError(
const Value& value,
const String& message,
839 const Value& extra) {
840 ptrdiff_t
const length = end_ - begin_;
841 if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
842 extra.getOffsetLimit() > length)
845 token.type_ = tokenError;
846 token.start_ = begin_ + value.getOffsetStart();
847 token.end_ = begin_ + value.getOffsetLimit();
850 info.message_ = message;
851 info.extra_ = begin_ + extra.getOffsetStart();
852 errors_.push_back(info);
856 bool Reader::good()
const {
return errors_.empty(); }
862 static OurFeatures all();
864 bool allowTrailingCommas_;
866 bool allowDroppedNullPlaceholders_;
867 bool allowNumericKeys_;
868 bool allowSingleQuotes_;
871 bool allowSpecialFloats_;
876 OurFeatures OurFeatures::all() {
return {}; }
886 using Location =
const Char*;
887 struct StructuredError {
888 ptrdiff_t offset_start;
889 ptrdiff_t offset_limit;
893 explicit OurReader(OurFeatures
const& features);
894 bool parse(
const char* beginDoc,
const char* endDoc, Value& root,
895 bool collectComments =
true);
896 String getFormattedErrorMessages()
const;
897 std::vector<StructuredError> getStructuredErrors()
const;
900 OurReader(OurReader
const&);
901 void operator=(OurReader
const&);
904 tokenEndOfStream = 0,
918 tokenMemberSeparator,
937 using Errors = std::deque<ErrorInfo>;
939 bool readToken(Token& token);
941 void skipBom(
bool skipBom);
942 bool match(
const Char* pattern,
int patternLength);
944 bool readCStyleComment(
bool* containsNewLineResult);
945 bool readCppStyleComment();
947 bool readStringSingleQuote();
948 bool readNumber(
bool checkInf);
950 bool readObject(Token& token);
951 bool readArray(Token& token);
952 bool decodeNumber(Token& token);
953 bool decodeNumber(Token& token, Value& decoded);
954 bool decodeString(Token& token);
955 bool decodeString(Token& token,
String& decoded);
956 bool decodeDouble(Token& token);
957 bool decodeDouble(Token& token, Value& decoded);
958 bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
959 unsigned int& unicode);
960 bool decodeUnicodeEscapeSequence(Token& token, Location& current,
961 Location end,
unsigned int& unicode);
962 bool addError(
const String& message, Token& token, Location extra =
nullptr);
963 bool recoverFromError(TokenType skipUntilToken);
964 bool addErrorAndRecover(
const String& message, Token& token,
965 TokenType skipUntilToken);
966 void skipUntilSpace();
967 Value& currentValue();
969 void getLocationLineAndColumn(Location location,
int& line,
971 String getLocationLineAndColumn(Location location)
const;
973 void skipCommentTokens(Token& token);
975 static String normalizeEOL(Location begin, Location end);
976 static bool containsNewLine(Location begin, Location end);
978 using Nodes = std::stack<Value*>;
983 Location begin_ =
nullptr;
984 Location end_ =
nullptr;
985 Location current_ =
nullptr;
986 Location lastValueEnd_ =
nullptr;
987 Value* lastValue_ =
nullptr;
988 bool lastValueHasAComment_ =
false;
991 OurFeatures
const features_;
992 bool collectComments_ =
false;
997 bool OurReader::containsNewLine(OurReader::Location begin,
998 OurReader::Location end) {
999 return std::any_of(begin, end, [](
char b) {
return b ==
'\n' || b ==
'\r'; });
1002 OurReader::OurReader(OurFeatures
const& features) : features_(features) {}
1004 bool OurReader::parse(
const char* beginDoc,
const char* endDoc, Value& root,
1005 bool collectComments) {
1006 if (!features_.allowComments_) {
1007 collectComments =
false;
1012 collectComments_ = collectComments;
1014 lastValueEnd_ =
nullptr;
1015 lastValue_ =
nullptr;
1016 commentsBefore_.clear();
1018 while (!nodes_.empty())
1023 skipBom(features_.skipBom_);
1024 bool successful = readValue();
1027 skipCommentTokens(token);
1028 if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) {
1029 addError(
"Extra non-whitespace after JSON value.", token);
1032 if (collectComments_ && !commentsBefore_.empty())
1034 if (features_.strictRoot_) {
1035 if (!root.isArray() && !root.isObject()) {
1038 token.type_ = tokenError;
1039 token.start_ = beginDoc;
1040 token.end_ = endDoc;
1042 "A valid JSON document must be either an array or an object value.",
1050 bool OurReader::readValue() {
1052 if (nodes_.size() > features_.stackLimit_)
1053 throwRuntimeError(
"Exceeded stackLimit in readValue().");
1055 skipCommentTokens(token);
1056 bool successful =
true;
1058 if (collectComments_ && !commentsBefore_.empty()) {
1060 commentsBefore_.clear();
1063 switch (token.type_) {
1064 case tokenObjectBegin:
1065 successful = readObject(token);
1066 currentValue().setOffsetLimit(current_ - begin_);
1068 case tokenArrayBegin:
1069 successful = readArray(token);
1070 currentValue().setOffsetLimit(current_ - begin_);
1073 successful = decodeNumber(token);
1076 successful = decodeString(token);
1080 currentValue().swapPayload(v);
1081 currentValue().setOffsetStart(token.start_ - begin_);
1082 currentValue().setOffsetLimit(token.end_ - begin_);
1086 currentValue().swapPayload(v);
1087 currentValue().setOffsetStart(token.start_ - begin_);
1088 currentValue().setOffsetLimit(token.end_ - begin_);
1092 currentValue().swapPayload(v);
1093 currentValue().setOffsetStart(token.start_ - begin_);
1094 currentValue().setOffsetLimit(token.end_ - begin_);
1097 Value v(std::numeric_limits<double>::quiet_NaN());
1098 currentValue().swapPayload(v);
1099 currentValue().setOffsetStart(token.start_ - begin_);
1100 currentValue().setOffsetLimit(token.end_ - begin_);
1103 Value v(std::numeric_limits<double>::infinity());
1104 currentValue().swapPayload(v);
1105 currentValue().setOffsetStart(token.start_ - begin_);
1106 currentValue().setOffsetLimit(token.end_ - begin_);
1109 Value v(-std::numeric_limits<double>::infinity());
1110 currentValue().swapPayload(v);
1111 currentValue().setOffsetStart(token.start_ - begin_);
1112 currentValue().setOffsetLimit(token.end_ - begin_);
1114 case tokenArraySeparator:
1115 case tokenObjectEnd:
1117 if (features_.allowDroppedNullPlaceholders_) {
1122 currentValue().swapPayload(v);
1123 currentValue().setOffsetStart(current_ - begin_ - 1);
1124 currentValue().setOffsetLimit(current_ - begin_);
1128 currentValue().setOffsetStart(token.start_ - begin_);
1129 currentValue().setOffsetLimit(token.end_ - begin_);
1130 return addError(
"Syntax error: value, object or array expected.", token);
1133 if (collectComments_) {
1134 lastValueEnd_ = current_;
1135 lastValueHasAComment_ =
false;
1136 lastValue_ = ¤tValue();
1142 void OurReader::skipCommentTokens(Token& token) {
1143 if (features_.allowComments_) {
1146 }
while (token.type_ == tokenComment);
1152 bool OurReader::readToken(Token& token) {
1154 token.start_ = current_;
1155 Char c = getNextChar();
1159 token.type_ = tokenObjectBegin;
1162 token.type_ = tokenObjectEnd;
1165 token.type_ = tokenArrayBegin;
1168 token.type_ = tokenArrayEnd;
1171 token.type_ = tokenString;
1175 if (features_.allowSingleQuotes_) {
1176 token.type_ = tokenString;
1177 ok = readStringSingleQuote();
1184 token.type_ = tokenComment;
1197 token.type_ = tokenNumber;
1201 if (readNumber(
true)) {
1202 token.type_ = tokenNumber;
1204 token.type_ = tokenNegInf;
1205 ok = features_.allowSpecialFloats_ && match(
"nfinity", 7);
1209 if (readNumber(
true)) {
1210 token.type_ = tokenNumber;
1212 token.type_ = tokenPosInf;
1213 ok = features_.allowSpecialFloats_ && match(
"nfinity", 7);
1217 token.type_ = tokenTrue;
1218 ok = match(
"rue", 3);
1221 token.type_ = tokenFalse;
1222 ok = match(
"alse", 4);
1225 token.type_ = tokenNull;
1226 ok = match(
"ull", 3);
1229 if (features_.allowSpecialFloats_) {
1230 token.type_ = tokenNaN;
1231 ok = match(
"aN", 2);
1237 if (features_.allowSpecialFloats_) {
1238 token.type_ = tokenPosInf;
1239 ok = match(
"nfinity", 7);
1245 token.type_ = tokenArraySeparator;
1248 token.type_ = tokenMemberSeparator;
1251 token.type_ = tokenEndOfStream;
1258 token.type_ = tokenError;
1259 token.end_ = current_;
1263 void OurReader::skipSpaces() {
1264 while (current_ != end_) {
1266 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n')
1273 void OurReader::skipBom(
bool skipBom) {
1276 if ((end_ - begin_) >= 3 && strncmp(begin_,
"\xEF\xBB\xBF", 3) == 0) {
1283 bool OurReader::match(
const Char* pattern,
int patternLength) {
1284 if (end_ - current_ < patternLength)
1286 int index = patternLength;
1288 if (current_[index] != pattern[index])
1290 current_ += patternLength;
1294 bool OurReader::readComment() {
1295 const Location commentBegin = current_ - 1;
1296 const Char c = getNextChar();
1297 bool successful =
false;
1298 bool cStyleWithEmbeddedNewline =
false;
1300 const bool isCStyleComment = (c ==
'*');
1301 const bool isCppStyleComment = (c ==
'/');
1302 if (isCStyleComment) {
1303 successful = readCStyleComment(&cStyleWithEmbeddedNewline);
1304 }
else if (isCppStyleComment) {
1305 successful = readCppStyleComment();
1311 if (collectComments_) {
1314 if (!lastValueHasAComment_) {
1315 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
1316 if (isCppStyleComment || !cStyleWithEmbeddedNewline) {
1318 lastValueHasAComment_ =
true;
1323 addComment(commentBegin, current_, placement);
1328 String OurReader::normalizeEOL(OurReader::Location begin,
1329 OurReader::Location end) {
1331 normalized.reserve(
static_cast<size_t>(end - begin));
1332 OurReader::Location current = begin;
1333 while (current != end) {
1334 char c = *current++;
1336 if (current != end && *current ==
'\n')
1348 void OurReader::addComment(Location begin, Location end,
1350 assert(collectComments_);
1351 const String& normalized = normalizeEOL(begin, end);
1353 assert(lastValue_ !=
nullptr);
1354 lastValue_->setComment(normalized, placement);
1356 commentsBefore_ += normalized;
1360 bool OurReader::readCStyleComment(
bool* containsNewLineResult) {
1361 *containsNewLineResult =
false;
1363 while ((current_ + 1) < end_) {
1364 Char c = getNextChar();
1365 if (c ==
'*' && *current_ ==
'/')
1368 *containsNewLineResult =
true;
1371 return getNextChar() ==
'/';
1374 bool OurReader::readCppStyleComment() {
1375 while (current_ != end_) {
1376 Char c = getNextChar();
1381 if (current_ != end_ && *current_ ==
'\n')
1390 bool OurReader::readNumber(
bool checkInf) {
1391 Location p = current_;
1392 if (checkInf && p != end_ && *p ==
'I') {
1398 while (c >=
'0' && c <=
'9')
1399 c = (current_ = p) < end_ ? *p++ :
'\0';
1402 c = (current_ = p) < end_ ? *p++ :
'\0';
1403 while (c >=
'0' && c <=
'9')
1404 c = (current_ = p) < end_ ? *p++ :
'\0';
1407 if (c ==
'e' || c ==
'E') {
1408 c = (current_ = p) < end_ ? *p++ :
'\0';
1409 if (c ==
'+' || c ==
'-')
1410 c = (current_ = p) < end_ ? *p++ :
'\0';
1411 while (c >=
'0' && c <=
'9')
1412 c = (current_ = p) < end_ ? *p++ :
'\0';
1416 bool OurReader::readString() {
1418 while (current_ != end_) {
1428 bool OurReader::readStringSingleQuote() {
1430 while (current_ != end_) {
1440 bool OurReader::readObject(Token& token) {
1444 currentValue().swapPayload(init);
1445 currentValue().setOffsetStart(token.start_ - begin_);
1446 while (readToken(tokenName)) {
1447 bool initialTokenOk =
true;
1448 while (tokenName.type_ == tokenComment && initialTokenOk)
1449 initialTokenOk = readToken(tokenName);
1450 if (!initialTokenOk)
1452 if (tokenName.type_ == tokenObjectEnd &&
1454 features_.allowTrailingCommas_))
1457 if (tokenName.type_ == tokenString) {
1458 if (!decodeString(tokenName, name))
1459 return recoverFromError(tokenObjectEnd);
1460 }
else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1462 if (!decodeNumber(tokenName, numberName))
1463 return recoverFromError(tokenObjectEnd);
1464 name = numberName.asString();
1468 if (name.length() >= (1U << 30))
1469 throwRuntimeError(
"keylength >= 2^30");
1470 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1471 String msg =
"Duplicate key: '" + name +
"'";
1472 return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
1476 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1477 return addErrorAndRecover(
"Missing ':' after object member name", colon,
1480 Value& value = currentValue()[name];
1481 nodes_.push(&value);
1482 bool ok = readValue();
1485 return recoverFromError(tokenObjectEnd);
1488 if (!readToken(comma) ||
1489 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1490 comma.type_ != tokenComment)) {
1491 return addErrorAndRecover(
"Missing ',' or '}' in object declaration",
1492 comma, tokenObjectEnd);
1494 bool finalizeTokenOk =
true;
1495 while (comma.type_ == tokenComment && finalizeTokenOk)
1496 finalizeTokenOk = readToken(comma);
1497 if (comma.type_ == tokenObjectEnd)
1500 return addErrorAndRecover(
"Missing '}' or object member name", tokenName,
1504 bool OurReader::readArray(Token& token) {
1506 currentValue().swapPayload(init);
1507 currentValue().setOffsetStart(token.start_ - begin_);
1511 if (current_ != end_ && *current_ ==
']' &&
1513 (features_.allowTrailingCommas_ &&
1514 !features_.allowDroppedNullPlaceholders_)))
1518 readToken(endArray);
1521 Value& value = currentValue()[index++];
1522 nodes_.push(&value);
1523 bool ok = readValue();
1526 return recoverFromError(tokenArrayEnd);
1530 ok = readToken(currentToken);
1531 while (currentToken.type_ == tokenComment && ok) {
1532 ok = readToken(currentToken);
1534 bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
1535 currentToken.type_ != tokenArrayEnd);
1536 if (!ok || badTokenType) {
1537 return addErrorAndRecover(
"Missing ',' or ']' in array declaration",
1538 currentToken, tokenArrayEnd);
1540 if (currentToken.type_ == tokenArrayEnd)
1546 bool OurReader::decodeNumber(Token& token) {
1548 if (!decodeNumber(token, decoded))
1550 currentValue().swapPayload(decoded);
1551 currentValue().setOffsetStart(token.start_ - begin_);
1552 currentValue().setOffsetLimit(token.end_ - begin_);
1556 bool OurReader::decodeNumber(Token& token, Value& decoded) {
1560 Location current = token.start_;
1561 const bool isNegative = *current ==
'-';
1570 "Int must be smaller than UInt");
1577 "The absolute value of minLargestInt must be greater than or "
1578 "equal to maxLargestInt");
1580 "The absolute value of minLargestInt must be only 1 magnitude "
1581 "larger than maxLargest Int");
1592 static constexpr
auto negative_threshold =
1594 static constexpr
auto negative_last_digit =
1598 isNegative ? negative_threshold : positive_threshold;
1600 isNegative ? negative_last_digit : positive_last_digit;
1603 while (current < token.end_) {
1604 Char c = *current++;
1605 if (c < '0' || c >
'9')
1606 return decodeDouble(token, decoded);
1608 const auto digit(
static_cast<Value::UInt>(c -
'0'));
1609 if (value >= threshold) {
1615 if (value > threshold || current != token.end_ ||
1616 digit > max_last_digit) {
1617 return decodeDouble(token, decoded);
1620 value = value * 10 + digit;
1625 const auto last_digit =
static_cast<Value::UInt>(value % 10);
1636 bool OurReader::decodeDouble(Token& token) {
1638 if (!decodeDouble(token, decoded))
1640 currentValue().swapPayload(decoded);
1641 currentValue().setOffsetStart(token.start_ - begin_);
1642 currentValue().setOffsetLimit(token.end_ - begin_);
1646 bool OurReader::decodeDouble(Token& token, Value& decoded) {
1648 const String buffer(token.start_, token.end_);
1650 if (!(is >> value)) {
1652 "'" +
String(token.start_, token.end_) +
"' is not a number.", token);
1658 bool OurReader::decodeString(Token& token) {
1660 if (!decodeString(token, decoded_string))
1662 Value decoded(decoded_string);
1663 currentValue().swapPayload(decoded);
1664 currentValue().setOffsetStart(token.start_ - begin_);
1665 currentValue().setOffsetLimit(token.end_ - begin_);
1669 bool OurReader::decodeString(Token& token,
String& decoded) {
1670 decoded.reserve(
static_cast<size_t>(token.end_ - token.start_ - 2));
1671 Location current = token.start_ + 1;
1672 Location end = token.end_ - 1;
1673 while (current != end) {
1674 Char c = *current++;
1679 return addError(
"Empty escape sequence in string", token, current);
1680 Char escape = *current++;
1707 unsigned int unicode;
1708 if (!decodeUnicodeCodePoint(token, current, end, unicode))
1713 return addError(
"Bad escape sequence in string", token, current);
1722 bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current,
1723 Location end,
unsigned int& unicode) {
1725 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1727 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1729 if (end - current < 6)
1731 "additional six characters expected to parse unicode surrogate pair.",
1733 if (*(current++) ==
'\\' && *(current++) ==
'u') {
1734 unsigned int surrogatePair;
1735 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1736 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1740 return addError(
"expecting another \\u token to begin the second half of "
1741 "a unicode surrogate pair",
1747 bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current,
1749 unsigned int& ret_unicode) {
1750 if (end - current < 4)
1752 "Bad unicode escape sequence in string: four digits expected.", token,
1755 for (
int index = 0; index < 4; ++index) {
1756 Char c = *current++;
1758 if (c >=
'0' && c <=
'9')
1760 else if (c >=
'a' && c <=
'f')
1761 unicode += c -
'a' + 10;
1762 else if (c >=
'A' && c <=
'F')
1763 unicode += c -
'A' + 10;
1766 "Bad unicode escape sequence in string: hexadecimal digit expected.",
1769 ret_unicode =
static_cast<unsigned int>(unicode);
1773 bool OurReader::addError(
const String& message, Token& token, Location extra) {
1775 info.token_ = token;
1776 info.message_ = message;
1777 info.extra_ = extra;
1778 errors_.push_back(info);
1782 bool OurReader::recoverFromError(TokenType skipUntilToken) {
1783 size_t errorCount = errors_.size();
1786 if (!readToken(skip))
1787 errors_.resize(errorCount);
1788 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
1791 errors_.resize(errorCount);
1795 bool OurReader::addErrorAndRecover(
const String& message, Token& token,
1796 TokenType skipUntilToken) {
1797 addError(message, token);
1798 return recoverFromError(skipUntilToken);
1801 Value& OurReader::currentValue() {
return *(nodes_.top()); }
1803 OurReader::Char OurReader::getNextChar() {
1804 if (current_ == end_)
1809 void OurReader::getLocationLineAndColumn(Location location,
int& line,
1810 int& column)
const {
1811 Location current = begin_;
1812 Location lastLineStart = current;
1814 while (current < location && current != end_) {
1815 Char c = *current++;
1817 if (*current ==
'\n')
1819 lastLineStart = current;
1821 }
else if (c ==
'\n') {
1822 lastLineStart = current;
1827 column = int(location - lastLineStart) + 1;
1831 String OurReader::getLocationLineAndColumn(Location location)
const {
1833 getLocationLineAndColumn(location, line, column);
1834 char buffer[18 + 16 + 16 + 1];
1835 jsoncpp_snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
1839 String OurReader::getFormattedErrorMessages()
const {
1841 for (
const auto& error : errors_) {
1843 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
1844 formattedMessage +=
" " + error.message_ +
"\n";
1847 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
1849 return formattedMessage;
1852 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors()
const {
1853 std::vector<OurReader::StructuredError> allErrors;
1854 for (
const auto& error : errors_) {
1855 OurReader::StructuredError structured;
1856 structured.offset_start = error.token_.start_ - begin_;
1857 structured.offset_limit = error.token_.end_ - begin_;
1858 structured.message = error.message_;
1859 allErrors.push_back(structured);
1864 class OurCharReader :
public CharReader {
1865 bool const collectComments_;
1869 OurCharReader(
bool collectComments, OurFeatures
const& features)
1870 : collectComments_(collectComments), reader_(features) {}
1871 bool parse(
char const* beginDoc,
char const* endDoc, Value* root,
1873 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1875 *errs = reader_.getFormattedErrorMessages();
1885 OurFeatures features = OurFeatures::all();
1887 features.allowTrailingCommas_ =
settings_[
"allowTrailingCommas"].
asBool();
1889 features.allowDroppedNullPlaceholders_ =
1892 features.allowSingleQuotes_ =
settings_[
"allowSingleQuotes"].
asBool();
1896 features.stackLimit_ =
static_cast<size_t>(
settings_[
"stackLimit"].
asUInt());
1899 features.allowSpecialFloats_ =
settings_[
"allowSpecialFloats"].
asBool();
1901 return new OurCharReader(collectComments, features);
1905 static const auto& valid_keys = *
new std::set<String>{
1908 "allowTrailingCommas",
1910 "allowDroppedNullPlaceholders",
1912 "allowSingleQuotes",
1916 "allowSpecialFloats",
1920 auto key = si.name();
1921 if (valid_keys.count(key))
1924 (*invalid)[std::move(key)] = *si;
1928 return invalid ? invalid->
empty() :
true;
1937 (*settings)[
"allowComments"] =
false;
1938 (*settings)[
"allowTrailingCommas"] =
false;
1939 (*settings)[
"strictRoot"] =
true;
1940 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1941 (*settings)[
"allowNumericKeys"] =
false;
1942 (*settings)[
"allowSingleQuotes"] =
false;
1943 (*settings)[
"stackLimit"] = 1000;
1944 (*settings)[
"failIfExtra"] =
true;
1945 (*settings)[
"rejectDupKeys"] =
true;
1946 (*settings)[
"allowSpecialFloats"] =
false;
1947 (*settings)[
"skipBom"] =
true;
1953 (*settings)[
"collectComments"] =
true;
1954 (*settings)[
"allowComments"] =
true;
1955 (*settings)[
"allowTrailingCommas"] =
true;
1956 (*settings)[
"strictRoot"] =
false;
1957 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1958 (*settings)[
"allowNumericKeys"] =
false;
1959 (*settings)[
"allowSingleQuotes"] =
false;
1960 (*settings)[
"stackLimit"] = 1000;
1961 (*settings)[
"failIfExtra"] =
false;
1962 (*settings)[
"rejectDupKeys"] =
false;
1963 (*settings)[
"allowSpecialFloats"] =
false;
1964 (*settings)[
"skipBom"] =
true;
1974 ssin << sin.rdbuf();
1976 char const* begin = doc.data();
1977 char const* end = begin + doc.size();
1980 return reader->parse(begin, end, root, errs);
1988 throwRuntimeError(errs);