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();
1181 token.type_ = tokenComment;
1194 token.type_ = tokenNumber;
1198 if (readNumber(
true)) {
1199 token.type_ = tokenNumber;
1201 token.type_ = tokenNegInf;
1202 ok = features_.allowSpecialFloats_ && match(
"nfinity", 7);
1206 if (readNumber(
true)) {
1207 token.type_ = tokenNumber;
1209 token.type_ = tokenPosInf;
1210 ok = features_.allowSpecialFloats_ && match(
"nfinity", 7);
1214 token.type_ = tokenTrue;
1215 ok = match(
"rue", 3);
1218 token.type_ = tokenFalse;
1219 ok = match(
"alse", 4);
1222 token.type_ = tokenNull;
1223 ok = match(
"ull", 3);
1226 if (features_.allowSpecialFloats_) {
1227 token.type_ = tokenNaN;
1228 ok = match(
"aN", 2);
1234 if (features_.allowSpecialFloats_) {
1235 token.type_ = tokenPosInf;
1236 ok = match(
"nfinity", 7);
1242 token.type_ = tokenArraySeparator;
1245 token.type_ = tokenMemberSeparator;
1248 token.type_ = tokenEndOfStream;
1255 token.type_ = tokenError;
1256 token.end_ = current_;
1260 void OurReader::skipSpaces() {
1261 while (current_ != end_) {
1263 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n')
1270 void OurReader::skipBom(
bool skipBom) {
1273 if ((end_ - begin_) >= 3 && strncmp(begin_,
"\xEF\xBB\xBF", 3) == 0) {
1280 bool OurReader::match(
const Char* pattern,
int patternLength) {
1281 if (end_ - current_ < patternLength)
1283 int index = patternLength;
1285 if (current_[index] != pattern[index])
1287 current_ += patternLength;
1291 bool OurReader::readComment() {
1292 const Location commentBegin = current_ - 1;
1293 const Char c = getNextChar();
1294 bool successful =
false;
1295 bool cStyleWithEmbeddedNewline =
false;
1297 const bool isCStyleComment = (c ==
'*');
1298 const bool isCppStyleComment = (c ==
'/');
1299 if (isCStyleComment) {
1300 successful = readCStyleComment(&cStyleWithEmbeddedNewline);
1301 }
else if (isCppStyleComment) {
1302 successful = readCppStyleComment();
1308 if (collectComments_) {
1311 if (!lastValueHasAComment_) {
1312 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
1313 if (isCppStyleComment || !cStyleWithEmbeddedNewline) {
1315 lastValueHasAComment_ =
true;
1320 addComment(commentBegin, current_, placement);
1325 String OurReader::normalizeEOL(OurReader::Location begin,
1326 OurReader::Location end) {
1328 normalized.reserve(
static_cast<size_t>(end - begin));
1329 OurReader::Location current = begin;
1330 while (current != end) {
1331 char c = *current++;
1333 if (current != end && *current ==
'\n')
1345 void OurReader::addComment(Location begin, Location end,
1347 assert(collectComments_);
1348 const String& normalized = normalizeEOL(begin, end);
1350 assert(lastValue_ !=
nullptr);
1351 lastValue_->setComment(normalized, placement);
1353 commentsBefore_ += normalized;
1357 bool OurReader::readCStyleComment(
bool* containsNewLineResult) {
1358 *containsNewLineResult =
false;
1360 while ((current_ + 1) < end_) {
1361 Char c = getNextChar();
1362 if (c ==
'*' && *current_ ==
'/')
1365 *containsNewLineResult =
true;
1368 return getNextChar() ==
'/';
1371 bool OurReader::readCppStyleComment() {
1372 while (current_ != end_) {
1373 Char c = getNextChar();
1378 if (current_ != end_ && *current_ ==
'\n')
1387 bool OurReader::readNumber(
bool checkInf) {
1388 Location p = current_;
1389 if (checkInf && p != end_ && *p ==
'I') {
1395 while (c >=
'0' && c <=
'9')
1396 c = (current_ = p) < end_ ? *p++ :
'\0';
1399 c = (current_ = p) < end_ ? *p++ :
'\0';
1400 while (c >=
'0' && c <=
'9')
1401 c = (current_ = p) < end_ ? *p++ :
'\0';
1404 if (c ==
'e' || c ==
'E') {
1405 c = (current_ = p) < end_ ? *p++ :
'\0';
1406 if (c ==
'+' || c ==
'-')
1407 c = (current_ = p) < end_ ? *p++ :
'\0';
1408 while (c >=
'0' && c <=
'9')
1409 c = (current_ = p) < end_ ? *p++ :
'\0';
1413 bool OurReader::readString() {
1415 while (current_ != end_) {
1425 bool OurReader::readStringSingleQuote() {
1427 while (current_ != end_) {
1437 bool OurReader::readObject(Token& token) {
1441 currentValue().swapPayload(init);
1442 currentValue().setOffsetStart(token.start_ - begin_);
1443 while (readToken(tokenName)) {
1444 bool initialTokenOk =
true;
1445 while (tokenName.type_ == tokenComment && initialTokenOk)
1446 initialTokenOk = readToken(tokenName);
1447 if (!initialTokenOk)
1449 if (tokenName.type_ == tokenObjectEnd &&
1451 features_.allowTrailingCommas_))
1454 if (tokenName.type_ == tokenString) {
1455 if (!decodeString(tokenName, name))
1456 return recoverFromError(tokenObjectEnd);
1457 }
else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1459 if (!decodeNumber(tokenName, numberName))
1460 return recoverFromError(tokenObjectEnd);
1461 name = numberName.asString();
1465 if (name.length() >= (1U << 30))
1466 throwRuntimeError(
"keylength >= 2^30");
1467 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1468 String msg =
"Duplicate key: '" + name +
"'";
1469 return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
1473 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1474 return addErrorAndRecover(
"Missing ':' after object member name", colon,
1477 Value& value = currentValue()[name];
1478 nodes_.push(&value);
1479 bool ok = readValue();
1482 return recoverFromError(tokenObjectEnd);
1485 if (!readToken(comma) ||
1486 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1487 comma.type_ != tokenComment)) {
1488 return addErrorAndRecover(
"Missing ',' or '}' in object declaration",
1489 comma, tokenObjectEnd);
1491 bool finalizeTokenOk =
true;
1492 while (comma.type_ == tokenComment && finalizeTokenOk)
1493 finalizeTokenOk = readToken(comma);
1494 if (comma.type_ == tokenObjectEnd)
1497 return addErrorAndRecover(
"Missing '}' or object member name", tokenName,
1501 bool OurReader::readArray(Token& token) {
1503 currentValue().swapPayload(init);
1504 currentValue().setOffsetStart(token.start_ - begin_);
1508 if (current_ != end_ && *current_ ==
']' &&
1510 (features_.allowTrailingCommas_ &&
1511 !features_.allowDroppedNullPlaceholders_)))
1515 readToken(endArray);
1518 Value& value = currentValue()[index++];
1519 nodes_.push(&value);
1520 bool ok = readValue();
1523 return recoverFromError(tokenArrayEnd);
1527 ok = readToken(currentToken);
1528 while (currentToken.type_ == tokenComment && ok) {
1529 ok = readToken(currentToken);
1531 bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
1532 currentToken.type_ != tokenArrayEnd);
1533 if (!ok || badTokenType) {
1534 return addErrorAndRecover(
"Missing ',' or ']' in array declaration",
1535 currentToken, tokenArrayEnd);
1537 if (currentToken.type_ == tokenArrayEnd)
1543 bool OurReader::decodeNumber(Token& token) {
1545 if (!decodeNumber(token, decoded))
1547 currentValue().swapPayload(decoded);
1548 currentValue().setOffsetStart(token.start_ - begin_);
1549 currentValue().setOffsetLimit(token.end_ - begin_);
1553 bool OurReader::decodeNumber(Token& token, Value& decoded) {
1557 Location current = token.start_;
1558 const bool isNegative = *current ==
'-';
1567 "Int must be smaller than UInt");
1574 "The absolute value of minLargestInt must be greater than or "
1575 "equal to maxLargestInt");
1577 "The absolute value of minLargestInt must be only 1 magnitude "
1578 "larger than maxLargest Int");
1589 static constexpr
auto negative_threshold =
1591 static constexpr
auto negative_last_digit =
1595 isNegative ? negative_threshold : positive_threshold;
1597 isNegative ? negative_last_digit : positive_last_digit;
1600 while (current < token.end_) {
1601 Char c = *current++;
1602 if (c < '0' || c >
'9')
1603 return decodeDouble(token, decoded);
1605 const auto digit(
static_cast<Value::UInt>(c -
'0'));
1606 if (value >= threshold) {
1612 if (value > threshold || current != token.end_ ||
1613 digit > max_last_digit) {
1614 return decodeDouble(token, decoded);
1617 value = value * 10 + digit;
1622 const auto last_digit =
static_cast<Value::UInt>(value % 10);
1633 bool OurReader::decodeDouble(Token& token) {
1635 if (!decodeDouble(token, decoded))
1637 currentValue().swapPayload(decoded);
1638 currentValue().setOffsetStart(token.start_ - begin_);
1639 currentValue().setOffsetLimit(token.end_ - begin_);
1643 bool OurReader::decodeDouble(Token& token, Value& decoded) {
1645 const String buffer(token.start_, token.end_);
1647 if (!(is >> value)) {
1649 "'" +
String(token.start_, token.end_) +
"' is not a number.", token);
1655 bool OurReader::decodeString(Token& token) {
1657 if (!decodeString(token, decoded_string))
1659 Value decoded(decoded_string);
1660 currentValue().swapPayload(decoded);
1661 currentValue().setOffsetStart(token.start_ - begin_);
1662 currentValue().setOffsetLimit(token.end_ - begin_);
1666 bool OurReader::decodeString(Token& token,
String& decoded) {
1667 decoded.reserve(
static_cast<size_t>(token.end_ - token.start_ - 2));
1668 Location current = token.start_ + 1;
1669 Location end = token.end_ - 1;
1670 while (current != end) {
1671 Char c = *current++;
1676 return addError(
"Empty escape sequence in string", token, current);
1677 Char escape = *current++;
1704 unsigned int unicode;
1705 if (!decodeUnicodeCodePoint(token, current, end, unicode))
1710 return addError(
"Bad escape sequence in string", token, current);
1719 bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current,
1720 Location end,
unsigned int& unicode) {
1722 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1724 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1726 if (end - current < 6)
1728 "additional six characters expected to parse unicode surrogate pair.",
1730 if (*(current++) ==
'\\' && *(current++) ==
'u') {
1731 unsigned int surrogatePair;
1732 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1733 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1737 return addError(
"expecting another \\u token to begin the second half of "
1738 "a unicode surrogate pair",
1744 bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current,
1746 unsigned int& ret_unicode) {
1747 if (end - current < 4)
1749 "Bad unicode escape sequence in string: four digits expected.", token,
1752 for (
int index = 0; index < 4; ++index) {
1753 Char c = *current++;
1755 if (c >=
'0' && c <=
'9')
1757 else if (c >=
'a' && c <=
'f')
1758 unicode += c -
'a' + 10;
1759 else if (c >=
'A' && c <=
'F')
1760 unicode += c -
'A' + 10;
1763 "Bad unicode escape sequence in string: hexadecimal digit expected.",
1766 ret_unicode =
static_cast<unsigned int>(unicode);
1770 bool OurReader::addError(
const String& message, Token& token, Location extra) {
1772 info.token_ = token;
1773 info.message_ = message;
1774 info.extra_ = extra;
1775 errors_.push_back(info);
1779 bool OurReader::recoverFromError(TokenType skipUntilToken) {
1780 size_t errorCount = errors_.size();
1783 if (!readToken(skip))
1784 errors_.resize(errorCount);
1785 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
1788 errors_.resize(errorCount);
1792 bool OurReader::addErrorAndRecover(
const String& message, Token& token,
1793 TokenType skipUntilToken) {
1794 addError(message, token);
1795 return recoverFromError(skipUntilToken);
1798 Value& OurReader::currentValue() {
return *(nodes_.top()); }
1800 OurReader::Char OurReader::getNextChar() {
1801 if (current_ == end_)
1806 void OurReader::getLocationLineAndColumn(Location location,
int& line,
1807 int& column)
const {
1808 Location current = begin_;
1809 Location lastLineStart = current;
1811 while (current < location && current != end_) {
1812 Char c = *current++;
1814 if (*current ==
'\n')
1816 lastLineStart = current;
1818 }
else if (c ==
'\n') {
1819 lastLineStart = current;
1824 column = int(location - lastLineStart) + 1;
1828 String OurReader::getLocationLineAndColumn(Location location)
const {
1830 getLocationLineAndColumn(location, line, column);
1831 char buffer[18 + 16 + 16 + 1];
1832 jsoncpp_snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
1836 String OurReader::getFormattedErrorMessages()
const {
1838 for (
const auto& error : errors_) {
1840 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
1841 formattedMessage +=
" " + error.message_ +
"\n";
1844 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
1846 return formattedMessage;
1849 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors()
const {
1850 std::vector<OurReader::StructuredError> allErrors;
1851 for (
const auto& error : errors_) {
1852 OurReader::StructuredError structured;
1853 structured.offset_start = error.token_.start_ - begin_;
1854 structured.offset_limit = error.token_.end_ - begin_;
1855 structured.message = error.message_;
1856 allErrors.push_back(structured);
1861 class OurCharReader :
public CharReader {
1862 bool const collectComments_;
1866 OurCharReader(
bool collectComments, OurFeatures
const& features)
1867 : collectComments_(collectComments), reader_(features) {}
1868 bool parse(
char const* beginDoc,
char const* endDoc, Value* root,
1870 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1872 *errs = reader_.getFormattedErrorMessages();
1882 OurFeatures features = OurFeatures::all();
1884 features.allowTrailingCommas_ =
settings_[
"allowTrailingCommas"].
asBool();
1886 features.allowDroppedNullPlaceholders_ =
1889 features.allowSingleQuotes_ =
settings_[
"allowSingleQuotes"].
asBool();
1893 features.stackLimit_ =
static_cast<size_t>(
settings_[
"stackLimit"].
asUInt());
1896 features.allowSpecialFloats_ =
settings_[
"allowSpecialFloats"].
asBool();
1898 return new OurCharReader(collectComments, features);
1902 static const auto& valid_keys = *
new std::set<String>{
1905 "allowTrailingCommas",
1907 "allowDroppedNullPlaceholders",
1909 "allowSingleQuotes",
1913 "allowSpecialFloats",
1917 auto key = si.name();
1918 if (valid_keys.count(key))
1921 (*invalid)[std::move(key)] = *si;
1925 return invalid ? invalid->
empty() :
true;
1934 (*settings)[
"allowComments"] =
false;
1935 (*settings)[
"allowTrailingCommas"] =
false;
1936 (*settings)[
"strictRoot"] =
true;
1937 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1938 (*settings)[
"allowNumericKeys"] =
false;
1939 (*settings)[
"allowSingleQuotes"] =
false;
1940 (*settings)[
"stackLimit"] = 1000;
1941 (*settings)[
"failIfExtra"] =
true;
1942 (*settings)[
"rejectDupKeys"] =
true;
1943 (*settings)[
"allowSpecialFloats"] =
false;
1944 (*settings)[
"skipBom"] =
true;
1950 (*settings)[
"collectComments"] =
true;
1951 (*settings)[
"allowComments"] =
true;
1952 (*settings)[
"allowTrailingCommas"] =
true;
1953 (*settings)[
"strictRoot"] =
false;
1954 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1955 (*settings)[
"allowNumericKeys"] =
false;
1956 (*settings)[
"allowSingleQuotes"] =
false;
1957 (*settings)[
"stackLimit"] = 1000;
1958 (*settings)[
"failIfExtra"] =
false;
1959 (*settings)[
"rejectDupKeys"] =
false;
1960 (*settings)[
"allowSpecialFloats"] =
false;
1961 (*settings)[
"skipBom"] =
true;
1971 ssin << sin.rdbuf();
1973 char const* begin = doc.data();
1974 char const* end = begin + doc.size();
1977 return reader->parse(begin, end, root, errs);
1985 throwRuntimeError(errs);