1 /// Json-cpp amalgated 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 The author (Baptiste Lepilleur) explicitly disclaims copyright in all
14 jurisdictions which recognize such a disclaimer. In such jurisdictions,
15 this software is released into the Public Domain.
17 In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
18 2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
19 released under the terms of the MIT License (see below).
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
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
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
96 // Also support old flag NO_LOCALE_SUPPORT
97 #ifdef NO_LOCALE_SUPPORT
98 #define JSONCPP_NO_LOCALE_SUPPORT
101 #ifndef JSONCPP_NO_LOCALE_SUPPORT
105 /* This header provides common string manipulation support, such as UTF-8,
106 * portable conversion from/to string...
108 * It is an internal header that must not be exposed.
112 static char getDecimalPoint() {
113 #ifdef JSONCPP_NO_LOCALE_SUPPORT
116 struct lconv* lc = localeconv();
117 return lc ? *(lc->decimal_point) : '\0';
121 /// Converts a unicode code-point to UTF-8.
122 static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) {
123 JSONCPP_STRING result;
125 // based on description from http://en.wikipedia.org/wiki/UTF-8
129 result[0] = static_cast<char>(cp);
130 } else if (cp <= 0x7FF) {
132 result[1] = static_cast<char>(0x80 | (0x3f & cp));
133 result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
134 } else if (cp <= 0xFFFF) {
136 result[2] = static_cast<char>(0x80 | (0x3f & cp));
137 result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
138 result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));
139 } else if (cp <= 0x10FFFF) {
141 result[3] = static_cast<char>(0x80 | (0x3f & cp));
142 result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
143 result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
144 result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
150 /// Returns true if ch is a control character (in range [1,31]).
151 static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; }
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 typedef char UIntToStringBuffer[uintToStringBufferSize];
162 /** Converts an unsigned integer to string.
163 * @param value Unsigned interger 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 static inline void fixNumericLocale(char* begin, char* end) {
181 while (begin < end) {
189 static inline void fixNumericLocaleInput(char* begin, char* end) {
190 char decimalPoint = getDecimalPoint();
191 if (decimalPoint != '\0' && decimalPoint != '.') {
192 while (begin < end) {
194 *begin = decimalPoint;
201 } // namespace Json {
203 #endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
205 // //////////////////////////////////////////////////////////////////////
206 // End of content of file: src/lib_json/json_tool.h
207 // //////////////////////////////////////////////////////////////////////
214 // //////////////////////////////////////////////////////////////////////
215 // Beginning of content of file: src/lib_json/json_reader.cpp
216 // //////////////////////////////////////////////////////////////////////
218 // Copyright 2007-2011 Baptiste Lepilleur
219 // Copyright (C) 2016 InfoTeCS JSC. All rights reserved.
220 // Distributed under MIT license, or public domain if desired and
221 // recognized in your jurisdiction.
222 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
224 #if !defined(JSON_IS_AMALGAMATION)
225 #include <json/assertions.h>
226 #include <json/reader.h>
227 #include <json/value.h>
228 #include "json_tool.h"
229 #endif // if !defined(JSON_IS_AMALGAMATION)
240 #if defined(_MSC_VER)
241 #if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
242 #define snprintf sprintf_s
243 #elif _MSC_VER >= 1900 // VC++ 14.0 and above
244 #define snprintf std::snprintf
246 #define snprintf _snprintf
248 #elif defined(__ANDROID__) || defined(__QNXNTO__)
249 #define snprintf snprintf
250 #elif __cplusplus >= 201103L
251 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
252 #define snprintf std::snprintf
256 #if defined(__QNXNTO__)
257 #define sscanf std::sscanf
260 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
261 // Disable warning about strdup being deprecated.
262 #pragma warning(disable : 4996)
265 // Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile time to change the stack limit
266 #if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
267 #define JSONCPP_DEPRECATED_STACK_LIMIT 1000
270 static size_t const stackLimit_g = JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()
274 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
275 typedef std::unique_ptr<CharReader> CharReaderPtr;
277 typedef std::auto_ptr<CharReader> CharReaderPtr;
280 // Implementation of class Features
281 // ////////////////////////////////
284 : allowComments_(true), strictRoot_(false),
285 allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
287 Features Features::all() { return Features(); }
289 Features Features::strictMode() {
291 features.allowComments_ = false;
292 features.strictRoot_ = true;
293 features.allowDroppedNullPlaceholders_ = false;
294 features.allowNumericKeys_ = false;
298 // Implementation of class Reader
299 // ////////////////////////////////
301 static bool containsNewLine(Reader::Location begin, Reader::Location end) {
302 for (; begin < end; ++begin)
303 if (*begin == '\n' || *begin == '\r')
309 // //////////////////////////////////////////////////////////////////
312 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
313 lastValue_(), commentsBefore_(), features_(Features::all()),
314 collectComments_() {}
316 Reader::Reader(const Features& features)
317 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
318 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
322 Reader::parse(const std::string& document, Value& root, bool collectComments) {
323 JSONCPP_STRING documentCopy(document.data(), document.data() + document.capacity());
324 std::swap(documentCopy, document_);
325 const char* begin = document_.c_str();
326 const char* end = begin + document_.length();
327 return parse(begin, end, root, collectComments);
330 bool Reader::parse(std::istream& sin, Value& root, bool collectComments) {
331 // std::istream_iterator<char> begin(sin);
332 // std::istream_iterator<char> end;
333 // Those would allow streamed input from a file, if parse() were a
334 // template function.
336 // Since JSONCPP_STRING is reference-counted, this at least does not
337 // create an extra copy.
339 std::getline(sin, doc, (char)EOF);
340 return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
343 bool Reader::parse(const char* beginDoc,
346 bool collectComments) {
347 if (!features_.allowComments_) {
348 collectComments = false;
353 collectComments_ = collectComments;
357 commentsBefore_ = "";
359 while (!nodes_.empty())
363 bool successful = readValue();
365 skipCommentTokens(token);
366 if (collectComments_ && !commentsBefore_.empty())
367 root.setComment(commentsBefore_, commentAfter);
368 if (features_.strictRoot_) {
369 if (!root.isArray() && !root.isObject()) {
370 // Set error location to start of doc, ideally should be first token found
372 token.type_ = tokenError;
373 token.start_ = beginDoc;
376 "A valid JSON document must be either an array or an object value.",
384 bool Reader::readValue() {
385 // readValue() may call itself only if it calls readObject() or ReadArray().
386 // These methods execute nodes_.push() just before and nodes_.pop)() just after calling readValue().
387 // parse() executes one nodes_.push(), so > instead of >=.
388 if (nodes_.size() > stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
391 skipCommentTokens(token);
392 bool successful = true;
394 if (collectComments_ && !commentsBefore_.empty()) {
395 currentValue().setComment(commentsBefore_, commentBefore);
396 commentsBefore_ = "";
399 switch (token.type_) {
400 case tokenObjectBegin:
401 successful = readObject(token);
402 currentValue().setOffsetLimit(current_ - begin_);
404 case tokenArrayBegin:
405 successful = readArray(token);
406 currentValue().setOffsetLimit(current_ - begin_);
409 successful = decodeNumber(token);
412 successful = decodeString(token);
417 currentValue().swapPayload(v);
418 currentValue().setOffsetStart(token.start_ - begin_);
419 currentValue().setOffsetLimit(token.end_ - begin_);
425 currentValue().swapPayload(v);
426 currentValue().setOffsetStart(token.start_ - begin_);
427 currentValue().setOffsetLimit(token.end_ - begin_);
433 currentValue().swapPayload(v);
434 currentValue().setOffsetStart(token.start_ - begin_);
435 currentValue().setOffsetLimit(token.end_ - begin_);
438 case tokenArraySeparator:
441 if (features_.allowDroppedNullPlaceholders_) {
442 // "Un-read" the current token and mark the current value as a null
446 currentValue().swapPayload(v);
447 currentValue().setOffsetStart(current_ - begin_ - 1);
448 currentValue().setOffsetLimit(current_ - begin_);
450 } // Else, fall through...
452 currentValue().setOffsetStart(token.start_ - begin_);
453 currentValue().setOffsetLimit(token.end_ - begin_);
454 return addError("Syntax error: value, object or array expected.", token);
457 if (collectComments_) {
458 lastValueEnd_ = current_;
459 lastValue_ = ¤tValue();
465 void Reader::skipCommentTokens(Token& token) {
466 if (features_.allowComments_) {
469 } while (token.type_ == tokenComment);
475 bool Reader::readToken(Token& token) {
477 token.start_ = current_;
478 Char c = getNextChar();
482 token.type_ = tokenObjectBegin;
485 token.type_ = tokenObjectEnd;
488 token.type_ = tokenArrayBegin;
491 token.type_ = tokenArrayEnd;
494 token.type_ = tokenString;
498 token.type_ = tokenComment;
512 token.type_ = tokenNumber;
516 token.type_ = tokenTrue;
517 ok = match("rue", 3);
520 token.type_ = tokenFalse;
521 ok = match("alse", 4);
524 token.type_ = tokenNull;
525 ok = match("ull", 3);
528 token.type_ = tokenArraySeparator;
531 token.type_ = tokenMemberSeparator;
534 token.type_ = tokenEndOfStream;
541 token.type_ = tokenError;
542 token.end_ = current_;
546 void Reader::skipSpaces() {
547 while (current_ != end_) {
549 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
556 bool Reader::match(Location pattern, int patternLength) {
557 if (end_ - current_ < patternLength)
559 int index = patternLength;
561 if (current_[index] != pattern[index])
563 current_ += patternLength;
567 bool Reader::readComment() {
568 Location commentBegin = current_ - 1;
569 Char c = getNextChar();
570 bool successful = false;
572 successful = readCStyleComment();
574 successful = readCppStyleComment();
578 if (collectComments_) {
579 CommentPlacement placement = commentBefore;
580 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
581 if (c != '*' || !containsNewLine(commentBegin, current_))
582 placement = commentAfterOnSameLine;
585 addComment(commentBegin, current_, placement);
590 static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Location end) {
591 JSONCPP_STRING normalized;
592 normalized.reserve(static_cast<size_t>(end - begin));
593 Reader::Location current = begin;
594 while (current != end) {
597 if (current != end && *current == '\n')
610 Reader::addComment(Location begin, Location end, CommentPlacement placement) {
611 assert(collectComments_);
612 const JSONCPP_STRING& normalized = normalizeEOL(begin, end);
613 if (placement == commentAfterOnSameLine) {
614 assert(lastValue_ != 0);
615 lastValue_->setComment(normalized, placement);
617 commentsBefore_ += normalized;
621 bool Reader::readCStyleComment() {
622 while ((current_ + 1) < end_) {
623 Char c = getNextChar();
624 if (c == '*' && *current_ == '/')
627 return getNextChar() == '/';
630 bool Reader::readCppStyleComment() {
631 while (current_ != end_) {
632 Char c = getNextChar();
636 // Consume DOS EOL. It will be normalized in addComment.
637 if (current_ != end_ && *current_ == '\n')
639 // Break on Moc OS 9 EOL.
646 void Reader::readNumber() {
647 const char *p = current_;
648 char c = '0'; // stopgap for already consumed character
650 while (c >= '0' && c <= '9')
651 c = (current_ = p) < end_ ? *p++ : '\0';
654 c = (current_ = p) < end_ ? *p++ : '\0';
655 while (c >= '0' && c <= '9')
656 c = (current_ = p) < end_ ? *p++ : '\0';
659 if (c == 'e' || c == 'E') {
660 c = (current_ = p) < end_ ? *p++ : '\0';
661 if (c == '+' || c == '-')
662 c = (current_ = p) < end_ ? *p++ : '\0';
663 while (c >= '0' && c <= '9')
664 c = (current_ = p) < end_ ? *p++ : '\0';
668 bool Reader::readString() {
670 while (current_ != end_) {
680 bool Reader::readObject(Token& tokenStart) {
683 Value init(objectValue);
684 currentValue().swapPayload(init);
685 currentValue().setOffsetStart(tokenStart.start_ - begin_);
686 while (readToken(tokenName)) {
687 bool initialTokenOk = true;
688 while (tokenName.type_ == tokenComment && initialTokenOk)
689 initialTokenOk = readToken(tokenName);
692 if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
695 if (tokenName.type_ == tokenString) {
696 if (!decodeString(tokenName, name))
697 return recoverFromError(tokenObjectEnd);
698 } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
700 if (!decodeNumber(tokenName, numberName))
701 return recoverFromError(tokenObjectEnd);
702 name = JSONCPP_STRING(numberName.asCString());
708 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
709 return addErrorAndRecover(
710 "Missing ':' after object member name", colon, tokenObjectEnd);
712 Value& value = currentValue()[name];
714 bool ok = readValue();
716 if (!ok) // error already set
717 return recoverFromError(tokenObjectEnd);
720 if (!readToken(comma) ||
721 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
722 comma.type_ != tokenComment)) {
723 return addErrorAndRecover(
724 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
726 bool finalizeTokenOk = true;
727 while (comma.type_ == tokenComment && finalizeTokenOk)
728 finalizeTokenOk = readToken(comma);
729 if (comma.type_ == tokenObjectEnd)
732 return addErrorAndRecover(
733 "Missing '}' or object member name", tokenName, tokenObjectEnd);
736 bool Reader::readArray(Token& tokenStart) {
737 Value init(arrayValue);
738 currentValue().swapPayload(init);
739 currentValue().setOffsetStart(tokenStart.start_ - begin_);
741 if (current_ != end_ && *current_ == ']') // empty array
749 Value& value = currentValue()[index++];
751 bool ok = readValue();
753 if (!ok) // error already set
754 return recoverFromError(tokenArrayEnd);
757 // Accept Comment after last item in the array.
758 ok = readToken(token);
759 while (token.type_ == tokenComment && ok) {
760 ok = readToken(token);
763 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
764 if (!ok || badTokenType) {
765 return addErrorAndRecover(
766 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
768 if (token.type_ == tokenArrayEnd)
774 bool Reader::decodeNumber(Token& token) {
776 if (!decodeNumber(token, decoded))
778 currentValue().swapPayload(decoded);
779 currentValue().setOffsetStart(token.start_ - begin_);
780 currentValue().setOffsetLimit(token.end_ - begin_);
784 bool Reader::decodeNumber(Token& token, Value& decoded) {
785 // Attempts to parse the number as an integer. If the number is
786 // larger than the maximum supported value of an integer then
787 // we decode the number as a double.
788 Location current = token.start_;
789 bool isNegative = *current == '-';
792 // TODO: Help the compiler do the div and mod at compile time or get rid of them.
793 Value::LargestUInt maxIntegerValue =
794 isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
795 : Value::maxLargestUInt;
796 Value::LargestUInt threshold = maxIntegerValue / 10;
797 Value::LargestUInt value = 0;
798 while (current < token.end_) {
800 if (c < '0' || c > '9')
801 return decodeDouble(token, decoded);
802 Value::UInt digit(static_cast<Value::UInt>(c - '0'));
803 if (value >= threshold) {
804 // We've hit or exceeded the max value divided by 10 (rounded down). If
805 // a) we've only just touched the limit, b) this is the last digit, and
806 // c) it's small enough to fit in that rounding delta, we're okay.
807 // Otherwise treat this number as a double to avoid overflow.
808 if (value > threshold || current != token.end_ ||
809 digit > maxIntegerValue % 10) {
810 return decodeDouble(token, decoded);
813 value = value * 10 + digit;
815 if (isNegative && value == maxIntegerValue)
816 decoded = Value::minLargestInt;
818 decoded = -Value::LargestInt(value);
819 else if (value <= Value::LargestUInt(Value::maxInt))
820 decoded = Value::LargestInt(value);
826 bool Reader::decodeDouble(Token& token) {
828 if (!decodeDouble(token, decoded))
830 currentValue().swapPayload(decoded);
831 currentValue().setOffsetStart(token.start_ - begin_);
832 currentValue().setOffsetLimit(token.end_ - begin_);
836 bool Reader::decodeDouble(Token& token, Value& decoded) {
838 JSONCPP_STRING buffer(token.start_, token.end_);
839 JSONCPP_ISTRINGSTREAM is(buffer);
841 return addError("'" + JSONCPP_STRING(token.start_, token.end_) +
842 "' is not a number.",
848 bool Reader::decodeString(Token& token) {
849 JSONCPP_STRING decoded_string;
850 if (!decodeString(token, decoded_string))
852 Value decoded(decoded_string);
853 currentValue().swapPayload(decoded);
854 currentValue().setOffsetStart(token.start_ - begin_);
855 currentValue().setOffsetLimit(token.end_ - begin_);
859 bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) {
860 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
861 Location current = token.start_ + 1; // skip '"'
862 Location end = token.end_ - 1; // do not include '"'
863 while (current != end) {
867 else if (c == '\\') {
869 return addError("Empty escape sequence in string", token, current);
870 Char escape = *current++;
897 unsigned int unicode;
898 if (!decodeUnicodeCodePoint(token, current, end, unicode))
900 decoded += codePointToUTF8(unicode);
903 return addError("Bad escape sequence in string", token, current);
912 bool Reader::decodeUnicodeCodePoint(Token& token,
915 unsigned int& unicode) {
917 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
919 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
921 if (end - current < 6)
923 "additional six characters expected to parse unicode surrogate pair.",
926 unsigned int surrogatePair;
927 if (*(current++) == '\\' && *(current++) == 'u') {
928 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
929 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
933 return addError("expecting another \\u token to begin the second half of "
934 "a unicode surrogate pair",
941 bool Reader::decodeUnicodeEscapeSequence(Token& token,
944 unsigned int& ret_unicode) {
945 if (end - current < 4)
947 "Bad unicode escape sequence in string: four digits expected.",
951 for (int index = 0; index < 4; ++index) {
954 if (c >= '0' && c <= '9')
956 else if (c >= 'a' && c <= 'f')
957 unicode += c - 'a' + 10;
958 else if (c >= 'A' && c <= 'F')
959 unicode += c - 'A' + 10;
962 "Bad unicode escape sequence in string: hexadecimal digit expected.",
966 ret_unicode = static_cast<unsigned int>(unicode);
971 Reader::addError(const JSONCPP_STRING& message, Token& token, Location extra) {
974 info.message_ = message;
976 errors_.push_back(info);
980 bool Reader::recoverFromError(TokenType skipUntilToken) {
981 size_t const errorCount = errors_.size();
984 if (!readToken(skip))
985 errors_.resize(errorCount); // discard errors caused by recovery
986 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
989 errors_.resize(errorCount);
993 bool Reader::addErrorAndRecover(const JSONCPP_STRING& message,
995 TokenType skipUntilToken) {
996 addError(message, token);
997 return recoverFromError(skipUntilToken);
1000 Value& Reader::currentValue() { return *(nodes_.top()); }
1002 Reader::Char Reader::getNextChar() {
1003 if (current_ == end_)
1008 void Reader::getLocationLineAndColumn(Location location,
1010 int& column) const {
1011 Location current = begin_;
1012 Location lastLineStart = current;
1014 while (current < location && current != end_) {
1015 Char c = *current++;
1017 if (*current == '\n')
1019 lastLineStart = current;
1021 } else if (c == '\n') {
1022 lastLineStart = current;
1026 // column & line start at 1
1027 column = int(location - lastLineStart) + 1;
1031 JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const {
1033 getLocationLineAndColumn(location, line, column);
1034 char buffer[18 + 16 + 16 + 1];
1035 snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
1039 // Deprecated. Preserved for backward compatibility
1040 JSONCPP_STRING Reader::getFormatedErrorMessages() const {
1041 return getFormattedErrorMessages();
1044 JSONCPP_STRING Reader::getFormattedErrorMessages() const {
1045 JSONCPP_STRING formattedMessage;
1046 for (Errors::const_iterator itError = errors_.begin();
1047 itError != errors_.end();
1049 const ErrorInfo& error = *itError;
1051 "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
1052 formattedMessage += " " + error.message_ + "\n";
1055 "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
1057 return formattedMessage;
1060 std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
1061 std::vector<Reader::StructuredError> allErrors;
1062 for (Errors::const_iterator itError = errors_.begin();
1063 itError != errors_.end();
1065 const ErrorInfo& error = *itError;
1066 Reader::StructuredError structured;
1067 structured.offset_start = error.token_.start_ - begin_;
1068 structured.offset_limit = error.token_.end_ - begin_;
1069 structured.message = error.message_;
1070 allErrors.push_back(structured);
1075 bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) {
1076 ptrdiff_t const length = end_ - begin_;
1077 if(value.getOffsetStart() > length
1078 || value.getOffsetLimit() > length)
1081 token.type_ = tokenError;
1082 token.start_ = begin_ + value.getOffsetStart();
1083 token.end_ = end_ + value.getOffsetLimit();
1085 info.token_ = token;
1086 info.message_ = message;
1088 errors_.push_back(info);
1092 bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) {
1093 ptrdiff_t const length = end_ - begin_;
1094 if(value.getOffsetStart() > length
1095 || value.getOffsetLimit() > length
1096 || extra.getOffsetLimit() > length)
1099 token.type_ = tokenError;
1100 token.start_ = begin_ + value.getOffsetStart();
1101 token.end_ = begin_ + value.getOffsetLimit();
1103 info.token_ = token;
1104 info.message_ = message;
1105 info.extra_ = begin_ + extra.getOffsetStart();
1106 errors_.push_back(info);
1110 bool Reader::good() const {
1111 return !errors_.size();
1114 // exact copy of Features
1117 static OurFeatures all();
1118 bool allowComments_;
1120 bool allowDroppedNullPlaceholders_;
1121 bool allowNumericKeys_;
1122 bool allowSingleQuotes_;
1124 bool rejectDupKeys_;
1125 bool allowSpecialFloats_;
1129 // exact copy of Implementation of class Features
1130 // ////////////////////////////////
1132 OurFeatures OurFeatures::all() { return OurFeatures(); }
1134 // Implementation of class Reader
1135 // ////////////////////////////////
1137 // exact copy of Reader, renamed to OurReader
1141 typedef const Char* Location;
1142 struct StructuredError {
1143 ptrdiff_t offset_start;
1144 ptrdiff_t offset_limit;
1145 JSONCPP_STRING message;
1148 OurReader(OurFeatures const& features);
1149 bool parse(const char* beginDoc,
1152 bool collectComments = true);
1153 JSONCPP_STRING getFormattedErrorMessages() const;
1154 std::vector<StructuredError> getStructuredErrors() const;
1155 bool pushError(const Value& value, const JSONCPP_STRING& message);
1156 bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra);
1160 OurReader(OurReader const&); // no impl
1161 void operator=(OurReader const&); // no impl
1164 tokenEndOfStream = 0,
1177 tokenArraySeparator,
1178 tokenMemberSeparator,
1193 JSONCPP_STRING message_;
1197 typedef std::deque<ErrorInfo> Errors;
1199 bool readToken(Token& token);
1201 bool match(Location pattern, int patternLength);
1203 bool readCStyleComment();
1204 bool readCppStyleComment();
1206 bool readStringSingleQuote();
1207 bool readNumber(bool checkInf);
1209 bool readObject(Token& token);
1210 bool readArray(Token& token);
1211 bool decodeNumber(Token& token);
1212 bool decodeNumber(Token& token, Value& decoded);
1213 bool decodeString(Token& token);
1214 bool decodeString(Token& token, JSONCPP_STRING& decoded);
1215 bool decodeDouble(Token& token);
1216 bool decodeDouble(Token& token, Value& decoded);
1217 bool decodeUnicodeCodePoint(Token& token,
1220 unsigned int& unicode);
1221 bool decodeUnicodeEscapeSequence(Token& token,
1224 unsigned int& unicode);
1225 bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0);
1226 bool recoverFromError(TokenType skipUntilToken);
1227 bool addErrorAndRecover(const JSONCPP_STRING& message,
1229 TokenType skipUntilToken);
1230 void skipUntilSpace();
1231 Value& currentValue();
1234 getLocationLineAndColumn(Location location, int& line, int& column) const;
1235 JSONCPP_STRING getLocationLineAndColumn(Location location) const;
1236 void addComment(Location begin, Location end, CommentPlacement placement);
1237 void skipCommentTokens(Token& token);
1239 typedef std::stack<Value*> Nodes;
1242 JSONCPP_STRING document_;
1246 Location lastValueEnd_;
1248 JSONCPP_STRING commentsBefore_;
1250 OurFeatures const features_;
1251 bool collectComments_;
1254 // complete copy of Read impl, for OurReader
1256 OurReader::OurReader(OurFeatures const& features)
1257 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
1258 lastValue_(), commentsBefore_(),
1259 features_(features), collectComments_() {
1262 bool OurReader::parse(const char* beginDoc,
1265 bool collectComments) {
1266 if (!features_.allowComments_) {
1267 collectComments = false;
1272 collectComments_ = collectComments;
1276 commentsBefore_ = "";
1278 while (!nodes_.empty())
1282 bool successful = readValue();
1284 skipCommentTokens(token);
1285 if (features_.failIfExtra_) {
1286 if ((features_.strictRoot_ || token.type_ != tokenError) && token.type_ != tokenEndOfStream) {
1287 addError("Extra non-whitespace after JSON value.", token);
1291 if (collectComments_ && !commentsBefore_.empty())
1292 root.setComment(commentsBefore_, commentAfter);
1293 if (features_.strictRoot_) {
1294 if (!root.isArray() && !root.isObject()) {
1295 // Set error location to start of doc, ideally should be first token found
1297 token.type_ = tokenError;
1298 token.start_ = beginDoc;
1299 token.end_ = endDoc;
1301 "A valid JSON document must be either an array or an object value.",
1309 bool OurReader::readValue() {
1310 // To preserve the old behaviour we cast size_t to int.
1311 if (static_cast<int>(nodes_.size()) > features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");
1313 skipCommentTokens(token);
1314 bool successful = true;
1316 if (collectComments_ && !commentsBefore_.empty()) {
1317 currentValue().setComment(commentsBefore_, commentBefore);
1318 commentsBefore_ = "";
1321 switch (token.type_) {
1322 case tokenObjectBegin:
1323 successful = readObject(token);
1324 currentValue().setOffsetLimit(current_ - begin_);
1326 case tokenArrayBegin:
1327 successful = readArray(token);
1328 currentValue().setOffsetLimit(current_ - begin_);
1331 successful = decodeNumber(token);
1334 successful = decodeString(token);
1339 currentValue().swapPayload(v);
1340 currentValue().setOffsetStart(token.start_ - begin_);
1341 currentValue().setOffsetLimit(token.end_ - begin_);
1347 currentValue().swapPayload(v);
1348 currentValue().setOffsetStart(token.start_ - begin_);
1349 currentValue().setOffsetLimit(token.end_ - begin_);
1355 currentValue().swapPayload(v);
1356 currentValue().setOffsetStart(token.start_ - begin_);
1357 currentValue().setOffsetLimit(token.end_ - begin_);
1362 Value v(std::numeric_limits<double>::quiet_NaN());
1363 currentValue().swapPayload(v);
1364 currentValue().setOffsetStart(token.start_ - begin_);
1365 currentValue().setOffsetLimit(token.end_ - begin_);
1370 Value v(std::numeric_limits<double>::infinity());
1371 currentValue().swapPayload(v);
1372 currentValue().setOffsetStart(token.start_ - begin_);
1373 currentValue().setOffsetLimit(token.end_ - begin_);
1378 Value v(-std::numeric_limits<double>::infinity());
1379 currentValue().swapPayload(v);
1380 currentValue().setOffsetStart(token.start_ - begin_);
1381 currentValue().setOffsetLimit(token.end_ - begin_);
1384 case tokenArraySeparator:
1385 case tokenObjectEnd:
1387 if (features_.allowDroppedNullPlaceholders_) {
1388 // "Un-read" the current token and mark the current value as a null
1392 currentValue().swapPayload(v);
1393 currentValue().setOffsetStart(current_ - begin_ - 1);
1394 currentValue().setOffsetLimit(current_ - begin_);
1396 } // else, fall through ...
1398 currentValue().setOffsetStart(token.start_ - begin_);
1399 currentValue().setOffsetLimit(token.end_ - begin_);
1400 return addError("Syntax error: value, object or array expected.", token);
1403 if (collectComments_) {
1404 lastValueEnd_ = current_;
1405 lastValue_ = ¤tValue();
1411 void OurReader::skipCommentTokens(Token& token) {
1412 if (features_.allowComments_) {
1415 } while (token.type_ == tokenComment);
1421 bool OurReader::readToken(Token& token) {
1423 token.start_ = current_;
1424 Char c = getNextChar();
1428 token.type_ = tokenObjectBegin;
1431 token.type_ = tokenObjectEnd;
1434 token.type_ = tokenArrayBegin;
1437 token.type_ = tokenArrayEnd;
1440 token.type_ = tokenString;
1444 if (features_.allowSingleQuotes_) {
1445 token.type_ = tokenString;
1446 ok = readStringSingleQuote();
1450 token.type_ = tokenComment;
1463 token.type_ = tokenNumber;
1467 if (readNumber(true)) {
1468 token.type_ = tokenNumber;
1470 token.type_ = tokenNegInf;
1471 ok = features_.allowSpecialFloats_ && match("nfinity", 7);
1475 token.type_ = tokenTrue;
1476 ok = match("rue", 3);
1479 token.type_ = tokenFalse;
1480 ok = match("alse", 4);
1483 token.type_ = tokenNull;
1484 ok = match("ull", 3);
1487 if (features_.allowSpecialFloats_) {
1488 token.type_ = tokenNaN;
1489 ok = match("aN", 2);
1495 if (features_.allowSpecialFloats_) {
1496 token.type_ = tokenPosInf;
1497 ok = match("nfinity", 7);
1503 token.type_ = tokenArraySeparator;
1506 token.type_ = tokenMemberSeparator;
1509 token.type_ = tokenEndOfStream;
1516 token.type_ = tokenError;
1517 token.end_ = current_;
1521 void OurReader::skipSpaces() {
1522 while (current_ != end_) {
1524 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
1531 bool OurReader::match(Location pattern, int patternLength) {
1532 if (end_ - current_ < patternLength)
1534 int index = patternLength;
1536 if (current_[index] != pattern[index])
1538 current_ += patternLength;
1542 bool OurReader::readComment() {
1543 Location commentBegin = current_ - 1;
1544 Char c = getNextChar();
1545 bool successful = false;
1547 successful = readCStyleComment();
1549 successful = readCppStyleComment();
1553 if (collectComments_) {
1554 CommentPlacement placement = commentBefore;
1555 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
1556 if (c != '*' || !containsNewLine(commentBegin, current_))
1557 placement = commentAfterOnSameLine;
1560 addComment(commentBegin, current_, placement);
1566 OurReader::addComment(Location begin, Location end, CommentPlacement placement) {
1567 assert(collectComments_);
1568 const JSONCPP_STRING& normalized = normalizeEOL(begin, end);
1569 if (placement == commentAfterOnSameLine) {
1570 assert(lastValue_ != 0);
1571 lastValue_->setComment(normalized, placement);
1573 commentsBefore_ += normalized;
1577 bool OurReader::readCStyleComment() {
1578 while ((current_ + 1) < end_) {
1579 Char c = getNextChar();
1580 if (c == '*' && *current_ == '/')
1583 return getNextChar() == '/';
1586 bool OurReader::readCppStyleComment() {
1587 while (current_ != end_) {
1588 Char c = getNextChar();
1592 // Consume DOS EOL. It will be normalized in addComment.
1593 if (current_ != end_ && *current_ == '\n')
1595 // Break on Moc OS 9 EOL.
1602 bool OurReader::readNumber(bool checkInf) {
1603 const char *p = current_;
1604 if (checkInf && p != end_ && *p == 'I') {
1608 char c = '0'; // stopgap for already consumed character
1610 while (c >= '0' && c <= '9')
1611 c = (current_ = p) < end_ ? *p++ : '\0';
1614 c = (current_ = p) < end_ ? *p++ : '\0';
1615 while (c >= '0' && c <= '9')
1616 c = (current_ = p) < end_ ? *p++ : '\0';
1619 if (c == 'e' || c == 'E') {
1620 c = (current_ = p) < end_ ? *p++ : '\0';
1621 if (c == '+' || c == '-')
1622 c = (current_ = p) < end_ ? *p++ : '\0';
1623 while (c >= '0' && c <= '9')
1624 c = (current_ = p) < end_ ? *p++ : '\0';
1628 bool OurReader::readString() {
1630 while (current_ != end_) {
1641 bool OurReader::readStringSingleQuote() {
1643 while (current_ != end_) {
1653 bool OurReader::readObject(Token& tokenStart) {
1655 JSONCPP_STRING name;
1656 Value init(objectValue);
1657 currentValue().swapPayload(init);
1658 currentValue().setOffsetStart(tokenStart.start_ - begin_);
1659 while (readToken(tokenName)) {
1660 bool initialTokenOk = true;
1661 while (tokenName.type_ == tokenComment && initialTokenOk)
1662 initialTokenOk = readToken(tokenName);
1663 if (!initialTokenOk)
1665 if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
1668 if (tokenName.type_ == tokenString) {
1669 if (!decodeString(tokenName, name))
1670 return recoverFromError(tokenObjectEnd);
1671 } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1673 if (!decodeNumber(tokenName, numberName))
1674 return recoverFromError(tokenObjectEnd);
1675 name = numberName.asString();
1681 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1682 return addErrorAndRecover(
1683 "Missing ':' after object member name", colon, tokenObjectEnd);
1685 if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");
1686 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1687 JSONCPP_STRING msg = "Duplicate key: '" + name + "'";
1688 return addErrorAndRecover(
1689 msg, tokenName, tokenObjectEnd);
1691 Value& value = currentValue()[name];
1692 nodes_.push(&value);
1693 bool ok = readValue();
1695 if (!ok) // error already set
1696 return recoverFromError(tokenObjectEnd);
1699 if (!readToken(comma) ||
1700 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1701 comma.type_ != tokenComment)) {
1702 return addErrorAndRecover(
1703 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
1705 bool finalizeTokenOk = true;
1706 while (comma.type_ == tokenComment && finalizeTokenOk)
1707 finalizeTokenOk = readToken(comma);
1708 if (comma.type_ == tokenObjectEnd)
1711 return addErrorAndRecover(
1712 "Missing '}' or object member name", tokenName, tokenObjectEnd);
1715 bool OurReader::readArray(Token& tokenStart) {
1716 Value init(arrayValue);
1717 currentValue().swapPayload(init);
1718 currentValue().setOffsetStart(tokenStart.start_ - begin_);
1720 if (current_ != end_ && *current_ == ']') // empty array
1723 readToken(endArray);
1728 Value& value = currentValue()[index++];
1729 nodes_.push(&value);
1730 bool ok = readValue();
1732 if (!ok) // error already set
1733 return recoverFromError(tokenArrayEnd);
1736 // Accept Comment after last item in the array.
1737 ok = readToken(token);
1738 while (token.type_ == tokenComment && ok) {
1739 ok = readToken(token);
1742 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
1743 if (!ok || badTokenType) {
1744 return addErrorAndRecover(
1745 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
1747 if (token.type_ == tokenArrayEnd)
1753 bool OurReader::decodeNumber(Token& token) {
1755 if (!decodeNumber(token, decoded))
1757 currentValue().swapPayload(decoded);
1758 currentValue().setOffsetStart(token.start_ - begin_);
1759 currentValue().setOffsetLimit(token.end_ - begin_);
1763 bool OurReader::decodeNumber(Token& token, Value& decoded) {
1764 // Attempts to parse the number as an integer. If the number is
1765 // larger than the maximum supported value of an integer then
1766 // we decode the number as a double.
1767 Location current = token.start_;
1768 bool isNegative = *current == '-';
1771 // TODO: Help the compiler do the div and mod at compile time or get rid of them.
1772 Value::LargestUInt maxIntegerValue =
1773 isNegative ? Value::LargestUInt(-Value::minLargestInt)
1774 : Value::maxLargestUInt;
1775 Value::LargestUInt threshold = maxIntegerValue / 10;
1776 Value::LargestUInt value = 0;
1777 while (current < token.end_) {
1778 Char c = *current++;
1779 if (c < '0' || c > '9')
1780 return decodeDouble(token, decoded);
1781 Value::UInt digit(static_cast<Value::UInt>(c - '0'));
1782 if (value >= threshold) {
1783 // We've hit or exceeded the max value divided by 10 (rounded down). If
1784 // a) we've only just touched the limit, b) this is the last digit, and
1785 // c) it's small enough to fit in that rounding delta, we're okay.
1786 // Otherwise treat this number as a double to avoid overflow.
1787 if (value > threshold || current != token.end_ ||
1788 digit > maxIntegerValue % 10) {
1789 return decodeDouble(token, decoded);
1792 value = value * 10 + digit;
1795 decoded = -Value::LargestInt(value);
1796 else if (value <= Value::LargestUInt(Value::maxInt))
1797 decoded = Value::LargestInt(value);
1803 bool OurReader::decodeDouble(Token& token) {
1805 if (!decodeDouble(token, decoded))
1807 currentValue().swapPayload(decoded);
1808 currentValue().setOffsetStart(token.start_ - begin_);
1809 currentValue().setOffsetLimit(token.end_ - begin_);
1813 bool OurReader::decodeDouble(Token& token, Value& decoded) {
1815 const int bufferSize = 32;
1817 ptrdiff_t const length = token.end_ - token.start_;
1819 // Sanity check to avoid buffer overflow exploits.
1821 return addError("Unable to parse token length", token);
1823 size_t const ulength = static_cast<size_t>(length);
1825 // Avoid using a string constant for the format control string given to
1826 // sscanf, as this can cause hard to debug crashes on OS X. See here for more
1829 // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
1830 char format[] = "%lf";
1832 if (length <= bufferSize) {
1833 Char buffer[bufferSize + 1];
1834 memcpy(buffer, token.start_, ulength);
1836 fixNumericLocaleInput(buffer, buffer + length);
1837 count = sscanf(buffer, format, &value);
1839 JSONCPP_STRING buffer(token.start_, token.end_);
1840 count = sscanf(buffer.c_str(), format, &value);
1844 return addError("'" + JSONCPP_STRING(token.start_, token.end_) +
1845 "' is not a number.",
1851 bool OurReader::decodeString(Token& token) {
1852 JSONCPP_STRING decoded_string;
1853 if (!decodeString(token, decoded_string))
1855 Value decoded(decoded_string);
1856 currentValue().swapPayload(decoded);
1857 currentValue().setOffsetStart(token.start_ - begin_);
1858 currentValue().setOffsetLimit(token.end_ - begin_);
1862 bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) {
1863 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
1864 Location current = token.start_ + 1; // skip '"'
1865 Location end = token.end_ - 1; // do not include '"'
1866 while (current != end) {
1867 Char c = *current++;
1870 else if (c == '\\') {
1872 return addError("Empty escape sequence in string", token, current);
1873 Char escape = *current++;
1900 unsigned int unicode;
1901 if (!decodeUnicodeCodePoint(token, current, end, unicode))
1903 decoded += codePointToUTF8(unicode);
1906 return addError("Bad escape sequence in string", token, current);
1915 bool OurReader::decodeUnicodeCodePoint(Token& token,
1918 unsigned int& unicode) {
1920 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1922 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1924 if (end - current < 6)
1926 "additional six characters expected to parse unicode surrogate pair.",
1929 unsigned int surrogatePair;
1930 if (*(current++) == '\\' && *(current++) == 'u') {
1931 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1932 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1936 return addError("expecting another \\u token to begin the second half of "
1937 "a unicode surrogate pair",
1944 bool OurReader::decodeUnicodeEscapeSequence(Token& token,
1947 unsigned int& ret_unicode) {
1948 if (end - current < 4)
1950 "Bad unicode escape sequence in string: four digits expected.",
1954 for (int index = 0; index < 4; ++index) {
1955 Char c = *current++;
1957 if (c >= '0' && c <= '9')
1959 else if (c >= 'a' && c <= 'f')
1960 unicode += c - 'a' + 10;
1961 else if (c >= 'A' && c <= 'F')
1962 unicode += c - 'A' + 10;
1965 "Bad unicode escape sequence in string: hexadecimal digit expected.",
1969 ret_unicode = static_cast<unsigned int>(unicode);
1974 OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) {
1976 info.token_ = token;
1977 info.message_ = message;
1978 info.extra_ = extra;
1979 errors_.push_back(info);
1983 bool OurReader::recoverFromError(TokenType skipUntilToken) {
1984 size_t errorCount = errors_.size();
1987 if (!readToken(skip))
1988 errors_.resize(errorCount); // discard errors caused by recovery
1989 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
1992 errors_.resize(errorCount);
1996 bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message,
1998 TokenType skipUntilToken) {
1999 addError(message, token);
2000 return recoverFromError(skipUntilToken);
2003 Value& OurReader::currentValue() { return *(nodes_.top()); }
2005 OurReader::Char OurReader::getNextChar() {
2006 if (current_ == end_)
2011 void OurReader::getLocationLineAndColumn(Location location,
2013 int& column) const {
2014 Location current = begin_;
2015 Location lastLineStart = current;
2017 while (current < location && current != end_) {
2018 Char c = *current++;
2020 if (*current == '\n')
2022 lastLineStart = current;
2024 } else if (c == '\n') {
2025 lastLineStart = current;
2029 // column & line start at 1
2030 column = int(location - lastLineStart) + 1;
2034 JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const {
2036 getLocationLineAndColumn(location, line, column);
2037 char buffer[18 + 16 + 16 + 1];
2038 snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
2042 JSONCPP_STRING OurReader::getFormattedErrorMessages() const {
2043 JSONCPP_STRING formattedMessage;
2044 for (Errors::const_iterator itError = errors_.begin();
2045 itError != errors_.end();
2047 const ErrorInfo& error = *itError;
2049 "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
2050 formattedMessage += " " + error.message_ + "\n";
2053 "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
2055 return formattedMessage;
2058 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
2059 std::vector<OurReader::StructuredError> allErrors;
2060 for (Errors::const_iterator itError = errors_.begin();
2061 itError != errors_.end();
2063 const ErrorInfo& error = *itError;
2064 OurReader::StructuredError structured;
2065 structured.offset_start = error.token_.start_ - begin_;
2066 structured.offset_limit = error.token_.end_ - begin_;
2067 structured.message = error.message_;
2068 allErrors.push_back(structured);
2073 bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) {
2074 ptrdiff_t length = end_ - begin_;
2075 if(value.getOffsetStart() > length
2076 || value.getOffsetLimit() > length)
2079 token.type_ = tokenError;
2080 token.start_ = begin_ + value.getOffsetStart();
2081 token.end_ = end_ + value.getOffsetLimit();
2083 info.token_ = token;
2084 info.message_ = message;
2086 errors_.push_back(info);
2090 bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) {
2091 ptrdiff_t length = end_ - begin_;
2092 if(value.getOffsetStart() > length
2093 || value.getOffsetLimit() > length
2094 || extra.getOffsetLimit() > length)
2097 token.type_ = tokenError;
2098 token.start_ = begin_ + value.getOffsetStart();
2099 token.end_ = begin_ + value.getOffsetLimit();
2101 info.token_ = token;
2102 info.message_ = message;
2103 info.extra_ = begin_ + extra.getOffsetStart();
2104 errors_.push_back(info);
2108 bool OurReader::good() const {
2109 return !errors_.size();
2113 class OurCharReader : public CharReader {
2114 bool const collectComments_;
2118 bool collectComments,
2119 OurFeatures const& features)
2120 : collectComments_(collectComments)
2124 char const* beginDoc, char const* endDoc,
2125 Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE {
2126 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
2128 *errs = reader_.getFormattedErrorMessages();
2134 CharReaderBuilder::CharReaderBuilder()
2136 setDefaults(&settings_);
2138 CharReaderBuilder::~CharReaderBuilder()
2140 CharReader* CharReaderBuilder::newCharReader() const
2142 bool collectComments = settings_["collectComments"].asBool();
2143 OurFeatures features = OurFeatures::all();
2144 features.allowComments_ = settings_["allowComments"].asBool();
2145 features.strictRoot_ = settings_["strictRoot"].asBool();
2146 features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
2147 features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
2148 features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
2149 features.stackLimit_ = settings_["stackLimit"].asInt();
2150 features.failIfExtra_ = settings_["failIfExtra"].asBool();
2151 features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
2152 features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
2153 return new OurCharReader(collectComments, features);
2155 static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys)
2157 valid_keys->clear();
2158 valid_keys->insert("collectComments");
2159 valid_keys->insert("allowComments");
2160 valid_keys->insert("strictRoot");
2161 valid_keys->insert("allowDroppedNullPlaceholders");
2162 valid_keys->insert("allowNumericKeys");
2163 valid_keys->insert("allowSingleQuotes");
2164 valid_keys->insert("stackLimit");
2165 valid_keys->insert("failIfExtra");
2166 valid_keys->insert("rejectDupKeys");
2167 valid_keys->insert("allowSpecialFloats");
2169 bool CharReaderBuilder::validate(Json::Value* invalid) const
2171 Json::Value my_invalid;
2172 if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
2173 Json::Value& inv = *invalid;
2174 std::set<JSONCPP_STRING> valid_keys;
2175 getValidReaderKeys(&valid_keys);
2176 Value::Members keys = settings_.getMemberNames();
2177 size_t n = keys.size();
2178 for (size_t i = 0; i < n; ++i) {
2179 JSONCPP_STRING const& key = keys[i];
2180 if (valid_keys.find(key) == valid_keys.end()) {
2181 inv[key] = settings_[key];
2184 return 0u == inv.size();
2186 Value& CharReaderBuilder::operator[](JSONCPP_STRING key)
2188 return settings_[key];
2191 void CharReaderBuilder::strictMode(Json::Value* settings)
2193 //! [CharReaderBuilderStrictMode]
2194 (*settings)["allowComments"] = false;
2195 (*settings)["strictRoot"] = true;
2196 (*settings)["allowDroppedNullPlaceholders"] = false;
2197 (*settings)["allowNumericKeys"] = false;
2198 (*settings)["allowSingleQuotes"] = false;
2199 (*settings)["stackLimit"] = 1000;
2200 (*settings)["failIfExtra"] = true;
2201 (*settings)["rejectDupKeys"] = true;
2202 (*settings)["allowSpecialFloats"] = false;
2203 //! [CharReaderBuilderStrictMode]
2206 void CharReaderBuilder::setDefaults(Json::Value* settings)
2208 //! [CharReaderBuilderDefaults]
2209 (*settings)["collectComments"] = true;
2210 (*settings)["allowComments"] = true;
2211 (*settings)["strictRoot"] = false;
2212 (*settings)["allowDroppedNullPlaceholders"] = false;
2213 (*settings)["allowNumericKeys"] = false;
2214 (*settings)["allowSingleQuotes"] = false;
2215 (*settings)["stackLimit"] = 1000;
2216 (*settings)["failIfExtra"] = false;
2217 (*settings)["rejectDupKeys"] = false;
2218 (*settings)["allowSpecialFloats"] = false;
2219 //! [CharReaderBuilderDefaults]
2222 //////////////////////////////////
2225 bool parseFromStream(
2226 CharReader::Factory const& fact, JSONCPP_ISTREAM& sin,
2227 Value* root, JSONCPP_STRING* errs)
2229 JSONCPP_OSTRINGSTREAM ssin;
2230 ssin << sin.rdbuf();
2231 JSONCPP_STRING doc = ssin.str();
2232 char const* begin = doc.data();
2233 char const* end = begin + doc.size();
2234 // Note that we do not actually need a null-terminator.
2235 CharReaderPtr const reader(fact.newCharReader());
2236 return reader->parse(begin, end, root, errs);
2239 JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) {
2240 CharReaderBuilder b;
2241 JSONCPP_STRING errs;
2242 bool ok = parseFromStream(b, sin, &root, &errs);
2245 "Error from reader: %s",
2248 throwRuntimeError(errs);
2255 // //////////////////////////////////////////////////////////////////////
2256 // End of content of file: src/lib_json/json_reader.cpp
2257 // //////////////////////////////////////////////////////////////////////
2264 // //////////////////////////////////////////////////////////////////////
2265 // Beginning of content of file: src/lib_json/json_valueiterator.inl
2266 // //////////////////////////////////////////////////////////////////////
2268 // Copyright 2007-2010 Baptiste Lepilleur
2269 // Distributed under MIT license, or public domain if desired and
2270 // recognized in your jurisdiction.
2271 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
2273 // included by json_value.cpp
2277 // //////////////////////////////////////////////////////////////////
2278 // //////////////////////////////////////////////////////////////////
2279 // //////////////////////////////////////////////////////////////////
2280 // class ValueIteratorBase
2281 // //////////////////////////////////////////////////////////////////
2282 // //////////////////////////////////////////////////////////////////
2283 // //////////////////////////////////////////////////////////////////
2285 ValueIteratorBase::ValueIteratorBase()
2286 : current_(), isNull_(true) {
2289 ValueIteratorBase::ValueIteratorBase(
2290 const Value::ObjectValues::iterator& current)
2291 : current_(current), isNull_(false) {}
2293 Value& ValueIteratorBase::deref() const {
2294 return current_->second;
2297 void ValueIteratorBase::increment() {
2301 void ValueIteratorBase::decrement() {
2305 ValueIteratorBase::difference_type
2306 ValueIteratorBase::computeDistance(const SelfType& other) const {
2307 #ifdef JSON_USE_CPPTL_SMALLMAP
2308 return other.current_ - current_;
2310 // Iterator for null value are initialized using the default
2311 // constructor, which initialize current_ to the default
2312 // std::map::iterator. As begin() and end() are two instance
2313 // of the default std::map::iterator, they can not be compared.
2314 // To allow this, we handle this comparison specifically.
2315 if (isNull_ && other.isNull_) {
2319 // Usage of std::distance is not portable (does not compile with Sun Studio 12
2321 // which is the one used by default).
2322 // Using a portable hand-made version for non random iterator instead:
2323 // return difference_type( std::distance( current_, other.current_ ) );
2324 difference_type myDistance = 0;
2325 for (Value::ObjectValues::iterator it = current_; it != other.current_;
2333 bool ValueIteratorBase::isEqual(const SelfType& other) const {
2335 return other.isNull_;
2337 return current_ == other.current_;
2340 void ValueIteratorBase::copy(const SelfType& other) {
2341 current_ = other.current_;
2342 isNull_ = other.isNull_;
2345 Value ValueIteratorBase::key() const {
2346 const Value::CZString czstring = (*current_).first;
2347 if (czstring.data()) {
2348 if (czstring.isStaticString())
2349 return Value(StaticString(czstring.data()));
2350 return Value(czstring.data(), czstring.data() + czstring.length());
2352 return Value(czstring.index());
2355 UInt ValueIteratorBase::index() const {
2356 const Value::CZString czstring = (*current_).first;
2357 if (!czstring.data())
2358 return czstring.index();
2359 return Value::UInt(-1);
2362 JSONCPP_STRING ValueIteratorBase::name() const {
2365 keey = memberName(&end);
2366 if (!keey) return JSONCPP_STRING();
2367 return JSONCPP_STRING(keey, end);
2370 char const* ValueIteratorBase::memberName() const {
2371 const char* cname = (*current_).first.data();
2372 return cname ? cname : "";
2375 char const* ValueIteratorBase::memberName(char const** end) const {
2376 const char* cname = (*current_).first.data();
2381 *end = cname + (*current_).first.length();
2385 // //////////////////////////////////////////////////////////////////
2386 // //////////////////////////////////////////////////////////////////
2387 // //////////////////////////////////////////////////////////////////
2388 // class ValueConstIterator
2389 // //////////////////////////////////////////////////////////////////
2390 // //////////////////////////////////////////////////////////////////
2391 // //////////////////////////////////////////////////////////////////
2393 ValueConstIterator::ValueConstIterator() {}
2395 ValueConstIterator::ValueConstIterator(
2396 const Value::ObjectValues::iterator& current)
2397 : ValueIteratorBase(current) {}
2399 ValueConstIterator::ValueConstIterator(ValueIterator const& other)
2400 : ValueIteratorBase(other) {}
2402 ValueConstIterator& ValueConstIterator::
2403 operator=(const ValueIteratorBase& other) {
2408 // //////////////////////////////////////////////////////////////////
2409 // //////////////////////////////////////////////////////////////////
2410 // //////////////////////////////////////////////////////////////////
2411 // class ValueIterator
2412 // //////////////////////////////////////////////////////////////////
2413 // //////////////////////////////////////////////////////////////////
2414 // //////////////////////////////////////////////////////////////////
2416 ValueIterator::ValueIterator() {}
2418 ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
2419 : ValueIteratorBase(current) {}
2421 ValueIterator::ValueIterator(const ValueConstIterator& other)
2422 : ValueIteratorBase(other) {
2423 throwRuntimeError("ConstIterator to Iterator should never be allowed.");
2426 ValueIterator::ValueIterator(const ValueIterator& other)
2427 : ValueIteratorBase(other) {}
2429 ValueIterator& ValueIterator::operator=(const SelfType& other) {
2436 // //////////////////////////////////////////////////////////////////////
2437 // End of content of file: src/lib_json/json_valueiterator.inl
2438 // //////////////////////////////////////////////////////////////////////
2445 // //////////////////////////////////////////////////////////////////////
2446 // Beginning of content of file: src/lib_json/json_value.cpp
2447 // //////////////////////////////////////////////////////////////////////
2449 // Copyright 2011 Baptiste Lepilleur
2450 // Distributed under MIT license, or public domain if desired and
2451 // recognized in your jurisdiction.
2452 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
2454 #if !defined(JSON_IS_AMALGAMATION)
2455 #include <json/assertions.h>
2456 #include <json/value.h>
2457 #include <json/writer.h>
2458 #endif // if !defined(JSON_IS_AMALGAMATION)
2464 #ifdef JSON_USE_CPPTL
2465 #include <cpptl/conststring.h>
2467 #include <cstddef> // size_t
2468 #include <algorithm> // min()
2470 #define JSON_ASSERT_UNREACHABLE assert(false)
2474 // This is a walkaround to avoid the static initialization of Value::null.
2475 // kNull must be word-aligned to avoid crashing on ARM. We use an alignment of
2476 // 8 (instead of 4) as a bit of future-proofing.
2477 #if defined(__ARMEL__)
2478 #define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
2480 #define ALIGNAS(byte_alignment)
2482 //static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
2483 //const unsigned char& kNullRef = kNull[0];
2484 //const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
2485 //const Value& Value::nullRef = null;
2488 Value const& Value::nullSingleton()
2490 static Value const nullStatic;
2494 // for backwards compatibility, we'll leave these global references around, but DO NOT
2495 // use them in JSONCPP library code any more!
2496 Value const& Value::null = Value::nullSingleton();
2497 Value const& Value::nullRef = Value::nullSingleton();
2499 const Int Value::minInt = Int(~(UInt(-1) / 2));
2500 const Int Value::maxInt = Int(UInt(-1) / 2);
2501 const UInt Value::maxUInt = UInt(-1);
2502 #if defined(JSON_HAS_INT64)
2503 const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2));
2504 const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2);
2505 const UInt64 Value::maxUInt64 = UInt64(-1);
2506 // The constant is hard-coded because some compiler have trouble
2507 // converting Value::maxUInt64 to a double correctly (AIX/xlC).
2508 // Assumes that UInt64 is a 64 bits integer.
2509 static const double maxUInt64AsDouble = 18446744073709551615.0;
2510 #endif // defined(JSON_HAS_INT64)
2511 const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
2512 const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
2513 const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
2515 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2516 template <typename T, typename U>
2517 static inline bool InRange(double d, T min, U max) {
2518 // The casts can lose precision, but we are looking only for
2519 // an approximate range. Might fail on edge cases though. ~cdunn
2520 //return d >= static_cast<double>(min) && d <= static_cast<double>(max);
2521 return d >= min && d <= max;
2523 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2524 static inline double integerToDouble(Json::UInt64 value) {
2525 return static_cast<double>(Int64(value / 2)) * 2.0 + static_cast<double>(Int64(value & 1));
2528 template <typename T> static inline double integerToDouble(T value) {
2529 return static_cast<double>(value);
2532 template <typename T, typename U>
2533 static inline bool InRange(double d, T min, U max) {
2534 return d >= integerToDouble(min) && d <= integerToDouble(max);
2536 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2538 /** Duplicates the specified string value.
2539 * @param value Pointer to the string to duplicate. Must be zero-terminated if
2540 * length is "unknown".
2541 * @param length Length of the value. if equals to unknown, then it will be
2542 * computed using strlen(value).
2543 * @return Pointer on the duplicate instance of string.
2545 static inline char* duplicateStringValue(const char* value,
2548 // Avoid an integer overflow in the call to malloc below by limiting length
2550 if (length >= static_cast<size_t>(Value::maxInt))
2551 length = Value::maxInt - 1;
2553 char* newString = static_cast<char*>(malloc(length + 1));
2554 if (newString == NULL) {
2556 "in Json::Value::duplicateStringValue(): "
2557 "Failed to allocate string value buffer");
2559 memcpy(newString, value, length);
2560 newString[length] = 0;
2564 /* Record the length as a prefix.
2566 static inline char* duplicateAndPrefixStringValue(
2568 unsigned int length)
2570 // Avoid an integer overflow in the call to malloc below by limiting length
2572 JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) - sizeof(unsigned) - 1U,
2573 "in Json::Value::duplicateAndPrefixStringValue(): "
2574 "length too big for prefixing");
2575 unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U;
2576 char* newString = static_cast<char*>(malloc(actualLength));
2577 if (newString == 0) {
2579 "in Json::Value::duplicateAndPrefixStringValue(): "
2580 "Failed to allocate string value buffer");
2582 *reinterpret_cast<unsigned*>(newString) = length;
2583 memcpy(newString + sizeof(unsigned), value, length);
2584 newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later
2587 inline static void decodePrefixedString(
2588 bool isPrefixed, char const* prefixed,
2589 unsigned* length, char const** value)
2592 *length = static_cast<unsigned>(strlen(prefixed));
2595 *length = *reinterpret_cast<unsigned const*>(prefixed);
2596 *value = prefixed + sizeof(unsigned);
2599 /** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue().
2601 #if JSONCPP_USING_SECURE_MEMORY
2602 static inline void releasePrefixedStringValue(char* value) {
2603 unsigned length = 0;
2604 char const* valueDecoded;
2605 decodePrefixedString(true, value, &length, &valueDecoded);
2606 size_t const size = sizeof(unsigned) + length + 1U;
2607 memset(value, 0, size);
2610 static inline void releaseStringValue(char* value, unsigned length) {
2611 // length==0 => we allocated the strings memory
2612 size_t size = (length==0) ? strlen(value) : length;
2613 memset(value, 0, size);
2616 #else // !JSONCPP_USING_SECURE_MEMORY
2617 static inline void releasePrefixedStringValue(char* value) {
2620 static inline void releaseStringValue(char* value, unsigned) {
2623 #endif // JSONCPP_USING_SECURE_MEMORY
2627 // //////////////////////////////////////////////////////////////////
2628 // //////////////////////////////////////////////////////////////////
2629 // //////////////////////////////////////////////////////////////////
2630 // ValueInternals...
2631 // //////////////////////////////////////////////////////////////////
2632 // //////////////////////////////////////////////////////////////////
2633 // //////////////////////////////////////////////////////////////////
2634 #if !defined(JSON_IS_AMALGAMATION)
2636 #include "json_valueiterator.inl"
2637 #endif // if !defined(JSON_IS_AMALGAMATION)
2641 Exception::Exception(JSONCPP_STRING const& msg)
2644 Exception::~Exception() JSONCPP_NOEXCEPT
2646 char const* Exception::what() const JSONCPP_NOEXCEPT
2648 return msg_.c_str();
2650 RuntimeError::RuntimeError(JSONCPP_STRING const& msg)
2653 LogicError::LogicError(JSONCPP_STRING const& msg)
2656 JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg)
2658 throw RuntimeError(msg);
2660 JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg)
2662 throw LogicError(msg);
2665 // //////////////////////////////////////////////////////////////////
2666 // //////////////////////////////////////////////////////////////////
2667 // //////////////////////////////////////////////////////////////////
2668 // class Value::CommentInfo
2669 // //////////////////////////////////////////////////////////////////
2670 // //////////////////////////////////////////////////////////////////
2671 // //////////////////////////////////////////////////////////////////
2673 Value::CommentInfo::CommentInfo() : comment_(0)
2676 Value::CommentInfo::~CommentInfo() {
2678 releaseStringValue(comment_, 0u);
2681 void Value::CommentInfo::setComment(const char* text, size_t len) {
2683 releaseStringValue(comment_, 0u);
2686 JSON_ASSERT(text != 0);
2687 JSON_ASSERT_MESSAGE(
2688 text[0] == '\0' || text[0] == '/',
2689 "in Json::Value::setComment(): Comments must start with /");
2690 // It seems that /**/ style comments are acceptable as well.
2691 comment_ = duplicateStringValue(text, len);
2694 // //////////////////////////////////////////////////////////////////
2695 // //////////////////////////////////////////////////////////////////
2696 // //////////////////////////////////////////////////////////////////
2697 // class Value::CZString
2698 // //////////////////////////////////////////////////////////////////
2699 // //////////////////////////////////////////////////////////////////
2700 // //////////////////////////////////////////////////////////////////
2702 // Notes: policy_ indicates if the string was allocated when
2703 // a string is stored.
2705 Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {}
2707 Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate)
2709 // allocate != duplicate
2710 storage_.policy_ = allocate & 0x3;
2711 storage_.length_ = ulength & 0x3FFFFFFF;
2714 Value::CZString::CZString(const CZString& other) {
2715 cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != 0
2716 ? duplicateStringValue(other.cstr_, other.storage_.length_)
2718 storage_.policy_ = static_cast<unsigned>(other.cstr_
2719 ? (static_cast<DuplicationPolicy>(other.storage_.policy_) == noDuplication
2720 ? noDuplication : duplicate)
2721 : static_cast<DuplicationPolicy>(other.storage_.policy_)) & 3U;
2722 storage_.length_ = other.storage_.length_;
2725 #if JSON_HAS_RVALUE_REFERENCES
2726 Value::CZString::CZString(CZString&& other)
2727 : cstr_(other.cstr_), index_(other.index_) {
2728 other.cstr_ = nullptr;
2732 Value::CZString::~CZString() {
2733 if (cstr_ && storage_.policy_ == duplicate) {
2734 releaseStringValue(const_cast<char*>(cstr_), storage_.length_ + 1u); //+1 for null terminating character for sake of completeness but not actually necessary
2738 void Value::CZString::swap(CZString& other) {
2739 std::swap(cstr_, other.cstr_);
2740 std::swap(index_, other.index_);
2743 Value::CZString& Value::CZString::operator=(CZString other) {
2748 bool Value::CZString::operator<(const CZString& other) const {
2749 if (!cstr_) return index_ < other.index_;
2750 //return strcmp(cstr_, other.cstr_) < 0;
2751 // Assume both are strings.
2752 unsigned this_len = this->storage_.length_;
2753 unsigned other_len = other.storage_.length_;
2754 unsigned min_len = std::min(this_len, other_len);
2755 JSON_ASSERT(this->cstr_ && other.cstr_);
2756 int comp = memcmp(this->cstr_, other.cstr_, min_len);
2757 if (comp < 0) return true;
2758 if (comp > 0) return false;
2759 return (this_len < other_len);
2762 bool Value::CZString::operator==(const CZString& other) const {
2763 if (!cstr_) return index_ == other.index_;
2764 //return strcmp(cstr_, other.cstr_) == 0;
2765 // Assume both are strings.
2766 unsigned this_len = this->storage_.length_;
2767 unsigned other_len = other.storage_.length_;
2768 if (this_len != other_len) return false;
2769 JSON_ASSERT(this->cstr_ && other.cstr_);
2770 int comp = memcmp(this->cstr_, other.cstr_, this_len);
2774 ArrayIndex Value::CZString::index() const { return index_; }
2776 //const char* Value::CZString::c_str() const { return cstr_; }
2777 const char* Value::CZString::data() const { return cstr_; }
2778 unsigned Value::CZString::length() const { return storage_.length_; }
2779 bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; }
2781 // //////////////////////////////////////////////////////////////////
2782 // //////////////////////////////////////////////////////////////////
2783 // //////////////////////////////////////////////////////////////////
2784 // class Value::Value
2785 // //////////////////////////////////////////////////////////////////
2786 // //////////////////////////////////////////////////////////////////
2787 // //////////////////////////////////////////////////////////////////
2789 /*! \internal Default constructor initialization must be equivalent to:
2790 * memset( this, 0, sizeof(Value) )
2791 * This optimization is used in ValueInternalMap fast allocator.
2793 Value::Value(ValueType vtype) {
2794 static char const emptyString[] = "";
2807 // allocated_ == false, so this is safe.
2808 value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString));
2812 value_.map_ = new ObjectValues();
2815 value_.bool_ = false;
2818 JSON_ASSERT_UNREACHABLE;
2822 Value::Value(Int value) {
2823 initBasic(intValue);
2824 value_.int_ = value;
2827 Value::Value(UInt value) {
2828 initBasic(uintValue);
2829 value_.uint_ = value;
2831 #if defined(JSON_HAS_INT64)
2832 Value::Value(Int64 value) {
2833 initBasic(intValue);
2834 value_.int_ = value;
2836 Value::Value(UInt64 value) {
2837 initBasic(uintValue);
2838 value_.uint_ = value;
2840 #endif // defined(JSON_HAS_INT64)
2842 Value::Value(double value) {
2843 initBasic(realValue);
2844 value_.real_ = value;
2847 Value::Value(const char* value) {
2848 initBasic(stringValue, true);
2849 value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value)));
2852 Value::Value(const char* beginValue, const char* endValue) {
2853 initBasic(stringValue, true);
2855 duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue));
2858 Value::Value(const JSONCPP_STRING& value) {
2859 initBasic(stringValue, true);
2861 duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length()));
2864 Value::Value(const StaticString& value) {
2865 initBasic(stringValue);
2866 value_.string_ = const_cast<char*>(value.c_str());
2869 #ifdef JSON_USE_CPPTL
2870 Value::Value(const CppTL::ConstString& value) {
2871 initBasic(stringValue, true);
2872 value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length()));
2876 Value::Value(bool value) {
2877 initBasic(booleanValue);
2878 value_.bool_ = value;
2881 Value::Value(Value const& other)
2882 : type_(other.type_), allocated_(false)
2884 comments_(0), start_(other.start_), limit_(other.limit_)
2892 value_ = other.value_;
2895 if (other.value_.string_ && other.allocated_) {
2898 decodePrefixedString(other.allocated_, other.value_.string_,
2900 value_.string_ = duplicateAndPrefixStringValue(str, len);
2903 value_.string_ = other.value_.string_;
2909 value_.map_ = new ObjectValues(*other.value_.map_);
2912 JSON_ASSERT_UNREACHABLE;
2914 if (other.comments_) {
2915 comments_ = new CommentInfo[numberOfCommentPlacement];
2916 for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {
2917 const CommentInfo& otherComment = other.comments_[comment];
2918 if (otherComment.comment_)
2919 comments_[comment].setComment(
2920 otherComment.comment_, strlen(otherComment.comment_));
2925 #if JSON_HAS_RVALUE_REFERENCES
2927 Value::Value(Value&& other) {
2928 initBasic(nullValue);
2943 releasePrefixedStringValue(value_.string_);
2950 JSON_ASSERT_UNREACHABLE;
2958 Value& Value::operator=(Value other) {
2963 void Value::swapPayload(Value& other) {
2964 ValueType temp = type_;
2965 type_ = other.type_;
2967 std::swap(value_, other.value_);
2968 int temp2 = allocated_;
2969 allocated_ = other.allocated_;
2970 other.allocated_ = temp2 & 0x1;
2973 void Value::swap(Value& other) {
2975 std::swap(comments_, other.comments_);
2976 std::swap(start_, other.start_);
2977 std::swap(limit_, other.limit_);
2980 ValueType Value::type() const { return type_; }
2982 int Value::compare(const Value& other) const {
2990 bool Value::operator<(const Value& other) const {
2991 int typeDelta = type_ - other.type_;
2993 return typeDelta < 0 ? true : false;
2998 return value_.int_ < other.value_.int_;
3000 return value_.uint_ < other.value_.uint_;
3002 return value_.real_ < other.value_.real_;
3004 return value_.bool_ < other.value_.bool_;
3007 if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
3008 if (other.value_.string_) return true;
3013 char const* this_str;
3014 char const* other_str;
3015 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
3016 decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
3017 unsigned min_len = std::min(this_len, other_len);
3018 JSON_ASSERT(this_str && other_str);
3019 int comp = memcmp(this_str, other_str, min_len);
3020 if (comp < 0) return true;
3021 if (comp > 0) return false;
3022 return (this_len < other_len);
3026 int delta = int(value_.map_->size() - other.value_.map_->size());
3029 return (*value_.map_) < (*other.value_.map_);
3032 JSON_ASSERT_UNREACHABLE;
3034 return false; // unreachable
3037 bool Value::operator<=(const Value& other) const { return !(other < *this); }
3039 bool Value::operator>=(const Value& other) const { return !(*this < other); }
3041 bool Value::operator>(const Value& other) const { return other < *this; }
3043 bool Value::operator==(const Value& other) const {
3044 // if ( type_ != other.type_ )
3046 // attempt to take address of bit-field structure member `Json::Value::type_'
3047 // Beats me, but a temp solves the problem.
3048 int temp = other.type_;
3055 return value_.int_ == other.value_.int_;
3057 return value_.uint_ == other.value_.uint_;
3059 return value_.real_ == other.value_.real_;
3061 return value_.bool_ == other.value_.bool_;
3064 if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
3065 return (value_.string_ == other.value_.string_);
3069 char const* this_str;
3070 char const* other_str;
3071 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
3072 decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
3073 if (this_len != other_len) return false;
3074 JSON_ASSERT(this_str && other_str);
3075 int comp = memcmp(this_str, other_str, this_len);
3080 return value_.map_->size() == other.value_.map_->size() &&
3081 (*value_.map_) == (*other.value_.map_);
3083 JSON_ASSERT_UNREACHABLE;
3085 return false; // unreachable
3088 bool Value::operator!=(const Value& other) const { return !(*this == other); }
3090 const char* Value::asCString() const {
3091 JSON_ASSERT_MESSAGE(type_ == stringValue,
3092 "in Json::Value::asCString(): requires stringValue");
3093 if (value_.string_ == 0) return 0;
3095 char const* this_str;
3096 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
3100 #if JSONCPP_USING_SECURE_MEMORY
3101 unsigned Value::getCStringLength() const {
3102 JSON_ASSERT_MESSAGE(type_ == stringValue,
3103 "in Json::Value::asCString(): requires stringValue");
3104 if (value_.string_ == 0) return 0;
3106 char const* this_str;
3107 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
3112 bool Value::getString(char const** str, char const** cend) const {
3113 if (type_ != stringValue) return false;
3114 if (value_.string_ == 0) return false;
3116 decodePrefixedString(this->allocated_, this->value_.string_, &length, str);
3117 *cend = *str + length;
3121 JSONCPP_STRING Value::asString() const {
3127 if (value_.string_ == 0) return "";
3129 char const* this_str;
3130 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
3131 return JSONCPP_STRING(this_str, this_len);
3134 return value_.bool_ ? "true" : "false";
3136 return valueToString(value_.int_);
3138 return valueToString(value_.uint_);
3140 return valueToString(value_.real_);
3142 JSON_FAIL_MESSAGE("Type is not convertible to string");
3146 #ifdef JSON_USE_CPPTL
3147 CppTL::ConstString Value::asConstString() const {
3150 decodePrefixedString(allocated_, value_.string_,
3152 return CppTL::ConstString(str, len);
3156 Value::Int Value::asInt() const {
3159 JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
3160 return Int(value_.int_);
3162 JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
3163 return Int(value_.uint_);
3165 JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
3166 "double out of Int range");
3167 return Int(value_.real_);
3171 return value_.bool_ ? 1 : 0;
3175 JSON_FAIL_MESSAGE("Value is not convertible to Int.");
3178 Value::UInt Value::asUInt() const {
3181 JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
3182 return UInt(value_.int_);
3184 JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
3185 return UInt(value_.uint_);
3187 JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
3188 "double out of UInt range");
3189 return UInt(value_.real_);
3193 return value_.bool_ ? 1 : 0;
3197 JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
3200 #if defined(JSON_HAS_INT64)
3202 Value::Int64 Value::asInt64() const {
3205 return Int64(value_.int_);
3207 JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
3208 return Int64(value_.uint_);
3210 JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
3211 "double out of Int64 range");
3212 return Int64(value_.real_);
3216 return value_.bool_ ? 1 : 0;
3220 JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
3223 Value::UInt64 Value::asUInt64() const {
3226 JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
3227 return UInt64(value_.int_);
3229 return UInt64(value_.uint_);
3231 JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
3232 "double out of UInt64 range");
3233 return UInt64(value_.real_);
3237 return value_.bool_ ? 1 : 0;
3241 JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
3243 #endif // if defined(JSON_HAS_INT64)
3245 LargestInt Value::asLargestInt() const {
3246 #if defined(JSON_NO_INT64)
3253 LargestUInt Value::asLargestUInt() const {
3254 #if defined(JSON_NO_INT64)
3261 double Value::asDouble() const {
3264 return static_cast<double>(value_.int_);
3266 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3267 return static_cast<double>(value_.uint_);
3268 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3269 return integerToDouble(value_.uint_);
3270 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3272 return value_.real_;
3276 return value_.bool_ ? 1.0 : 0.0;
3280 JSON_FAIL_MESSAGE("Value is not convertible to double.");
3283 float Value::asFloat() const {
3286 return static_cast<float>(value_.int_);
3288 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3289 return static_cast<float>(value_.uint_);
3290 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3291 // This can fail (silently?) if the value is bigger than MAX_FLOAT.
3292 return static_cast<float>(integerToDouble(value_.uint_));
3293 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3295 return static_cast<float>(value_.real_);
3299 return value_.bool_ ? 1.0f : 0.0f;
3303 JSON_FAIL_MESSAGE("Value is not convertible to float.");
3306 bool Value::asBool() const {
3309 return value_.bool_;
3313 return value_.int_ ? true : false;
3315 return value_.uint_ ? true : false;
3317 // This is kind of strange. Not recommended.
3318 return (value_.real_ != 0.0) ? true : false;
3322 JSON_FAIL_MESSAGE("Value is not convertible to bool.");
3325 bool Value::isConvertibleTo(ValueType other) const {
3328 return (isNumeric() && asDouble() == 0.0) ||
3329 (type_ == booleanValue && value_.bool_ == false) ||
3330 (type_ == stringValue && asString() == "") ||
3331 (type_ == arrayValue && value_.map_->size() == 0) ||
3332 (type_ == objectValue && value_.map_->size() == 0) ||
3336 (type_ == realValue && InRange(value_.real_, minInt, maxInt)) ||
3337 type_ == booleanValue || type_ == nullValue;
3340 (type_ == realValue && InRange(value_.real_, 0, maxUInt)) ||
3341 type_ == booleanValue || type_ == nullValue;
3343 return isNumeric() || type_ == booleanValue || type_ == nullValue;
3345 return isNumeric() || type_ == booleanValue || type_ == nullValue;
3347 return isNumeric() || type_ == booleanValue || type_ == stringValue ||
3350 return type_ == arrayValue || type_ == nullValue;
3352 return type_ == objectValue || type_ == nullValue;
3354 JSON_ASSERT_UNREACHABLE;
3358 /// Number of values in array or object
3359 ArrayIndex Value::size() const {
3368 case arrayValue: // size of the array is highest index + 1
3369 if (!value_.map_->empty()) {
3370 ObjectValues::const_iterator itLast = value_.map_->end();
3372 return (*itLast).first.index() + 1;
3376 return ArrayIndex(value_.map_->size());
3378 JSON_ASSERT_UNREACHABLE;
3379 return 0; // unreachable;
3382 bool Value::empty() const {
3383 if (isNull() || isArray() || isObject())
3384 return size() == 0u;
3389 bool Value::operator!() const { return isNull(); }
3391 void Value::clear() {
3392 JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue ||
3393 type_ == objectValue,
3394 "in Json::Value::clear(): requires complex value");
3400 value_.map_->clear();
3407 void Value::resize(ArrayIndex newSize) {
3408 JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,
3409 "in Json::Value::resize(): requires arrayValue");
3410 if (type_ == nullValue)
3411 *this = Value(arrayValue);
3412 ArrayIndex oldSize = size();
3415 else if (newSize > oldSize)
3416 (*this)[newSize - 1];
3418 for (ArrayIndex index = newSize; index < oldSize; ++index) {
3419 value_.map_->erase(index);
3421 JSON_ASSERT(size() == newSize);
3425 Value& Value::operator[](ArrayIndex index) {
3426 JSON_ASSERT_MESSAGE(
3427 type_ == nullValue || type_ == arrayValue,
3428 "in Json::Value::operator[](ArrayIndex): requires arrayValue");
3429 if (type_ == nullValue)
3430 *this = Value(arrayValue);
3431 CZString key(index);
3432 ObjectValues::iterator it = value_.map_->lower_bound(key);
3433 if (it != value_.map_->end() && (*it).first == key)
3434 return (*it).second;
3436 ObjectValues::value_type defaultValue(key, nullSingleton());
3437 it = value_.map_->insert(it, defaultValue);
3438 return (*it).second;
3441 Value& Value::operator[](int index) {
3442 JSON_ASSERT_MESSAGE(
3444 "in Json::Value::operator[](int index): index cannot be negative");
3445 return (*this)[ArrayIndex(index)];
3448 const Value& Value::operator[](ArrayIndex index) const {
3449 JSON_ASSERT_MESSAGE(
3450 type_ == nullValue || type_ == arrayValue,
3451 "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
3452 if (type_ == nullValue)
3453 return nullSingleton();
3454 CZString key(index);
3455 ObjectValues::const_iterator it = value_.map_->find(key);
3456 if (it == value_.map_->end())
3457 return nullSingleton();
3458 return (*it).second;
3461 const Value& Value::operator[](int index) const {
3462 JSON_ASSERT_MESSAGE(
3464 "in Json::Value::operator[](int index) const: index cannot be negative");
3465 return (*this)[ArrayIndex(index)];
3468 void Value::initBasic(ValueType vtype, bool allocated) {
3470 allocated_ = allocated;
3476 // Access an object value by name, create a null member if it does not exist.
3477 // @pre Type of '*this' is object or null.
3478 // @param key is null-terminated.
3479 Value& Value::resolveReference(const char* key) {
3480 JSON_ASSERT_MESSAGE(
3481 type_ == nullValue || type_ == objectValue,
3482 "in Json::Value::resolveReference(): requires objectValue");
3483 if (type_ == nullValue)
3484 *this = Value(objectValue);
3486 key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE!
3487 ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
3488 if (it != value_.map_->end() && (*it).first == actualKey)
3489 return (*it).second;
3491 ObjectValues::value_type defaultValue(actualKey, nullSingleton());
3492 it = value_.map_->insert(it, defaultValue);
3493 Value& value = (*it).second;
3497 // @param key is not null-terminated.
3498 Value& Value::resolveReference(char const* key, char const* cend)
3500 JSON_ASSERT_MESSAGE(
3501 type_ == nullValue || type_ == objectValue,
3502 "in Json::Value::resolveReference(key, end): requires objectValue");
3503 if (type_ == nullValue)
3504 *this = Value(objectValue);
3506 key, static_cast<unsigned>(cend-key), CZString::duplicateOnCopy);
3507 ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
3508 if (it != value_.map_->end() && (*it).first == actualKey)
3509 return (*it).second;
3511 ObjectValues::value_type defaultValue(actualKey, nullSingleton());
3512 it = value_.map_->insert(it, defaultValue);
3513 Value& value = (*it).second;
3517 Value Value::get(ArrayIndex index, const Value& defaultValue) const {
3518 const Value* value = &((*this)[index]);
3519 return value == &nullSingleton() ? defaultValue : *value;
3522 bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
3524 Value const* Value::find(char const* key, char const* cend) const
3526 JSON_ASSERT_MESSAGE(
3527 type_ == nullValue || type_ == objectValue,
3528 "in Json::Value::find(key, end, found): requires objectValue or nullValue");
3529 if (type_ == nullValue) return NULL;
3530 CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
3531 ObjectValues::const_iterator it = value_.map_->find(actualKey);
3532 if (it == value_.map_->end()) return NULL;
3533 return &(*it).second;
3535 const Value& Value::operator[](const char* key) const
3537 Value const* found = find(key, key + strlen(key));
3538 if (!found) return nullSingleton();
3541 Value const& Value::operator[](JSONCPP_STRING const& key) const
3543 Value const* found = find(key.data(), key.data() + key.length());
3544 if (!found) return nullSingleton();
3548 Value& Value::operator[](const char* key) {
3549 return resolveReference(key, key + strlen(key));
3552 Value& Value::operator[](const JSONCPP_STRING& key) {
3553 return resolveReference(key.data(), key.data() + key.length());
3556 Value& Value::operator[](const StaticString& key) {
3557 return resolveReference(key.c_str());
3560 #ifdef JSON_USE_CPPTL
3561 Value& Value::operator[](const CppTL::ConstString& key) {
3562 return resolveReference(key.c_str(), key.end_c_str());
3564 Value const& Value::operator[](CppTL::ConstString const& key) const
3566 Value const* found = find(key.c_str(), key.end_c_str());
3567 if (!found) return nullSingleton();
3572 Value& Value::append(const Value& value) { return (*this)[size()] = value; }
3574 Value Value::get(char const* key, char const* cend, Value const& defaultValue) const
3576 Value const* found = find(key, cend);
3577 return !found ? defaultValue : *found;
3579 Value Value::get(char const* key, Value const& defaultValue) const
3581 return get(key, key + strlen(key), defaultValue);
3583 Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue) const
3585 return get(key.data(), key.data() + key.length(), defaultValue);
3589 bool Value::removeMember(const char* key, const char* cend, Value* removed)
3591 if (type_ != objectValue) {
3594 CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
3595 ObjectValues::iterator it = value_.map_->find(actualKey);
3596 if (it == value_.map_->end())
3598 *removed = it->second;
3599 value_.map_->erase(it);
3602 bool Value::removeMember(const char* key, Value* removed)
3604 return removeMember(key, key + strlen(key), removed);
3606 bool Value::removeMember(JSONCPP_STRING const& key, Value* removed)
3608 return removeMember(key.data(), key.data() + key.length(), removed);
3610 Value Value::removeMember(const char* key)
3612 JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
3613 "in Json::Value::removeMember(): requires objectValue");
3614 if (type_ == nullValue)
3615 return nullSingleton();
3617 Value removed; // null
3618 removeMember(key, key + strlen(key), &removed);
3619 return removed; // still null if removeMember() did nothing
3621 Value Value::removeMember(const JSONCPP_STRING& key)
3623 return removeMember(key.c_str());
3626 bool Value::removeIndex(ArrayIndex index, Value* removed) {
3627 if (type_ != arrayValue) {
3630 CZString key(index);
3631 ObjectValues::iterator it = value_.map_->find(key);
3632 if (it == value_.map_->end()) {
3635 *removed = it->second;
3636 ArrayIndex oldSize = size();
3637 // shift left all items left, into the place of the "removed"
3638 for (ArrayIndex i = index; i < (oldSize - 1); ++i){
3640 (*value_.map_)[keey] = (*this)[i + 1];
3642 // erase the last one ("leftover")
3643 CZString keyLast(oldSize - 1);
3644 ObjectValues::iterator itLast = value_.map_->find(keyLast);
3645 value_.map_->erase(itLast);
3649 #ifdef JSON_USE_CPPTL
3650 Value Value::get(const CppTL::ConstString& key,
3651 const Value& defaultValue) const {
3652 return get(key.c_str(), key.end_c_str(), defaultValue);
3656 bool Value::isMember(char const* key, char const* cend) const
3658 Value const* value = find(key, cend);
3659 return NULL != value;
3661 bool Value::isMember(char const* key) const
3663 return isMember(key, key + strlen(key));
3665 bool Value::isMember(JSONCPP_STRING const& key) const
3667 return isMember(key.data(), key.data() + key.length());
3670 #ifdef JSON_USE_CPPTL
3671 bool Value::isMember(const CppTL::ConstString& key) const {
3672 return isMember(key.c_str(), key.end_c_str());
3676 Value::Members Value::getMemberNames() const {
3677 JSON_ASSERT_MESSAGE(
3678 type_ == nullValue || type_ == objectValue,
3679 "in Json::Value::getMemberNames(), value must be objectValue");
3680 if (type_ == nullValue)
3681 return Value::Members();
3683 members.reserve(value_.map_->size());
3684 ObjectValues::const_iterator it = value_.map_->begin();
3685 ObjectValues::const_iterator itEnd = value_.map_->end();
3686 for (; it != itEnd; ++it) {
3687 members.push_back(JSONCPP_STRING((*it).first.data(),
3688 (*it).first.length()));
3693 //# ifdef JSON_USE_CPPTL
3695 // Value::enumMemberNames() const
3697 // if ( type_ == objectValue )
3699 // return CppTL::Enum::any( CppTL::Enum::transform(
3700 // CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
3701 // MemberNamesTransform() ) );
3703 // return EnumMemberNames();
3708 // Value::enumValues() const
3710 // if ( type_ == objectValue || type_ == arrayValue )
3711 // return CppTL::Enum::anyValues( *(value_.map_),
3712 // CppTL::Type<const Value &>() );
3713 // return EnumValues();
3718 static bool IsIntegral(double d) {
3719 double integral_part;
3720 return modf(d, &integral_part) == 0.0;
3723 bool Value::isNull() const { return type_ == nullValue; }
3725 bool Value::isBool() const { return type_ == booleanValue; }
3727 bool Value::isInt() const {
3730 #if defined(JSON_HAS_INT64)
3731 return value_.int_ >= minInt && value_.int_ <= maxInt;
3736 return value_.uint_ <= UInt(maxInt);
3738 return value_.real_ >= minInt && value_.real_ <= maxInt &&
3739 IsIntegral(value_.real_);
3746 bool Value::isUInt() const {
3749 #if defined(JSON_HAS_INT64)
3750 return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
3752 return value_.int_ >= 0;
3755 #if defined(JSON_HAS_INT64)
3756 return value_.uint_ <= maxUInt;
3761 return value_.real_ >= 0 && value_.real_ <= maxUInt &&
3762 IsIntegral(value_.real_);
3769 bool Value::isInt64() const {
3770 #if defined(JSON_HAS_INT64)
3775 return value_.uint_ <= UInt64(maxInt64);
3777 // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
3778 // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
3779 // require the value to be strictly less than the limit.
3780 return value_.real_ >= double(minInt64) &&
3781 value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
3785 #endif // JSON_HAS_INT64
3789 bool Value::isUInt64() const {
3790 #if defined(JSON_HAS_INT64)
3793 return value_.int_ >= 0;
3797 // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
3798 // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
3799 // require the value to be strictly less than the limit.
3800 return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
3801 IsIntegral(value_.real_);
3805 #endif // JSON_HAS_INT64
3809 bool Value::isIntegral() const {
3810 #if defined(JSON_HAS_INT64)
3811 return isInt64() || isUInt64();
3813 return isInt() || isUInt();
3817 bool Value::isDouble() const { return type_ == intValue || type_ == uintValue || type_ == realValue; }
3819 bool Value::isNumeric() const { return isDouble(); }
3821 bool Value::isString() const { return type_ == stringValue; }
3823 bool Value::isArray() const { return type_ == arrayValue; }
3825 bool Value::isObject() const { return type_ == objectValue; }
3827 void Value::setComment(const char* comment, size_t len, CommentPlacement placement) {
3829 comments_ = new CommentInfo[numberOfCommentPlacement];
3830 if ((len > 0) && (comment[len-1] == '\n')) {
3831 // Always discard trailing newline, to aid indentation.
3834 comments_[placement].setComment(comment, len);
3837 void Value::setComment(const char* comment, CommentPlacement placement) {
3838 setComment(comment, strlen(comment), placement);
3841 void Value::setComment(const JSONCPP_STRING& comment, CommentPlacement placement) {
3842 setComment(comment.c_str(), comment.length(), placement);
3845 bool Value::hasComment(CommentPlacement placement) const {
3846 return comments_ != 0 && comments_[placement].comment_ != 0;
3849 JSONCPP_STRING Value::getComment(CommentPlacement placement) const {
3850 if (hasComment(placement))
3851 return comments_[placement].comment_;
3855 void Value::setOffsetStart(ptrdiff_t start) { start_ = start; }
3857 void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; }
3859 ptrdiff_t Value::getOffsetStart() const { return start_; }
3861 ptrdiff_t Value::getOffsetLimit() const { return limit_; }
3863 JSONCPP_STRING Value::toStyledString() const {
3864 StyledWriter writer;
3865 return writer.write(*this);
3868 Value::const_iterator Value::begin() const {
3873 return const_iterator(value_.map_->begin());
3878 return const_iterator();
3881 Value::const_iterator Value::end() const {
3886 return const_iterator(value_.map_->end());
3891 return const_iterator();
3894 Value::iterator Value::begin() {
3899 return iterator(value_.map_->begin());
3907 Value::iterator Value::end() {
3912 return iterator(value_.map_->end());
3920 // class PathArgument
3921 // //////////////////////////////////////////////////////////////////
3923 PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {}
3925 PathArgument::PathArgument(ArrayIndex index)
3926 : key_(), index_(index), kind_(kindIndex) {}
3928 PathArgument::PathArgument(const char* key)
3929 : key_(key), index_(), kind_(kindKey) {}
3931 PathArgument::PathArgument(const JSONCPP_STRING& key)
3932 : key_(key.c_str()), index_(), kind_(kindKey) {}
3935 // //////////////////////////////////////////////////////////////////
3937 Path::Path(const JSONCPP_STRING& path,
3938 const PathArgument& a1,
3939 const PathArgument& a2,
3940 const PathArgument& a3,
3941 const PathArgument& a4,
3942 const PathArgument& a5) {
3952 void Path::makePath(const JSONCPP_STRING& path, const InArgs& in) {
3953 const char* current = path.c_str();
3954 const char* end = current + path.length();
3955 InArgs::const_iterator itInArg = in.begin();
3956 while (current != end) {
3957 if (*current == '[') {
3959 if (*current == '%')
3960 addPathInArg(path, in, itInArg, PathArgument::kindIndex);
3962 ArrayIndex index = 0;
3963 for (; current != end && *current >= '0' && *current <= '9'; ++current)
3964 index = index * 10 + ArrayIndex(*current - '0');
3965 args_.push_back(index);
3967 if (current == end || *++current != ']')
3968 invalidPath(path, int(current - path.c_str()));
3969 } else if (*current == '%') {
3970 addPathInArg(path, in, itInArg, PathArgument::kindKey);
3972 } else if (*current == '.' || *current == ']') {
3975 const char* beginName = current;
3976 while (current != end && !strchr("[.", *current))
3978 args_.push_back(JSONCPP_STRING(beginName, current));
3983 void Path::addPathInArg(const JSONCPP_STRING& /*path*/,
3985 InArgs::const_iterator& itInArg,
3986 PathArgument::Kind kind) {
3987 if (itInArg == in.end()) {
3988 // Error: missing argument %d
3989 } else if ((*itInArg)->kind_ != kind) {
3990 // Error: bad argument type
3992 args_.push_back(**itInArg++);
3996 void Path::invalidPath(const JSONCPP_STRING& /*path*/, int /*location*/) {
3997 // Error: invalid path.
4000 const Value& Path::resolve(const Value& root) const {
4001 const Value* node = &root;
4002 for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
4003 const PathArgument& arg = *it;
4004 if (arg.kind_ == PathArgument::kindIndex) {
4005 if (!node->isArray() || !node->isValidIndex(arg.index_)) {
4006 // Error: unable to resolve path (array value expected at position...
4009 node = &((*node)[arg.index_]);
4010 } else if (arg.kind_ == PathArgument::kindKey) {
4011 if (!node->isObject()) {
4012 // Error: unable to resolve path (object value expected at position...)
4015 node = &((*node)[arg.key_]);
4016 if (node == &Value::nullSingleton()) {
4017 // Error: unable to resolve path (object has no member named '' at
4026 Value Path::resolve(const Value& root, const Value& defaultValue) const {
4027 const Value* node = &root;
4028 for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
4029 const PathArgument& arg = *it;
4030 if (arg.kind_ == PathArgument::kindIndex) {
4031 if (!node->isArray() || !node->isValidIndex(arg.index_))
4032 return defaultValue;
4033 node = &((*node)[arg.index_]);
4034 } else if (arg.kind_ == PathArgument::kindKey) {
4035 if (!node->isObject())
4036 return defaultValue;
4037 node = &((*node)[arg.key_]);
4038 if (node == &Value::nullSingleton())
4039 return defaultValue;
4045 Value& Path::make(Value& root) const {
4046 Value* node = &root;
4047 for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
4048 const PathArgument& arg = *it;
4049 if (arg.kind_ == PathArgument::kindIndex) {
4050 if (!node->isArray()) {
4051 // Error: node is not an array at position ...
4053 node = &((*node)[arg.index_]);
4054 } else if (arg.kind_ == PathArgument::kindKey) {
4055 if (!node->isObject()) {
4056 // Error: node is not an object at position...
4058 node = &((*node)[arg.key_]);
4066 // //////////////////////////////////////////////////////////////////////
4067 // End of content of file: src/lib_json/json_value.cpp
4068 // //////////////////////////////////////////////////////////////////////
4075 // //////////////////////////////////////////////////////////////////////
4076 // Beginning of content of file: src/lib_json/json_writer.cpp
4077 // //////////////////////////////////////////////////////////////////////
4079 // Copyright 2011 Baptiste Lepilleur
4080 // Distributed under MIT license, or public domain if desired and
4081 // recognized in your jurisdiction.
4082 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
4084 #if !defined(JSON_IS_AMALGAMATION)
4085 #include <json/writer.h>
4086 #include "json_tool.h"
4087 #endif // if !defined(JSON_IS_AMALGAMATION)
4097 #if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0
4099 #define isfinite _finite
4100 #elif defined(__sun) && defined(__SVR4) //Solaris
4101 #if !defined(isfinite)
4103 #define isfinite finite
4106 #if !defined(isfinite)
4108 #define isfinite finite
4110 #elif defined(__hpux)
4111 #if !defined(isfinite)
4112 #if defined(__ia64) && !defined(finite)
4113 #define isfinite(x) ((sizeof(x) == sizeof(float) ? \
4114 _Isfinitef(x) : _IsFinite(x)))
4117 #define isfinite finite
4122 #if !(defined(__QNXNTO__)) // QNX already defines isfinite
4123 #define isfinite std::isfinite
4127 #if defined(_MSC_VER)
4128 #if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
4129 #define snprintf sprintf_s
4130 #elif _MSC_VER >= 1900 // VC++ 14.0 and above
4131 #define snprintf std::snprintf
4133 #define snprintf _snprintf
4135 #elif defined(__ANDROID__) || defined(__QNXNTO__)
4136 #define snprintf snprintf
4137 #elif __cplusplus >= 201103L
4138 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
4139 #define snprintf std::snprintf
4143 #if defined(__BORLANDC__)
4145 #define isfinite _finite
4146 #define snprintf _snprintf
4149 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
4150 // Disable warning about strdup being deprecated.
4151 #pragma warning(disable : 4996)
4156 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
4157 typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
4159 typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
4162 static bool containsControlCharacter(const char* str) {
4164 if (isControlCharacter(*(str++)))
4170 static bool containsControlCharacter0(const char* str, unsigned len) {
4171 char const* end = str + len;
4172 while (end != str) {
4173 if (isControlCharacter(*str) || 0==*str)
4180 JSONCPP_STRING valueToString(LargestInt value) {
4181 UIntToStringBuffer buffer;
4182 char* current = buffer + sizeof(buffer);
4183 if (value == Value::minLargestInt) {
4184 uintToString(LargestUInt(Value::maxLargestInt) + 1, current);
4186 } else if (value < 0) {
4187 uintToString(LargestUInt(-value), current);
4190 uintToString(LargestUInt(value), current);
4192 assert(current >= buffer);
4196 JSONCPP_STRING valueToString(LargestUInt value) {
4197 UIntToStringBuffer buffer;
4198 char* current = buffer + sizeof(buffer);
4199 uintToString(value, current);
4200 assert(current >= buffer);
4204 #if defined(JSON_HAS_INT64)
4206 JSONCPP_STRING valueToString(Int value) {
4207 return valueToString(LargestInt(value));
4210 JSONCPP_STRING valueToString(UInt value) {
4211 return valueToString(LargestUInt(value));
4214 #endif // # if defined(JSON_HAS_INT64)
4217 JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) {
4218 // Allocate a buffer that is more than large enough to store the 16 digits of
4219 // precision requested below.
4223 char formatString[6];
4224 sprintf(formatString, "%%.%dg", precision);
4226 // Print into the buffer. We need not request the alternative representation
4227 // that always has a decimal point because JSON doesn't distingish the
4228 // concepts of reals and integers.
4229 if (isfinite(value)) {
4230 len = snprintf(buffer, sizeof(buffer), formatString, value);
4232 // try to ensure we preserve the fact that this was given to us as a double on input
4233 if (!strstr(buffer, ".") && !strstr(buffer, "e")) {
4234 strcat(buffer, ".0");
4238 // IEEE standard states that NaN values will not compare to themselves
4239 if (value != value) {
4240 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");
4241 } else if (value < 0) {
4242 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999");
4244 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999");
4246 // For those, we do not need to call fixNumLoc, but it is fast.
4249 fixNumericLocale(buffer, buffer + len);
4254 JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); }
4256 JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; }
4258 JSONCPP_STRING valueToQuotedString(const char* value) {
4261 // Not sure how to handle unicode...
4262 if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL &&
4263 !containsControlCharacter(value))
4264 return JSONCPP_STRING("\"") + value + "\"";
4265 // We have to walk value and escape any special characters.
4266 // Appending to JSONCPP_STRING is not efficient, but this should be rare.
4267 // (Note: forward slashes are *not* rare, but I am not escaping them.)
4268 JSONCPP_STRING::size_type maxsize =
4269 strlen(value) * 2 + 3; // allescaped+quotes+NULL
4270 JSONCPP_STRING result;
4271 result.reserve(maxsize); // to avoid lots of mallocs
4273 for (const char* c = value; *c != 0; ++c) {
4297 // Even though \/ is considered a legal escape in JSON, a bare
4298 // slash is also legal, so I see no reason to escape it.
4299 // (I hope I am not misunderstanding something.
4300 // blep notes: actually escaping \/ may be useful in javascript to avoid </
4302 // Should add a flag to allow this compatibility mode and prevent this
4303 // sequence from occurring.
4305 if (isControlCharacter(*c)) {
4306 JSONCPP_OSTRINGSTREAM oss;
4307 oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
4308 << std::setw(4) << static_cast<int>(*c);
4309 result += oss.str();
4320 // https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp
4321 static char const* strnpbrk(char const* s, char const* accept, size_t n) {
4322 assert((s || !n) && accept);
4324 char const* const end = s + n;
4325 for (char const* cur = s; cur < end; ++cur) {
4327 for (char const* a = accept; *a; ++a) {
4335 static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) {
4338 // Not sure how to handle unicode...
4339 if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL &&
4340 !containsControlCharacter0(value, length))
4341 return JSONCPP_STRING("\"") + value + "\"";
4342 // We have to walk value and escape any special characters.
4343 // Appending to JSONCPP_STRING is not efficient, but this should be rare.
4344 // (Note: forward slashes are *not* rare, but I am not escaping them.)
4345 JSONCPP_STRING::size_type maxsize =
4346 length * 2 + 3; // allescaped+quotes+NULL
4347 JSONCPP_STRING result;
4348 result.reserve(maxsize); // to avoid lots of mallocs
4350 char const* end = value + length;
4351 for (const char* c = value; c != end; ++c) {
4375 // Even though \/ is considered a legal escape in JSON, a bare
4376 // slash is also legal, so I see no reason to escape it.
4377 // (I hope I am not misunderstanding something.)
4378 // blep notes: actually escaping \/ may be useful in javascript to avoid </
4380 // Should add a flag to allow this compatibility mode and prevent this
4381 // sequence from occurring.
4383 if ((isControlCharacter(*c)) || (*c == 0)) {
4384 JSONCPP_OSTRINGSTREAM oss;
4385 oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
4386 << std::setw(4) << static_cast<int>(*c);
4387 result += oss.str();
4399 // //////////////////////////////////////////////////////////////////
4400 Writer::~Writer() {}
4403 // //////////////////////////////////////////////////////////////////
4405 FastWriter::FastWriter()
4406 : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false),
4407 omitEndingLineFeed_(false) {}
4409 void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
4411 void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
4413 void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
4415 JSONCPP_STRING FastWriter::write(const Value& root) {
4418 if (!omitEndingLineFeed_)
4423 void FastWriter::writeValue(const Value& value) {
4424 switch (value.type()) {
4426 if (!dropNullPlaceholders_)
4427 document_ += "null";
4430 document_ += valueToString(value.asLargestInt());
4433 document_ += valueToString(value.asLargestUInt());
4436 document_ += valueToString(value.asDouble());
4440 // Is NULL possible for value.string_? No.
4443 bool ok = value.getString(&str, &end);
4444 if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str));
4448 document_ += valueToString(value.asBool());
4452 ArrayIndex size = value.size();
4453 for (ArrayIndex index = 0; index < size; ++index) {
4456 writeValue(value[index]);
4461 Value::Members members(value.getMemberNames());
4463 for (Value::Members::iterator it = members.begin(); it != members.end();
4465 const JSONCPP_STRING& name = *it;
4466 if (it != members.begin())
4468 document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()));
4469 document_ += yamlCompatiblityEnabled_ ? ": " : ":";
4470 writeValue(value[name]);
4477 // Class StyledWriter
4478 // //////////////////////////////////////////////////////////////////
4480 StyledWriter::StyledWriter()
4481 : rightMargin_(74), indentSize_(3), addChildValues_() {}
4483 JSONCPP_STRING StyledWriter::write(const Value& root) {
4485 addChildValues_ = false;
4487 writeCommentBeforeValue(root);
4489 writeCommentAfterValueOnSameLine(root);
4494 void StyledWriter::writeValue(const Value& value) {
4495 switch (value.type()) {
4500 pushValue(valueToString(value.asLargestInt()));
4503 pushValue(valueToString(value.asLargestUInt()));
4506 pushValue(valueToString(value.asDouble()));
4510 // Is NULL possible for value.string_? No.
4513 bool ok = value.getString(&str, &end);
4514 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
4519 pushValue(valueToString(value.asBool()));
4522 writeArrayValue(value);
4525 Value::Members members(value.getMemberNames());
4526 if (members.empty())
4529 writeWithIndent("{");
4531 Value::Members::iterator it = members.begin();
4533 const JSONCPP_STRING& name = *it;
4534 const Value& childValue = value[name];
4535 writeCommentBeforeValue(childValue);
4536 writeWithIndent(valueToQuotedString(name.c_str()));
4538 writeValue(childValue);
4539 if (++it == members.end()) {
4540 writeCommentAfterValueOnSameLine(childValue);
4544 writeCommentAfterValueOnSameLine(childValue);
4547 writeWithIndent("}");
4553 void StyledWriter::writeArrayValue(const Value& value) {
4554 unsigned size = value.size();
4558 bool isArrayMultiLine = isMultineArray(value);
4559 if (isArrayMultiLine) {
4560 writeWithIndent("[");
4562 bool hasChildValue = !childValues_.empty();
4565 const Value& childValue = value[index];
4566 writeCommentBeforeValue(childValue);
4568 writeWithIndent(childValues_[index]);
4571 writeValue(childValue);
4573 if (++index == size) {
4574 writeCommentAfterValueOnSameLine(childValue);
4578 writeCommentAfterValueOnSameLine(childValue);
4581 writeWithIndent("]");
4582 } else // output on a single line
4584 assert(childValues_.size() == size);
4586 for (unsigned index = 0; index < size; ++index) {
4589 document_ += childValues_[index];
4596 bool StyledWriter::isMultineArray(const Value& value) {
4597 ArrayIndex const size = value.size();
4598 bool isMultiLine = size * 3 >= rightMargin_;
4599 childValues_.clear();
4600 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
4601 const Value& childValue = value[index];
4602 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
4603 childValue.size() > 0);
4605 if (!isMultiLine) // check if line length > max line length
4607 childValues_.reserve(size);
4608 addChildValues_ = true;
4609 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
4610 for (ArrayIndex index = 0; index < size; ++index) {
4611 if (hasCommentForValue(value[index])) {
4614 writeValue(value[index]);
4615 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
4617 addChildValues_ = false;
4618 isMultiLine = isMultiLine || lineLength >= rightMargin_;
4623 void StyledWriter::pushValue(const JSONCPP_STRING& value) {
4624 if (addChildValues_)
4625 childValues_.push_back(value);
4630 void StyledWriter::writeIndent() {
4631 if (!document_.empty()) {
4632 char last = document_[document_.length() - 1];
4633 if (last == ' ') // already indented
4635 if (last != '\n') // Comments may add new-line
4638 document_ += indentString_;
4641 void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) {
4646 void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); }
4648 void StyledWriter::unindent() {
4649 assert(indentString_.size() >= indentSize_);
4650 indentString_.resize(indentString_.size() - indentSize_);
4653 void StyledWriter::writeCommentBeforeValue(const Value& root) {
4654 if (!root.hasComment(commentBefore))
4659 const JSONCPP_STRING& comment = root.getComment(commentBefore);
4660 JSONCPP_STRING::const_iterator iter = comment.begin();
4661 while (iter != comment.end()) {
4663 if (*iter == '\n' &&
4664 (iter != comment.end() && *(iter + 1) == '/'))
4669 // Comments are stripped of trailing newlines, so add one here
4673 void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
4674 if (root.hasComment(commentAfterOnSameLine))
4675 document_ += " " + root.getComment(commentAfterOnSameLine);
4677 if (root.hasComment(commentAfter)) {
4679 document_ += root.getComment(commentAfter);
4684 bool StyledWriter::hasCommentForValue(const Value& value) {
4685 return value.hasComment(commentBefore) ||
4686 value.hasComment(commentAfterOnSameLine) ||
4687 value.hasComment(commentAfter);
4690 // Class StyledStreamWriter
4691 // //////////////////////////////////////////////////////////////////
4693 StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation)
4694 : document_(NULL), rightMargin_(74), indentation_(indentation),
4695 addChildValues_() {}
4697 void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) {
4699 addChildValues_ = false;
4702 writeCommentBeforeValue(root);
4703 if (!indented_) writeIndent();
4706 writeCommentAfterValueOnSameLine(root);
4708 document_ = NULL; // Forget the stream, for safety.
4711 void StyledStreamWriter::writeValue(const Value& value) {
4712 switch (value.type()) {
4717 pushValue(valueToString(value.asLargestInt()));
4720 pushValue(valueToString(value.asLargestUInt()));
4723 pushValue(valueToString(value.asDouble()));
4727 // Is NULL possible for value.string_? No.
4730 bool ok = value.getString(&str, &end);
4731 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
4736 pushValue(valueToString(value.asBool()));
4739 writeArrayValue(value);
4742 Value::Members members(value.getMemberNames());
4743 if (members.empty())
4746 writeWithIndent("{");
4748 Value::Members::iterator it = members.begin();
4750 const JSONCPP_STRING& name = *it;
4751 const Value& childValue = value[name];
4752 writeCommentBeforeValue(childValue);
4753 writeWithIndent(valueToQuotedString(name.c_str()));
4754 *document_ << " : ";
4755 writeValue(childValue);
4756 if (++it == members.end()) {
4757 writeCommentAfterValueOnSameLine(childValue);
4761 writeCommentAfterValueOnSameLine(childValue);
4764 writeWithIndent("}");
4770 void StyledStreamWriter::writeArrayValue(const Value& value) {
4771 unsigned size = value.size();
4775 bool isArrayMultiLine = isMultineArray(value);
4776 if (isArrayMultiLine) {
4777 writeWithIndent("[");
4779 bool hasChildValue = !childValues_.empty();
4782 const Value& childValue = value[index];
4783 writeCommentBeforeValue(childValue);
4785 writeWithIndent(childValues_[index]);
4787 if (!indented_) writeIndent();
4789 writeValue(childValue);
4792 if (++index == size) {
4793 writeCommentAfterValueOnSameLine(childValue);
4797 writeCommentAfterValueOnSameLine(childValue);
4800 writeWithIndent("]");
4801 } else // output on a single line
4803 assert(childValues_.size() == size);
4805 for (unsigned index = 0; index < size; ++index) {
4808 *document_ << childValues_[index];
4815 bool StyledStreamWriter::isMultineArray(const Value& value) {
4816 ArrayIndex const size = value.size();
4817 bool isMultiLine = size * 3 >= rightMargin_;
4818 childValues_.clear();
4819 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
4820 const Value& childValue = value[index];
4821 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
4822 childValue.size() > 0);
4824 if (!isMultiLine) // check if line length > max line length
4826 childValues_.reserve(size);
4827 addChildValues_ = true;
4828 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
4829 for (ArrayIndex index = 0; index < size; ++index) {
4830 if (hasCommentForValue(value[index])) {
4833 writeValue(value[index]);
4834 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
4836 addChildValues_ = false;
4837 isMultiLine = isMultiLine || lineLength >= rightMargin_;
4842 void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) {
4843 if (addChildValues_)
4844 childValues_.push_back(value);
4846 *document_ << value;
4849 void StyledStreamWriter::writeIndent() {
4850 // blep intended this to look at the so-far-written string
4851 // to determine whether we are already indented, but
4852 // with a stream we cannot do that. So we rely on some saved state.
4853 // The caller checks indented_.
4854 *document_ << '\n' << indentString_;
4857 void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) {
4858 if (!indented_) writeIndent();
4859 *document_ << value;
4863 void StyledStreamWriter::indent() { indentString_ += indentation_; }
4865 void StyledStreamWriter::unindent() {
4866 assert(indentString_.size() >= indentation_.size());
4867 indentString_.resize(indentString_.size() - indentation_.size());
4870 void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
4871 if (!root.hasComment(commentBefore))
4874 if (!indented_) writeIndent();
4875 const JSONCPP_STRING& comment = root.getComment(commentBefore);
4876 JSONCPP_STRING::const_iterator iter = comment.begin();
4877 while (iter != comment.end()) {
4878 *document_ << *iter;
4879 if (*iter == '\n' &&
4880 (iter != comment.end() && *(iter + 1) == '/'))
4881 // writeIndent(); // would include newline
4882 *document_ << indentString_;
4888 void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
4889 if (root.hasComment(commentAfterOnSameLine))
4890 *document_ << ' ' << root.getComment(commentAfterOnSameLine);
4892 if (root.hasComment(commentAfter)) {
4894 *document_ << root.getComment(commentAfter);
4899 bool StyledStreamWriter::hasCommentForValue(const Value& value) {
4900 return value.hasComment(commentBefore) ||
4901 value.hasComment(commentAfterOnSameLine) ||
4902 value.hasComment(commentAfter);
4905 //////////////////////////
4906 // BuiltStyledStreamWriter
4908 /// Scoped enums are not available until C++11.
4909 struct CommentStyle {
4910 /// Decide whether to write comments.
4912 None, ///< Drop all comments.
4913 Most, ///< Recover odd behavior of previous versions (not implemented yet).
4914 All ///< Keep all comments.
4918 struct BuiltStyledStreamWriter : public StreamWriter
4920 BuiltStyledStreamWriter(
4921 JSONCPP_STRING const& indentation,
4922 CommentStyle::Enum cs,
4923 JSONCPP_STRING const& colonSymbol,
4924 JSONCPP_STRING const& nullSymbol,
4925 JSONCPP_STRING const& endingLineFeedSymbol,
4926 bool useSpecialFloats,
4927 unsigned int precision);
4928 int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE;
4930 void writeValue(Value const& value);
4931 void writeArrayValue(Value const& value);
4932 bool isMultineArray(Value const& value);
4933 void pushValue(JSONCPP_STRING const& value);
4935 void writeWithIndent(JSONCPP_STRING const& value);
4938 void writeCommentBeforeValue(Value const& root);
4939 void writeCommentAfterValueOnSameLine(Value const& root);
4940 static bool hasCommentForValue(const Value& value);
4942 typedef std::vector<JSONCPP_STRING> ChildValues;
4944 ChildValues childValues_;
4945 JSONCPP_STRING indentString_;
4946 unsigned int rightMargin_;
4947 JSONCPP_STRING indentation_;
4948 CommentStyle::Enum cs_;
4949 JSONCPP_STRING colonSymbol_;
4950 JSONCPP_STRING nullSymbol_;
4951 JSONCPP_STRING endingLineFeedSymbol_;
4952 bool addChildValues_ : 1;
4954 bool useSpecialFloats_ : 1;
4955 unsigned int precision_;
4957 BuiltStyledStreamWriter::BuiltStyledStreamWriter(
4958 JSONCPP_STRING const& indentation,
4959 CommentStyle::Enum cs,
4960 JSONCPP_STRING const& colonSymbol,
4961 JSONCPP_STRING const& nullSymbol,
4962 JSONCPP_STRING const& endingLineFeedSymbol,
4963 bool useSpecialFloats,
4964 unsigned int precision)
4966 , indentation_(indentation)
4968 , colonSymbol_(colonSymbol)
4969 , nullSymbol_(nullSymbol)
4970 , endingLineFeedSymbol_(endingLineFeedSymbol)
4971 , addChildValues_(false)
4973 , useSpecialFloats_(useSpecialFloats)
4974 , precision_(precision)
4977 int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout)
4980 addChildValues_ = false;
4983 writeCommentBeforeValue(root);
4984 if (!indented_) writeIndent();
4987 writeCommentAfterValueOnSameLine(root);
4988 *sout_ << endingLineFeedSymbol_;
4992 void BuiltStyledStreamWriter::writeValue(Value const& value) {
4993 switch (value.type()) {
4995 pushValue(nullSymbol_);
4998 pushValue(valueToString(value.asLargestInt()));
5001 pushValue(valueToString(value.asLargestUInt()));
5004 pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
5008 // Is NULL is possible for value.string_? No.
5011 bool ok = value.getString(&str, &end);
5012 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
5017 pushValue(valueToString(value.asBool()));
5020 writeArrayValue(value);
5023 Value::Members members(value.getMemberNames());
5024 if (members.empty())
5027 writeWithIndent("{");
5029 Value::Members::iterator it = members.begin();
5031 JSONCPP_STRING const& name = *it;
5032 Value const& childValue = value[name];
5033 writeCommentBeforeValue(childValue);
5034 writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())));
5035 *sout_ << colonSymbol_;
5036 writeValue(childValue);
5037 if (++it == members.end()) {
5038 writeCommentAfterValueOnSameLine(childValue);
5042 writeCommentAfterValueOnSameLine(childValue);
5045 writeWithIndent("}");
5051 void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
5052 unsigned size = value.size();
5056 bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value);
5058 writeWithIndent("[");
5060 bool hasChildValue = !childValues_.empty();
5063 Value const& childValue = value[index];
5064 writeCommentBeforeValue(childValue);
5066 writeWithIndent(childValues_[index]);
5068 if (!indented_) writeIndent();
5070 writeValue(childValue);
5073 if (++index == size) {
5074 writeCommentAfterValueOnSameLine(childValue);
5078 writeCommentAfterValueOnSameLine(childValue);
5081 writeWithIndent("]");
5082 } else // output on a single line
5084 assert(childValues_.size() == size);
5086 if (!indentation_.empty()) *sout_ << " ";
5087 for (unsigned index = 0; index < size; ++index) {
5089 *sout_ << ((!indentation_.empty()) ? ", " : ",");
5090 *sout_ << childValues_[index];
5092 if (!indentation_.empty()) *sout_ << " ";
5098 bool BuiltStyledStreamWriter::isMultineArray(Value const& value) {
5099 ArrayIndex const size = value.size();
5100 bool isMultiLine = size * 3 >= rightMargin_;
5101 childValues_.clear();
5102 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
5103 Value const& childValue = value[index];
5104 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
5105 childValue.size() > 0);
5107 if (!isMultiLine) // check if line length > max line length
5109 childValues_.reserve(size);
5110 addChildValues_ = true;
5111 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
5112 for (ArrayIndex index = 0; index < size; ++index) {
5113 if (hasCommentForValue(value[index])) {
5116 writeValue(value[index]);
5117 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
5119 addChildValues_ = false;
5120 isMultiLine = isMultiLine || lineLength >= rightMargin_;
5125 void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) {
5126 if (addChildValues_)
5127 childValues_.push_back(value);
5132 void BuiltStyledStreamWriter::writeIndent() {
5133 // blep intended this to look at the so-far-written string
5134 // to determine whether we are already indented, but
5135 // with a stream we cannot do that. So we rely on some saved state.
5136 // The caller checks indented_.
5138 if (!indentation_.empty()) {
5139 // In this case, drop newlines too.
5140 *sout_ << '\n' << indentString_;
5144 void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) {
5145 if (!indented_) writeIndent();
5150 void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
5152 void BuiltStyledStreamWriter::unindent() {
5153 assert(indentString_.size() >= indentation_.size());
5154 indentString_.resize(indentString_.size() - indentation_.size());
5157 void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
5158 if (cs_ == CommentStyle::None) return;
5159 if (!root.hasComment(commentBefore))
5162 if (!indented_) writeIndent();
5163 const JSONCPP_STRING& comment = root.getComment(commentBefore);
5164 JSONCPP_STRING::const_iterator iter = comment.begin();
5165 while (iter != comment.end()) {
5167 if (*iter == '\n' &&
5168 (iter != comment.end() && *(iter + 1) == '/'))
5169 // writeIndent(); // would write extra newline
5170 *sout_ << indentString_;
5176 void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) {
5177 if (cs_ == CommentStyle::None) return;
5178 if (root.hasComment(commentAfterOnSameLine))
5179 *sout_ << " " + root.getComment(commentAfterOnSameLine);
5181 if (root.hasComment(commentAfter)) {
5183 *sout_ << root.getComment(commentAfter);
5188 bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
5189 return value.hasComment(commentBefore) ||
5190 value.hasComment(commentAfterOnSameLine) ||
5191 value.hasComment(commentAfter);
5197 StreamWriter::StreamWriter()
5201 StreamWriter::~StreamWriter()
5204 StreamWriter::Factory::~Factory()
5206 StreamWriterBuilder::StreamWriterBuilder()
5208 setDefaults(&settings_);
5210 StreamWriterBuilder::~StreamWriterBuilder()
5212 StreamWriter* StreamWriterBuilder::newStreamWriter() const
5214 JSONCPP_STRING indentation = settings_["indentation"].asString();
5215 JSONCPP_STRING cs_str = settings_["commentStyle"].asString();
5216 bool eyc = settings_["enableYAMLCompatibility"].asBool();
5217 bool dnp = settings_["dropNullPlaceholders"].asBool();
5218 bool usf = settings_["useSpecialFloats"].asBool();
5219 unsigned int pre = settings_["precision"].asUInt();
5220 CommentStyle::Enum cs = CommentStyle::All;
5221 if (cs_str == "All") {
5222 cs = CommentStyle::All;
5223 } else if (cs_str == "None") {
5224 cs = CommentStyle::None;
5226 throwRuntimeError("commentStyle must be 'All' or 'None'");
5228 JSONCPP_STRING colonSymbol = " : ";
5231 } else if (indentation.empty()) {
5234 JSONCPP_STRING nullSymbol = "null";
5238 if (pre > 17) pre = 17;
5239 JSONCPP_STRING endingLineFeedSymbol = "";
5240 return new BuiltStyledStreamWriter(
5242 colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);
5244 static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys)
5246 valid_keys->clear();
5247 valid_keys->insert("indentation");
5248 valid_keys->insert("commentStyle");
5249 valid_keys->insert("enableYAMLCompatibility");
5250 valid_keys->insert("dropNullPlaceholders");
5251 valid_keys->insert("useSpecialFloats");
5252 valid_keys->insert("precision");
5254 bool StreamWriterBuilder::validate(Json::Value* invalid) const
5256 Json::Value my_invalid;
5257 if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
5258 Json::Value& inv = *invalid;
5259 std::set<JSONCPP_STRING> valid_keys;
5260 getValidWriterKeys(&valid_keys);
5261 Value::Members keys = settings_.getMemberNames();
5262 size_t n = keys.size();
5263 for (size_t i = 0; i < n; ++i) {
5264 JSONCPP_STRING const& key = keys[i];
5265 if (valid_keys.find(key) == valid_keys.end()) {
5266 inv[key] = settings_[key];
5269 return 0u == inv.size();
5271 Value& StreamWriterBuilder::operator[](JSONCPP_STRING key)
5273 return settings_[key];
5276 void StreamWriterBuilder::setDefaults(Json::Value* settings)
5278 //! [StreamWriterBuilderDefaults]
5279 (*settings)["commentStyle"] = "All";
5280 (*settings)["indentation"] = "\t";
5281 (*settings)["enableYAMLCompatibility"] = false;
5282 (*settings)["dropNullPlaceholders"] = false;
5283 (*settings)["useSpecialFloats"] = false;
5284 (*settings)["precision"] = 17;
5285 //! [StreamWriterBuilderDefaults]
5288 JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) {
5289 JSONCPP_OSTRINGSTREAM sout;
5290 StreamWriterPtr const writer(builder.newStreamWriter());
5291 writer->write(root, &sout);
5295 JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) {
5296 StreamWriterBuilder builder;
5297 StreamWriterPtr const writer(builder.newStreamWriter());
5298 writer->write(root, &sout);
5304 // //////////////////////////////////////////////////////////////////////
5305 // End of content of file: src/lib_json/json_writer.cpp
5306 // //////////////////////////////////////////////////////////////////////