comparison Resources/CodeGeneration/testWasmIntegrated/jsoncpp-1.8.4/jsoncpp.cpp @ 499:baa9e1e932db bgo-commands-codegen

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