00001
00002
00003
00004
00005
00006 #if !defined(JSON_IS_AMALGAMATION)
00007 #include <json/assertions.h>
00008 #include <json/reader.h>
00009 #include <json/value.h>
00010 #include "json_tool.h"
00011 #endif // if !defined(JSON_IS_AMALGAMATION)
00012 #include <utility>
00013 #include <cstdio>
00014 #include <cassert>
00015 #include <cstring>
00016 #include <istream>
00017 #include <sstream>
00018 #include <memory>
00019 #include <set>
00020
00021 #if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
00022 #define snprintf _snprintf
00023 #endif
00024
00025 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
00026
00027 #pragma warning(disable : 4996)
00028 #endif
00029
00030 static int const stackLimit_g = 1000;
00031 static int stackDepth_g = 0;
00032
00033 namespace Json {
00034
00035 #if __cplusplus >= 201103L
00036 typedef std::unique_ptr<CharReader> CharReaderPtr;
00037 #else
00038 typedef std::auto_ptr<CharReader> CharReaderPtr;
00039 #endif
00040
00041
00042
00043
00044 Features::Features()
00045 : allowComments_(true), strictRoot_(false)
00046 {}
00047 Features Features::all() { return Features(); }
00048
00049 Features Features::strictMode() {
00050 Features features;
00051 features.allowComments_ = false;
00052 features.strictRoot_ = true;
00053 return features;
00054 }
00055
00056
00057
00058
00059 static bool containsNewLine(Reader::Location begin, Reader::Location end) {
00060 for (; begin < end; ++begin)
00061 if (*begin == '\n' || *begin == '\r')
00062 return true;
00063 return false;
00064 }
00065
00066
00067
00068
00069 Reader::Reader()
00070 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
00071 lastValue_(), commentsBefore_(), features_(Features::all()),
00072 collectComments_() {}
00073
00074 Reader::Reader(const Features& features)
00075 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
00076 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
00077 }
00078
00079 bool
00080 Reader::parse(const std::string& document, Value& root, bool collectComments) {
00081 document_ = document;
00082 const char* begin = document_.c_str();
00083 const char* end = begin + document_.length();
00084 return parse(begin, end, root, collectComments);
00085 }
00086
00087 bool Reader::parse(std::istream& sin, Value& root, bool collectComments) {
00088
00089
00090
00091
00092
00093
00094
00095 std::string doc;
00096 std::getline(sin, doc, (char)EOF);
00097 return parse(doc, root, collectComments);
00098 }
00099
00100 bool Reader::parse(const char* beginDoc,
00101 const char* endDoc,
00102 Value& root,
00103 bool collectComments) {
00104 if (!features_.allowComments_) {
00105 collectComments = false;
00106 }
00107
00108 begin_ = beginDoc;
00109 end_ = endDoc;
00110 collectComments_ = collectComments;
00111 current_ = begin_;
00112 lastValueEnd_ = 0;
00113 lastValue_ = 0;
00114 commentsBefore_ = "";
00115 errors_.clear();
00116 while (!nodes_.empty())
00117 nodes_.pop();
00118 nodes_.push(&root);
00119
00120 stackDepth_g = 0;
00121 bool successful = readValue();
00122 Token token;
00123 skipCommentTokens(token);
00124 if (collectComments_ && !commentsBefore_.empty())
00125 root.setComment(commentsBefore_, commentAfter);
00126 if (features_.strictRoot_) {
00127 if (!root.isArray() && !root.isObject()) {
00128
00129
00130 token.type_ = tokenError;
00131 token.start_ = beginDoc;
00132 token.end_ = endDoc;
00133 addError(
00134 "A valid JSON document must be either an array or an object value.",
00135 token);
00136 return false;
00137 }
00138 }
00139 return successful;
00140 }
00141
00142 bool Reader::readValue() {
00143
00144
00145
00146
00147 if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
00148 ++stackDepth_g;
00149
00150 Token token;
00151 skipCommentTokens(token);
00152 bool successful = true;
00153
00154 if (collectComments_ && !commentsBefore_.empty()) {
00155 currentValue().setComment(commentsBefore_, commentBefore);
00156 commentsBefore_ = "";
00157 }
00158
00159 switch (token.type_) {
00160 case tokenObjectBegin:
00161 successful = readObject(token);
00162 break;
00163 case tokenArrayBegin:
00164 successful = readArray(token);
00165 break;
00166 case tokenNumber:
00167 successful = decodeNumber(token);
00168 break;
00169 case tokenString:
00170 successful = decodeString(token);
00171 break;
00172 case tokenTrue:
00173 {
00174 Value v(true);
00175 currentValue().swapPayload(v);
00176 }
00177 break;
00178 case tokenFalse:
00179 {
00180 Value v(false);
00181 currentValue().swapPayload(v);
00182 }
00183 break;
00184 case tokenNull:
00185 {
00186 Value v;
00187 currentValue().swapPayload(v);
00188 }
00189 break;
00190
00191 default:
00192 return addError("Syntax error: value, object or array expected.", token);
00193 }
00194
00195 if (collectComments_) {
00196 lastValueEnd_ = current_;
00197 lastValue_ = ¤tValue();
00198 }
00199
00200 --stackDepth_g;
00201 return successful;
00202 }
00203
00204 void Reader::skipCommentTokens(Token& token) {
00205 if (features_.allowComments_) {
00206 do {
00207 readToken(token);
00208 } while (token.type_ == tokenComment);
00209 } else {
00210 readToken(token);
00211 }
00212 }
00213
00214 bool Reader::readToken(Token& token) {
00215 skipSpaces();
00216 token.start_ = current_;
00217 Char c = getNextChar();
00218 bool ok = true;
00219 switch (c) {
00220 case '{':
00221 token.type_ = tokenObjectBegin;
00222 break;
00223 case '}':
00224 token.type_ = tokenObjectEnd;
00225 break;
00226 case '[':
00227 token.type_ = tokenArrayBegin;
00228 break;
00229 case ']':
00230 token.type_ = tokenArrayEnd;
00231 break;
00232 case '"':
00233 token.type_ = tokenString;
00234 ok = readString();
00235 break;
00236 case '/':
00237 token.type_ = tokenComment;
00238 ok = readComment();
00239 break;
00240 case '0':
00241 case '1':
00242 case '2':
00243 case '3':
00244 case '4':
00245 case '5':
00246 case '6':
00247 case '7':
00248 case '8':
00249 case '9':
00250 case '-':
00251 token.type_ = tokenNumber;
00252 readNumber();
00253 break;
00254 case 't':
00255 token.type_ = tokenTrue;
00256 ok = match("rue", 3);
00257 break;
00258 case 'f':
00259 token.type_ = tokenFalse;
00260 ok = match("alse", 4);
00261 break;
00262 case 'n':
00263 token.type_ = tokenNull;
00264 ok = match("ull", 3);
00265 break;
00266 case ',':
00267 token.type_ = tokenArraySeparator;
00268 break;
00269 case ':':
00270 token.type_ = tokenMemberSeparator;
00271 break;
00272 case 0:
00273 token.type_ = tokenEndOfStream;
00274 break;
00275 default:
00276 ok = false;
00277 break;
00278 }
00279 if (!ok)
00280 token.type_ = tokenError;
00281 token.end_ = current_;
00282 return true;
00283 }
00284
00285 void Reader::skipSpaces() {
00286 while (current_ != end_) {
00287 Char c = *current_;
00288 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
00289 ++current_;
00290 else
00291 break;
00292 }
00293 }
00294
00295 bool Reader::match(Location pattern, int patternLength) {
00296 if (end_ - current_ < patternLength)
00297 return false;
00298 int index = patternLength;
00299 while (index--)
00300 if (current_[index] != pattern[index])
00301 return false;
00302 current_ += patternLength;
00303 return true;
00304 }
00305
00306 bool Reader::readComment() {
00307 Location commentBegin = current_ - 1;
00308 Char c = getNextChar();
00309 bool successful = false;
00310 if (c == '*')
00311 successful = readCStyleComment();
00312 else if (c == '/')
00313 successful = readCppStyleComment();
00314 if (!successful)
00315 return false;
00316
00317 if (collectComments_) {
00318 CommentPlacement placement = commentBefore;
00319 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
00320 if (c != '*' || !containsNewLine(commentBegin, current_))
00321 placement = commentAfterOnSameLine;
00322 }
00323
00324 addComment(commentBegin, current_, placement);
00325 }
00326 return true;
00327 }
00328
00329 static std::string normalizeEOL(Reader::Location begin, Reader::Location end) {
00330 std::string normalized;
00331 normalized.reserve(end - begin);
00332 Reader::Location current = begin;
00333 while (current != end) {
00334 char c = *current++;
00335 if (c == '\r') {
00336 if (current != end && *current == '\n')
00337
00338 ++current;
00339
00340 normalized += '\n';
00341 } else {
00342 normalized += c;
00343 }
00344 }
00345 return normalized;
00346 }
00347
00348 void
00349 Reader::addComment(Location begin, Location end, CommentPlacement placement) {
00350 assert(collectComments_);
00351 const std::string& normalized = normalizeEOL(begin, end);
00352 if (placement == commentAfterOnSameLine) {
00353 assert(lastValue_ != 0);
00354 lastValue_->setComment(normalized, placement);
00355 } else {
00356 commentsBefore_ += normalized;
00357 }
00358 }
00359
00360 bool Reader::readCStyleComment() {
00361 while (current_ != end_) {
00362 Char c = getNextChar();
00363 if (c == '*' && *current_ == '/')
00364 break;
00365 }
00366 return getNextChar() == '/';
00367 }
00368
00369 bool Reader::readCppStyleComment() {
00370 while (current_ != end_) {
00371 Char c = getNextChar();
00372 if (c == '\n')
00373 break;
00374 if (c == '\r') {
00375
00376 if (current_ != end_ && *current_ == '\n')
00377 getNextChar();
00378
00379 break;
00380 }
00381 }
00382 return true;
00383 }
00384
00385 void Reader::readNumber() {
00386 const char *p = current_;
00387 char c = '0';
00388
00389 while (c >= '0' && c <= '9')
00390 c = (current_ = p) < end_ ? *p++ : 0;
00391
00392 if (c == '.') {
00393 c = (current_ = p) < end_ ? *p++ : 0;
00394 while (c >= '0' && c <= '9')
00395 c = (current_ = p) < end_ ? *p++ : 0;
00396 }
00397
00398 if (c == 'e' || c == 'E') {
00399 c = (current_ = p) < end_ ? *p++ : 0;
00400 if (c == '+' || c == '-')
00401 c = (current_ = p) < end_ ? *p++ : 0;
00402 while (c >= '0' && c <= '9')
00403 c = (current_ = p) < end_ ? *p++ : 0;
00404 }
00405 }
00406
00407 bool Reader::readString() {
00408 Char c = 0;
00409 while (current_ != end_) {
00410 c = getNextChar();
00411 if (c == '\\')
00412 getNextChar();
00413 else if (c == '"')
00414 break;
00415 }
00416 return c == '"';
00417 }
00418
00419 bool Reader::readObject(Token& ) {
00420 Token tokenName;
00421 std::string name;
00422 Value init(objectValue);
00423 currentValue().swapPayload(init);
00424 while (readToken(tokenName)) {
00425 bool initialTokenOk = true;
00426 while (tokenName.type_ == tokenComment && initialTokenOk)
00427 initialTokenOk = readToken(tokenName);
00428 if (!initialTokenOk)
00429 break;
00430 if (tokenName.type_ == tokenObjectEnd && name.empty())
00431 return true;
00432 name = "";
00433 if (tokenName.type_ == tokenString) {
00434 if (!decodeString(tokenName, name))
00435 return recoverFromError(tokenObjectEnd);
00436 } else {
00437 break;
00438 }
00439
00440 Token colon;
00441 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
00442 return addErrorAndRecover(
00443 "Missing ':' after object member name", colon, tokenObjectEnd);
00444 }
00445 Value& value = currentValue()[name];
00446 nodes_.push(&value);
00447 bool ok = readValue();
00448 nodes_.pop();
00449 if (!ok)
00450 return recoverFromError(tokenObjectEnd);
00451
00452 Token comma;
00453 if (!readToken(comma) ||
00454 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
00455 comma.type_ != tokenComment)) {
00456 return addErrorAndRecover(
00457 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
00458 }
00459 bool finalizeTokenOk = true;
00460 while (comma.type_ == tokenComment && finalizeTokenOk)
00461 finalizeTokenOk = readToken(comma);
00462 if (comma.type_ == tokenObjectEnd)
00463 return true;
00464 }
00465 return addErrorAndRecover(
00466 "Missing '}' or object member name", tokenName, tokenObjectEnd);
00467 }
00468
00469 bool Reader::readArray(Token& ) {
00470 Value init(arrayValue);
00471 currentValue().swapPayload(init);
00472 skipSpaces();
00473 if (*current_ == ']')
00474 {
00475 Token endArray;
00476 readToken(endArray);
00477 return true;
00478 }
00479 int index = 0;
00480 for (;;) {
00481 Value& value = currentValue()[index++];
00482 nodes_.push(&value);
00483 bool ok = readValue();
00484 nodes_.pop();
00485 if (!ok)
00486 return recoverFromError(tokenArrayEnd);
00487
00488 Token token;
00489
00490 ok = readToken(token);
00491 while (token.type_ == tokenComment && ok) {
00492 ok = readToken(token);
00493 }
00494 bool badTokenType =
00495 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
00496 if (!ok || badTokenType) {
00497 return addErrorAndRecover(
00498 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
00499 }
00500 if (token.type_ == tokenArrayEnd)
00501 break;
00502 }
00503 return true;
00504 }
00505
00506 bool Reader::decodeNumber(Token& token) {
00507 Value decoded;
00508 if (!decodeNumber(token, decoded))
00509 return false;
00510 currentValue().swapPayload(decoded);
00511 return true;
00512 }
00513
00514 bool Reader::decodeNumber(Token& token, Value& decoded) {
00515
00516
00517
00518 Location current = token.start_;
00519 bool isNegative = *current == '-';
00520 if (isNegative)
00521 ++current;
00522
00523 Value::LargestUInt maxIntegerValue =
00524 isNegative ? Value::LargestUInt(-Value::minLargestInt)
00525 : Value::maxLargestUInt;
00526 Value::LargestUInt threshold = maxIntegerValue / 10;
00527 Value::LargestUInt value = 0;
00528 while (current < token.end_) {
00529 Char c = *current++;
00530 if (c < '0' || c > '9')
00531 return decodeDouble(token, decoded);
00532 Value::UInt digit(c - '0');
00533 if (value >= threshold) {
00534
00535
00536
00537
00538 if (value > threshold || current != token.end_ ||
00539 digit > maxIntegerValue % 10) {
00540 return decodeDouble(token, decoded);
00541 }
00542 }
00543 value = value * 10 + digit;
00544 }
00545 if (isNegative)
00546 decoded = -Value::LargestInt(value);
00547 else if (value <= Value::LargestUInt(Value::maxInt))
00548 decoded = Value::LargestInt(value);
00549 else
00550 decoded = value;
00551 return true;
00552 }
00553
00554 bool Reader::decodeDouble(Token& token) {
00555 Value decoded;
00556 if (!decodeDouble(token, decoded))
00557 return false;
00558 currentValue().swapPayload(decoded);
00559 return true;
00560 }
00561
00562 bool Reader::decodeDouble(Token& token, Value& decoded) {
00563 double value = 0;
00564
00565 std::string buffer( token.start_, token.end_ );
00566 std::istringstream is(buffer);
00567
00568 if (!(is >> value))
00569 return addError("'" + std::string(token.start_, token.end_) +
00570 "' is not a number.",
00571 token);
00572 decoded = value;
00573 return true;
00574 }
00575
00576 bool Reader::decodeString(Token& token) {
00577 std::string decoded_string;
00578 if (!decodeString(token, decoded_string))
00579 return false;
00580 Value decoded(decoded_string);
00581 currentValue().swapPayload(decoded);
00582 return true;
00583 }
00584
00585 bool Reader::decodeString(Token& token, std::string& decoded) {
00586 decoded.reserve(token.end_ - token.start_ - 2);
00587 Location current = token.start_ + 1;
00588 Location end = token.end_ - 1;
00589 while (current != end) {
00590 Char c = *current++;
00591 if (c == '"')
00592 break;
00593 else if (c == '\\') {
00594 if (current == end)
00595 return addError("Empty escape sequence in string", token, current);
00596 Char escape = *current++;
00597 switch (escape) {
00598 case '"':
00599 decoded += '"';
00600 break;
00601 case '/':
00602 decoded += '/';
00603 break;
00604 case '\\':
00605 decoded += '\\';
00606 break;
00607 case 'b':
00608 decoded += '\b';
00609 break;
00610 case 'f':
00611 decoded += '\f';
00612 break;
00613 case 'n':
00614 decoded += '\n';
00615 break;
00616 case 'r':
00617 decoded += '\r';
00618 break;
00619 case 't':
00620 decoded += '\t';
00621 break;
00622 case 'u': {
00623 unsigned int unicode;
00624 if (!decodeUnicodeCodePoint(token, current, end, unicode))
00625 return false;
00626 decoded += codePointToUTF8(unicode);
00627 } break;
00628 default:
00629 return addError("Bad escape sequence in string", token, current);
00630 }
00631 } else {
00632 decoded += c;
00633 }
00634 }
00635 return true;
00636 }
00637
00638 bool Reader::decodeUnicodeCodePoint(Token& token,
00639 Location& current,
00640 Location end,
00641 unsigned int& unicode) {
00642
00643 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
00644 return false;
00645 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
00646
00647 if (end - current < 6)
00648 return addError(
00649 "additional six characters expected to parse unicode surrogate pair.",
00650 token,
00651 current);
00652 unsigned int surrogatePair;
00653 if (*(current++) == '\\' && *(current++) == 'u') {
00654 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
00655 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
00656 } else
00657 return false;
00658 } else
00659 return addError("expecting another \\u token to begin the second half of "
00660 "a unicode surrogate pair",
00661 token,
00662 current);
00663 }
00664 return true;
00665 }
00666
00667 bool Reader::decodeUnicodeEscapeSequence(Token& token,
00668 Location& current,
00669 Location end,
00670 unsigned int& unicode) {
00671 if (end - current < 4)
00672 return addError(
00673 "Bad unicode escape sequence in string: four digits expected.",
00674 token,
00675 current);
00676 unicode = 0;
00677 for (int index = 0; index < 4; ++index) {
00678 Char c = *current++;
00679 unicode *= 16;
00680 if (c >= '0' && c <= '9')
00681 unicode += c - '0';
00682 else if (c >= 'a' && c <= 'f')
00683 unicode += c - 'a' + 10;
00684 else if (c >= 'A' && c <= 'F')
00685 unicode += c - 'A' + 10;
00686 else
00687 return addError(
00688 "Bad unicode escape sequence in string: hexadecimal digit expected.",
00689 token,
00690 current);
00691 }
00692 return true;
00693 }
00694
00695 bool
00696 Reader::addError(const std::string& message, Token& token, Location extra) {
00697 ErrorInfo info;
00698 info.token_ = token;
00699 info.message_ = message;
00700 info.extra_ = extra;
00701 errors_.push_back(info);
00702 return false;
00703 }
00704
00705 bool Reader::recoverFromError(TokenType skipUntilToken) {
00706 int errorCount = int(errors_.size());
00707 Token skip;
00708 for (;;) {
00709 if (!readToken(skip))
00710 errors_.resize(errorCount);
00711 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
00712 break;
00713 }
00714 errors_.resize(errorCount);
00715 return false;
00716 }
00717
00718 bool Reader::addErrorAndRecover(const std::string& message,
00719 Token& token,
00720 TokenType skipUntilToken) {
00721 addError(message, token);
00722 return recoverFromError(skipUntilToken);
00723 }
00724
00725 Value& Reader::currentValue() { return *(nodes_.top()); }
00726
00727 Reader::Char Reader::getNextChar() {
00728 if (current_ == end_)
00729 return 0;
00730 return *current_++;
00731 }
00732
00733 void Reader::getLocationLineAndColumn(Location location,
00734 int& line,
00735 int& column) const {
00736 Location current = begin_;
00737 Location lastLineStart = current;
00738 line = 0;
00739 while (current < location && current != end_) {
00740 Char c = *current++;
00741 if (c == '\r') {
00742 if (*current == '\n')
00743 ++current;
00744 lastLineStart = current;
00745 ++line;
00746 } else if (c == '\n') {
00747 lastLineStart = current;
00748 ++line;
00749 }
00750 }
00751
00752 column = int(location - lastLineStart) + 1;
00753 ++line;
00754 }
00755
00756 std::string Reader::getLocationLineAndColumn(Location location) const {
00757 int line, column;
00758 getLocationLineAndColumn(location, line, column);
00759 char buffer[18 + 16 + 16 + 1];
00760 #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
00761 #if defined(WINCE)
00762 _snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
00763 #else
00764 sprintf_s(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
00765 #endif
00766 #else
00767 snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
00768 #endif
00769 return buffer;
00770 }
00771
00772
00773 std::string Reader::getFormatedErrorMessages() const {
00774 return getFormattedErrorMessages();
00775 }
00776
00777 std::string Reader::getFormattedErrorMessages() const {
00778 std::string formattedMessage;
00779 for (Errors::const_iterator itError = errors_.begin();
00780 itError != errors_.end();
00781 ++itError) {
00782 const ErrorInfo& error = *itError;
00783 formattedMessage +=
00784 "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
00785 formattedMessage += " " + error.message_ + "\n";
00786 if (error.extra_)
00787 formattedMessage +=
00788 "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
00789 }
00790 return formattedMessage;
00791 }
00792
00793
00795
00796
00797 class OurFeatures {
00798 public:
00799 static OurFeatures all();
00800 OurFeatures();
00801 bool allowComments_;
00802 bool strictRoot_;
00803 bool allowDroppedNullPlaceholders_;
00804 bool allowNumericKeys_;
00805 bool allowSingleQuotes_;
00806 bool failIfExtra_;
00807 bool rejectDupKeys_;
00808 int stackLimit_;
00809 };
00810
00811
00812
00813
00814 OurFeatures::OurFeatures()
00815 : allowComments_(true), strictRoot_(false)
00816 , allowDroppedNullPlaceholders_(false), allowNumericKeys_(false)
00817 , allowSingleQuotes_(false)
00818 , failIfExtra_(false)
00819 {
00820 }
00821
00822 OurFeatures OurFeatures::all() { return OurFeatures(); }
00823
00824
00825
00826
00827
00828 class OurReader {
00829 public:
00830 typedef char Char;
00831 typedef const Char* Location;
00832 struct StructuredError {
00833 size_t offset_start;
00834 size_t offset_limit;
00835 std::string message;
00836 };
00837
00838 OurReader(OurFeatures const& features);
00839 bool parse(const char* beginDoc,
00840 const char* endDoc,
00841 Value& root,
00842 bool collectComments = true);
00843 std::string getFormattedErrorMessages() const;
00844
00845 private:
00846 OurReader(OurReader const&);
00847 void operator=(OurReader const&);
00848
00849 enum TokenType {
00850 tokenEndOfStream = 0,
00851 tokenObjectBegin,
00852 tokenObjectEnd,
00853 tokenArrayBegin,
00854 tokenArrayEnd,
00855 tokenString,
00856 tokenNumber,
00857 tokenTrue,
00858 tokenFalse,
00859 tokenNull,
00860 tokenArraySeparator,
00861 tokenMemberSeparator,
00862 tokenComment,
00863 tokenError
00864 };
00865
00866 class Token {
00867 public:
00868 TokenType type_;
00869 Location start_;
00870 Location end_;
00871 };
00872
00873 class ErrorInfo {
00874 public:
00875 Token token_;
00876 std::string message_;
00877 Location extra_;
00878 };
00879
00880 typedef std::deque<ErrorInfo> Errors;
00881
00882 bool readToken(Token& token);
00883 void skipSpaces();
00884 bool match(Location pattern, int patternLength);
00885 bool readComment();
00886 bool readCStyleComment();
00887 bool readCppStyleComment();
00888 bool readString();
00889 bool readStringSingleQuote();
00890 void readNumber();
00891 bool readValue();
00892 bool readObject(Token& token);
00893 bool readArray(Token& token);
00894 bool decodeNumber(Token& token);
00895 bool decodeNumber(Token& token, Value& decoded);
00896 bool decodeString(Token& token);
00897 bool decodeString(Token& token, std::string& decoded);
00898 bool decodeDouble(Token& token);
00899 bool decodeDouble(Token& token, Value& decoded);
00900 bool decodeUnicodeCodePoint(Token& token,
00901 Location& current,
00902 Location end,
00903 unsigned int& unicode);
00904 bool decodeUnicodeEscapeSequence(Token& token,
00905 Location& current,
00906 Location end,
00907 unsigned int& unicode);
00908 bool addError(const std::string& message, Token& token, Location extra = 0);
00909 bool recoverFromError(TokenType skipUntilToken);
00910 bool addErrorAndRecover(const std::string& message,
00911 Token& token,
00912 TokenType skipUntilToken);
00913 void skipUntilSpace();
00914 Value& currentValue();
00915 Char getNextChar();
00916 void
00917 getLocationLineAndColumn(Location location, int& line, int& column) const;
00918 std::string getLocationLineAndColumn(Location location) const;
00919 void addComment(Location begin, Location end, CommentPlacement placement);
00920 void skipCommentTokens(Token& token);
00921
00922 typedef std::stack<Value*> Nodes;
00923 Nodes nodes_;
00924 Errors errors_;
00925 std::string document_;
00926 Location begin_;
00927 Location end_;
00928 Location current_;
00929 Location lastValueEnd_;
00930 Value* lastValue_;
00931 std::string commentsBefore_;
00932 int stackDepth_;
00933
00934 OurFeatures const features_;
00935 bool collectComments_;
00936 };
00937
00938
00939
00940 OurReader::OurReader(OurFeatures const& features)
00941 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
00942 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
00943 }
00944
00945 bool OurReader::parse(const char* beginDoc,
00946 const char* endDoc,
00947 Value& root,
00948 bool collectComments) {
00949 if (!features_.allowComments_) {
00950 collectComments = false;
00951 }
00952
00953 begin_ = beginDoc;
00954 end_ = endDoc;
00955 collectComments_ = collectComments;
00956 current_ = begin_;
00957 lastValueEnd_ = 0;
00958 lastValue_ = 0;
00959 commentsBefore_ = "";
00960 errors_.clear();
00961 while (!nodes_.empty())
00962 nodes_.pop();
00963 nodes_.push(&root);
00964
00965 stackDepth_ = 0;
00966 bool successful = readValue();
00967 Token token;
00968 skipCommentTokens(token);
00969 if (features_.failIfExtra_) {
00970 if (token.type_ != tokenError && token.type_ != tokenEndOfStream) {
00971 addError("Extra non-whitespace after JSON value.", token);
00972 return false;
00973 }
00974 }
00975 if (collectComments_ && !commentsBefore_.empty())
00976 root.setComment(commentsBefore_, commentAfter);
00977 if (features_.strictRoot_) {
00978 if (!root.isArray() && !root.isObject()) {
00979
00980
00981 token.type_ = tokenError;
00982 token.start_ = beginDoc;
00983 token.end_ = endDoc;
00984 addError(
00985 "A valid JSON document must be either an array or an object value.",
00986 token);
00987 return false;
00988 }
00989 }
00990 return successful;
00991 }
00992
00993 bool OurReader::readValue() {
00994 if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");
00995 ++stackDepth_;
00996 Token token;
00997 skipCommentTokens(token);
00998 bool successful = true;
00999
01000 if (collectComments_ && !commentsBefore_.empty()) {
01001 currentValue().setComment(commentsBefore_, commentBefore);
01002 commentsBefore_ = "";
01003 }
01004
01005 switch (token.type_) {
01006 case tokenObjectBegin:
01007 successful = readObject(token);
01008 break;
01009 case tokenArrayBegin:
01010 successful = readArray(token);
01011 break;
01012 case tokenNumber:
01013 successful = decodeNumber(token);
01014 break;
01015 case tokenString:
01016 successful = decodeString(token);
01017 break;
01018 case tokenTrue:
01019 {
01020 Value v(true);
01021 currentValue().swapPayload(v);
01022 }
01023 break;
01024 case tokenFalse:
01025 {
01026 Value v(false);
01027 currentValue().swapPayload(v);
01028 }
01029 break;
01030 case tokenNull:
01031 {
01032 Value v;
01033 currentValue().swapPayload(v);
01034 }
01035 break;
01036 case tokenArraySeparator:
01037 case tokenObjectEnd:
01038 case tokenArrayEnd:
01039 if (features_.allowDroppedNullPlaceholders_) {
01040
01041
01042 current_--;
01043 Value v;
01044 currentValue().swapPayload(v);
01045 break;
01046 }
01047 default:
01048 return addError("Syntax error: value, object or array expected.", token);
01049 }
01050
01051 if (collectComments_) {
01052 lastValueEnd_ = current_;
01053 lastValue_ = ¤tValue();
01054 }
01055
01056 --stackDepth_;
01057 return successful;
01058 }
01059
01060 void OurReader::skipCommentTokens(Token& token) {
01061 if (features_.allowComments_) {
01062 do {
01063 readToken(token);
01064 } while (token.type_ == tokenComment);
01065 } else {
01066 readToken(token);
01067 }
01068 }
01069
01070 bool OurReader::readToken(Token& token) {
01071 skipSpaces();
01072 token.start_ = current_;
01073 Char c = getNextChar();
01074 bool ok = true;
01075 switch (c) {
01076 case '{':
01077 token.type_ = tokenObjectBegin;
01078 break;
01079 case '}':
01080 token.type_ = tokenObjectEnd;
01081 break;
01082 case '[':
01083 token.type_ = tokenArrayBegin;
01084 break;
01085 case ']':
01086 token.type_ = tokenArrayEnd;
01087 break;
01088 case '"':
01089 token.type_ = tokenString;
01090 ok = readString();
01091 break;
01092 case '\'':
01093 if (features_.allowSingleQuotes_) {
01094 token.type_ = tokenString;
01095 ok = readStringSingleQuote();
01096 break;
01097 }
01098 case '/':
01099 token.type_ = tokenComment;
01100 ok = readComment();
01101 break;
01102 case '0':
01103 case '1':
01104 case '2':
01105 case '3':
01106 case '4':
01107 case '5':
01108 case '6':
01109 case '7':
01110 case '8':
01111 case '9':
01112 case '-':
01113 token.type_ = tokenNumber;
01114 readNumber();
01115 break;
01116 case 't':
01117 token.type_ = tokenTrue;
01118 ok = match("rue", 3);
01119 break;
01120 case 'f':
01121 token.type_ = tokenFalse;
01122 ok = match("alse", 4);
01123 break;
01124 case 'n':
01125 token.type_ = tokenNull;
01126 ok = match("ull", 3);
01127 break;
01128 case ',':
01129 token.type_ = tokenArraySeparator;
01130 break;
01131 case ':':
01132 token.type_ = tokenMemberSeparator;
01133 break;
01134 case 0:
01135 token.type_ = tokenEndOfStream;
01136 break;
01137 default:
01138 ok = false;
01139 break;
01140 }
01141 if (!ok)
01142 token.type_ = tokenError;
01143 token.end_ = current_;
01144 return true;
01145 }
01146
01147 void OurReader::skipSpaces() {
01148 while (current_ != end_) {
01149 Char c = *current_;
01150 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
01151 ++current_;
01152 else
01153 break;
01154 }
01155 }
01156
01157 bool OurReader::match(Location pattern, int patternLength) {
01158 if (end_ - current_ < patternLength)
01159 return false;
01160 int index = patternLength;
01161 while (index--)
01162 if (current_[index] != pattern[index])
01163 return false;
01164 current_ += patternLength;
01165 return true;
01166 }
01167
01168 bool OurReader::readComment() {
01169 Location commentBegin = current_ - 1;
01170 Char c = getNextChar();
01171 bool successful = false;
01172 if (c == '*')
01173 successful = readCStyleComment();
01174 else if (c == '/')
01175 successful = readCppStyleComment();
01176 if (!successful)
01177 return false;
01178
01179 if (collectComments_) {
01180 CommentPlacement placement = commentBefore;
01181 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
01182 if (c != '*' || !containsNewLine(commentBegin, current_))
01183 placement = commentAfterOnSameLine;
01184 }
01185
01186 addComment(commentBegin, current_, placement);
01187 }
01188 return true;
01189 }
01190
01191 void
01192 OurReader::addComment(Location begin, Location end, CommentPlacement placement) {
01193 assert(collectComments_);
01194 const std::string& normalized = normalizeEOL(begin, end);
01195 if (placement == commentAfterOnSameLine) {
01196 assert(lastValue_ != 0);
01197 lastValue_->setComment(normalized, placement);
01198 } else {
01199 commentsBefore_ += normalized;
01200 }
01201 }
01202
01203 bool OurReader::readCStyleComment() {
01204 while (current_ != end_) {
01205 Char c = getNextChar();
01206 if (c == '*' && *current_ == '/')
01207 break;
01208 }
01209 return getNextChar() == '/';
01210 }
01211
01212 bool OurReader::readCppStyleComment() {
01213 while (current_ != end_) {
01214 Char c = getNextChar();
01215 if (c == '\n')
01216 break;
01217 if (c == '\r') {
01218
01219 if (current_ != end_ && *current_ == '\n')
01220 getNextChar();
01221
01222 break;
01223 }
01224 }
01225 return true;
01226 }
01227
01228 void OurReader::readNumber() {
01229 const char *p = current_;
01230 char c = '0';
01231
01232 while (c >= '0' && c <= '9')
01233 c = (current_ = p) < end_ ? *p++ : 0;
01234
01235 if (c == '.') {
01236 c = (current_ = p) < end_ ? *p++ : 0;
01237 while (c >= '0' && c <= '9')
01238 c = (current_ = p) < end_ ? *p++ : 0;
01239 }
01240
01241 if (c == 'e' || c == 'E') {
01242 c = (current_ = p) < end_ ? *p++ : 0;
01243 if (c == '+' || c == '-')
01244 c = (current_ = p) < end_ ? *p++ : 0;
01245 while (c >= '0' && c <= '9')
01246 c = (current_ = p) < end_ ? *p++ : 0;
01247 }
01248 }
01249 bool OurReader::readString() {
01250 Char c = 0;
01251 while (current_ != end_) {
01252 c = getNextChar();
01253 if (c == '\\')
01254 getNextChar();
01255 else if (c == '"')
01256 break;
01257 }
01258 return c == '"';
01259 }
01260
01261
01262 bool OurReader::readStringSingleQuote() {
01263 Char c = 0;
01264 while (current_ != end_) {
01265 c = getNextChar();
01266 if (c == '\\')
01267 getNextChar();
01268 else if (c == '\'')
01269 break;
01270 }
01271 return c == '\'';
01272 }
01273
01274 bool OurReader::readObject(Token& tokenStart) {
01275 Token tokenName;
01276 std::string name;
01277 Value init(objectValue);
01278 currentValue().swapPayload(init);
01279 while (readToken(tokenName)) {
01280 bool initialTokenOk = true;
01281 while (tokenName.type_ == tokenComment && initialTokenOk)
01282 initialTokenOk = readToken(tokenName);
01283 if (!initialTokenOk)
01284 break;
01285 if (tokenName.type_ == tokenObjectEnd && name.empty())
01286 return true;
01287 name = "";
01288 if (tokenName.type_ == tokenString) {
01289 if (!decodeString(tokenName, name))
01290 return recoverFromError(tokenObjectEnd);
01291 } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
01292 Value numberName;
01293 if (!decodeNumber(tokenName, numberName))
01294 return recoverFromError(tokenObjectEnd);
01295 name = numberName.asString();
01296 } else {
01297 break;
01298 }
01299
01300 Token colon;
01301 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
01302 return addErrorAndRecover(
01303 "Missing ':' after object member name", colon, tokenObjectEnd);
01304 }
01305 if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");
01306 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
01307 std::string msg = "Duplicate key: '" + name + "'";
01308 return addErrorAndRecover(
01309 msg, tokenName, tokenObjectEnd);
01310 }
01311 Value& value = currentValue()[name];
01312 nodes_.push(&value);
01313 bool ok = readValue();
01314 nodes_.pop();
01315 if (!ok)
01316 return recoverFromError(tokenObjectEnd);
01317
01318 Token comma;
01319 if (!readToken(comma) ||
01320 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
01321 comma.type_ != tokenComment)) {
01322 return addErrorAndRecover(
01323 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
01324 }
01325 bool finalizeTokenOk = true;
01326 while (comma.type_ == tokenComment && finalizeTokenOk)
01327 finalizeTokenOk = readToken(comma);
01328 if (comma.type_ == tokenObjectEnd)
01329 return true;
01330 }
01331 return addErrorAndRecover(
01332 "Missing '}' or object member name", tokenName, tokenObjectEnd);
01333 }
01334
01335 bool OurReader::readArray(Token& tokenStart) {
01336 Value init(arrayValue);
01337 currentValue().swapPayload(init);
01338 skipSpaces();
01339 if (*current_ == ']')
01340 {
01341 Token endArray;
01342 readToken(endArray);
01343 return true;
01344 }
01345 int index = 0;
01346 for (;;) {
01347 Value& value = currentValue()[index++];
01348 nodes_.push(&value);
01349 bool ok = readValue();
01350 nodes_.pop();
01351 if (!ok)
01352 return recoverFromError(tokenArrayEnd);
01353
01354 Token token;
01355
01356 ok = readToken(token);
01357 while (token.type_ == tokenComment && ok) {
01358 ok = readToken(token);
01359 }
01360 bool badTokenType =
01361 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
01362 if (!ok || badTokenType) {
01363 return addErrorAndRecover(
01364 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
01365 }
01366 if (token.type_ == tokenArrayEnd)
01367 break;
01368 }
01369 return true;
01370 }
01371
01372 bool OurReader::decodeNumber(Token& token) {
01373 Value decoded;
01374 if (!decodeNumber(token, decoded))
01375 return false;
01376 currentValue().swapPayload(decoded);
01377 return true;
01378 }
01379
01380 bool OurReader::decodeNumber(Token& token, Value& decoded) {
01381
01382
01383
01384 Location current = token.start_;
01385 bool isNegative = *current == '-';
01386 if (isNegative)
01387 ++current;
01388
01389 Value::LargestUInt maxIntegerValue =
01390 isNegative ? Value::LargestUInt(-Value::minLargestInt)
01391 : Value::maxLargestUInt;
01392 Value::LargestUInt threshold = maxIntegerValue / 10;
01393 Value::LargestUInt value = 0;
01394 while (current < token.end_) {
01395 Char c = *current++;
01396 if (c < '0' || c > '9')
01397 return decodeDouble(token, decoded);
01398 Value::UInt digit(c - '0');
01399 if (value >= threshold) {
01400
01401
01402
01403
01404 if (value > threshold || current != token.end_ ||
01405 digit > maxIntegerValue % 10) {
01406 return decodeDouble(token, decoded);
01407 }
01408 }
01409 value = value * 10 + digit;
01410 }
01411 if (isNegative)
01412 decoded = -Value::LargestInt(value);
01413 else if (value <= Value::LargestUInt(Value::maxInt))
01414 decoded = Value::LargestInt(value);
01415 else
01416 decoded = value;
01417 return true;
01418 }
01419
01420 bool OurReader::decodeDouble(Token& token) {
01421 Value decoded;
01422 if (!decodeDouble(token, decoded))
01423 return false;
01424 currentValue().swapPayload(decoded);
01425 return true;
01426 }
01427
01428 bool OurReader::decodeDouble(Token& token, Value& decoded) {
01429 double value = 0;
01430 const int bufferSize = 32;
01431 int count;
01432 int length = int(token.end_ - token.start_);
01433
01434
01435 if (length < 0) {
01436 return addError("Unable to parse token length", token);
01437 }
01438
01439
01440
01441
01442
01443
01444 char format[] = "%lf";
01445
01446 if (length <= bufferSize) {
01447 Char buffer[bufferSize + 1];
01448 memcpy(buffer, token.start_, length);
01449 buffer[length] = 0;
01450 count = sscanf(buffer, format, &value);
01451 } else {
01452 std::string buffer(token.start_, token.end_);
01453 count = sscanf(buffer.c_str(), format, &value);
01454 }
01455
01456 if (count != 1)
01457 return addError("'" + std::string(token.start_, token.end_) +
01458 "' is not a number.",
01459 token);
01460 decoded = value;
01461 return true;
01462 }
01463
01464 bool OurReader::decodeString(Token& token) {
01465 std::string decoded_string;
01466 if (!decodeString(token, decoded_string))
01467 return false;
01468 Value decoded(decoded_string);
01469 currentValue().swapPayload(decoded);
01470 return true;
01471 }
01472
01473 bool OurReader::decodeString(Token& token, std::string& decoded) {
01474 decoded.reserve(token.end_ - token.start_ - 2);
01475 Location current = token.start_ + 1;
01476 Location end = token.end_ - 1;
01477 while (current != end) {
01478 Char c = *current++;
01479 if (c == '"')
01480 break;
01481 else if (c == '\\') {
01482 if (current == end)
01483 return addError("Empty escape sequence in string", token, current);
01484 Char escape = *current++;
01485 switch (escape) {
01486 case '"':
01487 decoded += '"';
01488 break;
01489 case '/':
01490 decoded += '/';
01491 break;
01492 case '\\':
01493 decoded += '\\';
01494 break;
01495 case 'b':
01496 decoded += '\b';
01497 break;
01498 case 'f':
01499 decoded += '\f';
01500 break;
01501 case 'n':
01502 decoded += '\n';
01503 break;
01504 case 'r':
01505 decoded += '\r';
01506 break;
01507 case 't':
01508 decoded += '\t';
01509 break;
01510 case 'u': {
01511 unsigned int unicode;
01512 if (!decodeUnicodeCodePoint(token, current, end, unicode))
01513 return false;
01514 decoded += codePointToUTF8(unicode);
01515 } break;
01516 default:
01517 return addError("Bad escape sequence in string", token, current);
01518 }
01519 } else {
01520 decoded += c;
01521 }
01522 }
01523 return true;
01524 }
01525
01526 bool OurReader::decodeUnicodeCodePoint(Token& token,
01527 Location& current,
01528 Location end,
01529 unsigned int& unicode) {
01530
01531 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
01532 return false;
01533 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
01534
01535 if (end - current < 6)
01536 return addError(
01537 "additional six characters expected to parse unicode surrogate pair.",
01538 token,
01539 current);
01540 unsigned int surrogatePair;
01541 if (*(current++) == '\\' && *(current++) == 'u') {
01542 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
01543 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
01544 } else
01545 return false;
01546 } else
01547 return addError("expecting another \\u token to begin the second half of "
01548 "a unicode surrogate pair",
01549 token,
01550 current);
01551 }
01552 return true;
01553 }
01554
01555 bool OurReader::decodeUnicodeEscapeSequence(Token& token,
01556 Location& current,
01557 Location end,
01558 unsigned int& unicode) {
01559 if (end - current < 4)
01560 return addError(
01561 "Bad unicode escape sequence in string: four digits expected.",
01562 token,
01563 current);
01564 unicode = 0;
01565 for (int index = 0; index < 4; ++index) {
01566 Char c = *current++;
01567 unicode *= 16;
01568 if (c >= '0' && c <= '9')
01569 unicode += c - '0';
01570 else if (c >= 'a' && c <= 'f')
01571 unicode += c - 'a' + 10;
01572 else if (c >= 'A' && c <= 'F')
01573 unicode += c - 'A' + 10;
01574 else
01575 return addError(
01576 "Bad unicode escape sequence in string: hexadecimal digit expected.",
01577 token,
01578 current);
01579 }
01580 return true;
01581 }
01582
01583 bool
01584 OurReader::addError(const std::string& message, Token& token, Location extra) {
01585 ErrorInfo info;
01586 info.token_ = token;
01587 info.message_ = message;
01588 info.extra_ = extra;
01589 errors_.push_back(info);
01590 return false;
01591 }
01592
01593 bool OurReader::recoverFromError(TokenType skipUntilToken) {
01594 int errorCount = int(errors_.size());
01595 Token skip;
01596 for (;;) {
01597 if (!readToken(skip))
01598 errors_.resize(errorCount);
01599 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
01600 break;
01601 }
01602 errors_.resize(errorCount);
01603 return false;
01604 }
01605
01606 bool OurReader::addErrorAndRecover(const std::string& message,
01607 Token& token,
01608 TokenType skipUntilToken) {
01609 addError(message, token);
01610 return recoverFromError(skipUntilToken);
01611 }
01612
01613 Value& OurReader::currentValue() { return *(nodes_.top()); }
01614
01615 OurReader::Char OurReader::getNextChar() {
01616 if (current_ == end_)
01617 return 0;
01618 return *current_++;
01619 }
01620
01621 void OurReader::getLocationLineAndColumn(Location location,
01622 int& line,
01623 int& column) const {
01624 Location current = begin_;
01625 Location lastLineStart = current;
01626 line = 0;
01627 while (current < location && current != end_) {
01628 Char c = *current++;
01629 if (c == '\r') {
01630 if (*current == '\n')
01631 ++current;
01632 lastLineStart = current;
01633 ++line;
01634 } else if (c == '\n') {
01635 lastLineStart = current;
01636 ++line;
01637 }
01638 }
01639
01640 column = int(location - lastLineStart) + 1;
01641 ++line;
01642 }
01643
01644 std::string OurReader::getLocationLineAndColumn(Location location) const {
01645 int line, column;
01646 getLocationLineAndColumn(location, line, column);
01647 char buffer[18 + 16 + 16 + 1];
01648 #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
01649 #if defined(WINCE)
01650 _snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
01651 #else
01652 sprintf_s(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
01653 #endif
01654 #else
01655 snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
01656 #endif
01657 return buffer;
01658 }
01659
01660 std::string OurReader::getFormattedErrorMessages() const {
01661 std::string formattedMessage;
01662 for (Errors::const_iterator itError = errors_.begin();
01663 itError != errors_.end();
01664 ++itError) {
01665 const ErrorInfo& error = *itError;
01666 formattedMessage +=
01667 "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
01668 formattedMessage += " " + error.message_ + "\n";
01669 if (error.extra_)
01670 formattedMessage +=
01671 "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
01672 }
01673 return formattedMessage;
01674 }
01675
01676
01677 class OurCharReader : public CharReader {
01678 bool const collectComments_;
01679 OurReader reader_;
01680 public:
01681 OurCharReader(
01682 bool collectComments,
01683 OurFeatures const& features)
01684 : collectComments_(collectComments)
01685 , reader_(features)
01686 {}
01687 virtual bool parse(
01688 char const* beginDoc, char const* endDoc,
01689 Value* root, std::string* errs) {
01690 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
01691 if (errs) {
01692 *errs = reader_.getFormattedErrorMessages();
01693 }
01694 return ok;
01695 }
01696 };
01697
01698 CharReaderBuilder::CharReaderBuilder()
01699 {
01700 setDefaults(&settings_);
01701 }
01702 CharReaderBuilder::~CharReaderBuilder()
01703 {}
01704 CharReader* CharReaderBuilder::newCharReader() const
01705 {
01706 bool collectComments = settings_["collectComments"].asBool();
01707 OurFeatures features = OurFeatures::all();
01708 features.allowComments_ = settings_["allowComments"].asBool();
01709 features.strictRoot_ = settings_["strictRoot"].asBool();
01710 features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
01711 features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
01712 features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
01713 features.stackLimit_ = settings_["stackLimit"].asInt();
01714 features.failIfExtra_ = settings_["failIfExtra"].asBool();
01715 features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
01716 return new OurCharReader(collectComments, features);
01717 }
01718 static void getValidReaderKeys(std::set<std::string>* valid_keys)
01719 {
01720 valid_keys->clear();
01721 valid_keys->insert("collectComments");
01722 valid_keys->insert("allowComments");
01723 valid_keys->insert("strictRoot");
01724 valid_keys->insert("allowDroppedNullPlaceholders");
01725 valid_keys->insert("allowNumericKeys");
01726 valid_keys->insert("allowSingleQuotes");
01727 valid_keys->insert("stackLimit");
01728 valid_keys->insert("failIfExtra");
01729 valid_keys->insert("rejectDupKeys");
01730 }
01731 bool CharReaderBuilder::validate(Json::Value* invalid) const
01732 {
01733 Json::Value my_invalid;
01734 if (!invalid) invalid = &my_invalid;
01735 Json::Value& inv = *invalid;
01736 std::set<std::string> valid_keys;
01737 getValidReaderKeys(&valid_keys);
01738 Value::Members keys = settings_.getMemberNames();
01739 size_t n = keys.size();
01740 for (size_t i = 0; i < n; ++i) {
01741 std::string const& key = keys[i];
01742 if (valid_keys.find(key) == valid_keys.end()) {
01743 inv[key] = settings_[key];
01744 }
01745 }
01746 return 0u == inv.size();
01747 }
01748 Value& CharReaderBuilder::operator[](std::string key)
01749 {
01750 return settings_[key];
01751 }
01752
01753 void CharReaderBuilder::strictMode(Json::Value* settings)
01754 {
01756 (*settings)["allowComments"] = false;
01757 (*settings)["strictRoot"] = true;
01758 (*settings)["allowDroppedNullPlaceholders"] = false;
01759 (*settings)["allowNumericKeys"] = false;
01760 (*settings)["allowSingleQuotes"] = false;
01761 (*settings)["failIfExtra"] = true;
01762 (*settings)["rejectDupKeys"] = true;
01764 }
01765
01766 void CharReaderBuilder::setDefaults(Json::Value* settings)
01767 {
01769 (*settings)["collectComments"] = true;
01770 (*settings)["allowComments"] = true;
01771 (*settings)["strictRoot"] = false;
01772 (*settings)["allowDroppedNullPlaceholders"] = false;
01773 (*settings)["allowNumericKeys"] = false;
01774 (*settings)["allowSingleQuotes"] = false;
01775 (*settings)["stackLimit"] = 1000;
01776 (*settings)["failIfExtra"] = false;
01777 (*settings)["rejectDupKeys"] = false;
01779 }
01780
01782
01783
01784 bool parseFromStream(
01785 CharReader::Factory const& fact, std::istream& sin,
01786 Value* root, std::string* errs)
01787 {
01788 std::ostringstream ssin;
01789 ssin << sin.rdbuf();
01790 std::string doc = ssin.str();
01791 char const* begin = doc.data();
01792 char const* end = begin + doc.size();
01793
01794 CharReaderPtr const reader(fact.newCharReader());
01795 return reader->parse(begin, end, root, errs);
01796 }
01797
01798 std::istream& operator>>(std::istream& sin, Value& root) {
01799 CharReaderBuilder b;
01800 std::string errs;
01801 bool ok = parseFromStream(b, sin, &root, &errs);
01802 if (!ok) {
01803 fprintf(stderr,
01804 "Error from reader: %s",
01805 errs.c_str());
01806
01807 throwRuntimeError("reader error");
01808 }
01809 return sin;
01810 }
01811
01812 }