JsonCpp project page JsonCpp home page

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