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