7 #if !defined(JSON_IS_AMALGAMATION) 
   12 #endif // if !defined(JSON_IS_AMALGAMATION) 
   25 #if __cplusplus >= 201103L 
   28 #define sscanf std::sscanf 
   34 #if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) 
   35 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 
   36 #endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 
   41 #pragma warning(disable : 4996) 
   46 #if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) 
   47 #define JSONCPP_DEPRECATED_STACK_LIMIT 1000 
   55 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) 
   80 bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
 
   81   return std::any_of(begin, end, [](
char b) { 
return b == 
'\n' || b == 
'\r'; });
 
   87 Reader::Reader() : features_(Features::all()) {}
 
   89 Reader::Reader(
const Features& features) : features_(features) {}
 
   91 bool Reader::parse(
const std::string& document, Value& root,
 
   92                    bool collectComments) {
 
   93   document_.assign(document.begin(), document.end());
 
   94   const char* begin = document_.c_str();
 
   95   const char* end = begin + document_.length();
 
   96   return parse(begin, end, root, collectComments);
 
   99 bool Reader::parse(std::istream& is, Value& root, 
bool collectComments) {
 
  108   std::getline(is, doc, 
static_cast<char> EOF);
 
  109   return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
 
  112 bool Reader::parse(
const char* beginDoc, 
const char* endDoc, Value& root,
 
  113                    bool collectComments) {
 
  114   if (!features_.allowComments_) {
 
  115     collectComments = 
false;
 
  120   collectComments_ = collectComments;
 
  122   lastValueEnd_ = 
nullptr;
 
  123   lastValue_ = 
nullptr;
 
  124   commentsBefore_.clear();
 
  126   while (!nodes_.empty())
 
  130   bool successful = readValue();
 
  132   skipCommentTokens(token);
 
  133   if (collectComments_ && !commentsBefore_.empty())
 
  135   if (features_.strictRoot_) {
 
  136     if (!root.isArray() && !root.isObject()) {
 
  139       token.type_ = tokenError;
 
  140       token.start_ = beginDoc;
 
  143           "A valid JSON document must be either an array or an object value.",
 
  151 bool Reader::readValue() {
 
  157     throwRuntimeError(
"Exceeded stackLimit in readValue().");
 
  160   skipCommentTokens(token);
 
  161   bool successful = 
true;
 
  163   if (collectComments_ && !commentsBefore_.empty()) {
 
  165     commentsBefore_.clear();
 
  168   switch (token.type_) {
 
  169   case tokenObjectBegin:
 
  170     successful = readObject(token);
 
  171     currentValue().setOffsetLimit(current_ - begin_);
 
  173   case tokenArrayBegin:
 
  174     successful = readArray(token);
 
  175     currentValue().setOffsetLimit(current_ - begin_);
 
  178     successful = decodeNumber(token);
 
  181     successful = decodeString(token);
 
  185     currentValue().swapPayload(v);
 
  186     currentValue().setOffsetStart(token.start_ - begin_);
 
  187     currentValue().setOffsetLimit(token.end_ - begin_);
 
  191     currentValue().swapPayload(v);
 
  192     currentValue().setOffsetStart(token.start_ - begin_);
 
  193     currentValue().setOffsetLimit(token.end_ - begin_);
 
  197     currentValue().swapPayload(v);
 
  198     currentValue().setOffsetStart(token.start_ - begin_);
 
  199     currentValue().setOffsetLimit(token.end_ - begin_);
 
  201   case tokenArraySeparator:
 
  204     if (features_.allowDroppedNullPlaceholders_) {
 
  209       currentValue().swapPayload(v);
 
  210       currentValue().setOffsetStart(current_ - begin_ - 1);
 
  211       currentValue().setOffsetLimit(current_ - begin_);
 
  215     currentValue().setOffsetStart(token.start_ - begin_);
 
  216     currentValue().setOffsetLimit(token.end_ - begin_);
 
  217     return addError(
"Syntax error: value, object or array expected.", token);
 
  220   if (collectComments_) {
 
  221     lastValueEnd_ = current_;
 
  222     lastValue_ = ¤tValue();
 
  228 void Reader::skipCommentTokens(Token& token) {
 
  229   if (features_.allowComments_) {
 
  232     } 
while (token.type_ == tokenComment);
 
  238 bool Reader::readToken(Token& token) {
 
  240   token.start_ = current_;
 
  241   Char c = getNextChar();
 
  245     token.type_ = tokenObjectBegin;
 
  248     token.type_ = tokenObjectEnd;
 
  251     token.type_ = tokenArrayBegin;
 
  254     token.type_ = tokenArrayEnd;
 
  257     token.type_ = tokenString;
 
  261     token.type_ = tokenComment;
 
  275     token.type_ = tokenNumber;
 
  279     token.type_ = tokenTrue;
 
  280     ok = match(
"rue", 3);
 
  283     token.type_ = tokenFalse;
 
  284     ok = match(
"alse", 4);
 
  287     token.type_ = tokenNull;
 
  288     ok = match(
"ull", 3);
 
  291     token.type_ = tokenArraySeparator;
 
  294     token.type_ = tokenMemberSeparator;
 
  297     token.type_ = tokenEndOfStream;
 
  304     token.type_ = tokenError;
 
  305   token.end_ = current_;
 
  309 void Reader::skipSpaces() {
 
  310   while (current_ != end_) {
 
  312     if (c == 
' ' || c == 
'\t' || c == 
'\r' || c == 
'\n')
 
  319 bool Reader::match(
const Char* pattern, 
int patternLength) {
 
  320   if (end_ - current_ < patternLength)
 
  322   int index = patternLength;
 
  324     if (current_[index] != pattern[index])
 
  326   current_ += patternLength;
 
  330 bool Reader::readComment() {
 
  331   Location commentBegin = current_ - 1;
 
  332   Char c = getNextChar();
 
  333   bool successful = 
false;
 
  335     successful = readCStyleComment();
 
  337     successful = readCppStyleComment();
 
  341   if (collectComments_) {
 
  343     if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
 
  344       if (c != 
'*' || !containsNewLine(commentBegin, current_))
 
  348     addComment(commentBegin, current_, placement);
 
  353 String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {
 
  355   normalized.reserve(
static_cast<size_t>(end - begin));
 
  356   Reader::Location current = begin;
 
  357   while (current != end) {
 
  360       if (current != end && *current == 
'\n')
 
  372 void Reader::addComment(Location begin, Location end,
 
  374   assert(collectComments_);
 
  375   const String& normalized = normalizeEOL(begin, end);
 
  377     assert(lastValue_ != 
nullptr);
 
  378     lastValue_->setComment(normalized, placement);
 
  380     commentsBefore_ += normalized;
 
  384 bool Reader::readCStyleComment() {
 
  385   while ((current_ + 1) < end_) {
 
  386     Char c = getNextChar();
 
  387     if (c == 
'*' && *current_ == 
'/')
 
  390   return getNextChar() == 
'/';
 
  393 bool Reader::readCppStyleComment() {
 
  394   while (current_ != end_) {
 
  395     Char c = getNextChar();
 
  400       if (current_ != end_ && *current_ == 
'\n')
 
  409 void Reader::readNumber() {
 
  410   Location p = current_;
 
  413   while (c >= 
'0' && c <= 
'9')
 
  414     c = (current_ = p) < end_ ? *p++ : 
'\0';
 
  417     c = (current_ = p) < end_ ? *p++ : 
'\0';
 
  418     while (c >= 
'0' && c <= 
'9')
 
  419       c = (current_ = p) < end_ ? *p++ : 
'\0';
 
  422   if (c == 
'e' || c == 
'E') {
 
  423     c = (current_ = p) < end_ ? *p++ : 
'\0';
 
  424     if (c == 
'+' || c == 
'-')
 
  425       c = (current_ = p) < end_ ? *p++ : 
'\0';
 
  426     while (c >= 
'0' && c <= 
'9')
 
  427       c = (current_ = p) < end_ ? *p++ : 
'\0';
 
  431 bool Reader::readString() {
 
  433   while (current_ != end_) {
 
  443 bool Reader::readObject(Token& token) {
 
  447   currentValue().swapPayload(init);
 
  448   currentValue().setOffsetStart(token.start_ - begin_);
 
  449   while (readToken(tokenName)) {
 
  450     bool initialTokenOk = 
true;
 
  451     while (tokenName.type_ == tokenComment && initialTokenOk)
 
  452       initialTokenOk = readToken(tokenName);
 
  455     if (tokenName.type_ == tokenObjectEnd && name.empty()) 
 
  458     if (tokenName.type_ == tokenString) {
 
  459       if (!decodeString(tokenName, name))
 
  460         return recoverFromError(tokenObjectEnd);
 
  461     } 
else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
 
  463       if (!decodeNumber(tokenName, numberName))
 
  464         return recoverFromError(tokenObjectEnd);
 
  465       name = numberName.asString();
 
  471     if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
 
  472       return addErrorAndRecover(
"Missing ':' after object member name", colon,
 
  475     Value& value = currentValue()[name];
 
  477     bool ok = readValue();
 
  480       return recoverFromError(tokenObjectEnd);
 
  483     if (!readToken(comma) ||
 
  484         (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
 
  485          comma.type_ != tokenComment)) {
 
  486       return addErrorAndRecover(
"Missing ',' or '}' in object declaration",
 
  487                                 comma, tokenObjectEnd);
 
  489     bool finalizeTokenOk = 
true;
 
  490     while (comma.type_ == tokenComment && finalizeTokenOk)
 
  491       finalizeTokenOk = readToken(comma);
 
  492     if (comma.type_ == tokenObjectEnd)
 
  495   return addErrorAndRecover(
"Missing '}' or object member name", tokenName,
 
  499 bool Reader::readArray(Token& token) {
 
  501   currentValue().swapPayload(init);
 
  502   currentValue().setOffsetStart(token.start_ - begin_);
 
  504   if (current_ != end_ && *current_ == 
']') 
 
  512     Value& value = currentValue()[index++];
 
  514     bool ok = readValue();
 
  517       return recoverFromError(tokenArrayEnd);
 
  521     ok = readToken(currentToken);
 
  522     while (currentToken.type_ == tokenComment && ok) {
 
  523       ok = readToken(currentToken);
 
  525     bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
 
  526                          currentToken.type_ != tokenArrayEnd);
 
  527     if (!ok || badTokenType) {
 
  528       return addErrorAndRecover(
"Missing ',' or ']' in array declaration",
 
  529                                 currentToken, tokenArrayEnd);
 
  531     if (currentToken.type_ == tokenArrayEnd)
 
  537 bool Reader::decodeNumber(Token& token) {
 
  539   if (!decodeNumber(token, decoded))
 
  541   currentValue().swapPayload(decoded);
 
  542   currentValue().setOffsetStart(token.start_ - begin_);
 
  543   currentValue().setOffsetLimit(token.end_ - begin_);
 
  547 bool Reader::decodeNumber(Token& token, Value& decoded) {
 
  551   Location current = token.start_;
 
  552   bool isNegative = *current == 
'-';
 
  562   while (current < token.end_) {
 
  564     if (c < '0' || c > 
'9')
 
  565       return decodeDouble(token, decoded);
 
  567     if (value >= threshold) {
 
  572       if (value > threshold || current != token.end_ ||
 
  573           digit > maxIntegerValue % 10) {
 
  574         return decodeDouble(token, decoded);
 
  577     value = value * 10 + digit;
 
  579   if (isNegative && value == maxIntegerValue)
 
  590 bool Reader::decodeDouble(Token& token) {
 
  592   if (!decodeDouble(token, decoded))
 
  594   currentValue().swapPayload(decoded);
 
  595   currentValue().setOffsetStart(token.start_ - begin_);
 
  596   currentValue().setOffsetLimit(token.end_ - begin_);
 
  600 bool Reader::decodeDouble(Token& token, Value& decoded) {
 
  602   String buffer(token.start_, token.end_);
 
  606         "'" + 
String(token.start_, token.end_) + 
"' is not a number.", token);
 
  611 bool Reader::decodeString(Token& token) {
 
  613   if (!decodeString(token, decoded_string))
 
  615   Value decoded(decoded_string);
 
  616   currentValue().swapPayload(decoded);
 
  617   currentValue().setOffsetStart(token.start_ - begin_);
 
  618   currentValue().setOffsetLimit(token.end_ - begin_);
 
  622 bool Reader::decodeString(Token& token, 
String& decoded) {
 
  623   decoded.reserve(
static_cast<size_t>(token.end_ - token.start_ - 2));
 
  624   Location current = token.start_ + 1; 
 
  625   Location end = token.end_ - 1;       
 
  626   while (current != end) {
 
  632         return addError(
"Empty escape sequence in string", token, current);
 
  633       Char escape = *current++;
 
  660         unsigned int unicode;
 
  661         if (!decodeUnicodeCodePoint(token, current, end, unicode))
 
  666         return addError(
"Bad escape sequence in string", token, current);
 
  675 bool Reader::decodeUnicodeCodePoint(Token& token, Location& current,
 
  676                                     Location end, 
unsigned int& unicode) {
 
  678   if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
 
  680   if (unicode >= 0xD800 && unicode <= 0xDBFF) {
 
  682     if (end - current < 6)
 
  684           "additional six characters expected to parse unicode surrogate pair.",
 
  686     if (*(current++) == 
'\\' && *(current++) == 
'u') {
 
  687       unsigned int surrogatePair;
 
  688       if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
 
  689         unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
 
  693       return addError(
"expecting another \\u token to begin the second half of " 
  694                       "a unicode surrogate pair",
 
  700 bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current,
 
  702                                          unsigned int& ret_unicode) {
 
  703   if (end - current < 4)
 
  705         "Bad unicode escape sequence in string: four digits expected.", token,
 
  708   for (
int index = 0; index < 4; ++index) {
 
  711     if (c >= 
'0' && c <= 
'9')
 
  713     else if (c >= 
'a' && c <= 
'f')
 
  714       unicode += c - 
'a' + 10;
 
  715     else if (c >= 
'A' && c <= 
'F')
 
  716       unicode += c - 
'A' + 10;
 
  719           "Bad unicode escape sequence in string: hexadecimal digit expected.",
 
  722   ret_unicode = 
static_cast<unsigned int>(unicode);
 
  726 bool Reader::addError(
const String& message, Token& token, Location extra) {
 
  729   info.message_ = message;
 
  731   errors_.push_back(info);
 
  735 bool Reader::recoverFromError(TokenType skipUntilToken) {
 
  736   size_t const errorCount = errors_.size();
 
  739     if (!readToken(skip))
 
  740       errors_.resize(errorCount); 
 
  741     if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
 
  744   errors_.resize(errorCount);
 
  748 bool Reader::addErrorAndRecover(
const String& message, Token& token,
 
  749                                 TokenType skipUntilToken) {
 
  750   addError(message, token);
 
  751   return recoverFromError(skipUntilToken);
 
  754 Value& Reader::currentValue() { 
return *(nodes_.top()); }
 
  756 Reader::Char Reader::getNextChar() {
 
  757   if (current_ == end_)
 
  762 void Reader::getLocationLineAndColumn(Location location, 
int& line,
 
  764   Location current = begin_;
 
  765   Location lastLineStart = current;
 
  767   while (current < location && current != end_) {
 
  770       if (*current == 
'\n')
 
  772       lastLineStart = current;
 
  774     } 
else if (c == 
'\n') {
 
  775       lastLineStart = current;
 
  780   column = int(location - lastLineStart) + 1;
 
  784 String Reader::getLocationLineAndColumn(Location location)
 const {
 
  786   getLocationLineAndColumn(location, line, column);
 
  787   char buffer[18 + 16 + 16 + 1];
 
  788   jsoncpp_snprintf(buffer, 
sizeof(buffer), 
"Line %d, Column %d", line, column);
 
  793 String Reader::getFormatedErrorMessages()
 const {
 
  794   return getFormattedErrorMessages();
 
  797 String Reader::getFormattedErrorMessages()
 const {
 
  799   for (
const auto& error : errors_) {
 
  801         "* " + getLocationLineAndColumn(error.token_.start_) + 
"\n";
 
  802     formattedMessage += 
"  " + error.message_ + 
"\n";
 
  805           "See " + getLocationLineAndColumn(error.extra_) + 
" for detail.\n";
 
  807   return formattedMessage;
 
  810 std::vector<Reader::StructuredError> Reader::getStructuredErrors()
 const {
 
  811   std::vector<Reader::StructuredError> allErrors;
 
  812   for (
const auto& error : errors_) {
 
  813     Reader::StructuredError structured;
 
  814     structured.offset_start = error.token_.start_ - begin_;
 
  815     structured.offset_limit = error.token_.end_ - begin_;
 
  816     structured.message = error.message_;
 
  817     allErrors.push_back(structured);
 
  822 bool Reader::pushError(
const Value& value, 
const String& message) {
 
  823   ptrdiff_t 
const length = end_ - begin_;
 
  824   if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
 
  827   token.type_ = tokenError;
 
  828   token.start_ = begin_ + value.getOffsetStart();
 
  829   token.end_ = begin_ + value.getOffsetLimit();
 
  832   info.message_ = message;
 
  833   info.extra_ = 
nullptr;
 
  834   errors_.push_back(info);
 
  838 bool Reader::pushError(
const Value& value, 
const String& message,
 
  839                        const Value& extra) {
 
  840   ptrdiff_t 
const length = end_ - begin_;
 
  841   if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
 
  842       extra.getOffsetLimit() > length)
 
  845   token.type_ = tokenError;
 
  846   token.start_ = begin_ + value.getOffsetStart();
 
  847   token.end_ = begin_ + value.getOffsetLimit();
 
  850   info.message_ = message;
 
  851   info.extra_ = begin_ + extra.getOffsetStart();
 
  852   errors_.push_back(info);
 
  856 bool Reader::good()
 const { 
return errors_.empty(); }
 
  862   static OurFeatures all();
 
  864   bool allowTrailingCommas_;
 
  866   bool allowDroppedNullPlaceholders_;
 
  867   bool allowNumericKeys_;
 
  868   bool allowSingleQuotes_;
 
  871   bool allowSpecialFloats_;
 
  876 OurFeatures OurFeatures::all() { 
return {}; }
 
  886   using Location = 
const Char*;
 
  887   struct StructuredError {
 
  888     ptrdiff_t offset_start;
 
  889     ptrdiff_t offset_limit;
 
  893   explicit OurReader(OurFeatures 
const& features);
 
  894   bool parse(
const char* beginDoc, 
const char* endDoc, Value& root,
 
  895              bool collectComments = 
true);
 
  896   String getFormattedErrorMessages() 
const;
 
  897   std::vector<StructuredError> getStructuredErrors() 
const;
 
  900   OurReader(OurReader 
const&);      
 
  901   void operator=(OurReader 
const&); 
 
  904     tokenEndOfStream = 0,
 
  918     tokenMemberSeparator,
 
  937   using Errors = std::deque<ErrorInfo>;
 
  939   bool readToken(Token& token);
 
  941   void skipBom(
bool skipBom);
 
  942   bool match(
const Char* pattern, 
int patternLength);
 
  944   bool readCStyleComment(
bool* containsNewLineResult);
 
  945   bool readCppStyleComment();
 
  947   bool readStringSingleQuote();
 
  948   bool readNumber(
bool checkInf);
 
  950   bool readObject(Token& token);
 
  951   bool readArray(Token& token);
 
  952   bool decodeNumber(Token& token);
 
  953   bool decodeNumber(Token& token, Value& decoded);
 
  954   bool decodeString(Token& token);
 
  955   bool decodeString(Token& token, 
String& decoded);
 
  956   bool decodeDouble(Token& token);
 
  957   bool decodeDouble(Token& token, Value& decoded);
 
  958   bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
 
  959                               unsigned int& unicode);
 
  960   bool decodeUnicodeEscapeSequence(Token& token, Location& current,
 
  961                                    Location end, 
unsigned int& unicode);
 
  962   bool addError(
const String& message, Token& token, Location extra = 
nullptr);
 
  963   bool recoverFromError(TokenType skipUntilToken);
 
  964   bool addErrorAndRecover(
const String& message, Token& token,
 
  965                           TokenType skipUntilToken);
 
  966   void skipUntilSpace();
 
  967   Value& currentValue();
 
  969   void getLocationLineAndColumn(Location location, 
int& line,
 
  971   String getLocationLineAndColumn(Location location) 
const;
 
  973   void skipCommentTokens(Token& token);
 
  975   static String normalizeEOL(Location begin, Location end);
 
  976   static bool containsNewLine(Location begin, Location end);
 
  978   using Nodes = std::stack<Value*>;
 
  983   Location begin_ = 
nullptr;
 
  984   Location end_ = 
nullptr;
 
  985   Location current_ = 
nullptr;
 
  986   Location lastValueEnd_ = 
nullptr;
 
  987   Value* lastValue_ = 
nullptr;
 
  988   bool lastValueHasAComment_ = 
false;
 
  991   OurFeatures 
const features_;
 
  992   bool collectComments_ = 
false;
 
  997 bool OurReader::containsNewLine(OurReader::Location begin,
 
  998                                 OurReader::Location end) {
 
  999   return std::any_of(begin, end, [](
char b) { 
return b == 
'\n' || b == 
'\r'; });
 
 1002 OurReader::OurReader(OurFeatures 
const& features) : features_(features) {}
 
 1004 bool OurReader::parse(
const char* beginDoc, 
const char* endDoc, Value& root,
 
 1005                       bool collectComments) {
 
 1006   if (!features_.allowComments_) {
 
 1007     collectComments = 
false;
 
 1012   collectComments_ = collectComments;
 
 1014   lastValueEnd_ = 
nullptr;
 
 1015   lastValue_ = 
nullptr;
 
 1016   commentsBefore_.clear();
 
 1018   while (!nodes_.empty())
 
 1023   skipBom(features_.skipBom_);
 
 1024   bool successful = readValue();
 
 1027   skipCommentTokens(token);
 
 1028   if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) {
 
 1029     addError(
"Extra non-whitespace after JSON value.", token);
 
 1032   if (collectComments_ && !commentsBefore_.empty())
 
 1034   if (features_.strictRoot_) {
 
 1035     if (!root.isArray() && !root.isObject()) {
 
 1038       token.type_ = tokenError;
 
 1039       token.start_ = beginDoc;
 
 1040       token.end_ = endDoc;
 
 1042           "A valid JSON document must be either an array or an object value.",
 
 1050 bool OurReader::readValue() {
 
 1052   if (nodes_.size() > features_.stackLimit_)
 
 1053     throwRuntimeError(
"Exceeded stackLimit in readValue().");
 
 1055   skipCommentTokens(token);
 
 1056   bool successful = 
true;
 
 1058   if (collectComments_ && !commentsBefore_.empty()) {
 
 1060     commentsBefore_.clear();
 
 1063   switch (token.type_) {
 
 1064   case tokenObjectBegin:
 
 1065     successful = readObject(token);
 
 1066     currentValue().setOffsetLimit(current_ - begin_);
 
 1068   case tokenArrayBegin:
 
 1069     successful = readArray(token);
 
 1070     currentValue().setOffsetLimit(current_ - begin_);
 
 1073     successful = decodeNumber(token);
 
 1076     successful = decodeString(token);
 
 1080     currentValue().swapPayload(v);
 
 1081     currentValue().setOffsetStart(token.start_ - begin_);
 
 1082     currentValue().setOffsetLimit(token.end_ - begin_);
 
 1086     currentValue().swapPayload(v);
 
 1087     currentValue().setOffsetStart(token.start_ - begin_);
 
 1088     currentValue().setOffsetLimit(token.end_ - begin_);
 
 1092     currentValue().swapPayload(v);
 
 1093     currentValue().setOffsetStart(token.start_ - begin_);
 
 1094     currentValue().setOffsetLimit(token.end_ - begin_);
 
 1097     Value v(std::numeric_limits<double>::quiet_NaN());
 
 1098     currentValue().swapPayload(v);
 
 1099     currentValue().setOffsetStart(token.start_ - begin_);
 
 1100     currentValue().setOffsetLimit(token.end_ - begin_);
 
 1103     Value v(std::numeric_limits<double>::infinity());
 
 1104     currentValue().swapPayload(v);
 
 1105     currentValue().setOffsetStart(token.start_ - begin_);
 
 1106     currentValue().setOffsetLimit(token.end_ - begin_);
 
 1109     Value v(-std::numeric_limits<double>::infinity());
 
 1110     currentValue().swapPayload(v);
 
 1111     currentValue().setOffsetStart(token.start_ - begin_);
 
 1112     currentValue().setOffsetLimit(token.end_ - begin_);
 
 1114   case tokenArraySeparator:
 
 1115   case tokenObjectEnd:
 
 1117     if (features_.allowDroppedNullPlaceholders_) {
 
 1122       currentValue().swapPayload(v);
 
 1123       currentValue().setOffsetStart(current_ - begin_ - 1);
 
 1124       currentValue().setOffsetLimit(current_ - begin_);
 
 1128     currentValue().setOffsetStart(token.start_ - begin_);
 
 1129     currentValue().setOffsetLimit(token.end_ - begin_);
 
 1130     return addError(
"Syntax error: value, object or array expected.", token);
 
 1133   if (collectComments_) {
 
 1134     lastValueEnd_ = current_;
 
 1135     lastValueHasAComment_ = 
false;
 
 1136     lastValue_ = ¤tValue();
 
 1142 void OurReader::skipCommentTokens(Token& token) {
 
 1143   if (features_.allowComments_) {
 
 1146     } 
while (token.type_ == tokenComment);
 
 1152 bool OurReader::readToken(Token& token) {
 
 1154   token.start_ = current_;
 
 1155   Char c = getNextChar();
 
 1159     token.type_ = tokenObjectBegin;
 
 1162     token.type_ = tokenObjectEnd;
 
 1165     token.type_ = tokenArrayBegin;
 
 1168     token.type_ = tokenArrayEnd;
 
 1171     token.type_ = tokenString;
 
 1175     if (features_.allowSingleQuotes_) {
 
 1176       token.type_ = tokenString;
 
 1177       ok = readStringSingleQuote();
 
 1181     token.type_ = tokenComment;
 
 1194     token.type_ = tokenNumber;
 
 1198     if (readNumber(
true)) {
 
 1199       token.type_ = tokenNumber;
 
 1201       token.type_ = tokenNegInf;
 
 1202       ok = features_.allowSpecialFloats_ && match(
"nfinity", 7);
 
 1206     if (readNumber(
true)) {
 
 1207       token.type_ = tokenNumber;
 
 1209       token.type_ = tokenPosInf;
 
 1210       ok = features_.allowSpecialFloats_ && match(
"nfinity", 7);
 
 1214     token.type_ = tokenTrue;
 
 1215     ok = match(
"rue", 3);
 
 1218     token.type_ = tokenFalse;
 
 1219     ok = match(
"alse", 4);
 
 1222     token.type_ = tokenNull;
 
 1223     ok = match(
"ull", 3);
 
 1226     if (features_.allowSpecialFloats_) {
 
 1227       token.type_ = tokenNaN;
 
 1228       ok = match(
"aN", 2);
 
 1234     if (features_.allowSpecialFloats_) {
 
 1235       token.type_ = tokenPosInf;
 
 1236       ok = match(
"nfinity", 7);
 
 1242     token.type_ = tokenArraySeparator;
 
 1245     token.type_ = tokenMemberSeparator;
 
 1248     token.type_ = tokenEndOfStream;
 
 1255     token.type_ = tokenError;
 
 1256   token.end_ = current_;
 
 1260 void OurReader::skipSpaces() {
 
 1261   while (current_ != end_) {
 
 1263     if (c == 
' ' || c == 
'\t' || c == 
'\r' || c == 
'\n')
 
 1270 void OurReader::skipBom(
bool skipBom) {
 
 1273     if ((end_ - begin_) >= 3 && strncmp(begin_, 
"\xEF\xBB\xBF", 3) == 0) {
 
 1280 bool OurReader::match(
const Char* pattern, 
int patternLength) {
 
 1281   if (end_ - current_ < patternLength)
 
 1283   int index = patternLength;
 
 1285     if (current_[index] != pattern[index])
 
 1287   current_ += patternLength;
 
 1291 bool OurReader::readComment() {
 
 1292   const Location commentBegin = current_ - 1;
 
 1293   const Char c = getNextChar();
 
 1294   bool successful = 
false;
 
 1295   bool cStyleWithEmbeddedNewline = 
false;
 
 1297   const bool isCStyleComment = (c == 
'*');
 
 1298   const bool isCppStyleComment = (c == 
'/');
 
 1299   if (isCStyleComment) {
 
 1300     successful = readCStyleComment(&cStyleWithEmbeddedNewline);
 
 1301   } 
else if (isCppStyleComment) {
 
 1302     successful = readCppStyleComment();
 
 1308   if (collectComments_) {
 
 1311     if (!lastValueHasAComment_) {
 
 1312       if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
 
 1313         if (isCppStyleComment || !cStyleWithEmbeddedNewline) {
 
 1315           lastValueHasAComment_ = 
true;
 
 1320     addComment(commentBegin, current_, placement);
 
 1325 String OurReader::normalizeEOL(OurReader::Location begin,
 
 1326                                OurReader::Location end) {
 
 1328   normalized.reserve(
static_cast<size_t>(end - begin));
 
 1329   OurReader::Location current = begin;
 
 1330   while (current != end) {
 
 1331     char c = *current++;
 
 1333       if (current != end && *current == 
'\n')
 
 1345 void OurReader::addComment(Location begin, Location end,
 
 1347   assert(collectComments_);
 
 1348   const String& normalized = normalizeEOL(begin, end);
 
 1350     assert(lastValue_ != 
nullptr);
 
 1351     lastValue_->setComment(normalized, placement);
 
 1353     commentsBefore_ += normalized;
 
 1357 bool OurReader::readCStyleComment(
bool* containsNewLineResult) {
 
 1358   *containsNewLineResult = 
false;
 
 1360   while ((current_ + 1) < end_) {
 
 1361     Char c = getNextChar();
 
 1362     if (c == 
'*' && *current_ == 
'/')
 
 1365       *containsNewLineResult = 
true;
 
 1368   return getNextChar() == 
'/';
 
 1371 bool OurReader::readCppStyleComment() {
 
 1372   while (current_ != end_) {
 
 1373     Char c = getNextChar();
 
 1378       if (current_ != end_ && *current_ == 
'\n')
 
 1387 bool OurReader::readNumber(
bool checkInf) {
 
 1388   Location p = current_;
 
 1389   if (checkInf && p != end_ && *p == 
'I') {
 
 1395   while (c >= 
'0' && c <= 
'9')
 
 1396     c = (current_ = p) < end_ ? *p++ : 
'\0';
 
 1399     c = (current_ = p) < end_ ? *p++ : 
'\0';
 
 1400     while (c >= 
'0' && c <= 
'9')
 
 1401       c = (current_ = p) < end_ ? *p++ : 
'\0';
 
 1404   if (c == 
'e' || c == 
'E') {
 
 1405     c = (current_ = p) < end_ ? *p++ : 
'\0';
 
 1406     if (c == 
'+' || c == 
'-')
 
 1407       c = (current_ = p) < end_ ? *p++ : 
'\0';
 
 1408     while (c >= 
'0' && c <= 
'9')
 
 1409       c = (current_ = p) < end_ ? *p++ : 
'\0';
 
 1413 bool OurReader::readString() {
 
 1415   while (current_ != end_) {
 
 1425 bool OurReader::readStringSingleQuote() {
 
 1427   while (current_ != end_) {
 
 1437 bool OurReader::readObject(Token& token) {
 
 1441   currentValue().swapPayload(init);
 
 1442   currentValue().setOffsetStart(token.start_ - begin_);
 
 1443   while (readToken(tokenName)) {
 
 1444     bool initialTokenOk = 
true;
 
 1445     while (tokenName.type_ == tokenComment && initialTokenOk)
 
 1446       initialTokenOk = readToken(tokenName);
 
 1447     if (!initialTokenOk)
 
 1449     if (tokenName.type_ == tokenObjectEnd &&
 
 1451          features_.allowTrailingCommas_)) 
 
 1454     if (tokenName.type_ == tokenString) {
 
 1455       if (!decodeString(tokenName, name))
 
 1456         return recoverFromError(tokenObjectEnd);
 
 1457     } 
else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
 
 1459       if (!decodeNumber(tokenName, numberName))
 
 1460         return recoverFromError(tokenObjectEnd);
 
 1461       name = numberName.asString();
 
 1465     if (name.length() >= (1U << 30))
 
 1466       throwRuntimeError(
"keylength >= 2^30");
 
 1467     if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
 
 1468       String msg = 
"Duplicate key: '" + name + 
"'";
 
 1469       return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
 
 1473     if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
 
 1474       return addErrorAndRecover(
"Missing ':' after object member name", colon,
 
 1477     Value& value = currentValue()[name];
 
 1478     nodes_.push(&value);
 
 1479     bool ok = readValue();
 
 1482       return recoverFromError(tokenObjectEnd);
 
 1485     if (!readToken(comma) ||
 
 1486         (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
 
 1487          comma.type_ != tokenComment)) {
 
 1488       return addErrorAndRecover(
"Missing ',' or '}' in object declaration",
 
 1489                                 comma, tokenObjectEnd);
 
 1491     bool finalizeTokenOk = 
true;
 
 1492     while (comma.type_ == tokenComment && finalizeTokenOk)
 
 1493       finalizeTokenOk = readToken(comma);
 
 1494     if (comma.type_ == tokenObjectEnd)
 
 1497   return addErrorAndRecover(
"Missing '}' or object member name", tokenName,
 
 1501 bool OurReader::readArray(Token& token) {
 
 1503   currentValue().swapPayload(init);
 
 1504   currentValue().setOffsetStart(token.start_ - begin_);
 
 1508     if (current_ != end_ && *current_ == 
']' &&
 
 1510          (features_.allowTrailingCommas_ &&
 
 1511           !features_.allowDroppedNullPlaceholders_))) 
 
 1515       readToken(endArray);
 
 1518     Value& value = currentValue()[index++];
 
 1519     nodes_.push(&value);
 
 1520     bool ok = readValue();
 
 1523       return recoverFromError(tokenArrayEnd);
 
 1527     ok = readToken(currentToken);
 
 1528     while (currentToken.type_ == tokenComment && ok) {
 
 1529       ok = readToken(currentToken);
 
 1531     bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
 
 1532                          currentToken.type_ != tokenArrayEnd);
 
 1533     if (!ok || badTokenType) {
 
 1534       return addErrorAndRecover(
"Missing ',' or ']' in array declaration",
 
 1535                                 currentToken, tokenArrayEnd);
 
 1537     if (currentToken.type_ == tokenArrayEnd)
 
 1543 bool OurReader::decodeNumber(Token& token) {
 
 1545   if (!decodeNumber(token, decoded))
 
 1547   currentValue().swapPayload(decoded);
 
 1548   currentValue().setOffsetStart(token.start_ - begin_);
 
 1549   currentValue().setOffsetLimit(token.end_ - begin_);
 
 1553 bool OurReader::decodeNumber(Token& token, Value& decoded) {
 
 1557   Location current = token.start_;
 
 1558   const bool isNegative = *current == 
'-';
 
 1567                 "Int must be smaller than UInt");
 
 1574                 "The absolute value of minLargestInt must be greater than or " 
 1575                 "equal to maxLargestInt");
 
 1577                 "The absolute value of minLargestInt must be only 1 magnitude " 
 1578                 "larger than maxLargest Int");
 
 1589   static constexpr 
auto negative_threshold =
 
 1591   static constexpr 
auto negative_last_digit =
 
 1595       isNegative ? negative_threshold : positive_threshold;
 
 1597       isNegative ? negative_last_digit : positive_last_digit;
 
 1600   while (current < token.end_) {
 
 1601     Char c = *current++;
 
 1602     if (c < '0' || c > 
'9')
 
 1603       return decodeDouble(token, decoded);
 
 1605     const auto digit(
static_cast<Value::UInt>(c - 
'0'));
 
 1606     if (value >= threshold) {
 
 1612       if (value > threshold || current != token.end_ ||
 
 1613           digit > max_last_digit) {
 
 1614         return decodeDouble(token, decoded);
 
 1617     value = value * 10 + digit;
 
 1622     const auto last_digit = 
static_cast<Value::UInt>(value % 10);
 
 1633 bool OurReader::decodeDouble(Token& token) {
 
 1635   if (!decodeDouble(token, decoded))
 
 1637   currentValue().swapPayload(decoded);
 
 1638   currentValue().setOffsetStart(token.start_ - begin_);
 
 1639   currentValue().setOffsetLimit(token.end_ - begin_);
 
 1643 bool OurReader::decodeDouble(Token& token, Value& decoded) {
 
 1645   const String buffer(token.start_, token.end_);
 
 1647   if (!(is >> value)) {
 
 1649         "'" + 
String(token.start_, token.end_) + 
"' is not a number.", token);
 
 1655 bool OurReader::decodeString(Token& token) {
 
 1657   if (!decodeString(token, decoded_string))
 
 1659   Value decoded(decoded_string);
 
 1660   currentValue().swapPayload(decoded);
 
 1661   currentValue().setOffsetStart(token.start_ - begin_);
 
 1662   currentValue().setOffsetLimit(token.end_ - begin_);
 
 1666 bool OurReader::decodeString(Token& token, 
String& decoded) {
 
 1667   decoded.reserve(
static_cast<size_t>(token.end_ - token.start_ - 2));
 
 1668   Location current = token.start_ + 1; 
 
 1669   Location end = token.end_ - 1;       
 
 1670   while (current != end) {
 
 1671     Char c = *current++;
 
 1676         return addError(
"Empty escape sequence in string", token, current);
 
 1677       Char escape = *current++;
 
 1704         unsigned int unicode;
 
 1705         if (!decodeUnicodeCodePoint(token, current, end, unicode))
 
 1710         return addError(
"Bad escape sequence in string", token, current);
 
 1719 bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current,
 
 1720                                        Location end, 
unsigned int& unicode) {
 
 1722   if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
 
 1724   if (unicode >= 0xD800 && unicode <= 0xDBFF) {
 
 1726     if (end - current < 6)
 
 1728           "additional six characters expected to parse unicode surrogate pair.",
 
 1730     if (*(current++) == 
'\\' && *(current++) == 
'u') {
 
 1731       unsigned int surrogatePair;
 
 1732       if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
 
 1733         unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
 
 1737       return addError(
"expecting another \\u token to begin the second half of " 
 1738                       "a unicode surrogate pair",
 
 1744 bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current,
 
 1746                                             unsigned int& ret_unicode) {
 
 1747   if (end - current < 4)
 
 1749         "Bad unicode escape sequence in string: four digits expected.", token,
 
 1752   for (
int index = 0; index < 4; ++index) {
 
 1753     Char c = *current++;
 
 1755     if (c >= 
'0' && c <= 
'9')
 
 1757     else if (c >= 
'a' && c <= 
'f')
 
 1758       unicode += c - 
'a' + 10;
 
 1759     else if (c >= 
'A' && c <= 
'F')
 
 1760       unicode += c - 
'A' + 10;
 
 1763           "Bad unicode escape sequence in string: hexadecimal digit expected.",
 
 1766   ret_unicode = 
static_cast<unsigned int>(unicode);
 
 1770 bool OurReader::addError(
const String& message, Token& token, Location extra) {
 
 1772   info.token_ = token;
 
 1773   info.message_ = message;
 
 1774   info.extra_ = extra;
 
 1775   errors_.push_back(info);
 
 1779 bool OurReader::recoverFromError(TokenType skipUntilToken) {
 
 1780   size_t errorCount = errors_.size();
 
 1783     if (!readToken(skip))
 
 1784       errors_.resize(errorCount); 
 
 1785     if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
 
 1788   errors_.resize(errorCount);
 
 1792 bool OurReader::addErrorAndRecover(
const String& message, Token& token,
 
 1793                                    TokenType skipUntilToken) {
 
 1794   addError(message, token);
 
 1795   return recoverFromError(skipUntilToken);
 
 1798 Value& OurReader::currentValue() { 
return *(nodes_.top()); }
 
 1800 OurReader::Char OurReader::getNextChar() {
 
 1801   if (current_ == end_)
 
 1806 void OurReader::getLocationLineAndColumn(Location location, 
int& line,
 
 1807                                          int& column)
 const {
 
 1808   Location current = begin_;
 
 1809   Location lastLineStart = current;
 
 1811   while (current < location && current != end_) {
 
 1812     Char c = *current++;
 
 1814       if (*current == 
'\n')
 
 1816       lastLineStart = current;
 
 1818     } 
else if (c == 
'\n') {
 
 1819       lastLineStart = current;
 
 1824   column = int(location - lastLineStart) + 1;
 
 1828 String OurReader::getLocationLineAndColumn(Location location)
 const {
 
 1830   getLocationLineAndColumn(location, line, column);
 
 1831   char buffer[18 + 16 + 16 + 1];
 
 1832   jsoncpp_snprintf(buffer, 
sizeof(buffer), 
"Line %d, Column %d", line, column);
 
 1836 String OurReader::getFormattedErrorMessages()
 const {
 
 1838   for (
const auto& error : errors_) {
 
 1840         "* " + getLocationLineAndColumn(error.token_.start_) + 
"\n";
 
 1841     formattedMessage += 
"  " + error.message_ + 
"\n";
 
 1844           "See " + getLocationLineAndColumn(error.extra_) + 
" for detail.\n";
 
 1846   return formattedMessage;
 
 1849 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors()
 const {
 
 1850   std::vector<OurReader::StructuredError> allErrors;
 
 1851   for (
const auto& error : errors_) {
 
 1852     OurReader::StructuredError structured;
 
 1853     structured.offset_start = error.token_.start_ - begin_;
 
 1854     structured.offset_limit = error.token_.end_ - begin_;
 
 1855     structured.message = error.message_;
 
 1856     allErrors.push_back(structured);
 
 1861 class OurCharReader : 
public CharReader {
 
 1862   bool const collectComments_;
 
 1866   OurCharReader(
bool collectComments, OurFeatures 
const& features)
 
 1867       : collectComments_(collectComments), reader_(features) {}
 
 1868   bool parse(
char const* beginDoc, 
char const* endDoc, Value* root,
 
 1870     bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
 
 1872       *errs = reader_.getFormattedErrorMessages();
 
 1882   OurFeatures features = OurFeatures::all();
 
 1884   features.allowTrailingCommas_ = 
settings_[
"allowTrailingCommas"].
asBool();
 
 1886   features.allowDroppedNullPlaceholders_ =
 
 1889   features.allowSingleQuotes_ = 
settings_[
"allowSingleQuotes"].
asBool();
 
 1893   features.stackLimit_ = 
static_cast<size_t>(
settings_[
"stackLimit"].
asUInt());
 
 1896   features.allowSpecialFloats_ = 
settings_[
"allowSpecialFloats"].
asBool();
 
 1898   return new OurCharReader(collectComments, features);
 
 1902   static const auto& valid_keys = *
new std::set<String>{
 
 1905       "allowTrailingCommas",
 
 1907       "allowDroppedNullPlaceholders",
 
 1909       "allowSingleQuotes",
 
 1913       "allowSpecialFloats",
 
 1917     auto key = si.name();
 
 1918     if (valid_keys.count(key))
 
 1921       (*invalid)[std::move(key)] = *si;
 
 1925   return invalid ? invalid->
empty() : 
true;
 
 1934   (*settings)[
"allowComments"] = 
false;
 
 1935   (*settings)[
"allowTrailingCommas"] = 
false;
 
 1936   (*settings)[
"strictRoot"] = 
true;
 
 1937   (*settings)[
"allowDroppedNullPlaceholders"] = 
false;
 
 1938   (*settings)[
"allowNumericKeys"] = 
false;
 
 1939   (*settings)[
"allowSingleQuotes"] = 
false;
 
 1940   (*settings)[
"stackLimit"] = 1000;
 
 1941   (*settings)[
"failIfExtra"] = 
true;
 
 1942   (*settings)[
"rejectDupKeys"] = 
true;
 
 1943   (*settings)[
"allowSpecialFloats"] = 
false;
 
 1944   (*settings)[
"skipBom"] = 
true;
 
 1950   (*settings)[
"collectComments"] = 
true;
 
 1951   (*settings)[
"allowComments"] = 
true;
 
 1952   (*settings)[
"allowTrailingCommas"] = 
true;
 
 1953   (*settings)[
"strictRoot"] = 
false;
 
 1954   (*settings)[
"allowDroppedNullPlaceholders"] = 
false;
 
 1955   (*settings)[
"allowNumericKeys"] = 
false;
 
 1956   (*settings)[
"allowSingleQuotes"] = 
false;
 
 1957   (*settings)[
"stackLimit"] = 1000;
 
 1958   (*settings)[
"failIfExtra"] = 
false;
 
 1959   (*settings)[
"rejectDupKeys"] = 
false;
 
 1960   (*settings)[
"allowSpecialFloats"] = 
false;
 
 1961   (*settings)[
"skipBom"] = 
true;
 
 1971   ssin << sin.rdbuf();
 
 1973   char const* begin = doc.data();
 
 1974   char const* end = begin + doc.size();
 
 1977   return reader->parse(begin, end, root, errs);
 
 1985     throwRuntimeError(errs);