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 
18 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
19 // Disable warning about strdup being deprecated.
20 #pragma warning(disable : 4996)
21 #endif
22 
23 namespace Json {
24 
25 // Implementation of class Features
26 // ////////////////////////////////
27 
29  : allowComments_(true), strictRoot_(false),
30  allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
31 
33 
35  Features features;
36  features.allowComments_ = false;
37  features.strictRoot_ = true;
38  features.allowDroppedNullPlaceholders_ = false;
39  features.allowNumericKeys_ = false;
40  return features;
41 }
42 
43 // Implementation of class Reader
44 // ////////////////////////////////
45 
46 static inline bool in(Reader::Char c,
47  Reader::Char c1,
48  Reader::Char c2,
49  Reader::Char c3,
50  Reader::Char c4) {
51  return c == c1 || c == c2 || c == c3 || c == c4;
52 }
53 
54 static inline bool in(Reader::Char c,
55  Reader::Char c1,
56  Reader::Char c2,
57  Reader::Char c3,
58  Reader::Char c4,
59  Reader::Char c5) {
60  return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
61 }
62 
64  for (; begin < end; ++begin)
65  if (*begin == '\n' || *begin == '\r')
66  return true;
67  return false;
68 }
69 
70 // Class Reader
71 // //////////////////////////////////////////////////////////////////
72 
74  : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
75  lastValue_(), commentsBefore_(), features_(Features::all()),
76  collectComments_() {}
77 
78 Reader::Reader(const Features &features)
79  : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
80  lastValue_(), commentsBefore_(), features_(features), collectComments_() {
81 }
82 
83 bool
84 Reader::parse(const std::string &document, Value &root, bool collectComments) {
85  document_ = document;
86  const char *begin = document_.c_str();
87  const char *end = begin + document_.length();
88  return parse(begin, end, root, collectComments);
89 }
90 
91 bool Reader::parse(std::istream &sin, Value &root, bool collectComments) {
92  // std::istream_iterator<char> begin(sin);
93  // std::istream_iterator<char> end;
94  // Those would allow streamed input from a file, if parse() were a
95  // template function.
96 
97  // Since std::string is reference-counted, this at least does not
98  // create an extra copy.
99  std::string doc;
100  std::getline(sin, doc, (char)EOF);
101  return parse(doc, root, collectComments);
102 }
103 
104 bool Reader::parse(const char *beginDoc,
105  const char *endDoc,
106  Value &root,
107  bool collectComments) {
108  if (!features_.allowComments_) {
109  collectComments = false;
110  }
111 
112  begin_ = beginDoc;
113  end_ = endDoc;
114  collectComments_ = collectComments;
115  current_ = begin_;
116  lastValueEnd_ = 0;
117  lastValue_ = 0;
118  commentsBefore_ = "";
119  errors_.clear();
120  while (!nodes_.empty())
121  nodes_.pop();
122  nodes_.push(&root);
123 
124  bool successful = readValue();
125  Token token;
126  skipCommentTokens(token);
127  if (collectComments_ && !commentsBefore_.empty())
128  root.setComment(commentsBefore_, commentAfter);
129  if (features_.strictRoot_) {
130  if (!root.isArray() && !root.isObject()) {
131  // Set error location to start of doc, ideally should be first token found
132  // in doc
133  token.type_ = tokenError;
134  token.start_ = beginDoc;
135  token.end_ = endDoc;
136  addError(
137  "A valid JSON document must be either an array or an object value.",
138  token);
139  return false;
140  }
141  }
142  return successful;
143 }
144 
145 bool Reader::readValue() {
146  Token token;
147  skipCommentTokens(token);
148  bool successful = true;
149 
150  if (collectComments_ && !commentsBefore_.empty()) {
151  // Remove newline characters at the end of the comments
152  size_t lastNonNewline = commentsBefore_.find_last_not_of("\r\n");
153  if (lastNonNewline != std::string::npos) {
154  commentsBefore_.erase(lastNonNewline + 1);
155  } else {
156  commentsBefore_.clear();
157  }
158 
159  currentValue().setComment(commentsBefore_, commentBefore);
160  commentsBefore_ = "";
161  }
162 
163  switch (token.type_) {
164  case tokenObjectBegin:
165  successful = readObject(token);
166  currentValue().setOffsetLimit(current_ - begin_);
167  break;
168  case tokenArrayBegin:
169  successful = readArray(token);
170  currentValue().setOffsetLimit(current_ - begin_);
171  break;
172  case tokenNumber:
173  successful = decodeNumber(token);
174  break;
175  case tokenString:
176  successful = decodeString(token);
177  break;
178  case tokenTrue:
179  currentValue() = true;
180  currentValue().setOffsetStart(token.start_ - begin_);
181  currentValue().setOffsetLimit(token.end_ - begin_);
182  break;
183  case tokenFalse:
184  currentValue() = false;
185  currentValue().setOffsetStart(token.start_ - begin_);
186  currentValue().setOffsetLimit(token.end_ - begin_);
187  break;
188  case tokenNull:
189  currentValue() = Value();
190  currentValue().setOffsetStart(token.start_ - begin_);
191  currentValue().setOffsetLimit(token.end_ - begin_);
192  break;
193  case tokenArraySeparator:
194  if (features_.allowDroppedNullPlaceholders_) {
195  // "Un-read" the current token and mark the current value as a null
196  // token.
197  current_--;
198  currentValue() = Value();
199  currentValue().setOffsetStart(current_ - begin_ - 1);
200  currentValue().setOffsetLimit(current_ - begin_);
201  break;
202  }
203  // Else, fall through...
204  default:
205  currentValue().setOffsetStart(token.start_ - begin_);
206  currentValue().setOffsetLimit(token.end_ - begin_);
207  return addError("Syntax error: value, object or array expected.", token);
208  }
209 
210  if (collectComments_) {
211  lastValueEnd_ = current_;
212  lastValue_ = &currentValue();
213  }
214 
215  return successful;
216 }
217 
218 void Reader::skipCommentTokens(Token &token) {
219  if (features_.allowComments_) {
220  do {
221  readToken(token);
222  } while (token.type_ == tokenComment);
223  } else {
224  readToken(token);
225  }
226 }
227 
228 bool Reader::expectToken(TokenType type, Token &token, const char *message) {
229  readToken(token);
230  if (token.type_ != type)
231  return addError(message, token);
232  return true;
233 }
234 
235 bool Reader::readToken(Token &token) {
236  skipSpaces();
237  token.start_ = current_;
238  Char c = getNextChar();
239  bool ok = true;
240  switch (c) {
241  case '{':
242  token.type_ = tokenObjectBegin;
243  break;
244  case '}':
245  token.type_ = tokenObjectEnd;
246  break;
247  case '[':
248  token.type_ = tokenArrayBegin;
249  break;
250  case ']':
251  token.type_ = tokenArrayEnd;
252  break;
253  case '"':
254  token.type_ = tokenString;
255  ok = readString();
256  break;
257  case '/':
258  token.type_ = tokenComment;
259  ok = readComment();
260  break;
261  case '0':
262  case '1':
263  case '2':
264  case '3':
265  case '4':
266  case '5':
267  case '6':
268  case '7':
269  case '8':
270  case '9':
271  case '-':
272  token.type_ = tokenNumber;
273  readNumber();
274  break;
275  case 't':
276  token.type_ = tokenTrue;
277  ok = match("rue", 3);
278  break;
279  case 'f':
280  token.type_ = tokenFalse;
281  ok = match("alse", 4);
282  break;
283  case 'n':
284  token.type_ = tokenNull;
285  ok = match("ull", 3);
286  break;
287  case ',':
288  token.type_ = tokenArraySeparator;
289  break;
290  case ':':
291  token.type_ = tokenMemberSeparator;
292  break;
293  case 0:
294  token.type_ = tokenEndOfStream;
295  break;
296  default:
297  ok = false;
298  break;
299  }
300  if (!ok)
301  token.type_ = tokenError;
302  token.end_ = current_;
303  return true;
304 }
305 
306 void Reader::skipSpaces() {
307  while (current_ != end_) {
308  Char c = *current_;
309  if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
310  ++current_;
311  else
312  break;
313  }
314 }
315 
316 bool Reader::match(Location pattern, int patternLength) {
317  if (end_ - current_ < patternLength)
318  return false;
319  int index = patternLength;
320  while (index--)
321  if (current_[index] != pattern[index])
322  return false;
323  current_ += patternLength;
324  return true;
325 }
326 
327 bool Reader::readComment() {
328  Location commentBegin = current_ - 1;
329  Char c = getNextChar();
330  bool successful = false;
331  if (c == '*')
332  successful = readCStyleComment();
333  else if (c == '/')
334  successful = readCppStyleComment();
335  if (!successful)
336  return false;
337 
338  if (collectComments_) {
339  CommentPlacement placement = commentBefore;
340  if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
341  if (c != '*' || !containsNewLine(commentBegin, current_))
342  placement = commentAfterOnSameLine;
343  }
344 
345  addComment(commentBegin, current_, placement);
346  }
347  return true;
348 }
349 
350 void
351 Reader::addComment(Location begin, Location end, CommentPlacement placement) {
352  assert(collectComments_);
353  if (placement == commentAfterOnSameLine) {
354  assert(lastValue_ != 0);
355  lastValue_->setComment(std::string(begin, end), placement);
356  } else {
357  if (!commentsBefore_.empty())
358  commentsBefore_ += "\n";
359  commentsBefore_ += std::string(begin, end);
360  }
361 }
362 
363 bool Reader::readCStyleComment() {
364  while (current_ != end_) {
365  Char c = getNextChar();
366  if (c == '*' && *current_ == '/')
367  break;
368  }
369  return getNextChar() == '/';
370 }
371 
372 bool Reader::readCppStyleComment() {
373  while (current_ != end_) {
374  Char c = getNextChar();
375  if (c == '\r' || c == '\n')
376  break;
377  }
378  return true;
379 }
380 
381 void Reader::readNumber() {
382  while (current_ != end_) {
383  if (!(*current_ >= '0' && *current_ <= '9') &&
384  !in(*current_, '.', 'e', 'E', '+', '-'))
385  break;
386  ++current_;
387  }
388 }
389 
390 bool Reader::readString() {
391  Char c = 0;
392  while (current_ != end_) {
393  c = getNextChar();
394  if (c == '\\')
395  getNextChar();
396  else if (c == '"')
397  break;
398  }
399  return c == '"';
400 }
401 
402 bool Reader::readObject(Token &tokenStart) {
403  Token tokenName;
404  std::string name;
405  currentValue() = Value(objectValue);
406  currentValue().setOffsetStart(tokenStart.start_ - begin_);
407  while (readToken(tokenName)) {
408  bool initialTokenOk = true;
409  while (tokenName.type_ == tokenComment && initialTokenOk)
410  initialTokenOk = readToken(tokenName);
411  if (!initialTokenOk)
412  break;
413  if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
414  return true;
415  name = "";
416  if (tokenName.type_ == tokenString) {
417  if (!decodeString(tokenName, name))
418  return recoverFromError(tokenObjectEnd);
419  } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
420  Value numberName;
421  if (!decodeNumber(tokenName, numberName))
422  return recoverFromError(tokenObjectEnd);
423  name = numberName.asString();
424  } else {
425  break;
426  }
427 
428  Token colon;
429  if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
430  return addErrorAndRecover(
431  "Missing ':' after object member name", colon, tokenObjectEnd);
432  }
433  Value &value = currentValue()[name];
434  nodes_.push(&value);
435  bool ok = readValue();
436  nodes_.pop();
437  if (!ok) // error already set
438  return recoverFromError(tokenObjectEnd);
439 
440  Token comma;
441  if (!readToken(comma) ||
442  (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
443  comma.type_ != tokenComment)) {
444  return addErrorAndRecover(
445  "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
446  }
447  bool finalizeTokenOk = true;
448  while (comma.type_ == tokenComment && finalizeTokenOk)
449  finalizeTokenOk = readToken(comma);
450  if (comma.type_ == tokenObjectEnd)
451  return true;
452  }
453  return addErrorAndRecover(
454  "Missing '}' or object member name", tokenName, tokenObjectEnd);
455 }
456 
457 bool Reader::readArray(Token &tokenStart) {
458  currentValue() = Value(arrayValue);
459  currentValue().setOffsetStart(tokenStart.start_ - begin_);
460  skipSpaces();
461  if (*current_ == ']') // empty array
462  {
463  Token endArray;
464  readToken(endArray);
465  return true;
466  }
467  int index = 0;
468  for (;;) {
469  Value &value = currentValue()[index++];
470  nodes_.push(&value);
471  bool ok = readValue();
472  nodes_.pop();
473  if (!ok) // error already set
474  return recoverFromError(tokenArrayEnd);
475 
476  Token token;
477  // Accept Comment after last item in the array.
478  ok = readToken(token);
479  while (token.type_ == tokenComment && ok) {
480  ok = readToken(token);
481  }
482  bool badTokenType =
483  (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
484  if (!ok || badTokenType) {
485  return addErrorAndRecover(
486  "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
487  }
488  if (token.type_ == tokenArrayEnd)
489  break;
490  }
491  return true;
492 }
493 
494 bool Reader::decodeNumber(Token &token) {
495  Value decoded;
496  if (!decodeNumber(token, decoded))
497  return false;
498  currentValue() = decoded;
499  currentValue().setOffsetStart(token.start_ - begin_);
500  currentValue().setOffsetLimit(token.end_ - begin_);
501  return true;
502 }
503 
504 bool Reader::decodeNumber(Token &token, Value &decoded) {
505  bool isDouble = false;
506  for (Location inspect = token.start_; inspect != token.end_; ++inspect) {
507  isDouble = isDouble || in(*inspect, '.', 'e', 'E', '+') ||
508  (*inspect == '-' && inspect != token.start_);
509  }
510  if (isDouble)
511  return decodeDouble(token, decoded);
512  // Attempts to parse the number as an integer. If the number is
513  // larger than the maximum supported value of an integer then
514  // we decode the number as a double.
515  Location current = token.start_;
516  bool isNegative = *current == '-';
517  if (isNegative)
518  ++current;
519  Value::LargestUInt maxIntegerValue =
521  : Value::maxLargestUInt;
522  Value::LargestUInt threshold = maxIntegerValue / 10;
523  Value::LargestUInt value = 0;
524  while (current < token.end_) {
525  Char c = *current++;
526  if (c < '0' || c > '9')
527  return addError("'" + std::string(token.start_, token.end_) +
528  "' is not a number.",
529  token);
530  Value::UInt digit(c - '0');
531  if (value >= threshold) {
532  // We've hit or exceeded the max value divided by 10 (rounded down). If
533  // a) we've only just touched the limit, b) this is the last digit, and
534  // c) it's small enough to fit in that rounding delta, we're okay.
535  // Otherwise treat this number as a double to avoid overflow.
536  if (value > threshold || current != token.end_ ||
537  digit > maxIntegerValue % 10) {
538  return decodeDouble(token, decoded);
539  }
540  }
541  value = value * 10 + digit;
542  }
543  if (isNegative)
544  decoded = -Value::LargestInt(value);
545  else if (value <= Value::LargestUInt(Value::maxInt))
546  decoded = Value::LargestInt(value);
547  else
548  decoded = value;
549  return true;
550 }
551 
552 bool Reader::decodeDouble(Token &token) {
553  Value decoded;
554  if (!decodeDouble(token, decoded))
555  return false;
556  currentValue() = decoded;
557  currentValue().setOffsetStart(token.start_ - begin_);
558  currentValue().setOffsetLimit(token.end_ - begin_);
559  return true;
560 }
561 
562 bool Reader::decodeDouble(Token &token, Value &decoded) {
563  double value = 0;
564  const int bufferSize = 32;
565  int count;
566  int length = int(token.end_ - token.start_);
567 
568  // Sanity check to avoid buffer overflow exploits.
569  if (length < 0) {
570  return addError("Unable to parse token length", token);
571  }
572 
573  // Avoid using a string constant for the format control string given to
574  // sscanf, as this can cause hard to debug crashes on OS X. See here for more
575  // info:
576  //
577  // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
578  char format[] = "%lf";
579 
580  if (length <= bufferSize) {
581  Char buffer[bufferSize + 1];
582  memcpy(buffer, token.start_, length);
583  buffer[length] = 0;
584  count = sscanf(buffer, format, &value);
585  } else {
586  std::string buffer(token.start_, token.end_);
587  count = sscanf(buffer.c_str(), format, &value);
588  }
589 
590  if (count != 1)
591  return addError("'" + std::string(token.start_, token.end_) +
592  "' is not a number.",
593  token);
594  decoded = value;
595  return true;
596 }
597 
598 bool Reader::decodeString(Token &token) {
599  std::string decoded;
600  if (!decodeString(token, decoded))
601  return false;
602  currentValue() = decoded;
603  currentValue().setOffsetStart(token.start_ - begin_);
604  currentValue().setOffsetLimit(token.end_ - begin_);
605  return true;
606 }
607 
608 bool Reader::decodeString(Token &token, std::string &decoded) {
609  decoded.reserve(token.end_ - token.start_ - 2);
610  Location current = token.start_ + 1; // skip '"'
611  Location end = token.end_ - 1; // do not include '"'
612  while (current != end) {
613  Char c = *current++;
614  if (c == '"')
615  break;
616  else if (c == '\\') {
617  if (current == end)
618  return addError("Empty escape sequence in string", token, current);
619  Char escape = *current++;
620  switch (escape) {
621  case '"':
622  decoded += '"';
623  break;
624  case '/':
625  decoded += '/';
626  break;
627  case '\\':
628  decoded += '\\';
629  break;
630  case 'b':
631  decoded += '\b';
632  break;
633  case 'f':
634  decoded += '\f';
635  break;
636  case 'n':
637  decoded += '\n';
638  break;
639  case 'r':
640  decoded += '\r';
641  break;
642  case 't':
643  decoded += '\t';
644  break;
645  case 'u': {
646  unsigned int unicode;
647  if (!decodeUnicodeCodePoint(token, current, end, unicode))
648  return false;
649  decoded += codePointToUTF8(unicode);
650  } break;
651  default:
652  return addError("Bad escape sequence in string", token, current);
653  }
654  } else {
655  decoded += c;
656  }
657  }
658  return true;
659 }
660 
661 bool Reader::decodeUnicodeCodePoint(Token &token,
662  Location &current,
663  Location end,
664  unsigned int &unicode) {
665 
666  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
667  return false;
668  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
669  // surrogate pairs
670  if (end - current < 6)
671  return addError(
672  "additional six characters expected to parse unicode surrogate pair.",
673  token,
674  current);
675  unsigned int surrogatePair;
676  if (*(current++) == '\\' && *(current++) == 'u') {
677  if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
678  unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
679  } else
680  return false;
681  } else
682  return addError("expecting another \\u token to begin the second half of "
683  "a unicode surrogate pair",
684  token,
685  current);
686  }
687  return true;
688 }
689 
690 bool Reader::decodeUnicodeEscapeSequence(Token &token,
691  Location &current,
692  Location end,
693  unsigned int &unicode) {
694  if (end - current < 4)
695  return addError(
696  "Bad unicode escape sequence in string: four digits expected.",
697  token,
698  current);
699  unicode = 0;
700  for (int index = 0; index < 4; ++index) {
701  Char c = *current++;
702  unicode *= 16;
703  if (c >= '0' && c <= '9')
704  unicode += c - '0';
705  else if (c >= 'a' && c <= 'f')
706  unicode += c - 'a' + 10;
707  else if (c >= 'A' && c <= 'F')
708  unicode += c - 'A' + 10;
709  else
710  return addError(
711  "Bad unicode escape sequence in string: hexadecimal digit expected.",
712  token,
713  current);
714  }
715  return true;
716 }
717 
718 bool
719 Reader::addError(const std::string &message, Token &token, Location extra) {
720  ErrorInfo info;
721  info.token_ = token;
722  info.message_ = message;
723  info.extra_ = extra;
724  errors_.push_back(info);
725  return false;
726 }
727 
728 bool Reader::recoverFromError(TokenType skipUntilToken) {
729  int errorCount = int(errors_.size());
730  Token skip;
731  for (;;) {
732  if (!readToken(skip))
733  errors_.resize(errorCount); // discard errors caused by recovery
734  if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
735  break;
736  }
737  errors_.resize(errorCount);
738  return false;
739 }
740 
741 bool Reader::addErrorAndRecover(const std::string &message,
742  Token &token,
743  TokenType skipUntilToken) {
744  addError(message, token);
745  return recoverFromError(skipUntilToken);
746 }
747 
748 Value &Reader::currentValue() { return *(nodes_.top()); }
749 
750 Reader::Char Reader::getNextChar() {
751  if (current_ == end_)
752  return 0;
753  return *current_++;
754 }
755 
756 void Reader::getLocationLineAndColumn(Location location,
757  int &line,
758  int &column) const {
759  Location current = begin_;
760  Location lastLineStart = current;
761  line = 0;
762  while (current < location && current != end_) {
763  Char c = *current++;
764  if (c == '\r') {
765  if (*current == '\n')
766  ++current;
767  lastLineStart = current;
768  ++line;
769  } else if (c == '\n') {
770  lastLineStart = current;
771  ++line;
772  }
773  }
774  // column & line start at 1
775  column = int(location - lastLineStart) + 1;
776  ++line;
777 }
778 
779 std::string Reader::getLocationLineAndColumn(Location location) const {
780  int line, column;
781  getLocationLineAndColumn(location, line, column);
782  char buffer[18 + 16 + 16 + 1];
783 #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
784  #if defined(WINCE)
785  _snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
786  #else
787  sprintf_s(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
788  #endif
789 #else
790  snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
791 #endif
792  return buffer;
793 }
794 
795 // Deprecated. Preserved for backward compatibility
796 std::string Reader::getFormatedErrorMessages() const {
797  return getFormattedErrorMessages();
798 }
799 
801  std::string formattedMessage;
802  for (Errors::const_iterator itError = errors_.begin();
803  itError != errors_.end();
804  ++itError) {
805  const ErrorInfo &error = *itError;
806  formattedMessage +=
807  "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
808  formattedMessage += " " + error.message_ + "\n";
809  if (error.extra_)
810  formattedMessage +=
811  "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
812  }
813  return formattedMessage;
814 }
815 
816 std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
817  std::vector<Reader::StructuredError> allErrors;
818  for (Errors::const_iterator itError = errors_.begin();
819  itError != errors_.end();
820  ++itError) {
821  const ErrorInfo &error = *itError;
822  Reader::StructuredError structured;
823  structured.offset_start = error.token_.start_ - begin_;
824  structured.offset_limit = error.token_.end_ - begin_;
825  structured.message = error.message_;
826  allErrors.push_back(structured);
827  }
828  return allErrors;
829 }
830 
831 std::istream &operator>>(std::istream &sin, Value &root) {
832  Json::Reader reader;
833  bool ok = reader.parse(sin, root, true);
834  if (!ok) {
835  fprintf(stderr,
836  "Error from reader: %s",
837  reader.getFormattedErrorMessages().c_str());
838 
839  JSON_FAIL_MESSAGE("reader error");
840  }
841  return sin;
842 }
843 
844 } // namespace Json
845 // vim: et ts=2 sts=2 sw=2 tw=0
Json::Reader::StructuredError::message
std::string message
Definition: reader.h:45
Json::Value::setComment
void setComment(const char *comment, CommentPlacement placement)
Comments must be //... or /* ... *‍/.
Definition: json_value.cpp:1250
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:84
Json::commentAfterOnSameLine
a comment just after a value on the same line
Definition: value.h:50
Json::commentBefore
a comment placed on the line before a value
Definition: value.h:49
Json::Features::strictMode
static Features strictMode()
A configuration that is strictly compatible with the JSON specification.
Definition: json_reader.cpp:34
Json::Features::allowDroppedNullPlaceholders_
bool allowDroppedNullPlaceholders_
true if dropped null placeholders are allowed. Default: false.
Definition: features.h:49
Json::codePointToUTF8
static std::string codePointToUTF8(unsigned int cp)
Converts a unicode code-point to UTF-8.
Definition: json_tool.h:18
Json::Reader
Unserialize a JSON document into a Value.
Definition: reader.h:31
Json::Reader::getFormattedErrorMessages
std::string getFormattedErrorMessages() const
Returns a user friendly string that list errors in the parsed document.
Definition: json_reader.cpp:800
Json::Reader::Reader
Reader()
Constructs a Reader allowing all features for parsing.
Definition: json_reader.cpp:73
Json::Features::all
static Features all()
A configuration that allows all features and assumes all strings are UTF-8.
Definition: json_reader.cpp:32
Json::commentAfter
a comment on the line after a value (only make sense for
Definition: value.h:51
Json::operator>>
std::istream & operator>>(std::istream &, Value &)
Read from 'sin' into 'root'.
Definition: json_reader.cpp:831
Json::Features::allowNumericKeys_
bool allowNumericKeys_
true if numeric object key are allowed. Default: false.
Definition: features.h:52
JSON_FAIL_MESSAGE
#define JSON_FAIL_MESSAGE(message)
Definition: assertions.h:19
json_tool.h
Json::Reader::StructuredError::offset_start
size_t offset_start
Definition: reader.h:43
Json::arrayValue
array value (ordered list)
Definition: value.h:44
Json::Value::maxInt
static const Int maxInt
Maximum signed int value that can be stored in a Json::Value.
Definition: value.h:147
reader.h
Json::Value
Represents a JSON value.
Definition: value.h:116
Json::Reader::Char
char Char
Definition: reader.h:33
Json::Reader::StructuredError::offset_limit
size_t offset_limit
Definition: reader.h:44
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1248
Json::Features::Features
Features()
Initialize the configuration like JsonConfig::allFeatures;.
Definition: json_reader.cpp:28
Json::CommentPlacement
CommentPlacement
Definition: value.h:48
Json::Value::LargestInt
Json::LargestInt LargestInt
Definition: value.h:132
Json::Value::setOffsetLimit
void setOffsetLimit(size_t limit)
Definition: json_value.cpp:1272
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1246
Json::in
static bool in(Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4)
Definition: json_reader.cpp:46
Json
JSON (JavaScript Object Notation).
Definition: config.h:90
Json::Value::minLargestInt
static const LargestInt minLargestInt
Minimum signed integer value that can be stored in a Json::Value.
Definition: value.h:138
Json::Reader::getStructuredErrors
std::vector< StructuredError > getStructuredErrors() const
Returns a vector of structured erros encounted while parsing.
Definition: json_reader.cpp:816
Json::Value::UInt
Json::UInt UInt
Definition: value.h:126
Json::Value::setOffsetStart
void setOffsetStart(size_t start)
Definition: json_value.cpp:1270
Json::Reader::StructuredError
An error tagged with where in the JSON text it was encountered.
Definition: reader.h:42
Json::Features::allowComments_
bool allowComments_
true if comments are allowed. Default: true.
Definition: features.h:42
Json::objectValue
object value (collection of name/value pairs).
Definition: value.h:45
Json::Value::LargestUInt
Json::LargestUInt LargestUInt
Definition: value.h:133
Json::Reader::getFormatedErrorMessages
std::string getFormatedErrorMessages() const
Returns a user friendly string that list errors in the parsed document.
Definition: json_reader.cpp:796
Json::Reader::Location
const typedef Char * Location
Definition: reader.h:34
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:63
assertions.h