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