6 #if !defined(JSON_IS_AMALGAMATION)
11 #endif // if !defined(JSON_IS_AMALGAMATION)
21 #if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
22 #define snprintf _snprintf
25 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
27 #pragma warning(disable : 4996)
35 #if __cplusplus >= 201103L
45 : allowComments_(true), strictRoot_(false)
60 for (; begin < end; ++begin)
61 if (*begin ==
'\n' || *begin ==
'\r')
70 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
71 lastValue_(), commentsBefore_(), features_(
Features::all()),
75 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
76 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
82 const char* begin = document_.c_str();
83 const char* end = begin + document_.length();
84 return parse(begin, end, root, collectComments);
96 std::getline(sin, doc, (
char)EOF);
97 return parse(doc, root, collectComments);
103 bool collectComments) {
105 collectComments =
false;
110 collectComments_ = collectComments;
114 commentsBefore_ =
"";
116 while (!nodes_.empty())
121 bool successful = readValue();
123 skipCommentTokens(token);
124 if (collectComments_ && !commentsBefore_.empty())
130 token.type_ = tokenError;
131 token.start_ = beginDoc;
134 "A valid JSON document must be either an array or an object value.",
142 bool Reader::readValue() {
151 skipCommentTokens(token);
152 bool successful =
true;
154 if (collectComments_ && !commentsBefore_.empty()) {
156 commentsBefore_ =
"";
159 switch (token.type_) {
160 case tokenObjectBegin:
161 successful = readObject(token);
163 case tokenArrayBegin:
164 successful = readArray(token);
167 successful = decodeNumber(token);
170 successful = decodeString(token);
192 return addError(
"Syntax error: value, object or array expected.", token);
195 if (collectComments_) {
196 lastValueEnd_ = current_;
197 lastValue_ = ¤tValue();
204 void Reader::skipCommentTokens(Token& token) {
208 }
while (token.type_ == tokenComment);
214 bool Reader::readToken(Token& token) {
216 token.start_ = current_;
217 Char c = getNextChar();
221 token.type_ = tokenObjectBegin;
224 token.type_ = tokenObjectEnd;
227 token.type_ = tokenArrayBegin;
230 token.type_ = tokenArrayEnd;
233 token.type_ = tokenString;
237 token.type_ = tokenComment;
251 token.type_ = tokenNumber;
255 token.type_ = tokenTrue;
256 ok = match(
"rue", 3);
259 token.type_ = tokenFalse;
260 ok = match(
"alse", 4);
263 token.type_ = tokenNull;
264 ok = match(
"ull", 3);
267 token.type_ = tokenArraySeparator;
270 token.type_ = tokenMemberSeparator;
273 token.type_ = tokenEndOfStream;
280 token.type_ = tokenError;
281 token.end_ = current_;
285 void Reader::skipSpaces() {
286 while (current_ != end_) {
288 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n')
295 bool Reader::match(Location pattern,
int patternLength) {
296 if (end_ - current_ < patternLength)
298 int index = patternLength;
300 if (current_[index] != pattern[index])
302 current_ += patternLength;
306 bool Reader::readComment() {
307 Location commentBegin = current_ - 1;
308 Char c = getNextChar();
309 bool successful =
false;
311 successful = readCStyleComment();
313 successful = readCppStyleComment();
317 if (collectComments_) {
324 addComment(commentBegin, current_, placement);
330 std::string normalized;
331 normalized.reserve(end - begin);
333 while (current != end) {
336 if (current != end && *current ==
'\n')
349 Reader::addComment(Location begin, Location end,
CommentPlacement placement) {
350 assert(collectComments_);
351 const std::string& normalized =
normalizeEOL(begin, end);
353 assert(lastValue_ != 0);
354 lastValue_->
setComment(normalized, placement);
356 commentsBefore_ += normalized;
360 bool Reader::readCStyleComment() {
361 while (current_ != end_) {
362 Char c = getNextChar();
363 if (c ==
'*' && *current_ ==
'/')
366 return getNextChar() ==
'/';
369 bool Reader::readCppStyleComment() {
370 while (current_ != end_) {
371 Char c = getNextChar();
376 if (current_ != end_ && *current_ ==
'\n')
385 void Reader::readNumber() {
386 const char *p = current_;
389 while (c >=
'0' && c <=
'9')
390 c = (current_ = p) < end_ ? *p++ : 0;
393 c = (current_ = p) < end_ ? *p++ : 0;
394 while (c >=
'0' && c <=
'9')
395 c = (current_ = p) < end_ ? *p++ : 0;
398 if (c ==
'e' || c ==
'E') {
399 c = (current_ = p) < end_ ? *p++ : 0;
400 if (c ==
'+' || c ==
'-')
401 c = (current_ = p) < end_ ? *p++ : 0;
402 while (c >=
'0' && c <=
'9')
403 c = (current_ = p) < end_ ? *p++ : 0;
407 bool Reader::readString() {
409 while (current_ != end_) {
419 bool Reader::readObject(Token& ) {
424 while (readToken(tokenName)) {
425 bool initialTokenOk =
true;
426 while (tokenName.type_ == tokenComment && initialTokenOk)
427 initialTokenOk = readToken(tokenName);
430 if (tokenName.type_ == tokenObjectEnd && name.empty())
433 if (tokenName.type_ == tokenString) {
434 if (!decodeString(tokenName, name))
435 return recoverFromError(tokenObjectEnd);
441 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
442 return addErrorAndRecover(
443 "Missing ':' after object member name", colon, tokenObjectEnd);
445 Value& value = currentValue()[name];
447 bool ok = readValue();
450 return recoverFromError(tokenObjectEnd);
453 if (!readToken(comma) ||
454 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
455 comma.type_ != tokenComment)) {
456 return addErrorAndRecover(
457 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
459 bool finalizeTokenOk =
true;
460 while (comma.type_ == tokenComment && finalizeTokenOk)
461 finalizeTokenOk = readToken(comma);
462 if (comma.type_ == tokenObjectEnd)
465 return addErrorAndRecover(
466 "Missing '}' or object member name", tokenName, tokenObjectEnd);
469 bool Reader::readArray(Token& ) {
473 if (*current_ ==
']')
481 Value& value = currentValue()[index++];
483 bool ok = readValue();
486 return recoverFromError(tokenArrayEnd);
490 ok = readToken(token);
491 while (token.type_ == tokenComment && ok) {
492 ok = readToken(token);
495 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
496 if (!ok || badTokenType) {
497 return addErrorAndRecover(
498 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
500 if (token.type_ == tokenArrayEnd)
506 bool Reader::decodeNumber(Token& token) {
508 if (!decodeNumber(token, decoded))
514 bool Reader::decodeNumber(Token& token, Value& decoded) {
519 bool isNegative = *current ==
'-';
525 : Value::maxLargestUInt;
526 Value::LargestUInt threshold = maxIntegerValue / 10;
527 Value::LargestUInt value = 0;
528 while (current < token.end_) {
530 if (c < '0' || c >
'9')
531 return decodeDouble(token, decoded);
533 if (value >= threshold) {
538 if (value > threshold || current != token.end_ ||
539 digit > maxIntegerValue % 10) {
540 return decodeDouble(token, decoded);
543 value = value * 10 + digit;
554 bool Reader::decodeDouble(Token& token) {
556 if (!decodeDouble(token, decoded))
562 bool Reader::decodeDouble(Token& token, Value& decoded) {
565 std::string buffer( token.start_, token.end_ );
566 std::istringstream is(buffer);
569 return addError(
"'" + std::string(token.start_, token.end_) +
570 "' is not a number.",
576 bool Reader::decodeString(Token& token) {
577 std::string decoded_string;
578 if (!decodeString(token, decoded_string))
580 Value decoded(decoded_string);
585 bool Reader::decodeString(Token& token, std::string& decoded) {
586 decoded.reserve(token.end_ - token.start_ - 2);
587 Location current = token.start_ + 1;
589 while (current != end) {
593 else if (c ==
'\\') {
595 return addError(
"Empty escape sequence in string", token, current);
596 Char escape = *current++;
623 unsigned int unicode;
624 if (!decodeUnicodeCodePoint(token, current, end, unicode))
629 return addError(
"Bad escape sequence in string", token, current);
638 bool Reader::decodeUnicodeCodePoint(Token& token,
641 unsigned int& unicode) {
643 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
645 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
647 if (end - current < 6)
649 "additional six characters expected to parse unicode surrogate pair.",
652 unsigned int surrogatePair;
653 if (*(current++) ==
'\\' && *(current++) ==
'u') {
654 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
655 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
659 return addError(
"expecting another \\u token to begin the second half of "
660 "a unicode surrogate pair",
667 bool Reader::decodeUnicodeEscapeSequence(Token& token,
670 unsigned int& unicode) {
671 if (end - current < 4)
673 "Bad unicode escape sequence in string: four digits expected.",
677 for (
int index = 0; index < 4; ++index) {
680 if (c >=
'0' && c <=
'9')
682 else if (c >=
'a' && c <=
'f')
683 unicode += c -
'a' + 10;
684 else if (c >=
'A' && c <=
'F')
685 unicode += c -
'A' + 10;
688 "Bad unicode escape sequence in string: hexadecimal digit expected.",
696 Reader::addError(
const std::string& message, Token& token, Location extra) {
699 info.message_ = message;
701 errors_.push_back(info);
705 bool Reader::recoverFromError(TokenType skipUntilToken) {
706 int errorCount = int(errors_.size());
709 if (!readToken(skip))
710 errors_.resize(errorCount);
711 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
714 errors_.resize(errorCount);
718 bool Reader::addErrorAndRecover(
const std::string& message,
720 TokenType skipUntilToken) {
721 addError(message, token);
722 return recoverFromError(skipUntilToken);
725 Value& Reader::currentValue() {
return *(nodes_.top()); }
728 if (current_ == end_)
733 void Reader::getLocationLineAndColumn(Location location,
739 while (current < location && current != end_) {
742 if (*current ==
'\n')
744 lastLineStart = current;
746 }
else if (c ==
'\n') {
747 lastLineStart = current;
752 column = int(location - lastLineStart) + 1;
756 std::string Reader::getLocationLineAndColumn(Location location)
const {
758 getLocationLineAndColumn(location, line, column);
759 char buffer[18 + 16 + 16 + 1];
760 #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
762 _snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
764 sprintf_s(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
767 snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
778 std::string formattedMessage;
779 for (Errors::const_iterator itError = errors_.begin();
780 itError != errors_.end();
782 const ErrorInfo& error = *itError;
784 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
785 formattedMessage +=
" " + error.message_ +
"\n";
788 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
790 return formattedMessage;
799 static OurFeatures all();
803 bool allowDroppedNullPlaceholders_;
804 bool allowNumericKeys_;
805 bool allowSingleQuotes_;
814 OurFeatures::OurFeatures()
815 : allowComments_(true), strictRoot_(false)
816 , allowDroppedNullPlaceholders_(false), allowNumericKeys_(false)
817 , allowSingleQuotes_(false)
818 , failIfExtra_(false)
822 OurFeatures OurFeatures::all() {
return OurFeatures(); }
831 typedef const Char* Location;
832 struct StructuredError {
838 OurReader(OurFeatures
const& features);
839 bool parse(
const char* beginDoc,
842 bool collectComments =
true);
843 std::string getFormattedErrorMessages()
const;
846 OurReader(OurReader
const&);
847 void operator=(OurReader
const&);
850 tokenEndOfStream = 0,
861 tokenMemberSeparator,
876 std::string message_;
880 typedef std::deque<ErrorInfo> Errors;
882 bool readToken(Token& token);
884 bool match(Location pattern,
int patternLength);
886 bool readCStyleComment();
887 bool readCppStyleComment();
889 bool readStringSingleQuote();
892 bool readObject(Token& token);
893 bool readArray(Token& token);
894 bool decodeNumber(Token& token);
895 bool decodeNumber(Token& token, Value& decoded);
896 bool decodeString(Token& token);
897 bool decodeString(Token& token, std::string& decoded);
898 bool decodeDouble(Token& token);
899 bool decodeDouble(Token& token, Value& decoded);
900 bool decodeUnicodeCodePoint(Token& token,
903 unsigned int& unicode);
904 bool decodeUnicodeEscapeSequence(Token& token,
907 unsigned int& unicode);
908 bool addError(
const std::string& message, Token& token, Location extra = 0);
909 bool recoverFromError(TokenType skipUntilToken);
910 bool addErrorAndRecover(
const std::string& message,
912 TokenType skipUntilToken);
913 void skipUntilSpace();
914 Value& currentValue();
917 getLocationLineAndColumn(Location location,
int& line,
int& column)
const;
918 std::string getLocationLineAndColumn(Location location)
const;
920 void skipCommentTokens(Token& token);
922 typedef std::stack<Value*> Nodes;
925 std::string document_;
929 Location lastValueEnd_;
931 std::string commentsBefore_;
934 OurFeatures
const features_;
935 bool collectComments_;
940 OurReader::OurReader(OurFeatures
const& features)
941 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
942 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
945 bool OurReader::parse(
const char* beginDoc,
948 bool collectComments) {
949 if (!features_.allowComments_) {
950 collectComments =
false;
955 collectComments_ = collectComments;
959 commentsBefore_ =
"";
961 while (!nodes_.empty())
966 bool successful = readValue();
968 skipCommentTokens(token);
969 if (features_.failIfExtra_) {
970 if (token.type_ != tokenError && token.type_ != tokenEndOfStream) {
971 addError(
"Extra non-whitespace after JSON value.", token);
975 if (collectComments_ && !commentsBefore_.empty())
977 if (features_.strictRoot_) {
978 if (!root.isArray() && !root.isObject()) {
981 token.type_ = tokenError;
982 token.start_ = beginDoc;
985 "A valid JSON document must be either an array or an object value.",
993 bool OurReader::readValue() {
994 if (stackDepth_ >= features_.stackLimit_)
throwRuntimeError(
"Exceeded stackLimit in readValue().");
997 skipCommentTokens(token);
998 bool successful =
true;
1000 if (collectComments_ && !commentsBefore_.empty()) {
1002 commentsBefore_ =
"";
1005 switch (token.type_) {
1006 case tokenObjectBegin:
1007 successful = readObject(token);
1009 case tokenArrayBegin:
1010 successful = readArray(token);
1013 successful = decodeNumber(token);
1016 successful = decodeString(token);
1021 currentValue().swapPayload(v);
1027 currentValue().swapPayload(v);
1033 currentValue().swapPayload(v);
1036 case tokenArraySeparator:
1037 case tokenObjectEnd:
1039 if (features_.allowDroppedNullPlaceholders_) {
1044 currentValue().swapPayload(v);
1048 return addError(
"Syntax error: value, object or array expected.", token);
1051 if (collectComments_) {
1052 lastValueEnd_ = current_;
1053 lastValue_ = ¤tValue();
1060 void OurReader::skipCommentTokens(Token& token) {
1061 if (features_.allowComments_) {
1064 }
while (token.type_ == tokenComment);
1070 bool OurReader::readToken(Token& token) {
1072 token.start_ = current_;
1073 Char c = getNextChar();
1077 token.type_ = tokenObjectBegin;
1080 token.type_ = tokenObjectEnd;
1083 token.type_ = tokenArrayBegin;
1086 token.type_ = tokenArrayEnd;
1089 token.type_ = tokenString;
1093 if (features_.allowSingleQuotes_) {
1094 token.type_ = tokenString;
1095 ok = readStringSingleQuote();
1099 token.type_ = tokenComment;
1113 token.type_ = tokenNumber;
1117 token.type_ = tokenTrue;
1118 ok = match(
"rue", 3);
1121 token.type_ = tokenFalse;
1122 ok = match(
"alse", 4);
1125 token.type_ = tokenNull;
1126 ok = match(
"ull", 3);
1129 token.type_ = tokenArraySeparator;
1132 token.type_ = tokenMemberSeparator;
1135 token.type_ = tokenEndOfStream;
1142 token.type_ = tokenError;
1143 token.end_ = current_;
1147 void OurReader::skipSpaces() {
1148 while (current_ != end_) {
1150 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n')
1157 bool OurReader::match(Location pattern,
int patternLength) {
1158 if (end_ - current_ < patternLength)
1160 int index = patternLength;
1162 if (current_[index] != pattern[index])
1164 current_ += patternLength;
1168 bool OurReader::readComment() {
1169 Location commentBegin = current_ - 1;
1170 Char c = getNextChar();
1171 bool successful =
false;
1173 successful = readCStyleComment();
1175 successful = readCppStyleComment();
1179 if (collectComments_) {
1186 addComment(commentBegin, current_, placement);
1192 OurReader::addComment(Location begin, Location end,
CommentPlacement placement) {
1193 assert(collectComments_);
1194 const std::string& normalized =
normalizeEOL(begin, end);
1196 assert(lastValue_ != 0);
1197 lastValue_->setComment(normalized, placement);
1199 commentsBefore_ += normalized;
1203 bool OurReader::readCStyleComment() {
1204 while (current_ != end_) {
1205 Char c = getNextChar();
1206 if (c ==
'*' && *current_ ==
'/')
1209 return getNextChar() ==
'/';
1212 bool OurReader::readCppStyleComment() {
1213 while (current_ != end_) {
1214 Char c = getNextChar();
1219 if (current_ != end_ && *current_ ==
'\n')
1228 void OurReader::readNumber() {
1229 const char *p = current_;
1232 while (c >=
'0' && c <=
'9')
1233 c = (current_ = p) < end_ ? *p++ : 0;
1236 c = (current_ = p) < end_ ? *p++ : 0;
1237 while (c >=
'0' && c <=
'9')
1238 c = (current_ = p) < end_ ? *p++ : 0;
1241 if (c ==
'e' || c ==
'E') {
1242 c = (current_ = p) < end_ ? *p++ : 0;
1243 if (c ==
'+' || c ==
'-')
1244 c = (current_ = p) < end_ ? *p++ : 0;
1245 while (c >=
'0' && c <=
'9')
1246 c = (current_ = p) < end_ ? *p++ : 0;
1249 bool OurReader::readString() {
1251 while (current_ != end_) {
1262 bool OurReader::readStringSingleQuote() {
1264 while (current_ != end_) {
1274 bool OurReader::readObject(Token& tokenStart) {
1278 currentValue().swapPayload(init);
1279 while (readToken(tokenName)) {
1280 bool initialTokenOk =
true;
1281 while (tokenName.type_ == tokenComment && initialTokenOk)
1282 initialTokenOk = readToken(tokenName);
1283 if (!initialTokenOk)
1285 if (tokenName.type_ == tokenObjectEnd && name.empty())
1288 if (tokenName.type_ == tokenString) {
1289 if (!decodeString(tokenName, name))
1290 return recoverFromError(tokenObjectEnd);
1291 }
else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1293 if (!decodeNumber(tokenName, numberName))
1294 return recoverFromError(tokenObjectEnd);
1295 name = numberName.asString();
1301 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1302 return addErrorAndRecover(
1303 "Missing ':' after object member name", colon, tokenObjectEnd);
1306 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1307 std::string msg =
"Duplicate key: '" + name +
"'";
1308 return addErrorAndRecover(
1309 msg, tokenName, tokenObjectEnd);
1311 Value& value = currentValue()[name];
1312 nodes_.push(&value);
1313 bool ok = readValue();
1316 return recoverFromError(tokenObjectEnd);
1319 if (!readToken(comma) ||
1320 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1321 comma.type_ != tokenComment)) {
1322 return addErrorAndRecover(
1323 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
1325 bool finalizeTokenOk =
true;
1326 while (comma.type_ == tokenComment && finalizeTokenOk)
1327 finalizeTokenOk = readToken(comma);
1328 if (comma.type_ == tokenObjectEnd)
1331 return addErrorAndRecover(
1332 "Missing '}' or object member name", tokenName, tokenObjectEnd);
1335 bool OurReader::readArray(Token& tokenStart) {
1337 currentValue().swapPayload(init);
1339 if (*current_ ==
']')
1342 readToken(endArray);
1347 Value& value = currentValue()[index++];
1348 nodes_.push(&value);
1349 bool ok = readValue();
1352 return recoverFromError(tokenArrayEnd);
1356 ok = readToken(token);
1357 while (token.type_ == tokenComment && ok) {
1358 ok = readToken(token);
1361 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
1362 if (!ok || badTokenType) {
1363 return addErrorAndRecover(
1364 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
1366 if (token.type_ == tokenArrayEnd)
1372 bool OurReader::decodeNumber(Token& token) {
1374 if (!decodeNumber(token, decoded))
1376 currentValue().swapPayload(decoded);
1380 bool OurReader::decodeNumber(Token& token, Value& decoded) {
1384 Location current = token.start_;
1385 bool isNegative = *current ==
'-';
1389 Value::LargestUInt maxIntegerValue =
1391 : Value::maxLargestUInt;
1392 Value::LargestUInt threshold = maxIntegerValue / 10;
1393 Value::LargestUInt value = 0;
1394 while (current < token.end_) {
1395 Char c = *current++;
1396 if (c < '0' || c >
'9')
1397 return decodeDouble(token, decoded);
1399 if (value >= threshold) {
1404 if (value > threshold || current != token.end_ ||
1405 digit > maxIntegerValue % 10) {
1406 return decodeDouble(token, decoded);
1409 value = value * 10 + digit;
1420 bool OurReader::decodeDouble(Token& token) {
1422 if (!decodeDouble(token, decoded))
1424 currentValue().swapPayload(decoded);
1428 bool OurReader::decodeDouble(Token& token, Value& decoded) {
1430 const int bufferSize = 32;
1432 int length = int(token.end_ - token.start_);
1436 return addError(
"Unable to parse token length", token);
1444 char format[] =
"%lf";
1446 if (length <= bufferSize) {
1447 Char buffer[bufferSize + 1];
1448 memcpy(buffer, token.start_, length);
1450 count = sscanf(buffer, format, &value);
1452 std::string buffer(token.start_, token.end_);
1453 count = sscanf(buffer.c_str(), format, &value);
1457 return addError(
"'" + std::string(token.start_, token.end_) +
1458 "' is not a number.",
1464 bool OurReader::decodeString(Token& token) {
1465 std::string decoded_string;
1466 if (!decodeString(token, decoded_string))
1468 Value decoded(decoded_string);
1469 currentValue().swapPayload(decoded);
1473 bool OurReader::decodeString(Token& token, std::string& decoded) {
1474 decoded.reserve(token.end_ - token.start_ - 2);
1475 Location current = token.start_ + 1;
1476 Location end = token.end_ - 1;
1477 while (current != end) {
1478 Char c = *current++;
1481 else if (c ==
'\\') {
1483 return addError(
"Empty escape sequence in string", token, current);
1484 Char escape = *current++;
1511 unsigned int unicode;
1512 if (!decodeUnicodeCodePoint(token, current, end, unicode))
1517 return addError(
"Bad escape sequence in string", token, current);
1526 bool OurReader::decodeUnicodeCodePoint(Token& token,
1529 unsigned int& unicode) {
1531 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1533 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1535 if (end - current < 6)
1537 "additional six characters expected to parse unicode surrogate pair.",
1540 unsigned int surrogatePair;
1541 if (*(current++) ==
'\\' && *(current++) ==
'u') {
1542 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1543 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1547 return addError(
"expecting another \\u token to begin the second half of "
1548 "a unicode surrogate pair",
1555 bool OurReader::decodeUnicodeEscapeSequence(Token& token,
1558 unsigned int& unicode) {
1559 if (end - current < 4)
1561 "Bad unicode escape sequence in string: four digits expected.",
1565 for (
int index = 0; index < 4; ++index) {
1566 Char c = *current++;
1568 if (c >=
'0' && c <=
'9')
1570 else if (c >=
'a' && c <=
'f')
1571 unicode += c -
'a' + 10;
1572 else if (c >=
'A' && c <=
'F')
1573 unicode += c -
'A' + 10;
1576 "Bad unicode escape sequence in string: hexadecimal digit expected.",
1584 OurReader::addError(
const std::string& message, Token& token, Location extra) {
1586 info.token_ = token;
1587 info.message_ = message;
1588 info.extra_ = extra;
1589 errors_.push_back(info);
1593 bool OurReader::recoverFromError(TokenType skipUntilToken) {
1594 int errorCount = int(errors_.size());
1597 if (!readToken(skip))
1598 errors_.resize(errorCount);
1599 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
1602 errors_.resize(errorCount);
1606 bool OurReader::addErrorAndRecover(
const std::string& message,
1608 TokenType skipUntilToken) {
1609 addError(message, token);
1610 return recoverFromError(skipUntilToken);
1613 Value& OurReader::currentValue() {
return *(nodes_.top()); }
1615 OurReader::Char OurReader::getNextChar() {
1616 if (current_ == end_)
1621 void OurReader::getLocationLineAndColumn(Location location,
1623 int& column)
const {
1624 Location current = begin_;
1625 Location lastLineStart = current;
1627 while (current < location && current != end_) {
1628 Char c = *current++;
1630 if (*current ==
'\n')
1632 lastLineStart = current;
1634 }
else if (c ==
'\n') {
1635 lastLineStart = current;
1640 column = int(location - lastLineStart) + 1;
1644 std::string OurReader::getLocationLineAndColumn(Location location)
const {
1646 getLocationLineAndColumn(location, line, column);
1647 char buffer[18 + 16 + 16 + 1];
1648 #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
1650 _snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
1652 sprintf_s(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
1655 snprintf(buffer,
sizeof(buffer),
"Line %d, Column %d", line, column);
1660 std::string OurReader::getFormattedErrorMessages()
const {
1661 std::string formattedMessage;
1662 for (Errors::const_iterator itError = errors_.begin();
1663 itError != errors_.end();
1665 const ErrorInfo& error = *itError;
1667 "* " + getLocationLineAndColumn(error.token_.start_) +
"\n";
1668 formattedMessage +=
" " + error.message_ +
"\n";
1671 "See " + getLocationLineAndColumn(error.extra_) +
" for detail.\n";
1673 return formattedMessage;
1677 class OurCharReader :
public CharReader {
1678 bool const collectComments_;
1682 bool collectComments,
1683 OurFeatures
const& features)
1684 : collectComments_(collectComments)
1688 char const* beginDoc,
char const* endDoc,
1689 Value* root, std::string* errs) {
1690 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1692 *errs = reader_.getFormattedErrorMessages();
1707 OurFeatures features = OurFeatures::all();
1710 features.allowDroppedNullPlaceholders_ =
settings_[
"allowDroppedNullPlaceholders"].
asBool();
1712 features.allowSingleQuotes_ =
settings_[
"allowSingleQuotes"].
asBool();
1716 return new OurCharReader(collectComments, features);
1720 valid_keys->clear();
1721 valid_keys->insert(
"collectComments");
1722 valid_keys->insert(
"allowComments");
1723 valid_keys->insert(
"strictRoot");
1724 valid_keys->insert(
"allowDroppedNullPlaceholders");
1725 valid_keys->insert(
"allowNumericKeys");
1726 valid_keys->insert(
"allowSingleQuotes");
1727 valid_keys->insert(
"stackLimit");
1728 valid_keys->insert(
"failIfExtra");
1729 valid_keys->insert(
"rejectDupKeys");
1734 if (!invalid) invalid = &my_invalid;
1736 std::set<std::string> valid_keys;
1739 size_t n = keys.size();
1740 for (
size_t i = 0; i < n; ++i) {
1741 std::string
const& key = keys[i];
1742 if (valid_keys.find(key) == valid_keys.end()) {
1746 return 0u == inv.
size();
1756 (*settings)[
"allowComments"] =
false;
1757 (*settings)[
"strictRoot"] =
true;
1758 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1759 (*settings)[
"allowNumericKeys"] =
false;
1760 (*settings)[
"allowSingleQuotes"] =
false;
1761 (*settings)[
"failIfExtra"] =
true;
1762 (*settings)[
"rejectDupKeys"] =
true;
1769 (*settings)[
"collectComments"] =
true;
1770 (*settings)[
"allowComments"] =
true;
1771 (*settings)[
"strictRoot"] =
false;
1772 (*settings)[
"allowDroppedNullPlaceholders"] =
false;
1773 (*settings)[
"allowNumericKeys"] =
false;
1774 (*settings)[
"allowSingleQuotes"] =
false;
1775 (*settings)[
"stackLimit"] = 1000;
1776 (*settings)[
"failIfExtra"] =
false;
1777 (*settings)[
"rejectDupKeys"] =
false;
1786 Value* root, std::string* errs)
1788 std::ostringstream ssin;
1789 ssin << sin.rdbuf();
1790 std::string doc = ssin.str();
1791 char const* begin = doc.data();
1792 char const* end = begin + doc.size();
1795 return reader->parse(begin, end, root, errs);
1804 "Error from reader: %s",