JsonCpp project page JsonCpp home page

json_reader.cpp
Go to the documentation of this file.
1 // Copyright 2007-2011 Baptiste Lepilleur
2 // Distributed under MIT license, or public domain if desired and
3 // recognized in your jurisdiction.
4 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
5 
6 #if !defined(JSON_IS_AMALGAMATION)
7 #include <json/assertions.h>
8 #include <json/reader.h>
9 #include <json/value.h>
10 #include "json_tool.h"
11 #endif // if !defined(JSON_IS_AMALGAMATION)
12 #include <utility>
13 #include <cstdio>
14 #include <cassert>
15 #include <cstring>
16 #include <istream>
17 #include <sstream>
18 #include <memory>
19 #include <set>
20 #include <limits>
21 
22 #if defined(_MSC_VER)
23 #if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
24 #define snprintf sprintf_s
25 #elif _MSC_VER >= 1900 // VC++ 14.0 and above
26 #define snprintf std::snprintf
27 #else
28 #define snprintf _snprintf
29 #endif
30 #elif defined(__ANDROID__) || defined(__QNXNTO__)
31 #define snprintf snprintf
32 #elif __cplusplus >= 201103L
33 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
34 #define snprintf std::snprintf
35 #endif
36 #endif
37 
38 #if defined(__QNXNTO__)
39 #define sscanf std::sscanf
40 #endif
41 
42 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
43 // Disable warning about strdup being deprecated.
44 #pragma warning(disable : 4996)
45 #endif
46 
47 static int const stackLimit_g = 1000;
48 static int stackDepth_g = 0; // see readValue()
49 
50 namespace Json {
51 
52 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
53 typedef std::unique_ptr<CharReader> CharReaderPtr;
54 #else
55 typedef std::auto_ptr<CharReader> CharReaderPtr;
56 #endif
57 
58 // Implementation of class Features
59 // ////////////////////////////////
60 
62  : allowComments_(true), strictRoot_(false),
63  allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
64 
66 
68  Features features;
69  features.allowComments_ = false;
70  features.strictRoot_ = true;
71  features.allowDroppedNullPlaceholders_ = false;
72  features.allowNumericKeys_ = false;
73  return features;
74 }
75 
76 // Implementation of class Reader
77 // ////////////////////////////////
78 
80  for (; begin < end; ++begin)
81  if (*begin == '\n' || *begin == '\r')
82  return true;
83  return false;
84 }
85 
86 // Class Reader
87 // //////////////////////////////////////////////////////////////////
88 
90  : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
91  lastValue_(), commentsBefore_(), features_(Features::all()),
92  collectComments_() {}
93 
94 Reader::Reader(const Features& features)
95  : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
96  lastValue_(), commentsBefore_(), features_(features), collectComments_() {
97 }
98 
99 bool
100 Reader::parse(const std::string& document, Value& root, bool collectComments) {
101  JSONCPP_STRING documentCopy(document.data(), document.data() + document.capacity());
102  std::swap(documentCopy, document_);
103  const char* begin = document_.c_str();
104  const char* end = begin + document_.length();
105  return parse(begin, end, root, collectComments);
106 }
107 
108 bool Reader::parse(std::istream& sin, Value& root, bool collectComments) {
109  // std::istream_iterator<char> begin(sin);
110  // std::istream_iterator<char> end;
111  // Those would allow streamed input from a file, if parse() were a
112  // template function.
113 
114  // Since JSONCPP_STRING is reference-counted, this at least does not
115  // create an extra copy.
116  JSONCPP_STRING doc;
117  std::getline(sin, doc, (char)EOF);
118  return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
119 }
120 
121 bool Reader::parse(const char* beginDoc,
122  const char* endDoc,
123  Value& root,
124  bool collectComments) {
125  if (!features_.allowComments_) {
126  collectComments = false;
127  }
128 
129  begin_ = beginDoc;
130  end_ = endDoc;
131  collectComments_ = collectComments;
132  current_ = begin_;
133  lastValueEnd_ = 0;
134  lastValue_ = 0;
135  commentsBefore_ = "";
136  errors_.clear();
137  while (!nodes_.empty())
138  nodes_.pop();
139  nodes_.push(&root);
140 
141  stackDepth_g = 0; // Yes, this is bad coding, but options are limited.
142  bool successful = readValue();
143  Token token;
144  skipCommentTokens(token);
145  if (collectComments_ && !commentsBefore_.empty())
146  root.setComment(commentsBefore_, commentAfter);
147  if (features_.strictRoot_) {
148  if (!root.isArray() && !root.isObject()) {
149  // Set error location to start of doc, ideally should be first token found
150  // in doc
151  token.type_ = tokenError;
152  token.start_ = beginDoc;
153  token.end_ = endDoc;
154  addError(
155  "A valid JSON document must be either an array or an object value.",
156  token);
157  return false;
158  }
159  }
160  return successful;
161 }
162 
163 bool Reader::readValue() {
164  // This is a non-reentrant way to support a stackLimit. Terrible!
165  // But this deprecated class has a security problem: Bad input can
166  // cause a seg-fault. This seems like a fair, binary-compatible way
167  // to prevent the problem.
168  if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
169  ++stackDepth_g;
170 
171  Token token;
172  skipCommentTokens(token);
173  bool successful = true;
174 
175  if (collectComments_ && !commentsBefore_.empty()) {
176  currentValue().setComment(commentsBefore_, commentBefore);
177  commentsBefore_ = "";
178  }
179 
180  switch (token.type_) {
181  case tokenObjectBegin:
182  successful = readObject(token);
183  currentValue().setOffsetLimit(current_ - begin_);
184  break;
185  case tokenArrayBegin:
186  successful = readArray(token);
187  currentValue().setOffsetLimit(current_ - begin_);
188  break;
189  case tokenNumber:
190  successful = decodeNumber(token);
191  break;
192  case tokenString:
193  successful = decodeString(token);
194  break;
195  case tokenTrue:
196  {
197  Value v(true);
198  currentValue().swapPayload(v);
199  currentValue().setOffsetStart(token.start_ - begin_);
200  currentValue().setOffsetLimit(token.end_ - begin_);
201  }
202  break;
203  case tokenFalse:
204  {
205  Value v(false);
206  currentValue().swapPayload(v);
207  currentValue().setOffsetStart(token.start_ - begin_);
208  currentValue().setOffsetLimit(token.end_ - begin_);
209  }
210  break;
211  case tokenNull:
212  {
213  Value v;
214  currentValue().swapPayload(v);
215  currentValue().setOffsetStart(token.start_ - begin_);
216  currentValue().setOffsetLimit(token.end_ - begin_);
217  }
218  break;
219  case tokenArraySeparator:
220  case tokenObjectEnd:
221  case tokenArrayEnd:
222  if (features_.allowDroppedNullPlaceholders_) {
223  // "Un-read" the current token and mark the current value as a null
224  // token.
225  current_--;
226  Value v;
227  currentValue().swapPayload(v);
228  currentValue().setOffsetStart(current_ - begin_ - 1);
229  currentValue().setOffsetLimit(current_ - begin_);
230  break;
231  } // Else, fall through...
232  default:
233  currentValue().setOffsetStart(token.start_ - begin_);
234  currentValue().setOffsetLimit(token.end_ - begin_);
235  return addError("Syntax error: value, object or array expected.", token);
236  }
237 
238  if (collectComments_) {
239  lastValueEnd_ = current_;
240  lastValue_ = &currentValue();
241  }
242 
243  --stackDepth_g;
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 
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_ != 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 = "";
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_ == ']') // 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);
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  typedef std::stack<Value*> Nodes;
1022  Nodes nodes_;
1023  Errors errors_;
1024  JSONCPP_STRING document_;
1025  Location begin_;
1026  Location end_;
1027  Location current_;
1028  Location lastValueEnd_;
1029  Value* lastValue_;
1030  JSONCPP_STRING commentsBefore_;
1031  int stackDepth_;
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  stackDepth_(0),
1043  features_(features), collectComments_() {
1044 }
1045 
1046 bool OurReader::parse(const char* beginDoc,
1047  const char* endDoc,
1048  Value& root,
1049  bool collectComments) {
1050  if (!features_.allowComments_) {
1051  collectComments = false;
1052  }
1053 
1054  begin_ = beginDoc;
1055  end_ = endDoc;
1056  collectComments_ = collectComments;
1057  current_ = begin_;
1058  lastValueEnd_ = 0;
1059  lastValue_ = 0;
1060  commentsBefore_ = "";
1061  errors_.clear();
1062  while (!nodes_.empty())
1063  nodes_.pop();
1064  nodes_.push(&root);
1065 
1066  stackDepth_ = 0;
1067  bool successful = readValue();
1068  Token token;
1069  skipCommentTokens(token);
1070  if (features_.failIfExtra_) {
1071  if (token.type_ != tokenError && token.type_ != tokenEndOfStream) {
1072  addError("Extra non-whitespace after JSON value.", token);
1073  return false;
1074  }
1075  }
1076  if (collectComments_ && !commentsBefore_.empty())
1077  root.setComment(commentsBefore_, commentAfter);
1078  if (features_.strictRoot_) {
1079  if (!root.isArray() && !root.isObject()) {
1080  // Set error location to start of doc, ideally should be first token found
1081  // in doc
1082  token.type_ = tokenError;
1083  token.start_ = beginDoc;
1084  token.end_ = endDoc;
1085  addError(
1086  "A valid JSON document must be either an array or an object value.",
1087  token);
1088  return false;
1089  }
1090  }
1091  return successful;
1092 }
1093 
1094 bool OurReader::readValue() {
1095  if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");
1096  ++stackDepth_;
1097  Token token;
1098  skipCommentTokens(token);
1099  bool successful = true;
1100 
1101  if (collectComments_ && !commentsBefore_.empty()) {
1102  currentValue().setComment(commentsBefore_, commentBefore);
1103  commentsBefore_ = "";
1104  }
1105 
1106  switch (token.type_) {
1107  case tokenObjectBegin:
1108  successful = readObject(token);
1109  currentValue().setOffsetLimit(current_ - begin_);
1110  break;
1111  case tokenArrayBegin:
1112  successful = readArray(token);
1113  currentValue().setOffsetLimit(current_ - begin_);
1114  break;
1115  case tokenNumber:
1116  successful = decodeNumber(token);
1117  break;
1118  case tokenString:
1119  successful = decodeString(token);
1120  break;
1121  case tokenTrue:
1122  {
1123  Value v(true);
1124  currentValue().swapPayload(v);
1125  currentValue().setOffsetStart(token.start_ - begin_);
1126  currentValue().setOffsetLimit(token.end_ - begin_);
1127  }
1128  break;
1129  case tokenFalse:
1130  {
1131  Value v(false);
1132  currentValue().swapPayload(v);
1133  currentValue().setOffsetStart(token.start_ - begin_);
1134  currentValue().setOffsetLimit(token.end_ - begin_);
1135  }
1136  break;
1137  case tokenNull:
1138  {
1139  Value v;
1140  currentValue().swapPayload(v);
1141  currentValue().setOffsetStart(token.start_ - begin_);
1142  currentValue().setOffsetLimit(token.end_ - begin_);
1143  }
1144  break;
1145  case tokenNaN:
1146  {
1147  Value v(std::numeric_limits<double>::quiet_NaN());
1148  currentValue().swapPayload(v);
1149  currentValue().setOffsetStart(token.start_ - begin_);
1150  currentValue().setOffsetLimit(token.end_ - begin_);
1151  }
1152  break;
1153  case tokenPosInf:
1154  {
1155  Value v(std::numeric_limits<double>::infinity());
1156  currentValue().swapPayload(v);
1157  currentValue().setOffsetStart(token.start_ - begin_);
1158  currentValue().setOffsetLimit(token.end_ - begin_);
1159  }
1160  break;
1161  case tokenNegInf:
1162  {
1163  Value v(-std::numeric_limits<double>::infinity());
1164  currentValue().swapPayload(v);
1165  currentValue().setOffsetStart(token.start_ - begin_);
1166  currentValue().setOffsetLimit(token.end_ - begin_);
1167  }
1168  break;
1169  case tokenArraySeparator:
1170  case tokenObjectEnd:
1171  case tokenArrayEnd:
1172  if (features_.allowDroppedNullPlaceholders_) {
1173  // "Un-read" the current token and mark the current value as a null
1174  // token.
1175  current_--;
1176  Value v;
1177  currentValue().swapPayload(v);
1178  currentValue().setOffsetStart(current_ - begin_ - 1);
1179  currentValue().setOffsetLimit(current_ - begin_);
1180  break;
1181  } // else, fall through ...
1182  default:
1183  currentValue().setOffsetStart(token.start_ - begin_);
1184  currentValue().setOffsetLimit(token.end_ - begin_);
1185  return addError("Syntax error: value, object or array expected.", token);
1186  }
1187 
1188  if (collectComments_) {
1189  lastValueEnd_ = current_;
1190  lastValue_ = &currentValue();
1191  }
1192 
1193  --stackDepth_;
1194  return successful;
1195 }
1196 
1197 void OurReader::skipCommentTokens(Token& token) {
1198  if (features_.allowComments_) {
1199  do {
1200  readToken(token);
1201  } while (token.type_ == tokenComment);
1202  } else {
1203  readToken(token);
1204  }
1205 }
1206 
1207 bool OurReader::readToken(Token& token) {
1208  skipSpaces();
1209  token.start_ = current_;
1210  Char c = getNextChar();
1211  bool ok = true;
1212  switch (c) {
1213  case '{':
1214  token.type_ = tokenObjectBegin;
1215  break;
1216  case '}':
1217  token.type_ = tokenObjectEnd;
1218  break;
1219  case '[':
1220  token.type_ = tokenArrayBegin;
1221  break;
1222  case ']':
1223  token.type_ = tokenArrayEnd;
1224  break;
1225  case '"':
1226  token.type_ = tokenString;
1227  ok = readString();
1228  break;
1229  case '\'':
1230  if (features_.allowSingleQuotes_) {
1231  token.type_ = tokenString;
1232  ok = readStringSingleQuote();
1233  break;
1234  } // else continue
1235  case '/':
1236  token.type_ = tokenComment;
1237  ok = readComment();
1238  break;
1239  case '0':
1240  case '1':
1241  case '2':
1242  case '3':
1243  case '4':
1244  case '5':
1245  case '6':
1246  case '7':
1247  case '8':
1248  case '9':
1249  token.type_ = tokenNumber;
1250  readNumber(false);
1251  break;
1252  case '-':
1253  if (readNumber(true)) {
1254  token.type_ = tokenNumber;
1255  } else {
1256  token.type_ = tokenNegInf;
1257  ok = features_.allowSpecialFloats_ && match("nfinity", 7);
1258  }
1259  break;
1260  case 't':
1261  token.type_ = tokenTrue;
1262  ok = match("rue", 3);
1263  break;
1264  case 'f':
1265  token.type_ = tokenFalse;
1266  ok = match("alse", 4);
1267  break;
1268  case 'n':
1269  token.type_ = tokenNull;
1270  ok = match("ull", 3);
1271  break;
1272  case 'N':
1273  if (features_.allowSpecialFloats_) {
1274  token.type_ = tokenNaN;
1275  ok = match("aN", 2);
1276  } else {
1277  ok = false;
1278  }
1279  break;
1280  case 'I':
1281  if (features_.allowSpecialFloats_) {
1282  token.type_ = tokenPosInf;
1283  ok = match("nfinity", 7);
1284  } else {
1285  ok = false;
1286  }
1287  break;
1288  case ',':
1289  token.type_ = tokenArraySeparator;
1290  break;
1291  case ':':
1292  token.type_ = tokenMemberSeparator;
1293  break;
1294  case 0:
1295  token.type_ = tokenEndOfStream;
1296  break;
1297  default:
1298  ok = false;
1299  break;
1300  }
1301  if (!ok)
1302  token.type_ = tokenError;
1303  token.end_ = current_;
1304  return true;
1305 }
1306 
1307 void OurReader::skipSpaces() {
1308  while (current_ != end_) {
1309  Char c = *current_;
1310  if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
1311  ++current_;
1312  else
1313  break;
1314  }
1315 }
1316 
1317 bool OurReader::match(Location pattern, int patternLength) {
1318  if (end_ - current_ < patternLength)
1319  return false;
1320  int index = patternLength;
1321  while (index--)
1322  if (current_[index] != pattern[index])
1323  return false;
1324  current_ += patternLength;
1325  return true;
1326 }
1327 
1328 bool OurReader::readComment() {
1329  Location commentBegin = current_ - 1;
1330  Char c = getNextChar();
1331  bool successful = false;
1332  if (c == '*')
1333  successful = readCStyleComment();
1334  else if (c == '/')
1335  successful = readCppStyleComment();
1336  if (!successful)
1337  return false;
1338 
1339  if (collectComments_) {
1340  CommentPlacement placement = commentBefore;
1341  if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
1342  if (c != '*' || !containsNewLine(commentBegin, current_))
1343  placement = commentAfterOnSameLine;
1344  }
1345 
1346  addComment(commentBegin, current_, placement);
1347  }
1348  return true;
1349 }
1350 
1351 void
1352 OurReader::addComment(Location begin, Location end, CommentPlacement placement) {
1353  assert(collectComments_);
1354  const JSONCPP_STRING& normalized = normalizeEOL(begin, end);
1355  if (placement == commentAfterOnSameLine) {
1356  assert(lastValue_ != 0);
1357  lastValue_->setComment(normalized, placement);
1358  } else {
1359  commentsBefore_ += normalized;
1360  }
1361 }
1362 
1363 bool OurReader::readCStyleComment() {
1364  while (current_ != end_) {
1365  Char c = getNextChar();
1366  if (c == '*' && *current_ == '/')
1367  break;
1368  }
1369  return getNextChar() == '/';
1370 }
1371 
1372 bool OurReader::readCppStyleComment() {
1373  while (current_ != end_) {
1374  Char c = getNextChar();
1375  if (c == '\n')
1376  break;
1377  if (c == '\r') {
1378  // Consume DOS EOL. It will be normalized in addComment.
1379  if (current_ != end_ && *current_ == '\n')
1380  getNextChar();
1381  // Break on Moc OS 9 EOL.
1382  break;
1383  }
1384  }
1385  return true;
1386 }
1387 
1388 bool OurReader::readNumber(bool checkInf) {
1389  const char *p = current_;
1390  if (checkInf && p != end_ && *p == 'I') {
1391  current_ = ++p;
1392  return false;
1393  }
1394  char c = '0'; // stopgap for already consumed character
1395  // integral part
1396  while (c >= '0' && c <= '9')
1397  c = (current_ = p) < end_ ? *p++ : 0;
1398  // fractional part
1399  if (c == '.') {
1400  c = (current_ = p) < end_ ? *p++ : 0;
1401  while (c >= '0' && c <= '9')
1402  c = (current_ = p) < end_ ? *p++ : 0;
1403  }
1404  // exponential part
1405  if (c == 'e' || c == 'E') {
1406  c = (current_ = p) < end_ ? *p++ : 0;
1407  if (c == '+' || c == '-')
1408  c = (current_ = p) < end_ ? *p++ : 0;
1409  while (c >= '0' && c <= '9')
1410  c = (current_ = p) < end_ ? *p++ : 0;
1411  }
1412  return true;
1413 }
1414 bool OurReader::readString() {
1415  Char c = 0;
1416  while (current_ != end_) {
1417  c = getNextChar();
1418  if (c == '\\')
1419  getNextChar();
1420  else if (c == '"')
1421  break;
1422  }
1423  return c == '"';
1424 }
1425 
1426 
1427 bool OurReader::readStringSingleQuote() {
1428  Char c = 0;
1429  while (current_ != end_) {
1430  c = getNextChar();
1431  if (c == '\\')
1432  getNextChar();
1433  else if (c == '\'')
1434  break;
1435  }
1436  return c == '\'';
1437 }
1438 
1439 bool OurReader::readObject(Token& tokenStart) {
1440  Token tokenName;
1441  JSONCPP_STRING name;
1442  Value init(objectValue);
1443  currentValue().swapPayload(init);
1444  currentValue().setOffsetStart(tokenStart.start_ - begin_);
1445  while (readToken(tokenName)) {
1446  bool initialTokenOk = true;
1447  while (tokenName.type_ == tokenComment && initialTokenOk)
1448  initialTokenOk = readToken(tokenName);
1449  if (!initialTokenOk)
1450  break;
1451  if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
1452  return true;
1453  name = "";
1454  if (tokenName.type_ == tokenString) {
1455  if (!decodeString(tokenName, name))
1456  return recoverFromError(tokenObjectEnd);
1457  } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1458  Value numberName;
1459  if (!decodeNumber(tokenName, numberName))
1460  return recoverFromError(tokenObjectEnd);
1461  name = numberName.asString();
1462  } else {
1463  break;
1464  }
1465 
1466  Token colon;
1467  if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1468  return addErrorAndRecover(
1469  "Missing ':' after object member name", colon, tokenObjectEnd);
1470  }
1471  if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");
1472  if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1473  JSONCPP_STRING msg = "Duplicate key: '" + name + "'";
1474  return addErrorAndRecover(
1475  msg, tokenName, tokenObjectEnd);
1476  }
1477  Value& value = currentValue()[name];
1478  nodes_.push(&value);
1479  bool ok = readValue();
1480  nodes_.pop();
1481  if (!ok) // error already set
1482  return recoverFromError(tokenObjectEnd);
1483 
1484  Token comma;
1485  if (!readToken(comma) ||
1486  (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1487  comma.type_ != tokenComment)) {
1488  return addErrorAndRecover(
1489  "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
1490  }
1491  bool finalizeTokenOk = true;
1492  while (comma.type_ == tokenComment && finalizeTokenOk)
1493  finalizeTokenOk = readToken(comma);
1494  if (comma.type_ == tokenObjectEnd)
1495  return true;
1496  }
1497  return addErrorAndRecover(
1498  "Missing '}' or object member name", tokenName, tokenObjectEnd);
1499 }
1500 
1501 bool OurReader::readArray(Token& tokenStart) {
1502  Value init(arrayValue);
1503  currentValue().swapPayload(init);
1504  currentValue().setOffsetStart(tokenStart.start_ - begin_);
1505  skipSpaces();
1506  if (*current_ == ']') // empty array
1507  {
1508  Token endArray;
1509  readToken(endArray);
1510  return true;
1511  }
1512  int index = 0;
1513  for (;;) {
1514  Value& value = currentValue()[index++];
1515  nodes_.push(&value);
1516  bool ok = readValue();
1517  nodes_.pop();
1518  if (!ok) // error already set
1519  return recoverFromError(tokenArrayEnd);
1520 
1521  Token token;
1522  // Accept Comment after last item in the array.
1523  ok = readToken(token);
1524  while (token.type_ == tokenComment && ok) {
1525  ok = readToken(token);
1526  }
1527  bool badTokenType =
1528  (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
1529  if (!ok || badTokenType) {
1530  return addErrorAndRecover(
1531  "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
1532  }
1533  if (token.type_ == tokenArrayEnd)
1534  break;
1535  }
1536  return true;
1537 }
1538 
1539 bool OurReader::decodeNumber(Token& token) {
1540  Value decoded;
1541  if (!decodeNumber(token, decoded))
1542  return false;
1543  currentValue().swapPayload(decoded);
1544  currentValue().setOffsetStart(token.start_ - begin_);
1545  currentValue().setOffsetLimit(token.end_ - begin_);
1546  return true;
1547 }
1548 
1549 bool OurReader::decodeNumber(Token& token, Value& decoded) {
1550  // Attempts to parse the number as an integer. If the number is
1551  // larger than the maximum supported value of an integer then
1552  // we decode the number as a double.
1553  Location current = token.start_;
1554  bool isNegative = *current == '-';
1555  if (isNegative)
1556  ++current;
1557  // TODO: Help the compiler do the div and mod at compile time or get rid of them.
1558  Value::LargestUInt maxIntegerValue =
1561  Value::LargestUInt threshold = maxIntegerValue / 10;
1562  Value::LargestUInt value = 0;
1563  while (current < token.end_) {
1564  Char c = *current++;
1565  if (c < '0' || c > '9')
1566  return decodeDouble(token, decoded);
1567  Value::UInt digit(static_cast<Value::UInt>(c - '0'));
1568  if (value >= threshold) {
1569  // We've hit or exceeded the max value divided by 10 (rounded down). If
1570  // a) we've only just touched the limit, b) this is the last digit, and
1571  // c) it's small enough to fit in that rounding delta, we're okay.
1572  // Otherwise treat this number as a double to avoid overflow.
1573  if (value > threshold || current != token.end_ ||
1574  digit > maxIntegerValue % 10) {
1575  return decodeDouble(token, decoded);
1576  }
1577  }
1578  value = value * 10 + digit;
1579  }
1580  if (isNegative)
1581  decoded = -Value::LargestInt(value);
1582  else if (value <= Value::LargestUInt(Value::maxInt))
1583  decoded = Value::LargestInt(value);
1584  else
1585  decoded = value;
1586  return true;
1587 }
1588 
1589 bool OurReader::decodeDouble(Token& token) {
1590  Value decoded;
1591  if (!decodeDouble(token, decoded))
1592  return false;
1593  currentValue().swapPayload(decoded);
1594  currentValue().setOffsetStart(token.start_ - begin_);
1595  currentValue().setOffsetLimit(token.end_ - begin_);
1596  return true;
1597 }
1598 
1599 bool OurReader::decodeDouble(Token& token, Value& decoded) {
1600  double value = 0;
1601  const int bufferSize = 32;
1602  int count;
1603  ptrdiff_t const length = token.end_ - token.start_;
1604 
1605  // Sanity check to avoid buffer overflow exploits.
1606  if (length < 0) {
1607  return addError("Unable to parse token length", token);
1608  }
1609  size_t const ulength = static_cast<size_t>(length);
1610 
1611  // Avoid using a string constant for the format control string given to
1612  // sscanf, as this can cause hard to debug crashes on OS X. See here for more
1613  // info:
1614  //
1615  // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
1616  char format[] = "%lf";
1617 
1618  if (length <= bufferSize) {
1619  Char buffer[bufferSize + 1];
1620  memcpy(buffer, token.start_, ulength);
1621  buffer[length] = 0;
1622  count = sscanf(buffer, format, &value);
1623  } else {
1624  JSONCPP_STRING buffer(token.start_, token.end_);
1625  count = sscanf(buffer.c_str(), format, &value);
1626  }
1627 
1628  if (count != 1)
1629  return addError("'" + JSONCPP_STRING(token.start_, token.end_) +
1630  "' is not a number.",
1631  token);
1632  decoded = value;
1633  return true;
1634 }
1635 
1636 bool OurReader::decodeString(Token& token) {
1637  JSONCPP_STRING decoded_string;
1638  if (!decodeString(token, decoded_string))
1639  return false;
1640  Value decoded(decoded_string);
1641  currentValue().swapPayload(decoded);
1642  currentValue().setOffsetStart(token.start_ - begin_);
1643  currentValue().setOffsetLimit(token.end_ - begin_);
1644  return true;
1645 }
1646 
1647 bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) {
1648  decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
1649  Location current = token.start_ + 1; // skip '"'
1650  Location end = token.end_ - 1; // do not include '"'
1651  while (current != end) {
1652  Char c = *current++;
1653  if (c == '"')
1654  break;
1655  else if (c == '\\') {
1656  if (current == end)
1657  return addError("Empty escape sequence in string", token, current);
1658  Char escape = *current++;
1659  switch (escape) {
1660  case '"':
1661  decoded += '"';
1662  break;
1663  case '/':
1664  decoded += '/';
1665  break;
1666  case '\\':
1667  decoded += '\\';
1668  break;
1669  case 'b':
1670  decoded += '\b';
1671  break;
1672  case 'f':
1673  decoded += '\f';
1674  break;
1675  case 'n':
1676  decoded += '\n';
1677  break;
1678  case 'r':
1679  decoded += '\r';
1680  break;
1681  case 't':
1682  decoded += '\t';
1683  break;
1684  case 'u': {
1685  unsigned int unicode;
1686  if (!decodeUnicodeCodePoint(token, current, end, unicode))
1687  return false;
1688  decoded += codePointToUTF8(unicode);
1689  } break;
1690  default:
1691  return addError("Bad escape sequence in string", token, current);
1692  }
1693  } else {
1694  decoded += c;
1695  }
1696  }
1697  return true;
1698 }
1699 
1700 bool OurReader::decodeUnicodeCodePoint(Token& token,
1701  Location& current,
1702  Location end,
1703  unsigned int& unicode) {
1704 
1705  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1706  return false;
1707  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1708  // surrogate pairs
1709  if (end - current < 6)
1710  return addError(
1711  "additional six characters expected to parse unicode surrogate pair.",
1712  token,
1713  current);
1714  unsigned int surrogatePair;
1715  if (*(current++) == '\\' && *(current++) == 'u') {
1716  if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1717  unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1718  } else
1719  return false;
1720  } else
1721  return addError("expecting another \\u token to begin the second half of "
1722  "a unicode surrogate pair",
1723  token,
1724  current);
1725  }
1726  return true;
1727 }
1728 
1729 bool OurReader::decodeUnicodeEscapeSequence(Token& token,
1730  Location& current,
1731  Location end,
1732  unsigned int& ret_unicode) {
1733  if (end - current < 4)
1734  return addError(
1735  "Bad unicode escape sequence in string: four digits expected.",
1736  token,
1737  current);
1738  int unicode = 0;
1739  for (int index = 0; index < 4; ++index) {
1740  Char c = *current++;
1741  unicode *= 16;
1742  if (c >= '0' && c <= '9')
1743  unicode += c - '0';
1744  else if (c >= 'a' && c <= 'f')
1745  unicode += c - 'a' + 10;
1746  else if (c >= 'A' && c <= 'F')
1747  unicode += c - 'A' + 10;
1748  else
1749  return addError(
1750  "Bad unicode escape sequence in string: hexadecimal digit expected.",
1751  token,
1752  current);
1753  }
1754  ret_unicode = static_cast<unsigned int>(unicode);
1755  return true;
1756 }
1757 
1758 bool
1759 OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) {
1760  ErrorInfo info;
1761  info.token_ = token;
1762  info.message_ = message;
1763  info.extra_ = extra;
1764  errors_.push_back(info);
1765  return false;
1766 }
1767 
1768 bool OurReader::recoverFromError(TokenType skipUntilToken) {
1769  size_t errorCount = errors_.size();
1770  Token skip;
1771  for (;;) {
1772  if (!readToken(skip))
1773  errors_.resize(errorCount); // discard errors caused by recovery
1774  if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
1775  break;
1776  }
1777  errors_.resize(errorCount);
1778  return false;
1779 }
1780 
1781 bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message,
1782  Token& token,
1783  TokenType skipUntilToken) {
1784  addError(message, token);
1785  return recoverFromError(skipUntilToken);
1786 }
1787 
1788 Value& OurReader::currentValue() { return *(nodes_.top()); }
1789 
1790 OurReader::Char OurReader::getNextChar() {
1791  if (current_ == end_)
1792  return 0;
1793  return *current_++;
1794 }
1795 
1796 void OurReader::getLocationLineAndColumn(Location location,
1797  int& line,
1798  int& column) const {
1799  Location current = begin_;
1800  Location lastLineStart = current;
1801  line = 0;
1802  while (current < location && current != end_) {
1803  Char c = *current++;
1804  if (c == '\r') {
1805  if (*current == '\n')
1806  ++current;
1807  lastLineStart = current;
1808  ++line;
1809  } else if (c == '\n') {
1810  lastLineStart = current;
1811  ++line;
1812  }
1813  }
1814  // column & line start at 1
1815  column = int(location - lastLineStart) + 1;
1816  ++line;
1817 }
1818 
1819 JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const {
1820  int line, column;
1821  getLocationLineAndColumn(location, line, column);
1822  char buffer[18 + 16 + 16 + 1];
1823  snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
1824  return buffer;
1825 }
1826 
1827 JSONCPP_STRING OurReader::getFormattedErrorMessages() const {
1828  JSONCPP_STRING formattedMessage;
1829  for (Errors::const_iterator itError = errors_.begin();
1830  itError != errors_.end();
1831  ++itError) {
1832  const ErrorInfo& error = *itError;
1833  formattedMessage +=
1834  "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
1835  formattedMessage += " " + error.message_ + "\n";
1836  if (error.extra_)
1837  formattedMessage +=
1838  "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
1839  }
1840  return formattedMessage;
1841 }
1842 
1843 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
1844  std::vector<OurReader::StructuredError> allErrors;
1845  for (Errors::const_iterator itError = errors_.begin();
1846  itError != errors_.end();
1847  ++itError) {
1848  const ErrorInfo& error = *itError;
1849  OurReader::StructuredError structured;
1850  structured.offset_start = error.token_.start_ - begin_;
1851  structured.offset_limit = error.token_.end_ - begin_;
1852  structured.message = error.message_;
1853  allErrors.push_back(structured);
1854  }
1855  return allErrors;
1856 }
1857 
1858 bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) {
1859  ptrdiff_t length = end_ - begin_;
1860  if(value.getOffsetStart() > length
1861  || value.getOffsetLimit() > length)
1862  return false;
1863  Token token;
1864  token.type_ = tokenError;
1865  token.start_ = begin_ + value.getOffsetStart();
1866  token.end_ = end_ + value.getOffsetLimit();
1867  ErrorInfo info;
1868  info.token_ = token;
1869  info.message_ = message;
1870  info.extra_ = 0;
1871  errors_.push_back(info);
1872  return true;
1873 }
1874 
1875 bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) {
1876  ptrdiff_t length = end_ - begin_;
1877  if(value.getOffsetStart() > length
1878  || value.getOffsetLimit() > length
1879  || extra.getOffsetLimit() > length)
1880  return false;
1881  Token token;
1882  token.type_ = tokenError;
1883  token.start_ = begin_ + value.getOffsetStart();
1884  token.end_ = begin_ + value.getOffsetLimit();
1885  ErrorInfo info;
1886  info.token_ = token;
1887  info.message_ = message;
1888  info.extra_ = begin_ + extra.getOffsetStart();
1889  errors_.push_back(info);
1890  return true;
1891 }
1892 
1893 bool OurReader::good() const {
1894  return !errors_.size();
1895 }
1896 
1897 
1898 class OurCharReader : public CharReader {
1899  bool const collectComments_;
1900  OurReader reader_;
1901 public:
1902  OurCharReader(
1903  bool collectComments,
1904  OurFeatures const& features)
1905  : collectComments_(collectComments)
1906  , reader_(features)
1907  {}
1908  bool parse(
1909  char const* beginDoc, char const* endDoc,
1910  Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE {
1911  bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1912  if (errs) {
1913  *errs = reader_.getFormattedErrorMessages();
1914  }
1915  return ok;
1916  }
1917 };
1918 
1920 {
1921  setDefaults(&settings_);
1922 }
1924 {}
1926 {
1927  bool collectComments = settings_["collectComments"].asBool();
1928  OurFeatures features = OurFeatures::all();
1929  features.allowComments_ = settings_["allowComments"].asBool();
1930  features.strictRoot_ = settings_["strictRoot"].asBool();
1931  features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
1932  features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
1933  features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
1934  features.stackLimit_ = settings_["stackLimit"].asInt();
1935  features.failIfExtra_ = settings_["failIfExtra"].asBool();
1936  features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
1937  features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
1938  return new OurCharReader(collectComments, features);
1939 }
1940 static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys)
1941 {
1942  valid_keys->clear();
1943  valid_keys->insert("collectComments");
1944  valid_keys->insert("allowComments");
1945  valid_keys->insert("strictRoot");
1946  valid_keys->insert("allowDroppedNullPlaceholders");
1947  valid_keys->insert("allowNumericKeys");
1948  valid_keys->insert("allowSingleQuotes");
1949  valid_keys->insert("stackLimit");
1950  valid_keys->insert("failIfExtra");
1951  valid_keys->insert("rejectDupKeys");
1952  valid_keys->insert("allowSpecialFloats");
1953 }
1955 {
1956  Json::Value my_invalid;
1957  if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
1958  Json::Value& inv = *invalid;
1959  std::set<JSONCPP_STRING> valid_keys;
1960  getValidReaderKeys(&valid_keys);
1961  Value::Members keys = settings_.getMemberNames();
1962  size_t n = keys.size();
1963  for (size_t i = 0; i < n; ++i) {
1964  JSONCPP_STRING const& key = keys[i];
1965  if (valid_keys.find(key) == valid_keys.end()) {
1966  inv[key] = settings_[key];
1967  }
1968  }
1969  return 0u == inv.size();
1970 }
1972 {
1973  return settings_[key];
1974 }
1975 // static
1977 {
1979  (*settings)["allowComments"] = false;
1980  (*settings)["strictRoot"] = true;
1981  (*settings)["allowDroppedNullPlaceholders"] = false;
1982  (*settings)["allowNumericKeys"] = false;
1983  (*settings)["allowSingleQuotes"] = false;
1984  (*settings)["stackLimit"] = 1000;
1985  (*settings)["failIfExtra"] = true;
1986  (*settings)["rejectDupKeys"] = true;
1987  (*settings)["allowSpecialFloats"] = false;
1989 }
1990 // static
1992 {
1994  (*settings)["collectComments"] = true;
1995  (*settings)["allowComments"] = true;
1996  (*settings)["strictRoot"] = false;
1997  (*settings)["allowDroppedNullPlaceholders"] = false;
1998  (*settings)["allowNumericKeys"] = false;
1999  (*settings)["allowSingleQuotes"] = false;
2000  (*settings)["stackLimit"] = 1000;
2001  (*settings)["failIfExtra"] = false;
2002  (*settings)["rejectDupKeys"] = false;
2003  (*settings)["allowSpecialFloats"] = false;
2005 }
2006 
2008 // global functions
2009 
2011  CharReader::Factory const& fact, JSONCPP_ISTREAM& sin,
2012  Value* root, JSONCPP_STRING* errs)
2013 {
2014  JSONCPP_OSTRINGSTREAM ssin;
2015  ssin << sin.rdbuf();
2016  JSONCPP_STRING doc = ssin.str();
2017  char const* begin = doc.data();
2018  char const* end = begin + doc.size();
2019  // Note that we do not actually need a null-terminator.
2020  CharReaderPtr const reader(fact.newCharReader());
2021  return reader->parse(begin, end, root, errs);
2022 }
2023 
2026  JSONCPP_STRING errs;
2027  bool ok = parseFromStream(b, sin, &root, &errs);
2028  if (!ok) {
2029  fprintf(stderr,
2030  "Error from reader: %s",
2031  errs.c_str());
2032 
2033  throwRuntimeError(errs);
2034  }
2035  return sin;
2036 }
2037 
2038 } // namespace Json
#define JSONCPP_OSTRINGSTREAM
Definition: config.h:166
#define JSONCPP_OVERRIDE
Definition: config.h:81
std::string asString() const
Embedded zeroes are possible.
Definition: json_value.cpp:660
#define JSONCPP_ISTREAM
Definition: config.h:169
CharReader * newCharReader() const
Allocate a CharReader via operator new().
static void strictMode(Json::Value *settings)
Same as old Features::strictMode().
array value (ordered list)
Definition: value.h:98
std::auto_ptr< CharReader > CharReaderPtr
Definition: json_reader.cpp:55
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:165
object value (collection of name/value pairs).
Definition: value.h:99
std::istream & operator>>(std::istream &, Value &)
Read from &#39;sin&#39; into &#39;root&#39;.
char Char
Definition: reader.h:35
std::string getFormatedErrorMessages() const
Returns a user friendly string that list errors in the parsed document.
void swapPayload(Value &other)
Swap values but leave comments and source offsets in place.
Definition: json_value.cpp:502
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:18
static const Int maxInt
Maximum signed int value that can be stored in a Json::Value.
Definition: value.h:203
Json::LargestUInt LargestUInt
Definition: value.h:188
Features()
Initialize the configuration like JsonConfig::allFeatures;.
Definition: json_reader.cpp:61
An error tagged with where in the JSON text it was encountered.
Definition: reader.h:44
std::vector< StructuredError > getStructuredErrors() const
Returns a vector of structured erros encounted while parsing.
bool isObject() const
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:194
bool allowComments_
true if comments are allowed. Default: true.
Definition: features.h:42
CommentPlacement
Definition: value.h:102
const Char * Location
Definition: reader.h:36
bool allowNumericKeys_
true if numeric object key are allowed. Default: false.
Definition: features.h:52
bool good() const
Return whether there are any errors.
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:12
bool allowDroppedNullPlaceholders_
true if dropped null placeholders are allowed. Default: false.
Definition: features.h:49
bool validate(Json::Value *invalid) const
Json::LargestInt LargestInt
Definition: value.h:187
static int const stackLimit_g
Definition: json_reader.cpp:47
const char * asCString() const
Embedded zeroes could cause you trouble!
Definition: json_value.cpp:629
Json::UInt UInt
Definition: value.h:181
static void setDefaults(Json::Value *settings)
Called by ctor, but you can use this to reset settings_.
Interface for reading JSON from a char array.
Definition: reader.h:247
ArrayIndex size() const
Number of values in array or object.
Definition: json_value.cpp:898
Represents a JSON value.
Definition: value.h:175
void setOffsetStart(ptrdiff_t start)
ptrdiff_t getOffsetStart() const
#define JSONCPP_ISTRINGSTREAM
Definition: config.h:168
static Features all()
A configuration that allows all features and assumes all strings are UTF-8.
Definition: json_reader.cpp:65
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:105
bool pushError(const Value &value, const std::string &message)
Add a semantic error message.
ptrdiff_t getOffsetLimit() const
void setOffsetLimit(ptrdiff_t limit)
std::vector< std::string > Members
Definition: value.h:178
static Features strictMode()
A configuration that is strictly compatible with the JSON specification.
Definition: json_reader.cpp:67
bool strictRoot_
true if root must be either an array or an object value.
Definition: features.h:46
bool isArray() const
Build a CharReader implementation.
Definition: reader.h:293
static int stackDepth_g
Definition: json_reader.cpp:48
#define snprintf
Definition: json_reader.cpp:28
static void getValidReaderKeys(std::set< std::string > *valid_keys)
static bool containsNewLine(Reader::Location begin, Reader::Location end)
Definition: json_reader.cpp:79
Configuration passed to reader and writer.
Definition: features.h:19
a comment placed on the line before a value
Definition: value.h:103
Reader()
Constructs a Reader allowing all features for parsing.
Definition: json_reader.cpp:89
std::string getFormattedErrorMessages() const
Returns a user friendly string that list errors in the parsed document.
a comment just after a value on the same line
Definition: value.h:104
static const LargestInt maxLargestInt
Maximum signed integer value that can be stored in a Json::Value.
Definition: value.h:196
virtual CharReader * newCharReader() const =0
Allocate a CharReader via operator new().
static const LargestUInt maxLargestUInt
Maximum unsigned integer value that can be stored in a Json::Value.
Definition: value.h:198