7 #if !defined(JSON_IS_AMALGAMATION)
12 #endif // if !defined(JSON_IS_AMALGAMATION)
24 #if __cplusplus >= 201103L
27 #define sscanf std::sscanf
33 #if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
34 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
35 #endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
40 #pragma warning(disable : 4996)
45 #if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
46 #define JSONCPP_DEPRECATED_STACK_LIMIT 1000
54 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
79 bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
80 for (; begin < end; ++begin)
81 if (*begin ==
'\n' || *begin ==
'\r')
89 Reader::Reader() : features_(Features::all()) {}
91 Reader::Reader(
const Features& features) : features_(features) {}
93 bool Reader::parse(
const std::string& document, Value& root,
94 bool collectComments) {
95 document_.assign(document.begin(), document.end());
96 const char* begin = document_.c_str();
97 const char* end = begin + document_.length();
98 return parse(begin, end, root, collectComments);
101 bool Reader::parse(std::istream& is, Value& root,
bool collectComments) {
110 std::getline(is, doc, static_cast<char> EOF);
111 return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
114 bool Reader::parse(
const char* beginDoc,
const char* endDoc, Value& root,
115 bool collectComments) {
116 if (!features_.allowComments_) {
117 collectComments =
false;
122 collectComments_ = collectComments;
124 lastValueEnd_ =
nullptr;
125 lastValue_ =
nullptr;
126 commentsBefore_.clear();
128 while (!nodes_.empty())
132 bool successful = readValue();
134 skipCommentTokens(token);
135 if (collectComments_ && !commentsBefore_.empty())
137 if (features_.strictRoot_) {
138 if (!root.isArray() && !root.isObject()) {
141 token.type_ = tokenError;
142 token.start_ = beginDoc;
145 "A valid JSON document must be either an array or an object value.",
153 bool Reader::readValue() {
159 throwRuntimeError(
"Exceeded stackLimit in readValue().");
162 skipCommentTokens(token);
163 bool successful =
true;
165 if (collectComments_ && !commentsBefore_.empty()) {
167 commentsBefore_.clear();
170 switch (token.type_) {
171 case tokenObjectBegin:
172 successful = readObject(token);
173 currentValue().setOffsetLimit(current_ - begin_);
175 case tokenArrayBegin:
176 successful = readArray(token);
177 currentValue().setOffsetLimit(current_ - begin_);
180 successful = decodeNumber(token);
183 successful = decodeString(token);
187 currentValue().swapPayload(v);
188 currentValue().setOffsetStart(token.start_ - begin_);
189 currentValue().setOffsetLimit(token.end_ - begin_);
193 currentValue().swapPayload(v);
194 currentValue().setOffsetStart(token.start_ - begin_);
195 currentValue().setOffsetLimit(token.end_ - begin_);
199 currentValue().swapPayload(v);
200 currentValue().setOffsetStart(token.start_ - begin_);
201 currentValue().setOffsetLimit(token.end_ - begin_);
203 case tokenArraySeparator:
206 if (features_.allowDroppedNullPlaceholders_) {
211 currentValue().swapPayload(v);
212 currentValue().setOffsetStart(current_ - begin_ - 1);
213 currentValue().setOffsetLimit(current_ - begin_);
217 currentValue().setOffsetStart(token.start_ - begin_);
218 currentValue().setOffsetLimit(token.end_ - begin_);
219 return addError(
"Syntax error: value, object or array expected.", token);
222 if (collectComments_) {
223 lastValueEnd_ = current_;
224 lastValue_ = ¤tValue();
230 void Reader::skipCommentTokens(Token& token) {
231 if (features_.allowComments_) {
234 }
while (token.type_ == tokenComment);
240 bool Reader::readToken(Token& token) {
242 token.start_ = current_;
243 Char c = getNextChar();
247 token.type_ = tokenObjectBegin;
250 token.type_ = tokenObjectEnd;
253 token.type_ = tokenArrayBegin;
256 token.type_ = tokenArrayEnd;
259 token.type_ = tokenString;
263 token.type_ = tokenComment;
277 token.type_ = tokenNumber;
281 token.type_ = tokenTrue;
282 ok = match(
"rue", 3);
285 token.type_ = tokenFalse;
286 ok = match(
"alse", 4);
289 token.type_ = tokenNull;
290 ok = match(
"ull", 3);
293 token.type_ = tokenArraySeparator;
296 token.type_ = tokenMemberSeparator;
299 token.type_ = tokenEndOfStream;
306 token.type_ = tokenError;
307 token.end_ = current_;
311 void Reader::skipSpaces() {
312 while (current_ != end_) {
314 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n')
321 bool Reader::match(
const Char* pattern,
int patternLength) {
322 if (end_ - current_ < patternLength)
324 int index = patternLength;
326 if (current_[index] != pattern[index])
328 current_ += patternLength;
332 bool Reader::readComment() {
333 Location commentBegin = current_ - 1;
334 Char c = getNextChar();
335 bool successful =
false;
337 successful = readCStyleComment();
339 successful = readCppStyleComment();
343 if (collectComments_) {
345 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
346 if (c !=
'*' || !containsNewLine(commentBegin, current_))
350 addComment(commentBegin, current_, placement);
355 String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {
357 normalized.reserve(static_cast<size_t>(end - begin));
358 Reader::Location current = begin;
359 while (current != end) {
362 if (current != end && *current ==
'\n')
374 void Reader::addComment(Location begin, Location end,
376 assert(collectComments_);
377 const String& normalized = normalizeEOL(begin, end);
379 assert(lastValue_ !=
nullptr);
380 lastValue_->setComment(normalized, placement);
382 commentsBefore_ += normalized;
386 bool Reader::readCStyleComment() {
387 while ((current_ + 1) < end_) {
388 Char c = getNextChar();
389 if (c ==
'*' && *current_ ==
'/')
392 return getNextChar() ==
'/';
395 bool Reader::readCppStyleComment() {
396 while (current_ != end_) {
397 Char c = getNextChar();
402 if (current_ != end_ && *current_ ==
'\n')
411 void Reader::readNumber() {
412 Location p = current_;
415 while (c >=
'0' && c <=
'9')
416 c = (current_ = p) < end_ ? *p++ :
'\0';
419 c = (current_ = p) < end_ ? *p++ :
'\0';
420 while (c >=
'0' && c <=
'9')
421 c = (current_ = p) < end_ ? *p++ :
'\0';
424 if (c ==
'e' || c ==
'E') {
425 c = (current_ = p) < end_ ? *p++ :
'\0';
426 if (c ==
'+' || c ==
'-')
427 c = (current_ = p) < end_ ? *p++ :
'\0';
428 while (c >=
'0' && c <=
'9')
429 c = (current_ = p) < end_ ? *p++ :
'\0';
433 bool Reader::readString() {
435 while (current_ != end_) {
445 bool Reader::readObject(Token& token) {
449 currentValue().swapPayload(init);
450 currentValue().setOffsetStart(token.start_ - begin_);
451 while (readToken(tokenName)) {
452 bool initialTokenOk =
true;
453 while (tokenName.type_ == tokenComment && initialTokenOk)
454 initialTokenOk = readToken(tokenName);
457 if (tokenName.type_ == tokenObjectEnd && name.empty())
460 if (tokenName.type_ == tokenString) {
461 if (!decodeString(tokenName, name))
462 return recoverFromError(tokenObjectEnd);
463 }
else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
465 if (!decodeNumber(tokenName, numberName))
466 return recoverFromError(tokenObjectEnd);
467 name =
String(numberName.asCString());
473 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
474 return addErrorAndRecover(
"Missing ':' after object member name", colon,
477 Value& value = currentValue()[name];
479 bool ok = readValue();
482 return recoverFromError(tokenObjectEnd);
485 if (!readToken(comma) ||
486 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
487 comma.type_ != tokenComment)) {
488 return addErrorAndRecover(
"Missing ',' or '}' in object declaration",
489 comma, tokenObjectEnd);
491 bool finalizeTokenOk =
true;
492 while (comma.type_ == tokenComment && finalizeTokenOk)
493 finalizeTokenOk = readToken(comma);
494 if (comma.type_ == tokenObjectEnd)
497 return addErrorAndRecover(
"Missing '}' or object member name", tokenName,
501 bool Reader::readArray(Token& token) {
503 currentValue().swapPayload(init);
504 currentValue().setOffsetStart(token.start_ - begin_);
506 if (current_ != end_ && *current_ ==
']')
514 Value& value = currentValue()[index++];
516 bool ok = readValue();
519 return recoverFromError(tokenArrayEnd);
523 ok = readToken(currentToken);
524 while (currentToken.type_ == tokenComment && ok) {
525 ok = readToken(currentToken);
527 bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
528 currentToken.type_ != tokenArrayEnd);
529 if (!ok || badTokenType) {
530 return addErrorAndRecover(
"Missing ',' or ']' in array declaration",
531 currentToken, tokenArrayEnd);
533 if (currentToken.type_ == tokenArrayEnd)
539 bool Reader::decodeNumber(Token& token) {
541 if (!decodeNumber(token, decoded))
543 currentValue().swapPayload(decoded);
544 currentValue().setOffsetStart(token.start_ - begin_);
545 currentValue().setOffsetLimit(token.end_ - begin_);
549 bool Reader::decodeNumber(Token& token, Value& decoded) {
553 Location current = token.start_;
554 bool isNegative = *current ==
'-';
564 while (current < token.end_) {
566 if (c < '0' || c >
'9')
567 return decodeDouble(token, decoded);
568 auto digit(static_cast<Value::UInt>(c -
'0'));
569 if (value >= threshold) {
574 if (value > threshold || current != token.end_ ||
575 digit > maxIntegerValue % 10) {
576 return decodeDouble(token, decoded);
579 value = value * 10 + digit;
581 if (isNegative && value == maxIntegerValue)
592 bool Reader::decodeDouble(Token& token) {
594 if (!decodeDouble(token, decoded))
596 currentValue().swapPayload(decoded);
597 currentValue().setOffsetStart(token.start_ - begin_);
598 currentValue().setOffsetLimit(token.end_ - begin_);
602 bool Reader::decodeDouble(Token& token, Value& decoded) {
604 String buffer(token.start_, token.end_);
608 "'" +
String(token.start_, token.end_) +
"' is not a number.", token);
613 bool Reader::decodeString(Token& token) {
615 if (!decodeString(token, decoded_string))
617 Value decoded(decoded_string);
618 currentValue().swapPayload(decoded);
619 currentValue().setOffsetStart(token.start_ - begin_);
620 currentValue().setOffsetLimit(token.end_ - begin_);
624 bool Reader::decodeString(Token& token,
String& decoded) {
625 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
626 Location current = token.start_ + 1;
627 Location end = token.end_ - 1;
628 while (current != end) {
632 else if (c ==
'\\') {
634 return addError(
"Empty escape sequence in string", token, current);
635 Char escape = *current++;
662 unsigned int unicode;
663 if (!decodeUnicodeCodePoint(token, current, end, unicode))
668 return addError(
"Bad escape sequence in string", token, current);
677 bool Reader::decodeUnicodeCodePoint(Token& token, Location& current,
678 Location end,
unsigned int& unicode) {
680 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
682 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
684 if (end - current < 6)
686 "additional six characters expected to parse unicode surrogate pair.",
688 if (*(current++) ==
'\\' && *(current++) ==
'u') {
689 unsigned int surrogatePair;
690 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
691 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
695 return addError(
"expecting another \\u token to begin the second half of "
696 "a unicode surrogate pair",
702 bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current,
704 unsigned int& ret_unicode) {
705 if (end - current < 4)
707 "Bad unicode escape sequence in string: four digits expected.", token,
710 for (
int index = 0; index < 4; ++index) {
713 if (c >=
'0' && c <=
'9')
715 else if (c >=
'a' && c <=
'f')
716 unicode += c -
'a' + 10;
717 else if (c >=
'A' && c <=
'F')
718 unicode += c -
'A' + 10;
721 "Bad unicode escape sequence in string: hexadecimal digit expected.",
724 ret_unicode = static_cast<unsigned int>(unicode);
728 bool Reader::addError(
const String& message, Token& token, Location extra) {
731 info.message_ = message;
733 errors_.push_back(info);
737 bool Reader::recoverFromError(TokenType skipUntilToken) {
738 size_t const errorCount = errors_.size();
741 if (!readToken(skip))
742 errors_.resize(errorCount);
743 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
746 errors_.resize(errorCount);
750 bool Reader::addErrorAndRecover(
const String& message, Token& token,
751 TokenType skipUntilToken) {
752 addError(message, token);
753 return recoverFromError(skipUntilToken);
756 Value& Reader::currentValue() {
return *(nodes_.top()); }
758 Reader::Char Reader::getNextChar() {
759 if (current_ == end_)
764 void Reader::getLocationLineAndColumn(Location location,
int& line,
766 Location current = begin_;
767 Location lastLineStart = current;
769 while (current < location && current != end_) {
772 if (*current ==
'\n')
774 lastLineStart = current;
776 }
else if (c ==
'\n') {
777 lastLineStart = current;
782 column = int(location - lastLineStart) + 1;
786 String Reader::getLocationLineAndColumn(Location location)
const {
788 getLocationLineAndColumn(location, line, column);
789 char buffer[18 + 16 + 16 + 1];
790 jsoncpp_snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
795 String Reader::getFormatedErrorMessages()
const {
796 return getFormattedErrorMessages();
799 String Reader::getFormattedErrorMessages()
const {
801 for (
const auto& error : errors_) {
803 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
804 formattedMessage +=
" " + error.message_ +
"\n";
807 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
809 return formattedMessage;
812 std::vector<Reader::StructuredError> Reader::getStructuredErrors()
const {
813 std::vector<Reader::StructuredError> allErrors;
814 for (
const auto& error : errors_) {
815 Reader::StructuredError structured;
816 structured.offset_start = error.token_.start_ - begin_;
817 structured.offset_limit = error.token_.end_ - begin_;
818 structured.message = error.message_;
819 allErrors.push_back(structured);
824 bool Reader::pushError(
const Value& value,
const String& message) {
825 ptrdiff_t
const length = end_ - begin_;
826 if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
829 token.type_ = tokenError;
830 token.start_ = begin_ + value.getOffsetStart();
831 token.end_ = begin_ + value.getOffsetLimit();
834 info.message_ = message;
835 info.extra_ =
nullptr;
836 errors_.push_back(info);
840 bool Reader::pushError(
const Value& value,
const String& message,
841 const Value& extra) {
842 ptrdiff_t
const length = end_ - begin_;
843 if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
844 extra.getOffsetLimit() > length)
847 token.type_ = tokenError;
848 token.start_ = begin_ + value.getOffsetStart();
849 token.end_ = begin_ + value.getOffsetLimit();
852 info.message_ = message;
853 info.extra_ = begin_ + extra.getOffsetStart();
854 errors_.push_back(info);
858 bool Reader::good()
const {
return errors_.empty(); }
864 static OurFeatures all();
867 bool allowDroppedNullPlaceholders_;
868 bool allowNumericKeys_;
869 bool allowSingleQuotes_;
872 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 bool match(
const Char* pattern,
int patternLength);
943 bool readCStyleComment(
bool* containsNewLineResult);
944 bool readCppStyleComment();
946 bool readStringSingleQuote();
947 bool readNumber(
bool checkInf);
949 bool readObject(Token& token);
950 bool readArray(Token& token);
951 bool decodeNumber(Token& token);
952 bool decodeNumber(Token& token, Value& decoded);
953 bool decodeString(Token& token);
954 bool decodeString(Token& token,
String& decoded);
955 bool decodeDouble(Token& token);
956 bool decodeDouble(Token& token, Value& decoded);
957 bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
958 unsigned int& unicode);
959 bool decodeUnicodeEscapeSequence(Token& token, Location& current,
960 Location end,
unsigned int& unicode);
961 bool addError(
const String& message, Token& token, Location extra =
nullptr);
962 bool recoverFromError(TokenType skipUntilToken);
963 bool addErrorAndRecover(
const String& message, Token& token,
964 TokenType skipUntilToken);
965 void skipUntilSpace();
966 Value& currentValue();
968 void getLocationLineAndColumn(Location location,
int& line,
970 String getLocationLineAndColumn(Location location)
const;
972 void skipCommentTokens(Token& token);
974 static String normalizeEOL(Location begin, Location end);
975 static bool containsNewLine(Location begin, Location end);
977 using Nodes = std::stack<Value*>;
982 Location begin_ =
nullptr;
983 Location end_ =
nullptr;
984 Location current_ =
nullptr;
985 Location lastValueEnd_ =
nullptr;
986 Value* lastValue_ =
nullptr;
987 bool lastValueHasAComment_ =
false;
990 OurFeatures
const features_;
991 bool collectComments_ =
false;
996 bool OurReader::containsNewLine(OurReader::Location begin,
997 OurReader::Location end) {
998 for (; begin < end; ++begin)
999 if (*begin ==
'\n' || *begin ==
'\r')
1004 OurReader::OurReader(OurFeatures
const& features) : features_(features) {}
1006 bool OurReader::parse(
const char* beginDoc,
const char* endDoc, Value& root,
1007 bool collectComments) {
1008 if (!features_.allowComments_) {
1009 collectComments =
false;
1014 collectComments_ = collectComments;
1016 lastValueEnd_ =
nullptr;
1017 lastValue_ =
nullptr;
1018 commentsBefore_.clear();
1020 while (!nodes_.empty())
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 bool OurReader::match(
const Char* pattern,
int patternLength) {
1271 if (end_ - current_ < patternLength)
1273 int index = patternLength;
1275 if (current_[index] != pattern[index])
1277 current_ += patternLength;
1281 bool OurReader::readComment() {
1282 const Location commentBegin = current_ - 1;
1283 const Char c = getNextChar();
1284 bool successful =
false;
1285 bool cStyleWithEmbeddedNewline =
false;
1287 const bool isCStyleComment = (c ==
'*');
1288 const bool isCppStyleComment = (c ==
'/');
1289 if (isCStyleComment) {
1290 successful = readCStyleComment(&cStyleWithEmbeddedNewline);
1291 }
else if (isCppStyleComment) {
1292 successful = readCppStyleComment();
1298 if (collectComments_) {
1301 if (!lastValueHasAComment_) {
1302 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
1303 if (isCppStyleComment || !cStyleWithEmbeddedNewline) {
1305 lastValueHasAComment_ =
true;
1310 addComment(commentBegin, current_, placement);
1315 String OurReader::normalizeEOL(OurReader::Location begin,
1316 OurReader::Location end) {
1318 normalized.reserve(static_cast<size_t>(end - begin));
1319 OurReader::Location current = begin;
1320 while (current != end) {
1321 char c = *current++;
1323 if (current != end && *current ==
'\n')
1335 void OurReader::addComment(Location begin, Location end,
1337 assert(collectComments_);
1338 const String& normalized = normalizeEOL(begin, end);
1340 assert(lastValue_ !=
nullptr);
1341 lastValue_->setComment(normalized, placement);
1343 commentsBefore_ += normalized;
1347 bool OurReader::readCStyleComment(
bool* containsNewLineResult) {
1348 *containsNewLineResult =
false;
1350 while ((current_ + 1) < end_) {
1351 Char c = getNextChar();
1352 if (c ==
'*' && *current_ ==
'/') {
1354 }
else if (c ==
'\n') {
1355 *containsNewLineResult =
true;
1359 return getNextChar() ==
'/';
1362 bool OurReader::readCppStyleComment() {
1363 while (current_ != end_) {
1364 Char c = getNextChar();
1369 if (current_ != end_ && *current_ ==
'\n')
1378 bool OurReader::readNumber(
bool checkInf) {
1379 Location p = current_;
1380 if (checkInf && p != end_ && *p ==
'I') {
1386 while (c >=
'0' && c <=
'9')
1387 c = (current_ = p) < end_ ? *p++ :
'\0';
1390 c = (current_ = p) < end_ ? *p++ :
'\0';
1391 while (c >=
'0' && c <=
'9')
1392 c = (current_ = p) < end_ ? *p++ :
'\0';
1395 if (c ==
'e' || c ==
'E') {
1396 c = (current_ = p) < end_ ? *p++ :
'\0';
1397 if (c ==
'+' || c ==
'-')
1398 c = (current_ = p) < end_ ? *p++ :
'\0';
1399 while (c >=
'0' && c <=
'9')
1400 c = (current_ = p) < end_ ? *p++ :
'\0';
1404 bool OurReader::readString() {
1406 while (current_ != end_) {
1416 bool OurReader::readStringSingleQuote() {
1418 while (current_ != end_) {
1428 bool OurReader::readObject(Token& token) {
1432 currentValue().swapPayload(init);
1433 currentValue().setOffsetStart(token.start_ - begin_);
1434 while (readToken(tokenName)) {
1435 bool initialTokenOk =
true;
1436 while (tokenName.type_ == tokenComment && initialTokenOk)
1437 initialTokenOk = readToken(tokenName);
1438 if (!initialTokenOk)
1440 if (tokenName.type_ == tokenObjectEnd && name.empty())
1443 if (tokenName.type_ == tokenString) {
1444 if (!decodeString(tokenName, name))
1445 return recoverFromError(tokenObjectEnd);
1446 }
else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1448 if (!decodeNumber(tokenName, numberName))
1449 return recoverFromError(tokenObjectEnd);
1450 name = numberName.asString();
1454 if (name.length() >= (1U << 30))
1455 throwRuntimeError(
"keylength >= 2^30");
1456 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1457 String msg =
"Duplicate key: '" + name +
"'";
1458 return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
1462 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1463 return addErrorAndRecover(
"Missing ':' after object member name", colon,
1466 Value& value = currentValue()[name];
1467 nodes_.push(&value);
1468 bool ok = readValue();
1471 return recoverFromError(tokenObjectEnd);
1474 if (!readToken(comma) ||
1475 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1476 comma.type_ != tokenComment)) {
1477 return addErrorAndRecover(
"Missing ',' or '}' in object declaration",
1478 comma, tokenObjectEnd);
1480 bool finalizeTokenOk =
true;
1481 while (comma.type_ == tokenComment && finalizeTokenOk)
1482 finalizeTokenOk = readToken(comma);
1483 if (comma.type_ == tokenObjectEnd)
1486 return addErrorAndRecover(
"Missing '}' or object member name", tokenName,
1490 bool OurReader::readArray(Token& token) {
1492 currentValue().swapPayload(init);
1493 currentValue().setOffsetStart(token.start_ - begin_);
1495 if (current_ != end_ && *current_ ==
']')
1498 readToken(endArray);
1503 Value& value = currentValue()[index++];
1504 nodes_.push(&value);
1505 bool ok = readValue();
1508 return recoverFromError(tokenArrayEnd);
1512 ok = readToken(currentToken);
1513 while (currentToken.type_ == tokenComment && ok) {
1514 ok = readToken(currentToken);
1516 bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
1517 currentToken.type_ != tokenArrayEnd);
1518 if (!ok || badTokenType) {
1519 return addErrorAndRecover(
"Missing ',' or ']' in array declaration",
1520 currentToken, tokenArrayEnd);
1522 if (currentToken.type_ == tokenArrayEnd)
1528 bool OurReader::decodeNumber(Token& token) {
1530 if (!decodeNumber(token, decoded))
1532 currentValue().swapPayload(decoded);
1533 currentValue().setOffsetStart(token.start_ - begin_);
1534 currentValue().setOffsetLimit(token.end_ - begin_);
1538 bool OurReader::decodeNumber(Token& token, Value& decoded) {
1542 Location current = token.start_;
1543 const bool isNegative = *current ==
'-';
1552 "Int must be smaller than UInt");
1559 "The absolute value of minLargestInt must be greater than or "
1560 "equal to maxLargestInt");
1562 "The absolute value of minLargestInt must be only 1 magnitude "
1563 "larger than maxLargest Int");
1576 static constexpr
Value::UInt negative_last_digit =
1580 isNegative ? negative_threshold : positive_threshold;
1582 isNegative ? negative_last_digit : positive_last_digit;
1585 while (current < token.end_) {
1586 Char c = *current++;
1587 if (c < '0' || c >
'9')
1588 return decodeDouble(token, decoded);
1590 const Value::UInt digit(static_cast<Value::UInt>(c -
'0'));
1591 if (value >= threshold) {
1597 if (value > threshold || current != token.end_ ||
1598 digit > max_last_digit) {
1599 return decodeDouble(token, decoded);
1602 value = value * 10 + digit;
1607 const Value::UInt last_digit = static_cast<Value::UInt>(value % 10);
1618 bool OurReader::decodeDouble(Token& token) {
1620 if (!decodeDouble(token, decoded))
1622 currentValue().swapPayload(decoded);
1623 currentValue().setOffsetStart(token.start_ - begin_);
1624 currentValue().setOffsetLimit(token.end_ - begin_);
1628 bool OurReader::decodeDouble(Token& token, Value& decoded) {
1630 const String buffer(token.start_, token.end_);
1632 if (!(is >> value)) {
1634 "'" +
String(token.start_, token.end_) +
"' is not a number.", token);
1640 bool OurReader::decodeString(Token& token) {
1642 if (!decodeString(token, decoded_string))
1644 Value decoded(decoded_string);
1645 currentValue().swapPayload(decoded);
1646 currentValue().setOffsetStart(token.start_ - begin_);
1647 currentValue().setOffsetLimit(token.end_ - begin_);
1651 bool OurReader::decodeString(Token& token,
String& decoded) {
1652 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
1653 Location current = token.start_ + 1;
1654 Location end = token.end_ - 1;
1655 while (current != end) {
1656 Char c = *current++;
1659 }
else if (c ==
'\\') {
1661 return addError(
"Empty escape sequence in string", token, current);
1662 Char escape = *current++;
1689 unsigned int unicode;
1690 if (!decodeUnicodeCodePoint(token, current, end, unicode))
1695 return addError(
"Bad escape sequence in string", token, current);
1704 bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current,
1705 Location end,
unsigned int& unicode) {
1707 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1709 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1711 if (end - current < 6)
1713 "additional six characters expected to parse unicode surrogate pair.",
1715 if (*(current++) ==
'\\' && *(current++) ==
'u') {
1716 unsigned int surrogatePair;
1717 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1718 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1722 return addError(
"expecting another \\u token to begin the second half of "
1723 "a unicode surrogate pair",
1729 bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current,
1731 unsigned int& ret_unicode) {
1732 if (end - current < 4)
1734 "Bad unicode escape sequence in string: four digits expected.", token,
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.",
1751 ret_unicode = static_cast<unsigned int>(unicode);
1755 bool OurReader::addError(
const String& message, Token& token, Location extra) {
1757 info.token_ = token;
1758 info.message_ = message;
1759 info.extra_ = extra;
1760 errors_.push_back(info);
1764 bool OurReader::recoverFromError(TokenType skipUntilToken) {
1765 size_t errorCount = errors_.size();
1768 if (!readToken(skip))
1769 errors_.resize(errorCount);
1770 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
1773 errors_.resize(errorCount);
1777 bool OurReader::addErrorAndRecover(
const String& message, Token& token,
1778 TokenType skipUntilToken) {
1779 addError(message, token);
1780 return recoverFromError(skipUntilToken);
1783 Value& OurReader::currentValue() {
return *(nodes_.top()); }
1785 OurReader::Char OurReader::getNextChar() {
1786 if (current_ == end_)
1791 void OurReader::getLocationLineAndColumn(Location location,
int& line,
1792 int& column)
const {
1793 Location current = begin_;
1794 Location lastLineStart = current;
1796 while (current < location && current != end_) {
1797 Char c = *current++;
1799 if (*current ==
'\n')
1801 lastLineStart = current;
1803 }
else if (c ==
'\n') {
1804 lastLineStart = current;
1809 column = int(location - lastLineStart) + 1;
1813 String OurReader::getLocationLineAndColumn(Location location)
const {
1815 getLocationLineAndColumn(location, line, column);
1816 char buffer[18 + 16 + 16 + 1];
1817 jsoncpp_snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
1821 String OurReader::getFormattedErrorMessages()
const {
1823 for (
const auto& error : errors_) {
1825 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
1826 formattedMessage +=
" " + error.message_ +
"\n";
1829 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
1831 return formattedMessage;
1834 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors()
const {
1835 std::vector<OurReader::StructuredError> allErrors;
1836 for (
const auto& error : errors_) {
1837 OurReader::StructuredError structured;
1838 structured.offset_start = error.token_.start_ - begin_;
1839 structured.offset_limit = error.token_.end_ - begin_;
1840 structured.message = error.message_;
1841 allErrors.push_back(structured);
1846 class OurCharReader :
public CharReader {
1847 bool const collectComments_;
1851 OurCharReader(
bool collectComments, OurFeatures
const& features)
1852 : collectComments_(collectComments), reader_(features) {}
1853 bool parse(
char const* beginDoc,
char const* endDoc, Value* root,
1855 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1857 *errs = reader_.getFormattedErrorMessages();
1867 OurFeatures features = OurFeatures::all();
1870 features.allowDroppedNullPlaceholders_ =
1873 features.allowSingleQuotes_ =
settings_[
"allowSingleQuotes"].
asBool();
1877 features.stackLimit_ = static_cast<size_t>(
settings_[
"stackLimit"].asUInt());
1880 features.allowSpecialFloats_ =
settings_[
"allowSpecialFloats"].
asBool();
1881 return new OurCharReader(collectComments, features);
1884 valid_keys->clear();
1885 valid_keys->insert(
"collectComments");
1886 valid_keys->insert(
"allowComments");
1887 valid_keys->insert(
"strictRoot");
1888 valid_keys->insert(
"allowDroppedNullPlaceholders");
1889 valid_keys->insert(
"allowNumericKeys");
1890 valid_keys->insert(
"allowSingleQuotes");
1891 valid_keys->insert(
"stackLimit");
1892 valid_keys->insert(
"failIfExtra");
1893 valid_keys->insert(
"rejectDupKeys");
1894 valid_keys->insert(
"allowSpecialFloats");
1899 invalid = &my_invalid;
1901 std::set<String> valid_keys;
1904 size_t n = keys.size();
1905 for (
size_t i = 0; i < n; ++i) {
1906 String const& key = keys[i];
1907 if (valid_keys.find(key) == valid_keys.end()) {
1919 (*settings)[
"allowComments"] =
false;
1920 (*settings)[
"strictRoot"] =
true;
1921 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1922 (*settings)[
"allowNumericKeys"] =
false;
1923 (*settings)[
"allowSingleQuotes"] =
false;
1924 (*settings)[
"stackLimit"] = 1000;
1925 (*settings)[
"failIfExtra"] =
true;
1926 (*settings)[
"rejectDupKeys"] =
true;
1927 (*settings)[
"allowSpecialFloats"] =
false;
1933 (*settings)[
"collectComments"] =
true;
1934 (*settings)[
"allowComments"] =
true;
1935 (*settings)[
"strictRoot"] =
false;
1936 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1937 (*settings)[
"allowNumericKeys"] =
false;
1938 (*settings)[
"allowSingleQuotes"] =
false;
1939 (*settings)[
"stackLimit"] = 1000;
1940 (*settings)[
"failIfExtra"] =
false;
1941 (*settings)[
"rejectDupKeys"] =
false;
1942 (*settings)[
"allowSpecialFloats"] =
false;
1952 ssin << sin.rdbuf();
1954 char const* begin = doc.data();
1955 char const* end = begin + doc.size();
1958 return reader->parse(begin, end, root, errs);
1966 throwRuntimeError(errs);