JsonCpp project page Classes Namespace JsonCpp home page

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