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