LCOV - code coverage report
Current view: top level - toolkit/components/jsoncpp/src/lib_json - json_reader.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1208 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 104 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright 2007-2011 Baptiste Lepilleur
       2             : // Copyright (C) 2016 InfoTeCS JSC. All rights reserved.
       3             : // Distributed under MIT license, or public domain if desired and
       4             : // recognized in your jurisdiction.
       5             : // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
       6             : 
       7             : #if !defined(JSON_IS_AMALGAMATION)
       8             : #include <json/assertions.h>
       9             : #include <json/reader.h>
      10             : #include <json/value.h>
      11             : #include "json_tool.h"
      12             : #endif // if !defined(JSON_IS_AMALGAMATION)
      13             : #include <utility>
      14             : #include <cstdio>
      15             : #include <cassert>
      16             : #include <cstring>
      17             : #include <istream>
      18             : #include <sstream>
      19             : #include <memory>
      20             : #include <set>
      21             : #include <limits>
      22             : 
      23             : #if defined(_MSC_VER)
      24             : #if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above 
      25             : #define snprintf sprintf_s
      26             : #elif _MSC_VER >= 1900 // VC++ 14.0 and above
      27             : #define snprintf std::snprintf
      28             : #else
      29             : #define snprintf _snprintf
      30             : #endif
      31             : #elif defined(__ANDROID__) || defined(__QNXNTO__)
      32             : #define snprintf snprintf
      33             : #elif __cplusplus >= 201103L
      34             : #if !defined(__MINGW32__) && !defined(__CYGWIN__)
      35             : #define snprintf std::snprintf
      36             : #endif
      37             : #endif
      38             : 
      39             : #if defined(__QNXNTO__)
      40             : #define sscanf std::sscanf
      41             : #endif
      42             : 
      43             : #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
      44             : // Disable warning about strdup being deprecated.
      45             : #pragma warning(disable : 4996)
      46             : #endif
      47             : 
      48             : // Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile time to change the stack limit
      49             : #if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
      50             : #define JSONCPP_DEPRECATED_STACK_LIMIT 1000
      51             : #endif
      52             : 
      53             : static size_t const stackLimit_g = JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()
      54             : 
      55             : namespace Json {
      56             : 
      57             : #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
      58             : typedef std::unique_ptr<CharReader> CharReaderPtr;
      59             : #else
      60             : typedef std::auto_ptr<CharReader>   CharReaderPtr;
      61             : #endif
      62             : 
      63             : // Implementation of class Features
      64             : // ////////////////////////////////
      65             : 
      66           0 : Features::Features()
      67             :     : allowComments_(true), strictRoot_(false),
      68           0 :       allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
      69             : 
      70           0 : Features Features::all() { return Features(); }
      71             : 
      72           0 : Features Features::strictMode() {
      73           0 :   Features features;
      74           0 :   features.allowComments_ = false;
      75           0 :   features.strictRoot_ = true;
      76           0 :   features.allowDroppedNullPlaceholders_ = false;
      77           0 :   features.allowNumericKeys_ = false;
      78           0 :   return features;
      79             : }
      80             : 
      81             : // Implementation of class Reader
      82             : // ////////////////////////////////
      83             : 
      84           0 : static bool containsNewLine(Reader::Location begin, Reader::Location end) {
      85           0 :   for (; begin < end; ++begin)
      86           0 :     if (*begin == '\n' || *begin == '\r')
      87           0 :       return true;
      88           0 :   return false;
      89             : }
      90             : 
      91             : // Class Reader
      92             : // //////////////////////////////////////////////////////////////////
      93             : 
      94           0 : Reader::Reader()
      95             :     : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
      96             :       lastValue_(), commentsBefore_(), features_(Features::all()),
      97           0 :       collectComments_() {}
      98             : 
      99           0 : Reader::Reader(const Features& features)
     100             :     : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
     101           0 :       lastValue_(), commentsBefore_(), features_(features), collectComments_() {
     102           0 : }
     103             : 
     104             : bool
     105           0 : Reader::parse(const std::string& document, Value& root, bool collectComments) {
     106           0 :   JSONCPP_STRING documentCopy(document.data(), document.data() + document.capacity());
     107           0 :   std::swap(documentCopy, document_);
     108           0 :   const char* begin = document_.c_str();
     109           0 :   const char* end = begin + document_.length();
     110           0 :   return parse(begin, end, root, collectComments);
     111             : }
     112             : 
     113           0 : bool Reader::parse(std::istream& sin, Value& root, bool collectComments) {
     114             :   // std::istream_iterator<char> begin(sin);
     115             :   // std::istream_iterator<char> end;
     116             :   // Those would allow streamed input from a file, if parse() were a
     117             :   // template function.
     118             : 
     119             :   // Since JSONCPP_STRING is reference-counted, this at least does not
     120             :   // create an extra copy.
     121           0 :   JSONCPP_STRING doc;
     122           0 :   std::getline(sin, doc, (char)EOF);
     123           0 :   return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
     124             : }
     125             : 
     126           0 : bool Reader::parse(const char* beginDoc,
     127             :                    const char* endDoc,
     128             :                    Value& root,
     129             :                    bool collectComments) {
     130           0 :   if (!features_.allowComments_) {
     131           0 :     collectComments = false;
     132             :   }
     133             : 
     134           0 :   begin_ = beginDoc;
     135           0 :   end_ = endDoc;
     136           0 :   collectComments_ = collectComments;
     137           0 :   current_ = begin_;
     138           0 :   lastValueEnd_ = 0;
     139           0 :   lastValue_ = 0;
     140           0 :   commentsBefore_.clear();
     141           0 :   errors_.clear();
     142           0 :   while (!nodes_.empty())
     143           0 :     nodes_.pop();
     144           0 :   nodes_.push(&root);
     145             : 
     146           0 :   bool successful = readValue();
     147             :   Token token;
     148           0 :   skipCommentTokens(token);
     149           0 :   if (collectComments_ && !commentsBefore_.empty())
     150           0 :     root.setComment(commentsBefore_, commentAfter);
     151           0 :   if (features_.strictRoot_) {
     152           0 :     if (!root.isArray() && !root.isObject()) {
     153             :       // Set error location to start of doc, ideally should be first token found
     154             :       // in doc
     155           0 :       token.type_ = tokenError;
     156           0 :       token.start_ = beginDoc;
     157           0 :       token.end_ = endDoc;
     158           0 :       addError(
     159             :           "A valid JSON document must be either an array or an object value.",
     160           0 :           token);
     161           0 :       return false;
     162             :     }
     163             :   }
     164           0 :   return successful;
     165             : }
     166             : 
     167           0 : bool Reader::readValue() {
     168             :   // readValue() may call itself only if it calls readObject() or ReadArray().
     169             :   // These methods execute nodes_.push() just before and nodes_.pop)() just after calling readValue(). 
     170             :   // parse() executes one nodes_.push(), so > instead of >=.
     171           0 :   if (nodes_.size() > stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
     172             : 
     173             :   Token token;
     174           0 :   skipCommentTokens(token);
     175           0 :   bool successful = true;
     176             : 
     177           0 :   if (collectComments_ && !commentsBefore_.empty()) {
     178           0 :     currentValue().setComment(commentsBefore_, commentBefore);
     179           0 :     commentsBefore_.clear();
     180             :   }
     181             : 
     182           0 :   switch (token.type_) {
     183             :   case tokenObjectBegin:
     184           0 :     successful = readObject(token);
     185           0 :     currentValue().setOffsetLimit(current_ - begin_);
     186           0 :     break;
     187             :   case tokenArrayBegin:
     188           0 :     successful = readArray(token);
     189           0 :     currentValue().setOffsetLimit(current_ - begin_);
     190           0 :     break;
     191             :   case tokenNumber:
     192           0 :     successful = decodeNumber(token);
     193           0 :     break;
     194             :   case tokenString:
     195           0 :     successful = decodeString(token);
     196           0 :     break;
     197             :   case tokenTrue:
     198             :     {
     199           0 :     Value v(true);
     200           0 :     currentValue().swapPayload(v);
     201           0 :     currentValue().setOffsetStart(token.start_ - begin_);
     202           0 :     currentValue().setOffsetLimit(token.end_ - begin_);
     203             :     }
     204           0 :     break;
     205             :   case tokenFalse:
     206             :     {
     207           0 :     Value v(false);
     208           0 :     currentValue().swapPayload(v);
     209           0 :     currentValue().setOffsetStart(token.start_ - begin_);
     210           0 :     currentValue().setOffsetLimit(token.end_ - begin_);
     211             :     }
     212           0 :     break;
     213             :   case tokenNull:
     214             :     {
     215           0 :     Value v;
     216           0 :     currentValue().swapPayload(v);
     217           0 :     currentValue().setOffsetStart(token.start_ - begin_);
     218           0 :     currentValue().setOffsetLimit(token.end_ - begin_);
     219             :     }
     220           0 :     break;
     221             :   case tokenArraySeparator:
     222             :   case tokenObjectEnd:
     223             :   case tokenArrayEnd:
     224           0 :     if (features_.allowDroppedNullPlaceholders_) {
     225             :       // "Un-read" the current token and mark the current value as a null
     226             :       // token.
     227           0 :       current_--;
     228           0 :       Value v;
     229           0 :       currentValue().swapPayload(v);
     230           0 :       currentValue().setOffsetStart(current_ - begin_ - 1);
     231           0 :       currentValue().setOffsetLimit(current_ - begin_);
     232           0 :       break;
     233             :     } // Else, fall through...
     234             :   default:
     235           0 :     currentValue().setOffsetStart(token.start_ - begin_);
     236           0 :     currentValue().setOffsetLimit(token.end_ - begin_);
     237           0 :     return addError("Syntax error: value, object or array expected.", token);
     238             :   }
     239             : 
     240           0 :   if (collectComments_) {
     241           0 :     lastValueEnd_ = current_;
     242           0 :     lastValue_ = &currentValue();
     243             :   }
     244             : 
     245           0 :   return successful;
     246             : }
     247             : 
     248           0 : void Reader::skipCommentTokens(Token& token) {
     249           0 :   if (features_.allowComments_) {
     250           0 :     do {
     251           0 :       readToken(token);
     252           0 :     } while (token.type_ == tokenComment);
     253             :   } else {
     254           0 :     readToken(token);
     255             :   }
     256           0 : }
     257             : 
     258           0 : bool Reader::readToken(Token& token) {
     259           0 :   skipSpaces();
     260           0 :   token.start_ = current_;
     261           0 :   Char c = getNextChar();
     262           0 :   bool ok = true;
     263           0 :   switch (c) {
     264             :   case '{':
     265           0 :     token.type_ = tokenObjectBegin;
     266           0 :     break;
     267             :   case '}':
     268           0 :     token.type_ = tokenObjectEnd;
     269           0 :     break;
     270             :   case '[':
     271           0 :     token.type_ = tokenArrayBegin;
     272           0 :     break;
     273             :   case ']':
     274           0 :     token.type_ = tokenArrayEnd;
     275           0 :     break;
     276             :   case '"':
     277           0 :     token.type_ = tokenString;
     278           0 :     ok = readString();
     279           0 :     break;
     280             :   case '/':
     281           0 :     token.type_ = tokenComment;
     282           0 :     ok = readComment();
     283           0 :     break;
     284             :   case '0':
     285             :   case '1':
     286             :   case '2':
     287             :   case '3':
     288             :   case '4':
     289             :   case '5':
     290             :   case '6':
     291             :   case '7':
     292             :   case '8':
     293             :   case '9':
     294             :   case '-':
     295           0 :     token.type_ = tokenNumber;
     296           0 :     readNumber();
     297           0 :     break;
     298             :   case 't':
     299           0 :     token.type_ = tokenTrue;
     300           0 :     ok = match("rue", 3);
     301           0 :     break;
     302             :   case 'f':
     303           0 :     token.type_ = tokenFalse;
     304           0 :     ok = match("alse", 4);
     305           0 :     break;
     306             :   case 'n':
     307           0 :     token.type_ = tokenNull;
     308           0 :     ok = match("ull", 3);
     309           0 :     break;
     310             :   case ',':
     311           0 :     token.type_ = tokenArraySeparator;
     312           0 :     break;
     313             :   case ':':
     314           0 :     token.type_ = tokenMemberSeparator;
     315           0 :     break;
     316             :   case 0:
     317           0 :     token.type_ = tokenEndOfStream;
     318           0 :     break;
     319             :   default:
     320           0 :     ok = false;
     321           0 :     break;
     322             :   }
     323           0 :   if (!ok)
     324           0 :     token.type_ = tokenError;
     325           0 :   token.end_ = current_;
     326           0 :   return true;
     327             : }
     328             : 
     329           0 : void Reader::skipSpaces() {
     330           0 :   while (current_ != end_) {
     331           0 :     Char c = *current_;
     332           0 :     if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
     333           0 :       ++current_;
     334             :     else
     335             :       break;
     336             :   }
     337           0 : }
     338             : 
     339           0 : bool Reader::match(Location pattern, int patternLength) {
     340           0 :   if (end_ - current_ < patternLength)
     341           0 :     return false;
     342           0 :   int index = patternLength;
     343           0 :   while (index--)
     344           0 :     if (current_[index] != pattern[index])
     345           0 :       return false;
     346           0 :   current_ += patternLength;
     347           0 :   return true;
     348             : }
     349             : 
     350           0 : bool Reader::readComment() {
     351           0 :   Location commentBegin = current_ - 1;
     352           0 :   Char c = getNextChar();
     353           0 :   bool successful = false;
     354           0 :   if (c == '*')
     355           0 :     successful = readCStyleComment();
     356           0 :   else if (c == '/')
     357           0 :     successful = readCppStyleComment();
     358           0 :   if (!successful)
     359           0 :     return false;
     360             : 
     361           0 :   if (collectComments_) {
     362           0 :     CommentPlacement placement = commentBefore;
     363           0 :     if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
     364           0 :       if (c != '*' || !containsNewLine(commentBegin, current_))
     365           0 :         placement = commentAfterOnSameLine;
     366             :     }
     367             : 
     368           0 :     addComment(commentBegin, current_, placement);
     369             :   }
     370           0 :   return true;
     371             : }
     372             : 
     373           0 : static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Location end) {
     374           0 :   JSONCPP_STRING normalized;
     375           0 :   normalized.reserve(static_cast<size_t>(end - begin));
     376           0 :   Reader::Location current = begin;
     377           0 :   while (current != end) {
     378           0 :     char c = *current++;
     379           0 :     if (c == '\r') {
     380           0 :       if (current != end && *current == '\n')
     381             :          // convert dos EOL
     382           0 :          ++current;
     383             :       // convert Mac EOL
     384           0 :       normalized += '\n';
     385             :     } else {
     386           0 :       normalized += c;
     387             :     }
     388             :   }
     389           0 :   return normalized;
     390             : }
     391             : 
     392             : void
     393           0 : Reader::addComment(Location begin, Location end, CommentPlacement placement) {
     394           0 :   assert(collectComments_);
     395           0 :   const JSONCPP_STRING& normalized = normalizeEOL(begin, end);
     396           0 :   if (placement == commentAfterOnSameLine) {
     397           0 :     assert(lastValue_ != 0);
     398           0 :     lastValue_->setComment(normalized, placement);
     399             :   } else {
     400           0 :     commentsBefore_ += normalized;
     401             :   }
     402           0 : }
     403             : 
     404           0 : bool Reader::readCStyleComment() {
     405           0 :   while ((current_ + 1) < end_) {
     406           0 :     Char c = getNextChar();
     407           0 :     if (c == '*' && *current_ == '/')
     408           0 :       break;
     409             :   }
     410           0 :   return getNextChar() == '/';
     411             : }
     412             : 
     413           0 : bool Reader::readCppStyleComment() {
     414           0 :   while (current_ != end_) {
     415           0 :     Char c = getNextChar();
     416           0 :     if (c == '\n')
     417           0 :       break;
     418           0 :     if (c == '\r') {
     419             :       // Consume DOS EOL. It will be normalized in addComment.
     420           0 :       if (current_ != end_ && *current_ == '\n')
     421           0 :         getNextChar();
     422             :       // Break on Moc OS 9 EOL.
     423           0 :       break;
     424             :     }
     425             :   }
     426           0 :   return true;
     427             : }
     428             : 
     429           0 : void Reader::readNumber() {
     430           0 :   const char *p = current_;
     431           0 :   char c = '0'; // stopgap for already consumed character
     432             :   // integral part
     433           0 :   while (c >= '0' && c <= '9')
     434           0 :     c = (current_ = p) < end_ ? *p++ : '\0';
     435             :   // fractional part
     436           0 :   if (c == '.') {
     437           0 :     c = (current_ = p) < end_ ? *p++ : '\0';
     438           0 :     while (c >= '0' && c <= '9')
     439           0 :       c = (current_ = p) < end_ ? *p++ : '\0';
     440             :   }
     441             :   // exponential part
     442           0 :   if (c == 'e' || c == 'E') {
     443           0 :     c = (current_ = p) < end_ ? *p++ : '\0';
     444           0 :     if (c == '+' || c == '-')
     445           0 :       c = (current_ = p) < end_ ? *p++ : '\0';
     446           0 :     while (c >= '0' && c <= '9')
     447           0 :       c = (current_ = p) < end_ ? *p++ : '\0';
     448             :   }
     449           0 : }
     450             : 
     451           0 : bool Reader::readString() {
     452           0 :   Char c = '\0';
     453           0 :   while (current_ != end_) {
     454           0 :     c = getNextChar();
     455           0 :     if (c == '\\')
     456           0 :       getNextChar();
     457           0 :     else if (c == '"')
     458           0 :       break;
     459             :   }
     460           0 :   return c == '"';
     461             : }
     462             : 
     463           0 : bool Reader::readObject(Token& tokenStart) {
     464             :   Token tokenName;
     465           0 :   JSONCPP_STRING name;
     466           0 :   Value init(objectValue);
     467           0 :   currentValue().swapPayload(init);
     468           0 :   currentValue().setOffsetStart(tokenStart.start_ - begin_);
     469           0 :   while (readToken(tokenName)) {
     470           0 :     bool initialTokenOk = true;
     471           0 :     while (tokenName.type_ == tokenComment && initialTokenOk)
     472           0 :       initialTokenOk = readToken(tokenName);
     473           0 :     if (!initialTokenOk)
     474           0 :       break;
     475           0 :     if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
     476           0 :       return true;
     477           0 :     name.clear();
     478           0 :     if (tokenName.type_ == tokenString) {
     479           0 :       if (!decodeString(tokenName, name))
     480           0 :         return recoverFromError(tokenObjectEnd);
     481           0 :     } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
     482           0 :       Value numberName;
     483           0 :       if (!decodeNumber(tokenName, numberName))
     484           0 :         return recoverFromError(tokenObjectEnd);
     485           0 :       name = JSONCPP_STRING(numberName.asCString());
     486             :     } else {
     487             :       break;
     488             :     }
     489             : 
     490             :     Token colon;
     491           0 :     if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
     492           0 :       return addErrorAndRecover(
     493           0 :           "Missing ':' after object member name", colon, tokenObjectEnd);
     494             :     }
     495           0 :     Value& value = currentValue()[name];
     496           0 :     nodes_.push(&value);
     497           0 :     bool ok = readValue();
     498           0 :     nodes_.pop();
     499           0 :     if (!ok) // error already set
     500           0 :       return recoverFromError(tokenObjectEnd);
     501             : 
     502             :     Token comma;
     503           0 :     if (!readToken(comma) ||
     504           0 :         (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
     505           0 :          comma.type_ != tokenComment)) {
     506           0 :       return addErrorAndRecover(
     507           0 :           "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
     508             :     }
     509           0 :     bool finalizeTokenOk = true;
     510           0 :     while (comma.type_ == tokenComment && finalizeTokenOk)
     511           0 :       finalizeTokenOk = readToken(comma);
     512           0 :     if (comma.type_ == tokenObjectEnd)
     513           0 :       return true;
     514             :   }
     515           0 :   return addErrorAndRecover(
     516           0 :       "Missing '}' or object member name", tokenName, tokenObjectEnd);
     517             : }
     518             : 
     519           0 : bool Reader::readArray(Token& tokenStart) {
     520           0 :   Value init(arrayValue);
     521           0 :   currentValue().swapPayload(init);
     522           0 :   currentValue().setOffsetStart(tokenStart.start_ - begin_);
     523           0 :   skipSpaces();
     524           0 :   if (current_ != end_ && *current_ == ']') // empty array
     525             :   {
     526             :     Token endArray;
     527           0 :     readToken(endArray);
     528           0 :     return true;
     529             :   }
     530           0 :   int index = 0;
     531             :   for (;;) {
     532           0 :     Value& value = currentValue()[index++];
     533           0 :     nodes_.push(&value);
     534           0 :     bool ok = readValue();
     535           0 :     nodes_.pop();
     536           0 :     if (!ok) // error already set
     537           0 :       return recoverFromError(tokenArrayEnd);
     538             : 
     539             :     Token token;
     540             :     // Accept Comment after last item in the array.
     541           0 :     ok = readToken(token);
     542           0 :     while (token.type_ == tokenComment && ok) {
     543           0 :       ok = readToken(token);
     544             :     }
     545             :     bool badTokenType =
     546           0 :         (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
     547           0 :     if (!ok || badTokenType) {
     548           0 :       return addErrorAndRecover(
     549           0 :           "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
     550             :     }
     551           0 :     if (token.type_ == tokenArrayEnd)
     552           0 :       break;
     553           0 :   }
     554           0 :   return true;
     555             : }
     556             : 
     557           0 : bool Reader::decodeNumber(Token& token) {
     558           0 :   Value decoded;
     559           0 :   if (!decodeNumber(token, decoded))
     560           0 :     return false;
     561           0 :   currentValue().swapPayload(decoded);
     562           0 :   currentValue().setOffsetStart(token.start_ - begin_);
     563           0 :   currentValue().setOffsetLimit(token.end_ - begin_);
     564           0 :   return true;
     565             : }
     566             : 
     567           0 : bool Reader::decodeNumber(Token& token, Value& decoded) {
     568             :   // Attempts to parse the number as an integer. If the number is
     569             :   // larger than the maximum supported value of an integer then
     570             :   // we decode the number as a double.
     571           0 :   Location current = token.start_;
     572           0 :   bool isNegative = *current == '-';
     573           0 :   if (isNegative)
     574           0 :     ++current;
     575             :   // TODO: Help the compiler do the div and mod at compile time or get rid of them.
     576             :   Value::LargestUInt maxIntegerValue =
     577           0 :       isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
     578           0 :                  : Value::maxLargestUInt;
     579           0 :   Value::LargestUInt threshold = maxIntegerValue / 10;
     580           0 :   Value::LargestUInt value = 0;
     581           0 :   while (current < token.end_) {
     582           0 :     Char c = *current++;
     583           0 :     if (c < '0' || c > '9')
     584           0 :       return decodeDouble(token, decoded);
     585           0 :     Value::UInt digit(static_cast<Value::UInt>(c - '0'));
     586           0 :     if (value >= threshold) {
     587             :       // We've hit or exceeded the max value divided by 10 (rounded down). If
     588             :       // a) we've only just touched the limit, b) this is the last digit, and
     589             :       // c) it's small enough to fit in that rounding delta, we're okay.
     590             :       // Otherwise treat this number as a double to avoid overflow.
     591           0 :       if (value > threshold || current != token.end_ ||
     592           0 :           digit > maxIntegerValue % 10) {
     593           0 :         return decodeDouble(token, decoded);
     594             :       }
     595             :     }
     596           0 :     value = value * 10 + digit;
     597             :   }
     598           0 :   if (isNegative && value == maxIntegerValue)
     599           0 :     decoded = Value::minLargestInt;
     600           0 :   else if (isNegative)
     601           0 :     decoded = -Value::LargestInt(value);
     602           0 :   else if (value <= Value::LargestUInt(Value::maxInt))
     603           0 :     decoded = Value::LargestInt(value);
     604             :   else
     605           0 :     decoded = value;
     606           0 :   return true;
     607             : }
     608             : 
     609           0 : bool Reader::decodeDouble(Token& token) {
     610           0 :   Value decoded;
     611           0 :   if (!decodeDouble(token, decoded))
     612           0 :     return false;
     613           0 :   currentValue().swapPayload(decoded);
     614           0 :   currentValue().setOffsetStart(token.start_ - begin_);
     615           0 :   currentValue().setOffsetLimit(token.end_ - begin_);
     616           0 :   return true;
     617             : }
     618             : 
     619           0 : bool Reader::decodeDouble(Token& token, Value& decoded) {
     620           0 :   double value = 0;
     621           0 :   JSONCPP_STRING buffer(token.start_, token.end_);
     622           0 :   JSONCPP_ISTRINGSTREAM is(buffer);
     623           0 :   if (!(is >> value))
     624           0 :     return addError("'" + JSONCPP_STRING(token.start_, token.end_) +
     625             :                         "' is not a number.",
     626           0 :                     token);
     627           0 :   decoded = value;
     628           0 :   return true;
     629             : }
     630             : 
     631           0 : bool Reader::decodeString(Token& token) {
     632           0 :   JSONCPP_STRING decoded_string;
     633           0 :   if (!decodeString(token, decoded_string))
     634           0 :     return false;
     635           0 :   Value decoded(decoded_string);
     636           0 :   currentValue().swapPayload(decoded);
     637           0 :   currentValue().setOffsetStart(token.start_ - begin_);
     638           0 :   currentValue().setOffsetLimit(token.end_ - begin_);
     639           0 :   return true;
     640             : }
     641             : 
     642           0 : bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) {
     643           0 :   decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
     644           0 :   Location current = token.start_ + 1; // skip '"'
     645           0 :   Location end = token.end_ - 1;       // do not include '"'
     646           0 :   while (current != end) {
     647           0 :     Char c = *current++;
     648           0 :     if (c == '"')
     649           0 :       break;
     650           0 :     else if (c == '\\') {
     651           0 :       if (current == end)
     652           0 :         return addError("Empty escape sequence in string", token, current);
     653           0 :       Char escape = *current++;
     654           0 :       switch (escape) {
     655             :       case '"':
     656           0 :         decoded += '"';
     657           0 :         break;
     658             :       case '/':
     659           0 :         decoded += '/';
     660           0 :         break;
     661             :       case '\\':
     662           0 :         decoded += '\\';
     663           0 :         break;
     664             :       case 'b':
     665           0 :         decoded += '\b';
     666           0 :         break;
     667             :       case 'f':
     668           0 :         decoded += '\f';
     669           0 :         break;
     670             :       case 'n':
     671           0 :         decoded += '\n';
     672           0 :         break;
     673             :       case 'r':
     674           0 :         decoded += '\r';
     675           0 :         break;
     676             :       case 't':
     677           0 :         decoded += '\t';
     678           0 :         break;
     679             :       case 'u': {
     680             :         unsigned int unicode;
     681           0 :         if (!decodeUnicodeCodePoint(token, current, end, unicode))
     682           0 :           return false;
     683           0 :         decoded += codePointToUTF8(unicode);
     684           0 :       } break;
     685             :       default:
     686           0 :         return addError("Bad escape sequence in string", token, current);
     687             :       }
     688             :     } else {
     689           0 :       decoded += c;
     690             :     }
     691             :   }
     692           0 :   return true;
     693             : }
     694             : 
     695           0 : bool Reader::decodeUnicodeCodePoint(Token& token,
     696             :                                     Location& current,
     697             :                                     Location end,
     698             :                                     unsigned int& unicode) {
     699             : 
     700           0 :   if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
     701           0 :     return false;
     702           0 :   if (unicode >= 0xD800 && unicode <= 0xDBFF) {
     703             :     // surrogate pairs
     704           0 :     if (end - current < 6)
     705           0 :       return addError(
     706             :           "additional six characters expected to parse unicode surrogate pair.",
     707             :           token,
     708           0 :           current);
     709             :     unsigned int surrogatePair;
     710           0 :     if (*(current++) == '\\' && *(current++) == 'u') {
     711           0 :       if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
     712           0 :         unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
     713             :       } else
     714           0 :         return false;
     715             :     } else
     716           0 :       return addError("expecting another \\u token to begin the second half of "
     717             :                       "a unicode surrogate pair",
     718             :                       token,
     719           0 :                       current);
     720             :   }
     721           0 :   return true;
     722             : }
     723             : 
     724           0 : bool Reader::decodeUnicodeEscapeSequence(Token& token,
     725             :                                          Location& current,
     726             :                                          Location end,
     727             :                                          unsigned int& ret_unicode) {
     728           0 :   if (end - current < 4)
     729           0 :     return addError(
     730             :         "Bad unicode escape sequence in string: four digits expected.",
     731             :         token,
     732           0 :         current);
     733           0 :   int unicode = 0;
     734           0 :   for (int index = 0; index < 4; ++index) {
     735           0 :     Char c = *current++;
     736           0 :     unicode *= 16;
     737           0 :     if (c >= '0' && c <= '9')
     738           0 :       unicode += c - '0';
     739           0 :     else if (c >= 'a' && c <= 'f')
     740           0 :       unicode += c - 'a' + 10;
     741           0 :     else if (c >= 'A' && c <= 'F')
     742           0 :       unicode += c - 'A' + 10;
     743             :     else
     744           0 :       return addError(
     745             :           "Bad unicode escape sequence in string: hexadecimal digit expected.",
     746             :           token,
     747           0 :           current);
     748             :   }
     749           0 :   ret_unicode = static_cast<unsigned int>(unicode);
     750           0 :   return true;
     751             : }
     752             : 
     753             : bool
     754           0 : Reader::addError(const JSONCPP_STRING& message, Token& token, Location extra) {
     755           0 :   ErrorInfo info;
     756           0 :   info.token_ = token;
     757           0 :   info.message_ = message;
     758           0 :   info.extra_ = extra;
     759           0 :   errors_.push_back(info);
     760           0 :   return false;
     761             : }
     762             : 
     763           0 : bool Reader::recoverFromError(TokenType skipUntilToken) {
     764           0 :   size_t const errorCount = errors_.size();
     765             :   Token skip;
     766             :   for (;;) {
     767           0 :     if (!readToken(skip))
     768           0 :       errors_.resize(errorCount); // discard errors caused by recovery
     769           0 :     if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
     770             :       break;
     771             :   }
     772           0 :   errors_.resize(errorCount);
     773           0 :   return false;
     774             : }
     775             : 
     776           0 : bool Reader::addErrorAndRecover(const JSONCPP_STRING& message,
     777             :                                 Token& token,
     778             :                                 TokenType skipUntilToken) {
     779           0 :   addError(message, token);
     780           0 :   return recoverFromError(skipUntilToken);
     781             : }
     782             : 
     783           0 : Value& Reader::currentValue() { return *(nodes_.top()); }
     784             : 
     785           0 : Reader::Char Reader::getNextChar() {
     786           0 :   if (current_ == end_)
     787           0 :     return 0;
     788           0 :   return *current_++;
     789             : }
     790             : 
     791           0 : void Reader::getLocationLineAndColumn(Location location,
     792             :                                       int& line,
     793             :                                       int& column) const {
     794           0 :   Location current = begin_;
     795           0 :   Location lastLineStart = current;
     796           0 :   line = 0;
     797           0 :   while (current < location && current != end_) {
     798           0 :     Char c = *current++;
     799           0 :     if (c == '\r') {
     800           0 :       if (*current == '\n')
     801           0 :         ++current;
     802           0 :       lastLineStart = current;
     803           0 :       ++line;
     804           0 :     } else if (c == '\n') {
     805           0 :       lastLineStart = current;
     806           0 :       ++line;
     807             :     }
     808             :   }
     809             :   // column & line start at 1
     810           0 :   column = int(location - lastLineStart) + 1;
     811           0 :   ++line;
     812           0 : }
     813             : 
     814           0 : JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const {
     815             :   int line, column;
     816           0 :   getLocationLineAndColumn(location, line, column);
     817             :   char buffer[18 + 16 + 16 + 1];
     818           0 :   snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
     819           0 :   return buffer;
     820             : }
     821             : 
     822             : // Deprecated. Preserved for backward compatibility
     823           0 : JSONCPP_STRING Reader::getFormatedErrorMessages() const {
     824           0 :   return getFormattedErrorMessages();
     825             : }
     826             : 
     827           0 : JSONCPP_STRING Reader::getFormattedErrorMessages() const {
     828           0 :   JSONCPP_STRING formattedMessage;
     829           0 :   for (Errors::const_iterator itError = errors_.begin();
     830           0 :        itError != errors_.end();
     831             :        ++itError) {
     832           0 :     const ErrorInfo& error = *itError;
     833             :     formattedMessage +=
     834           0 :         "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
     835           0 :     formattedMessage += "  " + error.message_ + "\n";
     836           0 :     if (error.extra_)
     837             :       formattedMessage +=
     838           0 :           "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
     839             :   }
     840           0 :   return formattedMessage;
     841             : }
     842             : 
     843           0 : std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
     844           0 :   std::vector<Reader::StructuredError> allErrors;
     845           0 :   for (Errors::const_iterator itError = errors_.begin();
     846           0 :        itError != errors_.end();
     847             :        ++itError) {
     848           0 :     const ErrorInfo& error = *itError;
     849           0 :     Reader::StructuredError structured;
     850           0 :     structured.offset_start = error.token_.start_ - begin_;
     851           0 :     structured.offset_limit = error.token_.end_ - begin_;
     852           0 :     structured.message = error.message_;
     853           0 :     allErrors.push_back(structured);
     854             :   }
     855           0 :   return allErrors;
     856             : }
     857             : 
     858           0 : bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) {
     859           0 :   ptrdiff_t const length = end_ - begin_;
     860           0 :   if(value.getOffsetStart() > length
     861           0 :     || value.getOffsetLimit() > length)
     862           0 :     return false;
     863             :   Token token;
     864           0 :   token.type_ = tokenError;
     865           0 :   token.start_ = begin_ + value.getOffsetStart();
     866           0 :   token.end_ = end_ + value.getOffsetLimit();
     867           0 :   ErrorInfo info;
     868           0 :   info.token_ = token;
     869           0 :   info.message_ = message;
     870           0 :   info.extra_ = 0;
     871           0 :   errors_.push_back(info);
     872           0 :   return true;
     873             : }
     874             : 
     875           0 : bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) {
     876           0 :   ptrdiff_t const length = end_ - begin_;
     877           0 :   if(value.getOffsetStart() > length
     878           0 :     || value.getOffsetLimit() > length
     879           0 :     || extra.getOffsetLimit() > length)
     880           0 :     return false;
     881             :   Token token;
     882           0 :   token.type_ = tokenError;
     883           0 :   token.start_ = begin_ + value.getOffsetStart();
     884           0 :   token.end_ = begin_ + value.getOffsetLimit();
     885           0 :   ErrorInfo info;
     886           0 :   info.token_ = token;
     887           0 :   info.message_ = message;
     888           0 :   info.extra_ = begin_ + extra.getOffsetStart();
     889           0 :   errors_.push_back(info);
     890           0 :   return true;
     891             : }
     892             : 
     893           0 : bool Reader::good() const {
     894           0 :   return !errors_.size();
     895             : }
     896             : 
     897             : // exact copy of Features
     898             : class OurFeatures {
     899             : public:
     900             :   static OurFeatures all();
     901             :   bool allowComments_;
     902             :   bool strictRoot_;
     903             :   bool allowDroppedNullPlaceholders_;
     904             :   bool allowNumericKeys_;
     905             :   bool allowSingleQuotes_;
     906             :   bool failIfExtra_;
     907             :   bool rejectDupKeys_;
     908             :   bool allowSpecialFloats_;
     909             :   int stackLimit_;
     910             : };  // OurFeatures
     911             : 
     912             : // exact copy of Implementation of class Features
     913             : // ////////////////////////////////
     914             : 
     915           0 : OurFeatures OurFeatures::all() { return OurFeatures(); }
     916             : 
     917             : // Implementation of class Reader
     918             : // ////////////////////////////////
     919             : 
     920             : // exact copy of Reader, renamed to OurReader
     921           0 : class OurReader {
     922             : public:
     923             :   typedef char Char;
     924             :   typedef const Char* Location;
     925           0 :   struct StructuredError {
     926             :     ptrdiff_t offset_start;
     927             :     ptrdiff_t offset_limit;
     928             :     JSONCPP_STRING message;
     929             :   };
     930             : 
     931             :   OurReader(OurFeatures const& features);
     932             :   bool parse(const char* beginDoc,
     933             :              const char* endDoc,
     934             :              Value& root,
     935             :              bool collectComments = true);
     936             :   JSONCPP_STRING getFormattedErrorMessages() const;
     937             :   std::vector<StructuredError> getStructuredErrors() const;
     938             :   bool pushError(const Value& value, const JSONCPP_STRING& message);
     939             :   bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra);
     940             :   bool good() const;
     941             : 
     942             : private:
     943             :   OurReader(OurReader const&);  // no impl
     944             :   void operator=(OurReader const&);  // no impl
     945             : 
     946             :   enum TokenType {
     947             :     tokenEndOfStream = 0,
     948             :     tokenObjectBegin,
     949             :     tokenObjectEnd,
     950             :     tokenArrayBegin,
     951             :     tokenArrayEnd,
     952             :     tokenString,
     953             :     tokenNumber,
     954             :     tokenTrue,
     955             :     tokenFalse,
     956             :     tokenNull,
     957             :     tokenNaN,
     958             :     tokenPosInf,
     959             :     tokenNegInf,
     960             :     tokenArraySeparator,
     961             :     tokenMemberSeparator,
     962             :     tokenComment,
     963             :     tokenError
     964             :   };
     965             : 
     966             :   class Token {
     967             :   public:
     968             :     TokenType type_;
     969             :     Location start_;
     970             :     Location end_;
     971             :   };
     972             : 
     973           0 :   class ErrorInfo {
     974             :   public:
     975             :     Token token_;
     976             :     JSONCPP_STRING message_;
     977             :     Location extra_;
     978             :   };
     979             : 
     980             :   typedef std::deque<ErrorInfo> Errors;
     981             : 
     982             :   bool readToken(Token& token);
     983             :   void skipSpaces();
     984             :   bool match(Location pattern, int patternLength);
     985             :   bool readComment();
     986             :   bool readCStyleComment();
     987             :   bool readCppStyleComment();
     988             :   bool readString();
     989             :   bool readStringSingleQuote();
     990             :   bool readNumber(bool checkInf);
     991             :   bool readValue();
     992             :   bool readObject(Token& token);
     993             :   bool readArray(Token& token);
     994             :   bool decodeNumber(Token& token);
     995             :   bool decodeNumber(Token& token, Value& decoded);
     996             :   bool decodeString(Token& token);
     997             :   bool decodeString(Token& token, JSONCPP_STRING& decoded);
     998             :   bool decodeDouble(Token& token);
     999             :   bool decodeDouble(Token& token, Value& decoded);
    1000             :   bool decodeUnicodeCodePoint(Token& token,
    1001             :                               Location& current,
    1002             :                               Location end,
    1003             :                               unsigned int& unicode);
    1004             :   bool decodeUnicodeEscapeSequence(Token& token,
    1005             :                                    Location& current,
    1006             :                                    Location end,
    1007             :                                    unsigned int& unicode);
    1008             :   bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0);
    1009             :   bool recoverFromError(TokenType skipUntilToken);
    1010             :   bool addErrorAndRecover(const JSONCPP_STRING& message,
    1011             :                           Token& token,
    1012             :                           TokenType skipUntilToken);
    1013             :   void skipUntilSpace();
    1014             :   Value& currentValue();
    1015             :   Char getNextChar();
    1016             :   void
    1017             :   getLocationLineAndColumn(Location location, int& line, int& column) const;
    1018             :   JSONCPP_STRING getLocationLineAndColumn(Location location) const;
    1019             :   void addComment(Location begin, Location end, CommentPlacement placement);
    1020             :   void skipCommentTokens(Token& token);
    1021             : 
    1022             :   typedef std::stack<Value*> Nodes;
    1023             :   Nodes nodes_;
    1024             :   Errors errors_;
    1025             :   JSONCPP_STRING document_;
    1026             :   Location begin_;
    1027             :   Location end_;
    1028             :   Location current_;
    1029             :   Location lastValueEnd_;
    1030             :   Value* lastValue_;
    1031             :   JSONCPP_STRING commentsBefore_;
    1032             : 
    1033             :   OurFeatures const features_;
    1034             :   bool collectComments_;
    1035             : };  // OurReader
    1036             : 
    1037             : // complete copy of Read impl, for OurReader
    1038             : 
    1039           0 : OurReader::OurReader(OurFeatures const& features)
    1040             :     : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
    1041             :       lastValue_(), commentsBefore_(),
    1042           0 :       features_(features), collectComments_() {
    1043           0 : }
    1044             : 
    1045           0 : bool OurReader::parse(const char* beginDoc,
    1046             :                    const char* endDoc,
    1047             :                    Value& root,
    1048             :                    bool collectComments) {
    1049           0 :   if (!features_.allowComments_) {
    1050           0 :     collectComments = false;
    1051             :   }
    1052             : 
    1053           0 :   begin_ = beginDoc;
    1054           0 :   end_ = endDoc;
    1055           0 :   collectComments_ = collectComments;
    1056           0 :   current_ = begin_;
    1057           0 :   lastValueEnd_ = 0;
    1058           0 :   lastValue_ = 0;
    1059           0 :   commentsBefore_.clear();
    1060           0 :   errors_.clear();
    1061           0 :   while (!nodes_.empty())
    1062           0 :     nodes_.pop();
    1063           0 :   nodes_.push(&root);
    1064             : 
    1065           0 :   bool successful = readValue();
    1066             :   Token token;
    1067           0 :   skipCommentTokens(token);
    1068           0 :   if (features_.failIfExtra_) {
    1069           0 :     if ((features_.strictRoot_ || token.type_ != tokenError) && token.type_ != tokenEndOfStream) {
    1070           0 :       addError("Extra non-whitespace after JSON value.", token);
    1071           0 :       return false;
    1072             :     }
    1073             :   }
    1074           0 :   if (collectComments_ && !commentsBefore_.empty())
    1075           0 :     root.setComment(commentsBefore_, commentAfter);
    1076           0 :   if (features_.strictRoot_) {
    1077           0 :     if (!root.isArray() && !root.isObject()) {
    1078             :       // Set error location to start of doc, ideally should be first token found
    1079             :       // in doc
    1080           0 :       token.type_ = tokenError;
    1081           0 :       token.start_ = beginDoc;
    1082           0 :       token.end_ = endDoc;
    1083           0 :       addError(
    1084             :           "A valid JSON document must be either an array or an object value.",
    1085           0 :           token);
    1086           0 :       return false;
    1087             :     }
    1088             :   }
    1089           0 :   return successful;
    1090             : }
    1091             : 
    1092           0 : bool OurReader::readValue() {
    1093             :   //  To preserve the old behaviour we cast size_t to int.
    1094           0 :   if (static_cast<int>(nodes_.size()) > features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");
    1095             :   Token token;
    1096           0 :   skipCommentTokens(token);
    1097           0 :   bool successful = true;
    1098             : 
    1099           0 :   if (collectComments_ && !commentsBefore_.empty()) {
    1100           0 :     currentValue().setComment(commentsBefore_, commentBefore);
    1101           0 :     commentsBefore_.clear();
    1102             :   }
    1103             : 
    1104           0 :   switch (token.type_) {
    1105             :   case tokenObjectBegin:
    1106           0 :     successful = readObject(token);
    1107           0 :     currentValue().setOffsetLimit(current_ - begin_);
    1108           0 :     break;
    1109             :   case tokenArrayBegin:
    1110           0 :     successful = readArray(token);
    1111           0 :     currentValue().setOffsetLimit(current_ - begin_);
    1112           0 :     break;
    1113             :   case tokenNumber:
    1114           0 :     successful = decodeNumber(token);
    1115           0 :     break;
    1116             :   case tokenString:
    1117           0 :     successful = decodeString(token);
    1118           0 :     break;
    1119             :   case tokenTrue:
    1120             :     {
    1121           0 :     Value v(true);
    1122           0 :     currentValue().swapPayload(v);
    1123           0 :     currentValue().setOffsetStart(token.start_ - begin_);
    1124           0 :     currentValue().setOffsetLimit(token.end_ - begin_);
    1125             :     }
    1126           0 :     break;
    1127             :   case tokenFalse:
    1128             :     {
    1129           0 :     Value v(false);
    1130           0 :     currentValue().swapPayload(v);
    1131           0 :     currentValue().setOffsetStart(token.start_ - begin_);
    1132           0 :     currentValue().setOffsetLimit(token.end_ - begin_);
    1133             :     }
    1134           0 :     break;
    1135             :   case tokenNull:
    1136             :     {
    1137           0 :     Value v;
    1138           0 :     currentValue().swapPayload(v);
    1139           0 :     currentValue().setOffsetStart(token.start_ - begin_);
    1140           0 :     currentValue().setOffsetLimit(token.end_ - begin_);
    1141             :     }
    1142           0 :     break;
    1143             :   case tokenNaN:
    1144             :     {
    1145           0 :     Value v(std::numeric_limits<double>::quiet_NaN());
    1146           0 :     currentValue().swapPayload(v);
    1147           0 :     currentValue().setOffsetStart(token.start_ - begin_);
    1148           0 :     currentValue().setOffsetLimit(token.end_ - begin_);
    1149             :     }
    1150           0 :     break;
    1151             :   case tokenPosInf:
    1152             :     {
    1153           0 :     Value v(std::numeric_limits<double>::infinity());
    1154           0 :     currentValue().swapPayload(v);
    1155           0 :     currentValue().setOffsetStart(token.start_ - begin_);
    1156           0 :     currentValue().setOffsetLimit(token.end_ - begin_);
    1157             :     }
    1158           0 :     break;
    1159             :   case tokenNegInf:
    1160             :     {
    1161           0 :     Value v(-std::numeric_limits<double>::infinity());
    1162           0 :     currentValue().swapPayload(v);
    1163           0 :     currentValue().setOffsetStart(token.start_ - begin_);
    1164           0 :     currentValue().setOffsetLimit(token.end_ - begin_);
    1165             :     }
    1166           0 :     break;
    1167             :   case tokenArraySeparator:
    1168             :   case tokenObjectEnd:
    1169             :   case tokenArrayEnd:
    1170           0 :     if (features_.allowDroppedNullPlaceholders_) {
    1171             :       // "Un-read" the current token and mark the current value as a null
    1172             :       // token.
    1173           0 :       current_--;
    1174           0 :       Value v;
    1175           0 :       currentValue().swapPayload(v);
    1176           0 :       currentValue().setOffsetStart(current_ - begin_ - 1);
    1177           0 :       currentValue().setOffsetLimit(current_ - begin_);
    1178           0 :       break;
    1179             :     } // else, fall through ...
    1180             :   default:
    1181           0 :     currentValue().setOffsetStart(token.start_ - begin_);
    1182           0 :     currentValue().setOffsetLimit(token.end_ - begin_);
    1183           0 :     return addError("Syntax error: value, object or array expected.", token);
    1184             :   }
    1185             : 
    1186           0 :   if (collectComments_) {
    1187           0 :     lastValueEnd_ = current_;
    1188           0 :     lastValue_ = &currentValue();
    1189             :   }
    1190             : 
    1191           0 :   return successful;
    1192             : }
    1193             : 
    1194           0 : void OurReader::skipCommentTokens(Token& token) {
    1195           0 :   if (features_.allowComments_) {
    1196           0 :     do {
    1197           0 :       readToken(token);
    1198           0 :     } while (token.type_ == tokenComment);
    1199             :   } else {
    1200           0 :     readToken(token);
    1201             :   }
    1202           0 : }
    1203             : 
    1204           0 : bool OurReader::readToken(Token& token) {
    1205           0 :   skipSpaces();
    1206           0 :   token.start_ = current_;
    1207           0 :   Char c = getNextChar();
    1208           0 :   bool ok = true;
    1209           0 :   switch (c) {
    1210             :   case '{':
    1211           0 :     token.type_ = tokenObjectBegin;
    1212           0 :     break;
    1213             :   case '}':
    1214           0 :     token.type_ = tokenObjectEnd;
    1215           0 :     break;
    1216             :   case '[':
    1217           0 :     token.type_ = tokenArrayBegin;
    1218           0 :     break;
    1219             :   case ']':
    1220           0 :     token.type_ = tokenArrayEnd;
    1221           0 :     break;
    1222             :   case '"':
    1223           0 :     token.type_ = tokenString;
    1224           0 :     ok = readString();
    1225           0 :     break;
    1226             :   case '\'':
    1227           0 :     if (features_.allowSingleQuotes_) {
    1228           0 :     token.type_ = tokenString;
    1229           0 :     ok = readStringSingleQuote();
    1230           0 :     break;
    1231             :     } // else continue
    1232             :   case '/':
    1233           0 :     token.type_ = tokenComment;
    1234           0 :     ok = readComment();
    1235           0 :     break;
    1236             :   case '0':
    1237             :   case '1':
    1238             :   case '2':
    1239             :   case '3':
    1240             :   case '4':
    1241             :   case '5':
    1242             :   case '6':
    1243             :   case '7':
    1244             :   case '8':
    1245             :   case '9':
    1246           0 :     token.type_ = tokenNumber;
    1247           0 :     readNumber(false);
    1248           0 :     break;
    1249             :   case '-':
    1250           0 :     if (readNumber(true)) {
    1251           0 :       token.type_ = tokenNumber;
    1252             :     } else {
    1253           0 :       token.type_ = tokenNegInf;
    1254           0 :       ok = features_.allowSpecialFloats_ && match("nfinity", 7);
    1255             :     }
    1256           0 :     break;
    1257             :   case 't':
    1258           0 :     token.type_ = tokenTrue;
    1259           0 :     ok = match("rue", 3);
    1260           0 :     break;
    1261             :   case 'f':
    1262           0 :     token.type_ = tokenFalse;
    1263           0 :     ok = match("alse", 4);
    1264           0 :     break;
    1265             :   case 'n':
    1266           0 :     token.type_ = tokenNull;
    1267           0 :     ok = match("ull", 3);
    1268           0 :     break;
    1269             :   case 'N':
    1270           0 :     if (features_.allowSpecialFloats_) {
    1271           0 :       token.type_ = tokenNaN;
    1272           0 :       ok = match("aN", 2);
    1273             :     } else {
    1274           0 :       ok = false;
    1275             :     }
    1276           0 :     break;
    1277             :   case 'I':
    1278           0 :     if (features_.allowSpecialFloats_) {
    1279           0 :       token.type_ = tokenPosInf;
    1280           0 :       ok = match("nfinity", 7);
    1281             :     } else {
    1282           0 :       ok = false;
    1283             :     }
    1284           0 :     break;
    1285             :   case ',':
    1286           0 :     token.type_ = tokenArraySeparator;
    1287           0 :     break;
    1288             :   case ':':
    1289           0 :     token.type_ = tokenMemberSeparator;
    1290           0 :     break;
    1291             :   case 0:
    1292           0 :     token.type_ = tokenEndOfStream;
    1293           0 :     break;
    1294             :   default:
    1295           0 :     ok = false;
    1296           0 :     break;
    1297             :   }
    1298           0 :   if (!ok)
    1299           0 :     token.type_ = tokenError;
    1300           0 :   token.end_ = current_;
    1301           0 :   return true;
    1302             : }
    1303             : 
    1304           0 : void OurReader::skipSpaces() {
    1305           0 :   while (current_ != end_) {
    1306           0 :     Char c = *current_;
    1307           0 :     if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
    1308           0 :       ++current_;
    1309             :     else
    1310             :       break;
    1311             :   }
    1312           0 : }
    1313             : 
    1314           0 : bool OurReader::match(Location pattern, int patternLength) {
    1315           0 :   if (end_ - current_ < patternLength)
    1316           0 :     return false;
    1317           0 :   int index = patternLength;
    1318           0 :   while (index--)
    1319           0 :     if (current_[index] != pattern[index])
    1320           0 :       return false;
    1321           0 :   current_ += patternLength;
    1322           0 :   return true;
    1323             : }
    1324             : 
    1325           0 : bool OurReader::readComment() {
    1326           0 :   Location commentBegin = current_ - 1;
    1327           0 :   Char c = getNextChar();
    1328           0 :   bool successful = false;
    1329           0 :   if (c == '*')
    1330           0 :     successful = readCStyleComment();
    1331           0 :   else if (c == '/')
    1332           0 :     successful = readCppStyleComment();
    1333           0 :   if (!successful)
    1334           0 :     return false;
    1335             : 
    1336           0 :   if (collectComments_) {
    1337           0 :     CommentPlacement placement = commentBefore;
    1338           0 :     if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
    1339           0 :       if (c != '*' || !containsNewLine(commentBegin, current_))
    1340           0 :         placement = commentAfterOnSameLine;
    1341             :     }
    1342             : 
    1343           0 :     addComment(commentBegin, current_, placement);
    1344             :   }
    1345           0 :   return true;
    1346             : }
    1347             : 
    1348             : void
    1349           0 : OurReader::addComment(Location begin, Location end, CommentPlacement placement) {
    1350           0 :   assert(collectComments_);
    1351           0 :   const JSONCPP_STRING& normalized = normalizeEOL(begin, end);
    1352           0 :   if (placement == commentAfterOnSameLine) {
    1353           0 :     assert(lastValue_ != 0);
    1354           0 :     lastValue_->setComment(normalized, placement);
    1355             :   } else {
    1356           0 :     commentsBefore_ += normalized;
    1357             :   }
    1358           0 : }
    1359             : 
    1360           0 : bool OurReader::readCStyleComment() {
    1361           0 :   while ((current_ + 1) < end_) {
    1362           0 :     Char c = getNextChar();
    1363           0 :     if (c == '*' && *current_ == '/')
    1364           0 :       break;
    1365             :   }
    1366           0 :   return getNextChar() == '/';
    1367             : }
    1368             : 
    1369           0 : bool OurReader::readCppStyleComment() {
    1370           0 :   while (current_ != end_) {
    1371           0 :     Char c = getNextChar();
    1372           0 :     if (c == '\n')
    1373           0 :       break;
    1374           0 :     if (c == '\r') {
    1375             :       // Consume DOS EOL. It will be normalized in addComment.
    1376           0 :       if (current_ != end_ && *current_ == '\n')
    1377           0 :         getNextChar();
    1378             :       // Break on Moc OS 9 EOL.
    1379           0 :       break;
    1380             :     }
    1381             :   }
    1382           0 :   return true;
    1383             : }
    1384             : 
    1385           0 : bool OurReader::readNumber(bool checkInf) {
    1386           0 :   const char *p = current_;
    1387           0 :   if (checkInf && p != end_ && *p == 'I') {
    1388           0 :     current_ = ++p;
    1389           0 :     return false;
    1390             :   }
    1391           0 :   char c = '0'; // stopgap for already consumed character
    1392             :   // integral part
    1393           0 :   while (c >= '0' && c <= '9')
    1394           0 :     c = (current_ = p) < end_ ? *p++ : '\0';
    1395             :   // fractional part
    1396           0 :   if (c == '.') {
    1397           0 :     c = (current_ = p) < end_ ? *p++ : '\0';
    1398           0 :     while (c >= '0' && c <= '9')
    1399           0 :       c = (current_ = p) < end_ ? *p++ : '\0';
    1400             :   }
    1401             :   // exponential part
    1402           0 :   if (c == 'e' || c == 'E') {
    1403           0 :     c = (current_ = p) < end_ ? *p++ : '\0';
    1404           0 :     if (c == '+' || c == '-')
    1405           0 :       c = (current_ = p) < end_ ? *p++ : '\0';
    1406           0 :     while (c >= '0' && c <= '9')
    1407           0 :       c = (current_ = p) < end_ ? *p++ : '\0';
    1408             :   }
    1409           0 :   return true;
    1410             : }
    1411           0 : bool OurReader::readString() {
    1412           0 :   Char c = 0;
    1413           0 :   while (current_ != end_) {
    1414           0 :     c = getNextChar();
    1415           0 :     if (c == '\\')
    1416           0 :       getNextChar();
    1417           0 :     else if (c == '"')
    1418           0 :       break;
    1419             :   }
    1420           0 :   return c == '"';
    1421             : }
    1422             : 
    1423             : 
    1424           0 : bool OurReader::readStringSingleQuote() {
    1425           0 :   Char c = 0;
    1426           0 :   while (current_ != end_) {
    1427           0 :     c = getNextChar();
    1428           0 :     if (c == '\\')
    1429           0 :       getNextChar();
    1430           0 :     else if (c == '\'')
    1431           0 :       break;
    1432             :   }
    1433           0 :   return c == '\'';
    1434             : }
    1435             : 
    1436           0 : bool OurReader::readObject(Token& tokenStart) {
    1437             :   Token tokenName;
    1438           0 :   JSONCPP_STRING name;
    1439           0 :   Value init(objectValue);
    1440           0 :   currentValue().swapPayload(init);
    1441           0 :   currentValue().setOffsetStart(tokenStart.start_ - begin_);
    1442           0 :   while (readToken(tokenName)) {
    1443           0 :     bool initialTokenOk = true;
    1444           0 :     while (tokenName.type_ == tokenComment && initialTokenOk)
    1445           0 :       initialTokenOk = readToken(tokenName);
    1446           0 :     if (!initialTokenOk)
    1447           0 :       break;
    1448           0 :     if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
    1449           0 :       return true;
    1450           0 :     name.clear();
    1451           0 :     if (tokenName.type_ == tokenString) {
    1452           0 :       if (!decodeString(tokenName, name))
    1453           0 :         return recoverFromError(tokenObjectEnd);
    1454           0 :     } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
    1455           0 :       Value numberName;
    1456           0 :       if (!decodeNumber(tokenName, numberName))
    1457           0 :         return recoverFromError(tokenObjectEnd);
    1458           0 :       name = numberName.asString();
    1459             :     } else {
    1460             :       break;
    1461             :     }
    1462             : 
    1463             :     Token colon;
    1464           0 :     if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
    1465           0 :       return addErrorAndRecover(
    1466           0 :           "Missing ':' after object member name", colon, tokenObjectEnd);
    1467             :     }
    1468           0 :     if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");
    1469           0 :     if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
    1470           0 :       JSONCPP_STRING msg = "Duplicate key: '" + name + "'";
    1471             :       return addErrorAndRecover(
    1472           0 :           msg, tokenName, tokenObjectEnd);
    1473             :     }
    1474           0 :     Value& value = currentValue()[name];
    1475           0 :     nodes_.push(&value);
    1476           0 :     bool ok = readValue();
    1477           0 :     nodes_.pop();
    1478           0 :     if (!ok) // error already set
    1479           0 :       return recoverFromError(tokenObjectEnd);
    1480             : 
    1481             :     Token comma;
    1482           0 :     if (!readToken(comma) ||
    1483           0 :         (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
    1484           0 :          comma.type_ != tokenComment)) {
    1485           0 :       return addErrorAndRecover(
    1486           0 :           "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
    1487             :     }
    1488           0 :     bool finalizeTokenOk = true;
    1489           0 :     while (comma.type_ == tokenComment && finalizeTokenOk)
    1490           0 :       finalizeTokenOk = readToken(comma);
    1491           0 :     if (comma.type_ == tokenObjectEnd)
    1492           0 :       return true;
    1493             :   }
    1494           0 :   return addErrorAndRecover(
    1495           0 :       "Missing '}' or object member name", tokenName, tokenObjectEnd);
    1496             : }
    1497             : 
    1498           0 : bool OurReader::readArray(Token& tokenStart) {
    1499           0 :   Value init(arrayValue);
    1500           0 :   currentValue().swapPayload(init);
    1501           0 :   currentValue().setOffsetStart(tokenStart.start_ - begin_);
    1502           0 :   skipSpaces();
    1503           0 :   if (current_ != end_ && *current_ == ']') // empty array
    1504             :   {
    1505             :     Token endArray;
    1506           0 :     readToken(endArray);
    1507           0 :     return true;
    1508             :   }
    1509           0 :   int index = 0;
    1510             :   for (;;) {
    1511           0 :     Value& value = currentValue()[index++];
    1512           0 :     nodes_.push(&value);
    1513           0 :     bool ok = readValue();
    1514           0 :     nodes_.pop();
    1515           0 :     if (!ok) // error already set
    1516           0 :       return recoverFromError(tokenArrayEnd);
    1517             : 
    1518             :     Token token;
    1519             :     // Accept Comment after last item in the array.
    1520           0 :     ok = readToken(token);
    1521           0 :     while (token.type_ == tokenComment && ok) {
    1522           0 :       ok = readToken(token);
    1523             :     }
    1524             :     bool badTokenType =
    1525           0 :         (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
    1526           0 :     if (!ok || badTokenType) {
    1527           0 :       return addErrorAndRecover(
    1528           0 :           "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
    1529             :     }
    1530           0 :     if (token.type_ == tokenArrayEnd)
    1531           0 :       break;
    1532           0 :   }
    1533           0 :   return true;
    1534             : }
    1535             : 
    1536           0 : bool OurReader::decodeNumber(Token& token) {
    1537           0 :   Value decoded;
    1538           0 :   if (!decodeNumber(token, decoded))
    1539           0 :     return false;
    1540           0 :   currentValue().swapPayload(decoded);
    1541           0 :   currentValue().setOffsetStart(token.start_ - begin_);
    1542           0 :   currentValue().setOffsetLimit(token.end_ - begin_);
    1543           0 :   return true;
    1544             : }
    1545             : 
    1546           0 : bool OurReader::decodeNumber(Token& token, Value& decoded) {
    1547             :   // Attempts to parse the number as an integer. If the number is
    1548             :   // larger than the maximum supported value of an integer then
    1549             :   // we decode the number as a double.
    1550           0 :   Location current = token.start_;
    1551           0 :   bool isNegative = *current == '-';
    1552           0 :   if (isNegative)
    1553           0 :     ++current;
    1554             :   // TODO: Help the compiler do the div and mod at compile time or get rid of them.
    1555             :   Value::LargestUInt maxIntegerValue =
    1556           0 :       isNegative ? Value::LargestUInt(-Value::minLargestInt)
    1557           0 :                  : Value::maxLargestUInt;
    1558           0 :   Value::LargestUInt threshold = maxIntegerValue / 10;
    1559           0 :   Value::LargestUInt value = 0;
    1560           0 :   while (current < token.end_) {
    1561           0 :     Char c = *current++;
    1562           0 :     if (c < '0' || c > '9')
    1563           0 :       return decodeDouble(token, decoded);
    1564           0 :     Value::UInt digit(static_cast<Value::UInt>(c - '0'));
    1565           0 :     if (value >= threshold) {
    1566             :       // We've hit or exceeded the max value divided by 10 (rounded down). If
    1567             :       // a) we've only just touched the limit, b) this is the last digit, and
    1568             :       // c) it's small enough to fit in that rounding delta, we're okay.
    1569             :       // Otherwise treat this number as a double to avoid overflow.
    1570           0 :       if (value > threshold || current != token.end_ ||
    1571           0 :           digit > maxIntegerValue % 10) {
    1572           0 :         return decodeDouble(token, decoded);
    1573             :       }
    1574             :     }
    1575           0 :     value = value * 10 + digit;
    1576             :   }
    1577           0 :   if (isNegative)
    1578           0 :     decoded = -Value::LargestInt(value);
    1579           0 :   else if (value <= Value::LargestUInt(Value::maxInt))
    1580           0 :     decoded = Value::LargestInt(value);
    1581             :   else
    1582           0 :     decoded = value;
    1583           0 :   return true;
    1584             : }
    1585             : 
    1586           0 : bool OurReader::decodeDouble(Token& token) {
    1587           0 :   Value decoded;
    1588           0 :   if (!decodeDouble(token, decoded))
    1589           0 :     return false;
    1590           0 :   currentValue().swapPayload(decoded);
    1591           0 :   currentValue().setOffsetStart(token.start_ - begin_);
    1592           0 :   currentValue().setOffsetLimit(token.end_ - begin_);
    1593           0 :   return true;
    1594             : }
    1595             : 
    1596           0 : bool OurReader::decodeDouble(Token& token, Value& decoded) {
    1597           0 :   double value = 0;
    1598           0 :   const int bufferSize = 32;
    1599             :   int count;
    1600           0 :   ptrdiff_t const length = token.end_ - token.start_;
    1601             : 
    1602             :   // Sanity check to avoid buffer overflow exploits.
    1603           0 :   if (length < 0) {
    1604           0 :     return addError("Unable to parse token length", token);
    1605             :   }
    1606           0 :   size_t const ulength = static_cast<size_t>(length);
    1607             : 
    1608             :   // Avoid using a string constant for the format control string given to
    1609             :   // sscanf, as this can cause hard to debug crashes on OS X. See here for more
    1610             :   // info:
    1611             :   //
    1612             :   //     http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
    1613           0 :   char format[] = "%lf";
    1614             : 
    1615           0 :   if (length <= bufferSize) {
    1616             :     Char buffer[bufferSize + 1];
    1617           0 :     memcpy(buffer, token.start_, ulength);
    1618           0 :     buffer[length] = 0;
    1619           0 :     fixNumericLocaleInput(buffer, buffer + length);
    1620           0 :     count = sscanf(buffer, format, &value);
    1621             :   } else {
    1622           0 :     JSONCPP_STRING buffer(token.start_, token.end_);
    1623           0 :     count = sscanf(buffer.c_str(), format, &value);
    1624             :   }
    1625             : 
    1626           0 :   if (count != 1)
    1627           0 :     return addError("'" + JSONCPP_STRING(token.start_, token.end_) +
    1628             :                         "' is not a number.",
    1629           0 :                     token);
    1630           0 :   decoded = value;
    1631           0 :   return true;
    1632             : }
    1633             : 
    1634           0 : bool OurReader::decodeString(Token& token) {
    1635           0 :   JSONCPP_STRING decoded_string;
    1636           0 :   if (!decodeString(token, decoded_string))
    1637           0 :     return false;
    1638           0 :   Value decoded(decoded_string);
    1639           0 :   currentValue().swapPayload(decoded);
    1640           0 :   currentValue().setOffsetStart(token.start_ - begin_);
    1641           0 :   currentValue().setOffsetLimit(token.end_ - begin_);
    1642           0 :   return true;
    1643             : }
    1644             : 
    1645           0 : bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) {
    1646           0 :   decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
    1647           0 :   Location current = token.start_ + 1; // skip '"'
    1648           0 :   Location end = token.end_ - 1;       // do not include '"'
    1649           0 :   while (current != end) {
    1650           0 :     Char c = *current++;
    1651           0 :     if (c == '"')
    1652           0 :       break;
    1653           0 :     else if (c == '\\') {
    1654           0 :       if (current == end)
    1655           0 :         return addError("Empty escape sequence in string", token, current);
    1656           0 :       Char escape = *current++;
    1657           0 :       switch (escape) {
    1658             :       case '"':
    1659           0 :         decoded += '"';
    1660           0 :         break;
    1661             :       case '/':
    1662           0 :         decoded += '/';
    1663           0 :         break;
    1664             :       case '\\':
    1665           0 :         decoded += '\\';
    1666           0 :         break;
    1667             :       case 'b':
    1668           0 :         decoded += '\b';
    1669           0 :         break;
    1670             :       case 'f':
    1671           0 :         decoded += '\f';
    1672           0 :         break;
    1673             :       case 'n':
    1674           0 :         decoded += '\n';
    1675           0 :         break;
    1676             :       case 'r':
    1677           0 :         decoded += '\r';
    1678           0 :         break;
    1679             :       case 't':
    1680           0 :         decoded += '\t';
    1681           0 :         break;
    1682             :       case 'u': {
    1683             :         unsigned int unicode;
    1684           0 :         if (!decodeUnicodeCodePoint(token, current, end, unicode))
    1685           0 :           return false;
    1686           0 :         decoded += codePointToUTF8(unicode);
    1687           0 :       } break;
    1688             :       default:
    1689           0 :         return addError("Bad escape sequence in string", token, current);
    1690             :       }
    1691             :     } else {
    1692           0 :       decoded += c;
    1693             :     }
    1694             :   }
    1695           0 :   return true;
    1696             : }
    1697             : 
    1698           0 : bool OurReader::decodeUnicodeCodePoint(Token& token,
    1699             :                                     Location& current,
    1700             :                                     Location end,
    1701             :                                     unsigned int& unicode) {
    1702             : 
    1703           0 :   if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
    1704           0 :     return false;
    1705           0 :   if (unicode >= 0xD800 && unicode <= 0xDBFF) {
    1706             :     // surrogate pairs
    1707           0 :     if (end - current < 6)
    1708           0 :       return addError(
    1709             :           "additional six characters expected to parse unicode surrogate pair.",
    1710             :           token,
    1711           0 :           current);
    1712             :     unsigned int surrogatePair;
    1713           0 :     if (*(current++) == '\\' && *(current++) == 'u') {
    1714           0 :       if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
    1715           0 :         unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
    1716             :       } else
    1717           0 :         return false;
    1718             :     } else
    1719           0 :       return addError("expecting another \\u token to begin the second half of "
    1720             :                       "a unicode surrogate pair",
    1721             :                       token,
    1722           0 :                       current);
    1723             :   }
    1724           0 :   return true;
    1725             : }
    1726             : 
    1727           0 : bool OurReader::decodeUnicodeEscapeSequence(Token& token,
    1728             :                                          Location& current,
    1729             :                                          Location end,
    1730             :                                          unsigned int& ret_unicode) {
    1731           0 :   if (end - current < 4)
    1732           0 :     return addError(
    1733             :         "Bad unicode escape sequence in string: four digits expected.",
    1734             :         token,
    1735           0 :         current);
    1736           0 :   int unicode = 0;
    1737           0 :   for (int index = 0; index < 4; ++index) {
    1738           0 :     Char c = *current++;
    1739           0 :     unicode *= 16;
    1740           0 :     if (c >= '0' && c <= '9')
    1741           0 :       unicode += c - '0';
    1742           0 :     else if (c >= 'a' && c <= 'f')
    1743           0 :       unicode += c - 'a' + 10;
    1744           0 :     else if (c >= 'A' && c <= 'F')
    1745           0 :       unicode += c - 'A' + 10;
    1746             :     else
    1747           0 :       return addError(
    1748             :           "Bad unicode escape sequence in string: hexadecimal digit expected.",
    1749             :           token,
    1750           0 :           current);
    1751             :   }
    1752           0 :   ret_unicode = static_cast<unsigned int>(unicode);
    1753           0 :   return true;
    1754             : }
    1755             : 
    1756             : bool
    1757           0 : OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) {
    1758           0 :   ErrorInfo info;
    1759           0 :   info.token_ = token;
    1760           0 :   info.message_ = message;
    1761           0 :   info.extra_ = extra;
    1762           0 :   errors_.push_back(info);
    1763           0 :   return false;
    1764             : }
    1765             : 
    1766           0 : bool OurReader::recoverFromError(TokenType skipUntilToken) {
    1767           0 :   size_t errorCount = errors_.size();
    1768             :   Token skip;
    1769             :   for (;;) {
    1770           0 :     if (!readToken(skip))
    1771           0 :       errors_.resize(errorCount); // discard errors caused by recovery
    1772           0 :     if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
    1773             :       break;
    1774             :   }
    1775           0 :   errors_.resize(errorCount);
    1776           0 :   return false;
    1777             : }
    1778             : 
    1779           0 : bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message,
    1780             :                                 Token& token,
    1781             :                                 TokenType skipUntilToken) {
    1782           0 :   addError(message, token);
    1783           0 :   return recoverFromError(skipUntilToken);
    1784             : }
    1785             : 
    1786           0 : Value& OurReader::currentValue() { return *(nodes_.top()); }
    1787             : 
    1788           0 : OurReader::Char OurReader::getNextChar() {
    1789           0 :   if (current_ == end_)
    1790           0 :     return 0;
    1791           0 :   return *current_++;
    1792             : }
    1793             : 
    1794           0 : void OurReader::getLocationLineAndColumn(Location location,
    1795             :                                       int& line,
    1796             :                                       int& column) const {
    1797           0 :   Location current = begin_;
    1798           0 :   Location lastLineStart = current;
    1799           0 :   line = 0;
    1800           0 :   while (current < location && current != end_) {
    1801           0 :     Char c = *current++;
    1802           0 :     if (c == '\r') {
    1803           0 :       if (*current == '\n')
    1804           0 :         ++current;
    1805           0 :       lastLineStart = current;
    1806           0 :       ++line;
    1807           0 :     } else if (c == '\n') {
    1808           0 :       lastLineStart = current;
    1809           0 :       ++line;
    1810             :     }
    1811             :   }
    1812             :   // column & line start at 1
    1813           0 :   column = int(location - lastLineStart) + 1;
    1814           0 :   ++line;
    1815           0 : }
    1816             : 
    1817           0 : JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const {
    1818             :   int line, column;
    1819           0 :   getLocationLineAndColumn(location, line, column);
    1820             :   char buffer[18 + 16 + 16 + 1];
    1821           0 :   snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
    1822           0 :   return buffer;
    1823             : }
    1824             : 
    1825           0 : JSONCPP_STRING OurReader::getFormattedErrorMessages() const {
    1826           0 :   JSONCPP_STRING formattedMessage;
    1827           0 :   for (Errors::const_iterator itError = errors_.begin();
    1828           0 :        itError != errors_.end();
    1829             :        ++itError) {
    1830           0 :     const ErrorInfo& error = *itError;
    1831             :     formattedMessage +=
    1832           0 :         "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
    1833           0 :     formattedMessage += "  " + error.message_ + "\n";
    1834           0 :     if (error.extra_)
    1835             :       formattedMessage +=
    1836           0 :           "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
    1837             :   }
    1838           0 :   return formattedMessage;
    1839             : }
    1840             : 
    1841           0 : std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
    1842           0 :   std::vector<OurReader::StructuredError> allErrors;
    1843           0 :   for (Errors::const_iterator itError = errors_.begin();
    1844           0 :        itError != errors_.end();
    1845             :        ++itError) {
    1846           0 :     const ErrorInfo& error = *itError;
    1847           0 :     OurReader::StructuredError structured;
    1848           0 :     structured.offset_start = error.token_.start_ - begin_;
    1849           0 :     structured.offset_limit = error.token_.end_ - begin_;
    1850           0 :     structured.message = error.message_;
    1851           0 :     allErrors.push_back(structured);
    1852             :   }
    1853           0 :   return allErrors;
    1854             : }
    1855             : 
    1856           0 : bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) {
    1857           0 :   ptrdiff_t length = end_ - begin_;
    1858           0 :   if(value.getOffsetStart() > length
    1859           0 :     || value.getOffsetLimit() > length)
    1860           0 :     return false;
    1861             :   Token token;
    1862           0 :   token.type_ = tokenError;
    1863           0 :   token.start_ = begin_ + value.getOffsetStart();
    1864           0 :   token.end_ = end_ + value.getOffsetLimit();
    1865           0 :   ErrorInfo info;
    1866           0 :   info.token_ = token;
    1867           0 :   info.message_ = message;
    1868           0 :   info.extra_ = 0;
    1869           0 :   errors_.push_back(info);
    1870           0 :   return true;
    1871             : }
    1872             : 
    1873           0 : bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) {
    1874           0 :   ptrdiff_t length = end_ - begin_;
    1875           0 :   if(value.getOffsetStart() > length
    1876           0 :     || value.getOffsetLimit() > length
    1877           0 :     || extra.getOffsetLimit() > length)
    1878           0 :     return false;
    1879             :   Token token;
    1880           0 :   token.type_ = tokenError;
    1881           0 :   token.start_ = begin_ + value.getOffsetStart();
    1882           0 :   token.end_ = begin_ + value.getOffsetLimit();
    1883           0 :   ErrorInfo info;
    1884           0 :   info.token_ = token;
    1885           0 :   info.message_ = message;
    1886           0 :   info.extra_ = begin_ + extra.getOffsetStart();
    1887           0 :   errors_.push_back(info);
    1888           0 :   return true;
    1889             : }
    1890             : 
    1891           0 : bool OurReader::good() const {
    1892           0 :   return !errors_.size();
    1893             : }
    1894             : 
    1895             : 
    1896           0 : class OurCharReader : public CharReader {
    1897             :   bool const collectComments_;
    1898             :   OurReader reader_;
    1899             : public:
    1900           0 :   OurCharReader(
    1901             :     bool collectComments,
    1902             :     OurFeatures const& features)
    1903           0 :   : collectComments_(collectComments)
    1904           0 :   , reader_(features)
    1905           0 :   {}
    1906           0 :   bool parse(
    1907             :       char const* beginDoc, char const* endDoc,
    1908             :       Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE {
    1909           0 :     bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
    1910           0 :     if (errs) {
    1911           0 :       *errs = reader_.getFormattedErrorMessages();
    1912             :     }
    1913           0 :     return ok;
    1914             :   }
    1915             : };
    1916             : 
    1917           0 : CharReaderBuilder::CharReaderBuilder()
    1918             : {
    1919           0 :   setDefaults(&settings_);
    1920           0 : }
    1921           0 : CharReaderBuilder::~CharReaderBuilder()
    1922           0 : {}
    1923           0 : CharReader* CharReaderBuilder::newCharReader() const
    1924             : {
    1925           0 :   bool collectComments = settings_["collectComments"].asBool();
    1926           0 :   OurFeatures features = OurFeatures::all();
    1927           0 :   features.allowComments_ = settings_["allowComments"].asBool();
    1928           0 :   features.strictRoot_ = settings_["strictRoot"].asBool();
    1929           0 :   features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
    1930           0 :   features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
    1931           0 :   features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
    1932           0 :   features.stackLimit_ = settings_["stackLimit"].asInt();
    1933           0 :   features.failIfExtra_ = settings_["failIfExtra"].asBool();
    1934           0 :   features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
    1935           0 :   features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
    1936           0 :   return new OurCharReader(collectComments, features);
    1937             : }
    1938           0 : static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys)
    1939             : {
    1940           0 :   valid_keys->clear();
    1941           0 :   valid_keys->insert("collectComments");
    1942           0 :   valid_keys->insert("allowComments");
    1943           0 :   valid_keys->insert("strictRoot");
    1944           0 :   valid_keys->insert("allowDroppedNullPlaceholders");
    1945           0 :   valid_keys->insert("allowNumericKeys");
    1946           0 :   valid_keys->insert("allowSingleQuotes");
    1947           0 :   valid_keys->insert("stackLimit");
    1948           0 :   valid_keys->insert("failIfExtra");
    1949           0 :   valid_keys->insert("rejectDupKeys");
    1950           0 :   valid_keys->insert("allowSpecialFloats");
    1951           0 : }
    1952           0 : bool CharReaderBuilder::validate(Json::Value* invalid) const
    1953             : {
    1954           0 :   Json::Value my_invalid;
    1955           0 :   if (!invalid) invalid = &my_invalid;  // so we do not need to test for NULL
    1956           0 :   Json::Value& inv = *invalid;
    1957           0 :   std::set<JSONCPP_STRING> valid_keys;
    1958           0 :   getValidReaderKeys(&valid_keys);
    1959           0 :   Value::Members keys = settings_.getMemberNames();
    1960           0 :   size_t n = keys.size();
    1961           0 :   for (size_t i = 0; i < n; ++i) {
    1962           0 :     JSONCPP_STRING const& key = keys[i];
    1963           0 :     if (valid_keys.find(key) == valid_keys.end()) {
    1964           0 :       inv[key] = settings_[key];
    1965             :     }
    1966             :   }
    1967           0 :   return 0u == inv.size();
    1968             : }
    1969           0 : Value& CharReaderBuilder::operator[](JSONCPP_STRING key)
    1970             : {
    1971           0 :   return settings_[key];
    1972             : }
    1973             : // static
    1974           0 : void CharReaderBuilder::strictMode(Json::Value* settings)
    1975             : {
    1976             : //! [CharReaderBuilderStrictMode]
    1977           0 :   (*settings)["allowComments"] = false;
    1978           0 :   (*settings)["strictRoot"] = true;
    1979           0 :   (*settings)["allowDroppedNullPlaceholders"] = false;
    1980           0 :   (*settings)["allowNumericKeys"] = false;
    1981           0 :   (*settings)["allowSingleQuotes"] = false;
    1982           0 :   (*settings)["stackLimit"] = 1000;
    1983           0 :   (*settings)["failIfExtra"] = true;
    1984           0 :   (*settings)["rejectDupKeys"] = true;
    1985           0 :   (*settings)["allowSpecialFloats"] = false;
    1986             : //! [CharReaderBuilderStrictMode]
    1987           0 : }
    1988             : // static
    1989           0 : void CharReaderBuilder::setDefaults(Json::Value* settings)
    1990             : {
    1991             : //! [CharReaderBuilderDefaults]
    1992           0 :   (*settings)["collectComments"] = true;
    1993           0 :   (*settings)["allowComments"] = true;
    1994           0 :   (*settings)["strictRoot"] = false;
    1995           0 :   (*settings)["allowDroppedNullPlaceholders"] = false;
    1996           0 :   (*settings)["allowNumericKeys"] = false;
    1997           0 :   (*settings)["allowSingleQuotes"] = false;
    1998           0 :   (*settings)["stackLimit"] = 1000;
    1999           0 :   (*settings)["failIfExtra"] = false;
    2000           0 :   (*settings)["rejectDupKeys"] = false;
    2001           0 :   (*settings)["allowSpecialFloats"] = false;
    2002             : //! [CharReaderBuilderDefaults]
    2003           0 : }
    2004             : 
    2005             : //////////////////////////////////
    2006             : // global functions
    2007             : 
    2008           0 : bool parseFromStream(
    2009             :     CharReader::Factory const& fact, JSONCPP_ISTREAM& sin,
    2010             :     Value* root, JSONCPP_STRING* errs)
    2011             : {
    2012           0 :   JSONCPP_OSTRINGSTREAM ssin;
    2013           0 :   ssin << sin.rdbuf();
    2014           0 :   JSONCPP_STRING doc = ssin.str();
    2015           0 :   char const* begin = doc.data();
    2016           0 :   char const* end = begin + doc.size();
    2017             :   // Note that we do not actually need a null-terminator.
    2018           0 :   CharReaderPtr const reader(fact.newCharReader());
    2019           0 :   return reader->parse(begin, end, root, errs);
    2020             : }
    2021             : 
    2022           0 : JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) {
    2023           0 :   CharReaderBuilder b;
    2024           0 :   JSONCPP_STRING errs;
    2025           0 :   bool ok = parseFromStream(b, sin, &root, &errs);
    2026           0 :   if (!ok) {
    2027           0 :     fprintf(stderr,
    2028             :             "Error from reader: %s",
    2029           0 :             errs.c_str());
    2030             : 
    2031           0 :     throwRuntimeError(errs);
    2032             :   }
    2033           0 :   return sin;
    2034             : }
    2035             : 
    2036             : } // namespace Json

Generated by: LCOV version 1.13