JsonCpp project page | Classes | Namespace | JsonCpp home page

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