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_ + 1) < end_) {
405  Char c = getNextChar();
406  if (c == '*' && *current_ == '/')
407  break;
408  }
409  return getNextChar() == '/';
410 }
411 
412 bool Reader::readCppStyleComment() {
413  while (current_ != end_) {
414  Char c = getNextChar();
415  if (c == '\n')
416  break;
417  if (c == '\r') {
418  // Consume DOS EOL. It will be normalized in addComment.
419  if (current_ != end_ && *current_ == '\n')
420  getNextChar();
421  // Break on Moc OS 9 EOL.
422  break;
423  }
424  }
425  return true;
426 }
427 
428 void Reader::readNumber() {
429  const char *p = current_;
430  char c = '0'; // stopgap for already consumed character
431  // integral part
432  while (c >= '0' && c <= '9')
433  c = (current_ = p) < end_ ? *p++ : '\0';
434  // fractional part
435  if (c == '.') {
436  c = (current_ = p) < end_ ? *p++ : '\0';
437  while (c >= '0' && c <= '9')
438  c = (current_ = p) < end_ ? *p++ : '\0';
439  }
440  // exponential part
441  if (c == 'e' || c == 'E') {
442  c = (current_ = p) < end_ ? *p++ : '\0';
443  if (c == '+' || c == '-')
444  c = (current_ = p) < end_ ? *p++ : '\0';
445  while (c >= '0' && c <= '9')
446  c = (current_ = p) < end_ ? *p++ : '\0';
447  }
448 }
449 
450 bool Reader::readString() {
451  Char c = '\0';
452  while (current_ != end_) {
453  c = getNextChar();
454  if (c == '\\')
455  getNextChar();
456  else if (c == '"')
457  break;
458  }
459  return c == '"';
460 }
461 
462 bool Reader::readObject(Token& tokenStart) {
463  Token tokenName;
464  JSONCPP_STRING name;
465  Value init(objectValue);
466  currentValue().swapPayload(init);
467  currentValue().setOffsetStart(tokenStart.start_ - begin_);
468  while (readToken(tokenName)) {
469  bool initialTokenOk = true;
470  while (tokenName.type_ == tokenComment && initialTokenOk)
471  initialTokenOk = readToken(tokenName);
472  if (!initialTokenOk)
473  break;
474  if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
475  return true;
476  name = "";
477  if (tokenName.type_ == tokenString) {
478  if (!decodeString(tokenName, name))
479  return recoverFromError(tokenObjectEnd);
480  } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
481  Value numberName;
482  if (!decodeNumber(tokenName, numberName))
483  return recoverFromError(tokenObjectEnd);
484  name = JSONCPP_STRING(numberName.asCString());
485  } else {
486  break;
487  }
488 
489  Token colon;
490  if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
491  return addErrorAndRecover(
492  "Missing ':' after object member name", colon, tokenObjectEnd);
493  }
494  Value& value = currentValue()[name];
495  nodes_.push(&value);
496  bool ok = readValue();
497  nodes_.pop();
498  if (!ok) // error already set
499  return recoverFromError(tokenObjectEnd);
500 
501  Token comma;
502  if (!readToken(comma) ||
503  (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
504  comma.type_ != tokenComment)) {
505  return addErrorAndRecover(
506  "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
507  }
508  bool finalizeTokenOk = true;
509  while (comma.type_ == tokenComment && finalizeTokenOk)
510  finalizeTokenOk = readToken(comma);
511  if (comma.type_ == tokenObjectEnd)
512  return true;
513  }
514  return addErrorAndRecover(
515  "Missing '}' or object member name", tokenName, tokenObjectEnd);
516 }
517 
518 bool Reader::readArray(Token& tokenStart) {
519  Value init(arrayValue);
520  currentValue().swapPayload(init);
521  currentValue().setOffsetStart(tokenStart.start_ - begin_);
522  skipSpaces();
523  if (current_ != end_ && *current_ == ']') // empty array
524  {
525  Token endArray;
526  readToken(endArray);
527  return true;
528  }
529  int index = 0;
530  for (;;) {
531  Value& value = currentValue()[index++];
532  nodes_.push(&value);
533  bool ok = readValue();
534  nodes_.pop();
535  if (!ok) // error already set
536  return recoverFromError(tokenArrayEnd);
537 
538  Token token;
539  // Accept Comment after last item in the array.
540  ok = readToken(token);
541  while (token.type_ == tokenComment && ok) {
542  ok = readToken(token);
543  }
544  bool badTokenType =
545  (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
546  if (!ok || badTokenType) {
547  return addErrorAndRecover(
548  "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
549  }
550  if (token.type_ == tokenArrayEnd)
551  break;
552  }
553  return true;
554 }
555 
556 bool Reader::decodeNumber(Token& token) {
557  Value decoded;
558  if (!decodeNumber(token, decoded))
559  return false;
560  currentValue().swapPayload(decoded);
561  currentValue().setOffsetStart(token.start_ - begin_);
562  currentValue().setOffsetLimit(token.end_ - begin_);
563  return true;
564 }
565 
566 bool Reader::decodeNumber(Token& token, Value& decoded) {
567  // Attempts to parse the number as an integer. If the number is
568  // larger than the maximum supported value of an integer then
569  // we decode the number as a double.
570  Location current = token.start_;
571  bool isNegative = *current == '-';
572  if (isNegative)
573  ++current;
574  // TODO: Help the compiler do the div and mod at compile time or get rid of them.
575  Value::LargestUInt maxIntegerValue =
576  isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
578  Value::LargestUInt threshold = maxIntegerValue / 10;
579  Value::LargestUInt value = 0;
580  while (current < token.end_) {
581  Char c = *current++;
582  if (c < '0' || c > '9')
583  return decodeDouble(token, decoded);
584  Value::UInt digit(static_cast<Value::UInt>(c - '0'));
585  if (value >= threshold) {
586  // We've hit or exceeded the max value divided by 10 (rounded down). If
587  // a) we've only just touched the limit, b) this is the last digit, and
588  // c) it's small enough to fit in that rounding delta, we're okay.
589  // Otherwise treat this number as a double to avoid overflow.
590  if (value > threshold || current != token.end_ ||
591  digit > maxIntegerValue % 10) {
592  return decodeDouble(token, decoded);
593  }
594  }
595  value = value * 10 + digit;
596  }
597  if (isNegative && value == maxIntegerValue)
598  decoded = Value::minLargestInt;
599  else if (isNegative)
600  decoded = -Value::LargestInt(value);
601  else if (value <= Value::LargestUInt(Value::maxInt))
602  decoded = Value::LargestInt(value);
603  else
604  decoded = value;
605  return true;
606 }
607 
608 bool Reader::decodeDouble(Token& token) {
609  Value decoded;
610  if (!decodeDouble(token, decoded))
611  return false;
612  currentValue().swapPayload(decoded);
613  currentValue().setOffsetStart(token.start_ - begin_);
614  currentValue().setOffsetLimit(token.end_ - begin_);
615  return true;
616 }
617 
618 bool Reader::decodeDouble(Token& token, Value& decoded) {
619  double value = 0;
620  JSONCPP_STRING buffer(token.start_, token.end_);
621  JSONCPP_ISTRINGSTREAM is(buffer);
622  if (!(is >> value))
623  return addError("'" + JSONCPP_STRING(token.start_, token.end_) +
624  "' is not a number.",
625  token);
626  decoded = value;
627  return true;
628 }
629 
630 bool Reader::decodeString(Token& token) {
631  JSONCPP_STRING decoded_string;
632  if (!decodeString(token, decoded_string))
633  return false;
634  Value decoded(decoded_string);
635  currentValue().swapPayload(decoded);
636  currentValue().setOffsetStart(token.start_ - begin_);
637  currentValue().setOffsetLimit(token.end_ - begin_);
638  return true;
639 }
640 
641 bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) {
642  decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
643  Location current = token.start_ + 1; // skip '"'
644  Location end = token.end_ - 1; // do not include '"'
645  while (current != end) {
646  Char c = *current++;
647  if (c == '"')
648  break;
649  else if (c == '\\') {
650  if (current == end)
651  return addError("Empty escape sequence in string", token, current);
652  Char escape = *current++;
653  switch (escape) {
654  case '"':
655  decoded += '"';
656  break;
657  case '/':
658  decoded += '/';
659  break;
660  case '\\':
661  decoded += '\\';
662  break;
663  case 'b':
664  decoded += '\b';
665  break;
666  case 'f':
667  decoded += '\f';
668  break;
669  case 'n':
670  decoded += '\n';
671  break;
672  case 'r':
673  decoded += '\r';
674  break;
675  case 't':
676  decoded += '\t';
677  break;
678  case 'u': {
679  unsigned int unicode;
680  if (!decodeUnicodeCodePoint(token, current, end, unicode))
681  return false;
682  decoded += codePointToUTF8(unicode);
683  } break;
684  default:
685  return addError("Bad escape sequence in string", token, current);
686  }
687  } else {
688  decoded += c;
689  }
690  }
691  return true;
692 }
693 
694 bool Reader::decodeUnicodeCodePoint(Token& token,
695  Location& current,
696  Location end,
697  unsigned int& unicode) {
698 
699  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
700  return false;
701  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
702  // surrogate pairs
703  if (end - current < 6)
704  return addError(
705  "additional six characters expected to parse unicode surrogate pair.",
706  token,
707  current);
708  unsigned int surrogatePair;
709  if (*(current++) == '\\' && *(current++) == 'u') {
710  if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
711  unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
712  } else
713  return false;
714  } else
715  return addError("expecting another \\u token to begin the second half of "
716  "a unicode surrogate pair",
717  token,
718  current);
719  }
720  return true;
721 }
722 
723 bool Reader::decodeUnicodeEscapeSequence(Token& token,
724  Location& current,
725  Location end,
726  unsigned int& ret_unicode) {
727  if (end - current < 4)
728  return addError(
729  "Bad unicode escape sequence in string: four digits expected.",
730  token,
731  current);
732  int unicode = 0;
733  for (int index = 0; index < 4; ++index) {
734  Char c = *current++;
735  unicode *= 16;
736  if (c >= '0' && c <= '9')
737  unicode += c - '0';
738  else if (c >= 'a' && c <= 'f')
739  unicode += c - 'a' + 10;
740  else if (c >= 'A' && c <= 'F')
741  unicode += c - 'A' + 10;
742  else
743  return addError(
744  "Bad unicode escape sequence in string: hexadecimal digit expected.",
745  token,
746  current);
747  }
748  ret_unicode = static_cast<unsigned int>(unicode);
749  return true;
750 }
751 
752 bool
753 Reader::addError(const JSONCPP_STRING& message, Token& token, Location extra) {
754  ErrorInfo info;
755  info.token_ = token;
756  info.message_ = message;
757  info.extra_ = extra;
758  errors_.push_back(info);
759  return false;
760 }
761 
762 bool Reader::recoverFromError(TokenType skipUntilToken) {
763  size_t const errorCount = errors_.size();
764  Token skip;
765  for (;;) {
766  if (!readToken(skip))
767  errors_.resize(errorCount); // discard errors caused by recovery
768  if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
769  break;
770  }
771  errors_.resize(errorCount);
772  return false;
773 }
774 
775 bool Reader::addErrorAndRecover(const JSONCPP_STRING& message,
776  Token& token,
777  TokenType skipUntilToken) {
778  addError(message, token);
779  return recoverFromError(skipUntilToken);
780 }
781 
782 Value& Reader::currentValue() { return *(nodes_.top()); }
783 
784 Reader::Char Reader::getNextChar() {
785  if (current_ == end_)
786  return 0;
787  return *current_++;
788 }
789 
790 void Reader::getLocationLineAndColumn(Location location,
791  int& line,
792  int& column) const {
793  Location current = begin_;
794  Location lastLineStart = current;
795  line = 0;
796  while (current < location && current != end_) {
797  Char c = *current++;
798  if (c == '\r') {
799  if (*current == '\n')
800  ++current;
801  lastLineStart = current;
802  ++line;
803  } else if (c == '\n') {
804  lastLineStart = current;
805  ++line;
806  }
807  }
808  // column & line start at 1
809  column = int(location - lastLineStart) + 1;
810  ++line;
811 }
812 
813 JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const {
814  int line, column;
815  getLocationLineAndColumn(location, line, column);
816  char buffer[18 + 16 + 16 + 1];
817  snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
818  return buffer;
819 }
820 
821 // Deprecated. Preserved for backward compatibility
823  return getFormattedErrorMessages();
824 }
825 
827  JSONCPP_STRING formattedMessage;
828  for (Errors::const_iterator itError = errors_.begin();
829  itError != errors_.end();
830  ++itError) {
831  const ErrorInfo& error = *itError;
832  formattedMessage +=
833  "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
834  formattedMessage += " " + error.message_ + "\n";
835  if (error.extra_)
836  formattedMessage +=
837  "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
838  }
839  return formattedMessage;
840 }
841 
842 std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
843  std::vector<Reader::StructuredError> allErrors;
844  for (Errors::const_iterator itError = errors_.begin();
845  itError != errors_.end();
846  ++itError) {
847  const ErrorInfo& error = *itError;
848  Reader::StructuredError structured;
849  structured.offset_start = error.token_.start_ - begin_;
850  structured.offset_limit = error.token_.end_ - begin_;
851  structured.message = error.message_;
852  allErrors.push_back(structured);
853  }
854  return allErrors;
855 }
856 
857 bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) {
858  ptrdiff_t const length = end_ - begin_;
859  if(value.getOffsetStart() > length
860  || value.getOffsetLimit() > length)
861  return false;
862  Token token;
863  token.type_ = tokenError;
864  token.start_ = begin_ + value.getOffsetStart();
865  token.end_ = end_ + value.getOffsetLimit();
866  ErrorInfo info;
867  info.token_ = token;
868  info.message_ = message;
869  info.extra_ = 0;
870  errors_.push_back(info);
871  return true;
872 }
873 
874 bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) {
875  ptrdiff_t const length = end_ - begin_;
876  if(value.getOffsetStart() > length
877  || value.getOffsetLimit() > length
878  || extra.getOffsetLimit() > length)
879  return false;
880  Token token;
881  token.type_ = tokenError;
882  token.start_ = begin_ + value.getOffsetStart();
883  token.end_ = begin_ + value.getOffsetLimit();
884  ErrorInfo info;
885  info.token_ = token;
886  info.message_ = message;
887  info.extra_ = begin_ + extra.getOffsetStart();
888  errors_.push_back(info);
889  return true;
890 }
891 
892 bool Reader::good() const {
893  return !errors_.size();
894 }
895 
896 // exact copy of Features
897 class OurFeatures {
898 public:
899  static OurFeatures all();
900  bool allowComments_;
901  bool strictRoot_;
902  bool allowDroppedNullPlaceholders_;
903  bool allowNumericKeys_;
904  bool allowSingleQuotes_;
905  bool failIfExtra_;
906  bool rejectDupKeys_;
907  bool allowSpecialFloats_;
908  int stackLimit_;
909 }; // OurFeatures
910 
911 // exact copy of Implementation of class Features
912 // ////////////////////////////////
913 
914 OurFeatures OurFeatures::all() { return OurFeatures(); }
915 
916 // Implementation of class Reader
917 // ////////////////////////////////
918 
919 // exact copy of Reader, renamed to OurReader
920 class OurReader {
921 public:
922  typedef char Char;
923  typedef const Char* Location;
924  struct StructuredError {
925  ptrdiff_t offset_start;
926  ptrdiff_t offset_limit;
927  JSONCPP_STRING message;
928  };
929 
930  OurReader(OurFeatures const& features);
931  bool parse(const char* beginDoc,
932  const char* endDoc,
933  Value& root,
934  bool collectComments = true);
935  JSONCPP_STRING getFormattedErrorMessages() const;
936  std::vector<StructuredError> getStructuredErrors() const;
937  bool pushError(const Value& value, const JSONCPP_STRING& message);
938  bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra);
939  bool good() const;
940 
941 private:
942  OurReader(OurReader const&); // no impl
943  void operator=(OurReader const&); // no impl
944 
945  enum TokenType {
946  tokenEndOfStream = 0,
947  tokenObjectBegin,
948  tokenObjectEnd,
949  tokenArrayBegin,
950  tokenArrayEnd,
951  tokenString,
952  tokenNumber,
953  tokenTrue,
954  tokenFalse,
955  tokenNull,
956  tokenNaN,
957  tokenPosInf,
958  tokenNegInf,
959  tokenArraySeparator,
960  tokenMemberSeparator,
961  tokenComment,
962  tokenError
963  };
964 
965  class Token {
966  public:
967  TokenType type_;
968  Location start_;
969  Location end_;
970  };
971 
972  class ErrorInfo {
973  public:
974  Token token_;
975  JSONCPP_STRING message_;
976  Location extra_;
977  };
978 
979  typedef std::deque<ErrorInfo> Errors;
980 
981  bool readToken(Token& token);
982  void skipSpaces();
983  bool match(Location pattern, int patternLength);
984  bool readComment();
985  bool readCStyleComment();
986  bool readCppStyleComment();
987  bool readString();
988  bool readStringSingleQuote();
989  bool readNumber(bool checkInf);
990  bool readValue();
991  bool readObject(Token& token);
992  bool readArray(Token& token);
993  bool decodeNumber(Token& token);
994  bool decodeNumber(Token& token, Value& decoded);
995  bool decodeString(Token& token);
996  bool decodeString(Token& token, JSONCPP_STRING& decoded);
997  bool decodeDouble(Token& token);
998  bool decodeDouble(Token& token, Value& decoded);
999  bool decodeUnicodeCodePoint(Token& token,
1000  Location& current,
1001  Location end,
1002  unsigned int& unicode);
1003  bool decodeUnicodeEscapeSequence(Token& token,
1004  Location& current,
1005  Location end,
1006  unsigned int& unicode);
1007  bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0);
1008  bool recoverFromError(TokenType skipUntilToken);
1009  bool addErrorAndRecover(const JSONCPP_STRING& message,
1010  Token& token,
1011  TokenType skipUntilToken);
1012  void skipUntilSpace();
1013  Value& currentValue();
1014  Char getNextChar();
1015  void
1016  getLocationLineAndColumn(Location location, int& line, int& column) const;
1017  JSONCPP_STRING getLocationLineAndColumn(Location location) const;
1018  void addComment(Location begin, Location end, CommentPlacement placement);
1019  void skipCommentTokens(Token& token);
1020 
1021  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 ((features_.strictRoot_ || 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_ + 1) < 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_ != end_ && *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 =
1560  : Value::maxLargestUInt;
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  fixNumericLocaleInput(buffer, buffer + length);
1623  count = sscanf(buffer, format, &value);
1624  } else {
1625  JSONCPP_STRING buffer(token.start_, token.end_);
1626  count = sscanf(buffer.c_str(), format, &value);
1627  }
1628 
1629  if (count != 1)
1630  return addError("'" + JSONCPP_STRING(token.start_, token.end_) +
1631  "' is not a number.",
1632  token);
1633  decoded = value;
1634  return true;
1635 }
1636 
1637 bool OurReader::decodeString(Token& token) {
1638  JSONCPP_STRING decoded_string;
1639  if (!decodeString(token, decoded_string))
1640  return false;
1641  Value decoded(decoded_string);
1642  currentValue().swapPayload(decoded);
1643  currentValue().setOffsetStart(token.start_ - begin_);
1644  currentValue().setOffsetLimit(token.end_ - begin_);
1645  return true;
1646 }
1647 
1648 bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) {
1649  decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
1650  Location current = token.start_ + 1; // skip '"'
1651  Location end = token.end_ - 1; // do not include '"'
1652  while (current != end) {
1653  Char c = *current++;
1654  if (c == '"')
1655  break;
1656  else if (c == '\\') {
1657  if (current == end)
1658  return addError("Empty escape sequence in string", token, current);
1659  Char escape = *current++;
1660  switch (escape) {
1661  case '"':
1662  decoded += '"';
1663  break;
1664  case '/':
1665  decoded += '/';
1666  break;
1667  case '\\':
1668  decoded += '\\';
1669  break;
1670  case 'b':
1671  decoded += '\b';
1672  break;
1673  case 'f':
1674  decoded += '\f';
1675  break;
1676  case 'n':
1677  decoded += '\n';
1678  break;
1679  case 'r':
1680  decoded += '\r';
1681  break;
1682  case 't':
1683  decoded += '\t';
1684  break;
1685  case 'u': {
1686  unsigned int unicode;
1687  if (!decodeUnicodeCodePoint(token, current, end, unicode))
1688  return false;
1689  decoded += codePointToUTF8(unicode);
1690  } break;
1691  default:
1692  return addError("Bad escape sequence in string", token, current);
1693  }
1694  } else {
1695  decoded += c;
1696  }
1697  }
1698  return true;
1699 }
1700 
1701 bool OurReader::decodeUnicodeCodePoint(Token& token,
1702  Location& current,
1703  Location end,
1704  unsigned int& unicode) {
1705 
1706  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1707  return false;
1708  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1709  // surrogate pairs
1710  if (end - current < 6)
1711  return addError(
1712  "additional six characters expected to parse unicode surrogate pair.",
1713  token,
1714  current);
1715  unsigned int surrogatePair;
1716  if (*(current++) == '\\' && *(current++) == 'u') {
1717  if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1718  unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1719  } else
1720  return false;
1721  } else
1722  return addError("expecting another \\u token to begin the second half of "
1723  "a unicode surrogate pair",
1724  token,
1725  current);
1726  }
1727  return true;
1728 }
1729 
1730 bool OurReader::decodeUnicodeEscapeSequence(Token& token,
1731  Location& current,
1732  Location end,
1733  unsigned int& ret_unicode) {
1734  if (end - current < 4)
1735  return addError(
1736  "Bad unicode escape sequence in string: four digits expected.",
1737  token,
1738  current);
1739  int unicode = 0;
1740  for (int index = 0; index < 4; ++index) {
1741  Char c = *current++;
1742  unicode *= 16;
1743  if (c >= '0' && c <= '9')
1744  unicode += c - '0';
1745  else if (c >= 'a' && c <= 'f')
1746  unicode += c - 'a' + 10;
1747  else if (c >= 'A' && c <= 'F')
1748  unicode += c - 'A' + 10;
1749  else
1750  return addError(
1751  "Bad unicode escape sequence in string: hexadecimal digit expected.",
1752  token,
1753  current);
1754  }
1755  ret_unicode = static_cast<unsigned int>(unicode);
1756  return true;
1757 }
1758 
1759 bool
1760 OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) {
1761  ErrorInfo info;
1762  info.token_ = token;
1763  info.message_ = message;
1764  info.extra_ = extra;
1765  errors_.push_back(info);
1766  return false;
1767 }
1768 
1769 bool OurReader::recoverFromError(TokenType skipUntilToken) {
1770  size_t errorCount = errors_.size();
1771  Token skip;
1772  for (;;) {
1773  if (!readToken(skip))
1774  errors_.resize(errorCount); // discard errors caused by recovery
1775  if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
1776  break;
1777  }
1778  errors_.resize(errorCount);
1779  return false;
1780 }
1781 
1782 bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message,
1783  Token& token,
1784  TokenType skipUntilToken) {
1785  addError(message, token);
1786  return recoverFromError(skipUntilToken);
1787 }
1788 
1789 Value& OurReader::currentValue() { return *(nodes_.top()); }
1790 
1791 OurReader::Char OurReader::getNextChar() {
1792  if (current_ == end_)
1793  return 0;
1794  return *current_++;
1795 }
1796 
1797 void OurReader::getLocationLineAndColumn(Location location,
1798  int& line,
1799  int& column) const {
1800  Location current = begin_;
1801  Location lastLineStart = current;
1802  line = 0;
1803  while (current < location && current != end_) {
1804  Char c = *current++;
1805  if (c == '\r') {
1806  if (*current == '\n')
1807  ++current;
1808  lastLineStart = current;
1809  ++line;
1810  } else if (c == '\n') {
1811  lastLineStart = current;
1812  ++line;
1813  }
1814  }
1815  // column & line start at 1
1816  column = int(location - lastLineStart) + 1;
1817  ++line;
1818 }
1819 
1820 JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const {
1821  int line, column;
1822  getLocationLineAndColumn(location, line, column);
1823  char buffer[18 + 16 + 16 + 1];
1824  snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
1825  return buffer;
1826 }
1827 
1828 JSONCPP_STRING OurReader::getFormattedErrorMessages() const {
1829  JSONCPP_STRING formattedMessage;
1830  for (Errors::const_iterator itError = errors_.begin();
1831  itError != errors_.end();
1832  ++itError) {
1833  const ErrorInfo& error = *itError;
1834  formattedMessage +=
1835  "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
1836  formattedMessage += " " + error.message_ + "\n";
1837  if (error.extra_)
1838  formattedMessage +=
1839  "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
1840  }
1841  return formattedMessage;
1842 }
1843 
1844 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
1845  std::vector<OurReader::StructuredError> allErrors;
1846  for (Errors::const_iterator itError = errors_.begin();
1847  itError != errors_.end();
1848  ++itError) {
1849  const ErrorInfo& error = *itError;
1850  OurReader::StructuredError structured;
1851  structured.offset_start = error.token_.start_ - begin_;
1852  structured.offset_limit = error.token_.end_ - begin_;
1853  structured.message = error.message_;
1854  allErrors.push_back(structured);
1855  }
1856  return allErrors;
1857 }
1858 
1859 bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) {
1860  ptrdiff_t length = end_ - begin_;
1861  if(value.getOffsetStart() > length
1862  || value.getOffsetLimit() > length)
1863  return false;
1864  Token token;
1865  token.type_ = tokenError;
1866  token.start_ = begin_ + value.getOffsetStart();
1867  token.end_ = end_ + value.getOffsetLimit();
1868  ErrorInfo info;
1869  info.token_ = token;
1870  info.message_ = message;
1871  info.extra_ = 0;
1872  errors_.push_back(info);
1873  return true;
1874 }
1875 
1876 bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) {
1877  ptrdiff_t length = end_ - begin_;
1878  if(value.getOffsetStart() > length
1879  || value.getOffsetLimit() > length
1880  || extra.getOffsetLimit() > length)
1881  return false;
1882  Token token;
1883  token.type_ = tokenError;
1884  token.start_ = begin_ + value.getOffsetStart();
1885  token.end_ = begin_ + value.getOffsetLimit();
1886  ErrorInfo info;
1887  info.token_ = token;
1888  info.message_ = message;
1889  info.extra_ = begin_ + extra.getOffsetStart();
1890  errors_.push_back(info);
1891  return true;
1892 }
1893 
1894 bool OurReader::good() const {
1895  return !errors_.size();
1896 }
1897 
1898 
1899 class OurCharReader : public CharReader {
1900  bool const collectComments_;
1901  OurReader reader_;
1902 public:
1903  OurCharReader(
1904  bool collectComments,
1905  OurFeatures const& features)
1906  : collectComments_(collectComments)
1907  , reader_(features)
1908  {}
1909  bool parse(
1910  char const* beginDoc, char const* endDoc,
1911  Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE {
1912  bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1913  if (errs) {
1914  *errs = reader_.getFormattedErrorMessages();
1915  }
1916  return ok;
1917  }
1918 };
1919 
1921 {
1923 }
1925 {}
1927 {
1928  bool collectComments = settings_["collectComments"].asBool();
1929  OurFeatures features = OurFeatures::all();
1930  features.allowComments_ = settings_["allowComments"].asBool();
1931  features.strictRoot_ = settings_["strictRoot"].asBool();
1932  features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
1933  features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
1934  features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
1935  features.stackLimit_ = settings_["stackLimit"].asInt();
1936  features.failIfExtra_ = settings_["failIfExtra"].asBool();
1937  features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
1938  features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
1939  return new OurCharReader(collectComments, features);
1940 }
1941 static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys)
1942 {
1943  valid_keys->clear();
1944  valid_keys->insert("collectComments");
1945  valid_keys->insert("allowComments");
1946  valid_keys->insert("strictRoot");
1947  valid_keys->insert("allowDroppedNullPlaceholders");
1948  valid_keys->insert("allowNumericKeys");
1949  valid_keys->insert("allowSingleQuotes");
1950  valid_keys->insert("stackLimit");
1951  valid_keys->insert("failIfExtra");
1952  valid_keys->insert("rejectDupKeys");
1953  valid_keys->insert("allowSpecialFloats");
1954 }
1956 {
1957  Json::Value my_invalid;
1958  if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
1959  Json::Value& inv = *invalid;
1960  std::set<JSONCPP_STRING> valid_keys;
1961  getValidReaderKeys(&valid_keys);
1963  size_t n = keys.size();
1964  for (size_t i = 0; i < n; ++i) {
1965  JSONCPP_STRING const& key = keys[i];
1966  if (valid_keys.find(key) == valid_keys.end()) {
1967  inv[key] = settings_[key];
1968  }
1969  }
1970  return 0u == inv.size();
1971 }
1973 {
1974  return settings_[key];
1975 }
1976 // static
1978 {
1980  (*settings)["allowComments"] = false;
1981  (*settings)["strictRoot"] = true;
1982  (*settings)["allowDroppedNullPlaceholders"] = false;
1983  (*settings)["allowNumericKeys"] = false;
1984  (*settings)["allowSingleQuotes"] = false;
1985  (*settings)["stackLimit"] = 1000;
1986  (*settings)["failIfExtra"] = true;
1987  (*settings)["rejectDupKeys"] = true;
1988  (*settings)["allowSpecialFloats"] = false;
1990 }
1991 // static
1993 {
1995  (*settings)["collectComments"] = true;
1996  (*settings)["allowComments"] = true;
1997  (*settings)["strictRoot"] = false;
1998  (*settings)["allowDroppedNullPlaceholders"] = false;
1999  (*settings)["allowNumericKeys"] = false;
2000  (*settings)["allowSingleQuotes"] = false;
2001  (*settings)["stackLimit"] = 1000;
2002  (*settings)["failIfExtra"] = false;
2003  (*settings)["rejectDupKeys"] = false;
2004  (*settings)["allowSpecialFloats"] = false;
2006 }
2007 
2009 // global functions
2010 
2012  CharReader::Factory const& fact, JSONCPP_ISTREAM& sin,
2013  Value* root, JSONCPP_STRING* errs)
2014 {
2015  JSONCPP_OSTRINGSTREAM ssin;
2016  ssin << sin.rdbuf();
2017  JSONCPP_STRING doc = ssin.str();
2018  char const* begin = doc.data();
2019  char const* end = begin + doc.size();
2020  // Note that we do not actually need a null-terminator.
2021  CharReaderPtr const reader(fact.newCharReader());
2022  return reader->parse(begin, end, root, errs);
2023 }
2024 
2027  JSONCPP_STRING errs;
2028  bool ok = parseFromStream(b, sin, &root, &errs);
2029  if (!ok) {
2030  fprintf(stderr,
2031  "Error from reader: %s",
2032  errs.c_str());
2033 
2034  throwRuntimeError(errs);
2035  }
2036  return sin;
2037 }
2038 
2039 } // namespace Json
Json::Reader::good
bool good() const
Return whether there are any errors.
Definition: json_reader.cpp:892
Json::Reader::StructuredError::message
std::string message
Definition: reader.h:47
Json::Value::setComment
void setComment(const char *comment, CommentPlacement placement)
Definition: json_value.cpp:1377
Json::CharReader::Factory
Definition: reader.h:271
Json::codePointToUTF8
static JSONCPP_STRING codePointToUTF8(unsigned int cp)
Converts a unicode code-point to UTF-8.
Definition: json_tool.h:30
Json::Reader::StructuredError::offset_limit
ptrdiff_t offset_limit
Definition: reader.h:46
Json::CharReaderBuilder::strictMode
static void strictMode(Json::Value *settings)
Same as old Features::strictMode().
Definition: json_reader.cpp:1977
snprintf
#define snprintf
Definition: json_reader.cpp:28
Json::Value::maxLargestInt
static const LargestInt maxLargestInt
Maximum signed integer value that can be stored in a Json::Value.
Definition: value.h:198
Json::getValidReaderKeys
static void getValidReaderKeys(std::set< std::string > *valid_keys)
Definition: json_reader.cpp:1941
Json::Reader::parse
bool parse(const std::string &document, Value &root, bool collectComments=true)
Read a Value from a JSON document.
Definition: json_reader.cpp:100
Json::Value::maxLargestUInt
static const LargestUInt maxLargestUInt
Maximum unsigned integer value that can be stored in a Json::Value.
Definition: value.h:200
Json::commentAfterOnSameLine
@ commentAfterOnSameLine
a comment just after a value on the same line
Definition: value.h:104
Json::commentBefore
@ commentBefore
a comment placed on the line before a value
Definition: value.h:103
Json::Value::Members
std::vector< std::string > Members
Definition: value.h:178
Json::Reader::pushError
bool pushError(const Value &value, const std::string &message)
Add a semantic error message.
Definition: json_reader.cpp:857
Json::Features::strictMode
static Features strictMode()
A configuration that is strictly compatible with the JSON specification.
Definition: json_reader.cpp:67
Json::Features::allowDroppedNullPlaceholders_
bool allowDroppedNullPlaceholders_
true if dropped null placeholders are allowed. Default: false.
Definition: features.h:49
Json::CharReaderBuilder::newCharReader
CharReader * newCharReader() const
Allocate a CharReader via operator new().
Definition: json_reader.cpp:1926
Json::Value::size
ArrayIndex size() const
Number of values in array or object.
Definition: json_value.cpp:911
Json::CharReaderBuilder::CharReaderBuilder
CharReaderBuilder()
Definition: json_reader.cpp:1920
Json::Reader::getFormattedErrorMessages
std::string getFormattedErrorMessages() const
Returns a user friendly string that list errors in the parsed document.
Definition: json_reader.cpp:826
Json::Reader::Reader
Reader()
Constructs a Reader allowing all features for parsing.
Definition: json_reader.cpp:89
Json::Features::all
static Features all()
A configuration that allows all features and assumes all strings are UTF-8.
Definition: json_reader.cpp:65
Json::commentAfter
@ commentAfter
a comment on the line after a value (only make sense for
Definition: value.h:105
Json::operator>>
std::istream & operator>>(std::istream &, Value &)
Read from 'sin' into 'root'.
Definition: json_reader.cpp:2025
Json::CharReaderBuilder::settings_
Json::Value settings_
Configuration of this builder.
Definition: reader.h:333
Json::CharReader::Factory::newCharReader
virtual CharReader * newCharReader() const =0
Allocate a CharReader via operator new().
Json::Value::setOffsetLimit
void setOffsetLimit(ptrdiff_t limit)
Definition: json_value.cpp:1397
Json::Features::allowNumericKeys_
bool allowNumericKeys_
true if numeric object key are allowed. Default: false.
Definition: features.h:52
JSONCPP_OSTRINGSTREAM
#define JSONCPP_OSTRINGSTREAM
Definition: config.h:170
JSONCPP_ISTRINGSTREAM
#define JSONCPP_ISTRINGSTREAM
Definition: config.h:172
json_tool.h
Json::CharReaderBuilder::operator[]
Value & operator[](std::string key)
A simple way to update a specific setting.
Definition: json_reader.cpp:1972
JSONCPP_ISTREAM
#define JSONCPP_ISTREAM
Definition: config.h:173
stackLimit_g
static const int stackLimit_g
Definition: json_reader.cpp:47
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: value.h:98
Json::Value::swapPayload
void swapPayload(Value &other)
Swap values but leave comments and source offsets in place.
Definition: json_value.cpp:515
Json::CharReaderBuilder::setDefaults
static void setDefaults(Json::Value *settings)
Called by ctor, but you can use this to reset settings_.
Definition: json_reader.cpp:1992
Json::Value::maxInt
static const Int maxInt
Maximum signed int value that can be stored in a Json::Value.
Definition: value.h:205
Json::Value::getOffsetStart
ptrdiff_t getOffsetStart() const
Definition: json_value.cpp:1399
JSONCPP_STRING
#define JSONCPP_STRING
Definition: config.h:169
reader.h
Json::Value
Represents a JSON value.
Definition: value.h:175
Json::Reader::Char
char Char
Definition: reader.h:35
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1365
Json::Features::Features
Features()
Initialize the configuration like JsonConfig::allFeatures;.
Definition: json_reader.cpp:61
Json::Value::setOffsetStart
void setOffsetStart(ptrdiff_t start)
Definition: json_value.cpp:1395
Json::CommentPlacement
CommentPlacement
Definition: value.h:102
Json::Value::LargestInt
Json::LargestInt LargestInt
Definition: value.h:187
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1363
Json::Value::asInt
Int asInt() const
Definition: json_value.cpp:708
Json
JSON (JavaScript Object Notation).
Definition: allocator.h:12
Json::Value::getMemberNames
Members getMemberNames() const
Return a list of the member names.
Definition: json_value.cpp:1228
Json::Value::minLargestInt
static const LargestInt minLargestInt
Minimum signed integer value that can be stored in a Json::Value.
Definition: value.h:196
Json::Reader::getStructuredErrors
std::vector< StructuredError > getStructuredErrors() const
Returns a vector of structured erros encounted while parsing.
Definition: json_reader.cpp:842
Json::Value::UInt
Json::UInt UInt
Definition: value.h:181
Json::Reader::StructuredError
An error tagged with where in the JSON text it was encountered.
Definition: reader.h:44
Json::Features::allowComments_
bool allowComments_
true if comments are allowed. Default: true.
Definition: features.h:42
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: value.h:99
JSONCPP_OVERRIDE
#define JSONCPP_OVERRIDE
Definition: config.h:88
Json::CharReaderBuilder::~CharReaderBuilder
~CharReaderBuilder()
Definition: json_reader.cpp:1924
stackDepth_g
static int stackDepth_g
Definition: json_reader.cpp:48
Json::CharReaderBuilder::validate
bool validate(Json::Value *invalid) const
Definition: json_reader.cpp:1955
Json::Value::LargestUInt
Json::LargestUInt LargestUInt
Definition: value.h:188
Json::normalizeEOL
static std::string normalizeEOL(Reader::Location begin, Reader::Location end)
Definition: json_reader.cpp:372
Json::CharReader
Interface for reading JSON from a char array.
Definition: reader.h:247
Json::Reader::getFormatedErrorMessages
std::string getFormatedErrorMessages() const
Returns a user friendly string that list errors in the parsed document.
Definition: json_reader.cpp:822
Json::CharReaderPtr
std::auto_ptr< CharReader > CharReaderPtr
Definition: json_reader.cpp:55
Json::parseFromStream
bool parseFromStream(CharReader::Factory const &, std::istream &, Value *root, std::string *errs)
Consume entire stream and use its begin/end.
Definition: json_reader.cpp:2011
Json::Value::getOffsetLimit
ptrdiff_t getOffsetLimit() const
Definition: json_value.cpp:1401
Json::fixNumericLocaleInput
static void fixNumericLocaleInput(char *begin, char *end)
Definition: json_tool.h:97
Json::Reader::Location
const typedef Char * Location
Definition: reader.h:36
value.h
Json::Features::strictRoot_
bool strictRoot_
true if root must be either an array or an object value.
Definition: features.h:46
Json::Features
Configuration passed to reader and writer.
Definition: features.h:19
Json::containsNewLine
static bool containsNewLine(Reader::Location begin, Reader::Location end)
Definition: json_reader.cpp:79
Json::Value::asBool
bool asBool() const
Definition: json_value.cpp:858
assertions.h
Json::Reader::StructuredError::offset_start
ptrdiff_t offset_start
Definition: reader.h:45
Json::CharReaderBuilder
Build a CharReader implementation.
Definition: reader.h:293