1 /// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/).
2 /// It is intended to be used with #include "json/json.h"
3
4 // //////////////////////////////////////////////////////////////////////
5 // Beginning of content of file: LICENSE
6 // //////////////////////////////////////////////////////////////////////
7
8 /*
9 The JsonCpp library's source code, including accompanying documentation,
10 tests and demonstration applications, are licensed under the following
11 conditions...
12
13 The author (Baptiste Lepilleur) explicitly disclaims copyright in all
14 jurisdictions which recognize such a disclaimer. In such jurisdictions,
15 this software is released into the Public Domain.
16
17 In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
18 2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
19 released under the terms of the MIT License (see below).
20
21 In jurisdictions which recognize Public Domain property, the user of this
22 software may choose to accept it either as 1) Public Domain, 2) under the
23 conditions of the MIT License (see below), or 3) under the terms of dual
24 Public Domain/MIT License conditions described here, as they choose.
25
26 The MIT License is about as close to Public Domain as a license can get, and is
27 described in clear, concise terms at:
28
29 http://en.wikipedia.org/wiki/MIT_License
30
31 The full text of the MIT License follows:
32
33 ========================================================================
34 Copyright (c) 2007-2010 Baptiste Lepilleur
35
36 Permission is hereby granted, free of charge, to any person
37 obtaining a copy of this software and associated documentation
38 files (the "Software"), to deal in the Software without
39 restriction, including without limitation the rights to use, copy,
40 modify, merge, publish, distribute, sublicense, and/or sell copies
41 of the Software, and to permit persons to whom the Software is
42 furnished to do so, subject to the following conditions:
43
44 The above copyright notice and this permission notice shall be
45 included in all copies or substantial portions of the Software.
46
47 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
48 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
49 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
50 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
51 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
52 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
53 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
54 SOFTWARE.
55 ========================================================================
56 (END LICENSE TEXT)
57
58 The MIT license is compatible with both the GPL and commercial
59 software, affording one all of the rights of Public Domain with the
60 minor nuisance of being required to keep the above copyright notice
61 and license text in the source code. Note also that by accepting the
62 Public Domain "license" you can re-license your copy using whatever
63 license you like.
64
65 */
66
67 // //////////////////////////////////////////////////////////////////////
68 // End of content of file: LICENSE
69 // //////////////////////////////////////////////////////////////////////
70
71
72
73
74
75
76 #include "third_party/jsoncpp/json.h"
77
78 #ifndef JSON_IS_AMALGAMATION
79 #error "Compile with -I PATH_TO_JSON_DIRECTORY"
80 #endif
81
82
83 // //////////////////////////////////////////////////////////////////////
84 // Beginning of content of file: src/lib_json/json_tool.h
85 // //////////////////////////////////////////////////////////////////////
86
87 // Copyright 2007-2010 Baptiste Lepilleur
88 // Distributed under MIT license, or public domain if desired and
89 // recognized in your jurisdiction.
90 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
91
92 #ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
93 #define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
94
95 /* This header provides common string manipulation support, such as UTF-8,
96 * portable conversion from/to string...
97 *
98 * It is an internal header that must not be exposed.
99 */
100
101 namespace Json {
102
103 /// Converts a unicode code-point to UTF-8.
codePointToUTF8(unsigned int cp)104 static inline std::string codePointToUTF8(unsigned int cp) {
105 std::string result;
106
107 // based on description from http://en.wikipedia.org/wiki/UTF-8
108
109 if (cp <= 0x7f) {
110 result.resize(1);
111 result[0] = static_cast<char>(cp);
112 } else if (cp <= 0x7FF) {
113 result.resize(2);
114 result[1] = static_cast<char>(0x80 | (0x3f & cp));
115 result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
116 } else if (cp <= 0xFFFF) {
117 result.resize(3);
118 result[2] = static_cast<char>(0x80 | (0x3f & cp));
119 result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
120 result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));
121 } else if (cp <= 0x10FFFF) {
122 result.resize(4);
123 result[3] = static_cast<char>(0x80 | (0x3f & cp));
124 result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
125 result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
126 result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
127 }
128
129 return result;
130 }
131
132 /// Returns true if ch is a control character (in range [1,31]).
isControlCharacter(char ch)133 static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; }
134
135 enum {
136 /// Constant that specify the size of the buffer that must be passed to
137 /// uintToString.
138 uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
139 };
140
141 // Defines a char buffer for use with uintToString().
142 typedef char UIntToStringBuffer[uintToStringBufferSize];
143
144 /** Converts an unsigned integer to string.
145 * @param value Unsigned interger to convert to string
146 * @param current Input/Output string buffer.
147 * Must have at least uintToStringBufferSize chars free.
148 */
uintToString(LargestUInt value,char * & current)149 static inline void uintToString(LargestUInt value, char*& current) {
150 *--current = 0;
151 do {
152 *--current = static_cast<signed char>(value % 10U + static_cast<unsigned>('0'));
153 value /= 10;
154 } while (value != 0);
155 }
156
157 /** Change ',' to '.' everywhere in buffer.
158 *
159 * We had a sophisticated way, but it did not work in WinCE.
160 * @see https://github.com/open-source-parsers/jsoncpp/pull/9
161 */
fixNumericLocale(char * begin,char * end)162 static inline void fixNumericLocale(char* begin, char* end) {
163 while (begin < end) {
164 if (*begin == ',') {
165 *begin = '.';
166 }
167 ++begin;
168 }
169 }
170
171 } // namespace Json {
172
173 #endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
174
175 // //////////////////////////////////////////////////////////////////////
176 // End of content of file: src/lib_json/json_tool.h
177 // //////////////////////////////////////////////////////////////////////
178
179
180
181
182
183
184 // //////////////////////////////////////////////////////////////////////
185 // Beginning of content of file: src/lib_json/json_reader.cpp
186 // //////////////////////////////////////////////////////////////////////
187
188 // Copyright 2007-2011 Baptiste Lepilleur
189 // Distributed under MIT license, or public domain if desired and
190 // recognized in your jurisdiction.
191 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
192
193 #if !defined(JSON_IS_AMALGAMATION)
194 #include <json/assertions.h>
195 #include <json/reader.h>
196 #include <json/value.h>
197 #include "json_tool.h"
198 #endif // if !defined(JSON_IS_AMALGAMATION)
199 #include <utility>
200 #include <cstdio>
201 #include <cassert>
202 #include <cstring>
203 #include <istream>
204 #include <sstream>
205 #include <memory>
206 #include <set>
207 #include <limits>
208
209 #if defined(_MSC_VER)
210 #if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
211 #define snprintf sprintf_s
212 #elif _MSC_VER >= 1900 // VC++ 14.0 and above
213 #define snprintf std::snprintf
214 #else
215 #define snprintf _snprintf
216 #endif
217 #elif defined(__ANDROID__) || defined(__QNXNTO__)
218 #define snprintf snprintf
219 #elif __cplusplus >= 201103L
220 #define snprintf std::snprintf
221 #endif
222
223 #if defined(__QNXNTO__)
224 #define sscanf std::sscanf
225 #endif
226
227 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
228 // Disable warning about strdup being deprecated.
229 #pragma warning(disable : 4996)
230 #endif
231
232 static int const stackLimit_g = 1000;
233 static int stackDepth_g = 0; // see readValue()
234
235 namespace Json {
236
237 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
238 typedef std::unique_ptr<CharReader> CharReaderPtr;
239 #else
240 typedef std::auto_ptr<CharReader> CharReaderPtr;
241 #endif
242
243 // Implementation of class Features
244 // ////////////////////////////////
245
Features()246 Features::Features()
247 : allowComments_(true), strictRoot_(false),
248 allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
249
all()250 Features Features::all() { return Features(); }
251
strictMode()252 Features Features::strictMode() {
253 Features features;
254 features.allowComments_ = false;
255 features.strictRoot_ = true;
256 features.allowDroppedNullPlaceholders_ = false;
257 features.allowNumericKeys_ = false;
258 return features;
259 }
260
261 // Implementation of class Reader
262 // ////////////////////////////////
263
containsNewLine(Reader::Location begin,Reader::Location end)264 static bool containsNewLine(Reader::Location begin, Reader::Location end) {
265 for (; begin < end; ++begin)
266 if (*begin == '\n' || *begin == '\r')
267 return true;
268 return false;
269 }
270
271 // Class Reader
272 // //////////////////////////////////////////////////////////////////
273
Reader()274 Reader::Reader()
275 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
276 lastValue_(), commentsBefore_(), features_(Features::all()),
277 collectComments_() {}
278
Reader(const Features & features)279 Reader::Reader(const Features& features)
280 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
281 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
282 }
283
284 bool
parse(const std::string & document,Value & root,bool collectComments)285 Reader::parse(const std::string& document, Value& root, bool collectComments) {
286 document_ = document;
287 const char* begin = document_.c_str();
288 const char* end = begin + document_.length();
289 return parse(begin, end, root, collectComments);
290 }
291
parse(std::istream & sin,Value & root,bool collectComments)292 bool Reader::parse(std::istream& sin, Value& root, bool collectComments) {
293 // std::istream_iterator<char> begin(sin);
294 // std::istream_iterator<char> end;
295 // Those would allow streamed input from a file, if parse() were a
296 // template function.
297
298 // Since std::string is reference-counted, this at least does not
299 // create an extra copy.
300 std::string doc;
301 std::getline(sin, doc, (char)EOF);
302 return parse(doc, root, collectComments);
303 }
304
parse(const char * beginDoc,const char * endDoc,Value & root,bool collectComments)305 bool Reader::parse(const char* beginDoc,
306 const char* endDoc,
307 Value& root,
308 bool collectComments) {
309 if (!features_.allowComments_) {
310 collectComments = false;
311 }
312
313 begin_ = beginDoc;
314 end_ = endDoc;
315 collectComments_ = collectComments;
316 current_ = begin_;
317 lastValueEnd_ = 0;
318 lastValue_ = 0;
319 commentsBefore_ = "";
320 errors_.clear();
321 while (!nodes_.empty())
322 nodes_.pop();
323 nodes_.push(&root);
324
325 stackDepth_g = 0; // Yes, this is bad coding, but options are limited.
326 bool successful = readValue();
327 Token token;
328 skipCommentTokens(token);
329 if (collectComments_ && !commentsBefore_.empty())
330 root.setComment(commentsBefore_, commentAfter);
331 if (features_.strictRoot_) {
332 if (!root.isArray() && !root.isObject()) {
333 // Set error location to start of doc, ideally should be first token found
334 // in doc
335 token.type_ = tokenError;
336 token.start_ = beginDoc;
337 token.end_ = endDoc;
338 addError(
339 "A valid JSON document must be either an array or an object value.",
340 token);
341 return false;
342 }
343 }
344 return successful;
345 }
346
readValue()347 bool Reader::readValue() {
348 // This is a non-reentrant way to support a stackLimit. Terrible!
349 // But this deprecated class has a security problem: Bad input can
350 // cause a seg-fault. This seems like a fair, binary-compatible way
351 // to prevent the problem.
352 if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
353 ++stackDepth_g;
354
355 Token token;
356 skipCommentTokens(token);
357 bool successful = true;
358
359 if (collectComments_ && !commentsBefore_.empty()) {
360 currentValue().setComment(commentsBefore_, commentBefore);
361 commentsBefore_ = "";
362 }
363
364 switch (token.type_) {
365 case tokenObjectBegin:
366 successful = readObject(token);
367 currentValue().setOffsetLimit(current_ - begin_);
368 break;
369 case tokenArrayBegin:
370 successful = readArray(token);
371 currentValue().setOffsetLimit(current_ - begin_);
372 break;
373 case tokenNumber:
374 successful = decodeNumber(token);
375 break;
376 case tokenString:
377 successful = decodeString(token);
378 break;
379 case tokenTrue:
380 {
381 Value v(true);
382 currentValue().swapPayload(v);
383 currentValue().setOffsetStart(token.start_ - begin_);
384 currentValue().setOffsetLimit(token.end_ - begin_);
385 }
386 break;
387 case tokenFalse:
388 {
389 Value v(false);
390 currentValue().swapPayload(v);
391 currentValue().setOffsetStart(token.start_ - begin_);
392 currentValue().setOffsetLimit(token.end_ - begin_);
393 }
394 break;
395 case tokenNull:
396 {
397 Value v;
398 currentValue().swapPayload(v);
399 currentValue().setOffsetStart(token.start_ - begin_);
400 currentValue().setOffsetLimit(token.end_ - begin_);
401 }
402 break;
403 case tokenArraySeparator:
404 case tokenObjectEnd:
405 case tokenArrayEnd:
406 if (features_.allowDroppedNullPlaceholders_) {
407 // "Un-read" the current token and mark the current value as a null
408 // token.
409 current_--;
410 Value v;
411 currentValue().swapPayload(v);
412 currentValue().setOffsetStart(current_ - begin_ - 1);
413 currentValue().setOffsetLimit(current_ - begin_);
414 break;
415 } // Else, fall through...
416 default:
417 currentValue().setOffsetStart(token.start_ - begin_);
418 currentValue().setOffsetLimit(token.end_ - begin_);
419 return addError("Syntax error: value, object or array expected.", token);
420 }
421
422 if (collectComments_) {
423 lastValueEnd_ = current_;
424 lastValue_ = ¤tValue();
425 }
426
427 --stackDepth_g;
428 return successful;
429 }
430
skipCommentTokens(Token & token)431 void Reader::skipCommentTokens(Token& token) {
432 if (features_.allowComments_) {
433 do {
434 readToken(token);
435 } while (token.type_ == tokenComment);
436 } else {
437 readToken(token);
438 }
439 }
440
readToken(Token & token)441 bool Reader::readToken(Token& token) {
442 skipSpaces();
443 token.start_ = current_;
444 Char c = getNextChar();
445 bool ok = true;
446 switch (c) {
447 case '{':
448 token.type_ = tokenObjectBegin;
449 break;
450 case '}':
451 token.type_ = tokenObjectEnd;
452 break;
453 case '[':
454 token.type_ = tokenArrayBegin;
455 break;
456 case ']':
457 token.type_ = tokenArrayEnd;
458 break;
459 case '"':
460 token.type_ = tokenString;
461 ok = readString();
462 break;
463 case '/':
464 token.type_ = tokenComment;
465 ok = readComment();
466 break;
467 case '0':
468 case '1':
469 case '2':
470 case '3':
471 case '4':
472 case '5':
473 case '6':
474 case '7':
475 case '8':
476 case '9':
477 case '-':
478 token.type_ = tokenNumber;
479 readNumber();
480 break;
481 case 't':
482 token.type_ = tokenTrue;
483 ok = match("rue", 3);
484 break;
485 case 'f':
486 token.type_ = tokenFalse;
487 ok = match("alse", 4);
488 break;
489 case 'n':
490 token.type_ = tokenNull;
491 ok = match("ull", 3);
492 break;
493 case ',':
494 token.type_ = tokenArraySeparator;
495 break;
496 case ':':
497 token.type_ = tokenMemberSeparator;
498 break;
499 case 0:
500 token.type_ = tokenEndOfStream;
501 break;
502 default:
503 ok = false;
504 break;
505 }
506 if (!ok)
507 token.type_ = tokenError;
508 token.end_ = current_;
509 return true;
510 }
511
skipSpaces()512 void Reader::skipSpaces() {
513 while (current_ != end_) {
514 Char c = *current_;
515 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
516 ++current_;
517 else
518 break;
519 }
520 }
521
match(Location pattern,int patternLength)522 bool Reader::match(Location pattern, int patternLength) {
523 if (end_ - current_ < patternLength)
524 return false;
525 int index = patternLength;
526 while (index--)
527 if (current_[index] != pattern[index])
528 return false;
529 current_ += patternLength;
530 return true;
531 }
532
readComment()533 bool Reader::readComment() {
534 Location commentBegin = current_ - 1;
535 Char c = getNextChar();
536 bool successful = false;
537 if (c == '*')
538 successful = readCStyleComment();
539 else if (c == '/')
540 successful = readCppStyleComment();
541 if (!successful)
542 return false;
543
544 if (collectComments_) {
545 CommentPlacement placement = commentBefore;
546 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
547 if (c != '*' || !containsNewLine(commentBegin, current_))
548 placement = commentAfterOnSameLine;
549 }
550
551 addComment(commentBegin, current_, placement);
552 }
553 return true;
554 }
555
normalizeEOL(Reader::Location begin,Reader::Location end)556 static std::string normalizeEOL(Reader::Location begin, Reader::Location end) {
557 std::string normalized;
558 normalized.reserve(end - begin);
559 Reader::Location current = begin;
560 while (current != end) {
561 char c = *current++;
562 if (c == '\r') {
563 if (current != end && *current == '\n')
564 // convert dos EOL
565 ++current;
566 // convert Mac EOL
567 normalized += '\n';
568 } else {
569 normalized += c;
570 }
571 }
572 return normalized;
573 }
574
575 void
addComment(Location begin,Location end,CommentPlacement placement)576 Reader::addComment(Location begin, Location end, CommentPlacement placement) {
577 assert(collectComments_);
578 const std::string& normalized = normalizeEOL(begin, end);
579 if (placement == commentAfterOnSameLine) {
580 assert(lastValue_ != 0);
581 lastValue_->setComment(normalized, placement);
582 } else {
583 commentsBefore_ += normalized;
584 }
585 }
586
readCStyleComment()587 bool Reader::readCStyleComment() {
588 while (current_ != end_) {
589 Char c = getNextChar();
590 if (c == '*' && *current_ == '/')
591 break;
592 }
593 return getNextChar() == '/';
594 }
595
readCppStyleComment()596 bool Reader::readCppStyleComment() {
597 while (current_ != end_) {
598 Char c = getNextChar();
599 if (c == '\n')
600 break;
601 if (c == '\r') {
602 // Consume DOS EOL. It will be normalized in addComment.
603 if (current_ != end_ && *current_ == '\n')
604 getNextChar();
605 // Break on Moc OS 9 EOL.
606 break;
607 }
608 }
609 return true;
610 }
611
readNumber()612 void Reader::readNumber() {
613 const char *p = current_;
614 char c = '0'; // stopgap for already consumed character
615 // integral part
616 while (c >= '0' && c <= '9')
617 c = (current_ = p) < end_ ? *p++ : 0;
618 // fractional part
619 if (c == '.') {
620 c = (current_ = p) < end_ ? *p++ : 0;
621 while (c >= '0' && c <= '9')
622 c = (current_ = p) < end_ ? *p++ : 0;
623 }
624 // exponential part
625 if (c == 'e' || c == 'E') {
626 c = (current_ = p) < end_ ? *p++ : 0;
627 if (c == '+' || c == '-')
628 c = (current_ = p) < end_ ? *p++ : 0;
629 while (c >= '0' && c <= '9')
630 c = (current_ = p) < end_ ? *p++ : 0;
631 }
632 }
633
readString()634 bool Reader::readString() {
635 Char c = 0;
636 while (current_ != end_) {
637 c = getNextChar();
638 if (c == '\\')
639 getNextChar();
640 else if (c == '"')
641 break;
642 }
643 return c == '"';
644 }
645
readObject(Token & tokenStart)646 bool Reader::readObject(Token& tokenStart) {
647 Token tokenName;
648 std::string name;
649 Value init(objectValue);
650 currentValue().swapPayload(init);
651 currentValue().setOffsetStart(tokenStart.start_ - begin_);
652 while (readToken(tokenName)) {
653 bool initialTokenOk = true;
654 while (tokenName.type_ == tokenComment && initialTokenOk)
655 initialTokenOk = readToken(tokenName);
656 if (!initialTokenOk)
657 break;
658 if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
659 return true;
660 name = "";
661 if (tokenName.type_ == tokenString) {
662 if (!decodeString(tokenName, name))
663 return recoverFromError(tokenObjectEnd);
664 } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
665 Value numberName;
666 if (!decodeNumber(tokenName, numberName))
667 return recoverFromError(tokenObjectEnd);
668 name = numberName.asString();
669 } else {
670 break;
671 }
672
673 Token colon;
674 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
675 return addErrorAndRecover(
676 "Missing ':' after object member name", colon, tokenObjectEnd);
677 }
678 Value& value = currentValue()[name];
679 nodes_.push(&value);
680 bool ok = readValue();
681 nodes_.pop();
682 if (!ok) // error already set
683 return recoverFromError(tokenObjectEnd);
684
685 Token comma;
686 if (!readToken(comma) ||
687 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
688 comma.type_ != tokenComment)) {
689 return addErrorAndRecover(
690 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
691 }
692 bool finalizeTokenOk = true;
693 while (comma.type_ == tokenComment && finalizeTokenOk)
694 finalizeTokenOk = readToken(comma);
695 if (comma.type_ == tokenObjectEnd)
696 return true;
697 }
698 return addErrorAndRecover(
699 "Missing '}' or object member name", tokenName, tokenObjectEnd);
700 }
701
readArray(Token & tokenStart)702 bool Reader::readArray(Token& tokenStart) {
703 Value init(arrayValue);
704 currentValue().swapPayload(init);
705 currentValue().setOffsetStart(tokenStart.start_ - begin_);
706 skipSpaces();
707 if (*current_ == ']') // empty array
708 {
709 Token endArray;
710 readToken(endArray);
711 return true;
712 }
713 int index = 0;
714 for (;;) {
715 Value& value = currentValue()[index++];
716 nodes_.push(&value);
717 bool ok = readValue();
718 nodes_.pop();
719 if (!ok) // error already set
720 return recoverFromError(tokenArrayEnd);
721
722 Token token;
723 // Accept Comment after last item in the array.
724 ok = readToken(token);
725 while (token.type_ == tokenComment && ok) {
726 ok = readToken(token);
727 }
728 bool badTokenType =
729 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
730 if (!ok || badTokenType) {
731 return addErrorAndRecover(
732 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
733 }
734 if (token.type_ == tokenArrayEnd)
735 break;
736 }
737 return true;
738 }
739
decodeNumber(Token & token)740 bool Reader::decodeNumber(Token& token) {
741 Value decoded;
742 if (!decodeNumber(token, decoded))
743 return false;
744 currentValue().swapPayload(decoded);
745 currentValue().setOffsetStart(token.start_ - begin_);
746 currentValue().setOffsetLimit(token.end_ - begin_);
747 return true;
748 }
749
decodeNumber(Token & token,Value & decoded)750 bool Reader::decodeNumber(Token& token, Value& decoded) {
751 // Attempts to parse the number as an integer. If the number is
752 // larger than the maximum supported value of an integer then
753 // we decode the number as a double.
754 Location current = token.start_;
755 bool isNegative = *current == '-';
756 if (isNegative)
757 ++current;
758 // TODO: Help the compiler do the div and mod at compile time or get rid of them.
759 Value::LargestUInt maxIntegerValue =
760 isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
761 : Value::maxLargestUInt;
762 Value::LargestUInt threshold = maxIntegerValue / 10;
763 Value::LargestUInt value = 0;
764 while (current < token.end_) {
765 Char c = *current++;
766 if (c < '0' || c > '9')
767 return decodeDouble(token, decoded);
768 Value::UInt digit(c - '0');
769 if (value >= threshold) {
770 // We've hit or exceeded the max value divided by 10 (rounded down). If
771 // a) we've only just touched the limit, b) this is the last digit, and
772 // c) it's small enough to fit in that rounding delta, we're okay.
773 // Otherwise treat this number as a double to avoid overflow.
774 if (value > threshold || current != token.end_ ||
775 digit > maxIntegerValue % 10) {
776 return decodeDouble(token, decoded);
777 }
778 }
779 value = value * 10 + digit;
780 }
781 if (isNegative && value == maxIntegerValue)
782 decoded = Value::minLargestInt;
783 else if (isNegative)
784 decoded = -Value::LargestInt(value);
785 else if (value <= Value::LargestUInt(Value::maxInt))
786 decoded = Value::LargestInt(value);
787 else
788 decoded = value;
789 return true;
790 }
791
decodeDouble(Token & token)792 bool Reader::decodeDouble(Token& token) {
793 Value decoded;
794 if (!decodeDouble(token, decoded))
795 return false;
796 currentValue().swapPayload(decoded);
797 currentValue().setOffsetStart(token.start_ - begin_);
798 currentValue().setOffsetLimit(token.end_ - begin_);
799 return true;
800 }
801
decodeDouble(Token & token,Value & decoded)802 bool Reader::decodeDouble(Token& token, Value& decoded) {
803 double value = 0;
804 std::string buffer(token.start_, token.end_);
805 std::istringstream is(buffer);
806 if (!(is >> value))
807 return addError("'" + std::string(token.start_, token.end_) +
808 "' is not a number.",
809 token);
810 decoded = value;
811 return true;
812 }
813
decodeString(Token & token)814 bool Reader::decodeString(Token& token) {
815 std::string decoded_string;
816 if (!decodeString(token, decoded_string))
817 return false;
818 Value decoded(decoded_string);
819 currentValue().swapPayload(decoded);
820 currentValue().setOffsetStart(token.start_ - begin_);
821 currentValue().setOffsetLimit(token.end_ - begin_);
822 return true;
823 }
824
decodeString(Token & token,std::string & decoded)825 bool Reader::decodeString(Token& token, std::string& decoded) {
826 decoded.reserve(token.end_ - token.start_ - 2);
827 Location current = token.start_ + 1; // skip '"'
828 Location end = token.end_ - 1; // do not include '"'
829 while (current != end) {
830 Char c = *current++;
831 if (c == '"')
832 break;
833 else if (c == '\\') {
834 if (current == end)
835 return addError("Empty escape sequence in string", token, current);
836 Char escape = *current++;
837 switch (escape) {
838 case '"':
839 decoded += '"';
840 break;
841 case '/':
842 decoded += '/';
843 break;
844 case '\\':
845 decoded += '\\';
846 break;
847 case 'b':
848 decoded += '\b';
849 break;
850 case 'f':
851 decoded += '\f';
852 break;
853 case 'n':
854 decoded += '\n';
855 break;
856 case 'r':
857 decoded += '\r';
858 break;
859 case 't':
860 decoded += '\t';
861 break;
862 case 'u': {
863 unsigned int unicode;
864 if (!decodeUnicodeCodePoint(token, current, end, unicode))
865 return false;
866 decoded += codePointToUTF8(unicode);
867 } break;
868 default:
869 return addError("Bad escape sequence in string", token, current);
870 }
871 } else {
872 decoded += c;
873 }
874 }
875 return true;
876 }
877
decodeUnicodeCodePoint(Token & token,Location & current,Location end,unsigned int & unicode)878 bool Reader::decodeUnicodeCodePoint(Token& token,
879 Location& current,
880 Location end,
881 unsigned int& unicode) {
882
883 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
884 return false;
885 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
886 // surrogate pairs
887 if (end - current < 6)
888 return addError(
889 "additional six characters expected to parse unicode surrogate pair.",
890 token,
891 current);
892 unsigned int surrogatePair;
893 if (*(current++) == '\\' && *(current++) == 'u') {
894 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
895 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
896 } else
897 return false;
898 } else
899 return addError("expecting another \\u token to begin the second half of "
900 "a unicode surrogate pair",
901 token,
902 current);
903 }
904 return true;
905 }
906
decodeUnicodeEscapeSequence(Token & token,Location & current,Location end,unsigned int & unicode)907 bool Reader::decodeUnicodeEscapeSequence(Token& token,
908 Location& current,
909 Location end,
910 unsigned int& unicode) {
911 if (end - current < 4)
912 return addError(
913 "Bad unicode escape sequence in string: four digits expected.",
914 token,
915 current);
916 unicode = 0;
917 for (int index = 0; index < 4; ++index) {
918 Char c = *current++;
919 unicode *= 16;
920 if (c >= '0' && c <= '9')
921 unicode += c - '0';
922 else if (c >= 'a' && c <= 'f')
923 unicode += c - 'a' + 10;
924 else if (c >= 'A' && c <= 'F')
925 unicode += c - 'A' + 10;
926 else
927 return addError(
928 "Bad unicode escape sequence in string: hexadecimal digit expected.",
929 token,
930 current);
931 }
932 return true;
933 }
934
935 bool
addError(const std::string & message,Token & token,Location extra)936 Reader::addError(const std::string& message, Token& token, Location extra) {
937 ErrorInfo info;
938 info.token_ = token;
939 info.message_ = message;
940 info.extra_ = extra;
941 errors_.push_back(info);
942 return false;
943 }
944
recoverFromError(TokenType skipUntilToken)945 bool Reader::recoverFromError(TokenType skipUntilToken) {
946 int errorCount = int(errors_.size());
947 Token skip;
948 for (;;) {
949 if (!readToken(skip))
950 errors_.resize(errorCount); // discard errors caused by recovery
951 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
952 break;
953 }
954 errors_.resize(errorCount);
955 return false;
956 }
957
addErrorAndRecover(const std::string & message,Token & token,TokenType skipUntilToken)958 bool Reader::addErrorAndRecover(const std::string& message,
959 Token& token,
960 TokenType skipUntilToken) {
961 addError(message, token);
962 return recoverFromError(skipUntilToken);
963 }
964
currentValue()965 Value& Reader::currentValue() { return *(nodes_.top()); }
966
getNextChar()967 Reader::Char Reader::getNextChar() {
968 if (current_ == end_)
969 return 0;
970 return *current_++;
971 }
972
getLocationLineAndColumn(Location location,int & line,int & column) const973 void Reader::getLocationLineAndColumn(Location location,
974 int& line,
975 int& column) const {
976 Location current = begin_;
977 Location lastLineStart = current;
978 line = 0;
979 while (current < location && current != end_) {
980 Char c = *current++;
981 if (c == '\r') {
982 if (*current == '\n')
983 ++current;
984 lastLineStart = current;
985 ++line;
986 } else if (c == '\n') {
987 lastLineStart = current;
988 ++line;
989 }
990 }
991 // column & line start at 1
992 column = int(location - lastLineStart) + 1;
993 ++line;
994 }
995
getLocationLineAndColumn(Location location) const996 std::string Reader::getLocationLineAndColumn(Location location) const {
997 int line, column;
998 getLocationLineAndColumn(location, line, column);
999 char buffer[18 + 16 + 16 + 1];
1000 snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
1001 return buffer;
1002 }
1003
1004 // Deprecated. Preserved for backward compatibility
getFormatedErrorMessages() const1005 std::string Reader::getFormatedErrorMessages() const {
1006 return getFormattedErrorMessages();
1007 }
1008
getFormattedErrorMessages() const1009 std::string Reader::getFormattedErrorMessages() const {
1010 std::string formattedMessage;
1011 for (Errors::const_iterator itError = errors_.begin();
1012 itError != errors_.end();
1013 ++itError) {
1014 const ErrorInfo& error = *itError;
1015 formattedMessage +=
1016 "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
1017 formattedMessage += " " + error.message_ + "\n";
1018 if (error.extra_)
1019 formattedMessage +=
1020 "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
1021 }
1022 return formattedMessage;
1023 }
1024
getStructuredErrors() const1025 std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
1026 std::vector<Reader::StructuredError> allErrors;
1027 for (Errors::const_iterator itError = errors_.begin();
1028 itError != errors_.end();
1029 ++itError) {
1030 const ErrorInfo& error = *itError;
1031 Reader::StructuredError structured;
1032 structured.offset_start = error.token_.start_ - begin_;
1033 structured.offset_limit = error.token_.end_ - begin_;
1034 structured.message = error.message_;
1035 allErrors.push_back(structured);
1036 }
1037 return allErrors;
1038 }
1039
pushError(const Value & value,const std::string & message)1040 bool Reader::pushError(const Value& value, const std::string& message) {
1041 size_t length = end_ - begin_;
1042 if(value.getOffsetStart() > length
1043 || value.getOffsetLimit() > length)
1044 return false;
1045 Token token;
1046 token.type_ = tokenError;
1047 token.start_ = begin_ + value.getOffsetStart();
1048 token.end_ = end_ + value.getOffsetLimit();
1049 ErrorInfo info;
1050 info.token_ = token;
1051 info.message_ = message;
1052 info.extra_ = 0;
1053 errors_.push_back(info);
1054 return true;
1055 }
1056
pushError(const Value & value,const std::string & message,const Value & extra)1057 bool Reader::pushError(const Value& value, const std::string& message, const Value& extra) {
1058 size_t length = end_ - begin_;
1059 if(value.getOffsetStart() > length
1060 || value.getOffsetLimit() > length
1061 || extra.getOffsetLimit() > length)
1062 return false;
1063 Token token;
1064 token.type_ = tokenError;
1065 token.start_ = begin_ + value.getOffsetStart();
1066 token.end_ = begin_ + value.getOffsetLimit();
1067 ErrorInfo info;
1068 info.token_ = token;
1069 info.message_ = message;
1070 info.extra_ = begin_ + extra.getOffsetStart();
1071 errors_.push_back(info);
1072 return true;
1073 }
1074
good() const1075 bool Reader::good() const {
1076 return !errors_.size();
1077 }
1078
1079 // exact copy of Features
1080 class OurFeatures {
1081 public:
1082 static OurFeatures all();
1083 bool allowComments_;
1084 bool strictRoot_;
1085 bool allowDroppedNullPlaceholders_;
1086 bool allowNumericKeys_;
1087 bool allowSingleQuotes_;
1088 bool failIfExtra_;
1089 bool rejectDupKeys_;
1090 bool allowSpecialFloats_;
1091 int stackLimit_;
1092 }; // OurFeatures
1093
1094 // exact copy of Implementation of class Features
1095 // ////////////////////////////////
1096
all()1097 OurFeatures OurFeatures::all() { return OurFeatures(); }
1098
1099 // Implementation of class Reader
1100 // ////////////////////////////////
1101
1102 // exact copy of Reader, renamed to OurReader
1103 class OurReader {
1104 public:
1105 typedef char Char;
1106 typedef const Char* Location;
1107 struct StructuredError {
1108 size_t offset_start;
1109 size_t offset_limit;
1110 std::string message;
1111 };
1112
1113 OurReader(OurFeatures const& features);
1114 bool parse(const char* beginDoc,
1115 const char* endDoc,
1116 Value& root,
1117 bool collectComments = true);
1118 std::string getFormattedErrorMessages() const;
1119 std::vector<StructuredError> getStructuredErrors() const;
1120 bool pushError(const Value& value, const std::string& message);
1121 bool pushError(const Value& value, const std::string& message, const Value& extra);
1122 bool good() const;
1123
1124 private:
1125 OurReader(OurReader const&); // no impl
1126 void operator=(OurReader const&); // no impl
1127
1128 enum TokenType {
1129 tokenEndOfStream = 0,
1130 tokenObjectBegin,
1131 tokenObjectEnd,
1132 tokenArrayBegin,
1133 tokenArrayEnd,
1134 tokenString,
1135 tokenNumber,
1136 tokenTrue,
1137 tokenFalse,
1138 tokenNull,
1139 tokenNaN,
1140 tokenPosInf,
1141 tokenNegInf,
1142 tokenArraySeparator,
1143 tokenMemberSeparator,
1144 tokenComment,
1145 tokenError
1146 };
1147
1148 class Token {
1149 public:
1150 TokenType type_;
1151 Location start_;
1152 Location end_;
1153 };
1154
1155 class ErrorInfo {
1156 public:
1157 Token token_;
1158 std::string message_;
1159 Location extra_;
1160 };
1161
1162 typedef std::deque<ErrorInfo> Errors;
1163
1164 bool readToken(Token& token);
1165 void skipSpaces();
1166 bool match(Location pattern, int patternLength);
1167 bool readComment();
1168 bool readCStyleComment();
1169 bool readCppStyleComment();
1170 bool readString();
1171 bool readStringSingleQuote();
1172 bool readNumber(bool checkInf);
1173 bool readValue();
1174 bool readObject(Token& token);
1175 bool readArray(Token& token);
1176 bool decodeNumber(Token& token);
1177 bool decodeNumber(Token& token, Value& decoded);
1178 bool decodeString(Token& token);
1179 bool decodeString(Token& token, std::string& decoded);
1180 bool decodeDouble(Token& token);
1181 bool decodeDouble(Token& token, Value& decoded);
1182 bool decodeUnicodeCodePoint(Token& token,
1183 Location& current,
1184 Location end,
1185 unsigned int& unicode);
1186 bool decodeUnicodeEscapeSequence(Token& token,
1187 Location& current,
1188 Location end,
1189 unsigned int& unicode);
1190 bool addError(const std::string& message, Token& token, Location extra = 0);
1191 bool recoverFromError(TokenType skipUntilToken);
1192 bool addErrorAndRecover(const std::string& message,
1193 Token& token,
1194 TokenType skipUntilToken);
1195 void skipUntilSpace();
1196 Value& currentValue();
1197 Char getNextChar();
1198 void
1199 getLocationLineAndColumn(Location location, int& line, int& column) const;
1200 std::string getLocationLineAndColumn(Location location) const;
1201 void addComment(Location begin, Location end, CommentPlacement placement);
1202 void skipCommentTokens(Token& token);
1203
1204 typedef std::stack<Value*> Nodes;
1205 Nodes nodes_;
1206 Errors errors_;
1207 std::string document_;
1208 Location begin_;
1209 Location end_;
1210 Location current_;
1211 Location lastValueEnd_;
1212 Value* lastValue_;
1213 std::string commentsBefore_;
1214 int stackDepth_;
1215
1216 OurFeatures const features_;
1217 bool collectComments_;
1218 }; // OurReader
1219
1220 // complete copy of Read impl, for OurReader
1221
OurReader(OurFeatures const & features)1222 OurReader::OurReader(OurFeatures const& features)
1223 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
1224 lastValue_(), commentsBefore_(),
1225 stackDepth_(0),
1226 features_(features), collectComments_() {
1227 }
1228
parse(const char * beginDoc,const char * endDoc,Value & root,bool collectComments)1229 bool OurReader::parse(const char* beginDoc,
1230 const char* endDoc,
1231 Value& root,
1232 bool collectComments) {
1233 if (!features_.allowComments_) {
1234 collectComments = false;
1235 }
1236
1237 begin_ = beginDoc;
1238 end_ = endDoc;
1239 collectComments_ = collectComments;
1240 current_ = begin_;
1241 lastValueEnd_ = 0;
1242 lastValue_ = 0;
1243 commentsBefore_ = "";
1244 errors_.clear();
1245 while (!nodes_.empty())
1246 nodes_.pop();
1247 nodes_.push(&root);
1248
1249 stackDepth_ = 0;
1250 bool successful = readValue();
1251 Token token;
1252 skipCommentTokens(token);
1253 if (features_.failIfExtra_) {
1254 if (token.type_ != tokenError && token.type_ != tokenEndOfStream) {
1255 addError("Extra non-whitespace after JSON value.", token);
1256 return false;
1257 }
1258 }
1259 if (collectComments_ && !commentsBefore_.empty())
1260 root.setComment(commentsBefore_, commentAfter);
1261 if (features_.strictRoot_) {
1262 if (!root.isArray() && !root.isObject()) {
1263 // Set error location to start of doc, ideally should be first token found
1264 // in doc
1265 token.type_ = tokenError;
1266 token.start_ = beginDoc;
1267 token.end_ = endDoc;
1268 addError(
1269 "A valid JSON document must be either an array or an object value.",
1270 token);
1271 return false;
1272 }
1273 }
1274 return successful;
1275 }
1276
readValue()1277 bool OurReader::readValue() {
1278 if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");
1279 ++stackDepth_;
1280 Token token;
1281 skipCommentTokens(token);
1282 bool successful = true;
1283
1284 if (collectComments_ && !commentsBefore_.empty()) {
1285 currentValue().setComment(commentsBefore_, commentBefore);
1286 commentsBefore_ = "";
1287 }
1288
1289 switch (token.type_) {
1290 case tokenObjectBegin:
1291 successful = readObject(token);
1292 currentValue().setOffsetLimit(current_ - begin_);
1293 break;
1294 case tokenArrayBegin:
1295 successful = readArray(token);
1296 currentValue().setOffsetLimit(current_ - begin_);
1297 break;
1298 case tokenNumber:
1299 successful = decodeNumber(token);
1300 break;
1301 case tokenString:
1302 successful = decodeString(token);
1303 break;
1304 case tokenTrue:
1305 {
1306 Value v(true);
1307 currentValue().swapPayload(v);
1308 currentValue().setOffsetStart(token.start_ - begin_);
1309 currentValue().setOffsetLimit(token.end_ - begin_);
1310 }
1311 break;
1312 case tokenFalse:
1313 {
1314 Value v(false);
1315 currentValue().swapPayload(v);
1316 currentValue().setOffsetStart(token.start_ - begin_);
1317 currentValue().setOffsetLimit(token.end_ - begin_);
1318 }
1319 break;
1320 case tokenNull:
1321 {
1322 Value v;
1323 currentValue().swapPayload(v);
1324 currentValue().setOffsetStart(token.start_ - begin_);
1325 currentValue().setOffsetLimit(token.end_ - begin_);
1326 }
1327 break;
1328 case tokenNaN:
1329 {
1330 Value v(std::numeric_limits<double>::quiet_NaN());
1331 currentValue().swapPayload(v);
1332 currentValue().setOffsetStart(token.start_ - begin_);
1333 currentValue().setOffsetLimit(token.end_ - begin_);
1334 }
1335 break;
1336 case tokenPosInf:
1337 {
1338 Value v(std::numeric_limits<double>::infinity());
1339 currentValue().swapPayload(v);
1340 currentValue().setOffsetStart(token.start_ - begin_);
1341 currentValue().setOffsetLimit(token.end_ - begin_);
1342 }
1343 break;
1344 case tokenNegInf:
1345 {
1346 Value v(-std::numeric_limits<double>::infinity());
1347 currentValue().swapPayload(v);
1348 currentValue().setOffsetStart(token.start_ - begin_);
1349 currentValue().setOffsetLimit(token.end_ - begin_);
1350 }
1351 break;
1352 case tokenArraySeparator:
1353 case tokenObjectEnd:
1354 case tokenArrayEnd:
1355 if (features_.allowDroppedNullPlaceholders_) {
1356 // "Un-read" the current token and mark the current value as a null
1357 // token.
1358 current_--;
1359 Value v;
1360 currentValue().swapPayload(v);
1361 currentValue().setOffsetStart(current_ - begin_ - 1);
1362 currentValue().setOffsetLimit(current_ - begin_);
1363 break;
1364 } // else, fall through ...
1365 default:
1366 currentValue().setOffsetStart(token.start_ - begin_);
1367 currentValue().setOffsetLimit(token.end_ - begin_);
1368 return addError("Syntax error: value, object or array expected.", token);
1369 }
1370
1371 if (collectComments_) {
1372 lastValueEnd_ = current_;
1373 lastValue_ = ¤tValue();
1374 }
1375
1376 --stackDepth_;
1377 return successful;
1378 }
1379
skipCommentTokens(Token & token)1380 void OurReader::skipCommentTokens(Token& token) {
1381 if (features_.allowComments_) {
1382 do {
1383 readToken(token);
1384 } while (token.type_ == tokenComment);
1385 } else {
1386 readToken(token);
1387 }
1388 }
1389
readToken(Token & token)1390 bool OurReader::readToken(Token& token) {
1391 skipSpaces();
1392 token.start_ = current_;
1393 Char c = getNextChar();
1394 bool ok = true;
1395 switch (c) {
1396 case '{':
1397 token.type_ = tokenObjectBegin;
1398 break;
1399 case '}':
1400 token.type_ = tokenObjectEnd;
1401 break;
1402 case '[':
1403 token.type_ = tokenArrayBegin;
1404 break;
1405 case ']':
1406 token.type_ = tokenArrayEnd;
1407 break;
1408 case '"':
1409 token.type_ = tokenString;
1410 ok = readString();
1411 break;
1412 case '\'':
1413 if (features_.allowSingleQuotes_) {
1414 token.type_ = tokenString;
1415 ok = readStringSingleQuote();
1416 break;
1417 } // else continue
1418 case '/':
1419 token.type_ = tokenComment;
1420 ok = readComment();
1421 break;
1422 case '0':
1423 case '1':
1424 case '2':
1425 case '3':
1426 case '4':
1427 case '5':
1428 case '6':
1429 case '7':
1430 case '8':
1431 case '9':
1432 token.type_ = tokenNumber;
1433 readNumber(false);
1434 break;
1435 case '-':
1436 if (readNumber(true)) {
1437 token.type_ = tokenNumber;
1438 } else {
1439 token.type_ = tokenNegInf;
1440 ok = features_.allowSpecialFloats_ && match("nfinity", 7);
1441 }
1442 break;
1443 case 't':
1444 token.type_ = tokenTrue;
1445 ok = match("rue", 3);
1446 break;
1447 case 'f':
1448 token.type_ = tokenFalse;
1449 ok = match("alse", 4);
1450 break;
1451 case 'n':
1452 token.type_ = tokenNull;
1453 ok = match("ull", 3);
1454 break;
1455 case 'N':
1456 if (features_.allowSpecialFloats_) {
1457 token.type_ = tokenNaN;
1458 ok = match("aN", 2);
1459 } else {
1460 ok = false;
1461 }
1462 break;
1463 case 'I':
1464 if (features_.allowSpecialFloats_) {
1465 token.type_ = tokenPosInf;
1466 ok = match("nfinity", 7);
1467 } else {
1468 ok = false;
1469 }
1470 break;
1471 case ',':
1472 token.type_ = tokenArraySeparator;
1473 break;
1474 case ':':
1475 token.type_ = tokenMemberSeparator;
1476 break;
1477 case 0:
1478 token.type_ = tokenEndOfStream;
1479 break;
1480 default:
1481 ok = false;
1482 break;
1483 }
1484 if (!ok)
1485 token.type_ = tokenError;
1486 token.end_ = current_;
1487 return true;
1488 }
1489
skipSpaces()1490 void OurReader::skipSpaces() {
1491 while (current_ != end_) {
1492 Char c = *current_;
1493 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
1494 ++current_;
1495 else
1496 break;
1497 }
1498 }
1499
match(Location pattern,int patternLength)1500 bool OurReader::match(Location pattern, int patternLength) {
1501 if (end_ - current_ < patternLength)
1502 return false;
1503 int index = patternLength;
1504 while (index--)
1505 if (current_[index] != pattern[index])
1506 return false;
1507 current_ += patternLength;
1508 return true;
1509 }
1510
readComment()1511 bool OurReader::readComment() {
1512 Location commentBegin = current_ - 1;
1513 Char c = getNextChar();
1514 bool successful = false;
1515 if (c == '*')
1516 successful = readCStyleComment();
1517 else if (c == '/')
1518 successful = readCppStyleComment();
1519 if (!successful)
1520 return false;
1521
1522 if (collectComments_) {
1523 CommentPlacement placement = commentBefore;
1524 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
1525 if (c != '*' || !containsNewLine(commentBegin, current_))
1526 placement = commentAfterOnSameLine;
1527 }
1528
1529 addComment(commentBegin, current_, placement);
1530 }
1531 return true;
1532 }
1533
1534 void
addComment(Location begin,Location end,CommentPlacement placement)1535 OurReader::addComment(Location begin, Location end, CommentPlacement placement) {
1536 assert(collectComments_);
1537 const std::string& normalized = normalizeEOL(begin, end);
1538 if (placement == commentAfterOnSameLine) {
1539 assert(lastValue_ != 0);
1540 lastValue_->setComment(normalized, placement);
1541 } else {
1542 commentsBefore_ += normalized;
1543 }
1544 }
1545
readCStyleComment()1546 bool OurReader::readCStyleComment() {
1547 while (current_ != end_) {
1548 Char c = getNextChar();
1549 if (c == '*' && *current_ == '/')
1550 break;
1551 }
1552 return getNextChar() == '/';
1553 }
1554
readCppStyleComment()1555 bool OurReader::readCppStyleComment() {
1556 while (current_ != end_) {
1557 Char c = getNextChar();
1558 if (c == '\n')
1559 break;
1560 if (c == '\r') {
1561 // Consume DOS EOL. It will be normalized in addComment.
1562 if (current_ != end_ && *current_ == '\n')
1563 getNextChar();
1564 // Break on Moc OS 9 EOL.
1565 break;
1566 }
1567 }
1568 return true;
1569 }
1570
readNumber(bool checkInf)1571 bool OurReader::readNumber(bool checkInf) {
1572 const char *p = current_;
1573 if (checkInf && p != end_ && *p == 'I') {
1574 current_ = ++p;
1575 return false;
1576 }
1577 char c = '0'; // stopgap for already consumed character
1578 // integral part
1579 while (c >= '0' && c <= '9')
1580 c = (current_ = p) < end_ ? *p++ : 0;
1581 // fractional part
1582 if (c == '.') {
1583 c = (current_ = p) < end_ ? *p++ : 0;
1584 while (c >= '0' && c <= '9')
1585 c = (current_ = p) < end_ ? *p++ : 0;
1586 }
1587 // exponential part
1588 if (c == 'e' || c == 'E') {
1589 c = (current_ = p) < end_ ? *p++ : 0;
1590 if (c == '+' || c == '-')
1591 c = (current_ = p) < end_ ? *p++ : 0;
1592 while (c >= '0' && c <= '9')
1593 c = (current_ = p) < end_ ? *p++ : 0;
1594 }
1595 return true;
1596 }
readString()1597 bool OurReader::readString() {
1598 Char c = 0;
1599 while (current_ != end_) {
1600 c = getNextChar();
1601 if (c == '\\')
1602 getNextChar();
1603 else if (c == '"')
1604 break;
1605 }
1606 return c == '"';
1607 }
1608
1609
readStringSingleQuote()1610 bool OurReader::readStringSingleQuote() {
1611 Char c = 0;
1612 while (current_ != end_) {
1613 c = getNextChar();
1614 if (c == '\\')
1615 getNextChar();
1616 else if (c == '\'')
1617 break;
1618 }
1619 return c == '\'';
1620 }
1621
readObject(Token & tokenStart)1622 bool OurReader::readObject(Token& tokenStart) {
1623 Token tokenName;
1624 std::string name;
1625 Value init(objectValue);
1626 currentValue().swapPayload(init);
1627 currentValue().setOffsetStart(tokenStart.start_ - begin_);
1628 while (readToken(tokenName)) {
1629 bool initialTokenOk = true;
1630 while (tokenName.type_ == tokenComment && initialTokenOk)
1631 initialTokenOk = readToken(tokenName);
1632 if (!initialTokenOk)
1633 break;
1634 if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
1635 return true;
1636 name = "";
1637 if (tokenName.type_ == tokenString) {
1638 if (!decodeString(tokenName, name))
1639 return recoverFromError(tokenObjectEnd);
1640 } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1641 Value numberName;
1642 if (!decodeNumber(tokenName, numberName))
1643 return recoverFromError(tokenObjectEnd);
1644 name = numberName.asString();
1645 } else {
1646 break;
1647 }
1648
1649 Token colon;
1650 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1651 return addErrorAndRecover(
1652 "Missing ':' after object member name", colon, tokenObjectEnd);
1653 }
1654 if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");
1655 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1656 std::string msg = "Duplicate key: '" + name + "'";
1657 return addErrorAndRecover(
1658 msg, tokenName, tokenObjectEnd);
1659 }
1660 Value& value = currentValue()[name];
1661 nodes_.push(&value);
1662 bool ok = readValue();
1663 nodes_.pop();
1664 if (!ok) // error already set
1665 return recoverFromError(tokenObjectEnd);
1666
1667 Token comma;
1668 if (!readToken(comma) ||
1669 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1670 comma.type_ != tokenComment)) {
1671 return addErrorAndRecover(
1672 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
1673 }
1674 bool finalizeTokenOk = true;
1675 while (comma.type_ == tokenComment && finalizeTokenOk)
1676 finalizeTokenOk = readToken(comma);
1677 if (comma.type_ == tokenObjectEnd)
1678 return true;
1679 }
1680 return addErrorAndRecover(
1681 "Missing '}' or object member name", tokenName, tokenObjectEnd);
1682 }
1683
readArray(Token & tokenStart)1684 bool OurReader::readArray(Token& tokenStart) {
1685 Value init(arrayValue);
1686 currentValue().swapPayload(init);
1687 currentValue().setOffsetStart(tokenStart.start_ - begin_);
1688 skipSpaces();
1689 if (*current_ == ']') // empty array
1690 {
1691 Token endArray;
1692 readToken(endArray);
1693 return true;
1694 }
1695 int index = 0;
1696 for (;;) {
1697 Value& value = currentValue()[index++];
1698 nodes_.push(&value);
1699 bool ok = readValue();
1700 nodes_.pop();
1701 if (!ok) // error already set
1702 return recoverFromError(tokenArrayEnd);
1703
1704 Token token;
1705 // Accept Comment after last item in the array.
1706 ok = readToken(token);
1707 while (token.type_ == tokenComment && ok) {
1708 ok = readToken(token);
1709 }
1710 bool badTokenType =
1711 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
1712 if (!ok || badTokenType) {
1713 return addErrorAndRecover(
1714 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
1715 }
1716 if (token.type_ == tokenArrayEnd)
1717 break;
1718 }
1719 return true;
1720 }
1721
decodeNumber(Token & token)1722 bool OurReader::decodeNumber(Token& token) {
1723 Value decoded;
1724 if (!decodeNumber(token, decoded))
1725 return false;
1726 currentValue().swapPayload(decoded);
1727 currentValue().setOffsetStart(token.start_ - begin_);
1728 currentValue().setOffsetLimit(token.end_ - begin_);
1729 return true;
1730 }
1731
decodeNumber(Token & token,Value & decoded)1732 bool OurReader::decodeNumber(Token& token, Value& decoded) {
1733 // Attempts to parse the number as an integer. If the number is
1734 // larger than the maximum supported value of an integer then
1735 // we decode the number as a double.
1736 Location current = token.start_;
1737 bool isNegative = *current == '-';
1738 if (isNegative)
1739 ++current;
1740 // TODO: Help the compiler do the div and mod at compile time or get rid of them.
1741 Value::LargestUInt maxIntegerValue =
1742 isNegative ? Value::LargestUInt(-Value::minLargestInt)
1743 : Value::maxLargestUInt;
1744 Value::LargestUInt threshold = maxIntegerValue / 10;
1745 Value::LargestUInt value = 0;
1746 while (current < token.end_) {
1747 Char c = *current++;
1748 if (c < '0' || c > '9')
1749 return decodeDouble(token, decoded);
1750 Value::UInt digit(c - '0');
1751 if (value >= threshold) {
1752 // We've hit or exceeded the max value divided by 10 (rounded down). If
1753 // a) we've only just touched the limit, b) this is the last digit, and
1754 // c) it's small enough to fit in that rounding delta, we're okay.
1755 // Otherwise treat this number as a double to avoid overflow.
1756 if (value > threshold || current != token.end_ ||
1757 digit > maxIntegerValue % 10) {
1758 return decodeDouble(token, decoded);
1759 }
1760 }
1761 value = value * 10 + digit;
1762 }
1763 if (isNegative)
1764 decoded = -Value::LargestInt(value);
1765 else if (value <= Value::LargestUInt(Value::maxInt))
1766 decoded = Value::LargestInt(value);
1767 else
1768 decoded = value;
1769 return true;
1770 }
1771
decodeDouble(Token & token)1772 bool OurReader::decodeDouble(Token& token) {
1773 Value decoded;
1774 if (!decodeDouble(token, decoded))
1775 return false;
1776 currentValue().swapPayload(decoded);
1777 currentValue().setOffsetStart(token.start_ - begin_);
1778 currentValue().setOffsetLimit(token.end_ - begin_);
1779 return true;
1780 }
1781
decodeDouble(Token & token,Value & decoded)1782 bool OurReader::decodeDouble(Token& token, Value& decoded) {
1783 double value = 0;
1784 const int bufferSize = 32;
1785 int count;
1786 int length = int(token.end_ - token.start_);
1787
1788 // Sanity check to avoid buffer overflow exploits.
1789 if (length < 0) {
1790 return addError("Unable to parse token length", token);
1791 }
1792
1793 // Avoid using a string constant for the format control string given to
1794 // sscanf, as this can cause hard to debug crashes on OS X. See here for more
1795 // info:
1796 //
1797 // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
1798 char format[] = "%lf";
1799
1800 if (length <= bufferSize) {
1801 Char buffer[bufferSize + 1];
1802 memcpy(buffer, token.start_, length);
1803 buffer[length] = 0;
1804 count = sscanf(buffer, format, &value);
1805 } else {
1806 std::string buffer(token.start_, token.end_);
1807 count = sscanf(buffer.c_str(), format, &value);
1808 }
1809
1810 if (count != 1)
1811 return addError("'" + std::string(token.start_, token.end_) +
1812 "' is not a number.",
1813 token);
1814 decoded = value;
1815 return true;
1816 }
1817
decodeString(Token & token)1818 bool OurReader::decodeString(Token& token) {
1819 std::string decoded_string;
1820 if (!decodeString(token, decoded_string))
1821 return false;
1822 Value decoded(decoded_string);
1823 currentValue().swapPayload(decoded);
1824 currentValue().setOffsetStart(token.start_ - begin_);
1825 currentValue().setOffsetLimit(token.end_ - begin_);
1826 return true;
1827 }
1828
decodeString(Token & token,std::string & decoded)1829 bool OurReader::decodeString(Token& token, std::string& decoded) {
1830 decoded.reserve(token.end_ - token.start_ - 2);
1831 Location current = token.start_ + 1; // skip '"'
1832 Location end = token.end_ - 1; // do not include '"'
1833 while (current != end) {
1834 Char c = *current++;
1835 if (c == '"')
1836 break;
1837 else if (c == '\\') {
1838 if (current == end)
1839 return addError("Empty escape sequence in string", token, current);
1840 Char escape = *current++;
1841 switch (escape) {
1842 case '"':
1843 decoded += '"';
1844 break;
1845 case '/':
1846 decoded += '/';
1847 break;
1848 case '\\':
1849 decoded += '\\';
1850 break;
1851 case 'b':
1852 decoded += '\b';
1853 break;
1854 case 'f':
1855 decoded += '\f';
1856 break;
1857 case 'n':
1858 decoded += '\n';
1859 break;
1860 case 'r':
1861 decoded += '\r';
1862 break;
1863 case 't':
1864 decoded += '\t';
1865 break;
1866 case 'u': {
1867 unsigned int unicode;
1868 if (!decodeUnicodeCodePoint(token, current, end, unicode))
1869 return false;
1870 decoded += codePointToUTF8(unicode);
1871 } break;
1872 default:
1873 return addError("Bad escape sequence in string", token, current);
1874 }
1875 } else {
1876 decoded += c;
1877 }
1878 }
1879 return true;
1880 }
1881
decodeUnicodeCodePoint(Token & token,Location & current,Location end,unsigned int & unicode)1882 bool OurReader::decodeUnicodeCodePoint(Token& token,
1883 Location& current,
1884 Location end,
1885 unsigned int& unicode) {
1886
1887 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1888 return false;
1889 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1890 // surrogate pairs
1891 if (end - current < 6)
1892 return addError(
1893 "additional six characters expected to parse unicode surrogate pair.",
1894 token,
1895 current);
1896 unsigned int surrogatePair;
1897 if (*(current++) == '\\' && *(current++) == 'u') {
1898 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1899 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1900 } else
1901 return false;
1902 } else
1903 return addError("expecting another \\u token to begin the second half of "
1904 "a unicode surrogate pair",
1905 token,
1906 current);
1907 }
1908 return true;
1909 }
1910
decodeUnicodeEscapeSequence(Token & token,Location & current,Location end,unsigned int & unicode)1911 bool OurReader::decodeUnicodeEscapeSequence(Token& token,
1912 Location& current,
1913 Location end,
1914 unsigned int& unicode) {
1915 if (end - current < 4)
1916 return addError(
1917 "Bad unicode escape sequence in string: four digits expected.",
1918 token,
1919 current);
1920 unicode = 0;
1921 for (int index = 0; index < 4; ++index) {
1922 Char c = *current++;
1923 unicode *= 16;
1924 if (c >= '0' && c <= '9')
1925 unicode += c - '0';
1926 else if (c >= 'a' && c <= 'f')
1927 unicode += c - 'a' + 10;
1928 else if (c >= 'A' && c <= 'F')
1929 unicode += c - 'A' + 10;
1930 else
1931 return addError(
1932 "Bad unicode escape sequence in string: hexadecimal digit expected.",
1933 token,
1934 current);
1935 }
1936 return true;
1937 }
1938
1939 bool
addError(const std::string & message,Token & token,Location extra)1940 OurReader::addError(const std::string& message, Token& token, Location extra) {
1941 ErrorInfo info;
1942 info.token_ = token;
1943 info.message_ = message;
1944 info.extra_ = extra;
1945 errors_.push_back(info);
1946 return false;
1947 }
1948
recoverFromError(TokenType skipUntilToken)1949 bool OurReader::recoverFromError(TokenType skipUntilToken) {
1950 int errorCount = int(errors_.size());
1951 Token skip;
1952 for (;;) {
1953 if (!readToken(skip))
1954 errors_.resize(errorCount); // discard errors caused by recovery
1955 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
1956 break;
1957 }
1958 errors_.resize(errorCount);
1959 return false;
1960 }
1961
addErrorAndRecover(const std::string & message,Token & token,TokenType skipUntilToken)1962 bool OurReader::addErrorAndRecover(const std::string& message,
1963 Token& token,
1964 TokenType skipUntilToken) {
1965 addError(message, token);
1966 return recoverFromError(skipUntilToken);
1967 }
1968
currentValue()1969 Value& OurReader::currentValue() { return *(nodes_.top()); }
1970
getNextChar()1971 OurReader::Char OurReader::getNextChar() {
1972 if (current_ == end_)
1973 return 0;
1974 return *current_++;
1975 }
1976
getLocationLineAndColumn(Location location,int & line,int & column) const1977 void OurReader::getLocationLineAndColumn(Location location,
1978 int& line,
1979 int& column) const {
1980 Location current = begin_;
1981 Location lastLineStart = current;
1982 line = 0;
1983 while (current < location && current != end_) {
1984 Char c = *current++;
1985 if (c == '\r') {
1986 if (*current == '\n')
1987 ++current;
1988 lastLineStart = current;
1989 ++line;
1990 } else if (c == '\n') {
1991 lastLineStart = current;
1992 ++line;
1993 }
1994 }
1995 // column & line start at 1
1996 column = int(location - lastLineStart) + 1;
1997 ++line;
1998 }
1999
getLocationLineAndColumn(Location location) const2000 std::string OurReader::getLocationLineAndColumn(Location location) const {
2001 int line, column;
2002 getLocationLineAndColumn(location, line, column);
2003 char buffer[18 + 16 + 16 + 1];
2004 snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
2005 return buffer;
2006 }
2007
getFormattedErrorMessages() const2008 std::string OurReader::getFormattedErrorMessages() const {
2009 std::string formattedMessage;
2010 for (Errors::const_iterator itError = errors_.begin();
2011 itError != errors_.end();
2012 ++itError) {
2013 const ErrorInfo& error = *itError;
2014 formattedMessage +=
2015 "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
2016 formattedMessage += " " + error.message_ + "\n";
2017 if (error.extra_)
2018 formattedMessage +=
2019 "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
2020 }
2021 return formattedMessage;
2022 }
2023
getStructuredErrors() const2024 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
2025 std::vector<OurReader::StructuredError> allErrors;
2026 for (Errors::const_iterator itError = errors_.begin();
2027 itError != errors_.end();
2028 ++itError) {
2029 const ErrorInfo& error = *itError;
2030 OurReader::StructuredError structured;
2031 structured.offset_start = error.token_.start_ - begin_;
2032 structured.offset_limit = error.token_.end_ - begin_;
2033 structured.message = error.message_;
2034 allErrors.push_back(structured);
2035 }
2036 return allErrors;
2037 }
2038
pushError(const Value & value,const std::string & message)2039 bool OurReader::pushError(const Value& value, const std::string& message) {
2040 size_t length = end_ - begin_;
2041 if(value.getOffsetStart() > length
2042 || value.getOffsetLimit() > length)
2043 return false;
2044 Token token;
2045 token.type_ = tokenError;
2046 token.start_ = begin_ + value.getOffsetStart();
2047 token.end_ = end_ + value.getOffsetLimit();
2048 ErrorInfo info;
2049 info.token_ = token;
2050 info.message_ = message;
2051 info.extra_ = 0;
2052 errors_.push_back(info);
2053 return true;
2054 }
2055
pushError(const Value & value,const std::string & message,const Value & extra)2056 bool OurReader::pushError(const Value& value, const std::string& message, const Value& extra) {
2057 size_t length = end_ - begin_;
2058 if(value.getOffsetStart() > length
2059 || value.getOffsetLimit() > length
2060 || extra.getOffsetLimit() > length)
2061 return false;
2062 Token token;
2063 token.type_ = tokenError;
2064 token.start_ = begin_ + value.getOffsetStart();
2065 token.end_ = begin_ + value.getOffsetLimit();
2066 ErrorInfo info;
2067 info.token_ = token;
2068 info.message_ = message;
2069 info.extra_ = begin_ + extra.getOffsetStart();
2070 errors_.push_back(info);
2071 return true;
2072 }
2073
good() const2074 bool OurReader::good() const {
2075 return !errors_.size();
2076 }
2077
2078
2079 class OurCharReader : public CharReader {
2080 bool const collectComments_;
2081 OurReader reader_;
2082 public:
OurCharReader(bool collectComments,OurFeatures const & features)2083 OurCharReader(
2084 bool collectComments,
2085 OurFeatures const& features)
2086 : collectComments_(collectComments)
2087 , reader_(features)
2088 {}
parse(char const * beginDoc,char const * endDoc,Value * root,std::string * errs)2089 bool parse(
2090 char const* beginDoc, char const* endDoc,
2091 Value* root, std::string* errs) override {
2092 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
2093 if (errs) {
2094 *errs = reader_.getFormattedErrorMessages();
2095 }
2096 return ok;
2097 }
2098 };
2099
CharReaderBuilder()2100 CharReaderBuilder::CharReaderBuilder()
2101 {
2102 setDefaults(&settings_);
2103 }
~CharReaderBuilder()2104 CharReaderBuilder::~CharReaderBuilder()
2105 {}
newCharReader() const2106 CharReader* CharReaderBuilder::newCharReader() const
2107 {
2108 bool collectComments = settings_["collectComments"].asBool();
2109 OurFeatures features = OurFeatures::all();
2110 features.allowComments_ = settings_["allowComments"].asBool();
2111 features.strictRoot_ = settings_["strictRoot"].asBool();
2112 features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
2113 features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
2114 features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
2115 features.stackLimit_ = settings_["stackLimit"].asInt();
2116 features.failIfExtra_ = settings_["failIfExtra"].asBool();
2117 features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
2118 features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
2119 return new OurCharReader(collectComments, features);
2120 }
getValidReaderKeys(std::set<std::string> * valid_keys)2121 static void getValidReaderKeys(std::set<std::string>* valid_keys)
2122 {
2123 valid_keys->clear();
2124 valid_keys->insert("collectComments");
2125 valid_keys->insert("allowComments");
2126 valid_keys->insert("strictRoot");
2127 valid_keys->insert("allowDroppedNullPlaceholders");
2128 valid_keys->insert("allowNumericKeys");
2129 valid_keys->insert("allowSingleQuotes");
2130 valid_keys->insert("stackLimit");
2131 valid_keys->insert("failIfExtra");
2132 valid_keys->insert("rejectDupKeys");
2133 valid_keys->insert("allowSpecialFloats");
2134 }
validate(Json::Value * invalid) const2135 bool CharReaderBuilder::validate(Json::Value* invalid) const
2136 {
2137 Json::Value my_invalid;
2138 if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
2139 Json::Value& inv = *invalid;
2140 std::set<std::string> valid_keys;
2141 getValidReaderKeys(&valid_keys);
2142 Value::Members keys = settings_.getMemberNames();
2143 size_t n = keys.size();
2144 for (size_t i = 0; i < n; ++i) {
2145 std::string const& key = keys[i];
2146 if (valid_keys.find(key) == valid_keys.end()) {
2147 inv[key] = settings_[key];
2148 }
2149 }
2150 return 0u == inv.size();
2151 }
operator [](std::string key)2152 Value& CharReaderBuilder::operator[](std::string key)
2153 {
2154 return settings_[key];
2155 }
2156 // static
strictMode(Json::Value * settings)2157 void CharReaderBuilder::strictMode(Json::Value* settings)
2158 {
2159 //! [CharReaderBuilderStrictMode]
2160 (*settings)["allowComments"] = false;
2161 (*settings)["strictRoot"] = true;
2162 (*settings)["allowDroppedNullPlaceholders"] = false;
2163 (*settings)["allowNumericKeys"] = false;
2164 (*settings)["allowSingleQuotes"] = false;
2165 (*settings)["stackLimit"] = 1000;
2166 (*settings)["failIfExtra"] = true;
2167 (*settings)["rejectDupKeys"] = true;
2168 (*settings)["allowSpecialFloats"] = false;
2169 //! [CharReaderBuilderStrictMode]
2170 }
2171 // static
setDefaults(Json::Value * settings)2172 void CharReaderBuilder::setDefaults(Json::Value* settings)
2173 {
2174 //! [CharReaderBuilderDefaults]
2175 (*settings)["collectComments"] = true;
2176 (*settings)["allowComments"] = true;
2177 (*settings)["strictRoot"] = false;
2178 (*settings)["allowDroppedNullPlaceholders"] = false;
2179 (*settings)["allowNumericKeys"] = false;
2180 (*settings)["allowSingleQuotes"] = false;
2181 (*settings)["stackLimit"] = 1000;
2182 (*settings)["failIfExtra"] = false;
2183 (*settings)["rejectDupKeys"] = false;
2184 (*settings)["allowSpecialFloats"] = false;
2185 //! [CharReaderBuilderDefaults]
2186 }
2187
2188 //////////////////////////////////
2189 // global functions
2190
parseFromStream(CharReader::Factory const & fact,std::istream & sin,Value * root,std::string * errs)2191 bool parseFromStream(
2192 CharReader::Factory const& fact, std::istream& sin,
2193 Value* root, std::string* errs)
2194 {
2195 std::ostringstream ssin;
2196 ssin << sin.rdbuf();
2197 std::string doc = ssin.str();
2198 char const* begin = doc.data();
2199 char const* end = begin + doc.size();
2200 // Note that we do not actually need a null-terminator.
2201 CharReaderPtr const reader(fact.newCharReader());
2202 return reader->parse(begin, end, root, errs);
2203 }
2204
operator >>(std::istream & sin,Value & root)2205 std::istream& operator>>(std::istream& sin, Value& root) {
2206 CharReaderBuilder b;
2207 std::string errs;
2208 bool ok = parseFromStream(b, sin, &root, &errs);
2209 if (!ok) {
2210 fprintf(stderr,
2211 "Error from reader: %s",
2212 errs.c_str());
2213
2214 throwRuntimeError(errs);
2215 }
2216 return sin;
2217 }
2218
2219 } // namespace Json
2220
2221 // //////////////////////////////////////////////////////////////////////
2222 // End of content of file: src/lib_json/json_reader.cpp
2223 // //////////////////////////////////////////////////////////////////////
2224
2225
2226
2227
2228
2229
2230 // //////////////////////////////////////////////////////////////////////
2231 // Beginning of content of file: src/lib_json/json_valueiterator.inl
2232 // //////////////////////////////////////////////////////////////////////
2233
2234 // Copyright 2007-2010 Baptiste Lepilleur
2235 // Distributed under MIT license, or public domain if desired and
2236 // recognized in your jurisdiction.
2237 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
2238
2239 // included by json_value.cpp
2240
2241 namespace Json {
2242
2243 // //////////////////////////////////////////////////////////////////
2244 // //////////////////////////////////////////////////////////////////
2245 // //////////////////////////////////////////////////////////////////
2246 // class ValueIteratorBase
2247 // //////////////////////////////////////////////////////////////////
2248 // //////////////////////////////////////////////////////////////////
2249 // //////////////////////////////////////////////////////////////////
2250
ValueIteratorBase()2251 ValueIteratorBase::ValueIteratorBase()
2252 : current_(), isNull_(true) {
2253 }
2254
ValueIteratorBase(const Value::ObjectValues::iterator & current)2255 ValueIteratorBase::ValueIteratorBase(
2256 const Value::ObjectValues::iterator& current)
2257 : current_(current), isNull_(false) {}
2258
deref() const2259 Value& ValueIteratorBase::deref() const {
2260 return current_->second;
2261 }
2262
increment()2263 void ValueIteratorBase::increment() {
2264 ++current_;
2265 }
2266
decrement()2267 void ValueIteratorBase::decrement() {
2268 --current_;
2269 }
2270
2271 ValueIteratorBase::difference_type
computeDistance(const SelfType & other) const2272 ValueIteratorBase::computeDistance(const SelfType& other) const {
2273 #ifdef JSON_USE_CPPTL_SMALLMAP
2274 return other.current_ - current_;
2275 #else
2276 // Iterator for null value are initialized using the default
2277 // constructor, which initialize current_ to the default
2278 // std::map::iterator. As begin() and end() are two instance
2279 // of the default std::map::iterator, they can not be compared.
2280 // To allow this, we handle this comparison specifically.
2281 if (isNull_ && other.isNull_) {
2282 return 0;
2283 }
2284
2285 // Usage of std::distance is not portable (does not compile with Sun Studio 12
2286 // RogueWave STL,
2287 // which is the one used by default).
2288 // Using a portable hand-made version for non random iterator instead:
2289 // return difference_type( std::distance( current_, other.current_ ) );
2290 difference_type myDistance = 0;
2291 for (Value::ObjectValues::iterator it = current_; it != other.current_;
2292 ++it) {
2293 ++myDistance;
2294 }
2295 return myDistance;
2296 #endif
2297 }
2298
isEqual(const SelfType & other) const2299 bool ValueIteratorBase::isEqual(const SelfType& other) const {
2300 if (isNull_) {
2301 return other.isNull_;
2302 }
2303 return current_ == other.current_;
2304 }
2305
copy(const SelfType & other)2306 void ValueIteratorBase::copy(const SelfType& other) {
2307 current_ = other.current_;
2308 isNull_ = other.isNull_;
2309 }
2310
key() const2311 Value ValueIteratorBase::key() const {
2312 const Value::CZString czstring = (*current_).first;
2313 if (czstring.data()) {
2314 if (czstring.isStaticString())
2315 return Value(StaticString(czstring.data()));
2316 return Value(czstring.data(), czstring.data() + czstring.length());
2317 }
2318 return Value(czstring.index());
2319 }
2320
index() const2321 UInt ValueIteratorBase::index() const {
2322 const Value::CZString czstring = (*current_).first;
2323 if (!czstring.data())
2324 return czstring.index();
2325 return Value::UInt(-1);
2326 }
2327
name() const2328 std::string ValueIteratorBase::name() const {
2329 char const* keey;
2330 char const* end;
2331 keey = memberName(&end);
2332 if (!keey) return std::string();
2333 return std::string(keey, end);
2334 }
2335
memberName() const2336 char const* ValueIteratorBase::memberName() const {
2337 const char* cname = (*current_).first.data();
2338 return cname ? cname : "";
2339 }
2340
memberName(char const ** end) const2341 char const* ValueIteratorBase::memberName(char const** end) const {
2342 const char* cname = (*current_).first.data();
2343 if (!cname) {
2344 *end = NULL;
2345 return NULL;
2346 }
2347 *end = cname + (*current_).first.length();
2348 return cname;
2349 }
2350
2351 // //////////////////////////////////////////////////////////////////
2352 // //////////////////////////////////////////////////////////////////
2353 // //////////////////////////////////////////////////////////////////
2354 // class ValueConstIterator
2355 // //////////////////////////////////////////////////////////////////
2356 // //////////////////////////////////////////////////////////////////
2357 // //////////////////////////////////////////////////////////////////
2358
ValueConstIterator()2359 ValueConstIterator::ValueConstIterator() {}
2360
ValueConstIterator(const Value::ObjectValues::iterator & current)2361 ValueConstIterator::ValueConstIterator(
2362 const Value::ObjectValues::iterator& current)
2363 : ValueIteratorBase(current) {}
2364
ValueConstIterator(ValueIterator const & other)2365 ValueConstIterator::ValueConstIterator(ValueIterator const& other)
2366 : ValueIteratorBase(other) {}
2367
2368 ValueConstIterator& ValueConstIterator::
operator =(const ValueIteratorBase & other)2369 operator=(const ValueIteratorBase& other) {
2370 copy(other);
2371 return *this;
2372 }
2373
2374 // //////////////////////////////////////////////////////////////////
2375 // //////////////////////////////////////////////////////////////////
2376 // //////////////////////////////////////////////////////////////////
2377 // class ValueIterator
2378 // //////////////////////////////////////////////////////////////////
2379 // //////////////////////////////////////////////////////////////////
2380 // //////////////////////////////////////////////////////////////////
2381
ValueIterator()2382 ValueIterator::ValueIterator() {}
2383
ValueIterator(const Value::ObjectValues::iterator & current)2384 ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
2385 : ValueIteratorBase(current) {}
2386
ValueIterator(const ValueConstIterator & other)2387 ValueIterator::ValueIterator(const ValueConstIterator& other)
2388 : ValueIteratorBase(other) {
2389 throwRuntimeError("ConstIterator to Iterator should never be allowed.");
2390 }
2391
ValueIterator(const ValueIterator & other)2392 ValueIterator::ValueIterator(const ValueIterator& other)
2393 : ValueIteratorBase(other) {}
2394
operator =(const SelfType & other)2395 ValueIterator& ValueIterator::operator=(const SelfType& other) {
2396 copy(other);
2397 return *this;
2398 }
2399
2400 } // namespace Json
2401
2402 // //////////////////////////////////////////////////////////////////////
2403 // End of content of file: src/lib_json/json_valueiterator.inl
2404 // //////////////////////////////////////////////////////////////////////
2405
2406
2407
2408
2409
2410
2411 // //////////////////////////////////////////////////////////////////////
2412 // Beginning of content of file: src/lib_json/json_value.cpp
2413 // //////////////////////////////////////////////////////////////////////
2414
2415 // Copyright 2011 Baptiste Lepilleur
2416 // Distributed under MIT license, or public domain if desired and
2417 // recognized in your jurisdiction.
2418 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
2419
2420 #if !defined(JSON_IS_AMALGAMATION)
2421 #include <json/assertions.h>
2422 #include <json/value.h>
2423 #include <json/writer.h>
2424 #endif // if !defined(JSON_IS_AMALGAMATION)
2425 #include <math.h>
2426 #include <sstream>
2427 #include <utility>
2428 #include <cstring>
2429 #include <cassert>
2430 #ifdef JSON_USE_CPPTL
2431 #include <cpptl/conststring.h>
2432 #endif
2433 #include <cstddef> // size_t
2434 #include <algorithm> // min()
2435
2436 #define JSON_ASSERT_UNREACHABLE assert(false)
2437
2438 namespace Json {
2439
2440 // This is a walkaround to avoid the static initialization of Value::null.
2441 // kNull must be word-aligned to avoid crashing on ARM. We use an alignment of
2442 // 8 (instead of 4) as a bit of future-proofing.
2443 #if defined(__ARMEL__)
2444 #define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
2445 #else
2446 #define ALIGNAS(byte_alignment)
2447 #endif
2448 static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
2449 const unsigned char& kNullRef = kNull[0];
2450 const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
2451 const Value& Value::nullRef = null;
2452
2453 const Int Value::minInt = Int(~(UInt(-1) / 2));
2454 const Int Value::maxInt = Int(UInt(-1) / 2);
2455 const UInt Value::maxUInt = UInt(-1);
2456 #if defined(JSON_HAS_INT64)
2457 const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2));
2458 const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2);
2459 const UInt64 Value::maxUInt64 = UInt64(-1);
2460 // The constant is hard-coded because some compiler have trouble
2461 // converting Value::maxUInt64 to a double correctly (AIX/xlC).
2462 // Assumes that UInt64 is a 64 bits integer.
2463 static const double maxUInt64AsDouble = 18446744073709551615.0;
2464 #endif // defined(JSON_HAS_INT64)
2465 const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
2466 const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
2467 const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
2468
2469 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2470 template <typename T, typename U>
InRange(double d,T min,U max)2471 static inline bool InRange(double d, T min, U max) {
2472 return d >= min && d <= max;
2473 }
2474 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
integerToDouble(Json::UInt64 value)2475 static inline double integerToDouble(Json::UInt64 value) {
2476 return static_cast<double>(Int64(value / 2)) * 2.0 + Int64(value & 1);
2477 }
2478
integerToDouble(T value)2479 template <typename T> static inline double integerToDouble(T value) {
2480 return static_cast<double>(value);
2481 }
2482
2483 template <typename T, typename U>
InRange(double d,T min,U max)2484 static inline bool InRange(double d, T min, U max) {
2485 return d >= integerToDouble(min) && d <= integerToDouble(max);
2486 }
2487 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2488
2489 /** Duplicates the specified string value.
2490 * @param value Pointer to the string to duplicate. Must be zero-terminated if
2491 * length is "unknown".
2492 * @param length Length of the value. if equals to unknown, then it will be
2493 * computed using strlen(value).
2494 * @return Pointer on the duplicate instance of string.
2495 */
duplicateStringValue(const char * value,size_t length)2496 static inline char* duplicateStringValue(const char* value,
2497 size_t length) {
2498 // Avoid an integer overflow in the call to malloc below by limiting length
2499 // to a sane value.
2500 if (length >= (size_t)Value::maxInt)
2501 length = Value::maxInt - 1;
2502
2503 char* newString = static_cast<char*>(malloc(length + 1));
2504 if (newString == NULL) {
2505 throwRuntimeError(
2506 "in Json::Value::duplicateStringValue(): "
2507 "Failed to allocate string value buffer");
2508 }
2509 memcpy(newString, value, length);
2510 newString[length] = 0;
2511 return newString;
2512 }
2513
2514 /* Record the length as a prefix.
2515 */
duplicateAndPrefixStringValue(const char * value,unsigned int length)2516 static inline char* duplicateAndPrefixStringValue(
2517 const char* value,
2518 unsigned int length)
2519 {
2520 // Avoid an integer overflow in the call to malloc below by limiting length
2521 // to a sane value.
2522 JSON_ASSERT_MESSAGE(length <= (unsigned)Value::maxInt - sizeof(unsigned) - 1U,
2523 "in Json::Value::duplicateAndPrefixStringValue(): "
2524 "length too big for prefixing");
2525 unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U;
2526 char* newString = static_cast<char*>(malloc(actualLength));
2527 if (newString == 0) {
2528 throwRuntimeError(
2529 "in Json::Value::duplicateAndPrefixStringValue(): "
2530 "Failed to allocate string value buffer");
2531 }
2532 *reinterpret_cast<unsigned*>(newString) = length;
2533 memcpy(newString + sizeof(unsigned), value, length);
2534 newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later
2535 return newString;
2536 }
decodePrefixedString(bool isPrefixed,char const * prefixed,unsigned * length,char const ** value)2537 inline static void decodePrefixedString(
2538 bool isPrefixed, char const* prefixed,
2539 unsigned* length, char const** value)
2540 {
2541 if (!isPrefixed) {
2542 *length = static_cast<unsigned>(strlen(prefixed));
2543 *value = prefixed;
2544 } else {
2545 *length = *reinterpret_cast<unsigned const*>(prefixed);
2546 *value = prefixed + sizeof(unsigned);
2547 }
2548 }
2549 /** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue().
2550 */
releaseStringValue(char * value)2551 static inline void releaseStringValue(char* value) { free(value); }
2552
2553 } // namespace Json
2554
2555 // //////////////////////////////////////////////////////////////////
2556 // //////////////////////////////////////////////////////////////////
2557 // //////////////////////////////////////////////////////////////////
2558 // ValueInternals...
2559 // //////////////////////////////////////////////////////////////////
2560 // //////////////////////////////////////////////////////////////////
2561 // //////////////////////////////////////////////////////////////////
2562 #if !defined(JSON_IS_AMALGAMATION)
2563
2564 #include "json_valueiterator.inl"
2565 #endif // if !defined(JSON_IS_AMALGAMATION)
2566
2567 namespace Json {
2568
Exception(std::string const & msg)2569 Exception::Exception(std::string const& msg)
2570 : msg_(msg)
2571 {}
~Exception()2572 Exception::~Exception() throw()
2573 {}
what() const2574 char const* Exception::what() const throw()
2575 {
2576 return msg_.c_str();
2577 }
RuntimeError(std::string const & msg)2578 RuntimeError::RuntimeError(std::string const& msg)
2579 : Exception(msg)
2580 {}
LogicError(std::string const & msg)2581 LogicError::LogicError(std::string const& msg)
2582 : Exception(msg)
2583 {}
throwRuntimeError(std::string const & msg)2584 void throwRuntimeError(std::string const& msg)
2585 {
2586 throw RuntimeError(msg);
2587 }
throwLogicError(std::string const & msg)2588 void throwLogicError(std::string const& msg)
2589 {
2590 throw LogicError(msg);
2591 }
2592
2593 // //////////////////////////////////////////////////////////////////
2594 // //////////////////////////////////////////////////////////////////
2595 // //////////////////////////////////////////////////////////////////
2596 // class Value::CommentInfo
2597 // //////////////////////////////////////////////////////////////////
2598 // //////////////////////////////////////////////////////////////////
2599 // //////////////////////////////////////////////////////////////////
2600
CommentInfo()2601 Value::CommentInfo::CommentInfo() : comment_(0) {}
2602
~CommentInfo()2603 Value::CommentInfo::~CommentInfo() {
2604 if (comment_)
2605 releaseStringValue(comment_);
2606 }
2607
setComment(const char * text,size_t len)2608 void Value::CommentInfo::setComment(const char* text, size_t len) {
2609 if (comment_) {
2610 releaseStringValue(comment_);
2611 comment_ = 0;
2612 }
2613 JSON_ASSERT(text != 0);
2614 JSON_ASSERT_MESSAGE(
2615 text[0] == '\0' || text[0] == '/',
2616 "in Json::Value::setComment(): Comments must start with /");
2617 // It seems that /**/ style comments are acceptable as well.
2618 comment_ = duplicateStringValue(text, len);
2619 }
2620
2621 // //////////////////////////////////////////////////////////////////
2622 // //////////////////////////////////////////////////////////////////
2623 // //////////////////////////////////////////////////////////////////
2624 // class Value::CZString
2625 // //////////////////////////////////////////////////////////////////
2626 // //////////////////////////////////////////////////////////////////
2627 // //////////////////////////////////////////////////////////////////
2628
2629 // Notes: policy_ indicates if the string was allocated when
2630 // a string is stored.
2631
CZString(ArrayIndex aindex)2632 Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {}
2633
CZString(char const * str,unsigned ulength,DuplicationPolicy allocate)2634 Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate)
2635 : cstr_(str) {
2636 // allocate != duplicate
2637 storage_.policy_ = allocate & 0x3;
2638 storage_.length_ = ulength & 0x3FFFFFFF;
2639 }
2640
CZString(const CZString & other)2641 Value::CZString::CZString(const CZString& other)
2642 : cstr_(other.storage_.policy_ != noDuplication && other.cstr_ != 0
2643 ? duplicateStringValue(other.cstr_, other.storage_.length_)
2644 : other.cstr_) {
2645 storage_.policy_ = (other.cstr_
2646 ? (static_cast<DuplicationPolicy>(other.storage_.policy_) == noDuplication
2647 ? noDuplication : duplicate)
2648 : static_cast<DuplicationPolicy>(other.storage_.policy_));
2649 storage_.length_ = other.storage_.length_;
2650 }
2651
2652 #if JSON_HAS_RVALUE_REFERENCES
CZString(CZString && other)2653 Value::CZString::CZString(CZString&& other)
2654 : cstr_(other.cstr_), index_(other.index_) {
2655 other.cstr_ = nullptr;
2656 }
2657 #endif
2658
~CZString()2659 Value::CZString::~CZString() {
2660 if (cstr_ && storage_.policy_ == duplicate)
2661 releaseStringValue(const_cast<char*>(cstr_));
2662 }
2663
swap(CZString & other)2664 void Value::CZString::swap(CZString& other) {
2665 std::swap(cstr_, other.cstr_);
2666 std::swap(index_, other.index_);
2667 }
2668
operator =(CZString other)2669 Value::CZString& Value::CZString::operator=(CZString other) {
2670 swap(other);
2671 return *this;
2672 }
2673
operator <(const CZString & other) const2674 bool Value::CZString::operator<(const CZString& other) const {
2675 if (!cstr_) return index_ < other.index_;
2676 //return strcmp(cstr_, other.cstr_) < 0;
2677 // Assume both are strings.
2678 unsigned this_len = this->storage_.length_;
2679 unsigned other_len = other.storage_.length_;
2680 unsigned min_len = std::min(this_len, other_len);
2681 int comp = memcmp(this->cstr_, other.cstr_, min_len);
2682 if (comp < 0) return true;
2683 if (comp > 0) return false;
2684 return (this_len < other_len);
2685 }
2686
operator ==(const CZString & other) const2687 bool Value::CZString::operator==(const CZString& other) const {
2688 if (!cstr_) return index_ == other.index_;
2689 //return strcmp(cstr_, other.cstr_) == 0;
2690 // Assume both are strings.
2691 unsigned this_len = this->storage_.length_;
2692 unsigned other_len = other.storage_.length_;
2693 if (this_len != other_len) return false;
2694 int comp = memcmp(this->cstr_, other.cstr_, this_len);
2695 return comp == 0;
2696 }
2697
index() const2698 ArrayIndex Value::CZString::index() const { return index_; }
2699
2700 //const char* Value::CZString::c_str() const { return cstr_; }
data() const2701 const char* Value::CZString::data() const { return cstr_; }
length() const2702 unsigned Value::CZString::length() const { return storage_.length_; }
isStaticString() const2703 bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; }
2704
2705 // //////////////////////////////////////////////////////////////////
2706 // //////////////////////////////////////////////////////////////////
2707 // //////////////////////////////////////////////////////////////////
2708 // class Value::Value
2709 // //////////////////////////////////////////////////////////////////
2710 // //////////////////////////////////////////////////////////////////
2711 // //////////////////////////////////////////////////////////////////
2712
2713 /*! \internal Default constructor initialization must be equivalent to:
2714 * memset( this, 0, sizeof(Value) )
2715 * This optimization is used in ValueInternalMap fast allocator.
2716 */
Value(ValueType vtype)2717 Value::Value(ValueType vtype) {
2718 initBasic(vtype);
2719 switch (vtype) {
2720 case nullValue:
2721 break;
2722 case intValue:
2723 case uintValue:
2724 value_.int_ = 0;
2725 break;
2726 case realValue:
2727 value_.real_ = 0.0;
2728 break;
2729 case stringValue:
2730 value_.string_ = 0;
2731 break;
2732 case arrayValue:
2733 case objectValue:
2734 value_.map_ = new ObjectValues();
2735 break;
2736 case booleanValue:
2737 value_.bool_ = false;
2738 break;
2739 default:
2740 JSON_ASSERT_UNREACHABLE;
2741 }
2742 }
2743
Value(Int value)2744 Value::Value(Int value) {
2745 initBasic(intValue);
2746 value_.int_ = value;
2747 }
2748
Value(UInt value)2749 Value::Value(UInt value) {
2750 initBasic(uintValue);
2751 value_.uint_ = value;
2752 }
2753 #if defined(JSON_HAS_INT64)
Value(Int64 value)2754 Value::Value(Int64 value) {
2755 initBasic(intValue);
2756 value_.int_ = value;
2757 }
Value(UInt64 value)2758 Value::Value(UInt64 value) {
2759 initBasic(uintValue);
2760 value_.uint_ = value;
2761 }
2762 #endif // defined(JSON_HAS_INT64)
2763
Value(double value)2764 Value::Value(double value) {
2765 initBasic(realValue);
2766 value_.real_ = value;
2767 }
2768
Value(const char * value)2769 Value::Value(const char* value) {
2770 initBasic(stringValue, true);
2771 value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value)));
2772 }
2773
Value(const char * beginValue,const char * endValue)2774 Value::Value(const char* beginValue, const char* endValue) {
2775 initBasic(stringValue, true);
2776 value_.string_ =
2777 duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue));
2778 }
2779
Value(const std::string & value)2780 Value::Value(const std::string& value) {
2781 initBasic(stringValue, true);
2782 value_.string_ =
2783 duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length()));
2784 }
2785
Value(const StaticString & value)2786 Value::Value(const StaticString& value) {
2787 initBasic(stringValue);
2788 value_.string_ = const_cast<char*>(value.c_str());
2789 }
2790
2791 #ifdef JSON_USE_CPPTL
Value(const CppTL::ConstString & value)2792 Value::Value(const CppTL::ConstString& value) {
2793 initBasic(stringValue, true);
2794 value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length()));
2795 }
2796 #endif
2797
Value(bool value)2798 Value::Value(bool value) {
2799 initBasic(booleanValue);
2800 value_.bool_ = value;
2801 }
2802
Value(Value const & other)2803 Value::Value(Value const& other)
2804 : type_(other.type_), allocated_(false)
2805 ,
2806 comments_(0), start_(other.start_), limit_(other.limit_)
2807 {
2808 switch (type_) {
2809 case nullValue:
2810 case intValue:
2811 case uintValue:
2812 case realValue:
2813 case booleanValue:
2814 value_ = other.value_;
2815 break;
2816 case stringValue:
2817 if (other.value_.string_ && other.allocated_) {
2818 unsigned len;
2819 char const* str;
2820 decodePrefixedString(other.allocated_, other.value_.string_,
2821 &len, &str);
2822 value_.string_ = duplicateAndPrefixStringValue(str, len);
2823 allocated_ = true;
2824 } else {
2825 value_.string_ = other.value_.string_;
2826 allocated_ = false;
2827 }
2828 break;
2829 case arrayValue:
2830 case objectValue:
2831 value_.map_ = new ObjectValues(*other.value_.map_);
2832 break;
2833 default:
2834 JSON_ASSERT_UNREACHABLE;
2835 }
2836 if (other.comments_) {
2837 comments_ = new CommentInfo[numberOfCommentPlacement];
2838 for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {
2839 const CommentInfo& otherComment = other.comments_[comment];
2840 if (otherComment.comment_)
2841 comments_[comment].setComment(
2842 otherComment.comment_, strlen(otherComment.comment_));
2843 }
2844 }
2845 }
2846
2847 #if JSON_HAS_RVALUE_REFERENCES
2848 // Move constructor
Value(Value && other)2849 Value::Value(Value&& other) {
2850 initBasic(nullValue);
2851 swap(other);
2852 }
2853 #endif
2854
~Value()2855 Value::~Value() {
2856 switch (type_) {
2857 case nullValue:
2858 case intValue:
2859 case uintValue:
2860 case realValue:
2861 case booleanValue:
2862 break;
2863 case stringValue:
2864 if (allocated_)
2865 releaseStringValue(value_.string_);
2866 break;
2867 case arrayValue:
2868 case objectValue:
2869 delete value_.map_;
2870 break;
2871 default:
2872 JSON_ASSERT_UNREACHABLE;
2873 }
2874
2875 if (comments_)
2876 delete[] comments_;
2877 }
2878
operator =(Value other)2879 Value& Value::operator=(Value other) {
2880 swap(other);
2881 return *this;
2882 }
2883
swapPayload(Value & other)2884 void Value::swapPayload(Value& other) {
2885 ValueType temp = type_;
2886 type_ = other.type_;
2887 other.type_ = temp;
2888 std::swap(value_, other.value_);
2889 int temp2 = allocated_;
2890 allocated_ = other.allocated_;
2891 other.allocated_ = temp2 & 0x1;
2892 }
2893
swap(Value & other)2894 void Value::swap(Value& other) {
2895 swapPayload(other);
2896 std::swap(comments_, other.comments_);
2897 std::swap(start_, other.start_);
2898 std::swap(limit_, other.limit_);
2899 }
2900
type() const2901 ValueType Value::type() const { return type_; }
2902
compare(const Value & other) const2903 int Value::compare(const Value& other) const {
2904 if (*this < other)
2905 return -1;
2906 if (*this > other)
2907 return 1;
2908 return 0;
2909 }
2910
operator <(const Value & other) const2911 bool Value::operator<(const Value& other) const {
2912 int typeDelta = type_ - other.type_;
2913 if (typeDelta)
2914 return typeDelta < 0 ? true : false;
2915 switch (type_) {
2916 case nullValue:
2917 return false;
2918 case intValue:
2919 return value_.int_ < other.value_.int_;
2920 case uintValue:
2921 return value_.uint_ < other.value_.uint_;
2922 case realValue:
2923 return value_.real_ < other.value_.real_;
2924 case booleanValue:
2925 return value_.bool_ < other.value_.bool_;
2926 case stringValue:
2927 {
2928 if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
2929 if (other.value_.string_) return true;
2930 else return false;
2931 }
2932 unsigned this_len;
2933 unsigned other_len;
2934 char const* this_str;
2935 char const* other_str;
2936 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
2937 decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
2938 unsigned min_len = std::min(this_len, other_len);
2939 int comp = memcmp(this_str, other_str, min_len);
2940 if (comp < 0) return true;
2941 if (comp > 0) return false;
2942 return (this_len < other_len);
2943 }
2944 case arrayValue:
2945 case objectValue: {
2946 int delta = int(value_.map_->size() - other.value_.map_->size());
2947 if (delta)
2948 return delta < 0;
2949 return (*value_.map_) < (*other.value_.map_);
2950 }
2951 default:
2952 JSON_ASSERT_UNREACHABLE;
2953 }
2954 return false; // unreachable
2955 }
2956
operator <=(const Value & other) const2957 bool Value::operator<=(const Value& other) const { return !(other < *this); }
2958
operator >=(const Value & other) const2959 bool Value::operator>=(const Value& other) const { return !(*this < other); }
2960
operator >(const Value & other) const2961 bool Value::operator>(const Value& other) const { return other < *this; }
2962
operator ==(const Value & other) const2963 bool Value::operator==(const Value& other) const {
2964 // if ( type_ != other.type_ )
2965 // GCC 2.95.3 says:
2966 // attempt to take address of bit-field structure member `Json::Value::type_'
2967 // Beats me, but a temp solves the problem.
2968 int temp = other.type_;
2969 if (type_ != temp)
2970 return false;
2971 switch (type_) {
2972 case nullValue:
2973 return true;
2974 case intValue:
2975 return value_.int_ == other.value_.int_;
2976 case uintValue:
2977 return value_.uint_ == other.value_.uint_;
2978 case realValue:
2979 return value_.real_ == other.value_.real_;
2980 case booleanValue:
2981 return value_.bool_ == other.value_.bool_;
2982 case stringValue:
2983 {
2984 if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
2985 return (value_.string_ == other.value_.string_);
2986 }
2987 unsigned this_len;
2988 unsigned other_len;
2989 char const* this_str;
2990 char const* other_str;
2991 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
2992 decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
2993 if (this_len != other_len) return false;
2994 int comp = memcmp(this_str, other_str, this_len);
2995 return comp == 0;
2996 }
2997 case arrayValue:
2998 case objectValue:
2999 return value_.map_->size() == other.value_.map_->size() &&
3000 (*value_.map_) == (*other.value_.map_);
3001 default:
3002 JSON_ASSERT_UNREACHABLE;
3003 }
3004 return false; // unreachable
3005 }
3006
operator !=(const Value & other) const3007 bool Value::operator!=(const Value& other) const { return !(*this == other); }
3008
asCString() const3009 const char* Value::asCString() const {
3010 JSON_ASSERT_MESSAGE(type_ == stringValue,
3011 "in Json::Value::asCString(): requires stringValue");
3012 if (value_.string_ == 0) return 0;
3013 unsigned this_len;
3014 char const* this_str;
3015 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
3016 return this_str;
3017 }
3018
getString(char const ** str,char const ** cend) const3019 bool Value::getString(char const** str, char const** cend) const {
3020 if (type_ != stringValue) return false;
3021 if (value_.string_ == 0) return false;
3022 unsigned length;
3023 decodePrefixedString(this->allocated_, this->value_.string_, &length, str);
3024 *cend = *str + length;
3025 return true;
3026 }
3027
asString() const3028 std::string Value::asString() const {
3029 switch (type_) {
3030 case nullValue:
3031 return "";
3032 case stringValue:
3033 {
3034 if (value_.string_ == 0) return "";
3035 unsigned this_len;
3036 char const* this_str;
3037 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
3038 return std::string(this_str, this_len);
3039 }
3040 case booleanValue:
3041 return value_.bool_ ? "true" : "false";
3042 case intValue:
3043 return valueToString(value_.int_);
3044 case uintValue:
3045 return valueToString(value_.uint_);
3046 case realValue:
3047 return valueToString(value_.real_);
3048 default:
3049 JSON_FAIL_MESSAGE("Type is not convertible to string");
3050 }
3051 }
3052
3053 #ifdef JSON_USE_CPPTL
asConstString() const3054 CppTL::ConstString Value::asConstString() const {
3055 unsigned len;
3056 char const* str;
3057 decodePrefixedString(allocated_, value_.string_,
3058 &len, &str);
3059 return CppTL::ConstString(str, len);
3060 }
3061 #endif
3062
asInt() const3063 Value::Int Value::asInt() const {
3064 switch (type_) {
3065 case intValue:
3066 JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
3067 return Int(value_.int_);
3068 case uintValue:
3069 JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
3070 return Int(value_.uint_);
3071 case realValue:
3072 JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
3073 "double out of Int range");
3074 return Int(value_.real_);
3075 case nullValue:
3076 return 0;
3077 case booleanValue:
3078 return value_.bool_ ? 1 : 0;
3079 default:
3080 break;
3081 }
3082 JSON_FAIL_MESSAGE("Value is not convertible to Int.");
3083 }
3084
asUInt() const3085 Value::UInt Value::asUInt() const {
3086 switch (type_) {
3087 case intValue:
3088 JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
3089 return UInt(value_.int_);
3090 case uintValue:
3091 JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
3092 return UInt(value_.uint_);
3093 case realValue:
3094 JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
3095 "double out of UInt range");
3096 return UInt(value_.real_);
3097 case nullValue:
3098 return 0;
3099 case booleanValue:
3100 return value_.bool_ ? 1 : 0;
3101 default:
3102 break;
3103 }
3104 JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
3105 }
3106
3107 #if defined(JSON_HAS_INT64)
3108
asInt64() const3109 Value::Int64 Value::asInt64() const {
3110 switch (type_) {
3111 case intValue:
3112 return Int64(value_.int_);
3113 case uintValue:
3114 JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
3115 return Int64(value_.uint_);
3116 case realValue:
3117 JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
3118 "double out of Int64 range");
3119 return Int64(value_.real_);
3120 case nullValue:
3121 return 0;
3122 case booleanValue:
3123 return value_.bool_ ? 1 : 0;
3124 default:
3125 break;
3126 }
3127 JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
3128 }
3129
asUInt64() const3130 Value::UInt64 Value::asUInt64() const {
3131 switch (type_) {
3132 case intValue:
3133 JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
3134 return UInt64(value_.int_);
3135 case uintValue:
3136 return UInt64(value_.uint_);
3137 case realValue:
3138 JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
3139 "double out of UInt64 range");
3140 return UInt64(value_.real_);
3141 case nullValue:
3142 return 0;
3143 case booleanValue:
3144 return value_.bool_ ? 1 : 0;
3145 default:
3146 break;
3147 }
3148 JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
3149 }
3150 #endif // if defined(JSON_HAS_INT64)
3151
asLargestInt() const3152 LargestInt Value::asLargestInt() const {
3153 #if defined(JSON_NO_INT64)
3154 return asInt();
3155 #else
3156 return asInt64();
3157 #endif
3158 }
3159
asLargestUInt() const3160 LargestUInt Value::asLargestUInt() const {
3161 #if defined(JSON_NO_INT64)
3162 return asUInt();
3163 #else
3164 return asUInt64();
3165 #endif
3166 }
3167
asDouble() const3168 double Value::asDouble() const {
3169 switch (type_) {
3170 case intValue:
3171 return static_cast<double>(value_.int_);
3172 case uintValue:
3173 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3174 return static_cast<double>(value_.uint_);
3175 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3176 return integerToDouble(value_.uint_);
3177 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3178 case realValue:
3179 return value_.real_;
3180 case nullValue:
3181 return 0.0;
3182 case booleanValue:
3183 return value_.bool_ ? 1.0 : 0.0;
3184 default:
3185 break;
3186 }
3187 JSON_FAIL_MESSAGE("Value is not convertible to double.");
3188 }
3189
asFloat() const3190 float Value::asFloat() const {
3191 switch (type_) {
3192 case intValue:
3193 return static_cast<float>(value_.int_);
3194 case uintValue:
3195 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3196 return static_cast<float>(value_.uint_);
3197 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3198 return integerToDouble(value_.uint_);
3199 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3200 case realValue:
3201 return static_cast<float>(value_.real_);
3202 case nullValue:
3203 return 0.0;
3204 case booleanValue:
3205 return value_.bool_ ? 1.0f : 0.0f;
3206 default:
3207 break;
3208 }
3209 JSON_FAIL_MESSAGE("Value is not convertible to float.");
3210 }
3211
asBool() const3212 bool Value::asBool() const {
3213 switch (type_) {
3214 case booleanValue:
3215 return value_.bool_;
3216 case nullValue:
3217 return false;
3218 case intValue:
3219 return value_.int_ ? true : false;
3220 case uintValue:
3221 return value_.uint_ ? true : false;
3222 case realValue:
3223 // This is kind of strange. Not recommended.
3224 return (value_.real_ != 0.0) ? true : false;
3225 default:
3226 break;
3227 }
3228 JSON_FAIL_MESSAGE("Value is not convertible to bool.");
3229 }
3230
isConvertibleTo(ValueType other) const3231 bool Value::isConvertibleTo(ValueType other) const {
3232 switch (other) {
3233 case nullValue:
3234 return (isNumeric() && asDouble() == 0.0) ||
3235 (type_ == booleanValue && value_.bool_ == false) ||
3236 (type_ == stringValue && asString() == "") ||
3237 (type_ == arrayValue && value_.map_->size() == 0) ||
3238 (type_ == objectValue && value_.map_->size() == 0) ||
3239 type_ == nullValue;
3240 case intValue:
3241 return isInt() ||
3242 (type_ == realValue && InRange(value_.real_, minInt, maxInt)) ||
3243 type_ == booleanValue || type_ == nullValue;
3244 case uintValue:
3245 return isUInt() ||
3246 (type_ == realValue && InRange(value_.real_, 0, maxUInt)) ||
3247 type_ == booleanValue || type_ == nullValue;
3248 case realValue:
3249 return isNumeric() || type_ == booleanValue || type_ == nullValue;
3250 case booleanValue:
3251 return isNumeric() || type_ == booleanValue || type_ == nullValue;
3252 case stringValue:
3253 return isNumeric() || type_ == booleanValue || type_ == stringValue ||
3254 type_ == nullValue;
3255 case arrayValue:
3256 return type_ == arrayValue || type_ == nullValue;
3257 case objectValue:
3258 return type_ == objectValue || type_ == nullValue;
3259 }
3260 JSON_ASSERT_UNREACHABLE;
3261 return false;
3262 }
3263
3264 /// Number of values in array or object
size() const3265 ArrayIndex Value::size() const {
3266 switch (type_) {
3267 case nullValue:
3268 case intValue:
3269 case uintValue:
3270 case realValue:
3271 case booleanValue:
3272 case stringValue:
3273 return 0;
3274 case arrayValue: // size of the array is highest index + 1
3275 if (!value_.map_->empty()) {
3276 ObjectValues::const_iterator itLast = value_.map_->end();
3277 --itLast;
3278 return (*itLast).first.index() + 1;
3279 }
3280 return 0;
3281 case objectValue:
3282 return ArrayIndex(value_.map_->size());
3283 }
3284 JSON_ASSERT_UNREACHABLE;
3285 return 0; // unreachable;
3286 }
3287
empty() const3288 bool Value::empty() const {
3289 if (isNull() || isArray() || isObject())
3290 return size() == 0u;
3291 else
3292 return false;
3293 }
3294
operator !() const3295 bool Value::operator!() const { return isNull(); }
3296
clear()3297 void Value::clear() {
3298 JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue ||
3299 type_ == objectValue,
3300 "in Json::Value::clear(): requires complex value");
3301 start_ = 0;
3302 limit_ = 0;
3303 switch (type_) {
3304 case arrayValue:
3305 case objectValue:
3306 value_.map_->clear();
3307 break;
3308 default:
3309 break;
3310 }
3311 }
3312
resize(ArrayIndex newSize)3313 void Value::resize(ArrayIndex newSize) {
3314 JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,
3315 "in Json::Value::resize(): requires arrayValue");
3316 if (type_ == nullValue)
3317 *this = Value(arrayValue);
3318 ArrayIndex oldSize = size();
3319 if (newSize == 0)
3320 clear();
3321 else if (newSize > oldSize)
3322 (*this)[newSize - 1];
3323 else {
3324 for (ArrayIndex index = newSize; index < oldSize; ++index) {
3325 value_.map_->erase(index);
3326 }
3327 assert(size() == newSize);
3328 }
3329 }
3330
operator [](ArrayIndex index)3331 Value& Value::operator[](ArrayIndex index) {
3332 JSON_ASSERT_MESSAGE(
3333 type_ == nullValue || type_ == arrayValue,
3334 "in Json::Value::operator[](ArrayIndex): requires arrayValue");
3335 if (type_ == nullValue)
3336 *this = Value(arrayValue);
3337 CZString key(index);
3338 ObjectValues::iterator it = value_.map_->lower_bound(key);
3339 if (it != value_.map_->end() && (*it).first == key)
3340 return (*it).second;
3341
3342 ObjectValues::value_type defaultValue(key, nullRef);
3343 it = value_.map_->insert(it, defaultValue);
3344 return (*it).second;
3345 }
3346
operator [](int index)3347 Value& Value::operator[](int index) {
3348 JSON_ASSERT_MESSAGE(
3349 index >= 0,
3350 "in Json::Value::operator[](int index): index cannot be negative");
3351 return (*this)[ArrayIndex(index)];
3352 }
3353
operator [](ArrayIndex index) const3354 const Value& Value::operator[](ArrayIndex index) const {
3355 JSON_ASSERT_MESSAGE(
3356 type_ == nullValue || type_ == arrayValue,
3357 "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
3358 if (type_ == nullValue)
3359 return nullRef;
3360 CZString key(index);
3361 ObjectValues::const_iterator it = value_.map_->find(key);
3362 if (it == value_.map_->end())
3363 return nullRef;
3364 return (*it).second;
3365 }
3366
operator [](int index) const3367 const Value& Value::operator[](int index) const {
3368 JSON_ASSERT_MESSAGE(
3369 index >= 0,
3370 "in Json::Value::operator[](int index) const: index cannot be negative");
3371 return (*this)[ArrayIndex(index)];
3372 }
3373
initBasic(ValueType vtype,bool allocated)3374 void Value::initBasic(ValueType vtype, bool allocated) {
3375 type_ = vtype;
3376 allocated_ = allocated;
3377 comments_ = 0;
3378 start_ = 0;
3379 limit_ = 0;
3380 }
3381
3382 // Access an object value by name, create a null member if it does not exist.
3383 // @pre Type of '*this' is object or null.
3384 // @param key is null-terminated.
resolveReference(const char * key)3385 Value& Value::resolveReference(const char* key) {
3386 JSON_ASSERT_MESSAGE(
3387 type_ == nullValue || type_ == objectValue,
3388 "in Json::Value::resolveReference(): requires objectValue");
3389 if (type_ == nullValue)
3390 *this = Value(objectValue);
3391 CZString actualKey(
3392 key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE!
3393 ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
3394 if (it != value_.map_->end() && (*it).first == actualKey)
3395 return (*it).second;
3396
3397 ObjectValues::value_type defaultValue(actualKey, nullRef);
3398 it = value_.map_->insert(it, defaultValue);
3399 Value& value = (*it).second;
3400 return value;
3401 }
3402
3403 // @param key is not null-terminated.
resolveReference(char const * key,char const * cend)3404 Value& Value::resolveReference(char const* key, char const* cend)
3405 {
3406 JSON_ASSERT_MESSAGE(
3407 type_ == nullValue || type_ == objectValue,
3408 "in Json::Value::resolveReference(key, end): requires objectValue");
3409 if (type_ == nullValue)
3410 *this = Value(objectValue);
3411 CZString actualKey(
3412 key, static_cast<unsigned>(cend-key), CZString::duplicateOnCopy);
3413 ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
3414 if (it != value_.map_->end() && (*it).first == actualKey)
3415 return (*it).second;
3416
3417 ObjectValues::value_type defaultValue(actualKey, nullRef);
3418 it = value_.map_->insert(it, defaultValue);
3419 Value& value = (*it).second;
3420 return value;
3421 }
3422
get(ArrayIndex index,const Value & defaultValue) const3423 Value Value::get(ArrayIndex index, const Value& defaultValue) const {
3424 const Value* value = &((*this)[index]);
3425 return value == &nullRef ? defaultValue : *value;
3426 }
3427
isValidIndex(ArrayIndex index) const3428 bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
3429
find(char const * key,char const * cend) const3430 Value const* Value::find(char const* key, char const* cend) const
3431 {
3432 JSON_ASSERT_MESSAGE(
3433 type_ == nullValue || type_ == objectValue,
3434 "in Json::Value::find(key, end, found): requires objectValue or nullValue");
3435 if (type_ == nullValue) return NULL;
3436 CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
3437 ObjectValues::const_iterator it = value_.map_->find(actualKey);
3438 if (it == value_.map_->end()) return NULL;
3439 return &(*it).second;
3440 }
operator [](const char * key) const3441 const Value& Value::operator[](const char* key) const
3442 {
3443 Value const* found = find(key, key + strlen(key));
3444 if (!found) return nullRef;
3445 return *found;
3446 }
operator [](std::string const & key) const3447 Value const& Value::operator[](std::string const& key) const
3448 {
3449 Value const* found = find(key.data(), key.data() + key.length());
3450 if (!found) return nullRef;
3451 return *found;
3452 }
3453
operator [](const char * key)3454 Value& Value::operator[](const char* key) {
3455 return resolveReference(key, key + strlen(key));
3456 }
3457
operator [](const std::string & key)3458 Value& Value::operator[](const std::string& key) {
3459 return resolveReference(key.data(), key.data() + key.length());
3460 }
3461
operator [](const StaticString & key)3462 Value& Value::operator[](const StaticString& key) {
3463 return resolveReference(key.c_str());
3464 }
3465
3466 #ifdef JSON_USE_CPPTL
operator [](const CppTL::ConstString & key)3467 Value& Value::operator[](const CppTL::ConstString& key) {
3468 return resolveReference(key.c_str(), key.end_c_str());
3469 }
operator [](CppTL::ConstString const & key) const3470 Value const& Value::operator[](CppTL::ConstString const& key) const
3471 {
3472 Value const* found = find(key.c_str(), key.end_c_str());
3473 if (!found) return nullRef;
3474 return *found;
3475 }
3476 #endif
3477
append(const Value & value)3478 Value& Value::append(const Value& value) { return (*this)[size()] = value; }
3479
get(char const * key,char const * cend,Value const & defaultValue) const3480 Value Value::get(char const* key, char const* cend, Value const& defaultValue) const
3481 {
3482 Value const* found = find(key, cend);
3483 return !found ? defaultValue : *found;
3484 }
get(char const * key,Value const & defaultValue) const3485 Value Value::get(char const* key, Value const& defaultValue) const
3486 {
3487 return get(key, key + strlen(key), defaultValue);
3488 }
get(std::string const & key,Value const & defaultValue) const3489 Value Value::get(std::string const& key, Value const& defaultValue) const
3490 {
3491 return get(key.data(), key.data() + key.length(), defaultValue);
3492 }
3493
3494
removeMember(const char * key,const char * cend,Value * removed)3495 bool Value::removeMember(const char* key, const char* cend, Value* removed)
3496 {
3497 if (type_ != objectValue) {
3498 return false;
3499 }
3500 CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
3501 ObjectValues::iterator it = value_.map_->find(actualKey);
3502 if (it == value_.map_->end())
3503 return false;
3504 *removed = it->second;
3505 value_.map_->erase(it);
3506 return true;
3507 }
removeMember(const char * key,Value * removed)3508 bool Value::removeMember(const char* key, Value* removed)
3509 {
3510 return removeMember(key, key + strlen(key), removed);
3511 }
removeMember(std::string const & key,Value * removed)3512 bool Value::removeMember(std::string const& key, Value* removed)
3513 {
3514 return removeMember(key.data(), key.data() + key.length(), removed);
3515 }
removeMember(const char * key)3516 Value Value::removeMember(const char* key)
3517 {
3518 JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
3519 "in Json::Value::removeMember(): requires objectValue");
3520 if (type_ == nullValue)
3521 return nullRef;
3522
3523 Value removed; // null
3524 removeMember(key, key + strlen(key), &removed);
3525 return removed; // still null if removeMember() did nothing
3526 }
removeMember(const std::string & key)3527 Value Value::removeMember(const std::string& key)
3528 {
3529 return removeMember(key.c_str());
3530 }
3531
removeIndex(ArrayIndex index,Value * removed)3532 bool Value::removeIndex(ArrayIndex index, Value* removed) {
3533 if (type_ != arrayValue) {
3534 return false;
3535 }
3536 CZString key(index);
3537 ObjectValues::iterator it = value_.map_->find(key);
3538 if (it == value_.map_->end()) {
3539 return false;
3540 }
3541 *removed = it->second;
3542 ArrayIndex oldSize = size();
3543 // shift left all items left, into the place of the "removed"
3544 for (ArrayIndex i = index; i < (oldSize - 1); ++i){
3545 CZString keey(i);
3546 (*value_.map_)[keey] = (*this)[i + 1];
3547 }
3548 // erase the last one ("leftover")
3549 CZString keyLast(oldSize - 1);
3550 ObjectValues::iterator itLast = value_.map_->find(keyLast);
3551 value_.map_->erase(itLast);
3552 return true;
3553 }
3554
3555 #ifdef JSON_USE_CPPTL
get(const CppTL::ConstString & key,const Value & defaultValue) const3556 Value Value::get(const CppTL::ConstString& key,
3557 const Value& defaultValue) const {
3558 return get(key.c_str(), key.end_c_str(), defaultValue);
3559 }
3560 #endif
3561
isMember(char const * key,char const * cend) const3562 bool Value::isMember(char const* key, char const* cend) const
3563 {
3564 Value const* value = find(key, cend);
3565 return NULL != value;
3566 }
isMember(char const * key) const3567 bool Value::isMember(char const* key) const
3568 {
3569 return isMember(key, key + strlen(key));
3570 }
isMember(std::string const & key) const3571 bool Value::isMember(std::string const& key) const
3572 {
3573 return isMember(key.data(), key.data() + key.length());
3574 }
3575
3576 #ifdef JSON_USE_CPPTL
isMember(const CppTL::ConstString & key) const3577 bool Value::isMember(const CppTL::ConstString& key) const {
3578 return isMember(key.c_str(), key.end_c_str());
3579 }
3580 #endif
3581
getMemberNames() const3582 Value::Members Value::getMemberNames() const {
3583 JSON_ASSERT_MESSAGE(
3584 type_ == nullValue || type_ == objectValue,
3585 "in Json::Value::getMemberNames(), value must be objectValue");
3586 if (type_ == nullValue)
3587 return Value::Members();
3588 Members members;
3589 members.reserve(value_.map_->size());
3590 ObjectValues::const_iterator it = value_.map_->begin();
3591 ObjectValues::const_iterator itEnd = value_.map_->end();
3592 for (; it != itEnd; ++it) {
3593 members.push_back(std::string((*it).first.data(),
3594 (*it).first.length()));
3595 }
3596 return members;
3597 }
3598 //
3599 //# ifdef JSON_USE_CPPTL
3600 // EnumMemberNames
3601 // Value::enumMemberNames() const
3602 //{
3603 // if ( type_ == objectValue )
3604 // {
3605 // return CppTL::Enum::any( CppTL::Enum::transform(
3606 // CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
3607 // MemberNamesTransform() ) );
3608 // }
3609 // return EnumMemberNames();
3610 //}
3611 //
3612 //
3613 // EnumValues
3614 // Value::enumValues() const
3615 //{
3616 // if ( type_ == objectValue || type_ == arrayValue )
3617 // return CppTL::Enum::anyValues( *(value_.map_),
3618 // CppTL::Type<const Value &>() );
3619 // return EnumValues();
3620 //}
3621 //
3622 //# endif
3623
IsIntegral(double d)3624 static bool IsIntegral(double d) {
3625 double integral_part;
3626 return modf(d, &integral_part) == 0.0;
3627 }
3628
isNull() const3629 bool Value::isNull() const { return type_ == nullValue; }
3630
isBool() const3631 bool Value::isBool() const { return type_ == booleanValue; }
3632
isInt() const3633 bool Value::isInt() const {
3634 switch (type_) {
3635 case intValue:
3636 return value_.int_ >= minInt && value_.int_ <= maxInt;
3637 case uintValue:
3638 return value_.uint_ <= UInt(maxInt);
3639 case realValue:
3640 return value_.real_ >= minInt && value_.real_ <= maxInt &&
3641 IsIntegral(value_.real_);
3642 default:
3643 break;
3644 }
3645 return false;
3646 }
3647
isUInt() const3648 bool Value::isUInt() const {
3649 switch (type_) {
3650 case intValue:
3651 return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
3652 case uintValue:
3653 return value_.uint_ <= maxUInt;
3654 case realValue:
3655 return value_.real_ >= 0 && value_.real_ <= maxUInt &&
3656 IsIntegral(value_.real_);
3657 default:
3658 break;
3659 }
3660 return false;
3661 }
3662
isInt64() const3663 bool Value::isInt64() const {
3664 #if defined(JSON_HAS_INT64)
3665 switch (type_) {
3666 case intValue:
3667 return true;
3668 case uintValue:
3669 return value_.uint_ <= UInt64(maxInt64);
3670 case realValue:
3671 // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
3672 // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
3673 // require the value to be strictly less than the limit.
3674 return value_.real_ >= double(minInt64) &&
3675 value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
3676 default:
3677 break;
3678 }
3679 #endif // JSON_HAS_INT64
3680 return false;
3681 }
3682
isUInt64() const3683 bool Value::isUInt64() const {
3684 #if defined(JSON_HAS_INT64)
3685 switch (type_) {
3686 case intValue:
3687 return value_.int_ >= 0;
3688 case uintValue:
3689 return true;
3690 case realValue:
3691 // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
3692 // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
3693 // require the value to be strictly less than the limit.
3694 return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
3695 IsIntegral(value_.real_);
3696 default:
3697 break;
3698 }
3699 #endif // JSON_HAS_INT64
3700 return false;
3701 }
3702
isIntegral() const3703 bool Value::isIntegral() const {
3704 #if defined(JSON_HAS_INT64)
3705 return isInt64() || isUInt64();
3706 #else
3707 return isInt() || isUInt();
3708 #endif
3709 }
3710
isDouble() const3711 bool Value::isDouble() const { return type_ == realValue || isIntegral(); }
3712
isNumeric() const3713 bool Value::isNumeric() const { return isIntegral() || isDouble(); }
3714
isString() const3715 bool Value::isString() const { return type_ == stringValue; }
3716
isArray() const3717 bool Value::isArray() const { return type_ == arrayValue; }
3718
isObject() const3719 bool Value::isObject() const { return type_ == objectValue; }
3720
setComment(const char * comment,size_t len,CommentPlacement placement)3721 void Value::setComment(const char* comment, size_t len, CommentPlacement placement) {
3722 if (!comments_)
3723 comments_ = new CommentInfo[numberOfCommentPlacement];
3724 if ((len > 0) && (comment[len-1] == '\n')) {
3725 // Always discard trailing newline, to aid indentation.
3726 len -= 1;
3727 }
3728 comments_[placement].setComment(comment, len);
3729 }
3730
setComment(const char * comment,CommentPlacement placement)3731 void Value::setComment(const char* comment, CommentPlacement placement) {
3732 setComment(comment, strlen(comment), placement);
3733 }
3734
setComment(const std::string & comment,CommentPlacement placement)3735 void Value::setComment(const std::string& comment, CommentPlacement placement) {
3736 setComment(comment.c_str(), comment.length(), placement);
3737 }
3738
hasComment(CommentPlacement placement) const3739 bool Value::hasComment(CommentPlacement placement) const {
3740 return comments_ != 0 && comments_[placement].comment_ != 0;
3741 }
3742
getComment(CommentPlacement placement) const3743 std::string Value::getComment(CommentPlacement placement) const {
3744 if (hasComment(placement))
3745 return comments_[placement].comment_;
3746 return "";
3747 }
3748
setOffsetStart(size_t start)3749 void Value::setOffsetStart(size_t start) { start_ = start; }
3750
setOffsetLimit(size_t limit)3751 void Value::setOffsetLimit(size_t limit) { limit_ = limit; }
3752
getOffsetStart() const3753 size_t Value::getOffsetStart() const { return start_; }
3754
getOffsetLimit() const3755 size_t Value::getOffsetLimit() const { return limit_; }
3756
toStyledString() const3757 std::string Value::toStyledString() const {
3758 StyledWriter writer;
3759 return writer.write(*this);
3760 }
3761
begin() const3762 Value::const_iterator Value::begin() const {
3763 switch (type_) {
3764 case arrayValue:
3765 case objectValue:
3766 if (value_.map_)
3767 return const_iterator(value_.map_->begin());
3768 break;
3769 default:
3770 break;
3771 }
3772 return const_iterator();
3773 }
3774
end() const3775 Value::const_iterator Value::end() const {
3776 switch (type_) {
3777 case arrayValue:
3778 case objectValue:
3779 if (value_.map_)
3780 return const_iterator(value_.map_->end());
3781 break;
3782 default:
3783 break;
3784 }
3785 return const_iterator();
3786 }
3787
begin()3788 Value::iterator Value::begin() {
3789 switch (type_) {
3790 case arrayValue:
3791 case objectValue:
3792 if (value_.map_)
3793 return iterator(value_.map_->begin());
3794 break;
3795 default:
3796 break;
3797 }
3798 return iterator();
3799 }
3800
end()3801 Value::iterator Value::end() {
3802 switch (type_) {
3803 case arrayValue:
3804 case objectValue:
3805 if (value_.map_)
3806 return iterator(value_.map_->end());
3807 break;
3808 default:
3809 break;
3810 }
3811 return iterator();
3812 }
3813
3814 // class PathArgument
3815 // //////////////////////////////////////////////////////////////////
3816
PathArgument()3817 PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {}
3818
PathArgument(ArrayIndex index)3819 PathArgument::PathArgument(ArrayIndex index)
3820 : key_(), index_(index), kind_(kindIndex) {}
3821
PathArgument(const char * key)3822 PathArgument::PathArgument(const char* key)
3823 : key_(key), index_(), kind_(kindKey) {}
3824
PathArgument(const std::string & key)3825 PathArgument::PathArgument(const std::string& key)
3826 : key_(key.c_str()), index_(), kind_(kindKey) {}
3827
3828 // class Path
3829 // //////////////////////////////////////////////////////////////////
3830
Path(const std::string & path,const PathArgument & a1,const PathArgument & a2,const PathArgument & a3,const PathArgument & a4,const PathArgument & a5)3831 Path::Path(const std::string& path,
3832 const PathArgument& a1,
3833 const PathArgument& a2,
3834 const PathArgument& a3,
3835 const PathArgument& a4,
3836 const PathArgument& a5) {
3837 InArgs in;
3838 in.push_back(&a1);
3839 in.push_back(&a2);
3840 in.push_back(&a3);
3841 in.push_back(&a4);
3842 in.push_back(&a5);
3843 makePath(path, in);
3844 }
3845
makePath(const std::string & path,const InArgs & in)3846 void Path::makePath(const std::string& path, const InArgs& in) {
3847 const char* current = path.c_str();
3848 const char* end = current + path.length();
3849 InArgs::const_iterator itInArg = in.begin();
3850 while (current != end) {
3851 if (*current == '[') {
3852 ++current;
3853 if (*current == '%')
3854 addPathInArg(path, in, itInArg, PathArgument::kindIndex);
3855 else {
3856 ArrayIndex index = 0;
3857 for (; current != end && *current >= '0' && *current <= '9'; ++current)
3858 index = index * 10 + ArrayIndex(*current - '0');
3859 args_.push_back(index);
3860 }
3861 if (current == end || *current++ != ']')
3862 invalidPath(path, int(current - path.c_str()));
3863 } else if (*current == '%') {
3864 addPathInArg(path, in, itInArg, PathArgument::kindKey);
3865 ++current;
3866 } else if (*current == '.') {
3867 ++current;
3868 } else {
3869 const char* beginName = current;
3870 while (current != end && !strchr("[.", *current))
3871 ++current;
3872 args_.push_back(std::string(beginName, current));
3873 }
3874 }
3875 }
3876
addPathInArg(const std::string &,const InArgs & in,InArgs::const_iterator & itInArg,PathArgument::Kind kind)3877 void Path::addPathInArg(const std::string& /*path*/,
3878 const InArgs& in,
3879 InArgs::const_iterator& itInArg,
3880 PathArgument::Kind kind) {
3881 if (itInArg == in.end()) {
3882 // Error: missing argument %d
3883 } else if ((*itInArg)->kind_ != kind) {
3884 // Error: bad argument type
3885 } else {
3886 args_.push_back(**itInArg);
3887 }
3888 }
3889
invalidPath(const std::string &,int)3890 void Path::invalidPath(const std::string& /*path*/, int /*location*/) {
3891 // Error: invalid path.
3892 }
3893
resolve(const Value & root) const3894 const Value& Path::resolve(const Value& root) const {
3895 const Value* node = &root;
3896 for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
3897 const PathArgument& arg = *it;
3898 if (arg.kind_ == PathArgument::kindIndex) {
3899 if (!node->isArray() || !node->isValidIndex(arg.index_)) {
3900 // Error: unable to resolve path (array value expected at position...
3901 }
3902 node = &((*node)[arg.index_]);
3903 } else if (arg.kind_ == PathArgument::kindKey) {
3904 if (!node->isObject()) {
3905 // Error: unable to resolve path (object value expected at position...)
3906 }
3907 node = &((*node)[arg.key_]);
3908 if (node == &Value::nullRef) {
3909 // Error: unable to resolve path (object has no member named '' at
3910 // position...)
3911 }
3912 }
3913 }
3914 return *node;
3915 }
3916
resolve(const Value & root,const Value & defaultValue) const3917 Value Path::resolve(const Value& root, const Value& defaultValue) const {
3918 const Value* node = &root;
3919 for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
3920 const PathArgument& arg = *it;
3921 if (arg.kind_ == PathArgument::kindIndex) {
3922 if (!node->isArray() || !node->isValidIndex(arg.index_))
3923 return defaultValue;
3924 node = &((*node)[arg.index_]);
3925 } else if (arg.kind_ == PathArgument::kindKey) {
3926 if (!node->isObject())
3927 return defaultValue;
3928 node = &((*node)[arg.key_]);
3929 if (node == &Value::nullRef)
3930 return defaultValue;
3931 }
3932 }
3933 return *node;
3934 }
3935
make(Value & root) const3936 Value& Path::make(Value& root) const {
3937 Value* node = &root;
3938 for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
3939 const PathArgument& arg = *it;
3940 if (arg.kind_ == PathArgument::kindIndex) {
3941 if (!node->isArray()) {
3942 // Error: node is not an array at position ...
3943 }
3944 node = &((*node)[arg.index_]);
3945 } else if (arg.kind_ == PathArgument::kindKey) {
3946 if (!node->isObject()) {
3947 // Error: node is not an object at position...
3948 }
3949 node = &((*node)[arg.key_]);
3950 }
3951 }
3952 return *node;
3953 }
3954
3955 } // namespace Json
3956
3957 // //////////////////////////////////////////////////////////////////////
3958 // End of content of file: src/lib_json/json_value.cpp
3959 // //////////////////////////////////////////////////////////////////////
3960
3961
3962
3963
3964
3965
3966 // //////////////////////////////////////////////////////////////////////
3967 // Beginning of content of file: src/lib_json/json_writer.cpp
3968 // //////////////////////////////////////////////////////////////////////
3969
3970 // Copyright 2011 Baptiste Lepilleur
3971 // Distributed under MIT license, or public domain if desired and
3972 // recognized in your jurisdiction.
3973 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
3974
3975 #if !defined(JSON_IS_AMALGAMATION)
3976 #include <json/writer.h>
3977 #include "json_tool.h"
3978 #endif // if !defined(JSON_IS_AMALGAMATION)
3979 #include <iomanip>
3980 #include <memory>
3981 #include <sstream>
3982 #include <utility>
3983 #include <set>
3984 #include <cassert>
3985 #include <cstring>
3986 #include <cstdio>
3987
3988 #if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0
3989 #include <float.h>
3990 #define isfinite _finite
3991 #elif defined(__sun) && defined(__SVR4) //Solaris
3992 #if !defined(isfinite)
3993 #include <ieeefp.h>
3994 #define isfinite finite
3995 #endif
3996 #elif defined(_AIX)
3997 #if !defined(isfinite)
3998 #include <math.h>
3999 #define isfinite finite
4000 #endif
4001 #elif defined(__hpux)
4002 #if !defined(isfinite)
4003 #if defined(__ia64) && !defined(finite)
4004 #define isfinite(x) ((sizeof(x) == sizeof(float) ? \
4005 _Isfinitef(x) : _IsFinite(x)))
4006 #else
4007 #include <math.h>
4008 #define isfinite finite
4009 #endif
4010 #endif
4011 #else
4012 #include <cmath>
4013 #if !(defined(__QNXNTO__)) // QNX already defines isfinite
4014 #define isfinite std::isfinite
4015 #endif
4016 #endif
4017
4018 #if defined(_MSC_VER)
4019 #if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
4020 #define snprintf sprintf_s
4021 #elif _MSC_VER >= 1900 // VC++ 14.0 and above
4022 #define snprintf std::snprintf
4023 #else
4024 #define snprintf _snprintf
4025 #endif
4026 #elif defined(__ANDROID__) || defined(__QNXNTO__)
4027 #define snprintf snprintf
4028 #elif __cplusplus >= 201103L
4029 #define snprintf std::snprintf
4030 #endif
4031
4032 #if defined(__BORLANDC__)
4033 #include <float.h>
4034 #define isfinite _finite
4035 #define snprintf _snprintf
4036 #endif
4037
4038 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
4039 // Disable warning about strdup being deprecated.
4040 #pragma warning(disable : 4996)
4041 #endif
4042
4043 namespace Json {
4044
4045 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
4046 typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
4047 #else
4048 typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
4049 #endif
4050
containsControlCharacter(const char * str)4051 static bool containsControlCharacter(const char* str) {
4052 while (*str) {
4053 if (isControlCharacter(*(str++)))
4054 return true;
4055 }
4056 return false;
4057 }
4058
containsControlCharacter0(const char * str,unsigned len)4059 static bool containsControlCharacter0(const char* str, unsigned len) {
4060 char const* end = str + len;
4061 while (end != str) {
4062 if (isControlCharacter(*str) || 0==*str)
4063 return true;
4064 ++str;
4065 }
4066 return false;
4067 }
4068
valueToString(LargestInt value)4069 std::string valueToString(LargestInt value) {
4070 UIntToStringBuffer buffer;
4071 char* current = buffer + sizeof(buffer);
4072 if (value == Value::minLargestInt) {
4073 uintToString(LargestUInt(Value::maxLargestInt) + 1, current);
4074 *--current = '-';
4075 } else if (value < 0) {
4076 uintToString(LargestUInt(-value), current);
4077 *--current = '-';
4078 } else {
4079 uintToString(LargestUInt(value), current);
4080 }
4081 assert(current >= buffer);
4082 return current;
4083 }
4084
valueToString(LargestUInt value)4085 std::string valueToString(LargestUInt value) {
4086 UIntToStringBuffer buffer;
4087 char* current = buffer + sizeof(buffer);
4088 uintToString(value, current);
4089 assert(current >= buffer);
4090 return current;
4091 }
4092
4093 #if defined(JSON_HAS_INT64)
4094
valueToString(Int value)4095 std::string valueToString(Int value) {
4096 return valueToString(LargestInt(value));
4097 }
4098
valueToString(UInt value)4099 std::string valueToString(UInt value) {
4100 return valueToString(LargestUInt(value));
4101 }
4102
4103 #endif // # if defined(JSON_HAS_INT64)
4104
valueToString(double value,bool useSpecialFloats,unsigned int precision)4105 std::string valueToString(double value, bool useSpecialFloats, unsigned int precision) {
4106 // Allocate a buffer that is more than large enough to store the 16 digits of
4107 // precision requested below.
4108 char buffer[32];
4109 int len = -1;
4110
4111 char formatString[6];
4112 sprintf(formatString, "%%.%dg", precision);
4113
4114 // Print into the buffer. We need not request the alternative representation
4115 // that always has a decimal point because JSON doesn't distingish the
4116 // concepts of reals and integers.
4117 if (isfinite(value)) {
4118 len = snprintf(buffer, sizeof(buffer), formatString, value);
4119 } else {
4120 // IEEE standard states that NaN values will not compare to themselves
4121 if (value != value) {
4122 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");
4123 } else if (value < 0) {
4124 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999");
4125 } else {
4126 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999");
4127 }
4128 // For those, we do not need to call fixNumLoc, but it is fast.
4129 }
4130 assert(len >= 0);
4131 fixNumericLocale(buffer, buffer + len);
4132 return buffer;
4133 }
4134
valueToString(double value)4135 std::string valueToString(double value) { return valueToString(value, false, 17); }
4136
valueToString(bool value)4137 std::string valueToString(bool value) { return value ? "true" : "false"; }
4138
valueToQuotedString(const char * value)4139 std::string valueToQuotedString(const char* value) {
4140 if (value == NULL)
4141 return "";
4142 // Not sure how to handle unicode...
4143 if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL &&
4144 !containsControlCharacter(value))
4145 return std::string("\"") + value + "\"";
4146 // We have to walk value and escape any special characters.
4147 // Appending to std::string is not efficient, but this should be rare.
4148 // (Note: forward slashes are *not* rare, but I am not escaping them.)
4149 std::string::size_type maxsize =
4150 strlen(value) * 2 + 3; // allescaped+quotes+NULL
4151 std::string result;
4152 result.reserve(maxsize); // to avoid lots of mallocs
4153 result += "\"";
4154 for (const char* c = value; *c != 0; ++c) {
4155 switch (*c) {
4156 case '\"':
4157 result += "\\\"";
4158 break;
4159 case '\\':
4160 result += "\\\\";
4161 break;
4162 case '\b':
4163 result += "\\b";
4164 break;
4165 case '\f':
4166 result += "\\f";
4167 break;
4168 case '\n':
4169 result += "\\n";
4170 break;
4171 case '\r':
4172 result += "\\r";
4173 break;
4174 case '\t':
4175 result += "\\t";
4176 break;
4177 // case '/':
4178 // Even though \/ is considered a legal escape in JSON, a bare
4179 // slash is also legal, so I see no reason to escape it.
4180 // (I hope I am not misunderstanding something.
4181 // blep notes: actually escaping \/ may be useful in javascript to avoid </
4182 // sequence.
4183 // Should add a flag to allow this compatibility mode and prevent this
4184 // sequence from occurring.
4185 default:
4186 if (isControlCharacter(*c)) {
4187 std::ostringstream oss;
4188 oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
4189 << std::setw(4) << static_cast<int>(*c);
4190 result += oss.str();
4191 } else {
4192 result += *c;
4193 }
4194 break;
4195 }
4196 }
4197 result += "\"";
4198 return result;
4199 }
4200
4201 // https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp
strnpbrk(char const * s,char const * accept,size_t n)4202 static char const* strnpbrk(char const* s, char const* accept, size_t n) {
4203 assert((s || !n) && accept);
4204
4205 char const* const end = s + n;
4206 for (char const* cur = s; cur < end; ++cur) {
4207 int const c = *cur;
4208 for (char const* a = accept; *a; ++a) {
4209 if (*a == c) {
4210 return cur;
4211 }
4212 }
4213 }
4214 return NULL;
4215 }
valueToQuotedStringN(const char * value,unsigned length)4216 static std::string valueToQuotedStringN(const char* value, unsigned length) {
4217 if (value == NULL)
4218 return "";
4219 // Not sure how to handle unicode...
4220 if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL &&
4221 !containsControlCharacter0(value, length))
4222 return std::string("\"") + value + "\"";
4223 // We have to walk value and escape any special characters.
4224 // Appending to std::string is not efficient, but this should be rare.
4225 // (Note: forward slashes are *not* rare, but I am not escaping them.)
4226 std::string::size_type maxsize =
4227 length * 2 + 3; // allescaped+quotes+NULL
4228 std::string result;
4229 result.reserve(maxsize); // to avoid lots of mallocs
4230 result += "\"";
4231 char const* end = value + length;
4232 for (const char* c = value; c != end; ++c) {
4233 switch (*c) {
4234 case '\"':
4235 result += "\\\"";
4236 break;
4237 case '\\':
4238 result += "\\\\";
4239 break;
4240 case '\b':
4241 result += "\\b";
4242 break;
4243 case '\f':
4244 result += "\\f";
4245 break;
4246 case '\n':
4247 result += "\\n";
4248 break;
4249 case '\r':
4250 result += "\\r";
4251 break;
4252 case '\t':
4253 result += "\\t";
4254 break;
4255 // case '/':
4256 // Even though \/ is considered a legal escape in JSON, a bare
4257 // slash is also legal, so I see no reason to escape it.
4258 // (I hope I am not misunderstanding something.)
4259 // blep notes: actually escaping \/ may be useful in javascript to avoid </
4260 // sequence.
4261 // Should add a flag to allow this compatibility mode and prevent this
4262 // sequence from occurring.
4263 default:
4264 if ((isControlCharacter(*c)) || (*c == 0)) {
4265 std::ostringstream oss;
4266 oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
4267 << std::setw(4) << static_cast<int>(*c);
4268 result += oss.str();
4269 } else {
4270 result += *c;
4271 }
4272 break;
4273 }
4274 }
4275 result += "\"";
4276 return result;
4277 }
4278
4279 // Class Writer
4280 // //////////////////////////////////////////////////////////////////
~Writer()4281 Writer::~Writer() {}
4282
4283 // Class FastWriter
4284 // //////////////////////////////////////////////////////////////////
4285
FastWriter()4286 FastWriter::FastWriter()
4287 : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false),
4288 omitEndingLineFeed_(false) {}
4289
enableYAMLCompatibility()4290 void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
4291
dropNullPlaceholders()4292 void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
4293
omitEndingLineFeed()4294 void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
4295
write(const Value & root)4296 std::string FastWriter::write(const Value& root) {
4297 document_ = "";
4298 writeValue(root);
4299 if (!omitEndingLineFeed_)
4300 document_ += "\n";
4301 return document_;
4302 }
4303
writeValue(const Value & value)4304 void FastWriter::writeValue(const Value& value) {
4305 switch (value.type()) {
4306 case nullValue:
4307 if (!dropNullPlaceholders_)
4308 document_ += "null";
4309 break;
4310 case intValue:
4311 document_ += valueToString(value.asLargestInt());
4312 break;
4313 case uintValue:
4314 document_ += valueToString(value.asLargestUInt());
4315 break;
4316 case realValue:
4317 document_ += valueToString(value.asDouble());
4318 break;
4319 case stringValue:
4320 {
4321 // Is NULL possible for value.string_?
4322 char const* str;
4323 char const* end;
4324 bool ok = value.getString(&str, &end);
4325 if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str));
4326 break;
4327 }
4328 case booleanValue:
4329 document_ += valueToString(value.asBool());
4330 break;
4331 case arrayValue: {
4332 document_ += '[';
4333 int size = value.size();
4334 for (int index = 0; index < size; ++index) {
4335 if (index > 0)
4336 document_ += ',';
4337 writeValue(value[index]);
4338 }
4339 document_ += ']';
4340 } break;
4341 case objectValue: {
4342 Value::Members members(value.getMemberNames());
4343 document_ += '{';
4344 for (Value::Members::iterator it = members.begin(); it != members.end();
4345 ++it) {
4346 const std::string& name = *it;
4347 if (it != members.begin())
4348 document_ += ',';
4349 document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()));
4350 document_ += yamlCompatiblityEnabled_ ? ": " : ":";
4351 writeValue(value[name]);
4352 }
4353 document_ += '}';
4354 } break;
4355 }
4356 }
4357
4358 // Class StyledWriter
4359 // //////////////////////////////////////////////////////////////////
4360
StyledWriter()4361 StyledWriter::StyledWriter()
4362 : rightMargin_(74), indentSize_(3), addChildValues_() {}
4363
write(const Value & root)4364 std::string StyledWriter::write(const Value& root) {
4365 document_ = "";
4366 addChildValues_ = false;
4367 indentString_ = "";
4368 writeCommentBeforeValue(root);
4369 writeValue(root);
4370 writeCommentAfterValueOnSameLine(root);
4371 document_ += "\n";
4372 return document_;
4373 }
4374
writeValue(const Value & value)4375 void StyledWriter::writeValue(const Value& value) {
4376 switch (value.type()) {
4377 case nullValue:
4378 pushValue("null");
4379 break;
4380 case intValue:
4381 pushValue(valueToString(value.asLargestInt()));
4382 break;
4383 case uintValue:
4384 pushValue(valueToString(value.asLargestUInt()));
4385 break;
4386 case realValue:
4387 pushValue(valueToString(value.asDouble()));
4388 break;
4389 case stringValue:
4390 {
4391 // Is NULL possible for value.string_?
4392 char const* str;
4393 char const* end;
4394 bool ok = value.getString(&str, &end);
4395 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
4396 else pushValue("");
4397 break;
4398 }
4399 case booleanValue:
4400 pushValue(valueToString(value.asBool()));
4401 break;
4402 case arrayValue:
4403 writeArrayValue(value);
4404 break;
4405 case objectValue: {
4406 Value::Members members(value.getMemberNames());
4407 if (members.empty())
4408 pushValue("{}");
4409 else {
4410 writeWithIndent("{");
4411 indent();
4412 Value::Members::iterator it = members.begin();
4413 for (;;) {
4414 const std::string& name = *it;
4415 const Value& childValue = value[name];
4416 writeCommentBeforeValue(childValue);
4417 writeWithIndent(valueToQuotedString(name.c_str()));
4418 document_ += " : ";
4419 writeValue(childValue);
4420 if (++it == members.end()) {
4421 writeCommentAfterValueOnSameLine(childValue);
4422 break;
4423 }
4424 document_ += ',';
4425 writeCommentAfterValueOnSameLine(childValue);
4426 }
4427 unindent();
4428 writeWithIndent("}");
4429 }
4430 } break;
4431 }
4432 }
4433
writeArrayValue(const Value & value)4434 void StyledWriter::writeArrayValue(const Value& value) {
4435 unsigned size = value.size();
4436 if (size == 0)
4437 pushValue("[]");
4438 else {
4439 bool isArrayMultiLine = isMultineArray(value);
4440 if (isArrayMultiLine) {
4441 writeWithIndent("[");
4442 indent();
4443 bool hasChildValue = !childValues_.empty();
4444 unsigned index = 0;
4445 for (;;) {
4446 const Value& childValue = value[index];
4447 writeCommentBeforeValue(childValue);
4448 if (hasChildValue)
4449 writeWithIndent(childValues_[index]);
4450 else {
4451 writeIndent();
4452 writeValue(childValue);
4453 }
4454 if (++index == size) {
4455 writeCommentAfterValueOnSameLine(childValue);
4456 break;
4457 }
4458 document_ += ',';
4459 writeCommentAfterValueOnSameLine(childValue);
4460 }
4461 unindent();
4462 writeWithIndent("]");
4463 } else // output on a single line
4464 {
4465 assert(childValues_.size() == size);
4466 document_ += "[ ";
4467 for (unsigned index = 0; index < size; ++index) {
4468 if (index > 0)
4469 document_ += ", ";
4470 document_ += childValues_[index];
4471 }
4472 document_ += " ]";
4473 }
4474 }
4475 }
4476
isMultineArray(const Value & value)4477 bool StyledWriter::isMultineArray(const Value& value) {
4478 int size = value.size();
4479 bool isMultiLine = size * 3 >= rightMargin_;
4480 childValues_.clear();
4481 for (int index = 0; index < size && !isMultiLine; ++index) {
4482 const Value& childValue = value[index];
4483 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
4484 childValue.size() > 0);
4485 }
4486 if (!isMultiLine) // check if line length > max line length
4487 {
4488 childValues_.reserve(size);
4489 addChildValues_ = true;
4490 int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
4491 for (int index = 0; index < size; ++index) {
4492 if (hasCommentForValue(value[index])) {
4493 isMultiLine = true;
4494 }
4495 writeValue(value[index]);
4496 lineLength += int(childValues_[index].length());
4497 }
4498 addChildValues_ = false;
4499 isMultiLine = isMultiLine || lineLength >= rightMargin_;
4500 }
4501 return isMultiLine;
4502 }
4503
pushValue(const std::string & value)4504 void StyledWriter::pushValue(const std::string& value) {
4505 if (addChildValues_)
4506 childValues_.push_back(value);
4507 else
4508 document_ += value;
4509 }
4510
writeIndent()4511 void StyledWriter::writeIndent() {
4512 if (!document_.empty()) {
4513 char last = document_[document_.length() - 1];
4514 if (last == ' ') // already indented
4515 return;
4516 if (last != '\n') // Comments may add new-line
4517 document_ += '\n';
4518 }
4519 document_ += indentString_;
4520 }
4521
writeWithIndent(const std::string & value)4522 void StyledWriter::writeWithIndent(const std::string& value) {
4523 writeIndent();
4524 document_ += value;
4525 }
4526
indent()4527 void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); }
4528
unindent()4529 void StyledWriter::unindent() {
4530 assert(int(indentString_.size()) >= indentSize_);
4531 indentString_.resize(indentString_.size() - indentSize_);
4532 }
4533
writeCommentBeforeValue(const Value & root)4534 void StyledWriter::writeCommentBeforeValue(const Value& root) {
4535 if (!root.hasComment(commentBefore))
4536 return;
4537
4538 document_ += "\n";
4539 writeIndent();
4540 const std::string& comment = root.getComment(commentBefore);
4541 std::string::const_iterator iter = comment.begin();
4542 while (iter != comment.end()) {
4543 document_ += *iter;
4544 if (*iter == '\n' &&
4545 (iter != comment.end() && *(iter + 1) == '/'))
4546 writeIndent();
4547 ++iter;
4548 }
4549
4550 // Comments are stripped of trailing newlines, so add one here
4551 document_ += "\n";
4552 }
4553
writeCommentAfterValueOnSameLine(const Value & root)4554 void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
4555 if (root.hasComment(commentAfterOnSameLine))
4556 document_ += " " + root.getComment(commentAfterOnSameLine);
4557
4558 if (root.hasComment(commentAfter)) {
4559 document_ += "\n";
4560 document_ += root.getComment(commentAfter);
4561 document_ += "\n";
4562 }
4563 }
4564
hasCommentForValue(const Value & value)4565 bool StyledWriter::hasCommentForValue(const Value& value) {
4566 return value.hasComment(commentBefore) ||
4567 value.hasComment(commentAfterOnSameLine) ||
4568 value.hasComment(commentAfter);
4569 }
4570
4571 // Class StyledStreamWriter
4572 // //////////////////////////////////////////////////////////////////
4573
StyledStreamWriter(std::string indentation)4574 StyledStreamWriter::StyledStreamWriter(std::string indentation)
4575 : document_(NULL), rightMargin_(74), indentation_(indentation),
4576 addChildValues_() {}
4577
write(std::ostream & out,const Value & root)4578 void StyledStreamWriter::write(std::ostream& out, const Value& root) {
4579 document_ = &out;
4580 addChildValues_ = false;
4581 indentString_ = "";
4582 indented_ = true;
4583 writeCommentBeforeValue(root);
4584 if (!indented_) writeIndent();
4585 indented_ = true;
4586 writeValue(root);
4587 writeCommentAfterValueOnSameLine(root);
4588 *document_ << "\n";
4589 document_ = NULL; // Forget the stream, for safety.
4590 }
4591
writeValue(const Value & value)4592 void StyledStreamWriter::writeValue(const Value& value) {
4593 switch (value.type()) {
4594 case nullValue:
4595 pushValue("null");
4596 break;
4597 case intValue:
4598 pushValue(valueToString(value.asLargestInt()));
4599 break;
4600 case uintValue:
4601 pushValue(valueToString(value.asLargestUInt()));
4602 break;
4603 case realValue:
4604 pushValue(valueToString(value.asDouble()));
4605 break;
4606 case stringValue:
4607 {
4608 // Is NULL possible for value.string_?
4609 char const* str;
4610 char const* end;
4611 bool ok = value.getString(&str, &end);
4612 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
4613 else pushValue("");
4614 break;
4615 }
4616 case booleanValue:
4617 pushValue(valueToString(value.asBool()));
4618 break;
4619 case arrayValue:
4620 writeArrayValue(value);
4621 break;
4622 case objectValue: {
4623 Value::Members members(value.getMemberNames());
4624 if (members.empty())
4625 pushValue("{}");
4626 else {
4627 writeWithIndent("{");
4628 indent();
4629 Value::Members::iterator it = members.begin();
4630 for (;;) {
4631 const std::string& name = *it;
4632 const Value& childValue = value[name];
4633 writeCommentBeforeValue(childValue);
4634 writeWithIndent(valueToQuotedString(name.c_str()));
4635 *document_ << " : ";
4636 writeValue(childValue);
4637 if (++it == members.end()) {
4638 writeCommentAfterValueOnSameLine(childValue);
4639 break;
4640 }
4641 *document_ << ",";
4642 writeCommentAfterValueOnSameLine(childValue);
4643 }
4644 unindent();
4645 writeWithIndent("}");
4646 }
4647 } break;
4648 }
4649 }
4650
writeArrayValue(const Value & value)4651 void StyledStreamWriter::writeArrayValue(const Value& value) {
4652 unsigned size = value.size();
4653 if (size == 0)
4654 pushValue("[]");
4655 else {
4656 bool isArrayMultiLine = isMultineArray(value);
4657 if (isArrayMultiLine) {
4658 writeWithIndent("[");
4659 indent();
4660 bool hasChildValue = !childValues_.empty();
4661 unsigned index = 0;
4662 for (;;) {
4663 const Value& childValue = value[index];
4664 writeCommentBeforeValue(childValue);
4665 if (hasChildValue)
4666 writeWithIndent(childValues_[index]);
4667 else {
4668 if (!indented_) writeIndent();
4669 indented_ = true;
4670 writeValue(childValue);
4671 indented_ = false;
4672 }
4673 if (++index == size) {
4674 writeCommentAfterValueOnSameLine(childValue);
4675 break;
4676 }
4677 *document_ << ",";
4678 writeCommentAfterValueOnSameLine(childValue);
4679 }
4680 unindent();
4681 writeWithIndent("]");
4682 } else // output on a single line
4683 {
4684 assert(childValues_.size() == size);
4685 *document_ << "[ ";
4686 for (unsigned index = 0; index < size; ++index) {
4687 if (index > 0)
4688 *document_ << ", ";
4689 *document_ << childValues_[index];
4690 }
4691 *document_ << " ]";
4692 }
4693 }
4694 }
4695
isMultineArray(const Value & value)4696 bool StyledStreamWriter::isMultineArray(const Value& value) {
4697 int size = value.size();
4698 bool isMultiLine = size * 3 >= rightMargin_;
4699 childValues_.clear();
4700 for (int index = 0; index < size && !isMultiLine; ++index) {
4701 const Value& childValue = value[index];
4702 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
4703 childValue.size() > 0);
4704 }
4705 if (!isMultiLine) // check if line length > max line length
4706 {
4707 childValues_.reserve(size);
4708 addChildValues_ = true;
4709 int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
4710 for (int index = 0; index < size; ++index) {
4711 if (hasCommentForValue(value[index])) {
4712 isMultiLine = true;
4713 }
4714 writeValue(value[index]);
4715 lineLength += int(childValues_[index].length());
4716 }
4717 addChildValues_ = false;
4718 isMultiLine = isMultiLine || lineLength >= rightMargin_;
4719 }
4720 return isMultiLine;
4721 }
4722
pushValue(const std::string & value)4723 void StyledStreamWriter::pushValue(const std::string& value) {
4724 if (addChildValues_)
4725 childValues_.push_back(value);
4726 else
4727 *document_ << value;
4728 }
4729
writeIndent()4730 void StyledStreamWriter::writeIndent() {
4731 // blep intended this to look at the so-far-written string
4732 // to determine whether we are already indented, but
4733 // with a stream we cannot do that. So we rely on some saved state.
4734 // The caller checks indented_.
4735 *document_ << '\n' << indentString_;
4736 }
4737
writeWithIndent(const std::string & value)4738 void StyledStreamWriter::writeWithIndent(const std::string& value) {
4739 if (!indented_) writeIndent();
4740 *document_ << value;
4741 indented_ = false;
4742 }
4743
indent()4744 void StyledStreamWriter::indent() { indentString_ += indentation_; }
4745
unindent()4746 void StyledStreamWriter::unindent() {
4747 assert(indentString_.size() >= indentation_.size());
4748 indentString_.resize(indentString_.size() - indentation_.size());
4749 }
4750
writeCommentBeforeValue(const Value & root)4751 void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
4752 if (!root.hasComment(commentBefore))
4753 return;
4754
4755 if (!indented_) writeIndent();
4756 const std::string& comment = root.getComment(commentBefore);
4757 std::string::const_iterator iter = comment.begin();
4758 while (iter != comment.end()) {
4759 *document_ << *iter;
4760 if (*iter == '\n' &&
4761 (iter != comment.end() && *(iter + 1) == '/'))
4762 // writeIndent(); // would include newline
4763 *document_ << indentString_;
4764 ++iter;
4765 }
4766 indented_ = false;
4767 }
4768
writeCommentAfterValueOnSameLine(const Value & root)4769 void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
4770 if (root.hasComment(commentAfterOnSameLine))
4771 *document_ << ' ' << root.getComment(commentAfterOnSameLine);
4772
4773 if (root.hasComment(commentAfter)) {
4774 writeIndent();
4775 *document_ << root.getComment(commentAfter);
4776 }
4777 indented_ = false;
4778 }
4779
hasCommentForValue(const Value & value)4780 bool StyledStreamWriter::hasCommentForValue(const Value& value) {
4781 return value.hasComment(commentBefore) ||
4782 value.hasComment(commentAfterOnSameLine) ||
4783 value.hasComment(commentAfter);
4784 }
4785
4786 //////////////////////////
4787 // BuiltStyledStreamWriter
4788
4789 /// Scoped enums are not available until C++11.
4790 struct CommentStyle {
4791 /// Decide whether to write comments.
4792 enum Enum {
4793 None, ///< Drop all comments.
4794 Most, ///< Recover odd behavior of previous versions (not implemented yet).
4795 All ///< Keep all comments.
4796 };
4797 };
4798
4799 struct BuiltStyledStreamWriter : public StreamWriter
4800 {
4801 BuiltStyledStreamWriter(
4802 std::string const& indentation,
4803 CommentStyle::Enum cs,
4804 std::string const& colonSymbol,
4805 std::string const& nullSymbol,
4806 std::string const& endingLineFeedSymbol,
4807 bool useSpecialFloats,
4808 unsigned int precision);
4809 int write(Value const& root, std::ostream* sout) override;
4810 private:
4811 void writeValue(Value const& value);
4812 void writeArrayValue(Value const& value);
4813 bool isMultineArray(Value const& value);
4814 void pushValue(std::string const& value);
4815 void writeIndent();
4816 void writeWithIndent(std::string const& value);
4817 void indent();
4818 void unindent();
4819 void writeCommentBeforeValue(Value const& root);
4820 void writeCommentAfterValueOnSameLine(Value const& root);
4821 static bool hasCommentForValue(const Value& value);
4822
4823 typedef std::vector<std::string> ChildValues;
4824
4825 ChildValues childValues_;
4826 std::string indentString_;
4827 int rightMargin_;
4828 std::string indentation_;
4829 CommentStyle::Enum cs_;
4830 std::string colonSymbol_;
4831 std::string nullSymbol_;
4832 std::string endingLineFeedSymbol_;
4833 bool addChildValues_ : 1;
4834 bool indented_ : 1;
4835 bool useSpecialFloats_ : 1;
4836 unsigned int precision_;
4837 };
BuiltStyledStreamWriter(std::string const & indentation,CommentStyle::Enum cs,std::string const & colonSymbol,std::string const & nullSymbol,std::string const & endingLineFeedSymbol,bool useSpecialFloats,unsigned int precision)4838 BuiltStyledStreamWriter::BuiltStyledStreamWriter(
4839 std::string const& indentation,
4840 CommentStyle::Enum cs,
4841 std::string const& colonSymbol,
4842 std::string const& nullSymbol,
4843 std::string const& endingLineFeedSymbol,
4844 bool useSpecialFloats,
4845 unsigned int precision)
4846 : rightMargin_(74)
4847 , indentation_(indentation)
4848 , cs_(cs)
4849 , colonSymbol_(colonSymbol)
4850 , nullSymbol_(nullSymbol)
4851 , endingLineFeedSymbol_(endingLineFeedSymbol)
4852 , addChildValues_(false)
4853 , indented_(false)
4854 , useSpecialFloats_(useSpecialFloats)
4855 , precision_(precision)
4856 {
4857 }
write(Value const & root,std::ostream * sout)4858 int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout)
4859 {
4860 sout_ = sout;
4861 addChildValues_ = false;
4862 indented_ = true;
4863 indentString_ = "";
4864 writeCommentBeforeValue(root);
4865 if (!indented_) writeIndent();
4866 indented_ = true;
4867 writeValue(root);
4868 writeCommentAfterValueOnSameLine(root);
4869 *sout_ << endingLineFeedSymbol_;
4870 sout_ = NULL;
4871 return 0;
4872 }
writeValue(Value const & value)4873 void BuiltStyledStreamWriter::writeValue(Value const& value) {
4874 switch (value.type()) {
4875 case nullValue:
4876 pushValue(nullSymbol_);
4877 break;
4878 case intValue:
4879 pushValue(valueToString(value.asLargestInt()));
4880 break;
4881 case uintValue:
4882 pushValue(valueToString(value.asLargestUInt()));
4883 break;
4884 case realValue:
4885 pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
4886 break;
4887 case stringValue:
4888 {
4889 // Is NULL is possible for value.string_?
4890 char const* str;
4891 char const* end;
4892 bool ok = value.getString(&str, &end);
4893 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
4894 else pushValue("");
4895 break;
4896 }
4897 case booleanValue:
4898 pushValue(valueToString(value.asBool()));
4899 break;
4900 case arrayValue:
4901 writeArrayValue(value);
4902 break;
4903 case objectValue: {
4904 Value::Members members(value.getMemberNames());
4905 if (members.empty())
4906 pushValue("{}");
4907 else {
4908 writeWithIndent("{");
4909 indent();
4910 Value::Members::iterator it = members.begin();
4911 for (;;) {
4912 std::string const& name = *it;
4913 Value const& childValue = value[name];
4914 writeCommentBeforeValue(childValue);
4915 writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())));
4916 *sout_ << colonSymbol_;
4917 writeValue(childValue);
4918 if (++it == members.end()) {
4919 writeCommentAfterValueOnSameLine(childValue);
4920 break;
4921 }
4922 *sout_ << ",";
4923 writeCommentAfterValueOnSameLine(childValue);
4924 }
4925 unindent();
4926 writeWithIndent("}");
4927 }
4928 } break;
4929 }
4930 }
4931
writeArrayValue(Value const & value)4932 void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
4933 unsigned size = value.size();
4934 if (size == 0)
4935 pushValue("[]");
4936 else {
4937 bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value);
4938 if (isMultiLine) {
4939 writeWithIndent("[");
4940 indent();
4941 bool hasChildValue = !childValues_.empty();
4942 unsigned index = 0;
4943 for (;;) {
4944 Value const& childValue = value[index];
4945 writeCommentBeforeValue(childValue);
4946 if (hasChildValue)
4947 writeWithIndent(childValues_[index]);
4948 else {
4949 if (!indented_) writeIndent();
4950 indented_ = true;
4951 writeValue(childValue);
4952 indented_ = false;
4953 }
4954 if (++index == size) {
4955 writeCommentAfterValueOnSameLine(childValue);
4956 break;
4957 }
4958 *sout_ << ",";
4959 writeCommentAfterValueOnSameLine(childValue);
4960 }
4961 unindent();
4962 writeWithIndent("]");
4963 } else // output on a single line
4964 {
4965 assert(childValues_.size() == size);
4966 *sout_ << "[";
4967 if (!indentation_.empty()) *sout_ << " ";
4968 for (unsigned index = 0; index < size; ++index) {
4969 if (index > 0)
4970 *sout_ << ", ";
4971 *sout_ << childValues_[index];
4972 }
4973 if (!indentation_.empty()) *sout_ << " ";
4974 *sout_ << "]";
4975 }
4976 }
4977 }
4978
isMultineArray(Value const & value)4979 bool BuiltStyledStreamWriter::isMultineArray(Value const& value) {
4980 int size = value.size();
4981 bool isMultiLine = size * 3 >= rightMargin_;
4982 childValues_.clear();
4983 for (int index = 0; index < size && !isMultiLine; ++index) {
4984 Value const& childValue = value[index];
4985 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
4986 childValue.size() > 0);
4987 }
4988 if (!isMultiLine) // check if line length > max line length
4989 {
4990 childValues_.reserve(size);
4991 addChildValues_ = true;
4992 int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
4993 for (int index = 0; index < size; ++index) {
4994 if (hasCommentForValue(value[index])) {
4995 isMultiLine = true;
4996 }
4997 writeValue(value[index]);
4998 lineLength += int(childValues_[index].length());
4999 }
5000 addChildValues_ = false;
5001 isMultiLine = isMultiLine || lineLength >= rightMargin_;
5002 }
5003 return isMultiLine;
5004 }
5005
pushValue(std::string const & value)5006 void BuiltStyledStreamWriter::pushValue(std::string const& value) {
5007 if (addChildValues_)
5008 childValues_.push_back(value);
5009 else
5010 *sout_ << value;
5011 }
5012
writeIndent()5013 void BuiltStyledStreamWriter::writeIndent() {
5014 // blep intended this to look at the so-far-written string
5015 // to determine whether we are already indented, but
5016 // with a stream we cannot do that. So we rely on some saved state.
5017 // The caller checks indented_.
5018
5019 if (!indentation_.empty()) {
5020 // In this case, drop newlines too.
5021 *sout_ << '\n' << indentString_;
5022 }
5023 }
5024
writeWithIndent(std::string const & value)5025 void BuiltStyledStreamWriter::writeWithIndent(std::string const& value) {
5026 if (!indented_) writeIndent();
5027 *sout_ << value;
5028 indented_ = false;
5029 }
5030
indent()5031 void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
5032
unindent()5033 void BuiltStyledStreamWriter::unindent() {
5034 assert(indentString_.size() >= indentation_.size());
5035 indentString_.resize(indentString_.size() - indentation_.size());
5036 }
5037
writeCommentBeforeValue(Value const & root)5038 void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
5039 if (cs_ == CommentStyle::None) return;
5040 if (!root.hasComment(commentBefore))
5041 return;
5042
5043 if (!indented_) writeIndent();
5044 const std::string& comment = root.getComment(commentBefore);
5045 std::string::const_iterator iter = comment.begin();
5046 while (iter != comment.end()) {
5047 *sout_ << *iter;
5048 if (*iter == '\n' &&
5049 (iter != comment.end() && *(iter + 1) == '/'))
5050 // writeIndent(); // would write extra newline
5051 *sout_ << indentString_;
5052 ++iter;
5053 }
5054 indented_ = false;
5055 }
5056
writeCommentAfterValueOnSameLine(Value const & root)5057 void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) {
5058 if (cs_ == CommentStyle::None) return;
5059 if (root.hasComment(commentAfterOnSameLine))
5060 *sout_ << " " + root.getComment(commentAfterOnSameLine);
5061
5062 if (root.hasComment(commentAfter)) {
5063 writeIndent();
5064 *sout_ << root.getComment(commentAfter);
5065 }
5066 }
5067
5068 // static
hasCommentForValue(const Value & value)5069 bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
5070 return value.hasComment(commentBefore) ||
5071 value.hasComment(commentAfterOnSameLine) ||
5072 value.hasComment(commentAfter);
5073 }
5074
5075 ///////////////
5076 // StreamWriter
5077
StreamWriter()5078 StreamWriter::StreamWriter()
5079 : sout_(NULL)
5080 {
5081 }
~StreamWriter()5082 StreamWriter::~StreamWriter()
5083 {
5084 }
~Factory()5085 StreamWriter::Factory::~Factory()
5086 {}
StreamWriterBuilder()5087 StreamWriterBuilder::StreamWriterBuilder()
5088 {
5089 setDefaults(&settings_);
5090 }
~StreamWriterBuilder()5091 StreamWriterBuilder::~StreamWriterBuilder()
5092 {}
newStreamWriter() const5093 StreamWriter* StreamWriterBuilder::newStreamWriter() const
5094 {
5095 std::string indentation = settings_["indentation"].asString();
5096 std::string cs_str = settings_["commentStyle"].asString();
5097 bool eyc = settings_["enableYAMLCompatibility"].asBool();
5098 bool dnp = settings_["dropNullPlaceholders"].asBool();
5099 bool usf = settings_["useSpecialFloats"].asBool();
5100 unsigned int pre = settings_["precision"].asUInt();
5101 CommentStyle::Enum cs = CommentStyle::All;
5102 if (cs_str == "All") {
5103 cs = CommentStyle::All;
5104 } else if (cs_str == "None") {
5105 cs = CommentStyle::None;
5106 } else {
5107 throwRuntimeError("commentStyle must be 'All' or 'None'");
5108 }
5109 std::string colonSymbol = " : ";
5110 if (eyc) {
5111 colonSymbol = ": ";
5112 } else if (indentation.empty()) {
5113 colonSymbol = ":";
5114 }
5115 std::string nullSymbol = "null";
5116 if (dnp) {
5117 nullSymbol = "";
5118 }
5119 if (pre > 17) pre = 17;
5120 std::string endingLineFeedSymbol = "";
5121 return new BuiltStyledStreamWriter(
5122 indentation, cs,
5123 colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);
5124 }
getValidWriterKeys(std::set<std::string> * valid_keys)5125 static void getValidWriterKeys(std::set<std::string>* valid_keys)
5126 {
5127 valid_keys->clear();
5128 valid_keys->insert("indentation");
5129 valid_keys->insert("commentStyle");
5130 valid_keys->insert("enableYAMLCompatibility");
5131 valid_keys->insert("dropNullPlaceholders");
5132 valid_keys->insert("useSpecialFloats");
5133 valid_keys->insert("precision");
5134 }
validate(Json::Value * invalid) const5135 bool StreamWriterBuilder::validate(Json::Value* invalid) const
5136 {
5137 Json::Value my_invalid;
5138 if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
5139 Json::Value& inv = *invalid;
5140 std::set<std::string> valid_keys;
5141 getValidWriterKeys(&valid_keys);
5142 Value::Members keys = settings_.getMemberNames();
5143 size_t n = keys.size();
5144 for (size_t i = 0; i < n; ++i) {
5145 std::string const& key = keys[i];
5146 if (valid_keys.find(key) == valid_keys.end()) {
5147 inv[key] = settings_[key];
5148 }
5149 }
5150 return 0u == inv.size();
5151 }
operator [](std::string key)5152 Value& StreamWriterBuilder::operator[](std::string key)
5153 {
5154 return settings_[key];
5155 }
5156 // static
setDefaults(Json::Value * settings)5157 void StreamWriterBuilder::setDefaults(Json::Value* settings)
5158 {
5159 //! [StreamWriterBuilderDefaults]
5160 (*settings)["commentStyle"] = "All";
5161 (*settings)["indentation"] = "\t";
5162 (*settings)["enableYAMLCompatibility"] = false;
5163 (*settings)["dropNullPlaceholders"] = false;
5164 (*settings)["useSpecialFloats"] = false;
5165 (*settings)["precision"] = 17;
5166 //! [StreamWriterBuilderDefaults]
5167 }
5168
writeString(StreamWriter::Factory const & builder,Value const & root)5169 std::string writeString(StreamWriter::Factory const& builder, Value const& root) {
5170 std::ostringstream sout;
5171 StreamWriterPtr const writer(builder.newStreamWriter());
5172 writer->write(root, &sout);
5173 return sout.str();
5174 }
5175
operator <<(std::ostream & sout,Value const & root)5176 std::ostream& operator<<(std::ostream& sout, Value const& root) {
5177 StreamWriterBuilder builder;
5178 StreamWriterPtr const writer(builder.newStreamWriter());
5179 writer->write(root, &sout);
5180 return sout;
5181 }
5182
5183 } // namespace Json
5184
5185 // //////////////////////////////////////////////////////////////////////
5186 // End of content of file: src/lib_json/json_writer.cpp
5187 // //////////////////////////////////////////////////////////////////////
5188
5189
5190
5191
5192
5193