1// Copyright 2007-2011 Baptiste Lepilleur 2// Distributed under MIT license, or public domain if desired and 3// recognized in your jurisdiction. 4// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 5 6#if !defined(JSON_IS_AMALGAMATION) 7#include <json/assertions.h> 8#include <json/reader.h> 9#include <json/value.h> 10#include "json_tool.h" 11#endif // if !defined(JSON_IS_AMALGAMATION) 12#include <iostream> 13#include <fstream> 14#include <utility> 15#include <cstdio> 16#include <cassert> 17#include <cstring> 18#include <istream> 19 20#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below 21#define snprintf _snprintf 22#endif 23 24#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 25// Disable warning about strdup being deprecated. 26#pragma warning(disable : 4996) 27#endif 28 29namespace Json { 30 31// Implementation of class Features 32// //////////////////////////////// 33 34Features::Features() 35 : allowComments_(true), strictRoot_(false), 36 allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} 37 38Features Features::all() { return Features(); } 39 40Features Features::strictMode() { 41 Features features; 42 features.allowComments_ = false; 43 features.strictRoot_ = true; 44 features.allowDroppedNullPlaceholders_ = false; 45 features.allowNumericKeys_ = false; 46 return features; 47} 48 49// Implementation of class Reader 50// //////////////////////////////// 51 52static inline bool in(Reader::Char c, 53 Reader::Char c1, 54 Reader::Char c2, 55 Reader::Char c3, 56 Reader::Char c4) { 57 return c == c1 || c == c2 || c == c3 || c == c4; 58} 59 60static inline bool in(Reader::Char c, 61 Reader::Char c1, 62 Reader::Char c2, 63 Reader::Char c3, 64 Reader::Char c4, 65 Reader::Char c5) { 66 return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; 67} 68 69static bool containsNewLine(Reader::Location begin, Reader::Location end) { 70 for (; begin < end; ++begin) 71 if (*begin == '\n' || *begin == '\r') 72 return true; 73 return false; 74} 75 76// Class Reader 77// ////////////////////////////////////////////////////////////////// 78 79Reader::Reader() 80 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), 81 lastValue_(), commentsBefore_(), features_(Features::all()), 82 collectComments_() {} 83 84Reader::Reader(const Features& features) 85 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), 86 lastValue_(), commentsBefore_(), features_(features), collectComments_() { 87} 88 89bool 90Reader::parse(const std::string& document, Value& root, bool collectComments) { 91 document_ = document; 92 const char* begin = document_.c_str(); 93 const char* end = begin + document_.length(); 94 return parse(begin, end, root, collectComments); 95} 96 97bool Reader::parse(std::istream& sin, Value& root, bool collectComments) { 98 // std::istream_iterator<char> begin(sin); 99 // std::istream_iterator<char> end; 100 // Those would allow streamed input from a file, if parse() were a 101 // template function. 102 103 // Since std::string is reference-counted, this at least does not 104 // create an extra copy. 105 std::string doc; 106 std::getline(sin, doc, (char)EOF); 107 return parse(doc, root, collectComments); 108} 109 110bool Reader::parse(const char* beginDoc, 111 const char* endDoc, 112 Value& root, 113 bool collectComments) { 114 if (!features_.allowComments_) { 115 collectComments = false; 116 } 117 118 begin_ = beginDoc; 119 end_ = endDoc; 120 collectComments_ = collectComments; 121 current_ = begin_; 122 lastValueEnd_ = 0; 123 lastValue_ = 0; 124 commentsBefore_ = ""; 125 errors_.clear(); 126 while (!nodes_.empty()) 127 nodes_.pop(); 128 nodes_.push(&root); 129 130 bool successful = readValue(); 131 Token token; 132 skipCommentTokens(token); 133 if (collectComments_ && !commentsBefore_.empty()) 134 root.setComment(commentsBefore_, commentAfter); 135 if (features_.strictRoot_) { 136 if (!root.isArray() && !root.isObject()) { 137 // Set error location to start of doc, ideally should be first token found 138 // in doc 139 token.type_ = tokenError; 140 token.start_ = beginDoc; 141 token.end_ = endDoc; 142 addError( 143 "A valid JSON document must be either an array or an object value.", 144 token); 145 return false; 146 } 147 } 148 return successful; 149} 150 151bool Reader::readValue() { 152 Token token; 153 skipCommentTokens(token); 154 bool successful = true; 155 156 if (collectComments_ && !commentsBefore_.empty()) { 157 // Remove newline characters at the end of the comments 158 size_t lastNonNewline = commentsBefore_.find_last_not_of("\r\n"); 159 if (lastNonNewline != std::string::npos) { 160 commentsBefore_.erase(lastNonNewline + 1); 161 } else { 162 commentsBefore_.clear(); 163 } 164 165 currentValue().setComment(commentsBefore_, commentBefore); 166 commentsBefore_ = ""; 167 } 168 169 switch (token.type_) { 170 case tokenObjectBegin: 171 successful = readObject(token); 172 currentValue().setOffsetLimit(current_ - begin_); 173 break; 174 case tokenArrayBegin: 175 successful = readArray(token); 176 currentValue().setOffsetLimit(current_ - begin_); 177 break; 178 case tokenNumber: 179 successful = decodeNumber(token); 180 break; 181 case tokenString: 182 successful = decodeString(token); 183 break; 184 case tokenTrue: 185 currentValue() = true; 186 currentValue().setOffsetStart(token.start_ - begin_); 187 currentValue().setOffsetLimit(token.end_ - begin_); 188 break; 189 case tokenFalse: 190 currentValue() = false; 191 currentValue().setOffsetStart(token.start_ - begin_); 192 currentValue().setOffsetLimit(token.end_ - begin_); 193 break; 194 case tokenNull: 195 currentValue() = Value(); 196 currentValue().setOffsetStart(token.start_ - begin_); 197 currentValue().setOffsetLimit(token.end_ - begin_); 198 break; 199 case tokenArraySeparator: 200 if (features_.allowDroppedNullPlaceholders_) { 201 // "Un-read" the current token and mark the current value as a null 202 // token. 203 current_--; 204 currentValue() = Value(); 205 currentValue().setOffsetStart(current_ - begin_ - 1); 206 currentValue().setOffsetLimit(current_ - begin_); 207 break; 208 } 209 // Else, fall through... 210 default: 211 currentValue().setOffsetStart(token.start_ - begin_); 212 currentValue().setOffsetLimit(token.end_ - begin_); 213 return addError("Syntax error: value, object or array expected.", token); 214 } 215 216 if (collectComments_) { 217 lastValueEnd_ = current_; 218 lastValue_ = ¤tValue(); 219 } 220 221 return successful; 222} 223 224void Reader::skipCommentTokens(Token& token) { 225 if (features_.allowComments_) { 226 do { 227 readToken(token); 228 } while (token.type_ == tokenComment); 229 } else { 230 readToken(token); 231 } 232} 233 234bool Reader::expectToken(TokenType type, Token& token, const char* message) { 235 readToken(token); 236 if (token.type_ != type) 237 return addError(message, token); 238 return true; 239} 240 241bool Reader::readToken(Token& token) { 242 skipSpaces(); 243 token.start_ = current_; 244 Char c = getNextChar(); 245 bool ok = true; 246 switch (c) { 247 case '{': 248 token.type_ = tokenObjectBegin; 249 break; 250 case '}': 251 token.type_ = tokenObjectEnd; 252 break; 253 case '[': 254 token.type_ = tokenArrayBegin; 255 break; 256 case ']': 257 token.type_ = tokenArrayEnd; 258 break; 259 case '"': 260 token.type_ = tokenString; 261 ok = readString(); 262 break; 263 case '/': 264 token.type_ = tokenComment; 265 ok = readComment(); 266 break; 267 case '0': 268 case '1': 269 case '2': 270 case '3': 271 case '4': 272 case '5': 273 case '6': 274 case '7': 275 case '8': 276 case '9': 277 case '-': 278 token.type_ = tokenNumber; 279 readNumber(); 280 break; 281 case 't': 282 token.type_ = tokenTrue; 283 ok = match("rue", 3); 284 break; 285 case 'f': 286 token.type_ = tokenFalse; 287 ok = match("alse", 4); 288 break; 289 case 'n': 290 token.type_ = tokenNull; 291 ok = match("ull", 3); 292 break; 293 case ',': 294 token.type_ = tokenArraySeparator; 295 break; 296 case ':': 297 token.type_ = tokenMemberSeparator; 298 break; 299 case 0: 300 token.type_ = tokenEndOfStream; 301 break; 302 default: 303 ok = false; 304 break; 305 } 306 if (!ok) 307 token.type_ = tokenError; 308 token.end_ = current_; 309 return true; 310} 311 312void Reader::skipSpaces() { 313 while (current_ != end_) { 314 Char c = *current_; 315 if (c == ' ' || c == '\t' || c == '\r' || c == '\n') 316 ++current_; 317 else 318 break; 319 } 320} 321 322bool Reader::match(Location pattern, int patternLength) { 323 if (end_ - current_ < patternLength) 324 return false; 325 int index = patternLength; 326 while (index--) 327 if (current_[index] != pattern[index]) 328 return false; 329 current_ += patternLength; 330 return true; 331} 332 333bool Reader::readComment() { 334 Location commentBegin = current_ - 1; 335 Char c = getNextChar(); 336 bool successful = false; 337 if (c == '*') 338 successful = readCStyleComment(); 339 else if (c == '/') 340 successful = readCppStyleComment(); 341 if (!successful) 342 return false; 343 344 if (collectComments_) { 345 CommentPlacement placement = commentBefore; 346 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { 347 if (c != '*' || !containsNewLine(commentBegin, current_)) 348 placement = commentAfterOnSameLine; 349 } 350 351 addComment(commentBegin, current_, placement); 352 } 353 return true; 354} 355 356void 357Reader::addComment(Location begin, Location end, CommentPlacement placement) { 358 assert(collectComments_); 359 if (placement == commentAfterOnSameLine) { 360 assert(lastValue_ != 0); 361 lastValue_->setComment(std::string(begin, end), placement); 362 } else { 363 commentsBefore_ += std::string(begin, end); 364 } 365} 366 367bool Reader::readCStyleComment() { 368 while (current_ != end_) { 369 Char c = getNextChar(); 370 if (c == '*' && *current_ == '/') 371 break; 372 } 373 return getNextChar() == '/'; 374} 375 376bool Reader::readCppStyleComment() { 377 while (current_ != end_) { 378 Char c = getNextChar(); 379 if (c == '\r' || c == '\n') 380 break; 381 } 382 return true; 383} 384 385void Reader::readNumber() { 386 while (current_ != end_) { 387 if (!(*current_ >= '0' && *current_ <= '9') && 388 !in(*current_, '.', 'e', 'E', '+', '-')) 389 break; 390 ++current_; 391 } 392} 393 394bool Reader::readString() { 395 Char c = 0; 396 while (current_ != end_) { 397 c = getNextChar(); 398 if (c == '\\') 399 getNextChar(); 400 else if (c == '"') 401 break; 402 } 403 return c == '"'; 404} 405 406bool Reader::readObject(Token& tokenStart) { 407 Token tokenName; 408 std::string name; 409 currentValue() = Value(objectValue); 410 currentValue().setOffsetStart(tokenStart.start_ - begin_); 411 while (readToken(tokenName)) { 412 bool initialTokenOk = true; 413 while (tokenName.type_ == tokenComment && initialTokenOk) 414 initialTokenOk = readToken(tokenName); 415 if (!initialTokenOk) 416 break; 417 if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object 418 return true; 419 name = ""; 420 if (tokenName.type_ == tokenString) { 421 if (!decodeString(tokenName, name)) 422 return recoverFromError(tokenObjectEnd); 423 } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { 424 Value numberName; 425 if (!decodeNumber(tokenName, numberName)) 426 return recoverFromError(tokenObjectEnd); 427 name = numberName.asString(); 428 } else { 429 break; 430 } 431 432 Token colon; 433 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { 434 return addErrorAndRecover( 435 "Missing ':' after object member name", colon, tokenObjectEnd); 436 } 437 Value& value = currentValue()[name]; 438 nodes_.push(&value); 439 bool ok = readValue(); 440 nodes_.pop(); 441 if (!ok) // error already set 442 return recoverFromError(tokenObjectEnd); 443 444 Token comma; 445 if (!readToken(comma) || 446 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && 447 comma.type_ != tokenComment)) { 448 return addErrorAndRecover( 449 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); 450 } 451 bool finalizeTokenOk = true; 452 while (comma.type_ == tokenComment && finalizeTokenOk) 453 finalizeTokenOk = readToken(comma); 454 if (comma.type_ == tokenObjectEnd) 455 return true; 456 } 457 return addErrorAndRecover( 458 "Missing '}' or object member name", tokenName, tokenObjectEnd); 459} 460 461bool Reader::readArray(Token& tokenStart) { 462 currentValue() = Value(arrayValue); 463 currentValue().setOffsetStart(tokenStart.start_ - begin_); 464 skipSpaces(); 465 if (*current_ == ']') // empty array 466 { 467 Token endArray; 468 readToken(endArray); 469 return true; 470 } 471 int index = 0; 472 for (;;) { 473 Value& value = currentValue()[index++]; 474 nodes_.push(&value); 475 bool ok = readValue(); 476 nodes_.pop(); 477 if (!ok) // error already set 478 return recoverFromError(tokenArrayEnd); 479 480 Token token; 481 // Accept Comment after last item in the array. 482 ok = readToken(token); 483 while (token.type_ == tokenComment && ok) { 484 ok = readToken(token); 485 } 486 bool badTokenType = 487 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); 488 if (!ok || badTokenType) { 489 return addErrorAndRecover( 490 "Missing ',' or ']' in array declaration", token, tokenArrayEnd); 491 } 492 if (token.type_ == tokenArrayEnd) 493 break; 494 } 495 return true; 496} 497 498bool Reader::decodeNumber(Token& token) { 499 Value decoded; 500 if (!decodeNumber(token, decoded)) 501 return false; 502 currentValue() = decoded; 503 currentValue().setOffsetStart(token.start_ - begin_); 504 currentValue().setOffsetLimit(token.end_ - begin_); 505 return true; 506} 507 508bool Reader::decodeNumber(Token& token, Value& decoded) { 509 bool isDouble = false; 510 for (Location inspect = token.start_; inspect != token.end_; ++inspect) { 511 isDouble = isDouble || in(*inspect, '.', 'e', 'E', '+') || 512 (*inspect == '-' && inspect != token.start_); 513 } 514 if (isDouble) 515 return decodeDouble(token, decoded); 516 // Attempts to parse the number as an integer. If the number is 517 // larger than the maximum supported value of an integer then 518 // we decode the number as a double. 519 Location current = token.start_; 520 bool isNegative = *current == '-'; 521 if (isNegative) 522 ++current; 523 Value::LargestUInt maxIntegerValue = 524 isNegative ? Value::LargestUInt(-Value::minLargestInt) 525 : Value::maxLargestUInt; 526 Value::LargestUInt threshold = maxIntegerValue / 10; 527 Value::LargestUInt value = 0; 528 while (current < token.end_) { 529 Char c = *current++; 530 if (c < '0' || c > '9') 531 return addError("'" + std::string(token.start_, token.end_) + 532 "' is not a number.", 533 token); 534 Value::UInt digit(c - '0'); 535 if (value >= threshold) { 536 // We've hit or exceeded the max value divided by 10 (rounded down). If 537 // a) we've only just touched the limit, b) this is the last digit, and 538 // c) it's small enough to fit in that rounding delta, we're okay. 539 // Otherwise treat this number as a double to avoid overflow. 540 if (value > threshold || current != token.end_ || 541 digit > maxIntegerValue % 10) { 542 return decodeDouble(token, decoded); 543 } 544 } 545 value = value * 10 + digit; 546 } 547 if (isNegative) 548 decoded = -Value::LargestInt(value); 549 else if (value <= Value::LargestUInt(Value::maxInt)) 550 decoded = Value::LargestInt(value); 551 else 552 decoded = value; 553 return true; 554} 555 556bool Reader::decodeDouble(Token& token) { 557 Value decoded; 558 if (!decodeDouble(token, decoded)) 559 return false; 560 currentValue() = decoded; 561 currentValue().setOffsetStart(token.start_ - begin_); 562 currentValue().setOffsetLimit(token.end_ - begin_); 563 return true; 564} 565 566bool Reader::decodeDouble(Token& token, Value& decoded) { 567 double value = 0; 568 const int bufferSize = 32; 569 int count; 570 int length = int(token.end_ - token.start_); 571 572 // Sanity check to avoid buffer overflow exploits. 573 if (length < 0) { 574 return addError("Unable to parse token length", token); 575 } 576 577 // Avoid using a string constant for the format control string given to 578 // sscanf, as this can cause hard to debug crashes on OS X. See here for more 579 // info: 580 // 581 // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html 582 char format[] = "%lf"; 583 584 if (length <= bufferSize) { 585 Char buffer[bufferSize + 1]; 586 memcpy(buffer, token.start_, length); 587 buffer[length] = 0; 588 count = sscanf(buffer, format, &value); 589 } else { 590 std::string buffer(token.start_, token.end_); 591 count = sscanf(buffer.c_str(), format, &value); 592 } 593 594 if (count != 1) 595 return addError("'" + std::string(token.start_, token.end_) + 596 "' is not a number.", 597 token); 598 decoded = value; 599 return true; 600} 601 602bool Reader::decodeString(Token& token) { 603 std::string decoded; 604 if (!decodeString(token, decoded)) 605 return false; 606 currentValue() = decoded; 607 currentValue().setOffsetStart(token.start_ - begin_); 608 currentValue().setOffsetLimit(token.end_ - begin_); 609 return true; 610} 611 612bool Reader::decodeString(Token& token, std::string& decoded) { 613 decoded.reserve(token.end_ - token.start_ - 2); 614 Location current = token.start_ + 1; // skip '"' 615 Location end = token.end_ - 1; // do not include '"' 616 while (current != end) { 617 Char c = *current++; 618 if (c == '"') 619 break; 620 else if (c == '\\') { 621 if (current == end) 622 return addError("Empty escape sequence in string", token, current); 623 Char escape = *current++; 624 switch (escape) { 625 case '"': 626 decoded += '"'; 627 break; 628 case '/': 629 decoded += '/'; 630 break; 631 case '\\': 632 decoded += '\\'; 633 break; 634 case 'b': 635 decoded += '\b'; 636 break; 637 case 'f': 638 decoded += '\f'; 639 break; 640 case 'n': 641 decoded += '\n'; 642 break; 643 case 'r': 644 decoded += '\r'; 645 break; 646 case 't': 647 decoded += '\t'; 648 break; 649 case 'u': { 650 unsigned int unicode; 651 if (!decodeUnicodeCodePoint(token, current, end, unicode)) 652 return false; 653 decoded += codePointToUTF8(unicode); 654 } break; 655 default: 656 return addError("Bad escape sequence in string", token, current); 657 } 658 } else { 659 decoded += c; 660 } 661 } 662 return true; 663} 664 665bool Reader::decodeUnicodeCodePoint(Token& token, 666 Location& current, 667 Location end, 668 unsigned int& unicode) { 669 670 if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) 671 return false; 672 if (unicode >= 0xD800 && unicode <= 0xDBFF) { 673 // surrogate pairs 674 if (end - current < 6) 675 return addError( 676 "additional six characters expected to parse unicode surrogate pair.", 677 token, 678 current); 679 unsigned int surrogatePair; 680 if (*(current++) == '\\' && *(current++) == 'u') { 681 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { 682 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); 683 } else 684 return false; 685 } else 686 return addError("expecting another \\u token to begin the second half of " 687 "a unicode surrogate pair", 688 token, 689 current); 690 } 691 return true; 692} 693 694bool Reader::decodeUnicodeEscapeSequence(Token& token, 695 Location& current, 696 Location end, 697 unsigned int& unicode) { 698 if (end - current < 4) 699 return addError( 700 "Bad unicode escape sequence in string: four digits expected.", 701 token, 702 current); 703 unicode = 0; 704 for (int index = 0; index < 4; ++index) { 705 Char c = *current++; 706 unicode *= 16; 707 if (c >= '0' && c <= '9') 708 unicode += c - '0'; 709 else if (c >= 'a' && c <= 'f') 710 unicode += c - 'a' + 10; 711 else if (c >= 'A' && c <= 'F') 712 unicode += c - 'A' + 10; 713 else 714 return addError( 715 "Bad unicode escape sequence in string: hexadecimal digit expected.", 716 token, 717 current); 718 } 719 return true; 720} 721 722bool 723Reader::addError(const std::string& message, Token& token, Location extra) { 724 ErrorInfo info; 725 info.token_ = token; 726 info.message_ = message; 727 info.extra_ = extra; 728 errors_.push_back(info); 729 return false; 730} 731 732bool Reader::recoverFromError(TokenType skipUntilToken) { 733 int errorCount = int(errors_.size()); 734 Token skip; 735 for (;;) { 736 if (!readToken(skip)) 737 errors_.resize(errorCount); // discard errors caused by recovery 738 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) 739 break; 740 } 741 errors_.resize(errorCount); 742 return false; 743} 744 745bool Reader::addErrorAndRecover(const std::string& message, 746 Token& token, 747 TokenType skipUntilToken) { 748 addError(message, token); 749 return recoverFromError(skipUntilToken); 750} 751 752Value& Reader::currentValue() { return *(nodes_.top()); } 753 754Reader::Char Reader::getNextChar() { 755 if (current_ == end_) 756 return 0; 757 return *current_++; 758} 759 760void Reader::getLocationLineAndColumn(Location location, 761 int& line, 762 int& column) const { 763 Location current = begin_; 764 Location lastLineStart = current; 765 line = 0; 766 while (current < location && current != end_) { 767 Char c = *current++; 768 if (c == '\r') { 769 if (*current == '\n') 770 ++current; 771 lastLineStart = current; 772 ++line; 773 } else if (c == '\n') { 774 lastLineStart = current; 775 ++line; 776 } 777 } 778 // column & line start at 1 779 column = int(location - lastLineStart) + 1; 780 ++line; 781} 782 783std::string Reader::getLocationLineAndColumn(Location location) const { 784 int line, column; 785 getLocationLineAndColumn(location, line, column); 786 char buffer[18 + 16 + 16 + 1]; 787#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) 788#if defined(WINCE) 789 _snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); 790#else 791 sprintf_s(buffer, sizeof(buffer), "Line %d, Column %d", line, column); 792#endif 793#else 794 snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); 795#endif 796 return buffer; 797} 798 799// Deprecated. Preserved for backward compatibility 800std::string Reader::getFormatedErrorMessages() const { 801 return getFormattedErrorMessages(); 802} 803 804std::string Reader::getFormattedErrorMessages() const { 805 std::string formattedMessage; 806 for (Errors::const_iterator itError = errors_.begin(); 807 itError != errors_.end(); 808 ++itError) { 809 const ErrorInfo& error = *itError; 810 formattedMessage += 811 "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; 812 formattedMessage += " " + error.message_ + "\n"; 813 if (error.extra_) 814 formattedMessage += 815 "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; 816 } 817 return formattedMessage; 818} 819 820std::vector<Reader::StructuredError> Reader::getStructuredErrors() const { 821 std::vector<Reader::StructuredError> allErrors; 822 for (Errors::const_iterator itError = errors_.begin(); 823 itError != errors_.end(); 824 ++itError) { 825 const ErrorInfo& error = *itError; 826 Reader::StructuredError structured; 827 structured.offset_start = error.token_.start_ - begin_; 828 structured.offset_limit = error.token_.end_ - begin_; 829 structured.message = error.message_; 830 allErrors.push_back(structured); 831 } 832 return allErrors; 833} 834 835bool Reader::pushError(const Value& value, const std::string& message) { 836 size_t length = end_ - begin_; 837 if(value.getOffsetStart() > length 838 || value.getOffsetLimit() > length) 839 return false; 840 Token token; 841 token.type_ = tokenError; 842 token.start_ = begin_ + value.getOffsetStart(); 843 token.end_ = end_ + value.getOffsetLimit(); 844 ErrorInfo info; 845 info.token_ = token; 846 info.message_ = message; 847 info.extra_ = 0; 848 errors_.push_back(info); 849 return true; 850} 851 852bool Reader::pushError(const Value& value, const std::string& message, const Value& extra) { 853 size_t length = end_ - begin_; 854 if(value.getOffsetStart() > length 855 || value.getOffsetLimit() > length 856 || extra.getOffsetLimit() > length) 857 return false; 858 Token token; 859 token.type_ = tokenError; 860 token.start_ = begin_ + value.getOffsetStart(); 861 token.end_ = begin_ + value.getOffsetLimit(); 862 ErrorInfo info; 863 info.token_ = token; 864 info.message_ = message; 865 info.extra_ = begin_ + extra.getOffsetStart(); 866 errors_.push_back(info); 867 return true; 868} 869 870bool Reader::good() const { 871 return !errors_.size(); 872} 873 874std::istream& operator>>(std::istream& sin, Value& root) { 875 Json::Reader reader; 876 bool ok = reader.parse(sin, root, true); 877 if (!ok) { 878 fprintf(stderr, 879 "Error from reader: %s", 880 reader.getFormattedErrorMessages().c_str()); 881 882 JSON_FAIL_MESSAGE("reader error"); 883 } 884 return sin; 885} 886 887} // namespace Json 888