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