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