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