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