diff options
Diffstat (limited to 'json/jsoncpp.cpp')
| -rw-r--r-- | json/jsoncpp.cpp | 1705 |
1 files changed, 918 insertions, 787 deletions
diff --git a/json/jsoncpp.cpp b/json/jsoncpp.cpp index 7634ed4f..c2a949d3 100644 --- a/json/jsoncpp.cpp +++ b/json/jsoncpp.cpp @@ -1,4 +1,4 @@ -/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). +/// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/). /// It is intended to be used with #include "json/json.h" // ////////////////////////////////////////////////////////////////////// @@ -10,13 +10,13 @@ The JsonCpp library's source code, including accompanying documentation, tests and demonstration applications, are licensed under the following conditions... -The author (Baptiste Lepilleur) explicitly disclaims copyright in all +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all jurisdictions which recognize such a disclaimer. In such jurisdictions, this software is released into the Public Domain. In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is -released under the terms of the MIT License (see below). +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). In jurisdictions which recognize Public Domain property, the user of this software may choose to accept it either as 1) Public Domain, 2) under the @@ -31,7 +31,7 @@ described in clear, concise terms at: The full text of the MIT License follows: ======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation @@ -84,7 +84,7 @@ license you like. // Beginning of content of file: src/lib_json/json_tool.h // ////////////////////////////////////////////////////////////////////// -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -92,6 +92,9 @@ license you like. #ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED #define LIB_JSONCPP_JSON_TOOL_H_INCLUDED +#ifndef JSON_CONFIG_H_INCLUDED +#include <json/config.h> +#endif // Also support old flag NO_LOCALE_SUPPORT #ifdef NO_LOCALE_SUPPORT @@ -109,7 +112,7 @@ license you like. */ namespace Json { -static char getDecimalPoint() { +static inline char getDecimalPoint() { #ifdef JSONCPP_NO_LOCALE_SUPPORT return '\0'; #else @@ -147,9 +150,6 @@ static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) { return result; } -/// Returns true if ch is a control character (in range [1,31]). -static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; } - enum { /// Constant that specify the size of the buffer that must be passed to /// uintToString. @@ -160,7 +160,7 @@ enum { typedef char UIntToStringBuffer[uintToStringBufferSize]; /** Converts an unsigned integer to string. - * @param value Unsigned interger to convert to string + * @param value Unsigned integer to convert to string * @param current Input/Output string buffer. * Must have at least uintToStringBufferSize chars free. */ @@ -177,28 +177,45 @@ static inline void uintToString(LargestUInt value, char*& current) { * We had a sophisticated way, but it did not work in WinCE. * @see https://github.com/open-source-parsers/jsoncpp/pull/9 */ -static inline void fixNumericLocale(char* begin, char* end) { - while (begin < end) { +template <typename Iter> Iter fixNumericLocale(Iter begin, Iter end) { + for (; begin != end; ++begin) { if (*begin == ',') { *begin = '.'; } - ++begin; } + return begin; } -static inline void fixNumericLocaleInput(char* begin, char* end) { +template <typename Iter> void fixNumericLocaleInput(Iter begin, Iter end) { char decimalPoint = getDecimalPoint(); - if (decimalPoint != '\0' && decimalPoint != '.') { - while (begin < end) { - if (*begin == '.') { - *begin = decimalPoint; - } - ++begin; + if (decimalPoint == '\0' || decimalPoint == '.') { + return; + } + for (; begin != end; ++begin) { + if (*begin == '.') { + *begin = decimalPoint; + } + } +} + +/** + * Return iterator that would be the new end of the range [begin,end), if we + * were to delete zeros in the end of string, but not the last zero before '.'. + */ +template <typename Iter> Iter fixZerosInTheEnd(Iter begin, Iter end) { + for (; begin != end; --end) { + if (*(end - 1) != '0') { + return end; + } + // Don't delete the last zero before the decimal point. + if (begin != (end - 1) && *(end - 2) == '.') { + return end; } } + return end; } -} // namespace Json { +} // namespace Json #endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED @@ -215,46 +232,46 @@ static inline void fixNumericLocaleInput(char* begin, char* end) { // Beginning of content of file: src/lib_json/json_reader.cpp // ////////////////////////////////////////////////////////////////////// -// Copyright 2007-2011 Baptiste Lepilleur +// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors // Copyright (C) 2016 InfoTeCS JSC. All rights reserved. // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #if !defined(JSON_IS_AMALGAMATION) +#include "json_tool.h" #include <json/assertions.h> #include <json/reader.h> #include <json/value.h> -#include "json_tool.h" #endif // if !defined(JSON_IS_AMALGAMATION) -#include <utility> -#include <cstdio> #include <cassert> #include <cstring> #include <istream> -#include <sstream> +#include <limits> #include <memory> #include <set> -#include <limits> +#include <sstream> +#include <utility> -#if defined(_MSC_VER) -#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above -#define snprintf sprintf_s -#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#if __cplusplus >= 201103L +#include <cstdio> + +#if !defined(snprintf) #define snprintf std::snprintf +#endif + +#if !defined(sscanf) +#define sscanf std::sscanf +#endif #else +#include <stdio.h> + +#if defined(_MSC_VER) +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 +#if !defined(snprintf) #define snprintf _snprintf #endif -#elif defined(__ANDROID__) || defined(__QNXNTO__) -#define snprintf snprintf -#elif __cplusplus >= 201103L -#if !defined(__MINGW32__) && !defined(__CYGWIN__) -#define snprintf std::snprintf -#endif #endif - -#if defined(__QNXNTO__) -#define sscanf std::sscanf #endif #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 @@ -262,19 +279,21 @@ static inline void fixNumericLocaleInput(char* begin, char* end) { #pragma warning(disable : 4996) #endif -// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile time to change the stack limit +// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile +// time to change the stack limit #if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) #define JSONCPP_DEPRECATED_STACK_LIMIT 1000 #endif -static size_t const stackLimit_g = JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue() +static size_t const stackLimit_g = + JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue() namespace Json { #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) typedef std::unique_ptr<CharReader> CharReaderPtr; #else -typedef std::auto_ptr<CharReader> CharReaderPtr; +typedef std::auto_ptr<CharReader> CharReaderPtr; #endif // Implementation of class Features @@ -298,7 +317,7 @@ Features Features::strictMode() { // Implementation of class Reader // //////////////////////////////// -static bool containsNewLine(Reader::Location begin, Reader::Location end) { +bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) { for (; begin < end; ++begin) if (*begin == '\n' || *begin == '\r') return true; @@ -318,10 +337,10 @@ Reader::Reader(const Features& features) lastValue_(), commentsBefore_(), features_(features), collectComments_() { } -bool -Reader::parse(const std::string& document, Value& root, bool collectComments) { - JSONCPP_STRING documentCopy(document.data(), document.data() + document.capacity()); - std::swap(documentCopy, document_); +bool Reader::parse(const std::string& document, + Value& root, + bool collectComments) { + document_.assign(document.begin(), document.end()); const char* begin = document_.c_str(); const char* end = begin + document_.length(); return parse(begin, end, root, collectComments); @@ -354,7 +373,7 @@ bool Reader::parse(const char* beginDoc, current_ = begin_; lastValueEnd_ = 0; lastValue_ = 0; - commentsBefore_ = ""; + commentsBefore_.clear(); errors_.clear(); while (!nodes_.empty()) nodes_.pop(); @@ -383,9 +402,11 @@ bool Reader::parse(const char* beginDoc, bool Reader::readValue() { // readValue() may call itself only if it calls readObject() or ReadArray(). - // These methods execute nodes_.push() just before and nodes_.pop)() just after calling readValue(). - // parse() executes one nodes_.push(), so > instead of >=. - if (nodes_.size() > stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue()."); + // These methods execute nodes_.push() just before and nodes_.pop)() just + // after calling readValue(). parse() executes one nodes_.push(), so > instead + // of >=. + if (nodes_.size() > stackLimit_g) + throwRuntimeError("Exceeded stackLimit in readValue()."); Token token; skipCommentTokens(token); @@ -393,7 +414,7 @@ bool Reader::readValue() { if (collectComments_ && !commentsBefore_.empty()) { currentValue().setComment(commentsBefore_, commentBefore); - commentsBefore_ = ""; + commentsBefore_.clear(); } switch (token.type_) { @@ -411,30 +432,24 @@ bool Reader::readValue() { case tokenString: successful = decodeString(token); break; - case tokenTrue: - { + case tokenTrue: { Value v(true); currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenFalse: - { + } break; + case tokenFalse: { Value v(false); currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNull: - { + } break; + case tokenNull: { Value v; currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; + } break; case tokenArraySeparator: case tokenObjectEnd: case tokenArrayEnd: @@ -587,7 +602,8 @@ bool Reader::readComment() { return true; } -static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Location end) { +JSONCPP_STRING Reader::normalizeEOL(Reader::Location begin, + Reader::Location end) { JSONCPP_STRING normalized; normalized.reserve(static_cast<size_t>(end - begin)); Reader::Location current = begin; @@ -595,8 +611,8 @@ static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Location end) char c = *current++; if (c == '\r') { if (current != end && *current == '\n') - // convert dos EOL - ++current; + // convert dos EOL + ++current; // convert Mac EOL normalized += '\n'; } else { @@ -606,8 +622,9 @@ static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Location end) return normalized; } -void -Reader::addComment(Location begin, Location end, CommentPlacement placement) { +void Reader::addComment(Location begin, + Location end, + CommentPlacement placement) { assert(collectComments_); const JSONCPP_STRING& normalized = normalizeEOL(begin, end); if (placement == commentAfterOnSameLine) { @@ -644,7 +661,7 @@ bool Reader::readCppStyleComment() { } void Reader::readNumber() { - const char *p = current_; + const char* p = current_; char c = '0'; // stopgap for already consumed character // integral part while (c >= '0' && c <= '9') @@ -691,7 +708,7 @@ bool Reader::readObject(Token& tokenStart) { break; if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object return true; - name = ""; + name.clear(); if (tokenName.type_ == tokenString) { if (!decodeString(tokenName, name)) return recoverFromError(tokenObjectEnd); @@ -706,8 +723,8 @@ bool Reader::readObject(Token& tokenStart) { Token colon; if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { - return addErrorAndRecover( - "Missing ':' after object member name", colon, tokenObjectEnd); + return addErrorAndRecover("Missing ':' after object member name", colon, + tokenObjectEnd); } Value& value = currentValue()[name]; nodes_.push(&value); @@ -720,8 +737,8 @@ bool Reader::readObject(Token& tokenStart) { if (!readToken(comma) || (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && comma.type_ != tokenComment)) { - return addErrorAndRecover( - "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); + return addErrorAndRecover("Missing ',' or '}' in object declaration", + comma, tokenObjectEnd); } bool finalizeTokenOk = true; while (comma.type_ == tokenComment && finalizeTokenOk) @@ -729,8 +746,8 @@ bool Reader::readObject(Token& tokenStart) { if (comma.type_ == tokenObjectEnd) return true; } - return addErrorAndRecover( - "Missing '}' or object member name", tokenName, tokenObjectEnd); + return addErrorAndRecover("Missing '}' or object member name", tokenName, + tokenObjectEnd); } bool Reader::readArray(Token& tokenStart) { @@ -762,8 +779,8 @@ bool Reader::readArray(Token& tokenStart) { bool badTokenType = (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); if (!ok || badTokenType) { - return addErrorAndRecover( - "Missing ',' or ']' in array declaration", token, tokenArrayEnd); + return addErrorAndRecover("Missing ',' or ']' in array declaration", + token, tokenArrayEnd); } if (token.type_ == tokenArrayEnd) break; @@ -789,7 +806,8 @@ bool Reader::decodeNumber(Token& token, Value& decoded) { bool isNegative = *current == '-'; if (isNegative) ++current; - // TODO: Help the compiler do the div and mod at compile time or get rid of them. + // TODO: Help the compiler do the div and mod at compile time or get rid of + // them. Value::LargestUInt maxIntegerValue = isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 : Value::maxLargestUInt; @@ -921,8 +939,7 @@ bool Reader::decodeUnicodeCodePoint(Token& token, if (end - current < 6) return addError( "additional six characters expected to parse unicode surrogate pair.", - token, - current); + token, current); unsigned int surrogatePair; if (*(current++) == '\\' && *(current++) == 'u') { if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { @@ -932,8 +949,7 @@ bool Reader::decodeUnicodeCodePoint(Token& token, } else return addError("expecting another \\u token to begin the second half of " "a unicode surrogate pair", - token, - current); + token, current); } return true; } @@ -944,8 +960,7 @@ bool Reader::decodeUnicodeEscapeSequence(Token& token, unsigned int& ret_unicode) { if (end - current < 4) return addError( - "Bad unicode escape sequence in string: four digits expected.", - token, + "Bad unicode escape sequence in string: four digits expected.", token, current); int unicode = 0; for (int index = 0; index < 4; ++index) { @@ -960,15 +975,15 @@ bool Reader::decodeUnicodeEscapeSequence(Token& token, else return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", - token, - current); + token, current); } ret_unicode = static_cast<unsigned int>(unicode); return true; } -bool -Reader::addError(const JSONCPP_STRING& message, Token& token, Location extra) { +bool Reader::addError(const JSONCPP_STRING& message, + Token& token, + Location extra) { ErrorInfo info; info.token_ = token; info.message_ = message; @@ -1044,8 +1059,7 @@ JSONCPP_STRING Reader::getFormatedErrorMessages() const { JSONCPP_STRING Reader::getFormattedErrorMessages() const { JSONCPP_STRING formattedMessage; for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { + itError != errors_.end(); ++itError) { const ErrorInfo& error = *itError; formattedMessage += "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; @@ -1060,8 +1074,7 @@ JSONCPP_STRING Reader::getFormattedErrorMessages() const { std::vector<Reader::StructuredError> Reader::getStructuredErrors() const { std::vector<Reader::StructuredError> allErrors; for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { + itError != errors_.end(); ++itError) { const ErrorInfo& error = *itError; Reader::StructuredError structured; structured.offset_start = error.token_.start_ - begin_; @@ -1074,8 +1087,7 @@ std::vector<Reader::StructuredError> Reader::getStructuredErrors() const { bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) { ptrdiff_t const length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length) + if (value.getOffsetStart() > length || value.getOffsetLimit() > length) return false; Token token; token.type_ = tokenError; @@ -1089,11 +1101,12 @@ bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) { return true; } -bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) { +bool Reader::pushError(const Value& value, + const JSONCPP_STRING& message, + const Value& extra) { ptrdiff_t const length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length - || extra.getOffsetLimit() > length) + if (value.getOffsetStart() > length || value.getOffsetLimit() > length || + extra.getOffsetLimit() > length) return false; Token token; token.type_ = tokenError; @@ -1107,9 +1120,7 @@ bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const return true; } -bool Reader::good() const { - return !errors_.size(); -} +bool Reader::good() const { return !errors_.size(); } // exact copy of Features class OurFeatures { @@ -1124,7 +1135,7 @@ public: bool rejectDupKeys_; bool allowSpecialFloats_; int stackLimit_; -}; // OurFeatures +}; // OurFeatures // exact copy of Implementation of class Features // //////////////////////////////// @@ -1153,12 +1164,14 @@ public: JSONCPP_STRING getFormattedErrorMessages() const; std::vector<StructuredError> getStructuredErrors() const; bool pushError(const Value& value, const JSONCPP_STRING& message); - bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); + bool pushError(const Value& value, + const JSONCPP_STRING& message, + const Value& extra); bool good() const; private: - OurReader(OurReader const&); // no impl - void operator=(OurReader const&); // no impl + OurReader(OurReader const&); // no impl + void operator=(OurReader const&); // no impl enum TokenType { tokenEndOfStream = 0, @@ -1222,7 +1235,8 @@ private: Location& current, Location end, unsigned int& unicode); - bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); + bool + addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); bool recoverFromError(TokenType skipUntilToken); bool addErrorAndRecover(const JSONCPP_STRING& message, Token& token, @@ -1236,6 +1250,9 @@ private: void addComment(Location begin, Location end, CommentPlacement placement); void skipCommentTokens(Token& token); + static JSONCPP_STRING normalizeEOL(Location begin, Location end); + static bool containsNewLine(Location begin, Location end); + typedef std::stack<Value*> Nodes; Nodes nodes_; Errors errors_; @@ -1249,20 +1266,27 @@ private: OurFeatures const features_; bool collectComments_; -}; // OurReader +}; // OurReader // complete copy of Read impl, for OurReader +bool OurReader::containsNewLine(OurReader::Location begin, + OurReader::Location end) { + for (; begin < end; ++begin) + if (*begin == '\n' || *begin == '\r') + return true; + return false; +} + OurReader::OurReader(OurFeatures const& features) : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), - lastValue_(), commentsBefore_(), - features_(features), collectComments_() { + lastValue_(), commentsBefore_(), features_(features), collectComments_() { } bool OurReader::parse(const char* beginDoc, - const char* endDoc, - Value& root, - bool collectComments) { + const char* endDoc, + Value& root, + bool collectComments) { if (!features_.allowComments_) { collectComments = false; } @@ -1273,7 +1297,7 @@ bool OurReader::parse(const char* beginDoc, current_ = begin_; lastValueEnd_ = 0; lastValue_ = 0; - commentsBefore_ = ""; + commentsBefore_.clear(); errors_.clear(); while (!nodes_.empty()) nodes_.pop(); @@ -1283,7 +1307,8 @@ bool OurReader::parse(const char* beginDoc, Token token; skipCommentTokens(token); if (features_.failIfExtra_) { - if ((features_.strictRoot_ || token.type_ != tokenError) && token.type_ != tokenEndOfStream) { + if ((features_.strictRoot_ || token.type_ != tokenError) && + token.type_ != tokenEndOfStream) { addError("Extra non-whitespace after JSON value.", token); return false; } @@ -1308,14 +1333,15 @@ bool OurReader::parse(const char* beginDoc, bool OurReader::readValue() { // To preserve the old behaviour we cast size_t to int. - if (static_cast<int>(nodes_.size()) > features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); + if (static_cast<int>(nodes_.size()) > features_.stackLimit_) + throwRuntimeError("Exceeded stackLimit in readValue()."); Token token; skipCommentTokens(token); bool successful = true; if (collectComments_ && !commentsBefore_.empty()) { currentValue().setComment(commentsBefore_, commentBefore); - commentsBefore_ = ""; + commentsBefore_.clear(); } switch (token.type_) { @@ -1333,54 +1359,42 @@ bool OurReader::readValue() { case tokenString: successful = decodeString(token); break; - case tokenTrue: - { + case tokenTrue: { Value v(true); currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenFalse: - { + } break; + case tokenFalse: { Value v(false); currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNull: - { + } break; + case tokenNull: { Value v; currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNaN: - { + } break; + case tokenNaN: { Value v(std::numeric_limits<double>::quiet_NaN()); currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenPosInf: - { + } break; + case tokenPosInf: { Value v(std::numeric_limits<double>::infinity()); currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNegInf: - { + } break; + case tokenNegInf: { Value v(-std::numeric_limits<double>::infinity()); currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; + } break; case tokenArraySeparator: case tokenObjectEnd: case tokenArrayEnd: @@ -1442,10 +1456,10 @@ bool OurReader::readToken(Token& token) { break; case '\'': if (features_.allowSingleQuotes_) { - token.type_ = tokenString; - ok = readStringSingleQuote(); - break; - } // else continue + token.type_ = tokenString; + ok = readStringSingleQuote(); + break; + } // else fall through case '/': token.type_ = tokenComment; ok = readComment(); @@ -1562,8 +1576,29 @@ bool OurReader::readComment() { return true; } -void -OurReader::addComment(Location begin, Location end, CommentPlacement placement) { +JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin, + OurReader::Location end) { + JSONCPP_STRING normalized; + normalized.reserve(static_cast<size_t>(end - begin)); + OurReader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + +void OurReader::addComment(Location begin, + Location end, + CommentPlacement placement) { assert(collectComments_); const JSONCPP_STRING& normalized = normalizeEOL(begin, end); if (placement == commentAfterOnSameLine) { @@ -1600,7 +1635,7 @@ bool OurReader::readCppStyleComment() { } bool OurReader::readNumber(bool checkInf) { - const char *p = current_; + const char* p = current_; if (checkInf && p != end_ && *p == 'I') { current_ = ++p; return false; @@ -1637,7 +1672,6 @@ bool OurReader::readString() { return c == '"'; } - bool OurReader::readStringSingleQuote() { Char c = 0; while (current_ != end_) { @@ -1664,7 +1698,7 @@ bool OurReader::readObject(Token& tokenStart) { break; if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object return true; - name = ""; + name.clear(); if (tokenName.type_ == tokenString) { if (!decodeString(tokenName, name)) return recoverFromError(tokenObjectEnd); @@ -1679,14 +1713,14 @@ bool OurReader::readObject(Token& tokenStart) { Token colon; if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { - return addErrorAndRecover( - "Missing ':' after object member name", colon, tokenObjectEnd); + return addErrorAndRecover("Missing ':' after object member name", colon, + tokenObjectEnd); } - if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30"); + if (name.length() >= (1U << 30)) + throwRuntimeError("keylength >= 2^30"); if (features_.rejectDupKeys_ && currentValue().isMember(name)) { JSONCPP_STRING msg = "Duplicate key: '" + name + "'"; - return addErrorAndRecover( - msg, tokenName, tokenObjectEnd); + return addErrorAndRecover(msg, tokenName, tokenObjectEnd); } Value& value = currentValue()[name]; nodes_.push(&value); @@ -1699,8 +1733,8 @@ bool OurReader::readObject(Token& tokenStart) { if (!readToken(comma) || (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && comma.type_ != tokenComment)) { - return addErrorAndRecover( - "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); + return addErrorAndRecover("Missing ',' or '}' in object declaration", + comma, tokenObjectEnd); } bool finalizeTokenOk = true; while (comma.type_ == tokenComment && finalizeTokenOk) @@ -1708,8 +1742,8 @@ bool OurReader::readObject(Token& tokenStart) { if (comma.type_ == tokenObjectEnd) return true; } - return addErrorAndRecover( - "Missing '}' or object member name", tokenName, tokenObjectEnd); + return addErrorAndRecover("Missing '}' or object member name", tokenName, + tokenObjectEnd); } bool OurReader::readArray(Token& tokenStart) { @@ -1741,8 +1775,8 @@ bool OurReader::readArray(Token& tokenStart) { bool badTokenType = (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); if (!ok || badTokenType) { - return addErrorAndRecover( - "Missing ',' or ']' in array declaration", token, tokenArrayEnd); + return addErrorAndRecover("Missing ',' or ']' in array declaration", + token, tokenArrayEnd); } if (token.type_ == tokenArrayEnd) break; @@ -1768,7 +1802,8 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) { bool isNegative = *current == '-'; if (isNegative) ++current; - // TODO: Help the compiler do the div and mod at compile time or get rid of them. + // TODO: Help the compiler do the div and mod at compile time or get rid of + // them. Value::LargestUInt maxIntegerValue = isNegative ? Value::LargestUInt(-Value::minLargestInt) : Value::maxLargestUInt; @@ -1913,9 +1948,9 @@ bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) { } bool OurReader::decodeUnicodeCodePoint(Token& token, - Location& current, - Location end, - unsigned int& unicode) { + Location& current, + Location end, + unsigned int& unicode) { if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) return false; @@ -1924,8 +1959,7 @@ bool OurReader::decodeUnicodeCodePoint(Token& token, if (end - current < 6) return addError( "additional six characters expected to parse unicode surrogate pair.", - token, - current); + token, current); unsigned int surrogatePair; if (*(current++) == '\\' && *(current++) == 'u') { if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { @@ -1935,20 +1969,18 @@ bool OurReader::decodeUnicodeCodePoint(Token& token, } else return addError("expecting another \\u token to begin the second half of " "a unicode surrogate pair", - token, - current); + token, current); } return true; } bool OurReader::decodeUnicodeEscapeSequence(Token& token, - Location& current, - Location end, - unsigned int& ret_unicode) { + Location& current, + Location end, + unsigned int& ret_unicode) { if (end - current < 4) return addError( - "Bad unicode escape sequence in string: four digits expected.", - token, + "Bad unicode escape sequence in string: four digits expected.", token, current); int unicode = 0; for (int index = 0; index < 4; ++index) { @@ -1963,15 +1995,15 @@ bool OurReader::decodeUnicodeEscapeSequence(Token& token, else return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", - token, - current); + token, current); } ret_unicode = static_cast<unsigned int>(unicode); return true; } -bool -OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) { +bool OurReader::addError(const JSONCPP_STRING& message, + Token& token, + Location extra) { ErrorInfo info; info.token_ = token; info.message_ = message; @@ -1994,8 +2026,8 @@ bool OurReader::recoverFromError(TokenType skipUntilToken) { } bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message, - Token& token, - TokenType skipUntilToken) { + Token& token, + TokenType skipUntilToken) { addError(message, token); return recoverFromError(skipUntilToken); } @@ -2009,8 +2041,8 @@ OurReader::Char OurReader::getNextChar() { } void OurReader::getLocationLineAndColumn(Location location, - int& line, - int& column) const { + int& line, + int& column) const { Location current = begin_; Location lastLineStart = current; line = 0; @@ -2042,8 +2074,7 @@ JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const { JSONCPP_STRING OurReader::getFormattedErrorMessages() const { JSONCPP_STRING formattedMessage; for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { + itError != errors_.end(); ++itError) { const ErrorInfo& error = *itError; formattedMessage += "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; @@ -2058,8 +2089,7 @@ JSONCPP_STRING OurReader::getFormattedErrorMessages() const { std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const { std::vector<OurReader::StructuredError> allErrors; for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { + itError != errors_.end(); ++itError) { const ErrorInfo& error = *itError; OurReader::StructuredError structured; structured.offset_start = error.token_.start_ - begin_; @@ -2072,8 +2102,7 @@ std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const { bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) { ptrdiff_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length) + if (value.getOffsetStart() > length || value.getOffsetLimit() > length) return false; Token token; token.type_ = tokenError; @@ -2087,11 +2116,12 @@ bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) { return true; } -bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) { +bool OurReader::pushError(const Value& value, + const JSONCPP_STRING& message, + const Value& extra) { ptrdiff_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length - || extra.getOffsetLimit() > length) + if (value.getOffsetStart() > length || value.getOffsetLimit() > length || + extra.getOffsetLimit() > length) return false; Token token; token.type_ = tokenError; @@ -2105,24 +2135,19 @@ bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, con return true; } -bool OurReader::good() const { - return !errors_.size(); -} - +bool OurReader::good() const { return !errors_.size(); } class OurCharReader : public CharReader { bool const collectComments_; OurReader reader_; + public: - OurCharReader( - bool collectComments, - OurFeatures const& features) - : collectComments_(collectComments) - , reader_(features) - {} - bool parse( - char const* beginDoc, char const* endDoc, - Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE { + OurCharReader(bool collectComments, OurFeatures const& features) + : collectComments_(collectComments), reader_(features) {} + bool parse(char const* beginDoc, + char const* endDoc, + Value* root, + JSONCPP_STRING* errs) JSONCPP_OVERRIDE { bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); if (errs) { *errs = reader_.getFormattedErrorMessages(); @@ -2131,19 +2156,15 @@ public: } }; -CharReaderBuilder::CharReaderBuilder() -{ - setDefaults(&settings_); -} -CharReaderBuilder::~CharReaderBuilder() -{} -CharReader* CharReaderBuilder::newCharReader() const -{ +CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); } +CharReaderBuilder::~CharReaderBuilder() {} +CharReader* CharReaderBuilder::newCharReader() const { bool collectComments = settings_["collectComments"].asBool(); OurFeatures features = OurFeatures::all(); features.allowComments_ = settings_["allowComments"].asBool(); features.strictRoot_ = settings_["strictRoot"].asBool(); - features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool(); + features.allowDroppedNullPlaceholders_ = + settings_["allowDroppedNullPlaceholders"].asBool(); features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); features.stackLimit_ = settings_["stackLimit"].asInt(); @@ -2152,8 +2173,7 @@ CharReader* CharReaderBuilder::newCharReader() const features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); return new OurCharReader(collectComments, features); } -static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys) -{ +static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys) { valid_keys->clear(); valid_keys->insert("collectComments"); valid_keys->insert("allowComments"); @@ -2166,10 +2186,10 @@ static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys) valid_keys->insert("rejectDupKeys"); valid_keys->insert("allowSpecialFloats"); } -bool CharReaderBuilder::validate(Json::Value* invalid) const -{ +bool CharReaderBuilder::validate(Json::Value* invalid) const { Json::Value my_invalid; - if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL + if (!invalid) + invalid = &my_invalid; // so we do not need to test for NULL Json::Value& inv = *invalid; std::set<JSONCPP_STRING> valid_keys; getValidReaderKeys(&valid_keys); @@ -2183,14 +2203,12 @@ bool CharReaderBuilder::validate(Json::Value* invalid) const } return 0u == inv.size(); } -Value& CharReaderBuilder::operator[](JSONCPP_STRING key) -{ +Value& CharReaderBuilder::operator[](JSONCPP_STRING key) { return settings_[key]; } // static -void CharReaderBuilder::strictMode(Json::Value* settings) -{ -//! [CharReaderBuilderStrictMode] +void CharReaderBuilder::strictMode(Json::Value* settings) { + //! [CharReaderBuilderStrictMode] (*settings)["allowComments"] = false; (*settings)["strictRoot"] = true; (*settings)["allowDroppedNullPlaceholders"] = false; @@ -2200,12 +2218,11 @@ void CharReaderBuilder::strictMode(Json::Value* settings) (*settings)["failIfExtra"] = true; (*settings)["rejectDupKeys"] = true; (*settings)["allowSpecialFloats"] = false; -//! [CharReaderBuilderStrictMode] + //! [CharReaderBuilderStrictMode] } // static -void CharReaderBuilder::setDefaults(Json::Value* settings) -{ -//! [CharReaderBuilderDefaults] +void CharReaderBuilder::setDefaults(Json::Value* settings) { + //! [CharReaderBuilderDefaults] (*settings)["collectComments"] = true; (*settings)["allowComments"] = true; (*settings)["strictRoot"] = false; @@ -2216,16 +2233,16 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) (*settings)["failIfExtra"] = false; (*settings)["rejectDupKeys"] = false; (*settings)["allowSpecialFloats"] = false; -//! [CharReaderBuilderDefaults] + //! [CharReaderBuilderDefaults] } ////////////////////////////////// // global functions -bool parseFromStream( - CharReader::Factory const& fact, JSONCPP_ISTREAM& sin, - Value* root, JSONCPP_STRING* errs) -{ +bool parseFromStream(CharReader::Factory const& fact, + JSONCPP_ISTREAM& sin, + Value* root, + JSONCPP_STRING* errs) { JSONCPP_OSTRINGSTREAM ssin; ssin << sin.rdbuf(); JSONCPP_STRING doc = ssin.str(); @@ -2241,10 +2258,6 @@ JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) { JSONCPP_STRING errs; bool ok = parseFromStream(b, sin, &root, &errs); if (!ok) { - fprintf(stderr, - "Error from reader: %s", - errs.c_str()); - throwRuntimeError(errs); } return sin; @@ -2265,7 +2278,7 @@ JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) { // Beginning of content of file: src/lib_json/json_valueiterator.inl // ////////////////////////////////////////////////////////////////////// -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -2446,7 +2459,7 @@ ValueIterator& ValueIterator::operator=(const SelfType& other) { // Beginning of content of file: src/lib_json/json_value.cpp // ////////////////////////////////////////////////////////////////////// -// Copyright 2011 Baptiste Lepilleur +// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -2456,16 +2469,21 @@ ValueIterator& ValueIterator::operator=(const SelfType& other) { #include <json/value.h> #include <json/writer.h> #endif // if !defined(JSON_IS_AMALGAMATION) +#include <cassert> +#include <cstring> #include <math.h> #include <sstream> #include <utility> -#include <cstring> -#include <cassert> #ifdef JSON_USE_CPPTL #include <cpptl/conststring.h> #endif -#include <cstddef> // size_t #include <algorithm> // min() +#include <cstddef> // size_t + +// Disable warning C4702 : unreachable code +#if defined(_MSC_VER) && _MSC_VER >= 1800 // VC++ 12.0 and above +#pragma warning(disable : 4702) +#endif #define JSON_ASSERT_UNREACHABLE assert(false) @@ -2479,20 +2497,19 @@ namespace Json { #else #define ALIGNAS(byte_alignment) #endif -//static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; -//const unsigned char& kNullRef = kNull[0]; -//const Value& Value::null = reinterpret_cast<const Value&>(kNullRef); -//const Value& Value::nullRef = null; +// static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; +// const unsigned char& kNullRef = kNull[0]; +// const Value& Value::null = reinterpret_cast<const Value&>(kNullRef); +// const Value& Value::nullRef = null; // static -Value const& Value::nullSingleton() -{ - static Value const nullStatic; - return nullStatic; +Value const& Value::nullSingleton() { + static Value const nullStatic; + return nullStatic; } -// for backwards compatibility, we'll leave these global references around, but DO NOT -// use them in JSONCPP library code any more! +// for backwards compatibility, we'll leave these global references around, but +// DO NOT use them in JSONCPP library code any more! Value const& Value::null = Value::nullSingleton(); Value const& Value::nullRef = Value::nullSingleton(); @@ -2512,17 +2529,20 @@ const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); const LargestUInt Value::maxLargestUInt = LargestUInt(-1); +const UInt Value::defaultRealPrecision = 17; + #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) template <typename T, typename U> static inline bool InRange(double d, T min, U max) { // The casts can lose precision, but we are looking only for // an approximate range. Might fail on edge cases though. ~cdunn - //return d >= static_cast<double>(min) && d <= static_cast<double>(max); + // return d >= static_cast<double>(min) && d <= static_cast<double>(max); return d >= min && d <= max; } #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) static inline double integerToDouble(Json::UInt64 value) { - return static_cast<double>(Int64(value / 2)) * 2.0 + static_cast<double>(Int64(value & 1)); + return static_cast<double>(Int64(value / 2)) * 2.0 + + static_cast<double>(Int64(value & 1)); } template <typename T> static inline double integerToDouble(T value) { @@ -2542,9 +2562,7 @@ static inline bool InRange(double d, T min, U max) { * computed using strlen(value). * @return Pointer on the duplicate instance of string. */ -static inline char* duplicateStringValue(const char* value, - size_t length) -{ +static inline char* duplicateStringValue(const char* value, size_t length) { // Avoid an integer overflow in the call to malloc below by limiting length // to a sane value. if (length >= static_cast<size_t>(Value::maxInt)) @@ -2552,9 +2570,8 @@ static inline char* duplicateStringValue(const char* value, char* newString = static_cast<char*>(malloc(length + 1)); if (newString == NULL) { - throwRuntimeError( - "in Json::Value::duplicateStringValue(): " - "Failed to allocate string value buffer"); + throwRuntimeError("in Json::Value::duplicateStringValue(): " + "Failed to allocate string value buffer"); } memcpy(newString, value, length); newString[length] = 0; @@ -2563,31 +2580,30 @@ static inline char* duplicateStringValue(const char* value, /* Record the length as a prefix. */ -static inline char* duplicateAndPrefixStringValue( - const char* value, - unsigned int length) -{ +static inline char* duplicateAndPrefixStringValue(const char* value, + unsigned int length) { // Avoid an integer overflow in the call to malloc below by limiting length // to a sane value. - JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) - sizeof(unsigned) - 1U, + JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) - + sizeof(unsigned) - 1U, "in Json::Value::duplicateAndPrefixStringValue(): " "length too big for prefixing"); unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U; char* newString = static_cast<char*>(malloc(actualLength)); if (newString == 0) { - throwRuntimeError( - "in Json::Value::duplicateAndPrefixStringValue(): " - "Failed to allocate string value buffer"); + throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): " + "Failed to allocate string value buffer"); } *reinterpret_cast<unsigned*>(newString) = length; memcpy(newString + sizeof(unsigned), value, length); - newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later + newString[actualLength - 1U] = + 0; // to avoid buffer over-run accidents by users later return newString; } -inline static void decodePrefixedString( - bool isPrefixed, char const* prefixed, - unsigned* length, char const** value) -{ +inline static void decodePrefixedString(bool isPrefixed, + char const* prefixed, + unsigned* length, + char const** value) { if (!isPrefixed) { *length = static_cast<unsigned>(strlen(prefixed)); *value = prefixed; @@ -2596,7 +2612,8 @@ inline static void decodePrefixedString( *value = prefixed + sizeof(unsigned); } } -/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue(). +/** Free the string duplicated by + * duplicateStringValue()/duplicateAndPrefixStringValue(). */ #if JSONCPP_USING_SECURE_MEMORY static inline void releasePrefixedStringValue(char* value) { @@ -2609,17 +2626,13 @@ static inline void releasePrefixedStringValue(char* value) { } static inline void releaseStringValue(char* value, unsigned length) { // length==0 => we allocated the strings memory - size_t size = (length==0) ? strlen(value) : length; + size_t size = (length == 0) ? strlen(value) : length; memset(value, 0, size); free(value); } -#else // !JSONCPP_USING_SECURE_MEMORY -static inline void releasePrefixedStringValue(char* value) { - free(value); -} -static inline void releaseStringValue(char* value, unsigned) { - free(value); -} +#else // !JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { free(value); } +static inline void releaseStringValue(char* value, unsigned) { free(value); } #endif // JSONCPP_USING_SECURE_MEMORY } // namespace Json @@ -2638,27 +2651,15 @@ static inline void releaseStringValue(char* value, unsigned) { namespace Json { -Exception::Exception(JSONCPP_STRING const& msg) - : msg_(msg) -{} -Exception::~Exception() JSONCPP_NOEXCEPT -{} -char const* Exception::what() const JSONCPP_NOEXCEPT -{ - return msg_.c_str(); -} -RuntimeError::RuntimeError(JSONCPP_STRING const& msg) - : Exception(msg) -{} -LogicError::LogicError(JSONCPP_STRING const& msg) - : Exception(msg) -{} -JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) -{ +Exception::Exception(JSONCPP_STRING const& msg) : msg_(msg) {} +Exception::~Exception() JSONCPP_NOEXCEPT {} +char const* Exception::what() const JSONCPP_NOEXCEPT { return msg_.c_str(); } +RuntimeError::RuntimeError(JSONCPP_STRING const& msg) : Exception(msg) {} +LogicError::LogicError(JSONCPP_STRING const& msg) : Exception(msg) {} +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) { throw RuntimeError(msg); } -JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) -{ +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) { throw LogicError(msg); } @@ -2670,8 +2671,7 @@ JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// -Value::CommentInfo::CommentInfo() : comment_(0) -{} +Value::CommentInfo::CommentInfo() : comment_(0) {} Value::CommentInfo::~CommentInfo() { if (comment_) @@ -2704,7 +2704,9 @@ void Value::CommentInfo::setComment(const char* text, size_t len) { Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {} -Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate) +Value::CZString::CZString(char const* str, + unsigned ulength, + DuplicationPolicy allocate) : cstr_(str) { // allocate != duplicate storage_.policy_ = allocate & 0x3; @@ -2713,25 +2715,34 @@ Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy a Value::CZString::CZString(const CZString& other) { cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != 0 - ? duplicateStringValue(other.cstr_, other.storage_.length_) - : other.cstr_); - storage_.policy_ = static_cast<unsigned>(other.cstr_ - ? (static_cast<DuplicationPolicy>(other.storage_.policy_) == noDuplication - ? noDuplication : duplicate) - : static_cast<DuplicationPolicy>(other.storage_.policy_)) & 3U; + ? duplicateStringValue(other.cstr_, other.storage_.length_) + : other.cstr_); + storage_.policy_ = + static_cast<unsigned>( + other.cstr_ + ? (static_cast<DuplicationPolicy>(other.storage_.policy_) == + noDuplication + ? noDuplication + : duplicate) + : static_cast<DuplicationPolicy>(other.storage_.policy_)) & + 3U; storage_.length_ = other.storage_.length_; } #if JSON_HAS_RVALUE_REFERENCES Value::CZString::CZString(CZString&& other) - : cstr_(other.cstr_), index_(other.index_) { + : cstr_(other.cstr_), index_(other.index_) { other.cstr_ = nullptr; } #endif Value::CZString::~CZString() { if (cstr_ && storage_.policy_ == duplicate) { - releaseStringValue(const_cast<char*>(cstr_), storage_.length_ + 1u); //+1 for null terminating character for sake of completeness but not actually necessary + releaseStringValue(const_cast<char*>(cstr_), + storage_.length_ + 1u); // +1 for null terminating + // character for sake of + // completeness but not actually + // necessary } } @@ -2740,32 +2751,47 @@ void Value::CZString::swap(CZString& other) { std::swap(index_, other.index_); } -Value::CZString& Value::CZString::operator=(CZString other) { - swap(other); +Value::CZString& Value::CZString::operator=(const CZString& other) { + cstr_ = other.cstr_; + index_ = other.index_; + return *this; +} + +#if JSON_HAS_RVALUE_REFERENCES +Value::CZString& Value::CZString::operator=(CZString&& other) { + cstr_ = other.cstr_; + index_ = other.index_; + other.cstr_ = nullptr; return *this; } +#endif bool Value::CZString::operator<(const CZString& other) const { - if (!cstr_) return index_ < other.index_; - //return strcmp(cstr_, other.cstr_) < 0; + if (!cstr_) + return index_ < other.index_; + // return strcmp(cstr_, other.cstr_) < 0; // Assume both are strings. unsigned this_len = this->storage_.length_; unsigned other_len = other.storage_.length_; unsigned min_len = std::min<unsigned>(this_len, other_len); JSON_ASSERT(this->cstr_ && other.cstr_); int comp = memcmp(this->cstr_, other.cstr_, min_len); - if (comp < 0) return true; - if (comp > 0) return false; + if (comp < 0) + return true; + if (comp > 0) + return false; return (this_len < other_len); } bool Value::CZString::operator==(const CZString& other) const { - if (!cstr_) return index_ == other.index_; - //return strcmp(cstr_, other.cstr_) == 0; + if (!cstr_) + return index_ == other.index_; + // return strcmp(cstr_, other.cstr_) == 0; // Assume both are strings. unsigned this_len = this->storage_.length_; unsigned other_len = other.storage_.length_; - if (this_len != other_len) return false; + if (this_len != other_len) + return false; JSON_ASSERT(this->cstr_ && other.cstr_); int comp = memcmp(this->cstr_, other.cstr_, this_len); return comp == 0; @@ -2773,10 +2799,12 @@ bool Value::CZString::operator==(const CZString& other) const { ArrayIndex Value::CZString::index() const { return index_; } -//const char* Value::CZString::c_str() const { return cstr_; } +// const char* Value::CZString::c_str() const { return cstr_; } const char* Value::CZString::data() const { return cstr_; } unsigned Value::CZString::length() const { return storage_.length_; } -bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; } +bool Value::CZString::isStaticString() const { + return storage_.policy_ == noDuplication; +} // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// @@ -2846,20 +2874,21 @@ Value::Value(double value) { Value::Value(const char* value) { initBasic(stringValue, true); - JSON_ASSERT_MESSAGE(value != NULL, "Null Value Passed to Value Constructor"); - value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value))); + JSON_ASSERT_MESSAGE(value != NULL, "Null Value Passed to Value Constructor"); + value_.string_ = duplicateAndPrefixStringValue( + value, static_cast<unsigned>(strlen(value))); } Value::Value(const char* beginValue, const char* endValue) { initBasic(stringValue, true); - value_.string_ = - duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue)); + value_.string_ = duplicateAndPrefixStringValue( + beginValue, static_cast<unsigned>(endValue - beginValue)); } Value::Value(const JSONCPP_STRING& value) { initBasic(stringValue, true); - value_.string_ = - duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length())); + value_.string_ = duplicateAndPrefixStringValue( + value.data(), static_cast<unsigned>(value.length())); } Value::Value(const StaticString& value) { @@ -2870,7 +2899,8 @@ Value::Value(const StaticString& value) { #ifdef JSON_USE_CPPTL Value::Value(const CppTL::ConstString& value) { initBasic(stringValue, true); - value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length())); + value_.string_ = duplicateAndPrefixStringValue( + value, static_cast<unsigned>(value.length())); } #endif @@ -2879,48 +2909,9 @@ Value::Value(bool value) { value_.bool_ = value; } -Value::Value(Value const& other) - : type_(other.type_), allocated_(false) - , - comments_(0), start_(other.start_), limit_(other.limit_) -{ - switch (type_) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - value_ = other.value_; - break; - case stringValue: - if (other.value_.string_ && other.allocated_) { - unsigned len; - char const* str; - decodePrefixedString(other.allocated_, other.value_.string_, - &len, &str); - value_.string_ = duplicateAndPrefixStringValue(str, len); - allocated_ = true; - } else { - value_.string_ = other.value_.string_; - allocated_ = false; - } - break; - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues(*other.value_.map_); - break; - default: - JSON_ASSERT_UNREACHABLE; - } - if (other.comments_) { - comments_ = new CommentInfo[numberOfCommentPlacement]; - for (int comment = 0; comment < numberOfCommentPlacement; ++comment) { - const CommentInfo& otherComment = other.comments_[comment]; - if (otherComment.comment_) - comments_[comment].setComment( - otherComment.comment_, strlen(otherComment.comment_)); - } - } +Value::Value(const Value& other) { + dupPayload(other); + dupMeta(other); } #if JSON_HAS_RVALUE_REFERENCES @@ -2932,24 +2923,7 @@ Value::Value(Value&& other) { #endif Value::~Value() { - switch (type_) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - break; - case stringValue: - if (allocated_) - releasePrefixedStringValue(value_.string_); - break; - case arrayValue: - case objectValue: - delete value_.map_; - break; - default: - JSON_ASSERT_UNREACHABLE; - } + releasePayload(); delete[] comments_; @@ -2971,6 +2945,11 @@ void Value::swapPayload(Value& other) { other.allocated_ = temp2 & 0x1; } +void Value::copyPayload(const Value& other) { + releasePayload(); + dupPayload(other); +} + void Value::swap(Value& other) { swapPayload(other); std::swap(comments_, other.comments_); @@ -2978,6 +2957,12 @@ void Value::swap(Value& other) { std::swap(limit_, other.limit_); } +void Value::copy(const Value& other) { + copyPayload(other); + delete[] comments_; + dupMeta(other); +} + ValueType Value::type() const { return type_; } int Value::compare(const Value& other) const { @@ -3003,23 +2988,28 @@ bool Value::operator<(const Value& other) const { return value_.real_ < other.value_.real_; case booleanValue: return value_.bool_ < other.value_.bool_; - case stringValue: - { + case stringValue: { if ((value_.string_ == 0) || (other.value_.string_ == 0)) { - if (other.value_.string_) return true; - else return false; + if (other.value_.string_) + return true; + else + return false; } unsigned this_len; unsigned other_len; char const* this_str; char const* other_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, + &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, + &other_str); unsigned min_len = std::min<unsigned>(this_len, other_len); JSON_ASSERT(this_str && other_str); int comp = memcmp(this_str, other_str, min_len); - if (comp < 0) return true; - if (comp > 0) return false; + if (comp < 0) + return true; + if (comp > 0) + return false; return (this_len < other_len); } case arrayValue: @@ -3060,8 +3050,7 @@ bool Value::operator==(const Value& other) const { return value_.real_ == other.value_.real_; case booleanValue: return value_.bool_ == other.value_.bool_; - case stringValue: - { + case stringValue: { if ((value_.string_ == 0) || (other.value_.string_ == 0)) { return (value_.string_ == other.value_.string_); } @@ -3069,9 +3058,12 @@ bool Value::operator==(const Value& other) const { unsigned other_len; char const* this_str; char const* other_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); - if (this_len != other_len) return false; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, + &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, + &other_str); + if (this_len != other_len) + return false; JSON_ASSERT(this_str && other_str); int comp = memcmp(this_str, other_str, this_len); return comp == 0; @@ -3091,28 +3083,34 @@ bool Value::operator!=(const Value& other) const { return !(*this == other); } const char* Value::asCString() const { JSON_ASSERT_MESSAGE(type_ == stringValue, "in Json::Value::asCString(): requires stringValue"); - if (value_.string_ == 0) return 0; + if (value_.string_ == 0) + return 0; unsigned this_len; char const* this_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, + &this_str); return this_str; } #if JSONCPP_USING_SECURE_MEMORY unsigned Value::getCStringLength() const { JSON_ASSERT_MESSAGE(type_ == stringValue, - "in Json::Value::asCString(): requires stringValue"); - if (value_.string_ == 0) return 0; + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) + return 0; unsigned this_len; char const* this_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, + &this_str); return this_len; } #endif bool Value::getString(char const** str, char const** cend) const { - if (type_ != stringValue) return false; - if (value_.string_ == 0) return false; + if (type_ != stringValue) + return false; + if (value_.string_ == 0) + return false; unsigned length; decodePrefixedString(this->allocated_, this->value_.string_, &length, str); *cend = *str + length; @@ -3123,12 +3121,13 @@ JSONCPP_STRING Value::asString() const { switch (type_) { case nullValue: return ""; - case stringValue: - { - if (value_.string_ == 0) return ""; + case stringValue: { + if (value_.string_ == 0) + return ""; unsigned this_len; char const* this_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, + &this_str); return JSONCPP_STRING(this_str, this_len); } case booleanValue: @@ -3148,8 +3147,7 @@ JSONCPP_STRING Value::asString() const { CppTL::ConstString Value::asConstString() const { unsigned len; char const* str; - decodePrefixedString(allocated_, value_.string_, - &len, &str); + decodePrefixedString(allocated_, value_.string_, &len, &str); return CppTL::ConstString(str, len); } #endif @@ -3328,7 +3326,7 @@ bool Value::isConvertibleTo(ValueType other) const { case nullValue: return (isNumeric() && asDouble() == 0.0) || (type_ == booleanValue && value_.bool_ == false) || - (type_ == stringValue && asString() == "") || + (type_ == stringValue && asString().empty()) || (type_ == arrayValue && value_.map_->size() == 0) || (type_ == objectValue && value_.map_->size() == 0) || type_ == nullValue; @@ -3387,7 +3385,7 @@ bool Value::empty() const { return false; } -bool Value::operator!() const { return isNull(); } +Value::operator bool() const { return !isNull(); } void Value::clear() { JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || @@ -3414,7 +3412,7 @@ void Value::resize(ArrayIndex newSize) { if (newSize == 0) clear(); else if (newSize > oldSize) - (*this)[newSize - 1]; + this->operator[](newSize - 1); else { for (ArrayIndex index = newSize; index < oldSize; ++index) { value_.map_->erase(index); @@ -3474,6 +3472,74 @@ void Value::initBasic(ValueType vtype, bool allocated) { limit_ = 0; } +void Value::dupPayload(const Value& other) { + type_ = other.type_; + allocated_ = false; + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if (other.value_.string_ && other.allocated_) { + unsigned len; + char const* str; + decodePrefixedString(other.allocated_, other.value_.string_, &len, &str); + value_.string_ = duplicateAndPrefixStringValue(str, len); + allocated_ = true; + } else { + value_.string_ = other.value_.string_; + } + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(*other.value_.map_); + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +void Value::releasePayload() { + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if (allocated_) + releasePrefixedStringValue(value_.string_); + break; + case arrayValue: + case objectValue: + delete value_.map_; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +void Value::dupMeta(const Value& other) { + if (other.comments_) { + comments_ = new CommentInfo[numberOfCommentPlacement]; + for (int comment = 0; comment < numberOfCommentPlacement; ++comment) { + const CommentInfo& otherComment = other.comments_[comment]; + if (otherComment.comment_) + comments_[comment].setComment(otherComment.comment_, + strlen(otherComment.comment_)); + } + } else { + comments_ = 0; + } + start_ = other.start_; + limit_ = other.limit_; +} + // Access an object value by name, create a null member if it does not exist. // @pre Type of '*this' is object or null. // @param key is null-terminated. @@ -3483,8 +3549,8 @@ Value& Value::resolveReference(const char* key) { "in Json::Value::resolveReference(): requires objectValue"); if (type_ == nullValue) *this = Value(objectValue); - CZString actualKey( - key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE! + CZString actualKey(key, static_cast<unsigned>(strlen(key)), + CZString::noDuplication); // NOTE! ObjectValues::iterator it = value_.map_->lower_bound(actualKey); if (it != value_.map_->end() && (*it).first == actualKey) return (*it).second; @@ -3496,15 +3562,14 @@ Value& Value::resolveReference(const char* key) { } // @param key is not null-terminated. -Value& Value::resolveReference(char const* key, char const* cend) -{ +Value& Value::resolveReference(char const* key, char const* cend) { JSON_ASSERT_MESSAGE( type_ == nullValue || type_ == objectValue, "in Json::Value::resolveReference(key, end): requires objectValue"); if (type_ == nullValue) *this = Value(objectValue); - CZString actualKey( - key, static_cast<unsigned>(cend-key), CZString::duplicateOnCopy); + CZString actualKey(key, static_cast<unsigned>(cend - key), + CZString::duplicateOnCopy); ObjectValues::iterator it = value_.map_->lower_bound(actualKey); if (it != value_.map_->end() && (*it).first == actualKey) return (*it).second; @@ -3522,27 +3587,29 @@ Value Value::get(ArrayIndex index, const Value& defaultValue) const { bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } -Value const* Value::find(char const* key, char const* cend) const -{ - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == objectValue, - "in Json::Value::find(key, end, found): requires objectValue or nullValue"); - if (type_ == nullValue) return NULL; - CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication); +Value const* Value::find(char const* key, char const* cend) const { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, + "in Json::Value::find(key, end, found): requires " + "objectValue or nullValue"); + if (type_ == nullValue) + return NULL; + CZString actualKey(key, static_cast<unsigned>(cend - key), + CZString::noDuplication); ObjectValues::const_iterator it = value_.map_->find(actualKey); - if (it == value_.map_->end()) return NULL; + if (it == value_.map_->end()) + return NULL; return &(*it).second; } -const Value& Value::operator[](const char* key) const -{ +const Value& Value::operator[](const char* key) const { Value const* found = find(key, key + strlen(key)); - if (!found) return nullSingleton(); + if (!found) + return nullSingleton(); return *found; } -Value const& Value::operator[](JSONCPP_STRING const& key) const -{ +Value const& Value::operator[](JSONCPP_STRING const& key) const { Value const* found = find(key.data(), key.data() + key.length()); - if (!found) return nullSingleton(); + if (!found) + return nullSingleton(); return *found; } @@ -3562,66 +3629,70 @@ Value& Value::operator[](const StaticString& key) { Value& Value::operator[](const CppTL::ConstString& key) { return resolveReference(key.c_str(), key.end_c_str()); } -Value const& Value::operator[](CppTL::ConstString const& key) const -{ +Value const& Value::operator[](CppTL::ConstString const& key) const { Value const* found = find(key.c_str(), key.end_c_str()); - if (!found) return nullSingleton(); + if (!found) + return nullSingleton(); return *found; } #endif Value& Value::append(const Value& value) { return (*this)[size()] = value; } -Value Value::get(char const* key, char const* cend, Value const& defaultValue) const -{ +#if JSON_HAS_RVALUE_REFERENCES +Value& Value::append(Value&& value) { + return (*this)[size()] = std::move(value); +} +#endif + +Value Value::get(char const* key, + char const* cend, + Value const& defaultValue) const { Value const* found = find(key, cend); return !found ? defaultValue : *found; } -Value Value::get(char const* key, Value const& defaultValue) const -{ +Value Value::get(char const* key, Value const& defaultValue) const { return get(key, key + strlen(key), defaultValue); } -Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue) const -{ +Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue) const { return get(key.data(), key.data() + key.length(), defaultValue); } - -bool Value::removeMember(const char* key, const char* cend, Value* removed) -{ +bool Value::removeMember(const char* key, const char* cend, Value* removed) { if (type_ != objectValue) { return false; } - CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication); + CZString actualKey(key, static_cast<unsigned>(cend - key), + CZString::noDuplication); ObjectValues::iterator it = value_.map_->find(actualKey); if (it == value_.map_->end()) return false; - *removed = it->second; + if (removed) +#if JSON_HAS_RVALUE_REFERENCES + *removed = std::move(it->second); +#else + *removed = it->second; +#endif value_.map_->erase(it); return true; } -bool Value::removeMember(const char* key, Value* removed) -{ +bool Value::removeMember(const char* key, Value* removed) { return removeMember(key, key + strlen(key), removed); } -bool Value::removeMember(JSONCPP_STRING const& key, Value* removed) -{ +bool Value::removeMember(JSONCPP_STRING const& key, Value* removed) { return removeMember(key.data(), key.data() + key.length(), removed); } -Value Value::removeMember(const char* key) -{ +void Value::removeMember(const char* key) { JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, "in Json::Value::removeMember(): requires objectValue"); if (type_ == nullValue) - return nullSingleton(); + return; - Value removed; // null - removeMember(key, key + strlen(key), &removed); - return removed; // still null if removeMember() did nothing + CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication); + value_.map_->erase(actualKey); } -Value Value::removeMember(const JSONCPP_STRING& key) -{ - return removeMember(key.c_str()); +void Value::removeMember(const JSONCPP_STRING& key) { + removeMember(key.c_str()); } bool Value::removeIndex(ArrayIndex index, Value* removed) { @@ -3636,7 +3707,7 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) { *removed = it->second; ArrayIndex oldSize = size(); // shift left all items left, into the place of the "removed" - for (ArrayIndex i = index; i < (oldSize - 1); ++i){ + for (ArrayIndex i = index; i < (oldSize - 1); ++i) { CZString keey(i); (*value_.map_)[keey] = (*this)[i + 1]; } @@ -3654,17 +3725,14 @@ Value Value::get(const CppTL::ConstString& key, } #endif -bool Value::isMember(char const* key, char const* cend) const -{ +bool Value::isMember(char const* key, char const* cend) const { Value const* value = find(key, cend); return NULL != value; } -bool Value::isMember(char const* key) const -{ +bool Value::isMember(char const* key) const { return isMember(key, key + strlen(key)); } -bool Value::isMember(JSONCPP_STRING const& key) const -{ +bool Value::isMember(JSONCPP_STRING const& key) const { return isMember(key.data(), key.data() + key.length()); } @@ -3685,8 +3753,7 @@ Value::Members Value::getMemberNames() const { ObjectValues::const_iterator it = value_.map_->begin(); ObjectValues::const_iterator itEnd = value_.map_->end(); for (; it != itEnd; ++it) { - members.push_back(JSONCPP_STRING((*it).first.data(), - (*it).first.length())); + members.push_back(JSONCPP_STRING((*it).first.data(), (*it).first.length())); } return members; } @@ -3808,14 +3875,30 @@ bool Value::isUInt64() const { } bool Value::isIntegral() const { + switch (type_) { + case intValue: + case uintValue: + return true; + case realValue: #if defined(JSON_HAS_INT64) - return isInt64() || isUInt64(); + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_); #else - return isInt() || isUInt(); -#endif + return value_.real_ >= minInt && value_.real_ <= maxUInt && + IsIntegral(value_.real_); +#endif // JSON_HAS_INT64 + default: + break; + } + return false; } -bool Value::isDouble() const { return type_ == intValue || type_ == uintValue || type_ == realValue; } +bool Value::isDouble() const { + return type_ == intValue || type_ == uintValue || type_ == realValue; +} bool Value::isNumeric() const { return isDouble(); } @@ -3825,10 +3908,12 @@ bool Value::isArray() const { return type_ == arrayValue; } bool Value::isObject() const { return type_ == objectValue; } -void Value::setComment(const char* comment, size_t len, CommentPlacement placement) { +void Value::setComment(const char* comment, + size_t len, + CommentPlacement placement) { if (!comments_) comments_ = new CommentInfo[numberOfCommentPlacement]; - if ((len > 0) && (comment[len-1] == '\n')) { + if ((len > 0) && (comment[len - 1] == '\n')) { // Always discard trailing newline, to aid indentation. len -= 1; } @@ -3839,7 +3924,8 @@ void Value::setComment(const char* comment, CommentPlacement placement) { setComment(comment, strlen(comment), placement); } -void Value::setComment(const JSONCPP_STRING& comment, CommentPlacement placement) { +void Value::setComment(const JSONCPP_STRING& comment, + CommentPlacement placement) { setComment(comment.c_str(), comment.length(), placement); } @@ -3862,8 +3948,13 @@ ptrdiff_t Value::getOffsetStart() const { return start_; } ptrdiff_t Value::getOffsetLimit() const { return limit_; } JSONCPP_STRING Value::toStyledString() const { - StyledWriter writer; - return writer.write(*this); + StreamWriterBuilder builder; + + JSONCPP_STRING out = this->hasComment(commentBefore) ? "\n" : ""; + out += Json::writeString(builder, *this); + out += "\n"; + + return out; } Value::const_iterator Value::begin() const { @@ -3942,6 +4033,7 @@ Path::Path(const JSONCPP_STRING& path, const PathArgument& a4, const PathArgument& a5) { InArgs in; + in.reserve(5); in.push_back(&a1); in.push_back(&a2); in.push_back(&a3); @@ -4077,74 +4169,83 @@ Value& Path::make(Value& root) const { // Beginning of content of file: src/lib_json/json_writer.cpp // ////////////////////////////////////////////////////////////////////// -// Copyright 2011 Baptiste Lepilleur +// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #if !defined(JSON_IS_AMALGAMATION) -#include <json/writer.h> #include "json_tool.h" +#include <json/writer.h> #endif // if !defined(JSON_IS_AMALGAMATION) +#include <cassert> +#include <cstring> #include <iomanip> #include <memory> +#include <set> #include <sstream> #include <utility> -#include <set> -#include <cassert> -#include <cstring> + +#if __cplusplus >= 201103L +#include <cmath> #include <cstdio> -#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0 +#if !defined(isnan) +#define isnan std::isnan +#endif + +#if !defined(isfinite) +#define isfinite std::isfinite +#endif + +#if !defined(snprintf) +#define snprintf std::snprintf +#endif +#else +#include <math.h> +#include <stdio.h> + +#if defined(_MSC_VER) +#if !defined(isnan) +#include <float.h> +#define isnan _isnan +#endif + +#if !defined(isfinite) #include <float.h> #define isfinite _finite -#elif defined(__sun) && defined(__SVR4) //Solaris +#endif + +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 +#if !defined(snprintf) +#define snprintf _snprintf +#endif +#endif + +#if defined(__sun) && defined(__SVR4) // Solaris #if !defined(isfinite) #include <ieeefp.h> #define isfinite finite #endif -#elif defined(_AIX) -#if !defined(isfinite) -#include <math.h> -#define isfinite finite #endif -#elif defined(__hpux) + +#if defined(__hpux) #if !defined(isfinite) #if defined(__ia64) && !defined(finite) -#define isfinite(x) ((sizeof(x) == sizeof(float) ? \ - _Isfinitef(x) : _IsFinite(x))) -#else -#include <math.h> -#define isfinite finite +#define isfinite(x) \ + ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x))) #endif #endif -#else -#include <cmath> -#if !(defined(__QNXNTO__)) // QNX already defines isfinite -#define isfinite std::isfinite -#endif #endif -#if defined(_MSC_VER) -#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above -#define snprintf sprintf_s -#elif _MSC_VER >= 1900 // VC++ 14.0 and above -#define snprintf std::snprintf -#else -#define snprintf _snprintf -#endif -#elif defined(__ANDROID__) || defined(__QNXNTO__) -#define snprintf snprintf -#elif __cplusplus >= 201103L -#if !defined(__MINGW32__) && !defined(__CYGWIN__) -#define snprintf std::snprintf -#endif +#if !defined(isnan) +// IEEE standard states that NaN values will not compare to themselves +#define isnan(x) (x != x) #endif -#if defined(__BORLANDC__) -#include <float.h> -#define isfinite _finite -#define snprintf _snprintf +#if !defined(isfinite) +#define isfinite finite +#endif #endif #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 @@ -4157,27 +4258,9 @@ namespace Json { #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) typedef std::unique_ptr<StreamWriter> StreamWriterPtr; #else -typedef std::auto_ptr<StreamWriter> StreamWriterPtr; +typedef std::auto_ptr<StreamWriter> StreamWriterPtr; #endif -static bool containsControlCharacter(const char* str) { - while (*str) { - if (isControlCharacter(*(str++))) - return true; - } - return false; -} - -static bool containsControlCharacter0(const char* str, unsigned len) { - char const* end = str + len; - while (end != str) { - if (isControlCharacter(*str) || 0==*str) - return true; - ++str; - } - return false; -} - JSONCPP_STRING valueToString(LargestInt value) { UIntToStringBuffer buffer; char* current = buffer + sizeof(buffer); @@ -4215,136 +4298,161 @@ JSONCPP_STRING valueToString(UInt value) { #endif // # if defined(JSON_HAS_INT64) namespace { -JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) { - // Allocate a buffer that is more than large enough to store the 16 digits of - // precision requested below. - char buffer[36]; - int len = -1; - - char formatString[6]; - sprintf(formatString, "%%.%dg", precision); - +JSONCPP_STRING valueToString(double value, + bool useSpecialFloats, + unsigned int precision, + PrecisionType precisionType) { // Print into the buffer. We need not request the alternative representation - // that always has a decimal point because JSON doesn't distingish the + // that always has a decimal point because JSON doesn't distinguish the // concepts of reals and integers. - if (isfinite(value)) { - len = snprintf(buffer, sizeof(buffer), formatString, value); - - // try to ensure we preserve the fact that this was given to us as a double on input - if (!strstr(buffer, ".") && !strstr(buffer, "e")) { - strcat(buffer, ".0"); - } + if (!isfinite(value)) { + static const char* const reps[2][3] = { { "NaN", "-Infinity", "Infinity" }, + { "null", "-1e+9999", "1e+9999" } }; + return reps[useSpecialFloats ? 0 : 1] + [isnan(value) ? 0 : (value < 0) ? 1 : 2]; + } - } else { - // IEEE standard states that NaN values will not compare to themselves - if (value != value) { - len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null"); - } else if (value < 0) { - len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999"); - } else { - len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999"); + JSONCPP_STRING buffer(size_t(36), '\0'); + while (true) { + int len = snprintf( + &*buffer.begin(), buffer.size(), + (precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f", + precision, value); + assert(len >= 0); + size_t wouldPrint = static_cast<size_t>(len); + if (wouldPrint >= buffer.size()) { + buffer.resize(wouldPrint + 1); + continue; } - // For those, we do not need to call fixNumLoc, but it is fast. + buffer.resize(wouldPrint); + break; + } + + buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end()); + + // strip the zero padding from the right + if (precisionType == PrecisionType::decimalPlaces) { + buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end()); + } + + // try to ensure we preserve the fact that this was given to us as a double on + // input + if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) { + buffer += ".0"; } - assert(len >= 0); - fixNumericLocale(buffer, buffer + len); return buffer; } -} +} // namespace -JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); } +JSONCPP_STRING valueToString(double value, + unsigned int precision, + PrecisionType precisionType) { + return valueToString(value, false, precision, precisionType); +} JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; } -JSONCPP_STRING valueToQuotedString(const char* value) { - if (value == NULL) - return ""; - // Not sure how to handle unicode... - if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && - !containsControlCharacter(value)) - return JSONCPP_STRING("\"") + value + "\""; - // We have to walk value and escape any special characters. - // Appending to JSONCPP_STRING is not efficient, but this should be rare. - // (Note: forward slashes are *not* rare, but I am not escaping them.) - JSONCPP_STRING::size_type maxsize = - strlen(value) * 2 + 3; // allescaped+quotes+NULL - JSONCPP_STRING result; - result.reserve(maxsize); // to avoid lots of mallocs - result += "\""; - for (const char* c = value; *c != 0; ++c) { - switch (*c) { - case '\"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - case '\b': - result += "\\b"; - break; - case '\f': - result += "\\f"; - break; - case '\n': - result += "\\n"; - break; - case '\r': - result += "\\r"; - break; - case '\t': - result += "\\t"; - break; - // case '/': - // Even though \/ is considered a legal escape in JSON, a bare - // slash is also legal, so I see no reason to escape it. - // (I hope I am not misunderstanding something. - // blep notes: actually escaping \/ may be useful in javascript to avoid </ - // sequence. - // Should add a flag to allow this compatibility mode and prevent this - // sequence from occurring. - default: - if (isControlCharacter(*c)) { - JSONCPP_OSTRINGSTREAM oss; - oss << "\\u" << std::hex << std::uppercase << std::setfill('0') - << std::setw(4) << static_cast<int>(*c); - result += oss.str(); - } else { - result += *c; - } - break; - } +static bool isAnyCharRequiredQuoting(char const* s, size_t n) { + assert(s || !n); + + char const* const end = s + n; + for (char const* cur = s; cur < end; ++cur) { + if (*cur == '\\' || *cur == '\"' || *cur < ' ' || + static_cast<unsigned char>(*cur) < 0x80) + return true; } - result += "\""; - return result; + return false; } -// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp -static char const* strnpbrk(char const* s, char const* accept, size_t n) { - assert((s || !n) && accept); +static unsigned int utf8ToCodepoint(const char*& s, const char* e) { + const unsigned int REPLACEMENT_CHARACTER = 0xFFFD; - char const* const end = s + n; - for (char const* cur = s; cur < end; ++cur) { - int const c = *cur; - for (char const* a = accept; *a; ++a) { - if (*a == c) { - return cur; - } - } + unsigned int firstByte = static_cast<unsigned char>(*s); + + if (firstByte < 0x80) + return firstByte; + + if (firstByte < 0xE0) { + if (e - s < 2) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = + ((firstByte & 0x1F) << 6) | (static_cast<unsigned int>(s[1]) & 0x3F); + s += 1; + // oversized encoded characters are invalid + return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated; + } + + if (firstByte < 0xF0) { + if (e - s < 3) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = ((firstByte & 0x0F) << 12) | + ((static_cast<unsigned int>(s[1]) & 0x3F) << 6) | + (static_cast<unsigned int>(s[2]) & 0x3F); + s += 2; + // surrogates aren't valid codepoints itself + // shouldn't be UTF-8 encoded + if (calculated >= 0xD800 && calculated <= 0xDFFF) + return REPLACEMENT_CHARACTER; + // oversized encoded characters are invalid + return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated; } - return NULL; + + if (firstByte < 0xF8) { + if (e - s < 4) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = ((firstByte & 0x07) << 18) | + ((static_cast<unsigned int>(s[1]) & 0x3F) << 12) | + ((static_cast<unsigned int>(s[2]) & 0x3F) << 6) | + (static_cast<unsigned int>(s[3]) & 0x3F); + s += 3; + // oversized encoded characters are invalid + return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated; + } + + return REPLACEMENT_CHARACTER; } + +static const char hex2[] = "000102030405060708090a0b0c0d0e0f" + "101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f" + "303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f" + "505152535455565758595a5b5c5d5e5f" + "606162636465666768696a6b6c6d6e6f" + "707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; + +static JSONCPP_STRING toHex16Bit(unsigned int x) { + const unsigned int hi = (x >> 8) & 0xff; + const unsigned int lo = x & 0xff; + JSONCPP_STRING result(4, ' '); + result[0] = hex2[2 * hi]; + result[1] = hex2[2 * hi + 1]; + result[2] = hex2[2 * lo]; + result[3] = hex2[2 * lo + 1]; + return result; +} + static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { if (value == NULL) return ""; - // Not sure how to handle unicode... - if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL && - !containsControlCharacter0(value, length)) + + if (!isAnyCharRequiredQuoting(value, length)) return JSONCPP_STRING("\"") + value + "\""; // We have to walk value and escape any special characters. // Appending to JSONCPP_STRING is not efficient, but this should be rare. // (Note: forward slashes are *not* rare, but I am not escaping them.) - JSONCPP_STRING::size_type maxsize = - length * 2 + 3; // allescaped+quotes+NULL + JSONCPP_STRING::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL JSONCPP_STRING result; result.reserve(maxsize); // to avoid lots of mallocs result += "\""; @@ -4380,22 +4488,34 @@ static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { // sequence. // Should add a flag to allow this compatibility mode and prevent this // sequence from occurring. - default: - if ((isControlCharacter(*c)) || (*c == 0)) { - JSONCPP_OSTRINGSTREAM oss; - oss << "\\u" << std::hex << std::uppercase << std::setfill('0') - << std::setw(4) << static_cast<int>(*c); - result += oss.str(); - } else { - result += *c; + default: { + unsigned int cp = utf8ToCodepoint(c, end); + // don't escape non-control characters + // (short escape sequence are applied above) + if (cp < 0x80 && cp >= 0x20) + result += static_cast<char>(cp); + else if (cp < 0x10000) { // codepoint is in Basic Multilingual Plane + result += "\\u"; + result += toHex16Bit(cp); + } else { // codepoint is not in Basic Multilingual Plane + // convert to surrogate pair first + cp -= 0x10000; + result += "\\u"; + result += toHex16Bit((cp >> 10) + 0xD800); + result += "\\u"; + result += toHex16Bit((cp & 0x3FF) + 0xDC00); } - break; + } break; } } result += "\""; return result; } +JSONCPP_STRING valueToQuotedString(const char* value) { + return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value))); +} + // Class Writer // ////////////////////////////////////////////////////////////////// Writer::~Writer() {} @@ -4404,17 +4524,17 @@ Writer::~Writer() {} // ////////////////////////////////////////////////////////////////// FastWriter::FastWriter() - : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), + : yamlCompatibilityEnabled_(false), dropNullPlaceholders_(false), omitEndingLineFeed_(false) {} -void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } +void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; } void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } JSONCPP_STRING FastWriter::write(const Value& root) { - document_ = ""; + document_.clear(); writeValue(root); if (!omitEndingLineFeed_) document_ += "\n"; @@ -4436,13 +4556,13 @@ void FastWriter::writeValue(const Value& value) { case realValue: document_ += valueToString(value.asDouble()); break; - case stringValue: - { + case stringValue: { // Is NULL possible for value.string_? No. char const* str; char const* end; bool ok = value.getString(&str, &end); - if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str)); + if (ok) + document_ += valueToQuotedStringN(str, static_cast<unsigned>(end - str)); break; } case booleanValue: @@ -4466,8 +4586,9 @@ void FastWriter::writeValue(const Value& value) { const JSONCPP_STRING& name = *it; if (it != members.begin()) document_ += ','; - document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())); - document_ += yamlCompatiblityEnabled_ ? ": " : ":"; + document_ += valueToQuotedStringN(name.data(), + static_cast<unsigned>(name.length())); + document_ += yamlCompatibilityEnabled_ ? ": " : ":"; writeValue(value[name]); } document_ += '}'; @@ -4482,9 +4603,9 @@ StyledWriter::StyledWriter() : rightMargin_(74), indentSize_(3), addChildValues_() {} JSONCPP_STRING StyledWriter::write(const Value& root) { - document_ = ""; + document_.clear(); addChildValues_ = false; - indentString_ = ""; + indentString_.clear(); writeCommentBeforeValue(root); writeValue(root); writeCommentAfterValueOnSameLine(root); @@ -4506,14 +4627,15 @@ void StyledWriter::writeValue(const Value& value) { case realValue: pushValue(valueToString(value.asDouble())); break; - case stringValue: - { + case stringValue: { // Is NULL possible for value.string_? No. char const* str; char const* end; bool ok = value.getString(&str, &end); - if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); - else pushValue(""); + if (ok) + pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str))); + else + pushValue(""); break; } case booleanValue: @@ -4556,7 +4678,7 @@ void StyledWriter::writeArrayValue(const Value& value) { if (size == 0) pushValue("[]"); else { - bool isArrayMultiLine = isMultineArray(value); + bool isArrayMultiLine = isMultilineArray(value); if (isArrayMultiLine) { writeWithIndent("["); indent(); @@ -4594,14 +4716,14 @@ void StyledWriter::writeArrayValue(const Value& value) { } } -bool StyledWriter::isMultineArray(const Value& value) { +bool StyledWriter::isMultilineArray(const Value& value) { ArrayIndex const size = value.size(); bool isMultiLine = size * 3 >= rightMargin_; childValues_.clear(); for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { const Value& childValue = value[index]; isMultiLine = ((childValue.isArray() || childValue.isObject()) && - childValue.size() > 0); + childValue.size() > 0); } if (!isMultiLine) // check if line length > max line length { @@ -4644,7 +4766,9 @@ void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) { document_ += value; } -void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); } +void StyledWriter::indent() { + indentString_ += JSONCPP_STRING(indentSize_, ' '); +} void StyledWriter::unindent() { assert(indentString_.size() >= indentSize_); @@ -4661,8 +4785,7 @@ void StyledWriter::writeCommentBeforeValue(const Value& root) { JSONCPP_STRING::const_iterator iter = comment.begin(); while (iter != comment.end()) { document_ += *iter; - if (*iter == '\n' && - (iter != comment.end() && *(iter + 1) == '/')) + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) writeIndent(); ++iter; } @@ -4691,17 +4814,18 @@ bool StyledWriter::hasCommentForValue(const Value& value) { // Class StyledStreamWriter // ////////////////////////////////////////////////////////////////// -StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation) +StyledStreamWriter::StyledStreamWriter(const JSONCPP_STRING& indentation) : document_(NULL), rightMargin_(74), indentation_(indentation), - addChildValues_() {} + addChildValues_(), indented_(false) {} void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) { document_ = &out; addChildValues_ = false; - indentString_ = ""; + indentString_.clear(); indented_ = true; writeCommentBeforeValue(root); - if (!indented_) writeIndent(); + if (!indented_) + writeIndent(); indented_ = true; writeValue(root); writeCommentAfterValueOnSameLine(root); @@ -4723,14 +4847,15 @@ void StyledStreamWriter::writeValue(const Value& value) { case realValue: pushValue(valueToString(value.asDouble())); break; - case stringValue: - { + case stringValue: { // Is NULL possible for value.string_? No. char const* str; char const* end; bool ok = value.getString(&str, &end); - if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); - else pushValue(""); + if (ok) + pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str))); + else + pushValue(""); break; } case booleanValue: @@ -4773,7 +4898,7 @@ void StyledStreamWriter::writeArrayValue(const Value& value) { if (size == 0) pushValue("[]"); else { - bool isArrayMultiLine = isMultineArray(value); + bool isArrayMultiLine = isMultilineArray(value); if (isArrayMultiLine) { writeWithIndent("["); indent(); @@ -4785,7 +4910,8 @@ void StyledStreamWriter::writeArrayValue(const Value& value) { if (hasChildValue) writeWithIndent(childValues_[index]); else { - if (!indented_) writeIndent(); + if (!indented_) + writeIndent(); indented_ = true; writeValue(childValue); indented_ = false; @@ -4813,14 +4939,14 @@ void StyledStreamWriter::writeArrayValue(const Value& value) { } } -bool StyledStreamWriter::isMultineArray(const Value& value) { +bool StyledStreamWriter::isMultilineArray(const Value& value) { ArrayIndex const size = value.size(); bool isMultiLine = size * 3 >= rightMargin_; childValues_.clear(); for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { const Value& childValue = value[index]; isMultiLine = ((childValue.isArray() || childValue.isObject()) && - childValue.size() > 0); + childValue.size() > 0); } if (!isMultiLine) // check if line length > max line length { @@ -4856,7 +4982,8 @@ void StyledStreamWriter::writeIndent() { } void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) { - if (!indented_) writeIndent(); + if (!indented_) + writeIndent(); *document_ << value; indented_ = false; } @@ -4872,13 +4999,13 @@ void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { if (!root.hasComment(commentBefore)) return; - if (!indented_) writeIndent(); + if (!indented_) + writeIndent(); const JSONCPP_STRING& comment = root.getComment(commentBefore); JSONCPP_STRING::const_iterator iter = comment.begin(); while (iter != comment.end()) { *document_ << *iter; - if (*iter == '\n' && - (iter != comment.end() && *(iter + 1) == '/')) + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) // writeIndent(); // would include newline *document_ << indentString_; ++iter; @@ -4910,27 +5037,27 @@ bool StyledStreamWriter::hasCommentForValue(const Value& value) { struct CommentStyle { /// Decide whether to write comments. enum Enum { - None, ///< Drop all comments. - Most, ///< Recover odd behavior of previous versions (not implemented yet). - All ///< Keep all comments. + None, ///< Drop all comments. + Most, ///< Recover odd behavior of previous versions (not implemented yet). + All ///< Keep all comments. }; }; -struct BuiltStyledStreamWriter : public StreamWriter -{ - BuiltStyledStreamWriter( - JSONCPP_STRING const& indentation, - CommentStyle::Enum cs, - JSONCPP_STRING const& colonSymbol, - JSONCPP_STRING const& nullSymbol, - JSONCPP_STRING const& endingLineFeedSymbol, - bool useSpecialFloats, - unsigned int precision); +struct BuiltStyledStreamWriter : public StreamWriter { + BuiltStyledStreamWriter(JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision, + PrecisionType precisionType); int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE; + private: void writeValue(Value const& value); void writeArrayValue(Value const& value); - bool isMultineArray(Value const& value); + bool isMultilineArray(Value const& value); void pushValue(JSONCPP_STRING const& value); void writeIndent(); void writeWithIndent(JSONCPP_STRING const& value); @@ -4954,35 +5081,30 @@ private: bool indented_ : 1; bool useSpecialFloats_ : 1; unsigned int precision_; + PrecisionType precisionType_; }; BuiltStyledStreamWriter::BuiltStyledStreamWriter( - JSONCPP_STRING const& indentation, - CommentStyle::Enum cs, - JSONCPP_STRING const& colonSymbol, - JSONCPP_STRING const& nullSymbol, - JSONCPP_STRING const& endingLineFeedSymbol, - bool useSpecialFloats, - unsigned int precision) - : rightMargin_(74) - , indentation_(indentation) - , cs_(cs) - , colonSymbol_(colonSymbol) - , nullSymbol_(nullSymbol) - , endingLineFeedSymbol_(endingLineFeedSymbol) - , addChildValues_(false) - , indented_(false) - , useSpecialFloats_(useSpecialFloats) - , precision_(precision) -{ -} -int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout) -{ + JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision, + PrecisionType precisionType) + : rightMargin_(74), indentation_(indentation), cs_(cs), + colonSymbol_(colonSymbol), nullSymbol_(nullSymbol), + endingLineFeedSymbol_(endingLineFeedSymbol), addChildValues_(false), + indented_(false), useSpecialFloats_(useSpecialFloats), + precision_(precision), precisionType_(precisionType) {} +int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout) { sout_ = sout; addChildValues_ = false; indented_ = true; - indentString_ = ""; + indentString_.clear(); writeCommentBeforeValue(root); - if (!indented_) writeIndent(); + if (!indented_) + writeIndent(); indented_ = true; writeValue(root); writeCommentAfterValueOnSameLine(root); @@ -5002,16 +5124,18 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) { pushValue(valueToString(value.asLargestUInt())); break; case realValue: - pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_)); + pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_, + precisionType_)); break; - case stringValue: - { + case stringValue: { // Is NULL is possible for value.string_? No. char const* str; char const* end; bool ok = value.getString(&str, &end); - if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); - else pushValue(""); + if (ok) + pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str))); + else + pushValue(""); break; } case booleanValue: @@ -5032,7 +5156,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) { JSONCPP_STRING const& name = *it; Value const& childValue = value[name]; writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()))); + writeWithIndent(valueToQuotedStringN( + name.data(), static_cast<unsigned>(name.length()))); *sout_ << colonSymbol_; writeValue(childValue); if (++it == members.end()) { @@ -5054,7 +5179,7 @@ void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { if (size == 0) pushValue("[]"); else { - bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value); + bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value); if (isMultiLine) { writeWithIndent("["); indent(); @@ -5066,7 +5191,8 @@ void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { if (hasChildValue) writeWithIndent(childValues_[index]); else { - if (!indented_) writeIndent(); + if (!indented_) + writeIndent(); indented_ = true; writeValue(childValue); indented_ = false; @@ -5084,26 +5210,28 @@ void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { { assert(childValues_.size() == size); *sout_ << "["; - if (!indentation_.empty()) *sout_ << " "; + if (!indentation_.empty()) + *sout_ << " "; for (unsigned index = 0; index < size; ++index) { if (index > 0) *sout_ << ((!indentation_.empty()) ? ", " : ","); *sout_ << childValues_[index]; } - if (!indentation_.empty()) *sout_ << " "; + if (!indentation_.empty()) + *sout_ << " "; *sout_ << "]"; } } } -bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { +bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) { ArrayIndex const size = value.size(); bool isMultiLine = size * 3 >= rightMargin_; childValues_.clear(); for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { Value const& childValue = value[index]; isMultiLine = ((childValue.isArray() || childValue.isObject()) && - childValue.size() > 0); + childValue.size() > 0); } if (!isMultiLine) // check if line length > max line length { @@ -5143,7 +5271,8 @@ void BuiltStyledStreamWriter::writeIndent() { } void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) { - if (!indented_) writeIndent(); + if (!indented_) + writeIndent(); *sout_ << value; indented_ = false; } @@ -5156,17 +5285,18 @@ void BuiltStyledStreamWriter::unindent() { } void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { - if (cs_ == CommentStyle::None) return; + if (cs_ == CommentStyle::None) + return; if (!root.hasComment(commentBefore)) return; - if (!indented_) writeIndent(); + if (!indented_) + writeIndent(); const JSONCPP_STRING& comment = root.getComment(commentBefore); JSONCPP_STRING::const_iterator iter = comment.begin(); while (iter != comment.end()) { *sout_ << *iter; - if (*iter == '\n' && - (iter != comment.end() && *(iter + 1) == '/')) + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) // writeIndent(); // would write extra newline *sout_ << indentString_; ++iter; @@ -5174,8 +5304,10 @@ void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { indented_ = false; } -void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) { - if (cs_ == CommentStyle::None) return; +void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine( + Value const& root) { + if (cs_ == CommentStyle::None) + return; if (root.hasComment(commentAfterOnSameLine)) *sout_ << " " + root.getComment(commentAfterOnSameLine); @@ -5195,28 +5327,18 @@ bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { /////////////// // StreamWriter -StreamWriter::StreamWriter() - : sout_(NULL) -{ -} -StreamWriter::~StreamWriter() -{ -} -StreamWriter::Factory::~Factory() -{} -StreamWriterBuilder::StreamWriterBuilder() -{ - setDefaults(&settings_); -} -StreamWriterBuilder::~StreamWriterBuilder() -{} -StreamWriter* StreamWriterBuilder::newStreamWriter() const -{ +StreamWriter::StreamWriter() : sout_(NULL) {} +StreamWriter::~StreamWriter() {} +StreamWriter::Factory::~Factory() {} +StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); } +StreamWriterBuilder::~StreamWriterBuilder() {} +StreamWriter* StreamWriterBuilder::newStreamWriter() const { JSONCPP_STRING indentation = settings_["indentation"].asString(); JSONCPP_STRING cs_str = settings_["commentStyle"].asString(); + JSONCPP_STRING pt_str = settings_["precisionType"].asString(); bool eyc = settings_["enableYAMLCompatibility"].asBool(); bool dnp = settings_["dropNullPlaceholders"].asBool(); - bool usf = settings_["useSpecialFloats"].asBool(); + bool usf = settings_["useSpecialFloats"].asBool(); unsigned int pre = settings_["precision"].asUInt(); CommentStyle::Enum cs = CommentStyle::All; if (cs_str == "All") { @@ -5226,6 +5348,14 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const } else { throwRuntimeError("commentStyle must be 'All' or 'None'"); } + PrecisionType precisionType(significantDigits); + if (pt_str == "significant") { + precisionType = PrecisionType::significantDigits; + } else if (pt_str == "decimal") { + precisionType = PrecisionType::decimalPlaces; + } else { + throwRuntimeError("precisionType must be 'significant' or 'decimal'"); + } JSONCPP_STRING colonSymbol = " : "; if (eyc) { colonSymbol = ": "; @@ -5234,16 +5364,16 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const } JSONCPP_STRING nullSymbol = "null"; if (dnp) { - nullSymbol = ""; + nullSymbol.clear(); } - if (pre > 17) pre = 17; - JSONCPP_STRING endingLineFeedSymbol = ""; - return new BuiltStyledStreamWriter( - indentation, cs, - colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre); + if (pre > 17) + pre = 17; + JSONCPP_STRING endingLineFeedSymbol; + return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol, + endingLineFeedSymbol, usf, pre, + precisionType); } -static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys) -{ +static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys) { valid_keys->clear(); valid_keys->insert("indentation"); valid_keys->insert("commentStyle"); @@ -5251,11 +5381,12 @@ static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys) valid_keys->insert("dropNullPlaceholders"); valid_keys->insert("useSpecialFloats"); valid_keys->insert("precision"); + valid_keys->insert("precisionType"); } -bool StreamWriterBuilder::validate(Json::Value* invalid) const -{ +bool StreamWriterBuilder::validate(Json::Value* invalid) const { Json::Value my_invalid; - if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL + if (!invalid) + invalid = &my_invalid; // so we do not need to test for NULL Json::Value& inv = *invalid; std::set<JSONCPP_STRING> valid_keys; getValidWriterKeys(&valid_keys); @@ -5269,13 +5400,11 @@ bool StreamWriterBuilder::validate(Json::Value* invalid) const } return 0u == inv.size(); } -Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) -{ +Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) { return settings_[key]; } // static -void StreamWriterBuilder::setDefaults(Json::Value* settings) -{ +void StreamWriterBuilder::setDefaults(Json::Value* settings) { //! [StreamWriterBuilderDefaults] (*settings)["commentStyle"] = "All"; (*settings)["indentation"] = "\t"; @@ -5283,10 +5412,12 @@ void StreamWriterBuilder::setDefaults(Json::Value* settings) (*settings)["dropNullPlaceholders"] = false; (*settings)["useSpecialFloats"] = false; (*settings)["precision"] = 17; + (*settings)["precisionType"] = "significant"; //! [StreamWriterBuilderDefaults] } -JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) { +JSONCPP_STRING writeString(StreamWriter::Factory const& builder, + Value const& root) { JSONCPP_OSTRINGSTREAM sout; StreamWriterPtr const writer(builder.newStreamWriter()); writer->write(root, &sout); |
