JsonCpp - JSON data format manipulation library

JsonCpp project page | JsonCpp home page

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