Home | History | Annotate | Download | only in lib_json
      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 
     29 namespace Json {
     30 
     31 // Implementation of class Features
     32 // ////////////////////////////////
     33 
     34 Features::Features()
     35     : allowComments_(true), strictRoot_(false),
     36       allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
     37 
     38 Features Features::all() { return Features(); }
     39 
     40 Features 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 
     52 static 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 
     60 static 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 
     69 static 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 
     79 Reader::Reader()
     80     : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
     81       lastValue_(), commentsBefore_(), features_(Features::all()),
     82       collectComments_() {}
     83 
     84 Reader::Reader(const Features& features)
     85     : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
     86       lastValue_(), commentsBefore_(), features_(features), collectComments_() {
     87 }
     88 
     89 bool
     90 Reader::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 
     97 bool 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 
    110 bool 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 
    151 bool 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_ = &currentValue();
    219   }
    220 
    221   return successful;
    222 }
    223 
    224 void 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 
    234 bool 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 
    241 bool 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 
    312 void 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 
    322 bool 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 
    333 bool 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 
    356 void
    357 Reader::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 
    367 bool Reader::readCStyleComment() {
    368   while (current_ != end_) {
    369     Char c = getNextChar();
    370     if (c == '*' && *current_ == '/')
    371       break;
    372   }
    373   return getNextChar() == '/';
    374 }
    375 
    376 bool Reader::readCppStyleComment() {
    377   while (current_ != end_) {
    378     Char c = getNextChar();
    379     if (c == '\r' || c == '\n')
    380       break;
    381   }
    382   return true;
    383 }
    384 
    385 void Reader::readNumber() {
    386   while (current_ != end_) {
    387     if (!(*current_ >= '0' && *current_ <= '9') &&
    388         !in(*current_, '.', 'e', 'E', '+', '-'))
    389       break;
    390     ++current_;
    391   }
    392 }
    393 
    394 bool 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 
    406 bool 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 
    461 bool 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 
    498 bool 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 
    508 bool 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 
    556 bool 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 
    566 bool 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 
    602 bool 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 
    612 bool 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 
    665 bool 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 
    694 bool 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 
    722 bool
    723 Reader::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 
    732 bool 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 
    745 bool Reader::addErrorAndRecover(const std::string& message,
    746                                 Token& token,
    747                                 TokenType skipUntilToken) {
    748   addError(message, token);
    749   return recoverFromError(skipUntilToken);
    750 }
    751 
    752 Value& Reader::currentValue() { return *(nodes_.top()); }
    753 
    754 Reader::Char Reader::getNextChar() {
    755   if (current_ == end_)
    756     return 0;
    757   return *current_++;
    758 }
    759 
    760 void 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 
    783 std::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
    800 std::string Reader::getFormatedErrorMessages() const {
    801   return getFormattedErrorMessages();
    802 }
    803 
    804 std::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 
    820 std::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 
    835 bool 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 
    852 bool 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 
    870 bool Reader::good() const {
    871   return !errors_.size();
    872 }
    873 
    874 std::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