diff options
Diffstat (limited to 'json/jsoncpp.cpp')
| -rw-r--r-- | json/jsoncpp.cpp | 1110 |
1 files changed, 662 insertions, 448 deletions
diff --git a/json/jsoncpp.cpp b/json/jsoncpp.cpp index 21b87cd5..7634ed4f 100644 --- a/json/jsoncpp.cpp +++ b/json/jsoncpp.cpp @@ -6,28 +6,28 @@ // ////////////////////////////////////////////////////////////////////// /* -The JsonCpp library's source code, including accompanying documentation, +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 -jurisdictions which recognize such a disclaimer. In such jurisdictions, +The author (Baptiste Lepilleur) explicitly disclaims 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). -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 -conditions of the MIT License (see below), or 3) under the terms of dual +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 +conditions of the MIT License (see below), or 3) under the terms of dual Public Domain/MIT License conditions described here, as they choose. The MIT License is about as close to Public Domain as a license can get, and is described in clear, concise terms at: http://en.wikipedia.org/wiki/MIT_License - + The full text of the MIT License follows: ======================================================================== @@ -73,7 +73,7 @@ license you like. -#include "json.h" +#include "json/json.h" #ifndef JSON_IS_AMALGAMATION #error "Compile with -I PATH_TO_JSON_DIRECTORY" @@ -92,6 +92,16 @@ license you like. #ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED #define LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +// Also support old flag NO_LOCALE_SUPPORT +#ifdef NO_LOCALE_SUPPORT +#define JSONCPP_NO_LOCALE_SUPPORT +#endif + +#ifndef JSONCPP_NO_LOCALE_SUPPORT +#include <clocale> +#endif + /* This header provides common string manipulation support, such as UTF-8, * portable conversion from/to string... * @@ -99,10 +109,18 @@ license you like. */ namespace Json { +static char getDecimalPoint() { +#ifdef JSONCPP_NO_LOCALE_SUPPORT + return '\0'; +#else + struct lconv* lc = localeconv(); + return lc ? *(lc->decimal_point) : '\0'; +#endif +} /// Converts a unicode code-point to UTF-8. -static inline std::string codePointToUTF8(unsigned int cp) { - std::string result; +static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) { + JSONCPP_STRING result; // based on description from http://en.wikipedia.org/wiki/UTF-8 @@ -116,8 +134,8 @@ static inline std::string codePointToUTF8(unsigned int cp) { } else if (cp <= 0xFFFF) { result.resize(3); result[2] = static_cast<char>(0x80 | (0x3f & cp)); - result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6))); - result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12))); + result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); + result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12))); } else if (cp <= 0x10FFFF) { result.resize(4); result[3] = static_cast<char>(0x80 | (0x3f & cp)); @@ -129,7 +147,7 @@ static inline std::string codePointToUTF8(unsigned int cp) { return result; } -/// Returns true if ch is a control character (in range [0,32[). +/// Returns true if ch is a control character (in range [1,31]). static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; } enum { @@ -149,7 +167,7 @@ typedef char UIntToStringBuffer[uintToStringBufferSize]; static inline void uintToString(LargestUInt value, char*& current) { *--current = 0; do { - *--current = char(value % 10) + '0'; + *--current = static_cast<char>(value % 10U + static_cast<unsigned>('0')); value /= 10; } while (value != 0); } @@ -168,6 +186,18 @@ static inline void fixNumericLocale(char* begin, char* end) { } } +static inline void fixNumericLocaleInput(char* begin, char* end) { + char decimalPoint = getDecimalPoint(); + if (decimalPoint != '\0' && decimalPoint != '.') { + while (begin < end) { + if (*begin == '.') { + *begin = decimalPoint; + } + ++begin; + } + } +} + } // namespace Json { #endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED @@ -186,6 +216,7 @@ static inline void fixNumericLocale(char* begin, char* end) { // ////////////////////////////////////////////////////////////////////// // Copyright 2007-2011 Baptiste Lepilleur +// 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 @@ -204,22 +235,43 @@ static inline void fixNumericLocale(char* begin, char* end) { #include <sstream> #include <memory> #include <set> +#include <limits> -#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below +#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 +#endif + +#if defined(__QNXNTO__) +#define sscanf std::sscanf +#endif #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 // Disable warning about strdup being deprecated. #pragma warning(disable : 4996) #endif -static int const stackLimit_g = 1000; -static int stackDepth_g = 0; // see readValue() +// 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() namespace Json { -#if __cplusplus >= 201103L +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) typedef std::unique_ptr<CharReader> CharReaderPtr; #else typedef std::auto_ptr<CharReader> CharReaderPtr; @@ -268,7 +320,8 @@ Reader::Reader(const Features& features) bool Reader::parse(const std::string& document, Value& root, bool collectComments) { - document_ = document; + JSONCPP_STRING documentCopy(document.data(), document.data() + document.capacity()); + std::swap(documentCopy, document_); const char* begin = document_.c_str(); const char* end = begin + document_.length(); return parse(begin, end, root, collectComments); @@ -280,11 +333,11 @@ bool Reader::parse(std::istream& sin, Value& root, bool collectComments) { // Those would allow streamed input from a file, if parse() were a // template function. - // Since std::string is reference-counted, this at least does not + // Since JSONCPP_STRING is reference-counted, this at least does not // create an extra copy. - std::string doc; + JSONCPP_STRING doc; std::getline(sin, doc, (char)EOF); - return parse(doc, root, collectComments); + return parse(doc.data(), doc.data() + doc.size(), root, collectComments); } bool Reader::parse(const char* beginDoc, @@ -307,7 +360,6 @@ bool Reader::parse(const char* beginDoc, nodes_.pop(); nodes_.push(&root); - stackDepth_g = 0; // Yes, this is bad coding, but options are limited. bool successful = readValue(); Token token; skipCommentTokens(token); @@ -330,12 +382,10 @@ bool Reader::parse(const char* beginDoc, } bool Reader::readValue() { - // This is a non-reentrant way to support a stackLimit. Terrible! - // But this deprecated class has a security problem: Bad input can - // cause a seg-fault. This seems like a fair, binary-compatible way - // to prevent the problem. - if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue()."); - ++stackDepth_g; + // 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()."); Token token; skipCommentTokens(token); @@ -409,7 +459,6 @@ bool Reader::readValue() { lastValue_ = ¤tValue(); } - --stackDepth_g; return successful; } @@ -538,9 +587,9 @@ bool Reader::readComment() { return true; } -static std::string normalizeEOL(Reader::Location begin, Reader::Location end) { - std::string normalized; - normalized.reserve(end - begin); +static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Location end) { + JSONCPP_STRING normalized; + normalized.reserve(static_cast<size_t>(end - begin)); Reader::Location current = begin; while (current != end) { char c = *current++; @@ -560,7 +609,7 @@ static std::string normalizeEOL(Reader::Location begin, Reader::Location end) { void Reader::addComment(Location begin, Location end, CommentPlacement placement) { assert(collectComments_); - const std::string& normalized = normalizeEOL(begin, end); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); if (placement == commentAfterOnSameLine) { assert(lastValue_ != 0); lastValue_->setComment(normalized, placement); @@ -570,7 +619,7 @@ Reader::addComment(Location begin, Location end, CommentPlacement placement) { } bool Reader::readCStyleComment() { - while (current_ != end_) { + while ((current_ + 1) < end_) { Char c = getNextChar(); if (c == '*' && *current_ == '/') break; @@ -599,25 +648,25 @@ void Reader::readNumber() { char c = '0'; // stopgap for already consumed character // integral part while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; // fractional part if (c == '.') { - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; } // exponential part if (c == 'e' || c == 'E') { - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; if (c == '+' || c == '-') - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; } } bool Reader::readString() { - Char c = 0; + Char c = '\0'; while (current_ != end_) { c = getNextChar(); if (c == '\\') @@ -630,7 +679,7 @@ bool Reader::readString() { bool Reader::readObject(Token& tokenStart) { Token tokenName; - std::string name; + JSONCPP_STRING name; Value init(objectValue); currentValue().swapPayload(init); currentValue().setOffsetStart(tokenStart.start_ - begin_); @@ -650,7 +699,7 @@ bool Reader::readObject(Token& tokenStart) { Value numberName; if (!decodeNumber(tokenName, numberName)) return recoverFromError(tokenObjectEnd); - name = numberName.asString(); + name = JSONCPP_STRING(numberName.asCString()); } else { break; } @@ -689,7 +738,7 @@ bool Reader::readArray(Token& tokenStart) { currentValue().swapPayload(init); currentValue().setOffsetStart(tokenStart.start_ - begin_); skipSpaces(); - if (*current_ == ']') // empty array + if (current_ != end_ && *current_ == ']') // empty array { Token endArray; readToken(endArray); @@ -742,7 +791,7 @@ bool Reader::decodeNumber(Token& token, Value& decoded) { ++current; // 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) + isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 : Value::maxLargestUInt; Value::LargestUInt threshold = maxIntegerValue / 10; Value::LargestUInt value = 0; @@ -750,7 +799,7 @@ bool Reader::decodeNumber(Token& token, Value& decoded) { Char c = *current++; if (c < '0' || c > '9') return decodeDouble(token, decoded); - Value::UInt digit(c - '0'); + Value::UInt digit(static_cast<Value::UInt>(c - '0')); if (value >= threshold) { // We've hit or exceeded the max value divided by 10 (rounded down). If // a) we've only just touched the limit, b) this is the last digit, and @@ -763,7 +812,9 @@ bool Reader::decodeNumber(Token& token, Value& decoded) { } value = value * 10 + digit; } - if (isNegative) + if (isNegative && value == maxIntegerValue) + decoded = Value::minLargestInt; + else if (isNegative) decoded = -Value::LargestInt(value); else if (value <= Value::LargestUInt(Value::maxInt)) decoded = Value::LargestInt(value); @@ -784,34 +835,10 @@ bool Reader::decodeDouble(Token& token) { bool Reader::decodeDouble(Token& token, Value& decoded) { double value = 0; - const int bufferSize = 32; - int count; - int length = int(token.end_ - token.start_); - - // Sanity check to avoid buffer overflow exploits. - if (length < 0) { - return addError("Unable to parse token length", token); - } - - // Avoid using a string constant for the format control string given to - // sscanf, as this can cause hard to debug crashes on OS X. See here for more - // info: - // - // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html - char format[] = "%lf"; - - if (length <= bufferSize) { - Char buffer[bufferSize + 1]; - memcpy(buffer, token.start_, length); - buffer[length] = 0; - count = sscanf(buffer, format, &value); - } else { - std::string buffer(token.start_, token.end_); - count = sscanf(buffer.c_str(), format, &value); - } - - if (count != 1) - return addError("'" + std::string(token.start_, token.end_) + + JSONCPP_STRING buffer(token.start_, token.end_); + JSONCPP_ISTRINGSTREAM is(buffer); + if (!(is >> value)) + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + "' is not a number.", token); decoded = value; @@ -819,7 +846,7 @@ bool Reader::decodeDouble(Token& token, Value& decoded) { } bool Reader::decodeString(Token& token) { - std::string decoded_string; + JSONCPP_STRING decoded_string; if (!decodeString(token, decoded_string)) return false; Value decoded(decoded_string); @@ -829,8 +856,8 @@ bool Reader::decodeString(Token& token) { return true; } -bool Reader::decodeString(Token& token, std::string& decoded) { - decoded.reserve(token.end_ - token.start_ - 2); +bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) { + decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2)); Location current = token.start_ + 1; // skip '"' Location end = token.end_ - 1; // do not include '"' while (current != end) { @@ -914,13 +941,13 @@ bool Reader::decodeUnicodeCodePoint(Token& token, bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current, Location end, - unsigned int& unicode) { + unsigned int& ret_unicode) { if (end - current < 4) return addError( "Bad unicode escape sequence in string: four digits expected.", token, current); - unicode = 0; + int unicode = 0; for (int index = 0; index < 4; ++index) { Char c = *current++; unicode *= 16; @@ -936,11 +963,12 @@ bool Reader::decodeUnicodeEscapeSequence(Token& token, token, current); } + ret_unicode = static_cast<unsigned int>(unicode); return true; } bool -Reader::addError(const std::string& message, Token& token, Location extra) { +Reader::addError(const JSONCPP_STRING& message, Token& token, Location extra) { ErrorInfo info; info.token_ = token; info.message_ = message; @@ -950,7 +978,7 @@ Reader::addError(const std::string& message, Token& token, Location extra) { } bool Reader::recoverFromError(TokenType skipUntilToken) { - int errorCount = int(errors_.size()); + size_t const errorCount = errors_.size(); Token skip; for (;;) { if (!readToken(skip)) @@ -962,7 +990,7 @@ bool Reader::recoverFromError(TokenType skipUntilToken) { return false; } -bool Reader::addErrorAndRecover(const std::string& message, +bool Reader::addErrorAndRecover(const JSONCPP_STRING& message, Token& token, TokenType skipUntilToken) { addError(message, token); @@ -1000,29 +1028,21 @@ void Reader::getLocationLineAndColumn(Location location, ++line; } -std::string Reader::getLocationLineAndColumn(Location location) const { +JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const { int line, column; getLocationLineAndColumn(location, line, column); char buffer[18 + 16 + 16 + 1]; -#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) -#if defined(WINCE) - _snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#else - sprintf_s(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#endif -#else snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#endif return buffer; } // Deprecated. Preserved for backward compatibility -std::string Reader::getFormatedErrorMessages() const { +JSONCPP_STRING Reader::getFormatedErrorMessages() const { return getFormattedErrorMessages(); } -std::string Reader::getFormattedErrorMessages() const { - std::string formattedMessage; +JSONCPP_STRING Reader::getFormattedErrorMessages() const { + JSONCPP_STRING formattedMessage; for (Errors::const_iterator itError = errors_.begin(); itError != errors_.end(); ++itError) { @@ -1052,8 +1072,8 @@ std::vector<Reader::StructuredError> Reader::getStructuredErrors() const { return allErrors; } -bool Reader::pushError(const Value& value, const std::string& message) { - size_t length = end_ - begin_; +bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) { + ptrdiff_t const length = end_ - begin_; if(value.getOffsetStart() > length || value.getOffsetLimit() > length) return false; @@ -1069,8 +1089,8 @@ bool Reader::pushError(const Value& value, const std::string& message) { return true; } -bool Reader::pushError(const Value& value, const std::string& message, const Value& extra) { - size_t length = end_ - begin_; +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) @@ -1095,7 +1115,6 @@ bool Reader::good() const { class OurFeatures { public: static OurFeatures all(); - OurFeatures(); bool allowComments_; bool strictRoot_; bool allowDroppedNullPlaceholders_; @@ -1103,20 +1122,13 @@ public: bool allowSingleQuotes_; bool failIfExtra_; bool rejectDupKeys_; + bool allowSpecialFloats_; int stackLimit_; }; // OurFeatures // exact copy of Implementation of class Features // //////////////////////////////// -OurFeatures::OurFeatures() - : allowComments_(true), strictRoot_(false) - , allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) - , allowSingleQuotes_(false) - , failIfExtra_(false) -{ -} - OurFeatures OurFeatures::all() { return OurFeatures(); } // Implementation of class Reader @@ -1128,9 +1140,9 @@ public: typedef char Char; typedef const Char* Location; struct StructuredError { - size_t offset_start; - size_t offset_limit; - std::string message; + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; }; OurReader(OurFeatures const& features); @@ -1138,10 +1150,10 @@ public: const char* endDoc, Value& root, bool collectComments = true); - std::string getFormattedErrorMessages() const; + JSONCPP_STRING getFormattedErrorMessages() const; std::vector<StructuredError> getStructuredErrors() const; - bool pushError(const Value& value, const std::string& message); - bool pushError(const Value& value, const std::string& message, const Value& extra); + bool pushError(const Value& value, const JSONCPP_STRING& message); + bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); bool good() const; private: @@ -1159,6 +1171,9 @@ private: tokenTrue, tokenFalse, tokenNull, + tokenNaN, + tokenPosInf, + tokenNegInf, tokenArraySeparator, tokenMemberSeparator, tokenComment, @@ -1175,7 +1190,7 @@ private: class ErrorInfo { public: Token token_; - std::string message_; + JSONCPP_STRING message_; Location extra_; }; @@ -1189,14 +1204,14 @@ private: bool readCppStyleComment(); bool readString(); bool readStringSingleQuote(); - void readNumber(); + bool readNumber(bool checkInf); bool readValue(); bool readObject(Token& token); bool readArray(Token& token); bool decodeNumber(Token& token); bool decodeNumber(Token& token, Value& decoded); bool decodeString(Token& token); - bool decodeString(Token& token, std::string& decoded); + bool decodeString(Token& token, JSONCPP_STRING& decoded); bool decodeDouble(Token& token); bool decodeDouble(Token& token, Value& decoded); bool decodeUnicodeCodePoint(Token& token, @@ -1207,9 +1222,9 @@ private: Location& current, Location end, unsigned int& unicode); - bool addError(const std::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 std::string& message, + bool addErrorAndRecover(const JSONCPP_STRING& message, Token& token, TokenType skipUntilToken); void skipUntilSpace(); @@ -1217,21 +1232,20 @@ private: Char getNextChar(); void getLocationLineAndColumn(Location location, int& line, int& column) const; - std::string getLocationLineAndColumn(Location location) const; + JSONCPP_STRING getLocationLineAndColumn(Location location) const; void addComment(Location begin, Location end, CommentPlacement placement); void skipCommentTokens(Token& token); typedef std::stack<Value*> Nodes; Nodes nodes_; Errors errors_; - std::string document_; + JSONCPP_STRING document_; Location begin_; Location end_; Location current_; Location lastValueEnd_; Value* lastValue_; - std::string commentsBefore_; - int stackDepth_; + JSONCPP_STRING commentsBefore_; OurFeatures const features_; bool collectComments_; @@ -1241,7 +1255,8 @@ private: 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, @@ -1264,12 +1279,11 @@ bool OurReader::parse(const char* beginDoc, nodes_.pop(); nodes_.push(&root); - stackDepth_ = 0; bool successful = readValue(); Token token; skipCommentTokens(token); if (features_.failIfExtra_) { - if (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; } @@ -1293,8 +1307,8 @@ bool OurReader::parse(const char* beginDoc, } bool OurReader::readValue() { - if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); - ++stackDepth_; + // To preserve the old behaviour we cast size_t to int. + if (static_cast<int>(nodes_.size()) > features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); Token token; skipCommentTokens(token); bool successful = true; @@ -1343,6 +1357,30 @@ bool OurReader::readValue() { currentValue().setOffsetLimit(token.end_ - begin_); } 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: + { + Value v(std::numeric_limits<double>::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNegInf: + { + Value v(-std::numeric_limits<double>::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; case tokenArraySeparator: case tokenObjectEnd: case tokenArrayEnd: @@ -1367,7 +1405,6 @@ bool OurReader::readValue() { lastValue_ = ¤tValue(); } - --stackDepth_; return successful; } @@ -1423,9 +1460,16 @@ bool OurReader::readToken(Token& token) { case '7': case '8': case '9': - case '-': token.type_ = tokenNumber; - readNumber(); + readNumber(false); + break; + case '-': + if (readNumber(true)) { + token.type_ = tokenNumber; + } else { + token.type_ = tokenNegInf; + ok = features_.allowSpecialFloats_ && match("nfinity", 7); + } break; case 't': token.type_ = tokenTrue; @@ -1439,6 +1483,22 @@ bool OurReader::readToken(Token& token) { token.type_ = tokenNull; ok = match("ull", 3); break; + case 'N': + if (features_.allowSpecialFloats_) { + token.type_ = tokenNaN; + ok = match("aN", 2); + } else { + ok = false; + } + break; + case 'I': + if (features_.allowSpecialFloats_) { + token.type_ = tokenPosInf; + ok = match("nfinity", 7); + } else { + ok = false; + } + break; case ',': token.type_ = tokenArraySeparator; break; @@ -1505,7 +1565,7 @@ bool OurReader::readComment() { void OurReader::addComment(Location begin, Location end, CommentPlacement placement) { assert(collectComments_); - const std::string& normalized = normalizeEOL(begin, end); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); if (placement == commentAfterOnSameLine) { assert(lastValue_ != 0); lastValue_->setComment(normalized, placement); @@ -1515,7 +1575,7 @@ OurReader::addComment(Location begin, Location end, CommentPlacement placement) } bool OurReader::readCStyleComment() { - while (current_ != end_) { + while ((current_ + 1) < end_) { Char c = getNextChar(); if (c == '*' && *current_ == '/') break; @@ -1539,26 +1599,31 @@ bool OurReader::readCppStyleComment() { return true; } -void OurReader::readNumber() { +bool OurReader::readNumber(bool checkInf) { const char *p = current_; + if (checkInf && p != end_ && *p == 'I') { + current_ = ++p; + return false; + } char c = '0'; // stopgap for already consumed character // integral part while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; // fractional part if (c == '.') { - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; } // exponential part if (c == 'e' || c == 'E') { - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; if (c == '+' || c == '-') - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; + c = (current_ = p) < end_ ? *p++ : '\0'; } + return true; } bool OurReader::readString() { Char c = 0; @@ -1587,7 +1652,7 @@ bool OurReader::readStringSingleQuote() { bool OurReader::readObject(Token& tokenStart) { Token tokenName; - std::string name; + JSONCPP_STRING name; Value init(objectValue); currentValue().swapPayload(init); currentValue().setOffsetStart(tokenStart.start_ - begin_); @@ -1619,7 +1684,7 @@ bool OurReader::readObject(Token& tokenStart) { } if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30"); if (features_.rejectDupKeys_ && currentValue().isMember(name)) { - std::string msg = "Duplicate key: '" + name + "'"; + JSONCPP_STRING msg = "Duplicate key: '" + name + "'"; return addErrorAndRecover( msg, tokenName, tokenObjectEnd); } @@ -1652,7 +1717,7 @@ bool OurReader::readArray(Token& tokenStart) { currentValue().swapPayload(init); currentValue().setOffsetStart(tokenStart.start_ - begin_); skipSpaces(); - if (*current_ == ']') // empty array + if (current_ != end_ && *current_ == ']') // empty array { Token endArray; readToken(endArray); @@ -1713,7 +1778,7 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) { Char c = *current++; if (c < '0' || c > '9') return decodeDouble(token, decoded); - Value::UInt digit(c - '0'); + Value::UInt digit(static_cast<Value::UInt>(c - '0')); if (value >= threshold) { // We've hit or exceeded the max value divided by 10 (rounded down). If // a) we've only just touched the limit, b) this is the last digit, and @@ -1749,12 +1814,13 @@ bool OurReader::decodeDouble(Token& token, Value& decoded) { double value = 0; const int bufferSize = 32; int count; - int length = int(token.end_ - token.start_); + ptrdiff_t const length = token.end_ - token.start_; // Sanity check to avoid buffer overflow exploits. if (length < 0) { return addError("Unable to parse token length", token); } + size_t const ulength = static_cast<size_t>(length); // Avoid using a string constant for the format control string given to // sscanf, as this can cause hard to debug crashes on OS X. See here for more @@ -1765,16 +1831,17 @@ bool OurReader::decodeDouble(Token& token, Value& decoded) { if (length <= bufferSize) { Char buffer[bufferSize + 1]; - memcpy(buffer, token.start_, length); + memcpy(buffer, token.start_, ulength); buffer[length] = 0; + fixNumericLocaleInput(buffer, buffer + length); count = sscanf(buffer, format, &value); } else { - std::string buffer(token.start_, token.end_); + JSONCPP_STRING buffer(token.start_, token.end_); count = sscanf(buffer.c_str(), format, &value); } if (count != 1) - return addError("'" + std::string(token.start_, token.end_) + + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + "' is not a number.", token); decoded = value; @@ -1782,7 +1849,7 @@ bool OurReader::decodeDouble(Token& token, Value& decoded) { } bool OurReader::decodeString(Token& token) { - std::string decoded_string; + JSONCPP_STRING decoded_string; if (!decodeString(token, decoded_string)) return false; Value decoded(decoded_string); @@ -1792,8 +1859,8 @@ bool OurReader::decodeString(Token& token) { return true; } -bool OurReader::decodeString(Token& token, std::string& decoded) { - decoded.reserve(token.end_ - token.start_ - 2); +bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) { + decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2)); Location current = token.start_ + 1; // skip '"' Location end = token.end_ - 1; // do not include '"' while (current != end) { @@ -1877,13 +1944,13 @@ bool OurReader::decodeUnicodeCodePoint(Token& token, bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current, Location end, - unsigned int& unicode) { + unsigned int& ret_unicode) { if (end - current < 4) return addError( "Bad unicode escape sequence in string: four digits expected.", token, current); - unicode = 0; + int unicode = 0; for (int index = 0; index < 4; ++index) { Char c = *current++; unicode *= 16; @@ -1899,11 +1966,12 @@ bool OurReader::decodeUnicodeEscapeSequence(Token& token, token, current); } + ret_unicode = static_cast<unsigned int>(unicode); return true; } bool -OurReader::addError(const std::string& message, Token& token, Location extra) { +OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) { ErrorInfo info; info.token_ = token; info.message_ = message; @@ -1913,7 +1981,7 @@ OurReader::addError(const std::string& message, Token& token, Location extra) { } bool OurReader::recoverFromError(TokenType skipUntilToken) { - int errorCount = int(errors_.size()); + size_t errorCount = errors_.size(); Token skip; for (;;) { if (!readToken(skip)) @@ -1925,7 +1993,7 @@ bool OurReader::recoverFromError(TokenType skipUntilToken) { return false; } -bool OurReader::addErrorAndRecover(const std::string& message, +bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message, Token& token, TokenType skipUntilToken) { addError(message, token); @@ -1963,24 +2031,16 @@ void OurReader::getLocationLineAndColumn(Location location, ++line; } -std::string OurReader::getLocationLineAndColumn(Location location) const { +JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const { int line, column; getLocationLineAndColumn(location, line, column); char buffer[18 + 16 + 16 + 1]; -#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) -#if defined(WINCE) - _snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#else - sprintf_s(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#endif -#else snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#endif return buffer; } -std::string OurReader::getFormattedErrorMessages() const { - std::string formattedMessage; +JSONCPP_STRING OurReader::getFormattedErrorMessages() const { + JSONCPP_STRING formattedMessage; for (Errors::const_iterator itError = errors_.begin(); itError != errors_.end(); ++itError) { @@ -2010,8 +2070,8 @@ std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const { return allErrors; } -bool OurReader::pushError(const Value& value, const std::string& message) { - size_t length = end_ - begin_; +bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) { + ptrdiff_t length = end_ - begin_; if(value.getOffsetStart() > length || value.getOffsetLimit() > length) return false; @@ -2027,8 +2087,8 @@ bool OurReader::pushError(const Value& value, const std::string& message) { return true; } -bool OurReader::pushError(const Value& value, const std::string& message, const Value& extra) { - size_t length = end_ - begin_; +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) @@ -2060,9 +2120,9 @@ public: : collectComments_(collectComments) , reader_(features) {} - virtual bool parse( + bool parse( char const* beginDoc, char const* endDoc, - Value* root, std::string* errs) { + Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE { bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); if (errs) { *errs = reader_.getFormattedErrorMessages(); @@ -2089,9 +2149,10 @@ CharReader* CharReaderBuilder::newCharReader() const features.stackLimit_ = settings_["stackLimit"].asInt(); features.failIfExtra_ = settings_["failIfExtra"].asBool(); features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); + features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); return new OurCharReader(collectComments, features); } -static void getValidReaderKeys(std::set<std::string>* valid_keys) +static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys) { valid_keys->clear(); valid_keys->insert("collectComments"); @@ -2103,25 +2164,26 @@ static void getValidReaderKeys(std::set<std::string>* valid_keys) valid_keys->insert("stackLimit"); valid_keys->insert("failIfExtra"); valid_keys->insert("rejectDupKeys"); + valid_keys->insert("allowSpecialFloats"); } 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 Json::Value& inv = *invalid; - std::set<std::string> valid_keys; + std::set<JSONCPP_STRING> valid_keys; getValidReaderKeys(&valid_keys); Value::Members keys = settings_.getMemberNames(); size_t n = keys.size(); for (size_t i = 0; i < n; ++i) { - std::string const& key = keys[i]; + JSONCPP_STRING const& key = keys[i]; if (valid_keys.find(key) == valid_keys.end()) { inv[key] = settings_[key]; } } return 0u == inv.size(); } -Value& CharReaderBuilder::operator[](std::string key) +Value& CharReaderBuilder::operator[](JSONCPP_STRING key) { return settings_[key]; } @@ -2134,8 +2196,10 @@ void CharReaderBuilder::strictMode(Json::Value* settings) (*settings)["allowDroppedNullPlaceholders"] = false; (*settings)["allowNumericKeys"] = false; (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; (*settings)["failIfExtra"] = true; (*settings)["rejectDupKeys"] = true; + (*settings)["allowSpecialFloats"] = false; //! [CharReaderBuilderStrictMode] } // static @@ -2151,6 +2215,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) (*settings)["stackLimit"] = 1000; (*settings)["failIfExtra"] = false; (*settings)["rejectDupKeys"] = false; + (*settings)["allowSpecialFloats"] = false; //! [CharReaderBuilderDefaults] } @@ -2158,12 +2223,12 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) // global functions bool parseFromStream( - CharReader::Factory const& fact, std::istream& sin, - Value* root, std::string* errs) + CharReader::Factory const& fact, JSONCPP_ISTREAM& sin, + Value* root, JSONCPP_STRING* errs) { - std::ostringstream ssin; + JSONCPP_OSTRINGSTREAM ssin; ssin << sin.rdbuf(); - std::string doc = ssin.str(); + JSONCPP_STRING doc = ssin.str(); char const* begin = doc.data(); char const* end = begin + doc.size(); // Note that we do not actually need a null-terminator. @@ -2171,16 +2236,16 @@ bool parseFromStream( return reader->parse(begin, end, root, errs); } -std::istream& operator>>(std::istream& sin, Value& root) { +JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) { CharReaderBuilder b; - std::string errs; + JSONCPP_STRING errs; bool ok = parseFromStream(b, sin, &root, &errs); if (!ok) { fprintf(stderr, "Error from reader: %s", errs.c_str()); - throwRuntimeError("reader error"); + throwRuntimeError(errs); } return sin; } @@ -2294,27 +2359,27 @@ UInt ValueIteratorBase::index() const { return Value::UInt(-1); } -std::string ValueIteratorBase::name() const { - char const* key; +JSONCPP_STRING ValueIteratorBase::name() const { + char const* keey; char const* end; - key = memberName(&end); - if (!key) return std::string(); - return std::string(key, end); + keey = memberName(&end); + if (!keey) return JSONCPP_STRING(); + return JSONCPP_STRING(keey, end); } char const* ValueIteratorBase::memberName() const { - const char* name = (*current_).first.data(); - return name ? name : ""; + const char* cname = (*current_).first.data(); + return cname ? cname : ""; } char const* ValueIteratorBase::memberName(char const** end) const { - const char* name = (*current_).first.data(); - if (!name) { + const char* cname = (*current_).first.data(); + if (!cname) { *end = NULL; return NULL; } - *end = name + (*current_).first.length(); - return name; + *end = cname + (*current_).first.length(); + return cname; } // ////////////////////////////////////////////////////////////////// @@ -2331,6 +2396,9 @@ ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator& current) : ValueIteratorBase(current) {} +ValueConstIterator::ValueConstIterator(ValueIterator const& other) + : ValueIteratorBase(other) {} + ValueConstIterator& ValueConstIterator:: operator=(const ValueIteratorBase& other) { copy(other); @@ -2351,7 +2419,9 @@ ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) : ValueIteratorBase(current) {} ValueIterator::ValueIterator(const ValueConstIterator& other) - : ValueIteratorBase(other) {} + : ValueIteratorBase(other) { + throwRuntimeError("ConstIterator to Iterator should never be allowed."); +} ValueIterator::ValueIterator(const ValueIterator& other) : ValueIteratorBase(other) {} @@ -2409,10 +2479,22 @@ 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; +} + +// 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(); const Int Value::minInt = Int(~(UInt(-1) / 2)); const Int Value::maxInt = Int(UInt(-1) / 2); @@ -2433,11 +2515,14 @@ const LargestUInt Value::maxLargestUInt = LargestUInt(-1); #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 >= 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 + 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) { @@ -2458,10 +2543,11 @@ static inline bool InRange(double d, T min, U max) { * @return Pointer on the duplicate instance of string. */ static inline char* duplicateStringValue(const char* value, - size_t length) { + size_t length) +{ // Avoid an integer overflow in the call to malloc below by limiting length // to a sane value. - if (length >= (size_t)Value::maxInt) + if (length >= static_cast<size_t>(Value::maxInt)) length = Value::maxInt - 1; char* newString = static_cast<char*>(malloc(length + 1)); @@ -2483,10 +2569,10 @@ static inline char* duplicateAndPrefixStringValue( { // Avoid an integer overflow in the call to malloc below by limiting length // to a sane value. - JSON_ASSERT_MESSAGE(length <= (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 + sizeof(unsigned) + 1U; + unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U; char* newString = static_cast<char*>(malloc(actualLength)); if (newString == 0) { throwRuntimeError( @@ -2503,7 +2589,7 @@ inline static void decodePrefixedString( unsigned* length, char const** value) { if (!isPrefixed) { - *length = strlen(prefixed); + *length = static_cast<unsigned>(strlen(prefixed)); *value = prefixed; } else { *length = *reinterpret_cast<unsigned const*>(prefixed); @@ -2512,7 +2598,29 @@ inline static void decodePrefixedString( } /** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue(). */ -static inline void releaseStringValue(char* value) { free(value); } +#if JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { + unsigned length = 0; + char const* valueDecoded; + decodePrefixedString(true, value, &length, &valueDecoded); + size_t const size = sizeof(unsigned) + length + 1U; + memset(value, 0, size); + free(value); +} +static inline void releaseStringValue(char* value, unsigned length) { + // length==0 => we allocated the strings memory + 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); +} +#endif // JSONCPP_USING_SECURE_MEMORY } // namespace Json @@ -2530,43 +2638,26 @@ static inline void releaseStringValue(char* value) { free(value); } namespace Json { -class JSON_API Exception : public std::exception { -public: - Exception(std::string const& msg); - virtual ~Exception() throw(); - virtual char const* what() const throw(); -protected: - std::string const msg_; -}; -class JSON_API RuntimeError : public Exception { -public: - RuntimeError(std::string const& msg); -}; -class JSON_API LogicError : public Exception { -public: - LogicError(std::string const& msg); -}; - -Exception::Exception(std::string const& msg) +Exception::Exception(JSONCPP_STRING const& msg) : msg_(msg) {} -Exception::~Exception() throw() +Exception::~Exception() JSONCPP_NOEXCEPT {} -char const* Exception::what() const throw() +char const* Exception::what() const JSONCPP_NOEXCEPT { return msg_.c_str(); } -RuntimeError::RuntimeError(std::string const& msg) +RuntimeError::RuntimeError(JSONCPP_STRING const& msg) : Exception(msg) {} -LogicError::LogicError(std::string const& msg) +LogicError::LogicError(JSONCPP_STRING const& msg) : Exception(msg) {} -void throwRuntimeError(std::string const& msg) +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) { throw RuntimeError(msg); } -void throwLogicError(std::string const& msg) +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) { throw LogicError(msg); } @@ -2579,16 +2670,17 @@ void throwLogicError(std::string const& msg) // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// -Value::CommentInfo::CommentInfo() : comment_(0) {} +Value::CommentInfo::CommentInfo() : comment_(0) +{} Value::CommentInfo::~CommentInfo() { if (comment_) - releaseStringValue(comment_); + releaseStringValue(comment_, 0u); } void Value::CommentInfo::setComment(const char* text, size_t len) { if (comment_) { - releaseStringValue(comment_); + releaseStringValue(comment_, 0u); comment_ = 0; } JSON_ASSERT(text != 0); @@ -2610,31 +2702,37 @@ void Value::CommentInfo::setComment(const char* text, size_t len) { // Notes: policy_ indicates if the string was allocated when // a string is stored. -Value::CZString::CZString(ArrayIndex index) : cstr_(0), index_(index) {} +Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {} -Value::CZString::CZString(char const* str, unsigned length, DuplicationPolicy allocate) - : cstr_(str) -{ +Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate) + : cstr_(str) { // allocate != duplicate - storage_.policy_ = allocate; - storage_.length_ = length; + storage_.policy_ = allocate & 0x3; + storage_.length_ = ulength & 0x3FFFFFFF; } -Value::CZString::CZString(const CZString& other) - : cstr_(other.storage_.policy_ != noDuplication && other.cstr_ != 0 - ? duplicateStringValue(other.cstr_, other.storage_.length_) - : other.cstr_) -{ - storage_.policy_ = (other.cstr_ - ? (other.storage_.policy_ == noDuplication +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) - : other.storage_.policy_); + : 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_) { + other.cstr_ = nullptr; +} +#endif + Value::CZString::~CZString() { - if (cstr_ && storage_.policy_ == duplicate) - releaseStringValue(const_cast<char*>(cstr_)); + 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 + } } void Value::CZString::swap(CZString& other) { @@ -2653,7 +2751,8 @@ bool Value::CZString::operator<(const CZString& other) const { // Assume both are strings. unsigned this_len = this->storage_.length_; unsigned other_len = other.storage_.length_; - unsigned min_len = std::min(this_len, other_len); + 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; @@ -2667,6 +2766,7 @@ bool Value::CZString::operator==(const CZString& other) const { unsigned this_len = this->storage_.length_; unsigned other_len = other.storage_.length_; 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; } @@ -2690,9 +2790,10 @@ bool Value::CZString::isStaticString() const { return storage_.policy_ == noDupl * memset( this, 0, sizeof(Value) ) * This optimization is used in ValueInternalMap fast allocator. */ -Value::Value(ValueType type) { - initBasic(type); - switch (type) { +Value::Value(ValueType vtype) { + static char const emptyString[] = ""; + initBasic(vtype); + switch (vtype) { case nullValue: break; case intValue: @@ -2703,7 +2804,8 @@ Value::Value(ValueType type) { value_.real_ = 0.0; break; case stringValue: - value_.string_ = 0; + // allocated_ == false, so this is safe. + value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString)); break; case arrayValue: case objectValue: @@ -2744,6 +2846,7 @@ 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))); } @@ -2753,7 +2856,7 @@ Value::Value(const char* beginValue, const char* endValue) { duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue)); } -Value::Value(const std::string& value) { +Value::Value(const JSONCPP_STRING& value) { initBasic(stringValue, true); value_.string_ = duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length())); @@ -2820,6 +2923,14 @@ Value::Value(Value const& other) } } +#if JSON_HAS_RVALUE_REFERENCES +// Move constructor +Value::Value(Value&& other) { + initBasic(nullValue); + swap(other); +} +#endif + Value::~Value() { switch (type_) { case nullValue: @@ -2830,7 +2941,7 @@ Value::~Value() { break; case stringValue: if (allocated_) - releaseStringValue(value_.string_); + releasePrefixedStringValue(value_.string_); break; case arrayValue: case objectValue: @@ -2840,8 +2951,9 @@ Value::~Value() { JSON_ASSERT_UNREACHABLE; } - if (comments_) - delete[] comments_; + delete[] comments_; + + value_.uint_ = 0; } Value& Value::operator=(Value other) { @@ -2856,7 +2968,7 @@ void Value::swapPayload(Value& other) { std::swap(value_, other.value_); int temp2 = allocated_; allocated_ = other.allocated_; - other.allocated_ = temp2; + other.allocated_ = temp2 & 0x1; } void Value::swap(Value& other) { @@ -2903,7 +3015,8 @@ bool Value::operator<(const Value& other) const { char const* 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(this_len, other_len); + 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; @@ -2959,6 +3072,7 @@ bool Value::operator==(const Value& other) const { 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; } @@ -2984,16 +3098,28 @@ const char* Value::asCString() const { return this_str; } -bool Value::getString(char const** str, char const** end) const { +#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; + unsigned this_len; + char const* 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; unsigned length; decodePrefixedString(this->allocated_, this->value_.string_, &length, str); - *end = *str + length; + *cend = *str + length; return true; } -std::string Value::asString() const { +JSONCPP_STRING Value::asString() const { switch (type_) { case nullValue: return ""; @@ -3003,7 +3129,7 @@ std::string Value::asString() const { unsigned this_len; char const* this_str; decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - return std::string(this_str, this_len); + return JSONCPP_STRING(this_str, this_len); } case booleanValue: return value_.bool_ ? "true" : "false"; @@ -3163,7 +3289,8 @@ float Value::asFloat() const { #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) return static_cast<float>(value_.uint_); #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return integerToDouble(value_.uint_); + // This can fail (silently?) if the value is bigger than MAX_FLOAT. + return static_cast<float>(integerToDouble(value_.uint_)); #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) case realValue: return static_cast<float>(value_.real_); @@ -3188,7 +3315,8 @@ bool Value::asBool() const { case uintValue: return value_.uint_ ? true : false; case realValue: - return value_.real_ ? true : false; + // This is kind of strange. Not recommended. + return (value_.real_ != 0.0) ? true : false; default: break; } @@ -3291,7 +3419,7 @@ void Value::resize(ArrayIndex newSize) { for (ArrayIndex index = newSize; index < oldSize; ++index) { value_.map_->erase(index); } - assert(size() == newSize); + JSON_ASSERT(size() == newSize); } } @@ -3306,7 +3434,7 @@ Value& Value::operator[](ArrayIndex index) { if (it != value_.map_->end() && (*it).first == key) return (*it).second; - ObjectValues::value_type defaultValue(key, nullRef); + ObjectValues::value_type defaultValue(key, nullSingleton()); it = value_.map_->insert(it, defaultValue); return (*it).second; } @@ -3323,11 +3451,11 @@ const Value& Value::operator[](ArrayIndex index) const { type_ == nullValue || type_ == arrayValue, "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); if (type_ == nullValue) - return nullRef; + return nullSingleton(); CZString key(index); ObjectValues::const_iterator it = value_.map_->find(key); if (it == value_.map_->end()) - return nullRef; + return nullSingleton(); return (*it).second; } @@ -3338,8 +3466,8 @@ const Value& Value::operator[](int index) const { return (*this)[ArrayIndex(index)]; } -void Value::initBasic(ValueType type, bool allocated) { - type_ = type; +void Value::initBasic(ValueType vtype, bool allocated) { + type_ = vtype; allocated_ = allocated; comments_ = 0; start_ = 0; @@ -3361,14 +3489,14 @@ Value& Value::resolveReference(const char* key) { if (it != value_.map_->end() && (*it).first == actualKey) return (*it).second; - ObjectValues::value_type defaultValue(actualKey, nullRef); + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); it = value_.map_->insert(it, defaultValue); Value& value = (*it).second; return value; } // @param key is not null-terminated. -Value& Value::resolveReference(char const* key, char const* end) +Value& Value::resolveReference(char const* key, char const* cend) { JSON_ASSERT_MESSAGE( type_ == nullValue || type_ == objectValue, @@ -3376,12 +3504,12 @@ Value& Value::resolveReference(char const* key, char const* end) if (type_ == nullValue) *this = Value(objectValue); CZString actualKey( - key, static_cast<unsigned>(end-key), CZString::duplicateOnCopy); + 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; - ObjectValues::value_type defaultValue(actualKey, nullRef); + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); it = value_.map_->insert(it, defaultValue); Value& value = (*it).second; return value; @@ -3389,18 +3517,18 @@ Value& Value::resolveReference(char const* key, char const* end) Value Value::get(ArrayIndex index, const Value& defaultValue) const { const Value* value = &((*this)[index]); - return value == &nullRef ? defaultValue : *value; + return value == &nullSingleton() ? defaultValue : *value; } bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } -Value const* Value::find(char const* key, char const* end) const +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>(end-key), CZString::noDuplication); + 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; return &(*it).second; @@ -3408,13 +3536,13 @@ Value const* Value::find(char const* key, char const* end) const const Value& Value::operator[](const char* key) const { Value const* found = find(key, key + strlen(key)); - if (!found) return nullRef; + if (!found) return nullSingleton(); return *found; } -Value const& Value::operator[](std::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 nullRef; + if (!found) return nullSingleton(); return *found; } @@ -3422,7 +3550,7 @@ Value& Value::operator[](const char* key) { return resolveReference(key, key + strlen(key)); } -Value& Value::operator[](const std::string& key) { +Value& Value::operator[](const JSONCPP_STRING& key) { return resolveReference(key.data(), key.data() + key.length()); } @@ -3437,34 +3565,34 @@ Value& Value::operator[](const CppTL::ConstString& key) { Value const& Value::operator[](CppTL::ConstString const& key) const { Value const* found = find(key.c_str(), key.end_c_str()); - if (!found) return nullRef; + 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* end, Value const& defaultValue) const +Value Value::get(char const* key, char const* cend, Value const& defaultValue) const { - Value const* found = find(key, end); + Value const* found = find(key, cend); return !found ? defaultValue : *found; } Value Value::get(char const* key, Value const& defaultValue) const { return get(key, key + strlen(key), defaultValue); } -Value Value::get(std::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* end, Value* removed) +bool Value::removeMember(const char* key, const char* cend, Value* removed) { if (type_ != objectValue) { return false; } - CZString actualKey(key, static_cast<unsigned>(end-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; @@ -3476,7 +3604,7 @@ bool Value::removeMember(const char* key, Value* removed) { return removeMember(key, key + strlen(key), removed); } -bool Value::removeMember(std::string const& key, Value* removed) +bool Value::removeMember(JSONCPP_STRING const& key, Value* removed) { return removeMember(key.data(), key.data() + key.length(), removed); } @@ -3485,13 +3613,13 @@ Value Value::removeMember(const char* key) JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, "in Json::Value::removeMember(): requires objectValue"); if (type_ == nullValue) - return nullRef; + return nullSingleton(); Value removed; // null removeMember(key, key + strlen(key), &removed); return removed; // still null if removeMember() did nothing } -Value Value::removeMember(const std::string& key) +Value Value::removeMember(const JSONCPP_STRING& key) { return removeMember(key.c_str()); } @@ -3509,8 +3637,8 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) { ArrayIndex oldSize = size(); // shift left all items left, into the place of the "removed" for (ArrayIndex i = index; i < (oldSize - 1); ++i){ - CZString key(i); - (*value_.map_)[key] = (*this)[i + 1]; + CZString keey(i); + (*value_.map_)[keey] = (*this)[i + 1]; } // erase the last one ("leftover") CZString keyLast(oldSize - 1); @@ -3526,16 +3654,16 @@ Value Value::get(const CppTL::ConstString& key, } #endif -bool Value::isMember(char const* key, char const* end) const +bool Value::isMember(char const* key, char const* cend) const { - Value const* value = find(key, end); + Value const* value = find(key, cend); return NULL != value; } bool Value::isMember(char const* key) const { return isMember(key, key + strlen(key)); } -bool Value::isMember(std::string const& key) const +bool Value::isMember(JSONCPP_STRING const& key) const { return isMember(key.data(), key.data() + key.length()); } @@ -3557,7 +3685,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(std::string((*it).first.data(), + members.push_back(JSONCPP_STRING((*it).first.data(), (*it).first.length())); } return members; @@ -3600,7 +3728,11 @@ bool Value::isBool() const { return type_ == booleanValue; } bool Value::isInt() const { switch (type_) { case intValue: +#if defined(JSON_HAS_INT64) return value_.int_ >= minInt && value_.int_ <= maxInt; +#else + return true; +#endif case uintValue: return value_.uint_ <= UInt(maxInt); case realValue: @@ -3615,9 +3747,17 @@ bool Value::isInt() const { bool Value::isUInt() const { switch (type_) { case intValue: +#if defined(JSON_HAS_INT64) return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); +#else + return value_.int_ >= 0; +#endif case uintValue: +#if defined(JSON_HAS_INT64) return value_.uint_ <= maxUInt; +#else + return true; +#endif case realValue: return value_.real_ >= 0 && value_.real_ <= maxUInt && IsIntegral(value_.real_); @@ -3675,9 +3815,9 @@ bool Value::isIntegral() const { #endif } -bool Value::isDouble() const { return type_ == realValue || isIntegral(); } +bool Value::isDouble() const { return type_ == intValue || type_ == uintValue || type_ == realValue; } -bool Value::isNumeric() const { return isIntegral() || isDouble(); } +bool Value::isNumeric() const { return isDouble(); } bool Value::isString() const { return type_ == stringValue; } @@ -3699,7 +3839,7 @@ void Value::setComment(const char* comment, CommentPlacement placement) { setComment(comment, strlen(comment), placement); } -void Value::setComment(const std::string& comment, CommentPlacement placement) { +void Value::setComment(const JSONCPP_STRING& comment, CommentPlacement placement) { setComment(comment.c_str(), comment.length(), placement); } @@ -3707,21 +3847,21 @@ bool Value::hasComment(CommentPlacement placement) const { return comments_ != 0 && comments_[placement].comment_ != 0; } -std::string Value::getComment(CommentPlacement placement) const { +JSONCPP_STRING Value::getComment(CommentPlacement placement) const { if (hasComment(placement)) return comments_[placement].comment_; return ""; } -void Value::setOffsetStart(size_t start) { start_ = start; } +void Value::setOffsetStart(ptrdiff_t start) { start_ = start; } -void Value::setOffsetLimit(size_t limit) { limit_ = limit; } +void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; } -size_t Value::getOffsetStart() const { return start_; } +ptrdiff_t Value::getOffsetStart() const { return start_; } -size_t Value::getOffsetLimit() const { return limit_; } +ptrdiff_t Value::getOffsetLimit() const { return limit_; } -std::string Value::toStyledString() const { +JSONCPP_STRING Value::toStyledString() const { StyledWriter writer; return writer.write(*this); } @@ -3789,13 +3929,13 @@ PathArgument::PathArgument(ArrayIndex index) PathArgument::PathArgument(const char* key) : key_(key), index_(), kind_(kindKey) {} -PathArgument::PathArgument(const std::string& key) +PathArgument::PathArgument(const JSONCPP_STRING& key) : key_(key.c_str()), index_(), kind_(kindKey) {} // class Path // ////////////////////////////////////////////////////////////////// -Path::Path(const std::string& path, +Path::Path(const JSONCPP_STRING& path, const PathArgument& a1, const PathArgument& a2, const PathArgument& a3, @@ -3810,7 +3950,7 @@ Path::Path(const std::string& path, makePath(path, in); } -void Path::makePath(const std::string& path, const InArgs& in) { +void Path::makePath(const JSONCPP_STRING& path, const InArgs& in) { const char* current = path.c_str(); const char* end = current + path.length(); InArgs::const_iterator itInArg = in.begin(); @@ -3825,23 +3965,23 @@ void Path::makePath(const std::string& path, const InArgs& in) { index = index * 10 + ArrayIndex(*current - '0'); args_.push_back(index); } - if (current == end || *current++ != ']') + if (current == end || *++current != ']') invalidPath(path, int(current - path.c_str())); } else if (*current == '%') { addPathInArg(path, in, itInArg, PathArgument::kindKey); ++current; - } else if (*current == '.') { + } else if (*current == '.' || *current == ']') { ++current; } else { const char* beginName = current; while (current != end && !strchr("[.", *current)) ++current; - args_.push_back(std::string(beginName, current)); + args_.push_back(JSONCPP_STRING(beginName, current)); } } } -void Path::addPathInArg(const std::string& /*path*/, +void Path::addPathInArg(const JSONCPP_STRING& /*path*/, const InArgs& in, InArgs::const_iterator& itInArg, PathArgument::Kind kind) { @@ -3850,11 +3990,11 @@ void Path::addPathInArg(const std::string& /*path*/, } else if ((*itInArg)->kind_ != kind) { // Error: bad argument type } else { - args_.push_back(**itInArg); + args_.push_back(**itInArg++); } } -void Path::invalidPath(const std::string& /*path*/, int /*location*/) { +void Path::invalidPath(const JSONCPP_STRING& /*path*/, int /*location*/) { // Error: invalid path. } @@ -3865,16 +4005,19 @@ const Value& Path::resolve(const Value& root) const { if (arg.kind_ == PathArgument::kindIndex) { if (!node->isArray() || !node->isValidIndex(arg.index_)) { // Error: unable to resolve path (array value expected at position... + return Value::null; } node = &((*node)[arg.index_]); } else if (arg.kind_ == PathArgument::kindKey) { if (!node->isObject()) { // Error: unable to resolve path (object value expected at position...) + return Value::null; } node = &((*node)[arg.key_]); - if (node == &Value::nullRef) { + if (node == &Value::nullSingleton()) { // Error: unable to resolve path (object has no member named '' at // position...) + return Value::null; } } } @@ -3893,7 +4036,7 @@ Value Path::resolve(const Value& root, const Value& defaultValue) const { if (!node->isObject()) return defaultValue; node = &((*node)[arg.key_]); - if (node == &Value::nullRef) + if (node == &Value::nullSingleton()) return defaultValue; } } @@ -3956,18 +4099,53 @@ Value& Path::make(Value& root) const { #include <float.h> #define isfinite _finite #elif 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(isfinite) +#if defined(__ia64) && !defined(finite) +#define isfinite(x) ((sizeof(x) == sizeof(float) ? \ + _Isfinitef(x) : _IsFinite(x))) +#else +#include <math.h> +#define isfinite finite +#endif +#endif #else #include <cmath> +#if !(defined(__QNXNTO__)) // QNX already defines isfinite #define isfinite std::isfinite #endif +#endif -#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below +#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 +#endif + +#if defined(__BORLANDC__) +#include <float.h> +#define isfinite _finite +#define snprintf _snprintf +#endif #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 // Disable warning about strdup being deprecated. @@ -3976,7 +4154,7 @@ Value& Path::make(Value& root) const { namespace Json { -#if __cplusplus >= 201103L +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) typedef std::unique_ptr<StreamWriter> StreamWriterPtr; #else typedef std::auto_ptr<StreamWriter> StreamWriterPtr; @@ -4000,20 +4178,23 @@ static bool containsControlCharacter0(const char* str, unsigned len) { return false; } -std::string valueToString(LargestInt value) { +JSONCPP_STRING valueToString(LargestInt value) { UIntToStringBuffer buffer; char* current = buffer + sizeof(buffer); - bool isNegative = value < 0; - if (isNegative) - value = -value; - uintToString(LargestUInt(value), current); - if (isNegative) + if (value == Value::minLargestInt) { + uintToString(LargestUInt(Value::maxLargestInt) + 1, current); + *--current = '-'; + } else if (value < 0) { + uintToString(LargestUInt(-value), current); *--current = '-'; + } else { + uintToString(LargestUInt(value), current); + } assert(current >= buffer); return current; } -std::string valueToString(LargestUInt value) { +JSONCPP_STRING valueToString(LargestUInt value) { UIntToStringBuffer buffer; char* current = buffer + sizeof(buffer); uintToString(value, current); @@ -4023,68 +4204,71 @@ std::string valueToString(LargestUInt value) { #if defined(JSON_HAS_INT64) -std::string valueToString(Int value) { +JSONCPP_STRING valueToString(Int value) { return valueToString(LargestInt(value)); } -std::string valueToString(UInt value) { +JSONCPP_STRING valueToString(UInt value) { return valueToString(LargestUInt(value)); } #endif // # if defined(JSON_HAS_INT64) -std::string valueToString(double value) { +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[32]; + char buffer[36]; int len = -1; -// Print into the buffer. We need not request the alternative representation -// that always has a decimal point because JSON doesn't distingish the -// concepts of reals and integers. -#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with - // visual studio 2005 to - // avoid warning. -#if defined(WINCE) - len = _snprintf(buffer, sizeof(buffer), "%.17g", value); -#else - len = sprintf_s(buffer, sizeof(buffer), "%.17g", value); -#endif -#else + char formatString[6]; + sprintf(formatString, "%%.%dg", precision); + + // Print into the buffer. We need not request the alternative representation + // that always has a decimal point because JSON doesn't distingish the + // concepts of reals and integers. if (isfinite(value)) { - len = snprintf(buffer, sizeof(buffer), "%.17g", 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"); + } + } else { // IEEE standard states that NaN values will not compare to themselves if (value != value) { - len = snprintf(buffer, sizeof(buffer), "null"); + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null"); } else if (value < 0) { - len = snprintf(buffer, sizeof(buffer), "-1e+9999"); + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999"); } else { - len = snprintf(buffer, sizeof(buffer), "1e+9999"); + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999"); } // For those, we do not need to call fixNumLoc, but it is fast. } -#endif assert(len >= 0); fixNumericLocale(buffer, buffer + len); return buffer; } +} + +JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); } -std::string valueToString(bool value) { return value ? "true" : "false"; } +JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; } -std::string valueToQuotedString(const char* value) { +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 std::string("\"") + value + "\""; + return JSONCPP_STRING("\"") + value + "\""; // We have to walk value and escape any special characters. - // Appending to std::string is not efficient, but this should be rare. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. // (Note: forward slashes are *not* rare, but I am not escaping them.) - std::string::size_type maxsize = + JSONCPP_STRING::size_type maxsize = strlen(value) * 2 + 3; // allescaped+quotes+NULL - std::string result; + JSONCPP_STRING result; result.reserve(maxsize); // to avoid lots of mallocs result += "\""; for (const char* c = value; *c != 0; ++c) { @@ -4120,7 +4304,7 @@ std::string valueToQuotedString(const char* value) { // sequence from occurring. default: if (isControlCharacter(*c)) { - std::ostringstream oss; + JSONCPP_OSTRINGSTREAM oss; oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c); result += oss.str(); @@ -4149,19 +4333,19 @@ static char const* strnpbrk(char const* s, char const* accept, size_t n) { } return NULL; } -static std::string valueToQuotedStringN(const char* value, unsigned length) { +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)) - return std::string("\"") + value + "\""; + return JSONCPP_STRING("\"") + value + "\""; // We have to walk value and escape any special characters. - // Appending to std::string is not efficient, but this should be rare. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. // (Note: forward slashes are *not* rare, but I am not escaping them.) - std::string::size_type maxsize = + JSONCPP_STRING::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL - std::string result; + JSONCPP_STRING result; result.reserve(maxsize); // to avoid lots of mallocs result += "\""; char const* end = value + length; @@ -4198,7 +4382,7 @@ static std::string valueToQuotedStringN(const char* value, unsigned length) { // sequence from occurring. default: if ((isControlCharacter(*c)) || (*c == 0)) { - std::ostringstream oss; + JSONCPP_OSTRINGSTREAM oss; oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c); result += oss.str(); @@ -4229,7 +4413,7 @@ void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } -std::string FastWriter::write(const Value& root) { +JSONCPP_STRING FastWriter::write(const Value& root) { document_ = ""; writeValue(root); if (!omitEndingLineFeed_) @@ -4253,15 +4437,21 @@ void FastWriter::writeValue(const Value& value) { document_ += valueToString(value.asDouble()); break; case stringValue: - document_ += valueToQuotedString(value.asCString()); + { + // 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)); break; + } case booleanValue: document_ += valueToString(value.asBool()); break; case arrayValue: { document_ += '['; - int size = value.size(); - for (int index = 0; index < size; ++index) { + ArrayIndex size = value.size(); + for (ArrayIndex index = 0; index < size; ++index) { if (index > 0) document_ += ','; writeValue(value[index]); @@ -4273,10 +4463,10 @@ void FastWriter::writeValue(const Value& value) { document_ += '{'; for (Value::Members::iterator it = members.begin(); it != members.end(); ++it) { - const std::string& name = *it; + const JSONCPP_STRING& name = *it; if (it != members.begin()) document_ += ','; - document_ += valueToQuotedStringN(name.data(), name.length()); + document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())); document_ += yamlCompatiblityEnabled_ ? ": " : ":"; writeValue(value[name]); } @@ -4291,7 +4481,7 @@ void FastWriter::writeValue(const Value& value) { StyledWriter::StyledWriter() : rightMargin_(74), indentSize_(3), addChildValues_() {} -std::string StyledWriter::write(const Value& root) { +JSONCPP_STRING StyledWriter::write(const Value& root) { document_ = ""; addChildValues_ = false; indentString_ = ""; @@ -4318,7 +4508,7 @@ void StyledWriter::writeValue(const Value& value) { break; case stringValue: { - // Is NULL is possible for value.string_? + // Is NULL possible for value.string_? No. char const* str; char const* end; bool ok = value.getString(&str, &end); @@ -4341,7 +4531,7 @@ void StyledWriter::writeValue(const Value& value) { indent(); Value::Members::iterator it = members.begin(); for (;;) { - const std::string& name = *it; + const JSONCPP_STRING& name = *it; const Value& childValue = value[name]; writeCommentBeforeValue(childValue); writeWithIndent(valueToQuotedString(name.c_str())); @@ -4405,26 +4595,25 @@ void StyledWriter::writeArrayValue(const Value& value) { } bool StyledWriter::isMultineArray(const Value& value) { - int size = value.size(); + ArrayIndex const size = value.size(); bool isMultiLine = size * 3 >= rightMargin_; childValues_.clear(); - for (int index = 0; index < size && !isMultiLine; ++index) { + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { const Value& childValue = value[index]; - isMultiLine = - isMultiLine || ((childValue.isArray() || childValue.isObject()) && + isMultiLine = ((childValue.isArray() || childValue.isObject()) && childValue.size() > 0); } if (!isMultiLine) // check if line length > max line length { childValues_.reserve(size); addChildValues_ = true; - int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (int index = 0; index < size; ++index) { + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { if (hasCommentForValue(value[index])) { isMultiLine = true; } writeValue(value[index]); - lineLength += int(childValues_[index].length()); + lineLength += static_cast<ArrayIndex>(childValues_[index].length()); } addChildValues_ = false; isMultiLine = isMultiLine || lineLength >= rightMargin_; @@ -4432,7 +4621,7 @@ bool StyledWriter::isMultineArray(const Value& value) { return isMultiLine; } -void StyledWriter::pushValue(const std::string& value) { +void StyledWriter::pushValue(const JSONCPP_STRING& value) { if (addChildValues_) childValues_.push_back(value); else @@ -4450,15 +4639,15 @@ void StyledWriter::writeIndent() { document_ += indentString_; } -void StyledWriter::writeWithIndent(const std::string& value) { +void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) { writeIndent(); document_ += value; } -void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); } +void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); } void StyledWriter::unindent() { - assert(int(indentString_.size()) >= indentSize_); + assert(indentString_.size() >= indentSize_); indentString_.resize(indentString_.size() - indentSize_); } @@ -4468,8 +4657,8 @@ void StyledWriter::writeCommentBeforeValue(const Value& root) { document_ += "\n"; writeIndent(); - const std::string& comment = root.getComment(commentBefore); - std::string::const_iterator iter = comment.begin(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); while (iter != comment.end()) { document_ += *iter; if (*iter == '\n' && @@ -4502,11 +4691,11 @@ bool StyledWriter::hasCommentForValue(const Value& value) { // Class StyledStreamWriter // ////////////////////////////////////////////////////////////////// -StyledStreamWriter::StyledStreamWriter(std::string indentation) +StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation) : document_(NULL), rightMargin_(74), indentation_(indentation), addChildValues_() {} -void StyledStreamWriter::write(std::ostream& out, const Value& root) { +void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) { document_ = &out; addChildValues_ = false; indentString_ = ""; @@ -4535,8 +4724,15 @@ void StyledStreamWriter::writeValue(const Value& value) { pushValue(valueToString(value.asDouble())); break; case stringValue: - pushValue(valueToQuotedString(value.asCString())); + { + // 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(""); break; + } case booleanValue: pushValue(valueToString(value.asBool())); break; @@ -4552,7 +4748,7 @@ void StyledStreamWriter::writeValue(const Value& value) { indent(); Value::Members::iterator it = members.begin(); for (;;) { - const std::string& name = *it; + const JSONCPP_STRING& name = *it; const Value& childValue = value[name]; writeCommentBeforeValue(childValue); writeWithIndent(valueToQuotedString(name.c_str())); @@ -4618,26 +4814,25 @@ void StyledStreamWriter::writeArrayValue(const Value& value) { } bool StyledStreamWriter::isMultineArray(const Value& value) { - int size = value.size(); + ArrayIndex const size = value.size(); bool isMultiLine = size * 3 >= rightMargin_; childValues_.clear(); - for (int index = 0; index < size && !isMultiLine; ++index) { + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { const Value& childValue = value[index]; - isMultiLine = - isMultiLine || ((childValue.isArray() || childValue.isObject()) && + isMultiLine = ((childValue.isArray() || childValue.isObject()) && childValue.size() > 0); } if (!isMultiLine) // check if line length > max line length { childValues_.reserve(size); addChildValues_ = true; - int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (int index = 0; index < size; ++index) { + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { if (hasCommentForValue(value[index])) { isMultiLine = true; } writeValue(value[index]); - lineLength += int(childValues_[index].length()); + lineLength += static_cast<ArrayIndex>(childValues_[index].length()); } addChildValues_ = false; isMultiLine = isMultiLine || lineLength >= rightMargin_; @@ -4645,7 +4840,7 @@ bool StyledStreamWriter::isMultineArray(const Value& value) { return isMultiLine; } -void StyledStreamWriter::pushValue(const std::string& value) { +void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) { if (addChildValues_) childValues_.push_back(value); else @@ -4660,7 +4855,7 @@ void StyledStreamWriter::writeIndent() { *document_ << '\n' << indentString_; } -void StyledStreamWriter::writeWithIndent(const std::string& value) { +void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) { if (!indented_) writeIndent(); *document_ << value; indented_ = false; @@ -4678,8 +4873,8 @@ void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { return; if (!indented_) writeIndent(); - const std::string& comment = root.getComment(commentBefore); - std::string::const_iterator iter = comment.begin(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); while (iter != comment.end()) { *document_ << *iter; if (*iter == '\n' && @@ -4724,44 +4919,50 @@ struct CommentStyle { struct BuiltStyledStreamWriter : public StreamWriter { BuiltStyledStreamWriter( - std::string const& indentation, + JSONCPP_STRING const& indentation, CommentStyle::Enum cs, - std::string const& colonSymbol, - std::string const& nullSymbol, - std::string const& endingLineFeedSymbol); - virtual int write(Value const& root, std::ostream* sout); + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision); + 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); - void pushValue(std::string const& value); + void pushValue(JSONCPP_STRING const& value); void writeIndent(); - void writeWithIndent(std::string const& value); + void writeWithIndent(JSONCPP_STRING const& value); void indent(); void unindent(); void writeCommentBeforeValue(Value const& root); void writeCommentAfterValueOnSameLine(Value const& root); static bool hasCommentForValue(const Value& value); - typedef std::vector<std::string> ChildValues; + typedef std::vector<JSONCPP_STRING> ChildValues; ChildValues childValues_; - std::string indentString_; - int rightMargin_; - std::string indentation_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; CommentStyle::Enum cs_; - std::string colonSymbol_; - std::string nullSymbol_; - std::string endingLineFeedSymbol_; + JSONCPP_STRING colonSymbol_; + JSONCPP_STRING nullSymbol_; + JSONCPP_STRING endingLineFeedSymbol_; bool addChildValues_ : 1; bool indented_ : 1; + bool useSpecialFloats_ : 1; + unsigned int precision_; }; BuiltStyledStreamWriter::BuiltStyledStreamWriter( - std::string const& indentation, + JSONCPP_STRING const& indentation, CommentStyle::Enum cs, - std::string const& colonSymbol, - std::string const& nullSymbol, - std::string const& endingLineFeedSymbol) + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision) : rightMargin_(74) , indentation_(indentation) , cs_(cs) @@ -4770,9 +4971,11 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter( , endingLineFeedSymbol_(endingLineFeedSymbol) , addChildValues_(false) , indented_(false) + , useSpecialFloats_(useSpecialFloats) + , precision_(precision) { } -int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout) +int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout) { sout_ = sout; addChildValues_ = false; @@ -4799,11 +5002,11 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) { pushValue(valueToString(value.asLargestUInt())); break; case realValue: - pushValue(valueToString(value.asDouble())); + pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_)); break; case stringValue: { - // Is NULL is possible for value.string_? + // Is NULL is possible for value.string_? No. char const* str; char const* end; bool ok = value.getString(&str, &end); @@ -4826,10 +5029,10 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) { indent(); Value::Members::iterator it = members.begin(); for (;;) { - std::string const& name = *it; + JSONCPP_STRING const& name = *it; Value const& childValue = value[name]; writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedStringN(name.data(), name.length())); + writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()))); *sout_ << colonSymbol_; writeValue(childValue); if (++it == members.end()) { @@ -4884,7 +5087,7 @@ void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { if (!indentation_.empty()) *sout_ << " "; for (unsigned index = 0; index < size; ++index) { if (index > 0) - *sout_ << ", "; + *sout_ << ((!indentation_.empty()) ? ", " : ","); *sout_ << childValues_[index]; } if (!indentation_.empty()) *sout_ << " "; @@ -4894,26 +5097,25 @@ void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { } bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { - int size = value.size(); + ArrayIndex const size = value.size(); bool isMultiLine = size * 3 >= rightMargin_; childValues_.clear(); - for (int index = 0; index < size && !isMultiLine; ++index) { + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { Value const& childValue = value[index]; - isMultiLine = - isMultiLine || ((childValue.isArray() || childValue.isObject()) && + isMultiLine = ((childValue.isArray() || childValue.isObject()) && childValue.size() > 0); } if (!isMultiLine) // check if line length > max line length { childValues_.reserve(size); addChildValues_ = true; - int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (int index = 0; index < size; ++index) { + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { if (hasCommentForValue(value[index])) { isMultiLine = true; } writeValue(value[index]); - lineLength += int(childValues_[index].length()); + lineLength += static_cast<ArrayIndex>(childValues_[index].length()); } addChildValues_ = false; isMultiLine = isMultiLine || lineLength >= rightMargin_; @@ -4921,7 +5123,7 @@ bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { return isMultiLine; } -void BuiltStyledStreamWriter::pushValue(std::string const& value) { +void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) { if (addChildValues_) childValues_.push_back(value); else @@ -4940,7 +5142,7 @@ void BuiltStyledStreamWriter::writeIndent() { } } -void BuiltStyledStreamWriter::writeWithIndent(std::string const& value) { +void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) { if (!indented_) writeIndent(); *sout_ << value; indented_ = false; @@ -4959,8 +5161,8 @@ void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { return; if (!indented_) writeIndent(); - const std::string& comment = root.getComment(commentBefore); - std::string::const_iterator iter = comment.begin(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); while (iter != comment.end()) { *sout_ << *iter; if (*iter == '\n' && @@ -5010,10 +5212,12 @@ StreamWriterBuilder::~StreamWriterBuilder() {} StreamWriter* StreamWriterBuilder::newStreamWriter() const { - std::string indentation = settings_["indentation"].asString(); - std::string cs_str = settings_["commentStyle"].asString(); + JSONCPP_STRING indentation = settings_["indentation"].asString(); + JSONCPP_STRING cs_str = settings_["commentStyle"].asString(); bool eyc = settings_["enableYAMLCompatibility"].asBool(); bool dnp = settings_["dropNullPlaceholders"].asBool(); + bool usf = settings_["useSpecialFloats"].asBool(); + unsigned int pre = settings_["precision"].asUInt(); CommentStyle::Enum cs = CommentStyle::All; if (cs_str == "All") { cs = CommentStyle::All; @@ -5022,47 +5226,50 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const } else { throwRuntimeError("commentStyle must be 'All' or 'None'"); } - std::string colonSymbol = " : "; + JSONCPP_STRING colonSymbol = " : "; if (eyc) { colonSymbol = ": "; } else if (indentation.empty()) { colonSymbol = ":"; } - std::string nullSymbol = "null"; + JSONCPP_STRING nullSymbol = "null"; if (dnp) { nullSymbol = ""; } - std::string endingLineFeedSymbol = ""; + if (pre > 17) pre = 17; + JSONCPP_STRING endingLineFeedSymbol = ""; return new BuiltStyledStreamWriter( indentation, cs, - colonSymbol, nullSymbol, endingLineFeedSymbol); + colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre); } -static void getValidWriterKeys(std::set<std::string>* valid_keys) +static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys) { valid_keys->clear(); valid_keys->insert("indentation"); valid_keys->insert("commentStyle"); valid_keys->insert("enableYAMLCompatibility"); valid_keys->insert("dropNullPlaceholders"); + valid_keys->insert("useSpecialFloats"); + valid_keys->insert("precision"); } 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 Json::Value& inv = *invalid; - std::set<std::string> valid_keys; + std::set<JSONCPP_STRING> valid_keys; getValidWriterKeys(&valid_keys); Value::Members keys = settings_.getMemberNames(); size_t n = keys.size(); for (size_t i = 0; i < n; ++i) { - std::string const& key = keys[i]; + JSONCPP_STRING const& key = keys[i]; if (valid_keys.find(key) == valid_keys.end()) { inv[key] = settings_[key]; } } return 0u == inv.size(); } -Value& StreamWriterBuilder::operator[](std::string key) +Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) { return settings_[key]; } @@ -5074,17 +5281,19 @@ void StreamWriterBuilder::setDefaults(Json::Value* settings) (*settings)["indentation"] = "\t"; (*settings)["enableYAMLCompatibility"] = false; (*settings)["dropNullPlaceholders"] = false; + (*settings)["useSpecialFloats"] = false; + (*settings)["precision"] = 17; //! [StreamWriterBuilderDefaults] } -std::string writeString(StreamWriter::Factory const& builder, Value const& root) { - std::ostringstream sout; +JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) { + JSONCPP_OSTRINGSTREAM sout; StreamWriterPtr const writer(builder.newStreamWriter()); writer->write(root, &sout); return sout.str(); } -std::ostream& operator<<(std::ostream& sout, Value const& root) { +JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) { StreamWriterBuilder builder; StreamWriterPtr const writer(builder.newStreamWriter()); writer->write(root, &sout); @@ -5096,3 +5305,8 @@ std::ostream& operator<<(std::ostream& sout, Value const& root) { // ////////////////////////////////////////////////////////////////////// // End of content of file: src/lib_json/json_writer.cpp // ////////////////////////////////////////////////////////////////////// + + + + + |
