7#if !defined(JSON_IS_AMALGAMATION) 
   26#if __cplusplus >= 201103L 
   29#define sscanf std::sscanf 
   35#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) 
   36#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 
   42#pragma warning(disable : 4996) 
   47#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) 
   48#define JSONCPP_DEPRECATED_STACK_LIMIT 1000 
   56#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) 
   82  return std::any_of(begin, end, [](
char b) { 
return b == 
'\n' || b == 
'\r'; });
 
   93                   bool collectComments) {
 
   94  document_.assign(document.begin(), document.end());
 
   95  const char* begin = document_.c_str();
 
   96  const char* end = begin + document_.length();
 
   97  return parse(begin, end, root, collectComments);
 
 
  108  String doc(std::istreambuf_iterator<char>(is), {});
 
  109  return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
 
 
  113                   bool collectComments) {
 
  115    collectComments = 
false;
 
  120  collectComments_ = collectComments;
 
  122  lastValueEnd_ = 
nullptr;
 
  123  lastValue_ = 
nullptr;
 
  124  commentsBefore_.clear();
 
  126  while (!nodes_.empty())
 
  130  bool successful = readValue();
 
  132  readTokenSkippingComments(token);
 
  133  if (collectComments_ && !commentsBefore_.empty())
 
  139      token.type_ = tokenError;
 
  140      token.start_ = beginDoc;
 
  143          "A valid JSON document must be either an array or an object value.",
 
 
  151bool Reader::readValue() {
 
  157    throwRuntimeError(
"Exceeded stackLimit in readValue().");
 
  160  readTokenSkippingComments(token);
 
  161  bool successful = 
true;
 
  163  if (collectComments_ && !commentsBefore_.empty()) {
 
  165    commentsBefore_.clear();
 
  168  switch (token.type_) {
 
  169  case tokenObjectBegin:
 
  170    successful = readObject(token);
 
  173  case tokenArrayBegin:
 
  174    successful = readArray(token);
 
  178    successful = decodeNumber(token);
 
  181    successful = decodeString(token);
 
  201  case tokenArraySeparator:
 
  217    return addError(
"Syntax error: value, object or array expected.", token);
 
  220  if (collectComments_) {
 
  221    lastValueEnd_ = current_;
 
  222    lastValue_ = ¤tValue();
 
  228bool Reader::readTokenSkippingComments(Token& token) {
 
  229  bool success = readToken(token);
 
  231    while (success && token.type_ == tokenComment) {
 
  232      success = readToken(token);
 
  238bool 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_;
 
  309void Reader::skipSpaces() {
 
  310  while (current_ != end_) {
 
  312    if (c == 
' ' || c == 
'\t' || c == 
'\r' || c == 
'\n')
 
  319bool 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;
 
  330bool 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);
 
  355  normalized.reserve(
static_cast<size_t>(end - begin));
 
  357  while (current != end) {
 
  360      if (current != end && *current == 
'\n')
 
  372void Reader::addComment(Location begin, Location end,
 
  373                        CommentPlacement placement) {
 
  374  assert(collectComments_);
 
  375  const String& normalized = normalizeEOL(begin, end);
 
  377    assert(lastValue_ != 
nullptr);
 
  378    lastValue_->
setComment(normalized, placement);
 
  380    commentsBefore_ += normalized;
 
  384bool Reader::readCStyleComment() {
 
  385  while ((current_ + 1) < end_) {
 
  386    Char c = getNextChar();
 
  387    if (c == 
'*' && *current_ == 
'/')
 
  390  return getNextChar() == 
'/';
 
  393bool Reader::readCppStyleComment() {
 
  394  while (current_ != end_) {
 
  395    Char c = getNextChar();
 
  400      if (current_ != end_ && *current_ == 
'\n')
 
  409void Reader::readNumber() {
 
  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';
 
  431bool Reader::readString() {
 
  433  while (current_ != end_) {
 
  443bool Reader::readObject(Token& token) {
 
  449  while (readTokenSkippingComments(tokenName)) {
 
  450    if (tokenName.type_ == tokenObjectEnd && name.empty()) 
 
  453    if (tokenName.type_ == tokenString) {
 
  454      if (!decodeString(tokenName, name))
 
  455        return recoverFromError(tokenObjectEnd);
 
  458      if (!decodeNumber(tokenName, numberName))
 
  459        return recoverFromError(tokenObjectEnd);
 
  460      name = numberName.asString();
 
  466    if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
 
  467      return addErrorAndRecover(
"Missing ':' after object member name", colon,
 
  470    Value& value = currentValue()[name];
 
  472    bool ok = readValue();
 
  475      return recoverFromError(tokenObjectEnd);
 
  478    if (!readTokenSkippingComments(comma) ||
 
  479        (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) {
 
  480      return addErrorAndRecover(
"Missing ',' or '}' in object declaration",
 
  481                                comma, tokenObjectEnd);
 
  483    if (comma.type_ == tokenObjectEnd)
 
  486  return addErrorAndRecover(
"Missing '}' or object member name", tokenName,
 
  490bool Reader::readArray(Token& token) {
 
  495  if (current_ != end_ && *current_ == 
']') 
 
  503    Value& value = currentValue()[index++];
 
  505    bool ok = readValue();
 
  508      return recoverFromError(tokenArrayEnd);
 
  512    ok = readTokenSkippingComments(currentToken);
 
  513    bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
 
  514                         currentToken.type_ != tokenArrayEnd);
 
  515    if (!ok || badTokenType) {
 
  516      return addErrorAndRecover(
"Missing ',' or ']' in array declaration",
 
  517                                currentToken, tokenArrayEnd);
 
  519    if (currentToken.type_ == tokenArrayEnd)
 
  525bool Reader::decodeNumber(Token& token) {
 
  527  if (!decodeNumber(token, decoded))
 
  535bool Reader::decodeNumber(Token& token, Value& decoded) {
 
  540  bool isNegative = *current == 
'-';
 
  550  while (current < token.end_) {
 
  552    if (c < 
'0' || c > 
'9')
 
  553      return decodeDouble(token, decoded);
 
  555    if (value >= threshold) {
 
  560      if (value > threshold || current != token.end_ ||
 
  561          digit > maxIntegerValue % 10) {
 
  562        return decodeDouble(token, decoded);
 
  565    value = value * 10 + digit;
 
  567  if (isNegative && value == maxIntegerValue)
 
  578bool Reader::decodeDouble(Token& token) {
 
  580  if (!decodeDouble(token, decoded))
 
  588bool Reader::decodeDouble(Token& token, Value& decoded) {
 
  591  if (!(is >> value)) {
 
  592    if (value == std::numeric_limits<double>::max())
 
  593      value = std::numeric_limits<double>::infinity();
 
  594    else if (value == std::numeric_limits<double>::lowest())
 
  595      value = -std::numeric_limits<double>::infinity();
 
  596    else if (!std::isinf(value))
 
  598          "'" + 
String(token.start_, token.end_) + 
"' is not a number.", token);
 
  604bool Reader::decodeString(Token& token) {
 
  606  if (!decodeString(token, decoded_string))
 
  608  Value decoded(decoded_string);
 
  615bool Reader::decodeString(Token& token, 
String& decoded) {
 
  616  decoded.reserve(
static_cast<size_t>(token.end_ - token.start_ - 2));
 
  617  Location current = token.start_ + 1; 
 
  619  while (current != end) {
 
  625        return addError(
"Empty escape sequence in string", token, current);
 
  626      Char escape = *current++;
 
  653        unsigned int unicode;
 
  654        if (!decodeUnicodeCodePoint(token, current, end, unicode))
 
  659        return addError(
"Bad escape sequence in string", token, current);
 
  668bool Reader::decodeUnicodeCodePoint(Token& token, Location& current,
 
  669                                    Location end, 
unsigned int& unicode) {
 
  671  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
 
  673  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
 
  675    if (end - current < 6)
 
  677          "additional six characters expected to parse unicode surrogate pair.",
 
  679    if (*(current++) == 
'\\' && *(current++) == 
'u') {
 
  680      unsigned int surrogatePair;
 
  681      if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
 
  682        unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
 
  686      return addError(
"expecting another \\u token to begin the second half of " 
  687                      "a unicode surrogate pair",
 
  693bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current,
 
  695                                         unsigned int& ret_unicode) {
 
  696  if (end - current < 4)
 
  698        "Bad unicode escape sequence in string: four digits expected.", token,
 
  701  for (
int index = 0; index < 4; ++index) {
 
  704    if (c >= 
'0' && c <= 
'9')
 
  706    else if (c >= 
'a' && c <= 
'f')
 
  707      unicode += c - 
'a' + 10;
 
  708    else if (c >= 
'A' && c <= 
'F')
 
  709      unicode += c - 
'A' + 10;
 
  712          "Bad unicode escape sequence in string: hexadecimal digit expected.",
 
  715  ret_unicode = 
static_cast<unsigned int>(unicode);
 
  719bool Reader::addError(
const String& message, Token& token, Location extra) {
 
  722  info.message_ = message;
 
  724  errors_.push_back(info);
 
  728bool Reader::recoverFromError(TokenType skipUntilToken) {
 
  729  size_t const errorCount = errors_.size();
 
  732    if (!readToken(skip))
 
  733      errors_.resize(errorCount); 
 
  734    if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
 
  737  errors_.resize(errorCount);
 
  741bool Reader::addErrorAndRecover(
const String& message, Token& token,
 
  742                                TokenType skipUntilToken) {
 
  743  addError(message, token);
 
  744  return recoverFromError(skipUntilToken);
 
  747Value& Reader::currentValue() { 
return *(nodes_.top()); }
 
  750  if (current_ == end_)
 
  755void Reader::getLocationLineAndColumn(Location location, 
int& line,
 
  760  while (current < location && current != end_) {
 
  763      if (current != end_ && *current == 
'\n')
 
  765      lastLineStart = current;
 
  767    } 
else if (c == 
'\n') {
 
  768      lastLineStart = current;
 
  773  column = int(location - lastLineStart) + 1;
 
  777String Reader::getLocationLineAndColumn(Location location)
 const {
 
  779  getLocationLineAndColumn(location, line, column);
 
  780  char buffer[18 + 16 + 16 + 1];
 
  781  jsoncpp_snprintf(buffer, 
sizeof(buffer), 
"Line %d, Column %d", line, column);
 
  786String Reader::getFormatedErrorMessages()
 const {
 
  792  for (
const auto& error : errors_) {
 
  794        "* " + getLocationLineAndColumn(error.token_.start_) + 
"\n";
 
  795    formattedMessage += 
"  " + error.message_ + 
"\n";
 
  798          "See " + getLocationLineAndColumn(error.extra_) + 
" for detail.\n";
 
  800  return formattedMessage;
 
 
  804  std::vector<Reader::StructuredError> allErrors;
 
  805  for (
const auto& error : errors_) {
 
  809    structured.
message = error.message_;
 
  810    allErrors.push_back(structured);
 
 
  816  ptrdiff_t 
const length = end_ - begin_;
 
  820  token.type_ = tokenError;
 
  825  info.message_ = message;
 
  826  info.extra_ = 
nullptr;
 
  827  errors_.push_back(info);
 
 
  832                       const Value& extra) {
 
  833  ptrdiff_t 
const length = end_ - begin_;
 
  838  token.type_ = tokenError;
 
  843  info.message_ = message;
 
  845  errors_.push_back(info);
 
 
  855  static OurFeatures all();
 
  857  bool allowTrailingCommas_;
 
  859  bool allowDroppedNullPlaceholders_;
 
  860  bool allowNumericKeys_;
 
  861  bool allowSingleQuotes_;
 
  864  bool allowSpecialFloats_;
 
  869OurFeatures OurFeatures::all() { 
return {}; }
 
  879  using Location = 
const Char*;
 
  881  explicit OurReader(OurFeatures 
const& features);
 
  882  bool parse(
const char* beginDoc, 
const char* endDoc, Value& root,
 
  883             bool collectComments = 
true);
 
  884  String getFormattedErrorMessages() 
const;
 
  885  std::vector<CharReader::StructuredError> getStructuredErrors() 
const;
 
  888  OurReader(OurReader 
const&);      
 
  889  void operator=(OurReader 
const&); 
 
  892    tokenEndOfStream = 0,
 
  906    tokenMemberSeparator,
 
  925  using Errors = std::deque<ErrorInfo>;
 
  927  bool readToken(Token& token);
 
  928  bool readTokenSkippingComments(Token& token);
 
  930  void skipBom(
bool skipBom);
 
  931  bool match(
const Char* pattern, 
int patternLength);
 
  933  bool readCStyleComment(
bool* containsNewLineResult);
 
  934  bool readCppStyleComment();
 
  936  bool readStringSingleQuote();
 
  937  bool readNumber(
bool checkInf);
 
  939  bool readObject(Token& token);
 
  940  bool readArray(Token& token);
 
  941  bool decodeNumber(Token& token);
 
  942  bool decodeNumber(Token& token, Value& decoded);
 
  943  bool decodeString(Token& token);
 
  944  bool decodeString(Token& token, 
String& decoded);
 
  945  bool decodeDouble(Token& token);
 
  946  bool decodeDouble(Token& token, Value& decoded);
 
  947  bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
 
  948                              unsigned int& unicode);
 
  949  bool decodeUnicodeEscapeSequence(Token& token, Location& current,
 
  950                                   Location end, 
unsigned int& unicode);
 
  951  bool addError(
const String& message, Token& token, Location extra = 
nullptr);
 
  952  bool recoverFromError(TokenType skipUntilToken);
 
  953  bool addErrorAndRecover(
const String& message, Token& token,
 
  954                          TokenType skipUntilToken);
 
  955  void skipUntilSpace();
 
  956  Value& currentValue();
 
  958  void getLocationLineAndColumn(Location location, 
int& line,
 
  960  String getLocationLineAndColumn(Location location) 
const;
 
  961  void addComment(Location begin, Location end, CommentPlacement placement);
 
  963  static String normalizeEOL(Location begin, Location end);
 
  964  static bool containsNewLine(Location begin, Location end);
 
  966  using Nodes = std::stack<Value*>;
 
  971  Location begin_ = 
nullptr;
 
  972  Location end_ = 
nullptr;
 
  973  Location current_ = 
nullptr;
 
  974  Location lastValueEnd_ = 
nullptr;
 
  975  Value* lastValue_ = 
nullptr;
 
  976  bool lastValueHasAComment_ = 
false;
 
  979  OurFeatures 
const features_;
 
  980  bool collectComments_ = 
false;
 
  985bool OurReader::containsNewLine(OurReader::Location begin,
 
  986                                OurReader::Location end) {
 
  987  return std::any_of(begin, end, [](
char b) { 
return b == 
'\n' || b == 
'\r'; });
 
  990OurReader::OurReader(OurFeatures 
const& features) : features_(features) {}
 
  992bool OurReader::parse(
const char* beginDoc, 
const char* endDoc, Value& root,
 
  993                      bool collectComments) {
 
  994  if (!features_.allowComments_) {
 
  995    collectComments = 
false;
 
 1000  collectComments_ = collectComments;
 
 1002  lastValueEnd_ = 
nullptr;
 
 1003  lastValue_ = 
nullptr;
 
 1004  commentsBefore_.clear();
 
 1006  while (!nodes_.empty())
 
 1011  skipBom(features_.skipBom_);
 
 1012  bool successful = readValue();
 
 1015  readTokenSkippingComments(token);
 
 1016  if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) {
 
 1017    addError(
"Extra non-whitespace after JSON value.", token);
 
 1020  if (collectComments_ && !commentsBefore_.empty())
 
 1022  if (features_.strictRoot_) {
 
 1023    if (!root.isArray() && !root.isObject()) {
 
 1026      token.type_ = tokenError;
 
 1027      token.start_ = beginDoc;
 
 1028      token.end_ = endDoc;
 
 1030          "A valid JSON document must be either an array or an object value.",
 
 1038bool OurReader::readValue() {
 
 1040  if (nodes_.size() > features_.stackLimit_)
 
 1041    throwRuntimeError(
"Exceeded stackLimit in readValue().");
 
 1043  readTokenSkippingComments(token);
 
 1044  bool successful = 
true;
 
 1046  if (collectComments_ && !commentsBefore_.empty()) {
 
 1048    commentsBefore_.clear();
 
 1051  switch (token.type_) {
 
 1052  case tokenObjectBegin:
 
 1053    successful = readObject(token);
 
 1056  case tokenArrayBegin:
 
 1057    successful = readArray(token);
 
 1061    successful = decodeNumber(token);
 
 1064    successful = decodeString(token);
 
 1085    Value v(std::numeric_limits<double>::quiet_NaN());
 
 1091    Value v(std::numeric_limits<double>::infinity());
 
 1097    Value v(-std::numeric_limits<double>::infinity());
 
 1102  case tokenArraySeparator:
 
 1103  case tokenObjectEnd:
 
 1105    if (features_.allowDroppedNullPlaceholders_) {
 
 1118    return addError(
"Syntax error: value, object or array expected.", token);
 
 1121  if (collectComments_) {
 
 1122    lastValueEnd_ = current_;
 
 1123    lastValueHasAComment_ = 
false;
 
 1124    lastValue_ = ¤tValue();
 
 1130bool OurReader::readTokenSkippingComments(Token& token) {
 
 1131  bool success = readToken(token);
 
 1132  if (features_.allowComments_) {
 
 1133    while (success && token.type_ == tokenComment) {
 
 1134      success = readToken(token);
 
 1140bool OurReader::readToken(Token& token) {
 
 1142  token.start_ = current_;
 
 1143  Char c = getNextChar();
 
 1147    token.type_ = tokenObjectBegin;
 
 1150    token.type_ = tokenObjectEnd;
 
 1153    token.type_ = tokenArrayBegin;
 
 1156    token.type_ = tokenArrayEnd;
 
 1159    token.type_ = tokenString;
 
 1163    if (features_.allowSingleQuotes_) {
 
 1164      token.type_ = tokenString;
 
 1165      ok = readStringSingleQuote();
 
 1172    token.type_ = tokenComment;
 
 1185    token.type_ = tokenNumber;
 
 1189    if (readNumber(
true)) {
 
 1190      token.type_ = tokenNumber;
 
 1192      token.type_ = tokenNegInf;
 
 1193      ok = features_.allowSpecialFloats_ && match(
"nfinity", 7);
 
 1197    if (readNumber(
true)) {
 
 1198      token.type_ = tokenNumber;
 
 1200      token.type_ = tokenPosInf;
 
 1201      ok = features_.allowSpecialFloats_ && match(
"nfinity", 7);
 
 1205    token.type_ = tokenTrue;
 
 1206    ok = match(
"rue", 3);
 
 1209    token.type_ = tokenFalse;
 
 1210    ok = match(
"alse", 4);
 
 1213    token.type_ = tokenNull;
 
 1214    ok = match(
"ull", 3);
 
 1217    if (features_.allowSpecialFloats_) {
 
 1218      token.type_ = tokenNaN;
 
 1219      ok = match(
"aN", 2);
 
 1225    if (features_.allowSpecialFloats_) {
 
 1226      token.type_ = tokenPosInf;
 
 1227      ok = match(
"nfinity", 7);
 
 1233    token.type_ = tokenArraySeparator;
 
 1236    token.type_ = tokenMemberSeparator;
 
 1239    token.type_ = tokenEndOfStream;
 
 1246    token.type_ = tokenError;
 
 1247  token.end_ = current_;
 
 1251void OurReader::skipSpaces() {
 
 1252  while (current_ != end_) {
 
 1254    if (c == 
' ' || c == 
'\t' || c == 
'\r' || c == 
'\n')
 
 1261void OurReader::skipBom(
bool skipBom) {
 
 1264    if ((end_ - begin_) >= 3 && strncmp(begin_, 
"\xEF\xBB\xBF", 3) == 0) {
 
 1271bool OurReader::match(
const Char* pattern, 
int patternLength) {
 
 1272  if (end_ - current_ < patternLength)
 
 1274  int index = patternLength;
 
 1276    if (current_[index] != pattern[index])
 
 1278  current_ += patternLength;
 
 1282bool OurReader::readComment() {
 
 1283  const Location commentBegin = current_ - 1;
 
 1284  const Char c = getNextChar();
 
 1285  bool successful = 
false;
 
 1286  bool cStyleWithEmbeddedNewline = 
false;
 
 1288  const bool isCStyleComment = (c == 
'*');
 
 1289  const bool isCppStyleComment = (c == 
'/');
 
 1290  if (isCStyleComment) {
 
 1291    successful = readCStyleComment(&cStyleWithEmbeddedNewline);
 
 1292  } 
else if (isCppStyleComment) {
 
 1293    successful = readCppStyleComment();
 
 1299  if (collectComments_) {
 
 1302    if (!lastValueHasAComment_) {
 
 1303      if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
 
 1304        if (isCppStyleComment || !cStyleWithEmbeddedNewline) {
 
 1306          lastValueHasAComment_ = 
true;
 
 1311    addComment(commentBegin, current_, placement);
 
 1316String OurReader::normalizeEOL(OurReader::Location begin,
 
 1317                               OurReader::Location end) {
 
 1319  normalized.reserve(
static_cast<size_t>(end - begin));
 
 1320  OurReader::Location current = begin;
 
 1321  while (current != end) {
 
 1322    char c = *current++;
 
 1324      if (current != end && *current == 
'\n')
 
 1336void OurReader::addComment(Location begin, Location end,
 
 1337                           CommentPlacement placement) {
 
 1338  assert(collectComments_);
 
 1339  const String& normalized = normalizeEOL(begin, end);
 
 1341    assert(lastValue_ != 
nullptr);
 
 1342    lastValue_->
setComment(normalized, placement);
 
 1344    commentsBefore_ += normalized;
 
 1348bool OurReader::readCStyleComment(
bool* containsNewLineResult) {
 
 1349  *containsNewLineResult = 
false;
 
 1351  while ((current_ + 1) < end_) {
 
 1352    Char c = getNextChar();
 
 1353    if (c == 
'*' && *current_ == 
'/')
 
 1356      *containsNewLineResult = 
true;
 
 1359  return getNextChar() == 
'/';
 
 1362bool OurReader::readCppStyleComment() {
 
 1363  while (current_ != end_) {
 
 1364    Char c = getNextChar();
 
 1369      if (current_ != end_ && *current_ == 
'\n')
 
 1378bool OurReader::readNumber(
bool checkInf) {
 
 1379  Location p = current_;
 
 1380  if (checkInf && p != end_ && *p == 
'I') {
 
 1386  while (c >= 
'0' && c <= 
'9')
 
 1387    c = (current_ = p) < end_ ? *p++ : 
'\0';
 
 1390    c = (current_ = p) < end_ ? *p++ : 
'\0';
 
 1391    while (c >= 
'0' && c <= 
'9')
 
 1392      c = (current_ = p) < end_ ? *p++ : 
'\0';
 
 1395  if (c == 
'e' || c == 
'E') {
 
 1396    c = (current_ = p) < end_ ? *p++ : 
'\0';
 
 1397    if (c == 
'+' || c == 
'-')
 
 1398      c = (current_ = p) < end_ ? *p++ : 
'\0';
 
 1399    while (c >= 
'0' && c <= 
'9')
 
 1400      c = (current_ = p) < end_ ? *p++ : 
'\0';
 
 1404bool OurReader::readString() {
 
 1406  while (current_ != end_) {
 
 1416bool OurReader::readStringSingleQuote() {
 
 1418  while (current_ != end_) {
 
 1428bool OurReader::readObject(Token& token) {
 
 1434  while (readTokenSkippingComments(tokenName)) {
 
 1435    if (tokenName.type_ == tokenObjectEnd &&
 
 1437         features_.allowTrailingCommas_)) 
 
 1440    if (tokenName.type_ == tokenString) {
 
 1441      if (!decodeString(tokenName, name))
 
 1442        return recoverFromError(tokenObjectEnd);
 
 1443    } 
else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
 
 1445      if (!decodeNumber(tokenName, numberName))
 
 1446        return recoverFromError(tokenObjectEnd);
 
 1447      name = numberName.asString();
 
 1451    if (name.length() >= (1U << 30))
 
 1452      throwRuntimeError(
"keylength >= 2^30");
 
 1453    if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
 
 1454      String msg = 
"Duplicate key: '" + name + 
"'";
 
 1455      return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
 
 1459    if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
 
 1460      return addErrorAndRecover(
"Missing ':' after object member name", colon,
 
 1463    Value& value = currentValue()[name];
 
 1464    nodes_.push(&value);
 
 1465    bool ok = readValue();
 
 1468      return recoverFromError(tokenObjectEnd);
 
 1471    if (!readTokenSkippingComments(comma) ||
 
 1472        (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) {
 
 1473      return addErrorAndRecover(
"Missing ',' or '}' in object declaration",
 
 1474                                comma, tokenObjectEnd);
 
 1476    if (comma.type_ == tokenObjectEnd)
 
 1479  return addErrorAndRecover(
"Missing '}' or object member name", tokenName,
 
 1483bool OurReader::readArray(Token& token) {
 
 1490    if (current_ != end_ && *current_ == 
']' &&
 
 1492         (features_.allowTrailingCommas_ &&
 
 1493          !features_.allowDroppedNullPlaceholders_))) 
 
 1497      readToken(endArray);
 
 1500    Value& value = currentValue()[index++];
 
 1501    nodes_.push(&value);
 
 1502    bool ok = readValue();
 
 1505      return recoverFromError(tokenArrayEnd);
 
 1509    ok = readTokenSkippingComments(currentToken);
 
 1510    bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
 
 1511                         currentToken.type_ != tokenArrayEnd);
 
 1512    if (!ok || badTokenType) {
 
 1513      return addErrorAndRecover(
"Missing ',' or ']' in array declaration",
 
 1514                                currentToken, tokenArrayEnd);
 
 1516    if (currentToken.type_ == tokenArrayEnd)
 
 1522bool OurReader::decodeNumber(Token& token) {
 
 1524  if (!decodeNumber(token, decoded))
 
 1532bool OurReader::decodeNumber(Token& token, Value& decoded) {
 
 1536  Location current = token.start_;
 
 1537  const bool isNegative = *current == 
'-';
 
 1546                "Int must be smaller than UInt");
 
 1553                "The absolute value of minLargestInt must be greater than or " 
 1554                "equal to maxLargestInt");
 
 1556                "The absolute value of minLargestInt must be only 1 magnitude " 
 1557                "larger than maxLargest Int");
 
 1568  static constexpr auto negative_threshold =
 
 1570  static constexpr auto negative_last_digit =
 
 1574      isNegative ? negative_threshold : positive_threshold;
 
 1576      isNegative ? negative_last_digit : positive_last_digit;
 
 1579  while (current < token.end_) {
 
 1580    Char c = *current++;
 
 1581    if (c < 
'0' || c > 
'9')
 
 1582      return decodeDouble(token, decoded);
 
 1584    const auto digit(
static_cast<Value::UInt>(c - 
'0'));
 
 1585    if (value >= threshold) {
 
 1591      if (value > threshold || current != token.end_ ||
 
 1592          digit > max_last_digit) {
 
 1593        return decodeDouble(token, decoded);
 
 1596    value = value * 10 + digit;
 
 1601    const auto last_digit = 
static_cast<Value::UInt>(value % 10);
 
 1612bool OurReader::decodeDouble(Token& token) {
 
 1614  if (!decodeDouble(token, decoded))
 
 1622bool OurReader::decodeDouble(Token& token, Value& decoded) {
 
 1625  if (!(is >> value)) {
 
 1626    if (value == std::numeric_limits<double>::max())
 
 1627      value = std::numeric_limits<double>::infinity();
 
 1628    else if (value == std::numeric_limits<double>::lowest())
 
 1629      value = -std::numeric_limits<double>::infinity();
 
 1630    else if (!std::isinf(value))
 
 1632          "'" + 
String(token.start_, token.end_) + 
"' is not a number.", token);
 
 1638bool OurReader::decodeString(Token& token) {
 
 1640  if (!decodeString(token, decoded_string))
 
 1642  Value decoded(decoded_string);
 
 1649bool OurReader::decodeString(Token& token, 
String& decoded) {
 
 1650  decoded.reserve(
static_cast<size_t>(token.end_ - token.start_ - 2));
 
 1651  Location current = token.start_ + 1; 
 
 1652  Location end = token.end_ - 1;       
 
 1653  while (current != end) {
 
 1654    Char c = *current++;
 
 1659        return addError(
"Empty escape sequence in string", token, current);
 
 1660      Char escape = *current++;
 
 1687        unsigned int unicode;
 
 1688        if (!decodeUnicodeCodePoint(token, current, end, unicode))
 
 1693        return addError(
"Bad escape sequence in string", token, current);
 
 1702bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current,
 
 1703                                       Location end, 
unsigned int& unicode) {
 
 1705  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
 
 1707  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
 
 1709    if (end - current < 6)
 
 1711          "additional six characters expected to parse unicode surrogate pair.",
 
 1713    if (*(current++) == 
'\\' && *(current++) == 
'u') {
 
 1714      unsigned int surrogatePair;
 
 1715      if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
 
 1716        unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
 
 1720      return addError(
"expecting another \\u token to begin the second half of " 
 1721                      "a unicode surrogate pair",
 
 1727bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current,
 
 1729                                            unsigned int& ret_unicode) {
 
 1730  if (end - current < 4)
 
 1732        "Bad unicode escape sequence in string: four digits expected.", token,
 
 1735  for (
int index = 0; index < 4; ++index) {
 
 1736    Char c = *current++;
 
 1738    if (c >= 
'0' && c <= 
'9')
 
 1740    else if (c >= 
'a' && c <= 
'f')
 
 1741      unicode += c - 
'a' + 10;
 
 1742    else if (c >= 
'A' && c <= 
'F')
 
 1743      unicode += c - 
'A' + 10;
 
 1746          "Bad unicode escape sequence in string: hexadecimal digit expected.",
 
 1749  ret_unicode = 
static_cast<unsigned int>(unicode);
 
 1753bool OurReader::addError(
const String& message, Token& token, Location extra) {
 
 1755  info.token_ = token;
 
 1756  info.message_ = message;
 
 1757  info.extra_ = extra;
 
 1758  errors_.push_back(info);
 
 1762bool OurReader::recoverFromError(TokenType skipUntilToken) {
 
 1763  size_t errorCount = errors_.size();
 
 1766    if (!readToken(skip))
 
 1767      errors_.resize(errorCount); 
 
 1768    if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
 
 1771  errors_.resize(errorCount);
 
 1775bool OurReader::addErrorAndRecover(
const String& message, Token& token,
 
 1776                                   TokenType skipUntilToken) {
 
 1777  addError(message, token);
 
 1778  return recoverFromError(skipUntilToken);
 
 1781Value& OurReader::currentValue() { 
return *(nodes_.top()); }
 
 1783OurReader::Char OurReader::getNextChar() {
 
 1784  if (current_ == end_)
 
 1789void OurReader::getLocationLineAndColumn(Location location, 
int& line,
 
 1790                                         int& column)
 const {
 
 1791  Location current = begin_;
 
 1792  Location lastLineStart = current;
 
 1794  while (current < location && current != end_) {
 
 1795    Char c = *current++;
 
 1797      if (current != end_ && *current == 
'\n')
 
 1799      lastLineStart = current;
 
 1801    } 
else if (c == 
'\n') {
 
 1802      lastLineStart = current;
 
 1807  column = int(location - lastLineStart) + 1;
 
 1811String OurReader::getLocationLineAndColumn(Location location)
 const {
 
 1813  getLocationLineAndColumn(location, line, column);
 
 1814  char buffer[18 + 16 + 16 + 1];
 
 1815  jsoncpp_snprintf(buffer, 
sizeof(buffer), 
"Line %d, Column %d", line, column);
 
 1819String OurReader::getFormattedErrorMessages()
 const {
 
 1821  for (
const auto& error : errors_) {
 
 1823        "* " + getLocationLineAndColumn(error.token_.start_) + 
"\n";
 
 1824    formattedMessage += 
"  " + error.message_ + 
"\n";
 
 1827          "See " + getLocationLineAndColumn(error.extra_) + 
" for detail.\n";
 
 1829  return formattedMessage;
 
 1832std::vector<CharReader::StructuredError>
 
 1833OurReader::getStructuredErrors()
 const {
 
 1834  std::vector<CharReader::StructuredError> allErrors;
 
 1835  for (
const auto& error : errors_) {
 
 1836    CharReader::StructuredError structured;
 
 1837    structured.offset_start = error.token_.start_ - begin_;
 
 1838    structured.offset_limit = error.token_.end_ - begin_;
 
 1839    structured.message = error.message_;
 
 1840    allErrors.push_back(structured);
 
 1845class OurCharReader : 
public CharReader {
 
 1848  OurCharReader(
bool collectComments, OurFeatures 
const& features)
 
 1850            std::unique_ptr<OurImpl>(new OurImpl(collectComments, features))) {}
 
 1853  class OurImpl : 
public Impl {
 
 1855    OurImpl(
bool collectComments, OurFeatures 
const& features)
 
 1856        : collectComments_(collectComments), reader_(features) {}
 
 1858    bool parse(
char const* beginDoc, 
char const* endDoc, Value* root,
 
 1860      bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
 
 1862        *errs = reader_.getFormattedErrorMessages();
 
 1867    std::vector<CharReader::StructuredError>
 
 1868    getStructuredErrors()
 const override {
 
 1869      return reader_.getStructuredErrors();
 
 1873    bool const collectComments_;
 
 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)[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;
 
 
 1967  (*settings)[
"allowComments"] = 
false;
 
 1968  (*settings)[
"allowTrailingCommas"] = 
false;
 
 1969  (*settings)[
"strictRoot"] = 
false;
 
 1970  (*settings)[
"allowDroppedNullPlaceholders"] = 
false;
 
 1971  (*settings)[
"allowNumericKeys"] = 
false;
 
 1972  (*settings)[
"allowSingleQuotes"] = 
false;
 
 1973  (*settings)[
"stackLimit"] = 1000;
 
 1974  (*settings)[
"failIfExtra"] = 
true;
 
 1975  (*settings)[
"rejectDupKeys"] = 
false;
 
 1976  (*settings)[
"allowSpecialFloats"] = 
false;
 
 1977  (*settings)[
"skipBom"] = 
false;
 
 
 1981std::vector<CharReader::StructuredError>
 
 1983  return _impl->getStructuredErrors();
 
 
 1988  return _impl->parse(beginDoc, endDoc, root, errs);
 
 
 1997  ssin << sin.rdbuf();
 
 1998  String doc = std::move(ssin).str();
 
 1999  char const* begin = doc.data();
 
 2000  char const* end = begin + doc.size();
 
 2003  return reader->parse(begin, end, root, errs);
 
 
 2011    throwRuntimeError(errs);
 
 
virtual CharReader * newCharReader() const =0
Allocate a CharReader via operator new().
Build a CharReader implementation.
static void setDefaults(Json::Value *settings)
Called by ctor, but you can use this to reset settings_.
static void ecma404Mode(Json::Value *settings)
ECMA-404 mode.
Value & operator[](const String &key)
A simple way to update a specific setting.
CharReader * newCharReader() const override
Allocate a CharReader via operator new().
static void strictMode(Json::Value *settings)
Same as old Features::strictMode().
Json::Value settings_
Configuration of this builder.
~CharReaderBuilder() override
bool validate(Json::Value *invalid) const
Interface for reading JSON from a char array.
CharReader(std::unique_ptr< Impl > impl)
std::vector< StructuredError > getStructuredErrors() const
Returns a vector of structured errors encountered while parsing.
virtual bool parse(char const *beginDoc, char const *endDoc, Value *root, String *errs)
Read a Value from a JSON document.
Configuration passed to reader and writer.
bool strictRoot_
true if root must be either an array or an object value.
bool allowComments_
true if comments are allowed. Default: true.
bool allowDroppedNullPlaceholders_
true if dropped null placeholders are allowed. Default: false.
static Features all()
A configuration that allows all features and assumes all strings are UTF-8.
Features()
Initialize the configuration like JsonConfig::allFeatures;.
static Features strictMode()
A configuration that is strictly compatible with the JSON specification.
bool allowNumericKeys_
true if numeric object key are allowed. Default: false.
Reader()
Constructs a Reader allowing all features for parsing.
bool pushError(const Value &value, const String &message)
Add a semantic error message.
bool good() const
Return whether there are any errors.
std::vector< StructuredError > getStructuredErrors() const
Returns a vector of structured errors encountered while parsing.
bool parse(const std::string &document, Value &root, bool collectComments=true)
Read a Value from a JSON document.
String getFormattedErrorMessages() const
Returns a user friendly string that list errors in the parsed document.
const_iterator begin() const
bool empty() const
Return true if empty array, empty object, or null; otherwise, false.
static constexpr LargestInt maxLargestInt
Maximum signed integer value that can be stored in a Json::Value.
void setComment(const char *comment, size_t len, CommentPlacement placement)
Comments must be //... or /* ... */.
ptrdiff_t getOffsetLimit() const
const_iterator end() const
void swapPayload(Value &other)
Swap values but leave comments and source offsets in place.
void setOffsetLimit(ptrdiff_t limit)
Json::LargestInt LargestInt
Json::LargestUInt LargestUInt
void setOffsetStart(ptrdiff_t start)
static constexpr Int maxInt
Maximum signed int value that can be stored in a Json::Value.
static constexpr LargestUInt maxLargestUInt
Maximum unsigned integer value that can be stored in a Json::Value.
static constexpr LargestInt minLargestInt
Minimum signed integer value that can be stored in a Json::Value.
ptrdiff_t getOffsetStart() const
#define JSONCPP_DEPRECATED_STACK_LIMIT
static size_t const stackLimit_g
JSON (JavaScript Object Notation).
std::basic_ostringstream< String::value_type, String::traits_type, String::allocator_type > OStringStream
@ commentAfterOnSameLine
a comment just after a value on the same line
@ commentBefore
a comment placed on the line before a value
@ commentAfter
a comment on the line after a value (only make sense for
std::basic_istringstream< String::value_type, String::traits_type, String::allocator_type > IStringStream
@ arrayValue
array value (ordered list)
@ objectValue
object value (collection of name/value pairs).
static String codePointToUTF8(unsigned int cp)
Converts a unicode code-point to UTF-8.
std::auto_ptr< CharReader > CharReaderPtr
std::basic_string< char, std::char_traits< char >, Allocator< char > > String
IStream & operator>>(IStream &, Value &)
Read from 'sin' into 'root'.
bool parseFromStream(CharReader::Factory const &, IStream &, Value *root, String *errs)
Consume entire stream and use its begin/end.
An error tagged with where in the JSON text it was encountered.