1 /// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/).
2 /// It is intended to be used with #include "json/json.h"
4 // //////////////////////////////////////////////////////////////////////
5 // Beginning of content of file: LICENSE
6 // //////////////////////////////////////////////////////////////////////
9 The JsonCpp library's source code, including accompanying documentation,
10 tests and demonstration applications, are licensed under the following
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.
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).
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.
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:
29 http://en.wikipedia.org/wiki/MIT_License
31 The full text of the MIT License follows:
33 ========================================================================
34 Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
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:
44 The above copyright notice and this permission notice shall be
45 included in all copies or substantial portions of the Software.
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
55 ========================================================================
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
67 // //////////////////////////////////////////////////////////////////////
68 // End of content of file: LICENSE
69 // //////////////////////////////////////////////////////////////////////
76 #include "json/json.h"
78 #ifndef JSON_IS_AMALGAMATION
79 #error "Compile with -I PATH_TO_JSON_DIRECTORY"
83 // //////////////////////////////////////////////////////////////////////
84 // Beginning of content of file: src/lib_json/json_tool.h
85 // //////////////////////////////////////////////////////////////////////
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
92 #ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
93 #define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
95 #if !defined(JSON_IS_AMALGAMATION)
96 #include <json/config.h>
99 // Also support old flag NO_LOCALE_SUPPORT
100 #ifdef NO_LOCALE_SUPPORT
101 #define JSONCPP_NO_LOCALE_SUPPORT
104 #ifndef JSONCPP_NO_LOCALE_SUPPORT
108 /* This header provides common string manipulation support, such as UTF-8,
109 * portable conversion from/to string...
111 * It is an internal header that must not be exposed.
115 static inline char getDecimalPoint() {
116 #ifdef JSONCPP_NO_LOCALE_SUPPORT
119 struct lconv* lc = localeconv();
120 return lc ? *(lc->decimal_point) : '\0';
124 /// Converts a unicode code-point to UTF-8.
125 static inline String codePointToUTF8(unsigned int cp) {
128 // based on description from http://en.wikipedia.org/wiki/UTF-8
132 result[0] = static_cast<char>(cp);
133 } else if (cp <= 0x7FF) {
135 result[1] = static_cast<char>(0x80 | (0x3f & cp));
136 result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
137 } else if (cp <= 0xFFFF) {
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) {
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)));
154 /// Constant that specify the size of the buffer that must be passed to
156 uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
159 // Defines a char buffer for use with uintToString().
160 using UIntToStringBuffer = char[uintToStringBufferSize];
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.
167 static inline void uintToString(LargestUInt value, char*& current) {
170 *--current = static_cast<char>(value % 10U + static_cast<unsigned>('0'));
172 } while (value != 0);
175 /** Change ',' to '.' everywhere in buffer.
177 * We had a sophisticated way, but it did not work in WinCE.
178 * @see https://github.com/open-source-parsers/jsoncpp/pull/9
180 template <typename Iter> Iter fixNumericLocale(Iter begin, Iter end) {
181 for (; begin != end; ++begin) {
189 template <typename Iter> void fixNumericLocaleInput(Iter begin, Iter end) {
190 char decimalPoint = getDecimalPoint();
191 if (decimalPoint == '\0' || decimalPoint == '.') {
194 for (; begin != end; ++begin) {
196 *begin = decimalPoint;
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 '.'.
205 template <typename Iter> Iter fixZerosInTheEnd(Iter begin, Iter end) {
206 for (; begin != end; --end) {
207 if (*(end - 1) != '0') {
210 // Don't delete the last zero before the decimal point.
211 if (begin != (end - 1) && *(end - 2) == '.') {
220 #endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
222 // //////////////////////////////////////////////////////////////////////
223 // End of content of file: src/lib_json/json_tool.h
224 // //////////////////////////////////////////////////////////////////////
231 // //////////////////////////////////////////////////////////////////////
232 // Beginning of content of file: src/lib_json/json_reader.cpp
233 // //////////////////////////////////////////////////////////////////////
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
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)
259 #if __cplusplus >= 201103L
262 #define sscanf std::sscanf
267 #if defined(_MSC_VER)
268 #if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
269 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
270 #endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
273 #if defined(_MSC_VER)
274 // Disable warning about strdup being deprecated.
275 #pragma warning(disable : 4996)
278 // Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile
279 // time to change the stack limit
280 #if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
281 #define JSONCPP_DEPRECATED_STACK_LIMIT 1000
284 static size_t const stackLimit_g =
285 JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()
289 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
290 using CharReaderPtr = std::unique_ptr<CharReader>;
292 using CharReaderPtr = std::auto_ptr<CharReader>;
295 // Implementation of class Features
296 // ////////////////////////////////
298 Features::Features() = default;
300 Features Features::all() { return {}; }
302 Features Features::strictMode() {
304 features.allowComments_ = false;
305 features.strictRoot_ = true;
306 features.allowDroppedNullPlaceholders_ = false;
307 features.allowNumericKeys_ = false;
311 // Implementation of class Reader
312 // ////////////////////////////////
314 bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
315 return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
319 // //////////////////////////////////////////////////////////////////
321 Reader::Reader() : features_(Features::all()) {}
323 Reader::Reader(const Features& features) : features_(features) {}
325 bool Reader::parse(const std::string& document, Value& root,
326 bool collectComments) {
327 document_.assign(document.begin(), document.end());
328 const char* begin = document_.c_str();
329 const char* end = begin + document_.length();
330 return parse(begin, end, root, collectComments);
333 bool Reader::parse(std::istream& is, Value& root, bool collectComments) {
334 // std::istream_iterator<char> begin(is);
335 // std::istream_iterator<char> end;
336 // Those would allow streamed input from a file, if parse() were a
337 // template function.
339 // Since String is reference-counted, this at least does not
340 // create an extra copy.
342 std::getline(is, doc, static_cast<char> EOF);
343 return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
346 bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root,
347 bool collectComments) {
348 if (!features_.allowComments_) {
349 collectComments = false;
354 collectComments_ = collectComments;
356 lastValueEnd_ = nullptr;
357 lastValue_ = nullptr;
358 commentsBefore_.clear();
360 while (!nodes_.empty())
364 bool successful = readValue();
366 skipCommentTokens(token);
367 if (collectComments_ && !commentsBefore_.empty())
368 root.setComment(commentsBefore_, commentAfter);
369 if (features_.strictRoot_) {
370 if (!root.isArray() && !root.isObject()) {
371 // Set error location to start of doc, ideally should be first token found
373 token.type_ = tokenError;
374 token.start_ = beginDoc;
377 "A valid JSON document must be either an array or an object value.",
385 bool Reader::readValue() {
386 // readValue() may call itself only if it calls readObject() or ReadArray().
387 // These methods execute nodes_.push() just before and nodes_.pop)() just
388 // after calling readValue(). parse() executes one nodes_.push(), so > instead
390 if (nodes_.size() > stackLimit_g)
391 throwRuntimeError("Exceeded stackLimit in readValue().");
394 skipCommentTokens(token);
395 bool successful = true;
397 if (collectComments_ && !commentsBefore_.empty()) {
398 currentValue().setComment(commentsBefore_, commentBefore);
399 commentsBefore_.clear();
402 switch (token.type_) {
403 case tokenObjectBegin:
404 successful = readObject(token);
405 currentValue().setOffsetLimit(current_ - begin_);
407 case tokenArrayBegin:
408 successful = readArray(token);
409 currentValue().setOffsetLimit(current_ - begin_);
412 successful = decodeNumber(token);
415 successful = decodeString(token);
419 currentValue().swapPayload(v);
420 currentValue().setOffsetStart(token.start_ - begin_);
421 currentValue().setOffsetLimit(token.end_ - begin_);
425 currentValue().swapPayload(v);
426 currentValue().setOffsetStart(token.start_ - begin_);
427 currentValue().setOffsetLimit(token.end_ - begin_);
431 currentValue().swapPayload(v);
432 currentValue().setOffsetStart(token.start_ - begin_);
433 currentValue().setOffsetLimit(token.end_ - begin_);
435 case tokenArraySeparator:
438 if (features_.allowDroppedNullPlaceholders_) {
439 // "Un-read" the current token and mark the current value as a null
443 currentValue().swapPayload(v);
444 currentValue().setOffsetStart(current_ - begin_ - 1);
445 currentValue().setOffsetLimit(current_ - begin_);
447 } // Else, fall through...
449 currentValue().setOffsetStart(token.start_ - begin_);
450 currentValue().setOffsetLimit(token.end_ - begin_);
451 return addError("Syntax error: value, object or array expected.", token);
454 if (collectComments_) {
455 lastValueEnd_ = current_;
456 lastValue_ = ¤tValue();
462 void Reader::skipCommentTokens(Token& token) {
463 if (features_.allowComments_) {
466 } while (token.type_ == tokenComment);
472 bool Reader::readToken(Token& token) {
474 token.start_ = current_;
475 Char c = getNextChar();
479 token.type_ = tokenObjectBegin;
482 token.type_ = tokenObjectEnd;
485 token.type_ = tokenArrayBegin;
488 token.type_ = tokenArrayEnd;
491 token.type_ = tokenString;
495 token.type_ = tokenComment;
509 token.type_ = tokenNumber;
513 token.type_ = tokenTrue;
514 ok = match("rue", 3);
517 token.type_ = tokenFalse;
518 ok = match("alse", 4);
521 token.type_ = tokenNull;
522 ok = match("ull", 3);
525 token.type_ = tokenArraySeparator;
528 token.type_ = tokenMemberSeparator;
531 token.type_ = tokenEndOfStream;
538 token.type_ = tokenError;
539 token.end_ = current_;
543 void Reader::skipSpaces() {
544 while (current_ != end_) {
546 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
553 bool Reader::match(const Char* pattern, int patternLength) {
554 if (end_ - current_ < patternLength)
556 int index = patternLength;
558 if (current_[index] != pattern[index])
560 current_ += patternLength;
564 bool Reader::readComment() {
565 Location commentBegin = current_ - 1;
566 Char c = getNextChar();
567 bool successful = false;
569 successful = readCStyleComment();
571 successful = readCppStyleComment();
575 if (collectComments_) {
576 CommentPlacement placement = commentBefore;
577 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
578 if (c != '*' || !containsNewLine(commentBegin, current_))
579 placement = commentAfterOnSameLine;
582 addComment(commentBegin, current_, placement);
587 String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {
589 normalized.reserve(static_cast<size_t>(end - begin));
590 Reader::Location current = begin;
591 while (current != end) {
594 if (current != end && *current == '\n')
606 void Reader::addComment(Location begin, Location end,
607 CommentPlacement placement) {
608 assert(collectComments_);
609 const String& normalized = normalizeEOL(begin, end);
610 if (placement == commentAfterOnSameLine) {
611 assert(lastValue_ != nullptr);
612 lastValue_->setComment(normalized, placement);
614 commentsBefore_ += normalized;
618 bool Reader::readCStyleComment() {
619 while ((current_ + 1) < end_) {
620 Char c = getNextChar();
621 if (c == '*' && *current_ == '/')
624 return getNextChar() == '/';
627 bool Reader::readCppStyleComment() {
628 while (current_ != end_) {
629 Char c = getNextChar();
633 // Consume DOS EOL. It will be normalized in addComment.
634 if (current_ != end_ && *current_ == '\n')
636 // Break on Moc OS 9 EOL.
643 void Reader::readNumber() {
644 Location p = current_;
645 char c = '0'; // stopgap for already consumed character
647 while (c >= '0' && c <= '9')
648 c = (current_ = p) < end_ ? *p++ : '\0';
651 c = (current_ = p) < end_ ? *p++ : '\0';
652 while (c >= '0' && c <= '9')
653 c = (current_ = p) < end_ ? *p++ : '\0';
656 if (c == 'e' || c == 'E') {
657 c = (current_ = p) < end_ ? *p++ : '\0';
658 if (c == '+' || c == '-')
659 c = (current_ = p) < end_ ? *p++ : '\0';
660 while (c >= '0' && c <= '9')
661 c = (current_ = p) < end_ ? *p++ : '\0';
665 bool Reader::readString() {
667 while (current_ != end_) {
677 bool Reader::readObject(Token& token) {
680 Value init(objectValue);
681 currentValue().swapPayload(init);
682 currentValue().setOffsetStart(token.start_ - begin_);
683 while (readToken(tokenName)) {
684 bool initialTokenOk = true;
685 while (tokenName.type_ == tokenComment && initialTokenOk)
686 initialTokenOk = readToken(tokenName);
689 if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
692 if (tokenName.type_ == tokenString) {
693 if (!decodeString(tokenName, name))
694 return recoverFromError(tokenObjectEnd);
695 } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
697 if (!decodeNumber(tokenName, numberName))
698 return recoverFromError(tokenObjectEnd);
699 name = numberName.asString();
705 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
706 return addErrorAndRecover("Missing ':' after object member name", colon,
709 Value& value = currentValue()[name];
711 bool ok = readValue();
713 if (!ok) // error already set
714 return recoverFromError(tokenObjectEnd);
717 if (!readToken(comma) ||
718 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
719 comma.type_ != tokenComment)) {
720 return addErrorAndRecover("Missing ',' or '}' in object declaration",
721 comma, tokenObjectEnd);
723 bool finalizeTokenOk = true;
724 while (comma.type_ == tokenComment && finalizeTokenOk)
725 finalizeTokenOk = readToken(comma);
726 if (comma.type_ == tokenObjectEnd)
729 return addErrorAndRecover("Missing '}' or object member name", tokenName,
733 bool Reader::readArray(Token& token) {
734 Value init(arrayValue);
735 currentValue().swapPayload(init);
736 currentValue().setOffsetStart(token.start_ - begin_);
738 if (current_ != end_ && *current_ == ']') // empty array
746 Value& value = currentValue()[index++];
748 bool ok = readValue();
750 if (!ok) // error already set
751 return recoverFromError(tokenArrayEnd);
754 // Accept Comment after last item in the array.
755 ok = readToken(currentToken);
756 while (currentToken.type_ == tokenComment && ok) {
757 ok = readToken(currentToken);
759 bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
760 currentToken.type_ != tokenArrayEnd);
761 if (!ok || badTokenType) {
762 return addErrorAndRecover("Missing ',' or ']' in array declaration",
763 currentToken, tokenArrayEnd);
765 if (currentToken.type_ == tokenArrayEnd)
771 bool Reader::decodeNumber(Token& token) {
773 if (!decodeNumber(token, decoded))
775 currentValue().swapPayload(decoded);
776 currentValue().setOffsetStart(token.start_ - begin_);
777 currentValue().setOffsetLimit(token.end_ - begin_);
781 bool Reader::decodeNumber(Token& token, Value& decoded) {
782 // Attempts to parse the number as an integer. If the number is
783 // larger than the maximum supported value of an integer then
784 // we decode the number as a double.
785 Location current = token.start_;
786 bool isNegative = *current == '-';
789 // TODO: Help the compiler do the div and mod at compile time or get rid of
791 Value::LargestUInt maxIntegerValue =
792 isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
793 : Value::maxLargestUInt;
794 Value::LargestUInt threshold = maxIntegerValue / 10;
795 Value::LargestUInt value = 0;
796 while (current < token.end_) {
798 if (c < '0' || c > '9')
799 return decodeDouble(token, decoded);
800 auto digit(static_cast<Value::UInt>(c - '0'));
801 if (value >= threshold) {
802 // We've hit or exceeded the max value divided by 10 (rounded down). If
803 // a) we've only just touched the limit, b) this is the last digit, and
804 // c) it's small enough to fit in that rounding delta, we're okay.
805 // Otherwise treat this number as a double to avoid overflow.
806 if (value > threshold || current != token.end_ ||
807 digit > maxIntegerValue % 10) {
808 return decodeDouble(token, decoded);
811 value = value * 10 + digit;
813 if (isNegative && value == maxIntegerValue)
814 decoded = Value::minLargestInt;
816 decoded = -Value::LargestInt(value);
817 else if (value <= Value::LargestUInt(Value::maxInt))
818 decoded = Value::LargestInt(value);
824 bool Reader::decodeDouble(Token& token) {
826 if (!decodeDouble(token, decoded))
828 currentValue().swapPayload(decoded);
829 currentValue().setOffsetStart(token.start_ - begin_);
830 currentValue().setOffsetLimit(token.end_ - begin_);
834 bool Reader::decodeDouble(Token& token, Value& decoded) {
836 String buffer(token.start_, token.end_);
837 IStringStream is(buffer);
840 "'" + String(token.start_, token.end_) + "' is not a number.", token);
845 bool Reader::decodeString(Token& token) {
846 String decoded_string;
847 if (!decodeString(token, decoded_string))
849 Value decoded(decoded_string);
850 currentValue().swapPayload(decoded);
851 currentValue().setOffsetStart(token.start_ - begin_);
852 currentValue().setOffsetLimit(token.end_ - begin_);
856 bool Reader::decodeString(Token& token, String& decoded) {
857 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
858 Location current = token.start_ + 1; // skip '"'
859 Location end = token.end_ - 1; // do not include '"'
860 while (current != end) {
866 return addError("Empty escape sequence in string", token, current);
867 Char escape = *current++;
894 unsigned int unicode;
895 if (!decodeUnicodeCodePoint(token, current, end, unicode))
897 decoded += codePointToUTF8(unicode);
900 return addError("Bad escape sequence in string", token, current);
909 bool Reader::decodeUnicodeCodePoint(Token& token, Location& current,
910 Location end, unsigned int& unicode) {
912 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
914 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
916 if (end - current < 6)
918 "additional six characters expected to parse unicode surrogate pair.",
920 if (*(current++) == '\\' && *(current++) == 'u') {
921 unsigned int surrogatePair;
922 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
923 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
927 return addError("expecting another \\u token to begin the second half of "
928 "a unicode surrogate pair",
934 bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current,
936 unsigned int& ret_unicode) {
937 if (end - current < 4)
939 "Bad unicode escape sequence in string: four digits expected.", token,
942 for (int index = 0; index < 4; ++index) {
945 if (c >= '0' && c <= '9')
947 else if (c >= 'a' && c <= 'f')
948 unicode += c - 'a' + 10;
949 else if (c >= 'A' && c <= 'F')
950 unicode += c - 'A' + 10;
953 "Bad unicode escape sequence in string: hexadecimal digit expected.",
956 ret_unicode = static_cast<unsigned int>(unicode);
960 bool Reader::addError(const String& message, Token& token, Location extra) {
963 info.message_ = message;
965 errors_.push_back(info);
969 bool Reader::recoverFromError(TokenType skipUntilToken) {
970 size_t const errorCount = errors_.size();
973 if (!readToken(skip))
974 errors_.resize(errorCount); // discard errors caused by recovery
975 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
978 errors_.resize(errorCount);
982 bool Reader::addErrorAndRecover(const String& message, Token& token,
983 TokenType skipUntilToken) {
984 addError(message, token);
985 return recoverFromError(skipUntilToken);
988 Value& Reader::currentValue() { return *(nodes_.top()); }
990 Reader::Char Reader::getNextChar() {
991 if (current_ == end_)
996 void Reader::getLocationLineAndColumn(Location location, int& line,
998 Location current = begin_;
999 Location lastLineStart = current;
1001 while (current < location && current != end_) {
1002 Char c = *current++;
1004 if (*current == '\n')
1006 lastLineStart = current;
1008 } else if (c == '\n') {
1009 lastLineStart = current;
1013 // column & line start at 1
1014 column = int(location - lastLineStart) + 1;
1018 String Reader::getLocationLineAndColumn(Location location) const {
1020 getLocationLineAndColumn(location, line, column);
1021 char buffer[18 + 16 + 16 + 1];
1022 jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
1026 // Deprecated. Preserved for backward compatibility
1027 String Reader::getFormatedErrorMessages() const {
1028 return getFormattedErrorMessages();
1031 String Reader::getFormattedErrorMessages() const {
1032 String formattedMessage;
1033 for (const auto& error : errors_) {
1035 "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
1036 formattedMessage += " " + error.message_ + "\n";
1039 "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
1041 return formattedMessage;
1044 std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
1045 std::vector<Reader::StructuredError> allErrors;
1046 for (const auto& error : errors_) {
1047 Reader::StructuredError structured;
1048 structured.offset_start = error.token_.start_ - begin_;
1049 structured.offset_limit = error.token_.end_ - begin_;
1050 structured.message = error.message_;
1051 allErrors.push_back(structured);
1056 bool Reader::pushError(const Value& value, const String& message) {
1057 ptrdiff_t const length = end_ - begin_;
1058 if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
1061 token.type_ = tokenError;
1062 token.start_ = begin_ + value.getOffsetStart();
1063 token.end_ = begin_ + value.getOffsetLimit();
1065 info.token_ = token;
1066 info.message_ = message;
1067 info.extra_ = nullptr;
1068 errors_.push_back(info);
1072 bool Reader::pushError(const Value& value, const String& message,
1073 const Value& extra) {
1074 ptrdiff_t const length = end_ - begin_;
1075 if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
1076 extra.getOffsetLimit() > length)
1079 token.type_ = tokenError;
1080 token.start_ = begin_ + value.getOffsetStart();
1081 token.end_ = begin_ + value.getOffsetLimit();
1083 info.token_ = token;
1084 info.message_ = message;
1085 info.extra_ = begin_ + extra.getOffsetStart();
1086 errors_.push_back(info);
1090 bool Reader::good() const { return errors_.empty(); }
1092 // Originally copied from the Features class (now deprecated), used internally
1093 // for features implementation.
1096 static OurFeatures all();
1097 bool allowComments_;
1098 bool allowTrailingCommas_;
1100 bool allowDroppedNullPlaceholders_;
1101 bool allowNumericKeys_;
1102 bool allowSingleQuotes_;
1104 bool rejectDupKeys_;
1105 bool allowSpecialFloats_;
1110 OurFeatures OurFeatures::all() { return {}; }
1112 // Implementation of class Reader
1113 // ////////////////////////////////
1115 // Originally copied from the Reader class (now deprecated), used internally
1116 // for implementing JSON reading.
1120 using Location = const Char*;
1121 struct StructuredError {
1122 ptrdiff_t offset_start;
1123 ptrdiff_t offset_limit;
1127 explicit OurReader(OurFeatures const& features);
1128 bool parse(const char* beginDoc, const char* endDoc, Value& root,
1129 bool collectComments = true);
1130 String getFormattedErrorMessages() const;
1131 std::vector<StructuredError> getStructuredErrors() const;
1134 OurReader(OurReader const&); // no impl
1135 void operator=(OurReader const&); // no impl
1138 tokenEndOfStream = 0,
1151 tokenArraySeparator,
1152 tokenMemberSeparator,
1171 using Errors = std::deque<ErrorInfo>;
1173 bool readToken(Token& token);
1175 void skipBom(bool skipBom);
1176 bool match(const Char* pattern, int patternLength);
1178 bool readCStyleComment(bool* containsNewLineResult);
1179 bool readCppStyleComment();
1181 bool readStringSingleQuote();
1182 bool readNumber(bool checkInf);
1184 bool readObject(Token& token);
1185 bool readArray(Token& token);
1186 bool decodeNumber(Token& token);
1187 bool decodeNumber(Token& token, Value& decoded);
1188 bool decodeString(Token& token);
1189 bool decodeString(Token& token, String& decoded);
1190 bool decodeDouble(Token& token);
1191 bool decodeDouble(Token& token, Value& decoded);
1192 bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
1193 unsigned int& unicode);
1194 bool decodeUnicodeEscapeSequence(Token& token, Location& current,
1195 Location end, unsigned int& unicode);
1196 bool addError(const String& message, Token& token, Location extra = nullptr);
1197 bool recoverFromError(TokenType skipUntilToken);
1198 bool addErrorAndRecover(const String& message, Token& token,
1199 TokenType skipUntilToken);
1200 void skipUntilSpace();
1201 Value& currentValue();
1203 void getLocationLineAndColumn(Location location, int& line,
1205 String getLocationLineAndColumn(Location location) const;
1206 void addComment(Location begin, Location end, CommentPlacement placement);
1207 void skipCommentTokens(Token& token);
1209 static String normalizeEOL(Location begin, Location end);
1210 static bool containsNewLine(Location begin, Location end);
1212 using Nodes = std::stack<Value*>;
1217 Location begin_ = nullptr;
1218 Location end_ = nullptr;
1219 Location current_ = nullptr;
1220 Location lastValueEnd_ = nullptr;
1221 Value* lastValue_ = nullptr;
1222 bool lastValueHasAComment_ = false;
1223 String commentsBefore_{};
1225 OurFeatures const features_;
1226 bool collectComments_ = false;
1229 // complete copy of Read impl, for OurReader
1231 bool OurReader::containsNewLine(OurReader::Location begin,
1232 OurReader::Location end) {
1233 return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
1236 OurReader::OurReader(OurFeatures const& features) : features_(features) {}
1238 bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
1239 bool collectComments) {
1240 if (!features_.allowComments_) {
1241 collectComments = false;
1246 collectComments_ = collectComments;
1248 lastValueEnd_ = nullptr;
1249 lastValue_ = nullptr;
1250 commentsBefore_.clear();
1252 while (!nodes_.empty())
1256 // skip byte order mark if it exists at the beginning of the UTF-8 text.
1257 skipBom(features_.skipBom_);
1258 bool successful = readValue();
1261 skipCommentTokens(token);
1262 if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) {
1263 addError("Extra non-whitespace after JSON value.", token);
1266 if (collectComments_ && !commentsBefore_.empty())
1267 root.setComment(commentsBefore_, commentAfter);
1268 if (features_.strictRoot_) {
1269 if (!root.isArray() && !root.isObject()) {
1270 // Set error location to start of doc, ideally should be first token found
1272 token.type_ = tokenError;
1273 token.start_ = beginDoc;
1274 token.end_ = endDoc;
1276 "A valid JSON document must be either an array or an object value.",
1284 bool OurReader::readValue() {
1285 // To preserve the old behaviour we cast size_t to int.
1286 if (nodes_.size() > features_.stackLimit_)
1287 throwRuntimeError("Exceeded stackLimit in readValue().");
1289 skipCommentTokens(token);
1290 bool successful = true;
1292 if (collectComments_ && !commentsBefore_.empty()) {
1293 currentValue().setComment(commentsBefore_, commentBefore);
1294 commentsBefore_.clear();
1297 switch (token.type_) {
1298 case tokenObjectBegin:
1299 successful = readObject(token);
1300 currentValue().setOffsetLimit(current_ - begin_);
1302 case tokenArrayBegin:
1303 successful = readArray(token);
1304 currentValue().setOffsetLimit(current_ - begin_);
1307 successful = decodeNumber(token);
1310 successful = decodeString(token);
1314 currentValue().swapPayload(v);
1315 currentValue().setOffsetStart(token.start_ - begin_);
1316 currentValue().setOffsetLimit(token.end_ - begin_);
1320 currentValue().swapPayload(v);
1321 currentValue().setOffsetStart(token.start_ - begin_);
1322 currentValue().setOffsetLimit(token.end_ - begin_);
1326 currentValue().swapPayload(v);
1327 currentValue().setOffsetStart(token.start_ - begin_);
1328 currentValue().setOffsetLimit(token.end_ - begin_);
1331 Value v(std::numeric_limits<double>::quiet_NaN());
1332 currentValue().swapPayload(v);
1333 currentValue().setOffsetStart(token.start_ - begin_);
1334 currentValue().setOffsetLimit(token.end_ - begin_);
1337 Value v(std::numeric_limits<double>::infinity());
1338 currentValue().swapPayload(v);
1339 currentValue().setOffsetStart(token.start_ - begin_);
1340 currentValue().setOffsetLimit(token.end_ - begin_);
1343 Value v(-std::numeric_limits<double>::infinity());
1344 currentValue().swapPayload(v);
1345 currentValue().setOffsetStart(token.start_ - begin_);
1346 currentValue().setOffsetLimit(token.end_ - begin_);
1348 case tokenArraySeparator:
1349 case tokenObjectEnd:
1351 if (features_.allowDroppedNullPlaceholders_) {
1352 // "Un-read" the current token and mark the current value as a null
1356 currentValue().swapPayload(v);
1357 currentValue().setOffsetStart(current_ - begin_ - 1);
1358 currentValue().setOffsetLimit(current_ - begin_);
1360 } // else, fall through ...
1362 currentValue().setOffsetStart(token.start_ - begin_);
1363 currentValue().setOffsetLimit(token.end_ - begin_);
1364 return addError("Syntax error: value, object or array expected.", token);
1367 if (collectComments_) {
1368 lastValueEnd_ = current_;
1369 lastValueHasAComment_ = false;
1370 lastValue_ = ¤tValue();
1376 void OurReader::skipCommentTokens(Token& token) {
1377 if (features_.allowComments_) {
1380 } while (token.type_ == tokenComment);
1386 bool OurReader::readToken(Token& token) {
1388 token.start_ = current_;
1389 Char c = getNextChar();
1393 token.type_ = tokenObjectBegin;
1396 token.type_ = tokenObjectEnd;
1399 token.type_ = tokenArrayBegin;
1402 token.type_ = tokenArrayEnd;
1405 token.type_ = tokenString;
1409 if (features_.allowSingleQuotes_) {
1410 token.type_ = tokenString;
1411 ok = readStringSingleQuote();
1413 // If we don't allow single quotes, this is a failure case.
1418 token.type_ = tokenComment;
1431 token.type_ = tokenNumber;
1435 if (readNumber(true)) {
1436 token.type_ = tokenNumber;
1438 token.type_ = tokenNegInf;
1439 ok = features_.allowSpecialFloats_ && match("nfinity", 7);
1443 if (readNumber(true)) {
1444 token.type_ = tokenNumber;
1446 token.type_ = tokenPosInf;
1447 ok = features_.allowSpecialFloats_ && match("nfinity", 7);
1451 token.type_ = tokenTrue;
1452 ok = match("rue", 3);
1455 token.type_ = tokenFalse;
1456 ok = match("alse", 4);
1459 token.type_ = tokenNull;
1460 ok = match("ull", 3);
1463 if (features_.allowSpecialFloats_) {
1464 token.type_ = tokenNaN;
1465 ok = match("aN", 2);
1471 if (features_.allowSpecialFloats_) {
1472 token.type_ = tokenPosInf;
1473 ok = match("nfinity", 7);
1479 token.type_ = tokenArraySeparator;
1482 token.type_ = tokenMemberSeparator;
1485 token.type_ = tokenEndOfStream;
1492 token.type_ = tokenError;
1493 token.end_ = current_;
1497 void OurReader::skipSpaces() {
1498 while (current_ != end_) {
1500 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
1507 void OurReader::skipBom(bool skipBom) {
1508 // The default behavior is to skip BOM.
1510 if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) {
1517 bool OurReader::match(const Char* pattern, int patternLength) {
1518 if (end_ - current_ < patternLength)
1520 int index = patternLength;
1522 if (current_[index] != pattern[index])
1524 current_ += patternLength;
1528 bool OurReader::readComment() {
1529 const Location commentBegin = current_ - 1;
1530 const Char c = getNextChar();
1531 bool successful = false;
1532 bool cStyleWithEmbeddedNewline = false;
1534 const bool isCStyleComment = (c == '*');
1535 const bool isCppStyleComment = (c == '/');
1536 if (isCStyleComment) {
1537 successful = readCStyleComment(&cStyleWithEmbeddedNewline);
1538 } else if (isCppStyleComment) {
1539 successful = readCppStyleComment();
1545 if (collectComments_) {
1546 CommentPlacement placement = commentBefore;
1548 if (!lastValueHasAComment_) {
1549 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
1550 if (isCppStyleComment || !cStyleWithEmbeddedNewline) {
1551 placement = commentAfterOnSameLine;
1552 lastValueHasAComment_ = true;
1557 addComment(commentBegin, current_, placement);
1562 String OurReader::normalizeEOL(OurReader::Location begin,
1563 OurReader::Location end) {
1565 normalized.reserve(static_cast<size_t>(end - begin));
1566 OurReader::Location current = begin;
1567 while (current != end) {
1568 char c = *current++;
1570 if (current != end && *current == '\n')
1582 void OurReader::addComment(Location begin, Location end,
1583 CommentPlacement placement) {
1584 assert(collectComments_);
1585 const String& normalized = normalizeEOL(begin, end);
1586 if (placement == commentAfterOnSameLine) {
1587 assert(lastValue_ != nullptr);
1588 lastValue_->setComment(normalized, placement);
1590 commentsBefore_ += normalized;
1594 bool OurReader::readCStyleComment(bool* containsNewLineResult) {
1595 *containsNewLineResult = false;
1597 while ((current_ + 1) < end_) {
1598 Char c = getNextChar();
1599 if (c == '*' && *current_ == '/')
1602 *containsNewLineResult = true;
1605 return getNextChar() == '/';
1608 bool OurReader::readCppStyleComment() {
1609 while (current_ != end_) {
1610 Char c = getNextChar();
1614 // Consume DOS EOL. It will be normalized in addComment.
1615 if (current_ != end_ && *current_ == '\n')
1617 // Break on Moc OS 9 EOL.
1624 bool OurReader::readNumber(bool checkInf) {
1625 Location p = current_;
1626 if (checkInf && p != end_ && *p == 'I') {
1630 char c = '0'; // stopgap for already consumed character
1632 while (c >= '0' && c <= '9')
1633 c = (current_ = p) < end_ ? *p++ : '\0';
1636 c = (current_ = p) < end_ ? *p++ : '\0';
1637 while (c >= '0' && c <= '9')
1638 c = (current_ = p) < end_ ? *p++ : '\0';
1641 if (c == 'e' || c == 'E') {
1642 c = (current_ = p) < end_ ? *p++ : '\0';
1643 if (c == '+' || c == '-')
1644 c = (current_ = p) < end_ ? *p++ : '\0';
1645 while (c >= '0' && c <= '9')
1646 c = (current_ = p) < end_ ? *p++ : '\0';
1650 bool OurReader::readString() {
1652 while (current_ != end_) {
1662 bool OurReader::readStringSingleQuote() {
1664 while (current_ != end_) {
1674 bool OurReader::readObject(Token& token) {
1677 Value init(objectValue);
1678 currentValue().swapPayload(init);
1679 currentValue().setOffsetStart(token.start_ - begin_);
1680 while (readToken(tokenName)) {
1681 bool initialTokenOk = true;
1682 while (tokenName.type_ == tokenComment && initialTokenOk)
1683 initialTokenOk = readToken(tokenName);
1684 if (!initialTokenOk)
1686 if (tokenName.type_ == tokenObjectEnd &&
1688 features_.allowTrailingCommas_)) // empty object or trailing comma
1691 if (tokenName.type_ == tokenString) {
1692 if (!decodeString(tokenName, name))
1693 return recoverFromError(tokenObjectEnd);
1694 } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1696 if (!decodeNumber(tokenName, numberName))
1697 return recoverFromError(tokenObjectEnd);
1698 name = numberName.asString();
1702 if (name.length() >= (1U << 30))
1703 throwRuntimeError("keylength >= 2^30");
1704 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1705 String msg = "Duplicate key: '" + name + "'";
1706 return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
1710 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1711 return addErrorAndRecover("Missing ':' after object member name", colon,
1714 Value& value = currentValue()[name];
1715 nodes_.push(&value);
1716 bool ok = readValue();
1718 if (!ok) // error already set
1719 return recoverFromError(tokenObjectEnd);
1722 if (!readToken(comma) ||
1723 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1724 comma.type_ != tokenComment)) {
1725 return addErrorAndRecover("Missing ',' or '}' in object declaration",
1726 comma, tokenObjectEnd);
1728 bool finalizeTokenOk = true;
1729 while (comma.type_ == tokenComment && finalizeTokenOk)
1730 finalizeTokenOk = readToken(comma);
1731 if (comma.type_ == tokenObjectEnd)
1734 return addErrorAndRecover("Missing '}' or object member name", tokenName,
1738 bool OurReader::readArray(Token& token) {
1739 Value init(arrayValue);
1740 currentValue().swapPayload(init);
1741 currentValue().setOffsetStart(token.start_ - begin_);
1745 if (current_ != end_ && *current_ == ']' &&
1747 (features_.allowTrailingCommas_ &&
1748 !features_.allowDroppedNullPlaceholders_))) // empty array or trailing
1752 readToken(endArray);
1755 Value& value = currentValue()[index++];
1756 nodes_.push(&value);
1757 bool ok = readValue();
1759 if (!ok) // error already set
1760 return recoverFromError(tokenArrayEnd);
1763 // Accept Comment after last item in the array.
1764 ok = readToken(currentToken);
1765 while (currentToken.type_ == tokenComment && ok) {
1766 ok = readToken(currentToken);
1768 bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
1769 currentToken.type_ != tokenArrayEnd);
1770 if (!ok || badTokenType) {
1771 return addErrorAndRecover("Missing ',' or ']' in array declaration",
1772 currentToken, tokenArrayEnd);
1774 if (currentToken.type_ == tokenArrayEnd)
1780 bool OurReader::decodeNumber(Token& token) {
1782 if (!decodeNumber(token, decoded))
1784 currentValue().swapPayload(decoded);
1785 currentValue().setOffsetStart(token.start_ - begin_);
1786 currentValue().setOffsetLimit(token.end_ - begin_);
1790 bool OurReader::decodeNumber(Token& token, Value& decoded) {
1791 // Attempts to parse the number as an integer. If the number is
1792 // larger than the maximum supported value of an integer then
1793 // we decode the number as a double.
1794 Location current = token.start_;
1795 const bool isNegative = *current == '-';
1800 // We assume we can represent the largest and smallest integer types as
1801 // unsigned integers with separate sign. This is only true if they can fit
1802 // into an unsigned integer.
1803 static_assert(Value::maxLargestInt <= Value::maxLargestUInt,
1804 "Int must be smaller than UInt");
1806 // We need to convert minLargestInt into a positive number. The easiest way
1807 // to do this conversion is to assume our "threshold" value of minLargestInt
1808 // divided by 10 can fit in maxLargestInt when absolute valued. This should
1809 // be a safe assumption.
1810 static_assert(Value::minLargestInt <= -Value::maxLargestInt,
1811 "The absolute value of minLargestInt must be greater than or "
1812 "equal to maxLargestInt");
1813 static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt,
1814 "The absolute value of minLargestInt must be only 1 magnitude "
1815 "larger than maxLargest Int");
1817 static constexpr Value::LargestUInt positive_threshold =
1818 Value::maxLargestUInt / 10;
1819 static constexpr Value::UInt positive_last_digit = Value::maxLargestUInt % 10;
1821 // For the negative values, we have to be more careful. Since typically
1822 // -Value::minLargestInt will cause an overflow, we first divide by 10 and
1823 // then take the inverse. This assumes that minLargestInt is only a single
1824 // power of 10 different in magnitude, which we check above. For the last
1825 // digit, we take the modulus before negating for the same reason.
1826 static constexpr auto negative_threshold =
1827 Value::LargestUInt(-(Value::minLargestInt / 10));
1828 static constexpr auto negative_last_digit =
1829 Value::UInt(-(Value::minLargestInt % 10));
1831 const Value::LargestUInt threshold =
1832 isNegative ? negative_threshold : positive_threshold;
1833 const Value::UInt max_last_digit =
1834 isNegative ? negative_last_digit : positive_last_digit;
1836 Value::LargestUInt value = 0;
1837 while (current < token.end_) {
1838 Char c = *current++;
1839 if (c < '0' || c > '9')
1840 return decodeDouble(token, decoded);
1842 const auto digit(static_cast<Value::UInt>(c - '0'));
1843 if (value >= threshold) {
1844 // We've hit or exceeded the max value divided by 10 (rounded down). If
1845 // a) we've only just touched the limit, meaing value == threshold,
1846 // b) this is the last digit, or
1847 // c) it's small enough to fit in that rounding delta, we're okay.
1848 // Otherwise treat this number as a double to avoid overflow.
1849 if (value > threshold || current != token.end_ ||
1850 digit > max_last_digit) {
1851 return decodeDouble(token, decoded);
1854 value = value * 10 + digit;
1858 // We use the same magnitude assumption here, just in case.
1859 const auto last_digit = static_cast<Value::UInt>(value % 10);
1860 decoded = -Value::LargestInt(value / 10) * 10 - last_digit;
1861 } else if (value <= Value::LargestUInt(Value::maxLargestInt)) {
1862 decoded = Value::LargestInt(value);
1870 bool OurReader::decodeDouble(Token& token) {
1872 if (!decodeDouble(token, decoded))
1874 currentValue().swapPayload(decoded);
1875 currentValue().setOffsetStart(token.start_ - begin_);
1876 currentValue().setOffsetLimit(token.end_ - begin_);
1880 bool OurReader::decodeDouble(Token& token, Value& decoded) {
1882 const String buffer(token.start_, token.end_);
1883 IStringStream is(buffer);
1884 if (!(is >> value)) {
1886 "'" + String(token.start_, token.end_) + "' is not a number.", token);
1892 bool OurReader::decodeString(Token& token) {
1893 String decoded_string;
1894 if (!decodeString(token, decoded_string))
1896 Value decoded(decoded_string);
1897 currentValue().swapPayload(decoded);
1898 currentValue().setOffsetStart(token.start_ - begin_);
1899 currentValue().setOffsetLimit(token.end_ - begin_);
1903 bool OurReader::decodeString(Token& token, String& decoded) {
1904 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
1905 Location current = token.start_ + 1; // skip '"'
1906 Location end = token.end_ - 1; // do not include '"'
1907 while (current != end) {
1908 Char c = *current++;
1913 return addError("Empty escape sequence in string", token, current);
1914 Char escape = *current++;
1941 unsigned int unicode;
1942 if (!decodeUnicodeCodePoint(token, current, end, unicode))
1944 decoded += codePointToUTF8(unicode);
1947 return addError("Bad escape sequence in string", token, current);
1956 bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current,
1957 Location end, unsigned int& unicode) {
1959 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1961 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1963 if (end - current < 6)
1965 "additional six characters expected to parse unicode surrogate pair.",
1967 if (*(current++) == '\\' && *(current++) == 'u') {
1968 unsigned int surrogatePair;
1969 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1970 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1974 return addError("expecting another \\u token to begin the second half of "
1975 "a unicode surrogate pair",
1981 bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current,
1983 unsigned int& ret_unicode) {
1984 if (end - current < 4)
1986 "Bad unicode escape sequence in string: four digits expected.", token,
1989 for (int index = 0; index < 4; ++index) {
1990 Char c = *current++;
1992 if (c >= '0' && c <= '9')
1994 else if (c >= 'a' && c <= 'f')
1995 unicode += c - 'a' + 10;
1996 else if (c >= 'A' && c <= 'F')
1997 unicode += c - 'A' + 10;
2000 "Bad unicode escape sequence in string: hexadecimal digit expected.",
2003 ret_unicode = static_cast<unsigned int>(unicode);
2007 bool OurReader::addError(const String& message, Token& token, Location extra) {
2009 info.token_ = token;
2010 info.message_ = message;
2011 info.extra_ = extra;
2012 errors_.push_back(info);
2016 bool OurReader::recoverFromError(TokenType skipUntilToken) {
2017 size_t errorCount = errors_.size();
2020 if (!readToken(skip))
2021 errors_.resize(errorCount); // discard errors caused by recovery
2022 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
2025 errors_.resize(errorCount);
2029 bool OurReader::addErrorAndRecover(const String& message, Token& token,
2030 TokenType skipUntilToken) {
2031 addError(message, token);
2032 return recoverFromError(skipUntilToken);
2035 Value& OurReader::currentValue() { return *(nodes_.top()); }
2037 OurReader::Char OurReader::getNextChar() {
2038 if (current_ == end_)
2043 void OurReader::getLocationLineAndColumn(Location location, int& line,
2044 int& column) const {
2045 Location current = begin_;
2046 Location lastLineStart = current;
2048 while (current < location && current != end_) {
2049 Char c = *current++;
2051 if (*current == '\n')
2053 lastLineStart = current;
2055 } else if (c == '\n') {
2056 lastLineStart = current;
2060 // column & line start at 1
2061 column = int(location - lastLineStart) + 1;
2065 String OurReader::getLocationLineAndColumn(Location location) const {
2067 getLocationLineAndColumn(location, line, column);
2068 char buffer[18 + 16 + 16 + 1];
2069 jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
2073 String OurReader::getFormattedErrorMessages() const {
2074 String formattedMessage;
2075 for (const auto& error : errors_) {
2077 "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
2078 formattedMessage += " " + error.message_ + "\n";
2081 "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
2083 return formattedMessage;
2086 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
2087 std::vector<OurReader::StructuredError> allErrors;
2088 for (const auto& error : errors_) {
2089 OurReader::StructuredError structured;
2090 structured.offset_start = error.token_.start_ - begin_;
2091 structured.offset_limit = error.token_.end_ - begin_;
2092 structured.message = error.message_;
2093 allErrors.push_back(structured);
2098 class OurCharReader : public CharReader {
2099 bool const collectComments_;
2103 OurCharReader(bool collectComments, OurFeatures const& features)
2104 : collectComments_(collectComments), reader_(features) {}
2105 bool parse(char const* beginDoc, char const* endDoc, Value* root,
2106 String* errs) override {
2107 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
2109 *errs = reader_.getFormattedErrorMessages();
2115 CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
2116 CharReaderBuilder::~CharReaderBuilder() = default;
2117 CharReader* CharReaderBuilder::newCharReader() const {
2118 bool collectComments = settings_["collectComments"].asBool();
2119 OurFeatures features = OurFeatures::all();
2120 features.allowComments_ = settings_["allowComments"].asBool();
2121 features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool();
2122 features.strictRoot_ = settings_["strictRoot"].asBool();
2123 features.allowDroppedNullPlaceholders_ =
2124 settings_["allowDroppedNullPlaceholders"].asBool();
2125 features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
2126 features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
2128 // Stack limit is always a size_t, so we get this as an unsigned int
2129 // regardless of it we have 64-bit integer support enabled.
2130 features.stackLimit_ = static_cast<size_t>(settings_["stackLimit"].asUInt());
2131 features.failIfExtra_ = settings_["failIfExtra"].asBool();
2132 features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
2133 features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
2134 features.skipBom_ = settings_["skipBom"].asBool();
2135 return new OurCharReader(collectComments, features);
2138 bool CharReaderBuilder::validate(Json::Value* invalid) const {
2139 static const auto& valid_keys = *new std::set<String>{
2142 "allowTrailingCommas",
2144 "allowDroppedNullPlaceholders",
2146 "allowSingleQuotes",
2150 "allowSpecialFloats",
2153 for (auto si = settings_.begin(); si != settings_.end(); ++si) {
2154 auto key = si.name();
2155 if (valid_keys.count(key))
2158 (*invalid)[std::move(key)] = *si;
2162 return invalid ? invalid->empty() : true;
2165 Value& CharReaderBuilder::operator[](const String& key) {
2166 return settings_[key];
2169 void CharReaderBuilder::strictMode(Json::Value* settings) {
2170 //! [CharReaderBuilderStrictMode]
2171 (*settings)["allowComments"] = false;
2172 (*settings)["allowTrailingCommas"] = false;
2173 (*settings)["strictRoot"] = true;
2174 (*settings)["allowDroppedNullPlaceholders"] = false;
2175 (*settings)["allowNumericKeys"] = false;
2176 (*settings)["allowSingleQuotes"] = false;
2177 (*settings)["stackLimit"] = 1000;
2178 (*settings)["failIfExtra"] = true;
2179 (*settings)["rejectDupKeys"] = true;
2180 (*settings)["allowSpecialFloats"] = false;
2181 (*settings)["skipBom"] = true;
2182 //! [CharReaderBuilderStrictMode]
2185 void CharReaderBuilder::setDefaults(Json::Value* settings) {
2186 //! [CharReaderBuilderDefaults]
2187 (*settings)["collectComments"] = true;
2188 (*settings)["allowComments"] = true;
2189 (*settings)["allowTrailingCommas"] = true;
2190 (*settings)["strictRoot"] = false;
2191 (*settings)["allowDroppedNullPlaceholders"] = false;
2192 (*settings)["allowNumericKeys"] = false;
2193 (*settings)["allowSingleQuotes"] = false;
2194 (*settings)["stackLimit"] = 1000;
2195 (*settings)["failIfExtra"] = false;
2196 (*settings)["rejectDupKeys"] = false;
2197 (*settings)["allowSpecialFloats"] = false;
2198 (*settings)["skipBom"] = true;
2199 //! [CharReaderBuilderDefaults]
2202 //////////////////////////////////
2205 bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root,
2208 ssin << sin.rdbuf();
2209 String doc = ssin.str();
2210 char const* begin = doc.data();
2211 char const* end = begin + doc.size();
2212 // Note that we do not actually need a null-terminator.
2213 CharReaderPtr const reader(fact.newCharReader());
2214 return reader->parse(begin, end, root, errs);
2217 IStream& operator>>(IStream& sin, Value& root) {
2218 CharReaderBuilder b;
2220 bool ok = parseFromStream(b, sin, &root, &errs);
2222 throwRuntimeError(errs);
2229 // //////////////////////////////////////////////////////////////////////
2230 // End of content of file: src/lib_json/json_reader.cpp
2231 // //////////////////////////////////////////////////////////////////////
2238 // //////////////////////////////////////////////////////////////////////
2239 // Beginning of content of file: src/lib_json/json_valueiterator.inl
2240 // //////////////////////////////////////////////////////////////////////
2242 // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
2243 // Distributed under MIT license, or public domain if desired and
2244 // recognized in your jurisdiction.
2245 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
2247 // included by json_value.cpp
2251 // //////////////////////////////////////////////////////////////////
2252 // //////////////////////////////////////////////////////////////////
2253 // //////////////////////////////////////////////////////////////////
2254 // class ValueIteratorBase
2255 // //////////////////////////////////////////////////////////////////
2256 // //////////////////////////////////////////////////////////////////
2257 // //////////////////////////////////////////////////////////////////
2259 ValueIteratorBase::ValueIteratorBase() : current_() {}
2261 ValueIteratorBase::ValueIteratorBase(
2262 const Value::ObjectValues::iterator& current)
2263 : current_(current), isNull_(false) {}
2265 Value& ValueIteratorBase::deref() { return current_->second; }
2266 const Value& ValueIteratorBase::deref() const { return current_->second; }
2268 void ValueIteratorBase::increment() { ++current_; }
2270 void ValueIteratorBase::decrement() { --current_; }
2272 ValueIteratorBase::difference_type
2273 ValueIteratorBase::computeDistance(const SelfType& other) const {
2274 // Iterator for null value are initialized using the default
2275 // constructor, which initialize current_ to the default
2276 // std::map::iterator. As begin() and end() are two instance
2277 // of the default std::map::iterator, they can not be compared.
2278 // To allow this, we handle this comparison specifically.
2279 if (isNull_ && other.isNull_) {
2283 // Usage of std::distance is not portable (does not compile with Sun Studio 12
2285 // which is the one used by default).
2286 // Using a portable hand-made version for non random iterator instead:
2287 // return difference_type( std::distance( current_, other.current_ ) );
2288 difference_type myDistance = 0;
2289 for (Value::ObjectValues::iterator it = current_; it != other.current_;
2296 bool ValueIteratorBase::isEqual(const SelfType& other) const {
2298 return other.isNull_;
2300 return current_ == other.current_;
2303 void ValueIteratorBase::copy(const SelfType& other) {
2304 current_ = other.current_;
2305 isNull_ = other.isNull_;
2308 Value ValueIteratorBase::key() const {
2309 const Value::CZString czstring = (*current_).first;
2310 if (czstring.data()) {
2311 if (czstring.isStaticString())
2312 return Value(StaticString(czstring.data()));
2313 return Value(czstring.data(), czstring.data() + czstring.length());
2315 return Value(czstring.index());
2318 UInt ValueIteratorBase::index() const {
2319 const Value::CZString czstring = (*current_).first;
2320 if (!czstring.data())
2321 return czstring.index();
2322 return Value::UInt(-1);
2325 String ValueIteratorBase::name() const {
2328 keey = memberName(&end);
2331 return String(keey, end);
2334 char const* ValueIteratorBase::memberName() const {
2335 const char* cname = (*current_).first.data();
2336 return cname ? cname : "";
2339 char const* ValueIteratorBase::memberName(char const** end) const {
2340 const char* cname = (*current_).first.data();
2345 *end = cname + (*current_).first.length();
2349 // //////////////////////////////////////////////////////////////////
2350 // //////////////////////////////////////////////////////////////////
2351 // //////////////////////////////////////////////////////////////////
2352 // class ValueConstIterator
2353 // //////////////////////////////////////////////////////////////////
2354 // //////////////////////////////////////////////////////////////////
2355 // //////////////////////////////////////////////////////////////////
2357 ValueConstIterator::ValueConstIterator() = default;
2359 ValueConstIterator::ValueConstIterator(
2360 const Value::ObjectValues::iterator& current)
2361 : ValueIteratorBase(current) {}
2363 ValueConstIterator::ValueConstIterator(ValueIterator const& other)
2364 : ValueIteratorBase(other) {}
2366 ValueConstIterator& ValueConstIterator::
2367 operator=(const ValueIteratorBase& other) {
2372 // //////////////////////////////////////////////////////////////////
2373 // //////////////////////////////////////////////////////////////////
2374 // //////////////////////////////////////////////////////////////////
2375 // class ValueIterator
2376 // //////////////////////////////////////////////////////////////////
2377 // //////////////////////////////////////////////////////////////////
2378 // //////////////////////////////////////////////////////////////////
2380 ValueIterator::ValueIterator() = default;
2382 ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
2383 : ValueIteratorBase(current) {}
2385 ValueIterator::ValueIterator(const ValueConstIterator& other)
2386 : ValueIteratorBase(other) {
2387 throwRuntimeError("ConstIterator to Iterator should never be allowed.");
2390 ValueIterator::ValueIterator(const ValueIterator& other) = default;
2392 ValueIterator& ValueIterator::operator=(const SelfType& other) {
2399 // //////////////////////////////////////////////////////////////////////
2400 // End of content of file: src/lib_json/json_valueiterator.inl
2401 // //////////////////////////////////////////////////////////////////////
2408 // //////////////////////////////////////////////////////////////////////
2409 // Beginning of content of file: src/lib_json/json_value.cpp
2410 // //////////////////////////////////////////////////////////////////////
2412 // Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors
2413 // Distributed under MIT license, or public domain if desired and
2414 // recognized in your jurisdiction.
2415 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
2417 #if !defined(JSON_IS_AMALGAMATION)
2418 #include <json/assertions.h>
2419 #include <json/value.h>
2420 #include <json/writer.h>
2421 #endif // if !defined(JSON_IS_AMALGAMATION)
2422 #include <algorithm>
2431 // Provide implementation equivalent of std::snprintf for older _MSC compilers
2432 #if defined(_MSC_VER) && _MSC_VER < 1900
2434 static int msvc_pre1900_c99_vsnprintf(char* outBuf, size_t size,
2435 const char* format, va_list ap) {
2438 count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
2440 count = _vscprintf(format, ap);
2444 int JSON_API msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
2445 const char* format, ...) {
2447 va_start(ap, format);
2448 const int count = msvc_pre1900_c99_vsnprintf(outBuf, size, format, ap);
2454 // Disable warning C4702 : unreachable code
2455 #if defined(_MSC_VER)
2456 #pragma warning(disable : 4702)
2459 #define JSON_ASSERT_UNREACHABLE assert(false)
2462 template <typename T>
2463 static std::unique_ptr<T> cloneUnique(const std::unique_ptr<T>& p) {
2464 std::unique_ptr<T> r;
2466 r = std::unique_ptr<T>(new T(*p));
2471 // This is a walkaround to avoid the static initialization of Value::null.
2472 // kNull must be word-aligned to avoid crashing on ARM. We use an alignment of
2473 // 8 (instead of 4) as a bit of future-proofing.
2474 #if defined(__ARMEL__)
2475 #define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
2477 #define ALIGNAS(byte_alignment)
2481 Value const& Value::nullSingleton() {
2482 static Value const nullStatic;
2486 #if JSON_USE_NULLREF
2487 // for backwards compatibility, we'll leave these global references around, but
2488 // DO NOT use them in JSONCPP library code any more!
2490 Value const& Value::null = Value::nullSingleton();
2493 Value const& Value::nullRef = Value::nullSingleton();
2496 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2497 template <typename T, typename U>
2498 static inline bool InRange(double d, T min, U max) {
2499 // The casts can lose precision, but we are looking only for
2500 // an approximate range. Might fail on edge cases though. ~cdunn
2501 return d >= static_cast<double>(min) && d <= static_cast<double>(max);
2503 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2504 static inline double integerToDouble(Json::UInt64 value) {
2505 return static_cast<double>(Int64(value / 2)) * 2.0 +
2506 static_cast<double>(Int64(value & 1));
2509 template <typename T> static inline double integerToDouble(T value) {
2510 return static_cast<double>(value);
2513 template <typename T, typename U>
2514 static inline bool InRange(double d, T min, U max) {
2515 return d >= integerToDouble(min) && d <= integerToDouble(max);
2517 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2519 /** Duplicates the specified string value.
2520 * @param value Pointer to the string to duplicate. Must be zero-terminated if
2521 * length is "unknown".
2522 * @param length Length of the value. if equals to unknown, then it will be
2523 * computed using strlen(value).
2524 * @return Pointer on the duplicate instance of string.
2526 static inline char* duplicateStringValue(const char* value, size_t length) {
2527 // Avoid an integer overflow in the call to malloc below by limiting length
2529 if (length >= static_cast<size_t>(Value::maxInt))
2530 length = Value::maxInt - 1;
2532 auto newString = static_cast<char*>(malloc(length + 1));
2533 if (newString == nullptr) {
2534 throwRuntimeError("in Json::Value::duplicateStringValue(): "
2535 "Failed to allocate string value buffer");
2537 memcpy(newString, value, length);
2538 newString[length] = 0;
2542 /* Record the length as a prefix.
2544 static inline char* duplicateAndPrefixStringValue(const char* value,
2545 unsigned int length) {
2546 // Avoid an integer overflow in the call to malloc below by limiting length
2548 JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) -
2549 sizeof(unsigned) - 1U,
2550 "in Json::Value::duplicateAndPrefixStringValue(): "
2551 "length too big for prefixing");
2552 size_t actualLength = sizeof(length) + length + 1;
2553 auto newString = static_cast<char*>(malloc(actualLength));
2554 if (newString == nullptr) {
2555 throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "
2556 "Failed to allocate string value buffer");
2558 *reinterpret_cast<unsigned*>(newString) = length;
2559 memcpy(newString + sizeof(unsigned), value, length);
2560 newString[actualLength - 1U] =
2561 0; // to avoid buffer over-run accidents by users later
2564 inline static void decodePrefixedString(bool isPrefixed, char const* prefixed,
2565 unsigned* length, char const** value) {
2567 *length = static_cast<unsigned>(strlen(prefixed));
2570 *length = *reinterpret_cast<unsigned const*>(prefixed);
2571 *value = prefixed + sizeof(unsigned);
2574 /** Free the string duplicated by
2575 * duplicateStringValue()/duplicateAndPrefixStringValue().
2577 #if JSONCPP_USING_SECURE_MEMORY
2578 static inline void releasePrefixedStringValue(char* value) {
2579 unsigned length = 0;
2580 char const* valueDecoded;
2581 decodePrefixedString(true, value, &length, &valueDecoded);
2582 size_t const size = sizeof(unsigned) + length + 1U;
2583 memset(value, 0, size);
2586 static inline void releaseStringValue(char* value, unsigned length) {
2587 // length==0 => we allocated the strings memory
2588 size_t size = (length == 0) ? strlen(value) : length;
2589 memset(value, 0, size);
2592 #else // !JSONCPP_USING_SECURE_MEMORY
2593 static inline void releasePrefixedStringValue(char* value) { free(value); }
2594 static inline void releaseStringValue(char* value, unsigned) { free(value); }
2595 #endif // JSONCPP_USING_SECURE_MEMORY
2599 // //////////////////////////////////////////////////////////////////
2600 // //////////////////////////////////////////////////////////////////
2601 // //////////////////////////////////////////////////////////////////
2602 // ValueInternals...
2603 // //////////////////////////////////////////////////////////////////
2604 // //////////////////////////////////////////////////////////////////
2605 // //////////////////////////////////////////////////////////////////
2606 #if !defined(JSON_IS_AMALGAMATION)
2608 #include "json_valueiterator.inl"
2609 #endif // if !defined(JSON_IS_AMALGAMATION)
2613 #if JSON_USE_EXCEPTION
2614 Exception::Exception(String msg) : msg_(std::move(msg)) {}
2615 Exception::~Exception() noexcept = default;
2616 char const* Exception::what() const noexcept { return msg_.c_str(); }
2617 RuntimeError::RuntimeError(String const& msg) : Exception(msg) {}
2618 LogicError::LogicError(String const& msg) : Exception(msg) {}
2619 JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
2620 throw RuntimeError(msg);
2622 JSONCPP_NORETURN void throwLogicError(String const& msg) {
2623 throw LogicError(msg);
2625 #else // !JSON_USE_EXCEPTION
2626 JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
2627 std::cerr << msg << std::endl;
2630 JSONCPP_NORETURN void throwLogicError(String const& msg) {
2631 std::cerr << msg << std::endl;
2636 // //////////////////////////////////////////////////////////////////
2637 // //////////////////////////////////////////////////////////////////
2638 // //////////////////////////////////////////////////////////////////
2639 // class Value::CZString
2640 // //////////////////////////////////////////////////////////////////
2641 // //////////////////////////////////////////////////////////////////
2642 // //////////////////////////////////////////////////////////////////
2644 // Notes: policy_ indicates if the string was allocated when
2645 // a string is stored.
2647 Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {}
2649 Value::CZString::CZString(char const* str, unsigned length,
2650 DuplicationPolicy allocate)
2652 // allocate != duplicate
2653 storage_.policy_ = allocate & 0x3;
2654 storage_.length_ = length & 0x3FFFFFFF;
2657 Value::CZString::CZString(const CZString& other) {
2658 cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr
2659 ? duplicateStringValue(other.cstr_, other.storage_.length_)
2662 static_cast<unsigned>(
2664 ? (static_cast<DuplicationPolicy>(other.storage_.policy_) ==
2668 : static_cast<DuplicationPolicy>(other.storage_.policy_)) &
2670 storage_.length_ = other.storage_.length_;
2673 Value::CZString::CZString(CZString&& other)
2674 : cstr_(other.cstr_), index_(other.index_) {
2675 other.cstr_ = nullptr;
2678 Value::CZString::~CZString() {
2679 if (cstr_ && storage_.policy_ == duplicate) {
2680 releaseStringValue(const_cast<char*>(cstr_),
2681 storage_.length_ + 1U); // +1 for null terminating
2682 // character for sake of
2683 // completeness but not actually
2688 void Value::CZString::swap(CZString& other) {
2689 std::swap(cstr_, other.cstr_);
2690 std::swap(index_, other.index_);
2693 Value::CZString& Value::CZString::operator=(const CZString& other) {
2694 cstr_ = other.cstr_;
2695 index_ = other.index_;
2699 Value::CZString& Value::CZString::operator=(CZString&& other) {
2700 cstr_ = other.cstr_;
2701 index_ = other.index_;
2702 other.cstr_ = nullptr;
2706 bool Value::CZString::operator<(const CZString& other) const {
2708 return index_ < other.index_;
2709 // return strcmp(cstr_, other.cstr_) < 0;
2710 // Assume both are strings.
2711 unsigned this_len = this->storage_.length_;
2712 unsigned other_len = other.storage_.length_;
2713 unsigned min_len = std::min<unsigned>(this_len, other_len);
2714 JSON_ASSERT(this->cstr_ && other.cstr_);
2715 int comp = memcmp(this->cstr_, other.cstr_, min_len);
2720 return (this_len < other_len);
2723 bool Value::CZString::operator==(const CZString& other) const {
2725 return index_ == other.index_;
2726 // return strcmp(cstr_, other.cstr_) == 0;
2727 // Assume both are strings.
2728 unsigned this_len = this->storage_.length_;
2729 unsigned other_len = other.storage_.length_;
2730 if (this_len != other_len)
2732 JSON_ASSERT(this->cstr_ && other.cstr_);
2733 int comp = memcmp(this->cstr_, other.cstr_, this_len);
2737 ArrayIndex Value::CZString::index() const { return index_; }
2739 // const char* Value::CZString::c_str() const { return cstr_; }
2740 const char* Value::CZString::data() const { return cstr_; }
2741 unsigned Value::CZString::length() const { return storage_.length_; }
2742 bool Value::CZString::isStaticString() const {
2743 return storage_.policy_ == noDuplication;
2746 // //////////////////////////////////////////////////////////////////
2747 // //////////////////////////////////////////////////////////////////
2748 // //////////////////////////////////////////////////////////////////
2749 // class Value::Value
2750 // //////////////////////////////////////////////////////////////////
2751 // //////////////////////////////////////////////////////////////////
2752 // //////////////////////////////////////////////////////////////////
2754 /*! \internal Default constructor initialization must be equivalent to:
2755 * memset( this, 0, sizeof(Value) )
2756 * This optimization is used in ValueInternalMap fast allocator.
2758 Value::Value(ValueType type) {
2759 static char const emptyString[] = "";
2772 // allocated_ == false, so this is safe.
2773 value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString));
2777 value_.map_ = new ObjectValues();
2780 value_.bool_ = false;
2783 JSON_ASSERT_UNREACHABLE;
2787 Value::Value(Int value) {
2788 initBasic(intValue);
2789 value_.int_ = value;
2792 Value::Value(UInt value) {
2793 initBasic(uintValue);
2794 value_.uint_ = value;
2796 #if defined(JSON_HAS_INT64)
2797 Value::Value(Int64 value) {
2798 initBasic(intValue);
2799 value_.int_ = value;
2801 Value::Value(UInt64 value) {
2802 initBasic(uintValue);
2803 value_.uint_ = value;
2805 #endif // defined(JSON_HAS_INT64)
2807 Value::Value(double value) {
2808 initBasic(realValue);
2809 value_.real_ = value;
2812 Value::Value(const char* value) {
2813 initBasic(stringValue, true);
2814 JSON_ASSERT_MESSAGE(value != nullptr,
2815 "Null Value Passed to Value Constructor");
2816 value_.string_ = duplicateAndPrefixStringValue(
2817 value, static_cast<unsigned>(strlen(value)));
2820 Value::Value(const char* begin, const char* end) {
2821 initBasic(stringValue, true);
2823 duplicateAndPrefixStringValue(begin, static_cast<unsigned>(end - begin));
2826 Value::Value(const String& value) {
2827 initBasic(stringValue, true);
2828 value_.string_ = duplicateAndPrefixStringValue(
2829 value.data(), static_cast<unsigned>(value.length()));
2832 Value::Value(const StaticString& value) {
2833 initBasic(stringValue);
2834 value_.string_ = const_cast<char*>(value.c_str());
2837 Value::Value(bool value) {
2838 initBasic(booleanValue);
2839 value_.bool_ = value;
2842 Value::Value(const Value& other) {
2847 Value::Value(Value&& other) {
2848 initBasic(nullValue);
2857 Value& Value::operator=(const Value& other) {
2858 Value(other).swap(*this);
2862 Value& Value::operator=(Value&& other) {
2867 void Value::swapPayload(Value& other) {
2868 std::swap(bits_, other.bits_);
2869 std::swap(value_, other.value_);
2872 void Value::copyPayload(const Value& other) {
2877 void Value::swap(Value& other) {
2879 std::swap(comments_, other.comments_);
2880 std::swap(start_, other.start_);
2881 std::swap(limit_, other.limit_);
2884 void Value::copy(const Value& other) {
2889 ValueType Value::type() const {
2890 return static_cast<ValueType>(bits_.value_type_);
2893 int Value::compare(const Value& other) const {
2901 bool Value::operator<(const Value& other) const {
2902 int typeDelta = type() - other.type();
2904 return typeDelta < 0;
2909 return value_.int_ < other.value_.int_;
2911 return value_.uint_ < other.value_.uint_;
2913 return value_.real_ < other.value_.real_;
2915 return value_.bool_ < other.value_.bool_;
2917 if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
2918 return other.value_.string_ != nullptr;
2922 char const* this_str;
2923 char const* other_str;
2924 decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
2926 decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
2928 unsigned min_len = std::min<unsigned>(this_len, other_len);
2929 JSON_ASSERT(this_str && other_str);
2930 int comp = memcmp(this_str, other_str, min_len);
2935 return (this_len < other_len);
2939 auto thisSize = value_.map_->size();
2940 auto otherSize = other.value_.map_->size();
2941 if (thisSize != otherSize)
2942 return thisSize < otherSize;
2943 return (*value_.map_) < (*other.value_.map_);
2946 JSON_ASSERT_UNREACHABLE;
2948 return false; // unreachable
2951 bool Value::operator<=(const Value& other) const { return !(other < *this); }
2953 bool Value::operator>=(const Value& other) const { return !(*this < other); }
2955 bool Value::operator>(const Value& other) const { return other < *this; }
2957 bool Value::operator==(const Value& other) const {
2958 if (type() != other.type())
2964 return value_.int_ == other.value_.int_;
2966 return value_.uint_ == other.value_.uint_;
2968 return value_.real_ == other.value_.real_;
2970 return value_.bool_ == other.value_.bool_;
2972 if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
2973 return (value_.string_ == other.value_.string_);
2977 char const* this_str;
2978 char const* other_str;
2979 decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
2981 decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
2983 if (this_len != other_len)
2985 JSON_ASSERT(this_str && other_str);
2986 int comp = memcmp(this_str, other_str, this_len);
2991 return value_.map_->size() == other.value_.map_->size() &&
2992 (*value_.map_) == (*other.value_.map_);
2994 JSON_ASSERT_UNREACHABLE;
2996 return false; // unreachable
2999 bool Value::operator!=(const Value& other) const { return !(*this == other); }
3001 const char* Value::asCString() const {
3002 JSON_ASSERT_MESSAGE(type() == stringValue,
3003 "in Json::Value::asCString(): requires stringValue");
3004 if (value_.string_ == nullptr)
3007 char const* this_str;
3008 decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
3013 #if JSONCPP_USING_SECURE_MEMORY
3014 unsigned Value::getCStringLength() const {
3015 JSON_ASSERT_MESSAGE(type() == stringValue,
3016 "in Json::Value::asCString(): requires stringValue");
3017 if (value_.string_ == 0)
3020 char const* this_str;
3021 decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
3027 bool Value::getString(char const** begin, char const** end) const {
3028 if (type() != stringValue)
3030 if (value_.string_ == nullptr)
3033 decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
3035 *end = *begin + length;
3039 String Value::asString() const {
3044 if (value_.string_ == nullptr)
3047 char const* this_str;
3048 decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
3050 return String(this_str, this_len);
3053 return value_.bool_ ? "true" : "false";
3055 return valueToString(value_.int_);
3057 return valueToString(value_.uint_);
3059 return valueToString(value_.real_);
3061 JSON_FAIL_MESSAGE("Type is not convertible to string");
3065 Value::Int Value::asInt() const {
3068 JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
3069 return Int(value_.int_);
3071 JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
3072 return Int(value_.uint_);
3074 JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
3075 "double out of Int range");
3076 return Int(value_.real_);
3080 return value_.bool_ ? 1 : 0;
3084 JSON_FAIL_MESSAGE("Value is not convertible to Int.");
3087 Value::UInt Value::asUInt() const {
3090 JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
3091 return UInt(value_.int_);
3093 JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
3094 return UInt(value_.uint_);
3096 JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
3097 "double out of UInt range");
3098 return UInt(value_.real_);
3102 return value_.bool_ ? 1 : 0;
3106 JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
3109 #if defined(JSON_HAS_INT64)
3111 Value::Int64 Value::asInt64() const {
3114 return Int64(value_.int_);
3116 JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
3117 return Int64(value_.uint_);
3119 JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
3120 "double out of Int64 range");
3121 return Int64(value_.real_);
3125 return value_.bool_ ? 1 : 0;
3129 JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
3132 Value::UInt64 Value::asUInt64() const {
3135 JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
3136 return UInt64(value_.int_);
3138 return UInt64(value_.uint_);
3140 JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
3141 "double out of UInt64 range");
3142 return UInt64(value_.real_);
3146 return value_.bool_ ? 1 : 0;
3150 JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
3152 #endif // if defined(JSON_HAS_INT64)
3154 LargestInt Value::asLargestInt() const {
3155 #if defined(JSON_NO_INT64)
3162 LargestUInt Value::asLargestUInt() const {
3163 #if defined(JSON_NO_INT64)
3170 double Value::asDouble() const {
3173 return static_cast<double>(value_.int_);
3175 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3176 return static_cast<double>(value_.uint_);
3177 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3178 return integerToDouble(value_.uint_);
3179 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3181 return value_.real_;
3185 return value_.bool_ ? 1.0 : 0.0;
3189 JSON_FAIL_MESSAGE("Value is not convertible to double.");
3192 float Value::asFloat() const {
3195 return static_cast<float>(value_.int_);
3197 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3198 return static_cast<float>(value_.uint_);
3199 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3200 // This can fail (silently?) if the value is bigger than MAX_FLOAT.
3201 return static_cast<float>(integerToDouble(value_.uint_));
3202 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3204 return static_cast<float>(value_.real_);
3208 return value_.bool_ ? 1.0F : 0.0F;
3212 JSON_FAIL_MESSAGE("Value is not convertible to float.");
3215 bool Value::asBool() const {
3218 return value_.bool_;
3222 return value_.int_ != 0;
3224 return value_.uint_ != 0;
3226 // According to JavaScript language zero or NaN is regarded as false
3227 const auto value_classification = std::fpclassify(value_.real_);
3228 return value_classification != FP_ZERO && value_classification != FP_NAN;
3233 JSON_FAIL_MESSAGE("Value is not convertible to bool.");
3236 bool Value::isConvertibleTo(ValueType other) const {
3239 return (isNumeric() && asDouble() == 0.0) ||
3240 (type() == booleanValue && !value_.bool_) ||
3241 (type() == stringValue && asString().empty()) ||
3242 (type() == arrayValue && value_.map_->empty()) ||
3243 (type() == objectValue && value_.map_->empty()) ||
3244 type() == nullValue;
3247 (type() == realValue && InRange(value_.real_, minInt, maxInt)) ||
3248 type() == booleanValue || type() == nullValue;
3251 (type() == realValue && InRange(value_.real_, 0, maxUInt)) ||
3252 type() == booleanValue || type() == nullValue;
3254 return isNumeric() || type() == booleanValue || type() == nullValue;
3256 return isNumeric() || type() == booleanValue || type() == nullValue;
3258 return isNumeric() || type() == booleanValue || type() == stringValue ||
3259 type() == nullValue;
3261 return type() == arrayValue || type() == nullValue;
3263 return type() == objectValue || type() == nullValue;
3265 JSON_ASSERT_UNREACHABLE;
3269 /// Number of values in array or object
3270 ArrayIndex Value::size() const {
3279 case arrayValue: // size of the array is highest index + 1
3280 if (!value_.map_->empty()) {
3281 ObjectValues::const_iterator itLast = value_.map_->end();
3283 return (*itLast).first.index() + 1;
3287 return ArrayIndex(value_.map_->size());
3289 JSON_ASSERT_UNREACHABLE;
3290 return 0; // unreachable;
3293 bool Value::empty() const {
3294 if (isNull() || isArray() || isObject())
3295 return size() == 0U;
3299 Value::operator bool() const { return !isNull(); }
3301 void Value::clear() {
3302 JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue ||
3303 type() == objectValue,
3304 "in Json::Value::clear(): requires complex value");
3310 value_.map_->clear();
3317 void Value::resize(ArrayIndex newSize) {
3318 JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
3319 "in Json::Value::resize(): requires arrayValue");
3320 if (type() == nullValue)
3321 *this = Value(arrayValue);
3322 ArrayIndex oldSize = size();
3325 else if (newSize > oldSize)
3326 this->operator[](newSize - 1);
3328 for (ArrayIndex index = newSize; index < oldSize; ++index) {
3329 value_.map_->erase(index);
3331 JSON_ASSERT(size() == newSize);
3335 Value& Value::operator[](ArrayIndex index) {
3336 JSON_ASSERT_MESSAGE(
3337 type() == nullValue || type() == arrayValue,
3338 "in Json::Value::operator[](ArrayIndex): requires arrayValue");
3339 if (type() == nullValue)
3340 *this = Value(arrayValue);
3341 CZString key(index);
3342 auto it = value_.map_->lower_bound(key);
3343 if (it != value_.map_->end() && (*it).first == key)
3344 return (*it).second;
3346 ObjectValues::value_type defaultValue(key, nullSingleton());
3347 it = value_.map_->insert(it, defaultValue);
3348 return (*it).second;
3351 Value& Value::operator[](int index) {
3352 JSON_ASSERT_MESSAGE(
3354 "in Json::Value::operator[](int index): index cannot be negative");
3355 return (*this)[ArrayIndex(index)];
3358 const Value& Value::operator[](ArrayIndex index) const {
3359 JSON_ASSERT_MESSAGE(
3360 type() == nullValue || type() == arrayValue,
3361 "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
3362 if (type() == nullValue)
3363 return nullSingleton();
3364 CZString key(index);
3365 ObjectValues::const_iterator it = value_.map_->find(key);
3366 if (it == value_.map_->end())
3367 return nullSingleton();
3368 return (*it).second;
3371 const Value& Value::operator[](int index) const {
3372 JSON_ASSERT_MESSAGE(
3374 "in Json::Value::operator[](int index) const: index cannot be negative");
3375 return (*this)[ArrayIndex(index)];
3378 void Value::initBasic(ValueType type, bool allocated) {
3380 setIsAllocated(allocated);
3381 comments_ = Comments{};
3386 void Value::dupPayload(const Value& other) {
3387 setType(other.type());
3388 setIsAllocated(false);
3395 value_ = other.value_;
3398 if (other.value_.string_ && other.isAllocated()) {
3401 decodePrefixedString(other.isAllocated(), other.value_.string_, &len,
3403 value_.string_ = duplicateAndPrefixStringValue(str, len);
3404 setIsAllocated(true);
3406 value_.string_ = other.value_.string_;
3411 value_.map_ = new ObjectValues(*other.value_.map_);
3414 JSON_ASSERT_UNREACHABLE;
3418 void Value::releasePayload() {
3428 releasePrefixedStringValue(value_.string_);
3435 JSON_ASSERT_UNREACHABLE;
3439 void Value::dupMeta(const Value& other) {
3440 comments_ = other.comments_;
3441 start_ = other.start_;
3442 limit_ = other.limit_;
3445 // Access an object value by name, create a null member if it does not exist.
3446 // @pre Type of '*this' is object or null.
3447 // @param key is null-terminated.
3448 Value& Value::resolveReference(const char* key) {
3449 JSON_ASSERT_MESSAGE(
3450 type() == nullValue || type() == objectValue,
3451 "in Json::Value::resolveReference(): requires objectValue");
3452 if (type() == nullValue)
3453 *this = Value(objectValue);
3454 CZString actualKey(key, static_cast<unsigned>(strlen(key)),
3455 CZString::noDuplication); // NOTE!
3456 auto it = value_.map_->lower_bound(actualKey);
3457 if (it != value_.map_->end() && (*it).first == actualKey)
3458 return (*it).second;
3460 ObjectValues::value_type defaultValue(actualKey, nullSingleton());
3461 it = value_.map_->insert(it, defaultValue);
3462 Value& value = (*it).second;
3466 // @param key is not null-terminated.
3467 Value& Value::resolveReference(char const* key, char const* end) {
3468 JSON_ASSERT_MESSAGE(
3469 type() == nullValue || type() == objectValue,
3470 "in Json::Value::resolveReference(key, end): requires objectValue");
3471 if (type() == nullValue)
3472 *this = Value(objectValue);
3473 CZString actualKey(key, static_cast<unsigned>(end - key),
3474 CZString::duplicateOnCopy);
3475 auto it = value_.map_->lower_bound(actualKey);
3476 if (it != value_.map_->end() && (*it).first == actualKey)
3477 return (*it).second;
3479 ObjectValues::value_type defaultValue(actualKey, nullSingleton());
3480 it = value_.map_->insert(it, defaultValue);
3481 Value& value = (*it).second;
3485 Value Value::get(ArrayIndex index, const Value& defaultValue) const {
3486 const Value* value = &((*this)[index]);
3487 return value == &nullSingleton() ? defaultValue : *value;
3490 bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
3492 Value const* Value::find(char const* begin, char const* end) const {
3493 JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
3494 "in Json::Value::find(begin, end): requires "
3495 "objectValue or nullValue");
3496 if (type() == nullValue)
3498 CZString actualKey(begin, static_cast<unsigned>(end - begin),
3499 CZString::noDuplication);
3500 ObjectValues::const_iterator it = value_.map_->find(actualKey);
3501 if (it == value_.map_->end())
3503 return &(*it).second;
3505 Value* Value::demand(char const* begin, char const* end) {
3506 JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
3507 "in Json::Value::demand(begin, end): requires "
3508 "objectValue or nullValue");
3509 return &resolveReference(begin, end);
3511 const Value& Value::operator[](const char* key) const {
3512 Value const* found = find(key, key + strlen(key));
3514 return nullSingleton();
3517 Value const& Value::operator[](const String& key) const {
3518 Value const* found = find(key.data(), key.data() + key.length());
3520 return nullSingleton();
3524 Value& Value::operator[](const char* key) {
3525 return resolveReference(key, key + strlen(key));
3528 Value& Value::operator[](const String& key) {
3529 return resolveReference(key.data(), key.data() + key.length());
3532 Value& Value::operator[](const StaticString& key) {
3533 return resolveReference(key.c_str());
3536 Value& Value::append(const Value& value) { return append(Value(value)); }
3538 Value& Value::append(Value&& value) {
3539 JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
3540 "in Json::Value::append: requires arrayValue");
3541 if (type() == nullValue) {
3542 *this = Value(arrayValue);
3544 return this->value_.map_->emplace(size(), std::move(value)).first->second;
3547 bool Value::insert(ArrayIndex index, const Value& newValue) {
3548 return insert(index, Value(newValue));
3551 bool Value::insert(ArrayIndex index, Value&& newValue) {
3552 JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
3553 "in Json::Value::insert: requires arrayValue");
3554 ArrayIndex length = size();
3555 if (index > length) {
3558 for (ArrayIndex i = length; i > index; i--) {
3559 (*this)[i] = std::move((*this)[i - 1]);
3561 (*this)[index] = std::move(newValue);
3565 Value Value::get(char const* begin, char const* end,
3566 Value const& defaultValue) const {
3567 Value const* found = find(begin, end);
3568 return !found ? defaultValue : *found;
3570 Value Value::get(char const* key, Value const& defaultValue) const {
3571 return get(key, key + strlen(key), defaultValue);
3573 Value Value::get(String const& key, Value const& defaultValue) const {
3574 return get(key.data(), key.data() + key.length(), defaultValue);
3577 bool Value::removeMember(const char* begin, const char* end, Value* removed) {
3578 if (type() != objectValue) {
3581 CZString actualKey(begin, static_cast<unsigned>(end - begin),
3582 CZString::noDuplication);
3583 auto it = value_.map_->find(actualKey);
3584 if (it == value_.map_->end())
3587 *removed = std::move(it->second);
3588 value_.map_->erase(it);
3591 bool Value::removeMember(const char* key, Value* removed) {
3592 return removeMember(key, key + strlen(key), removed);
3594 bool Value::removeMember(String const& key, Value* removed) {
3595 return removeMember(key.data(), key.data() + key.length(), removed);
3597 void Value::removeMember(const char* key) {
3598 JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
3599 "in Json::Value::removeMember(): requires objectValue");
3600 if (type() == nullValue)
3603 CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication);
3604 value_.map_->erase(actualKey);
3606 void Value::removeMember(const String& key) { removeMember(key.c_str()); }
3608 bool Value::removeIndex(ArrayIndex index, Value* removed) {
3609 if (type() != arrayValue) {
3612 CZString key(index);
3613 auto it = value_.map_->find(key);
3614 if (it == value_.map_->end()) {
3618 *removed = it->second;
3619 ArrayIndex oldSize = size();
3620 // shift left all items left, into the place of the "removed"
3621 for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
3623 (*value_.map_)[keey] = (*this)[i + 1];
3625 // erase the last one ("leftover")
3626 CZString keyLast(oldSize - 1);
3627 auto itLast = value_.map_->find(keyLast);
3628 value_.map_->erase(itLast);
3632 bool Value::isMember(char const* begin, char const* end) const {
3633 Value const* value = find(begin, end);
3634 return nullptr != value;
3636 bool Value::isMember(char const* key) const {
3637 return isMember(key, key + strlen(key));
3639 bool Value::isMember(String const& key) const {
3640 return isMember(key.data(), key.data() + key.length());
3643 Value::Members Value::getMemberNames() const {
3644 JSON_ASSERT_MESSAGE(
3645 type() == nullValue || type() == objectValue,
3646 "in Json::Value::getMemberNames(), value must be objectValue");
3647 if (type() == nullValue)
3648 return Value::Members();
3650 members.reserve(value_.map_->size());
3651 ObjectValues::const_iterator it = value_.map_->begin();
3652 ObjectValues::const_iterator itEnd = value_.map_->end();
3653 for (; it != itEnd; ++it) {
3654 members.push_back(String((*it).first.data(), (*it).first.length()));
3659 static bool IsIntegral(double d) {
3660 double integral_part;
3661 return modf(d, &integral_part) == 0.0;
3664 bool Value::isNull() const { return type() == nullValue; }
3666 bool Value::isBool() const { return type() == booleanValue; }
3668 bool Value::isInt() const {
3671 #if defined(JSON_HAS_INT64)
3672 return value_.int_ >= minInt && value_.int_ <= maxInt;
3677 return value_.uint_ <= UInt(maxInt);
3679 return value_.real_ >= minInt && value_.real_ <= maxInt &&
3680 IsIntegral(value_.real_);
3687 bool Value::isUInt() const {
3690 #if defined(JSON_HAS_INT64)
3691 return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
3693 return value_.int_ >= 0;
3696 #if defined(JSON_HAS_INT64)
3697 return value_.uint_ <= maxUInt;
3702 return value_.real_ >= 0 && value_.real_ <= maxUInt &&
3703 IsIntegral(value_.real_);
3710 bool Value::isInt64() const {
3711 #if defined(JSON_HAS_INT64)
3716 return value_.uint_ <= UInt64(maxInt64);
3718 // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
3719 // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
3720 // require the value to be strictly less than the limit.
3721 return value_.real_ >= double(minInt64) &&
3722 value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
3726 #endif // JSON_HAS_INT64
3730 bool Value::isUInt64() const {
3731 #if defined(JSON_HAS_INT64)
3734 return value_.int_ >= 0;
3738 // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
3739 // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
3740 // require the value to be strictly less than the limit.
3741 return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
3742 IsIntegral(value_.real_);
3746 #endif // JSON_HAS_INT64
3750 bool Value::isIntegral() const {
3756 #if defined(JSON_HAS_INT64)
3757 // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
3758 // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
3759 // require the value to be strictly less than the limit.
3760 return value_.real_ >= double(minInt64) &&
3761 value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
3763 return value_.real_ >= minInt && value_.real_ <= maxUInt &&
3764 IsIntegral(value_.real_);
3765 #endif // JSON_HAS_INT64
3772 bool Value::isDouble() const {
3773 return type() == intValue || type() == uintValue || type() == realValue;
3776 bool Value::isNumeric() const { return isDouble(); }
3778 bool Value::isString() const { return type() == stringValue; }
3780 bool Value::isArray() const { return type() == arrayValue; }
3782 bool Value::isObject() const { return type() == objectValue; }
3784 Value::Comments::Comments(const Comments& that)
3785 : ptr_{cloneUnique(that.ptr_)} {}
3787 Value::Comments::Comments(Comments&& that) : ptr_{std::move(that.ptr_)} {}
3789 Value::Comments& Value::Comments::operator=(const Comments& that) {
3790 ptr_ = cloneUnique(that.ptr_);
3794 Value::Comments& Value::Comments::operator=(Comments&& that) {
3795 ptr_ = std::move(that.ptr_);
3799 bool Value::Comments::has(CommentPlacement slot) const {
3800 return ptr_ && !(*ptr_)[slot].empty();
3803 String Value::Comments::get(CommentPlacement slot) const {
3806 return (*ptr_)[slot];
3809 void Value::Comments::set(CommentPlacement slot, String comment) {
3811 ptr_ = std::unique_ptr<Array>(new Array());
3813 // check comments array boundry.
3814 if (slot < CommentPlacement::numberOfCommentPlacement) {
3815 (*ptr_)[slot] = std::move(comment);
3819 void Value::setComment(String comment, CommentPlacement placement) {
3820 if (!comment.empty() && (comment.back() == '\n')) {
3821 // Always discard trailing newline, to aid indentation.
3824 JSON_ASSERT(!comment.empty());
3825 JSON_ASSERT_MESSAGE(
3826 comment[0] == '\0' || comment[0] == '/',
3827 "in Json::Value::setComment(): Comments must start with /");
3828 comments_.set(placement, std::move(comment));
3831 bool Value::hasComment(CommentPlacement placement) const {
3832 return comments_.has(placement);
3835 String Value::getComment(CommentPlacement placement) const {
3836 return comments_.get(placement);
3839 void Value::setOffsetStart(ptrdiff_t start) { start_ = start; }
3841 void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; }
3843 ptrdiff_t Value::getOffsetStart() const { return start_; }
3845 ptrdiff_t Value::getOffsetLimit() const { return limit_; }
3847 String Value::toStyledString() const {
3848 StreamWriterBuilder builder;
3850 String out = this->hasComment(commentBefore) ? "\n" : "";
3851 out += Json::writeString(builder, *this);
3857 Value::const_iterator Value::begin() const {
3862 return const_iterator(value_.map_->begin());
3870 Value::const_iterator Value::end() const {
3875 return const_iterator(value_.map_->end());
3883 Value::iterator Value::begin() {
3888 return iterator(value_.map_->begin());
3896 Value::iterator Value::end() {
3901 return iterator(value_.map_->end());
3909 // class PathArgument
3910 // //////////////////////////////////////////////////////////////////
3912 PathArgument::PathArgument() = default;
3914 PathArgument::PathArgument(ArrayIndex index)
3915 : index_(index), kind_(kindIndex) {}
3917 PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {}
3919 PathArgument::PathArgument(String key) : key_(std::move(key)), kind_(kindKey) {}
3922 // //////////////////////////////////////////////////////////////////
3924 Path::Path(const String& path, const PathArgument& a1, const PathArgument& a2,
3925 const PathArgument& a3, const PathArgument& a4,
3926 const PathArgument& a5) {
3937 void Path::makePath(const String& path, const InArgs& in) {
3938 const char* current = path.c_str();
3939 const char* end = current + path.length();
3940 auto itInArg = in.begin();
3941 while (current != end) {
3942 if (*current == '[') {
3944 if (*current == '%')
3945 addPathInArg(path, in, itInArg, PathArgument::kindIndex);
3947 ArrayIndex index = 0;
3948 for (; current != end && *current >= '0' && *current <= '9'; ++current)
3949 index = index * 10 + ArrayIndex(*current - '0');
3950 args_.push_back(index);
3952 if (current == end || *++current != ']')
3953 invalidPath(path, int(current - path.c_str()));
3954 } else if (*current == '%') {
3955 addPathInArg(path, in, itInArg, PathArgument::kindKey);
3957 } else if (*current == '.' || *current == ']') {
3960 const char* beginName = current;
3961 while (current != end && !strchr("[.", *current))
3963 args_.push_back(String(beginName, current));
3968 void Path::addPathInArg(const String& /*path*/, const InArgs& in,
3969 InArgs::const_iterator& itInArg,
3970 PathArgument::Kind kind) {
3971 if (itInArg == in.end()) {
3972 // Error: missing argument %d
3973 } else if ((*itInArg)->kind_ != kind) {
3974 // Error: bad argument type
3976 args_.push_back(**itInArg++);
3980 void Path::invalidPath(const String& /*path*/, int /*location*/) {
3981 // Error: invalid path.
3984 const Value& Path::resolve(const Value& root) const {
3985 const Value* node = &root;
3986 for (const auto& arg : args_) {
3987 if (arg.kind_ == PathArgument::kindIndex) {
3988 if (!node->isArray() || !node->isValidIndex(arg.index_)) {
3989 // Error: unable to resolve path (array value expected at position... )
3990 return Value::nullSingleton();
3992 node = &((*node)[arg.index_]);
3993 } else if (arg.kind_ == PathArgument::kindKey) {
3994 if (!node->isObject()) {
3995 // Error: unable to resolve path (object value expected at position...)
3996 return Value::nullSingleton();
3998 node = &((*node)[arg.key_]);
3999 if (node == &Value::nullSingleton()) {
4000 // Error: unable to resolve path (object has no member named '' at
4002 return Value::nullSingleton();
4009 Value Path::resolve(const Value& root, const Value& defaultValue) const {
4010 const Value* node = &root;
4011 for (const auto& arg : args_) {
4012 if (arg.kind_ == PathArgument::kindIndex) {
4013 if (!node->isArray() || !node->isValidIndex(arg.index_))
4014 return defaultValue;
4015 node = &((*node)[arg.index_]);
4016 } else if (arg.kind_ == PathArgument::kindKey) {
4017 if (!node->isObject())
4018 return defaultValue;
4019 node = &((*node)[arg.key_]);
4020 if (node == &Value::nullSingleton())
4021 return defaultValue;
4027 Value& Path::make(Value& root) const {
4028 Value* node = &root;
4029 for (const auto& arg : args_) {
4030 if (arg.kind_ == PathArgument::kindIndex) {
4031 if (!node->isArray()) {
4032 // Error: node is not an array at position ...
4034 node = &((*node)[arg.index_]);
4035 } else if (arg.kind_ == PathArgument::kindKey) {
4036 if (!node->isObject()) {
4037 // Error: node is not an object at position...
4039 node = &((*node)[arg.key_]);
4047 // //////////////////////////////////////////////////////////////////////
4048 // End of content of file: src/lib_json/json_value.cpp
4049 // //////////////////////////////////////////////////////////////////////
4056 // //////////////////////////////////////////////////////////////////////
4057 // Beginning of content of file: src/lib_json/json_writer.cpp
4058 // //////////////////////////////////////////////////////////////////////
4060 // Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors
4061 // Distributed under MIT license, or public domain if desired and
4062 // recognized in your jurisdiction.
4063 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
4065 #if !defined(JSON_IS_AMALGAMATION)
4066 #include "json_tool.h"
4067 #include <json/writer.h>
4068 #endif // if !defined(JSON_IS_AMALGAMATION)
4069 #include <algorithm>
4079 #if __cplusplus >= 201103L
4084 #define isnan std::isnan
4087 #if !defined(isfinite)
4088 #define isfinite std::isfinite
4095 #if defined(_MSC_VER)
4098 #define isnan _isnan
4101 #if !defined(isfinite)
4103 #define isfinite _finite
4106 #if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
4107 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
4108 #endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
4112 #if defined(__sun) && defined(__SVR4) // Solaris
4113 #if !defined(isfinite)
4115 #define isfinite finite
4120 #if !defined(isfinite)
4121 #if defined(__ia64) && !defined(finite)
4122 #define isfinite(x) \
4123 ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x)))
4129 // IEEE standard states that NaN values will not compare to themselves
4130 #define isnan(x) (x != x)
4133 #if !defined(__APPLE__)
4134 #if !defined(isfinite)
4135 #define isfinite finite
4140 #if defined(_MSC_VER)
4141 // Disable warning about strdup being deprecated.
4142 #pragma warning(disable : 4996)
4147 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
4148 using StreamWriterPtr = std::unique_ptr<StreamWriter>;
4150 using StreamWriterPtr = std::auto_ptr<StreamWriter>;
4153 String valueToString(LargestInt value) {
4154 UIntToStringBuffer buffer;
4155 char* current = buffer + sizeof(buffer);
4156 if (value == Value::minLargestInt) {
4157 uintToString(LargestUInt(Value::maxLargestInt) + 1, current);
4159 } else if (value < 0) {
4160 uintToString(LargestUInt(-value), current);
4163 uintToString(LargestUInt(value), current);
4165 assert(current >= buffer);
4169 String valueToString(LargestUInt value) {
4170 UIntToStringBuffer buffer;
4171 char* current = buffer + sizeof(buffer);
4172 uintToString(value, current);
4173 assert(current >= buffer);
4177 #if defined(JSON_HAS_INT64)
4179 String valueToString(Int value) { return valueToString(LargestInt(value)); }
4181 String valueToString(UInt value) { return valueToString(LargestUInt(value)); }
4183 #endif // # if defined(JSON_HAS_INT64)
4186 String valueToString(double value, bool useSpecialFloats,
4187 unsigned int precision, PrecisionType precisionType) {
4188 // Print into the buffer. We need not request the alternative representation
4189 // that always has a decimal point because JSON doesn't distinguish the
4190 // concepts of reals and integers.
4191 if (!isfinite(value)) {
4192 static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"},
4193 {"null", "-1e+9999", "1e+9999"}};
4194 return reps[useSpecialFloats ? 0 : 1]
4195 [isnan(value) ? 0 : (value < 0) ? 1 : 2];
4198 String buffer(size_t(36), '\0');
4200 int len = jsoncpp_snprintf(
4201 &*buffer.begin(), buffer.size(),
4202 (precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f",
4205 auto wouldPrint = static_cast<size_t>(len);
4206 if (wouldPrint >= buffer.size()) {
4207 buffer.resize(wouldPrint + 1);
4210 buffer.resize(wouldPrint);
4214 buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end());
4216 // strip the zero padding from the right
4217 if (precisionType == PrecisionType::decimalPlaces) {
4218 buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end());
4221 // try to ensure we preserve the fact that this was given to us as a double on
4223 if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) {
4230 String valueToString(double value, unsigned int precision,
4231 PrecisionType precisionType) {
4232 return valueToString(value, false, precision, precisionType);
4235 String valueToString(bool value) { return value ? "true" : "false"; }
4237 static bool doesAnyCharRequireEscaping(char const* s, size_t n) {
4240 return std::any_of(s, s + n, [](unsigned char c) {
4241 return c == '\\' || c == '"' || c < 0x20 || c > 0x7F;
4245 static unsigned int utf8ToCodepoint(const char*& s, const char* e) {
4246 const unsigned int REPLACEMENT_CHARACTER = 0xFFFD;
4248 unsigned int firstByte = static_cast<unsigned char>(*s);
4250 if (firstByte < 0x80)
4253 if (firstByte < 0xE0) {
4255 return REPLACEMENT_CHARACTER;
4257 unsigned int calculated =
4258 ((firstByte & 0x1F) << 6) | (static_cast<unsigned int>(s[1]) & 0x3F);
4260 // oversized encoded characters are invalid
4261 return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated;
4264 if (firstByte < 0xF0) {
4266 return REPLACEMENT_CHARACTER;
4268 unsigned int calculated = ((firstByte & 0x0F) << 12) |
4269 ((static_cast<unsigned int>(s[1]) & 0x3F) << 6) |
4270 (static_cast<unsigned int>(s[2]) & 0x3F);
4272 // surrogates aren't valid codepoints itself
4273 // shouldn't be UTF-8 encoded
4274 if (calculated >= 0xD800 && calculated <= 0xDFFF)
4275 return REPLACEMENT_CHARACTER;
4276 // oversized encoded characters are invalid
4277 return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated;
4280 if (firstByte < 0xF8) {
4282 return REPLACEMENT_CHARACTER;
4284 unsigned int calculated = ((firstByte & 0x07) << 18) |
4285 ((static_cast<unsigned int>(s[1]) & 0x3F) << 12) |
4286 ((static_cast<unsigned int>(s[2]) & 0x3F) << 6) |
4287 (static_cast<unsigned int>(s[3]) & 0x3F);
4289 // oversized encoded characters are invalid
4290 return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated;
4293 return REPLACEMENT_CHARACTER;
4296 static const char hex2[] = "000102030405060708090a0b0c0d0e0f"
4297 "101112131415161718191a1b1c1d1e1f"
4298 "202122232425262728292a2b2c2d2e2f"
4299 "303132333435363738393a3b3c3d3e3f"
4300 "404142434445464748494a4b4c4d4e4f"
4301 "505152535455565758595a5b5c5d5e5f"
4302 "606162636465666768696a6b6c6d6e6f"
4303 "707172737475767778797a7b7c7d7e7f"
4304 "808182838485868788898a8b8c8d8e8f"
4305 "909192939495969798999a9b9c9d9e9f"
4306 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
4307 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
4308 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
4309 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
4310 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
4311 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
4313 static String toHex16Bit(unsigned int x) {
4314 const unsigned int hi = (x >> 8) & 0xff;
4315 const unsigned int lo = x & 0xff;
4316 String result(4, ' ');
4317 result[0] = hex2[2 * hi];
4318 result[1] = hex2[2 * hi + 1];
4319 result[2] = hex2[2 * lo];
4320 result[3] = hex2[2 * lo + 1];
4324 static void appendRaw(String& result, unsigned ch) {
4325 result += static_cast<char>(ch);
4328 static void appendHex(String& result, unsigned ch) {
4329 result.append("\\u").append(toHex16Bit(ch));
4332 static String valueToQuotedStringN(const char* value, unsigned length,
4333 bool emitUTF8 = false) {
4334 if (value == nullptr)
4337 if (!doesAnyCharRequireEscaping(value, length))
4338 return String("\"") + value + "\"";
4339 // We have to walk value and escape any special characters.
4340 // Appending to String is not efficient, but this should be rare.
4341 // (Note: forward slashes are *not* rare, but I am not escaping them.)
4342 String::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL
4344 result.reserve(maxsize); // to avoid lots of mallocs
4346 char const* end = value + length;
4347 for (const char* c = value; c != end; ++c) {
4371 // Even though \/ is considered a legal escape in JSON, a bare
4372 // slash is also legal, so I see no reason to escape it.
4373 // (I hope I am not misunderstanding something.)
4374 // blep notes: actually escaping \/ may be useful in javascript to avoid </
4376 // Should add a flag to allow this compatibility mode and prevent this
4377 // sequence from occurring.
4380 unsigned codepoint = static_cast<unsigned char>(*c);
4381 if (codepoint < 0x20) {
4382 appendHex(result, codepoint);
4384 appendRaw(result, codepoint);
4387 unsigned codepoint = utf8ToCodepoint(c, end); // modifies `c`
4388 if (codepoint < 0x20) {
4389 appendHex(result, codepoint);
4390 } else if (codepoint < 0x80) {
4391 appendRaw(result, codepoint);
4392 } else if (codepoint < 0x10000) {
4393 // Basic Multilingual Plane
4394 appendHex(result, codepoint);
4396 // Extended Unicode. Encode 20 bits as a surrogate pair.
4397 codepoint -= 0x10000;
4398 appendHex(result, 0xd800 + ((codepoint >> 10) & 0x3ff));
4399 appendHex(result, 0xdc00 + (codepoint & 0x3ff));
4409 String valueToQuotedString(const char* value) {
4410 return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value)));
4414 // //////////////////////////////////////////////////////////////////
4415 Writer::~Writer() = default;
4418 // //////////////////////////////////////////////////////////////////
4420 FastWriter::FastWriter()
4424 void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; }
4426 void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
4428 void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
4430 String FastWriter::write(const Value& root) {
4433 if (!omitEndingLineFeed_)
4438 void FastWriter::writeValue(const Value& value) {
4439 switch (value.type()) {
4441 if (!dropNullPlaceholders_)
4442 document_ += "null";
4445 document_ += valueToString(value.asLargestInt());
4448 document_ += valueToString(value.asLargestUInt());
4451 document_ += valueToString(value.asDouble());
4454 // Is NULL possible for value.string_? No.
4457 bool ok = value.getString(&str, &end);
4459 document_ += valueToQuotedStringN(str, static_cast<unsigned>(end - str));
4463 document_ += valueToString(value.asBool());
4467 ArrayIndex size = value.size();
4468 for (ArrayIndex index = 0; index < size; ++index) {
4471 writeValue(value[index]);
4476 Value::Members members(value.getMemberNames());
4478 for (auto it = members.begin(); it != members.end(); ++it) {
4479 const String& name = *it;
4480 if (it != members.begin())
4482 document_ += valueToQuotedStringN(name.data(),
4483 static_cast<unsigned>(name.length()));
4484 document_ += yamlCompatibilityEnabled_ ? ": " : ":";
4485 writeValue(value[name]);
4492 // Class StyledWriter
4493 // //////////////////////////////////////////////////////////////////
4495 StyledWriter::StyledWriter() = default;
4497 String StyledWriter::write(const Value& root) {
4499 addChildValues_ = false;
4500 indentString_.clear();
4501 writeCommentBeforeValue(root);
4503 writeCommentAfterValueOnSameLine(root);
4508 void StyledWriter::writeValue(const Value& value) {
4509 switch (value.type()) {
4514 pushValue(valueToString(value.asLargestInt()));
4517 pushValue(valueToString(value.asLargestUInt()));
4520 pushValue(valueToString(value.asDouble()));
4523 // Is NULL possible for value.string_? No.
4526 bool ok = value.getString(&str, &end);
4528 pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
4534 pushValue(valueToString(value.asBool()));
4537 writeArrayValue(value);
4540 Value::Members members(value.getMemberNames());
4541 if (members.empty())
4544 writeWithIndent("{");
4546 auto it = members.begin();
4548 const String& name = *it;
4549 const Value& childValue = value[name];
4550 writeCommentBeforeValue(childValue);
4551 writeWithIndent(valueToQuotedString(name.c_str()));
4553 writeValue(childValue);
4554 if (++it == members.end()) {
4555 writeCommentAfterValueOnSameLine(childValue);
4559 writeCommentAfterValueOnSameLine(childValue);
4562 writeWithIndent("}");
4568 void StyledWriter::writeArrayValue(const Value& value) {
4569 unsigned size = value.size();
4573 bool isArrayMultiLine = isMultilineArray(value);
4574 if (isArrayMultiLine) {
4575 writeWithIndent("[");
4577 bool hasChildValue = !childValues_.empty();
4580 const Value& childValue = value[index];
4581 writeCommentBeforeValue(childValue);
4583 writeWithIndent(childValues_[index]);
4586 writeValue(childValue);
4588 if (++index == size) {
4589 writeCommentAfterValueOnSameLine(childValue);
4593 writeCommentAfterValueOnSameLine(childValue);
4596 writeWithIndent("]");
4597 } else // output on a single line
4599 assert(childValues_.size() == size);
4601 for (unsigned index = 0; index < size; ++index) {
4604 document_ += childValues_[index];
4611 bool StyledWriter::isMultilineArray(const Value& value) {
4612 ArrayIndex const size = value.size();
4613 bool isMultiLine = size * 3 >= rightMargin_;
4614 childValues_.clear();
4615 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
4616 const Value& childValue = value[index];
4617 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
4618 !childValue.empty());
4620 if (!isMultiLine) // check if line length > max line length
4622 childValues_.reserve(size);
4623 addChildValues_ = true;
4624 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
4625 for (ArrayIndex index = 0; index < size; ++index) {
4626 if (hasCommentForValue(value[index])) {
4629 writeValue(value[index]);
4630 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
4632 addChildValues_ = false;
4633 isMultiLine = isMultiLine || lineLength >= rightMargin_;
4638 void StyledWriter::pushValue(const String& value) {
4639 if (addChildValues_)
4640 childValues_.push_back(value);
4645 void StyledWriter::writeIndent() {
4646 if (!document_.empty()) {
4647 char last = document_[document_.length() - 1];
4648 if (last == ' ') // already indented
4650 if (last != '\n') // Comments may add new-line
4653 document_ += indentString_;
4656 void StyledWriter::writeWithIndent(const String& value) {
4661 void StyledWriter::indent() { indentString_ += String(indentSize_, ' '); }
4663 void StyledWriter::unindent() {
4664 assert(indentString_.size() >= indentSize_);
4665 indentString_.resize(indentString_.size() - indentSize_);
4668 void StyledWriter::writeCommentBeforeValue(const Value& root) {
4669 if (!root.hasComment(commentBefore))
4674 const String& comment = root.getComment(commentBefore);
4675 String::const_iterator iter = comment.begin();
4676 while (iter != comment.end()) {
4678 if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))
4683 // Comments are stripped of trailing newlines, so add one here
4687 void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
4688 if (root.hasComment(commentAfterOnSameLine))
4689 document_ += " " + root.getComment(commentAfterOnSameLine);
4691 if (root.hasComment(commentAfter)) {
4693 document_ += root.getComment(commentAfter);
4698 bool StyledWriter::hasCommentForValue(const Value& value) {
4699 return value.hasComment(commentBefore) ||
4700 value.hasComment(commentAfterOnSameLine) ||
4701 value.hasComment(commentAfter);
4704 // Class StyledStreamWriter
4705 // //////////////////////////////////////////////////////////////////
4707 StyledStreamWriter::StyledStreamWriter(String indentation)
4708 : document_(nullptr), indentation_(std::move(indentation)),
4709 addChildValues_(), indented_(false) {}
4711 void StyledStreamWriter::write(OStream& out, const Value& root) {
4713 addChildValues_ = false;
4714 indentString_.clear();
4716 writeCommentBeforeValue(root);
4721 writeCommentAfterValueOnSameLine(root);
4723 document_ = nullptr; // Forget the stream, for safety.
4726 void StyledStreamWriter::writeValue(const Value& value) {
4727 switch (value.type()) {
4732 pushValue(valueToString(value.asLargestInt()));
4735 pushValue(valueToString(value.asLargestUInt()));
4738 pushValue(valueToString(value.asDouble()));
4741 // Is NULL possible for value.string_? No.
4744 bool ok = value.getString(&str, &end);
4746 pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
4752 pushValue(valueToString(value.asBool()));
4755 writeArrayValue(value);
4758 Value::Members members(value.getMemberNames());
4759 if (members.empty())
4762 writeWithIndent("{");
4764 auto it = members.begin();
4766 const String& name = *it;
4767 const Value& childValue = value[name];
4768 writeCommentBeforeValue(childValue);
4769 writeWithIndent(valueToQuotedString(name.c_str()));
4770 *document_ << " : ";
4771 writeValue(childValue);
4772 if (++it == members.end()) {
4773 writeCommentAfterValueOnSameLine(childValue);
4777 writeCommentAfterValueOnSameLine(childValue);
4780 writeWithIndent("}");
4786 void StyledStreamWriter::writeArrayValue(const Value& value) {
4787 unsigned size = value.size();
4791 bool isArrayMultiLine = isMultilineArray(value);
4792 if (isArrayMultiLine) {
4793 writeWithIndent("[");
4795 bool hasChildValue = !childValues_.empty();
4798 const Value& childValue = value[index];
4799 writeCommentBeforeValue(childValue);
4801 writeWithIndent(childValues_[index]);
4806 writeValue(childValue);
4809 if (++index == size) {
4810 writeCommentAfterValueOnSameLine(childValue);
4814 writeCommentAfterValueOnSameLine(childValue);
4817 writeWithIndent("]");
4818 } else // output on a single line
4820 assert(childValues_.size() == size);
4822 for (unsigned index = 0; index < size; ++index) {
4825 *document_ << childValues_[index];
4832 bool StyledStreamWriter::isMultilineArray(const Value& value) {
4833 ArrayIndex const size = value.size();
4834 bool isMultiLine = size * 3 >= rightMargin_;
4835 childValues_.clear();
4836 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
4837 const Value& childValue = value[index];
4838 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
4839 !childValue.empty());
4841 if (!isMultiLine) // check if line length > max line length
4843 childValues_.reserve(size);
4844 addChildValues_ = true;
4845 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
4846 for (ArrayIndex index = 0; index < size; ++index) {
4847 if (hasCommentForValue(value[index])) {
4850 writeValue(value[index]);
4851 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
4853 addChildValues_ = false;
4854 isMultiLine = isMultiLine || lineLength >= rightMargin_;
4859 void StyledStreamWriter::pushValue(const String& value) {
4860 if (addChildValues_)
4861 childValues_.push_back(value);
4863 *document_ << value;
4866 void StyledStreamWriter::writeIndent() {
4867 // blep intended this to look at the so-far-written string
4868 // to determine whether we are already indented, but
4869 // with a stream we cannot do that. So we rely on some saved state.
4870 // The caller checks indented_.
4871 *document_ << '\n' << indentString_;
4874 void StyledStreamWriter::writeWithIndent(const String& value) {
4877 *document_ << value;
4881 void StyledStreamWriter::indent() { indentString_ += indentation_; }
4883 void StyledStreamWriter::unindent() {
4884 assert(indentString_.size() >= indentation_.size());
4885 indentString_.resize(indentString_.size() - indentation_.size());
4888 void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
4889 if (!root.hasComment(commentBefore))
4894 const String& comment = root.getComment(commentBefore);
4895 String::const_iterator iter = comment.begin();
4896 while (iter != comment.end()) {
4897 *document_ << *iter;
4898 if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))
4899 // writeIndent(); // would include newline
4900 *document_ << indentString_;
4906 void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
4907 if (root.hasComment(commentAfterOnSameLine))
4908 *document_ << ' ' << root.getComment(commentAfterOnSameLine);
4910 if (root.hasComment(commentAfter)) {
4912 *document_ << root.getComment(commentAfter);
4917 bool StyledStreamWriter::hasCommentForValue(const Value& value) {
4918 return value.hasComment(commentBefore) ||
4919 value.hasComment(commentAfterOnSameLine) ||
4920 value.hasComment(commentAfter);
4923 //////////////////////////
4924 // BuiltStyledStreamWriter
4926 /// Scoped enums are not available until C++11.
4927 struct CommentStyle {
4928 /// Decide whether to write comments.
4930 None, ///< Drop all comments.
4931 Most, ///< Recover odd behavior of previous versions (not implemented yet).
4932 All ///< Keep all comments.
4936 struct BuiltStyledStreamWriter : public StreamWriter {
4937 BuiltStyledStreamWriter(String indentation, CommentStyle::Enum cs,
4938 String colonSymbol, String nullSymbol,
4939 String endingLineFeedSymbol, bool useSpecialFloats,
4940 bool emitUTF8, unsigned int precision,
4941 PrecisionType precisionType);
4942 int write(Value const& root, OStream* sout) override;
4945 void writeValue(Value const& value);
4946 void writeArrayValue(Value const& value);
4947 bool isMultilineArray(Value const& value);
4948 void pushValue(String const& value);
4950 void writeWithIndent(String const& value);
4953 void writeCommentBeforeValue(Value const& root);
4954 void writeCommentAfterValueOnSameLine(Value const& root);
4955 static bool hasCommentForValue(const Value& value);
4957 using ChildValues = std::vector<String>;
4959 ChildValues childValues_;
4960 String indentString_;
4961 unsigned int rightMargin_;
4962 String indentation_;
4963 CommentStyle::Enum cs_;
4964 String colonSymbol_;
4966 String endingLineFeedSymbol_;
4967 bool addChildValues_ : 1;
4969 bool useSpecialFloats_ : 1;
4971 unsigned int precision_;
4972 PrecisionType precisionType_;
4974 BuiltStyledStreamWriter::BuiltStyledStreamWriter(
4975 String indentation, CommentStyle::Enum cs, String colonSymbol,
4976 String nullSymbol, String endingLineFeedSymbol, bool useSpecialFloats,
4977 bool emitUTF8, unsigned int precision, PrecisionType precisionType)
4978 : rightMargin_(74), indentation_(std::move(indentation)), cs_(cs),
4979 colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)),
4980 endingLineFeedSymbol_(std::move(endingLineFeedSymbol)),
4981 addChildValues_(false), indented_(false),
4982 useSpecialFloats_(useSpecialFloats), emitUTF8_(emitUTF8),
4983 precision_(precision), precisionType_(precisionType) {}
4984 int BuiltStyledStreamWriter::write(Value const& root, OStream* sout) {
4986 addChildValues_ = false;
4988 indentString_.clear();
4989 writeCommentBeforeValue(root);
4994 writeCommentAfterValueOnSameLine(root);
4995 *sout_ << endingLineFeedSymbol_;
4999 void BuiltStyledStreamWriter::writeValue(Value const& value) {
5000 switch (value.type()) {
5002 pushValue(nullSymbol_);
5005 pushValue(valueToString(value.asLargestInt()));
5008 pushValue(valueToString(value.asLargestUInt()));
5011 pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_,
5015 // Is NULL is possible for value.string_? No.
5018 bool ok = value.getString(&str, &end);
5020 pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str),
5027 pushValue(valueToString(value.asBool()));
5030 writeArrayValue(value);
5033 Value::Members members(value.getMemberNames());
5034 if (members.empty())
5037 writeWithIndent("{");
5039 auto it = members.begin();
5041 String const& name = *it;
5042 Value const& childValue = value[name];
5043 writeCommentBeforeValue(childValue);
5044 writeWithIndent(valueToQuotedStringN(
5045 name.data(), static_cast<unsigned>(name.length()), emitUTF8_));
5046 *sout_ << colonSymbol_;
5047 writeValue(childValue);
5048 if (++it == members.end()) {
5049 writeCommentAfterValueOnSameLine(childValue);
5053 writeCommentAfterValueOnSameLine(childValue);
5056 writeWithIndent("}");
5062 void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
5063 unsigned size = value.size();
5067 bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value);
5069 writeWithIndent("[");
5071 bool hasChildValue = !childValues_.empty();
5074 Value const& childValue = value[index];
5075 writeCommentBeforeValue(childValue);
5077 writeWithIndent(childValues_[index]);
5082 writeValue(childValue);
5085 if (++index == size) {
5086 writeCommentAfterValueOnSameLine(childValue);
5090 writeCommentAfterValueOnSameLine(childValue);
5093 writeWithIndent("]");
5094 } else // output on a single line
5096 assert(childValues_.size() == size);
5098 if (!indentation_.empty())
5100 for (unsigned index = 0; index < size; ++index) {
5102 *sout_ << ((!indentation_.empty()) ? ", " : ",");
5103 *sout_ << childValues_[index];
5105 if (!indentation_.empty())
5112 bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) {
5113 ArrayIndex const size = value.size();
5114 bool isMultiLine = size * 3 >= rightMargin_;
5115 childValues_.clear();
5116 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
5117 Value const& childValue = value[index];
5118 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
5119 !childValue.empty());
5121 if (!isMultiLine) // check if line length > max line length
5123 childValues_.reserve(size);
5124 addChildValues_ = true;
5125 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
5126 for (ArrayIndex index = 0; index < size; ++index) {
5127 if (hasCommentForValue(value[index])) {
5130 writeValue(value[index]);
5131 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
5133 addChildValues_ = false;
5134 isMultiLine = isMultiLine || lineLength >= rightMargin_;
5139 void BuiltStyledStreamWriter::pushValue(String const& value) {
5140 if (addChildValues_)
5141 childValues_.push_back(value);
5146 void BuiltStyledStreamWriter::writeIndent() {
5147 // blep intended this to look at the so-far-written string
5148 // to determine whether we are already indented, but
5149 // with a stream we cannot do that. So we rely on some saved state.
5150 // The caller checks indented_.
5152 if (!indentation_.empty()) {
5153 // In this case, drop newlines too.
5154 *sout_ << '\n' << indentString_;
5158 void BuiltStyledStreamWriter::writeWithIndent(String const& value) {
5165 void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
5167 void BuiltStyledStreamWriter::unindent() {
5168 assert(indentString_.size() >= indentation_.size());
5169 indentString_.resize(indentString_.size() - indentation_.size());
5172 void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
5173 if (cs_ == CommentStyle::None)
5175 if (!root.hasComment(commentBefore))
5180 const String& comment = root.getComment(commentBefore);
5181 String::const_iterator iter = comment.begin();
5182 while (iter != comment.end()) {
5184 if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))
5185 // writeIndent(); // would write extra newline
5186 *sout_ << indentString_;
5192 void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(
5193 Value const& root) {
5194 if (cs_ == CommentStyle::None)
5196 if (root.hasComment(commentAfterOnSameLine))
5197 *sout_ << " " + root.getComment(commentAfterOnSameLine);
5199 if (root.hasComment(commentAfter)) {
5201 *sout_ << root.getComment(commentAfter);
5206 bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
5207 return value.hasComment(commentBefore) ||
5208 value.hasComment(commentAfterOnSameLine) ||
5209 value.hasComment(commentAfter);
5215 StreamWriter::StreamWriter() : sout_(nullptr) {}
5216 StreamWriter::~StreamWriter() = default;
5217 StreamWriter::Factory::~Factory() = default;
5218 StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); }
5219 StreamWriterBuilder::~StreamWriterBuilder() = default;
5220 StreamWriter* StreamWriterBuilder::newStreamWriter() const {
5221 const String indentation = settings_["indentation"].asString();
5222 const String cs_str = settings_["commentStyle"].asString();
5223 const String pt_str = settings_["precisionType"].asString();
5224 const bool eyc = settings_["enableYAMLCompatibility"].asBool();
5225 const bool dnp = settings_["dropNullPlaceholders"].asBool();
5226 const bool usf = settings_["useSpecialFloats"].asBool();
5227 const bool emitUTF8 = settings_["emitUTF8"].asBool();
5228 unsigned int pre = settings_["precision"].asUInt();
5229 CommentStyle::Enum cs = CommentStyle::All;
5230 if (cs_str == "All") {
5231 cs = CommentStyle::All;
5232 } else if (cs_str == "None") {
5233 cs = CommentStyle::None;
5235 throwRuntimeError("commentStyle must be 'All' or 'None'");
5237 PrecisionType precisionType(significantDigits);
5238 if (pt_str == "significant") {
5239 precisionType = PrecisionType::significantDigits;
5240 } else if (pt_str == "decimal") {
5241 precisionType = PrecisionType::decimalPlaces;
5243 throwRuntimeError("precisionType must be 'significant' or 'decimal'");
5245 String colonSymbol = " : ";
5248 } else if (indentation.empty()) {
5251 String nullSymbol = "null";
5257 String endingLineFeedSymbol;
5258 return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol,
5259 endingLineFeedSymbol, usf, emitUTF8, pre,
5263 bool StreamWriterBuilder::validate(Json::Value* invalid) const {
5264 static const auto& valid_keys = *new std::set<String>{
5267 "enableYAMLCompatibility",
5268 "dropNullPlaceholders",
5274 for (auto si = settings_.begin(); si != settings_.end(); ++si) {
5275 auto key = si.name();
5276 if (valid_keys.count(key))
5279 (*invalid)[std::move(key)] = *si;
5283 return invalid ? invalid->empty() : true;
5286 Value& StreamWriterBuilder::operator[](const String& key) {
5287 return settings_[key];
5290 void StreamWriterBuilder::setDefaults(Json::Value* settings) {
5291 //! [StreamWriterBuilderDefaults]
5292 (*settings)["commentStyle"] = "All";
5293 (*settings)["indentation"] = "\t";
5294 (*settings)["enableYAMLCompatibility"] = false;
5295 (*settings)["dropNullPlaceholders"] = false;
5296 (*settings)["useSpecialFloats"] = false;
5297 (*settings)["emitUTF8"] = false;
5298 (*settings)["precision"] = 17;
5299 (*settings)["precisionType"] = "significant";
5300 //! [StreamWriterBuilderDefaults]
5303 String writeString(StreamWriter::Factory const& factory, Value const& root) {
5305 StreamWriterPtr const writer(factory.newStreamWriter());
5306 writer->write(root, &sout);
5310 OStream& operator<<(OStream& sout, Value const& root) {
5311 StreamWriterBuilder builder;
5312 StreamWriterPtr const writer(builder.newStreamWriter());
5313 writer->write(root, &sout);
5319 // //////////////////////////////////////////////////////////////////////
5320 // End of content of file: src/lib_json/json_writer.cpp
5321 // //////////////////////////////////////////////////////////////////////