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_ = &currentValue();
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