From 7a7f6d68bedb3beab0610db4dd0c521b94eddb5e Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Tue, 4 Jun 2019 14:57:11 -0400 Subject: [PATCH] Update jsoncpp --- include/json/json-forwards.h | 152 +++- include/json/json.h | 555 ++++++++----- include/jsoncpp.cpp | 1485 ++++++++++++++++++++-------------- 3 files changed, 1375 insertions(+), 817 deletions(-) diff --git a/include/json/json-forwards.h b/include/json/json-forwards.h index ccbdb2b..de2e4bd 100644 --- a/include/json/json-forwards.h +++ b/include/json/json-forwards.h @@ -1,4 +1,4 @@ -/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/). +/// Json-cpp amalgamated forward header (http://jsoncpp.sourceforge.net/). /// It is intended to be used with #include "json/json-forwards.h" /// This header provides forward declaration for all JsonCpp types. @@ -11,13 +11,13 @@ The JsonCpp library's source code, including accompanying documentation, tests and demonstration applications, are licensed under the following conditions... -The author (Baptiste Lepilleur) explicitly disclaims copyright in all +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all jurisdictions which recognize such a disclaimer. In such jurisdictions, this software is released into the Public Domain. In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is -released under the terms of the MIT License (see below). +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). In jurisdictions which recognize Public Domain property, the user of this software may choose to accept it either as 1) Public Domain, 2) under the @@ -32,7 +32,7 @@ described in clear, concise terms at: The full text of the MIT License follows: ======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation @@ -73,9 +73,9 @@ license you like. -#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED -# define JSON_FORWARD_AMALGATED_H_INCLUDED -/// If defined, indicates that the source file is amalgated +#ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED +# define JSON_FORWARD_AMALGAMATED_H_INCLUDED +/// If defined, indicates that the source file is amalgamated /// to prevent private header inclusion. #define JSON_IS_AMALGAMATION @@ -83,13 +83,16 @@ license you like. // Beginning of content of file: include/json/config.h // ////////////////////////////////////////////////////////////////////// -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef JSON_CONFIG_H_INCLUDED #define JSON_CONFIG_H_INCLUDED +#include +#include //typedef String +#include //typedef int64_t, uint64_t /// If defined, indicates that json library is embedded in CppTL library. //# define JSON_IN_CPPTL 1 @@ -107,9 +110,9 @@ license you like. #define JSON_USE_EXCEPTION 1 #endif -/// If defined, indicates that the source file is amalgated +/// If defined, indicates that the source file is amalgamated /// to prevent private header inclusion. -/// Remarks: it is automatically defined in the generated amalgated header. +/// Remarks: it is automatically defined in the generated amalgamated header. // #define JSON_IS_AMALGAMATION #ifdef JSON_IN_CPPTL @@ -122,12 +125,12 @@ license you like. #ifdef JSON_IN_CPPTL #define JSON_API CPPTL_API #elif defined(JSON_DLL_BUILD) -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__MINGW32__) #define JSON_API __declspec(dllexport) #define JSONCPP_DISABLE_DLL_INTERFACE_WARNING #endif // if defined(_MSC_VER) #elif defined(JSON_DLL) -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__MINGW32__) #define JSON_API __declspec(dllimport) #define JSONCPP_DISABLE_DLL_INTERFACE_WARNING #endif // if defined(_MSC_VER) @@ -141,34 +144,96 @@ license you like. // Storages, and 64 bits integer support is disabled. // #define JSON_NO_INT64 1 -#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6 -// Microsoft Visual Studio 6 only support conversion from __int64 to double -// (no conversion from unsigned __int64). -#define JSON_USE_INT64_DOUBLE_CONVERSION 1 -// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' -// characters in the debug information) -// All projects I've ever seen with VS6 were using this globally (not bothering -// with pragma push/pop). -#pragma warning(disable : 4786) -#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6 +#if defined(_MSC_VER) // MSVC +# if _MSC_VER <= 1200 // MSVC 6 + // Microsoft Visual Studio 6 only support conversion from __int64 to double + // (no conversion from unsigned __int64). +# define JSON_USE_INT64_DOUBLE_CONVERSION 1 + // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' + // characters in the debug information) + // All projects I've ever seen with VS6 were using this globally (not bothering + // with pragma push/pop). +# pragma warning(disable : 4786) +# endif // MSVC 6 -#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 -/// Indicates that the following function is deprecated. -#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) -#elif defined(__clang__) && defined(__has_feature) -#if __has_feature(attribute_deprecated_with_message) -#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# if _MSC_VER >= 1500 // MSVC 2008 + /// Indicates that the following function is deprecated. +# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +# endif + +#endif // defined(_MSC_VER) + +// In c++11 the override keyword allows you to explicitly define that a function +// is intended to override the base-class version. This makes the code more +// managable and fixes a set of common hard-to-find bugs. +#if __cplusplus >= 201103L +# define JSONCPP_OVERRIDE override +# define JSONCPP_NOEXCEPT noexcept +#elif defined(_MSC_VER) && _MSC_VER > 1600 && _MSC_VER < 1900 +# define JSONCPP_OVERRIDE override +# define JSONCPP_NOEXCEPT throw() +#elif defined(_MSC_VER) && _MSC_VER >= 1900 +# define JSONCPP_OVERRIDE override +# define JSONCPP_NOEXCEPT noexcept +#else +# define JSONCPP_OVERRIDE +# define JSONCPP_NOEXCEPT throw() #endif -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) -#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) -#elif defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) -#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) + +#ifndef JSON_HAS_RVALUE_REFERENCES + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // MSVC >= 2010 + +#ifdef __clang__ +#if __has_feature(cxx_rvalue_references) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // has_feature + +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // GXX_EXPERIMENTAL + +#endif // __clang__ || __GNUC__ + +#endif // not defined JSON_HAS_RVALUE_REFERENCES + +#ifndef JSON_HAS_RVALUE_REFERENCES +#define JSON_HAS_RVALUE_REFERENCES 0 #endif +#ifdef __clang__ +# if __has_extension(attribute_deprecated_with_message) +# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# endif +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +# endif // GNUC version +#endif // __clang__ || __GNUC__ + #if !defined(JSONCPP_DEPRECATED) #define JSONCPP_DEPRECATED(message) #endif // if !defined(JSONCPP_DEPRECATED) +#if __GNUC__ >= 6 +# define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +# include "version.h" + +# if JSONCPP_USING_SECURE_MEMORY +# include "allocator.h" //typedef Allocator +# endif + +#endif // if !defined(JSON_IS_AMALGAMATION) + namespace Json { typedef int Int; typedef unsigned int UInt; @@ -182,13 +247,26 @@ typedef unsigned int LargestUInt; typedef __int64 Int64; typedef unsigned __int64 UInt64; #else // if defined(_MSC_VER) // Other platforms, use long long -typedef long long int Int64; -typedef unsigned long long int UInt64; +typedef int64_t Int64; +typedef uint64_t UInt64; #endif // if defined(_MSC_VER) typedef Int64 LargestInt; typedef UInt64 LargestUInt; #define JSON_HAS_INT64 #endif // if defined(JSON_NO_INT64) +#if JSONCPP_USING_SECURE_MEMORY +#define JSONCPP_STRING std::basic_string, Json::SecureAllocator > +#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream, Json::SecureAllocator > +#define JSONCPP_OSTREAM std::basic_ostream> +#define JSONCPP_ISTRINGSTREAM std::basic_istringstream, Json::SecureAllocator > +#define JSONCPP_ISTREAM std::istream +#else +#define JSONCPP_STRING std::string +#define JSONCPP_OSTRINGSTREAM std::ostringstream +#define JSONCPP_OSTREAM std::ostream +#define JSONCPP_ISTRINGSTREAM std::istringstream +#define JSONCPP_ISTREAM std::istream +#endif // if JSONCPP_USING_SECURE_MEMORY } // end namespace Json #endif // JSON_CONFIG_H_INCLUDED @@ -206,7 +284,7 @@ typedef UInt64 LargestUInt; // Beginning of content of file: include/json/forwards.h // ////////////////////////////////////////////////////////////////////// -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -252,4 +330,4 @@ class ValueConstIterator; -#endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED +#endif //ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED diff --git a/include/json/json.h b/include/json/json.h index b1184db..b0421a3 100644 --- a/include/json/json.h +++ b/include/json/json.h @@ -1,4 +1,4 @@ -/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/). +/// Json-cpp amalgamated header (http://jsoncpp.sourceforge.net/). /// It is intended to be used with #include "json/json.h" // ////////////////////////////////////////////////////////////////////// @@ -10,13 +10,13 @@ The JsonCpp library's source code, including accompanying documentation, tests and demonstration applications, are licensed under the following conditions... -The author (Baptiste Lepilleur) explicitly disclaims copyright in all +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all jurisdictions which recognize such a disclaimer. In such jurisdictions, this software is released into the Public Domain. In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is -released under the terms of the MIT License (see below). +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). In jurisdictions which recognize Public Domain property, the user of this software may choose to accept it either as 1) Public Domain, 2) under the @@ -31,7 +31,7 @@ described in clear, concise terms at: The full text of the MIT License follows: ======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation @@ -69,13 +69,12 @@ license you like. // ////////////////////////////////////////////////////////////////////// -// Tell C++11 where to find std::unique_ptr -#include -#ifndef JSON_AMALGATED_H_INCLUDED -# define JSON_AMALGATED_H_INCLUDED -/// If defined, indicates that the source file is amalgated + +#ifndef JSON_AMALGAMATED_H_INCLUDED +# define JSON_AMALGAMATED_H_INCLUDED +/// If defined, indicates that the source file is amalgamated /// to prevent private header inclusion. #define JSON_IS_AMALGAMATION @@ -83,19 +82,25 @@ license you like. // Beginning of content of file: include/json/version.h // ////////////////////////////////////////////////////////////////////// -// DO NOT EDIT. This file is generated by CMake from "version" -// and "version.h.in" files. +// DO NOT EDIT. This file (and "version") is generated by CMake. // Run CMake configure step to update it. #ifndef JSON_VERSION_H_INCLUDED # define JSON_VERSION_H_INCLUDED -# define JSONCPP_VERSION_STRING "1.6.1" +# define JSONCPP_VERSION_STRING "1.8.4" # define JSONCPP_VERSION_MAJOR 1 -# define JSONCPP_VERSION_MINOR 6 -# define JSONCPP_VERSION_PATCH 1 +# define JSONCPP_VERSION_MINOR 8 +# define JSONCPP_VERSION_PATCH 4 # define JSONCPP_VERSION_QUALIFIER # define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) +#ifdef JSONCPP_USING_SECURE_MEMORY +#undef JSONCPP_USING_SECURE_MEMORY +#endif +#define JSONCPP_USING_SECURE_MEMORY 0 +// If non-zero, the library zeroes any memory that it has allocated before +// it frees its memory. + #endif // JSON_VERSION_H_INCLUDED // ////////////////////////////////////////////////////////////////////// @@ -111,13 +116,16 @@ license you like. // Beginning of content of file: include/json/config.h // ////////////////////////////////////////////////////////////////////// -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #ifndef JSON_CONFIG_H_INCLUDED #define JSON_CONFIG_H_INCLUDED +#include +#include //typedef String +#include //typedef int64_t, uint64_t /// If defined, indicates that json library is embedded in CppTL library. //# define JSON_IN_CPPTL 1 @@ -135,9 +143,9 @@ license you like. #define JSON_USE_EXCEPTION 1 #endif -/// If defined, indicates that the source file is amalgated +/// If defined, indicates that the source file is amalgamated /// to prevent private header inclusion. -/// Remarks: it is automatically defined in the generated amalgated header. +/// Remarks: it is automatically defined in the generated amalgamated header. // #define JSON_IS_AMALGAMATION #ifdef JSON_IN_CPPTL @@ -150,12 +158,12 @@ license you like. #ifdef JSON_IN_CPPTL #define JSON_API CPPTL_API #elif defined(JSON_DLL_BUILD) -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__MINGW32__) #define JSON_API __declspec(dllexport) #define JSONCPP_DISABLE_DLL_INTERFACE_WARNING #endif // if defined(_MSC_VER) #elif defined(JSON_DLL) -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__MINGW32__) #define JSON_API __declspec(dllimport) #define JSONCPP_DISABLE_DLL_INTERFACE_WARNING #endif // if defined(_MSC_VER) @@ -169,34 +177,96 @@ license you like. // Storages, and 64 bits integer support is disabled. // #define JSON_NO_INT64 1 -#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6 -// Microsoft Visual Studio 6 only support conversion from __int64 to double -// (no conversion from unsigned __int64). -#define JSON_USE_INT64_DOUBLE_CONVERSION 1 -// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' -// characters in the debug information) -// All projects I've ever seen with VS6 were using this globally (not bothering -// with pragma push/pop). -#pragma warning(disable : 4786) -#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6 +#if defined(_MSC_VER) // MSVC +# if _MSC_VER <= 1200 // MSVC 6 + // Microsoft Visual Studio 6 only support conversion from __int64 to double + // (no conversion from unsigned __int64). +# define JSON_USE_INT64_DOUBLE_CONVERSION 1 + // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' + // characters in the debug information) + // All projects I've ever seen with VS6 were using this globally (not bothering + // with pragma push/pop). +# pragma warning(disable : 4786) +# endif // MSVC 6 -#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 -/// Indicates that the following function is deprecated. -#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) -#elif defined(__clang__) && defined(__has_feature) -#if __has_feature(attribute_deprecated_with_message) -#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# if _MSC_VER >= 1500 // MSVC 2008 + /// Indicates that the following function is deprecated. +# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +# endif + +#endif // defined(_MSC_VER) + +// In c++11 the override keyword allows you to explicitly define that a function +// is intended to override the base-class version. This makes the code more +// managable and fixes a set of common hard-to-find bugs. +#if __cplusplus >= 201103L +# define JSONCPP_OVERRIDE override +# define JSONCPP_NOEXCEPT noexcept +#elif defined(_MSC_VER) && _MSC_VER > 1600 && _MSC_VER < 1900 +# define JSONCPP_OVERRIDE override +# define JSONCPP_NOEXCEPT throw() +#elif defined(_MSC_VER) && _MSC_VER >= 1900 +# define JSONCPP_OVERRIDE override +# define JSONCPP_NOEXCEPT noexcept +#else +# define JSONCPP_OVERRIDE +# define JSONCPP_NOEXCEPT throw() #endif -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) -#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) -#elif defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) -#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) + +#ifndef JSON_HAS_RVALUE_REFERENCES + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // MSVC >= 2010 + +#ifdef __clang__ +#if __has_feature(cxx_rvalue_references) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // has_feature + +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // GXX_EXPERIMENTAL + +#endif // __clang__ || __GNUC__ + +#endif // not defined JSON_HAS_RVALUE_REFERENCES + +#ifndef JSON_HAS_RVALUE_REFERENCES +#define JSON_HAS_RVALUE_REFERENCES 0 #endif +#ifdef __clang__ +# if __has_extension(attribute_deprecated_with_message) +# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# endif +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +# endif // GNUC version +#endif // __clang__ || __GNUC__ + #if !defined(JSONCPP_DEPRECATED) #define JSONCPP_DEPRECATED(message) #endif // if !defined(JSONCPP_DEPRECATED) +#if __GNUC__ >= 6 +# define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +# include "version.h" + +# if JSONCPP_USING_SECURE_MEMORY +# include "allocator.h" //typedef Allocator +# endif + +#endif // if !defined(JSON_IS_AMALGAMATION) + namespace Json { typedef int Int; typedef unsigned int UInt; @@ -210,13 +280,26 @@ typedef unsigned int LargestUInt; typedef __int64 Int64; typedef unsigned __int64 UInt64; #else // if defined(_MSC_VER) // Other platforms, use long long -typedef long long int Int64; -typedef unsigned long long int UInt64; +typedef int64_t Int64; +typedef uint64_t UInt64; #endif // if defined(_MSC_VER) typedef Int64 LargestInt; typedef UInt64 LargestUInt; #define JSON_HAS_INT64 #endif // if defined(JSON_NO_INT64) +#if JSONCPP_USING_SECURE_MEMORY +#define JSONCPP_STRING std::basic_string, Json::SecureAllocator > +#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream, Json::SecureAllocator > +#define JSONCPP_OSTREAM std::basic_ostream> +#define JSONCPP_ISTRINGSTREAM std::basic_istringstream, Json::SecureAllocator > +#define JSONCPP_ISTREAM std::istream +#else +#define JSONCPP_STRING std::string +#define JSONCPP_OSTRINGSTREAM std::ostringstream +#define JSONCPP_OSTREAM std::ostream +#define JSONCPP_ISTRINGSTREAM std::istringstream +#define JSONCPP_ISTREAM std::istream +#endif // if JSONCPP_USING_SECURE_MEMORY } // end namespace Json #endif // JSON_CONFIG_H_INCLUDED @@ -234,7 +317,7 @@ typedef UInt64 LargestUInt; // Beginning of content of file: include/json/forwards.h // ////////////////////////////////////////////////////////////////////// -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -285,7 +368,7 @@ class ValueConstIterator; // Beginning of content of file: include/json/features.h // ////////////////////////////////////////////////////////////////////// -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -297,6 +380,8 @@ class ValueConstIterator; #include "forwards.h" #endif // if !defined(JSON_IS_AMALGAMATION) +#pragma pack(push, 8) + namespace Json { /** \brief Configuration passed to reader and writer. @@ -341,6 +426,8 @@ public: } // namespace Json +#pragma pack(pop) + #endif // CPPTL_JSON_FEATURES_H_INCLUDED // ////////////////////////////////////////////////////////////////////// @@ -356,7 +443,7 @@ public: // Beginning of content of file: include/json/value.h // ////////////////////////////////////////////////////////////////////// -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -380,6 +467,19 @@ public: #include #endif +//Conditional NORETURN attribute on the throw functions would: +// a) suppress false positives from static code analysis +// b) possibly improve optimization opportunities. +#if !defined(JSONCPP_NORETURN) +# if defined(_MSC_VER) +# define JSONCPP_NORETURN __declspec(noreturn) +# elif defined(__GNUC__) +# define JSONCPP_NORETURN __attribute__ ((__noreturn__)) +# else +# define JSONCPP_NORETURN +# endif +#endif + // Disable warning C4251: : needs to have dll-interface to // be used by... #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) @@ -387,6 +487,8 @@ public: #pragma warning(disable : 4251) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma pack(push, 8) + /** \brief JSON (JavaScript Object Notation). */ namespace Json { @@ -395,26 +497,41 @@ namespace Json { * * We use nothing but these internally. Of course, STL can throw others. */ -class JSON_API Exception; +class JSON_API Exception : public std::exception { +public: + Exception(JSONCPP_STRING const& msg); + ~Exception() JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; + char const* what() const JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; +protected: + JSONCPP_STRING msg_; +}; + /** Exceptions which the user cannot easily avoid. * * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input - * + * * \remark derived from Json::Exception */ -class JSON_API RuntimeError; +class JSON_API RuntimeError : public Exception { +public: + RuntimeError(JSONCPP_STRING const& msg); +}; + /** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. * * These are precondition-violations (user bugs) and internal errors (our bugs). - * + * * \remark derived from Json::Exception */ -class JSON_API LogicError; +class JSON_API LogicError : public Exception { +public: + LogicError(JSONCPP_STRING const& msg); +}; /// used internally -void throwRuntimeError(std::string const& msg); +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg); /// used internally -void throwLogicError(std::string const& msg); +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg); /** \brief Type of the value held by a Value object. */ @@ -444,7 +561,7 @@ enum CommentPlacement { /** \brief Lightweight wrapper to tag static string. * - * Value constructor and objectValue member assignement takes advantage of the + * Value constructor and objectValue member assignment takes advantage of the * StaticString and avoid the cost of string duplication when storing the * string or the member name. * @@ -505,7 +622,7 @@ private: class JSON_API Value { friend class ValueIteratorBase; public: - typedef std::vector Members; + typedef std::vector Members; typedef ValueIterator iterator; typedef ValueConstIterator const_iterator; typedef Json::UInt UInt; @@ -518,8 +635,13 @@ public: typedef Json::LargestUInt LargestUInt; typedef Json::ArrayIndex ArrayIndex; + // Required for boost integration, e. g. BOOST_TEST + typedef std::string value_type; + static const Value& null; ///< We regret this reference to a global instance; prefer the simpler Value(). static const Value& nullRef; ///< just a kludge for binary-compatibility; same as null + static Value const& nullSingleton(); ///< Prefer this to null or nullRef. + /// Minimum signed integer value that can be stored in a Json::Value. static const LargestInt minLargestInt; /// Maximum signed integer value that can be stored in a Json::Value. @@ -555,8 +677,16 @@ private: CZString(ArrayIndex index); CZString(char const* str, unsigned length, DuplicationPolicy allocate); CZString(CZString const& other); +#if JSON_HAS_RVALUE_REFERENCES + CZString(CZString&& other); +#endif ~CZString(); - CZString& operator=(CZString other); + CZString& operator=(const CZString& other); + +#if JSON_HAS_RVALUE_REFERENCES + CZString& operator=(CZString&& other); +#endif + bool operator<(CZString const& other) const; bool operator==(CZString const& other) const; ArrayIndex index() const; @@ -569,7 +699,7 @@ private: void swap(CZString& other); struct StringStorage { - DuplicationPolicy policy_: 2; + unsigned policy_: 2; unsigned length_: 30; // 1GB max }; @@ -613,7 +743,7 @@ Json::Value obj_value(Json::objectValue); // {} #endif // if defined(JSON_HAS_INT64) Value(double value); Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) - Value(const char* beginValue, const char* endValue); ///< Copy all, incl zeroes. + Value(const char* begin, const char* end); ///< Copy all, incl zeroes. /** \brief Constructs a value from a static string. * Like other value string constructor but do not duplicate the string for @@ -630,23 +760,33 @@ Json::Value obj_value(Json::objectValue); // {} * \endcode */ Value(const StaticString& value); - Value(const std::string& value); ///< Copy data() til size(). Embedded zeroes too. + Value(const JSONCPP_STRING& value); ///< Copy data() til size(). Embedded zeroes too. #ifdef JSON_USE_CPPTL Value(const CppTL::ConstString& value); #endif Value(bool value); /// Deep copy. Value(const Value& other); +#if JSON_HAS_RVALUE_REFERENCES + /// Move constructor + Value(Value&& other); +#endif ~Value(); /// Deep copy, then swap(other). /// \note Over-write existing comments. To preserve comments, use #swapPayload(). Value& operator=(Value other); + /// Swap everything. void swap(Value& other); /// Swap values but leave comments and source offsets in place. void swapPayload(Value& other); + /// copy everything. + void copy(const Value& other); + /// copy values but leave comments and source offsets in place. + void copyPayload(const Value& other); + ValueType type() const; /// Compare payload only, not comments etc. @@ -659,12 +799,15 @@ Json::Value obj_value(Json::objectValue); // {} int compare(const Value& other) const; const char* asCString() const; ///< Embedded zeroes could cause you trouble! - std::string asString() const; ///< Embedded zeroes are possible. +#if JSONCPP_USING_SECURE_MEMORY + unsigned getCStringLength() const; //Allows you to understand the length of the CString +#endif + JSONCPP_STRING asString() const; ///< Embedded zeroes are possible. /** Get raw char* of string-value. * \return false if !string. (Seg-fault if str or end are NULL.) */ bool getString( - char const** str, char const** end) const; + char const** begin, char const** end) const; #ifdef JSON_USE_CPPTL CppTL::ConstString asConstString() const; #endif @@ -702,8 +845,8 @@ Json::Value obj_value(Json::objectValue); // {} /// otherwise, false. bool empty() const; - /// Return isNull() - bool operator!() const; + /// Return !isNull() + explicit operator bool() const; /// Remove all object members and array elements. /// \pre type() is arrayValue, objectValue, or nullValue @@ -754,6 +897,10 @@ Json::Value obj_value(Json::objectValue); // {} /// Equivalent to jsonvalue[jsonvalue.size()] = value; Value& append(const Value& value); +#if JSON_HAS_RVALUE_REFERENCES + Value& append(Value&& value); +#endif + /// Access an object value by name, create a null member if it does not exist. /// \note Because of our implementation, keys are limited to 2^30 -1 chars. /// Exceeding that will cause an exception. @@ -763,11 +910,11 @@ Json::Value obj_value(Json::objectValue); // {} const Value& operator[](const char* key) const; /// Access an object value by name, create a null member if it does not exist. /// \param key may contain embedded nulls. - Value& operator[](const std::string& key); + Value& operator[](const JSONCPP_STRING& key); /// Access an object value by name, returns null if there is no member with /// that name. /// \param key may contain embedded nulls. - const Value& operator[](const std::string& key) const; + const Value& operator[](const JSONCPP_STRING& key) const; /** \brief Access an object value by name, create a null member if it does not exist. @@ -793,12 +940,12 @@ Json::Value obj_value(Json::objectValue); // {} Value get(const char* key, const Value& defaultValue) const; /// Return the member named key if it exist, defaultValue otherwise. /// \note deep copy - /// \param key may contain embedded nulls. - Value get(const char* key, const char* end, const Value& defaultValue) const; + /// \note key may contain embedded nulls. + Value get(const char* begin, const char* end, const Value& defaultValue) const; /// Return the member named key if it exist, defaultValue otherwise. /// \note deep copy /// \param key may contain embedded nulls. - Value get(const std::string& key, const Value& defaultValue) const; + Value get(const JSONCPP_STRING& key, const Value& defaultValue) const; #ifdef JSON_USE_CPPTL /// Return the member named key if it exist, defaultValue otherwise. /// \note deep copy @@ -806,12 +953,12 @@ Json::Value obj_value(Json::objectValue); // {} #endif /// Most general and efficient version of isMember()const, get()const, /// and operator[]const - /// \note As stated elsewhere, behavior is undefined if (end-key) >= 2^30 - Value const* find(char const* key, char const* end) const; + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + Value const* find(char const* begin, char const* end) const; /// Most general and efficient version of object-mutators. - /// \note As stated elsewhere, behavior is undefined if (end-key) >= 2^30 + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. - Value const* demand(char const* key, char const* end); + Value const* demand(char const* begin, char const* end); /// \brief Remove and return the named member. /// /// Do nothing if it did not exist. @@ -819,12 +966,12 @@ Json::Value obj_value(Json::objectValue); // {} /// \pre type() is objectValue or nullValue /// \post type() is unchanged /// \deprecated - Value removeMember(const char* key); + void removeMember(const char* key); /// Same as removeMember(const char*) /// \param key may contain embedded nulls. /// \deprecated - Value removeMember(const std::string& key); - /// Same as removeMember(const char* key, const char* end, Value* removed), + void removeMember(const JSONCPP_STRING& key); + /// Same as removeMember(const char* begin, const char* end, Value* removed), /// but 'key' is null-terminated. bool removeMember(const char* key, Value* removed); /** \brief Remove the named map member. @@ -833,9 +980,9 @@ Json::Value obj_value(Json::objectValue); // {} \param key may contain embedded nulls. \return true iff removed (no exceptions) */ - bool removeMember(std::string const& key, Value* removed); - /// Same as removeMember(std::string const& key, Value* removed) - bool removeMember(const char* key, const char* end, Value* removed); + bool removeMember(JSONCPP_STRING const& key, Value* removed); + /// Same as removeMember(JSONCPP_STRING const& key, Value* removed) + bool removeMember(const char* begin, const char* end, Value* removed); /** \brief Remove the indexed array element. O(n) expensive operations. @@ -849,9 +996,9 @@ Json::Value obj_value(Json::objectValue); // {} bool isMember(const char* key) const; /// Return true if the object has a member named key. /// \param key may contain embedded nulls. - bool isMember(const std::string& key) const; - /// Same as isMember(std::string const& key)const - bool isMember(const char* key, const char* end) const; + bool isMember(const JSONCPP_STRING& key) const; + /// Same as isMember(JSONCPP_STRING const& key)const + bool isMember(const char* begin, const char* end) const; #ifdef JSON_USE_CPPTL /// Return true if the object has a member named key. bool isMember(const CppTL::ConstString& key) const; @@ -870,16 +1017,17 @@ Json::Value obj_value(Json::objectValue); // {} //# endif /// \deprecated Always pass len. + JSONCPP_DEPRECATED("Use setComment(JSONCPP_STRING const&) instead.") void setComment(const char* comment, CommentPlacement placement); /// Comments must be //... or /* ... */ void setComment(const char* comment, size_t len, CommentPlacement placement); /// Comments must be //... or /* ... */ - void setComment(const std::string& comment, CommentPlacement placement); + void setComment(const JSONCPP_STRING& comment, CommentPlacement placement); bool hasComment(CommentPlacement placement) const; /// Include delimiters and embedded newlines. - std::string getComment(CommentPlacement placement) const; + JSONCPP_STRING getComment(CommentPlacement placement) const; - std::string toStyledString() const; + JSONCPP_STRING toStyledString() const; const_iterator begin() const; const_iterator end() const; @@ -889,10 +1037,10 @@ Json::Value obj_value(Json::objectValue); // {} // Accessors for the [start, limit) range of bytes within the JSON text from // which this value was parsed, if any. - void setOffsetStart(size_t start); - void setOffsetLimit(size_t limit); - size_t getOffsetStart() const; - size_t getOffsetLimit() const; + void setOffsetStart(ptrdiff_t start); + void setOffsetLimit(ptrdiff_t limit); + ptrdiff_t getOffsetStart() const; + ptrdiff_t getOffsetLimit() const; private: void initBasic(ValueType type, bool allocated = false); @@ -933,8 +1081,8 @@ private: // [start, limit) byte offsets in the source JSON text from which this Value // was extracted. - size_t start_; - size_t limit_; + ptrdiff_t start_; + ptrdiff_t limit_; }; /** \brief Experimental and untested: represents an element of the "path" to @@ -947,7 +1095,7 @@ public: PathArgument(); PathArgument(ArrayIndex index); PathArgument(const char* key); - PathArgument(const std::string& key); + PathArgument(const JSONCPP_STRING& key); private: enum Kind { @@ -955,7 +1103,7 @@ private: kindIndex, kindKey }; - std::string key_; + JSONCPP_STRING key_; ArrayIndex index_; Kind kind_; }; @@ -973,7 +1121,7 @@ private: */ class JSON_API Path { public: - Path(const std::string& path, + Path(const JSONCPP_STRING& path, const PathArgument& a1 = PathArgument(), const PathArgument& a2 = PathArgument(), const PathArgument& a3 = PathArgument(), @@ -990,12 +1138,12 @@ private: typedef std::vector InArgs; typedef std::vector Args; - void makePath(const std::string& path, const InArgs& in); - void addPathInArg(const std::string& path, + void makePath(const JSONCPP_STRING& path, const InArgs& in); + void addPathInArg(const JSONCPP_STRING& path, const InArgs& in, InArgs::const_iterator& itInArg, PathArgument::Kind kind); - void invalidPath(const std::string& path, int location); + void invalidPath(const JSONCPP_STRING& path, int location); Args args_; }; @@ -1010,9 +1158,6 @@ public: typedef int difference_type; typedef ValueIteratorBase SelfType; - ValueIteratorBase(); - explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); - bool operator==(const SelfType& other) const { return isEqual(other); } bool operator!=(const SelfType& other) const { return !isEqual(other); } @@ -1031,7 +1176,7 @@ public: /// Return the member name of the referenced Value, or "" if it is not an /// objectValue. /// \note Avoid `c_str()` on result, as embedded zeroes are possible. - std::string name() const; + JSONCPP_STRING name() const; /// Return the member name of the referenced Value. "" if it is not an /// objectValue. @@ -1060,6 +1205,12 @@ private: Value::ObjectValues::iterator current_; // Indicates that iterator is for a null value. bool isNull_; + +public: + // For some reason, BORLAND needs these at the end, rather + // than earlier. No idea why. + ValueIteratorBase(); + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); }; /** \brief const iterator for object and array value. @@ -1077,6 +1228,7 @@ public: typedef ValueConstIterator SelfType; ValueConstIterator(); + ValueConstIterator(ValueIterator const& other); private: /*! \internal Use by Value to create an iterator. @@ -1126,7 +1278,7 @@ public: typedef ValueIterator SelfType; ValueIterator(); - ValueIterator(const ValueConstIterator& other); + explicit ValueIterator(const ValueConstIterator& other); ValueIterator(const ValueIterator& other); private: @@ -1172,6 +1324,7 @@ template<> inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); } } +#pragma pack(pop) #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #pragma warning(pop) @@ -1192,7 +1345,7 @@ inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); } // Beginning of content of file: include/json/reader.h // ////////////////////////////////////////////////////////////////////// -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -1217,6 +1370,8 @@ inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); } #pragma warning(disable : 4251) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma pack(push, 8) + namespace Json { /** \brief Unserialize a JSON document into a @@ -1236,9 +1391,9 @@ public: * */ struct StructuredError { - size_t offset_start; - size_t offset_limit; - std::string message; + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; }; /** \brief Constructs a Reader allowing all features @@ -1293,7 +1448,7 @@ public: /// \brief Parse from input stream. /// \see Json::operator>>(std::istream&, Json::Value&). - bool parse(std::istream& is, Value& root, bool collectComments = true); + bool parse(JSONCPP_ISTREAM& is, Value& root, bool collectComments = true); /** \brief Returns a user friendly string that list errors in the parsed * document. @@ -1305,7 +1460,7 @@ public: * \deprecated Use getFormattedErrorMessages() instead (typo fix). */ JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") - std::string getFormatedErrorMessages() const; + JSONCPP_STRING getFormatedErrorMessages() const; /** \brief Returns a user friendly string that list errors in the parsed * document. @@ -1315,7 +1470,7 @@ public: * occurred * during parsing. */ - std::string getFormattedErrorMessages() const; + JSONCPP_STRING getFormattedErrorMessages() const; /** \brief Returns a vector of structured erros encounted while parsing. * \return A (possibly empty) vector of StructuredError objects. Currently @@ -1332,7 +1487,7 @@ public: * \return \c true if the error was successfully added, \c false if the * Value offset exceeds the document size. */ - bool pushError(const Value& value, const std::string& message); + bool pushError(const Value& value, const JSONCPP_STRING& message); /** \brief Add a semantic error message with extra context. * \param value JSON Value location associated with the error @@ -1341,7 +1496,7 @@ public: * \return \c true if the error was successfully added, \c false if either * Value offset exceeds the document size. */ - bool pushError(const Value& value, const std::string& message, const Value& extra); + bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); /** \brief Return whether there are any errors. * \return \c true if there are no errors to report \c false if @@ -1377,7 +1532,7 @@ private: class ErrorInfo { public: Token token_; - std::string message_; + JSONCPP_STRING message_; Location extra_; }; @@ -1397,7 +1552,7 @@ private: 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, @@ -1408,9 +1563,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(); @@ -1418,20 +1573,23 @@ 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); + static bool containsNewLine(Location begin, Location end); + static JSONCPP_STRING normalizeEOL(Location begin, Location end); + typedef std::stack Nodes; Nodes nodes_; Errors errors_; - std::string document_; + JSONCPP_STRING document_; Location begin_; Location end_; Location current_; Location lastValueEnd_; Value* lastValue_; - std::string commentsBefore_; + JSONCPP_STRING commentsBefore_; Features features_; bool collectComments_; }; // Reader @@ -1460,9 +1618,9 @@ public: */ virtual bool parse( char const* beginDoc, char const* endDoc, - Value* root, std::string* errs) = 0; + Value* root, JSONCPP_STRING* errs) = 0; - class Factory { + class JSON_API Factory { public: virtual ~Factory() {} /** \brief Allocate a CharReader via operator new(). @@ -1480,7 +1638,7 @@ Usage: CharReaderBuilder builder; builder["collectComments"] = false; Value value; - std::string errs; + JSONCPP_STRING errs; bool ok = parseFromStream(builder, std::cin, &value, &errs); \endcode */ @@ -1515,6 +1673,9 @@ public: the JSON value in the input string. - `"rejectDupKeys": false or true` - If true, `parse()` returns false when a key is duplicated within an object. + - `"allowSpecialFloats": false or true` + - If true, special float values (NaNs and infinities) are allowed + and their values are lossfree restorable. You can examine 'settings_` yourself to see the defaults. You can also write and read them just like any @@ -1524,9 +1685,9 @@ public: Json::Value settings_; CharReaderBuilder(); - virtual ~CharReaderBuilder(); + ~CharReaderBuilder() JSONCPP_OVERRIDE; - virtual CharReader* newCharReader() const; + CharReader* newCharReader() const JSONCPP_OVERRIDE; /** \return true if 'settings' are legal and consistent; * otherwise, indicate bad settings via 'invalid'. @@ -1535,18 +1696,18 @@ public: /** A simple way to update a specific setting. */ - Value& operator[](std::string key); + Value& operator[](JSONCPP_STRING key); /** Called by ctor, but you can use this to reset settings_. * \pre 'settings' != NULL (but Json::null is fine) * \remark Defaults: - * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults */ static void setDefaults(Json::Value* settings); /** Same as old Features::strictMode(). * \pre 'settings' != NULL (but Json::null is fine) * \remark Defaults: - * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode */ static void strictMode(Json::Value* settings); }; @@ -1557,7 +1718,7 @@ public: */ bool JSON_API parseFromStream( CharReader::Factory const&, - std::istream&, + JSONCPP_ISTREAM&, Value* root, std::string* errs); /** \brief Read from 'sin' into 'root'. @@ -1584,10 +1745,12 @@ bool JSON_API parseFromStream( \throw std::exception on parse error. \see Json::operator<<() */ -JSON_API std::istream& operator>>(std::istream&, Value&); +JSON_API JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM&, Value&); } // namespace Json +#pragma pack(pop) + #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #pragma warning(pop) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) @@ -1607,7 +1770,7 @@ JSON_API std::istream& operator>>(std::istream&, Value&); // Beginning of content of file: include/json/writer.h // ////////////////////////////////////////////////////////////////////// -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -1624,11 +1787,13 @@ JSON_API std::istream& operator>>(std::istream&, Value&); // Disable warning C4251: : needs to have dll-interface to // be used by... -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) && defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4251) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma pack(push, 8) + namespace Json { class Value; @@ -1648,7 +1813,7 @@ Usage: */ class JSON_API StreamWriter { protected: - std::ostream* sout_; // not owned; will not delete + JSONCPP_OSTREAM* sout_; // not owned; will not delete public: StreamWriter(); virtual ~StreamWriter(); @@ -1658,7 +1823,7 @@ public: \return zero on success (For now, we always return zero, so check the stream instead.) \throw std::exception possibly, depending on configuration */ - virtual int write(Value const& root, std::ostream* sout) = 0; + virtual int write(Value const& root, JSONCPP_OSTREAM* sout) = 0; /** \brief A simple abstract factory. */ @@ -1675,7 +1840,7 @@ public: /** \brief Write into stringstream, then return string, for convenience. * A StreamWriter will be created from the factory, used, and then deleted. */ -std::string JSON_API writeString(StreamWriter::Factory const& factory, Value const& root); +JSONCPP_STRING JSON_API writeString(StreamWriter::Factory const& factory, Value const& root); /** \brief Build a StreamWriter implementation. @@ -1706,8 +1871,12 @@ public: - "dropNullPlaceholders": false or true - Drop the "null" string from the writer's output for nullValues. Strictly speaking, this is not valid JSON. But when the output is being - fed to a browser's Javascript, it makes for smaller output and the + fed to a browser's JavaScript, it makes for smaller output and the browser can handle the output just fine. + - "useSpecialFloats": false or true + - If true, outputs non-finite floating point values in the following way: + NaN values as "NaN", positive infinity as "Infinity", and negative infinity + as "-Infinity". You can examine 'settings_` yourself to see the defaults. You can also write and read them just like any @@ -1717,12 +1886,12 @@ public: Json::Value settings_; StreamWriterBuilder(); - virtual ~StreamWriterBuilder(); + ~StreamWriterBuilder() JSONCPP_OVERRIDE; /** * \throw std::exception if something goes wrong (e.g. invalid settings) */ - virtual StreamWriter* newStreamWriter() const; + StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE; /** \return true if 'settings' are legal and consistent; * otherwise, indicate bad settings via 'invalid'. @@ -1730,7 +1899,7 @@ public: bool validate(Json::Value* invalid) const; /** A simple way to update a specific setting. */ - Value& operator[](std::string key); + Value& operator[](JSONCPP_STRING key); /** Called by ctor, but you can use this to reset settings_. * \pre 'settings' != NULL (but Json::null is fine) @@ -1743,11 +1912,11 @@ public: /** \brief Abstract class for writers. * \deprecated Use StreamWriter. (And really, this is an implementation detail.) */ -class JSON_API Writer { +class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer { public: virtual ~Writer(); - virtual std::string write(const Value& root) = 0; + virtual JSONCPP_STRING write(const Value& root) = 0; }; /** \brief Outputs a Value in JSON format @@ -1759,17 +1928,20 @@ public: * \sa Reader, Value * \deprecated Use StreamWriterBuilder. */ -class JSON_API FastWriter : public Writer { - +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4996) // Deriving from deprecated class +#endif +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter : public Writer { public: FastWriter(); - virtual ~FastWriter() {} + ~FastWriter() JSONCPP_OVERRIDE {} void enableYAMLCompatibility(); /** \brief Drop the "null" string from the writer's output for nullValues. * Strictly speaking, this is not valid JSON. But when the output is being - * fed to a browser's Javascript, it makes for smaller output and the + * fed to a browser's JavaScript, it makes for smaller output and the * browser can handle the output just fine. */ void dropNullPlaceholders(); @@ -1777,16 +1949,19 @@ public: void omitEndingLineFeed(); public: // overridden from Writer - virtual std::string write(const Value& root); + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; private: void writeValue(const Value& value); - std::string document_; - bool yamlCompatiblityEnabled_; + JSONCPP_STRING document_; + bool yamlCompatibilityEnabled_; bool dropNullPlaceholders_; bool omitEndingLineFeed_; }; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif /** \brief Writes a Value in JSON format in a *human friendly way. @@ -1812,41 +1987,48 @@ private: * \sa Reader, Value, Value::setComment() * \deprecated Use StreamWriterBuilder. */ -class JSON_API StyledWriter : public Writer { +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4996) // Deriving from deprecated class +#endif +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API StyledWriter : public Writer { public: StyledWriter(); - virtual ~StyledWriter() {} + ~StyledWriter() JSONCPP_OVERRIDE {} public: // overridden from Writer /** \brief Serialize a Value in JSON format. * \param root Value to serialize. * \return String containing the JSON document that represents the root value. */ - virtual std::string write(const Value& root); + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; private: void writeValue(const Value& value); void writeArrayValue(const Value& value); - bool isMultineArray(const Value& value); - void pushValue(const std::string& value); + bool isMultilineArray(const Value& value); + void pushValue(const JSONCPP_STRING& value); void writeIndent(); - void writeWithIndent(const std::string& value); + void writeWithIndent(const JSONCPP_STRING& value); void indent(); void unindent(); void writeCommentBeforeValue(const Value& root); void writeCommentAfterValueOnSameLine(const Value& root); bool hasCommentForValue(const Value& value); - static std::string normalizeEOL(const std::string& text); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); - typedef std::vector ChildValues; + typedef std::vector ChildValues; ChildValues childValues_; - std::string document_; - std::string indentString_; - int rightMargin_; - int indentSize_; + JSONCPP_STRING document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + unsigned int indentSize_; bool addChildValues_; }; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif /** \brief Writes a Value in JSON format in a human friendly way, @@ -1870,13 +2052,19 @@ private: * If the Value have comments then they are outputed according to their #CommentPlacement. * - * \param indentation Each level will be indented by this amount extra. * \sa Reader, Value, Value::setComment() * \deprecated Use StreamWriterBuilder. */ -class JSON_API StyledStreamWriter { +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4996) // Deriving from deprecated class +#endif +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API StyledStreamWriter { public: - StyledStreamWriter(std::string indentation = "\t"); +/** + * \param indentation Each level will be indented by this amount extra. + */ + StyledStreamWriter(JSONCPP_STRING indentation = "\t"); ~StyledStreamWriter() {} public: @@ -1886,49 +2074,54 @@ public: * \note There is no point in deriving from Writer, since write() should not * return a value. */ - void write(std::ostream& out, const Value& root); + void write(JSONCPP_OSTREAM& out, const Value& root); private: void writeValue(const Value& value); void writeArrayValue(const Value& value); - bool isMultineArray(const Value& value); - void pushValue(const std::string& value); + bool isMultilineArray(const Value& value); + void pushValue(const JSONCPP_STRING& value); void writeIndent(); - void writeWithIndent(const std::string& value); + void writeWithIndent(const JSONCPP_STRING& value); void indent(); void unindent(); void writeCommentBeforeValue(const Value& root); void writeCommentAfterValueOnSameLine(const Value& root); bool hasCommentForValue(const Value& value); - static std::string normalizeEOL(const std::string& text); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); - typedef std::vector ChildValues; + typedef std::vector ChildValues; ChildValues childValues_; - std::ostream* document_; - std::string indentString_; - int rightMargin_; - std::string indentation_; + JSONCPP_OSTREAM* document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; bool addChildValues_ : 1; bool indented_ : 1; }; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif #if defined(JSON_HAS_INT64) -std::string JSON_API valueToString(Int value); -std::string JSON_API valueToString(UInt value); +JSONCPP_STRING JSON_API valueToString(Int value); +JSONCPP_STRING JSON_API valueToString(UInt value); #endif // if defined(JSON_HAS_INT64) -std::string JSON_API valueToString(LargestInt value); -std::string JSON_API valueToString(LargestUInt value); -std::string JSON_API valueToString(double value); -std::string JSON_API valueToString(bool value); -std::string JSON_API valueToQuotedString(const char* value); +JSONCPP_STRING JSON_API valueToString(LargestInt value); +JSONCPP_STRING JSON_API valueToString(LargestUInt value); +JSONCPP_STRING JSON_API valueToString(double value); +JSONCPP_STRING JSON_API valueToString(bool value); +JSONCPP_STRING JSON_API valueToQuotedString(const char* value); /// \brief Output using the StyledStreamWriter. /// \see Json::operator>>() -JSON_API std::ostream& operator<<(std::ostream&, const Value& root); +JSON_API JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM&, const Value& root); } // namespace Json +#pragma pack(pop) + #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #pragma warning(pop) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) @@ -1948,7 +2141,7 @@ JSON_API std::ostream& operator<<(std::ostream&, const Value& root); // Beginning of content of file: include/json/assertions.h // ////////////////////////////////////////////////////////////////////// -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -1975,7 +2168,7 @@ JSON_API std::ostream& operator<<(std::ostream&, const Value& root); # define JSON_FAIL_MESSAGE(message) \ { \ - std::ostringstream oss; oss << message; \ + JSONCPP_OSTRINGSTREAM oss; oss << message; \ Json::throwLogicError(oss.str()); \ abort(); \ } @@ -1988,7 +2181,7 @@ JSON_API std::ostream& operator<<(std::ostream&, const Value& root); // release builds we abort, for a core-dump or debugger. # define JSON_FAIL_MESSAGE(message) \ { \ - std::ostringstream oss; oss << message; \ + JSONCPP_OSTRINGSTREAM oss; oss << message; \ assert(false && oss.str().c_str()); \ abort(); \ } @@ -2011,4 +2204,4 @@ JSON_API std::ostream& operator<<(std::ostream&, const Value& root); -#endif //ifndef JSON_AMALGATED_H_INCLUDED +#endif //ifndef JSON_AMALGAMATED_H_INCLUDED diff --git a/include/jsoncpp.cpp b/include/jsoncpp.cpp index 38a4863..507a1c6 100644 --- a/include/jsoncpp.cpp +++ b/include/jsoncpp.cpp @@ -1,4 +1,4 @@ -/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). +/// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/). /// It is intended to be used with #include "json/json.h" // ////////////////////////////////////////////////////////////////////// @@ -10,13 +10,13 @@ The JsonCpp library's source code, including accompanying documentation, tests and demonstration applications, are licensed under the following conditions... -The author (Baptiste Lepilleur) explicitly disclaims copyright in all +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all jurisdictions which recognize such a disclaimer. In such jurisdictions, this software is released into the Public Domain. In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is -released under the terms of the MIT License (see below). +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). In jurisdictions which recognize Public Domain property, the user of this software may choose to accept it either as 1) Public Domain, 2) under the @@ -31,7 +31,7 @@ described in clear, concise terms at: The full text of the MIT License follows: ======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation @@ -73,7 +73,7 @@ license you like. -#include +#include "json/json.h" #ifndef JSON_IS_AMALGAMATION #error "Compile with -I PATH_TO_JSON_DIRECTORY" @@ -84,7 +84,7 @@ license you like. // Beginning of content of file: src/lib_json/json_tool.h // ////////////////////////////////////////////////////////////////////// -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -92,6 +92,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 +#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(0x80 | (0x3f & cp)); - result[1] = 0x80 | static_cast((0x3f & (cp >> 6))); - result[0] = 0xE0 | static_cast((0xf & (cp >> 12))); + result[1] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[0] = static_cast(0xE0 | (0xf & (cp >> 12))); } else if (cp <= 0x10FFFF) { result.resize(4); result[3] = static_cast(0x80 | (0x3f & cp)); @@ -129,9 +147,6 @@ static inline std::string codePointToUTF8(unsigned int cp) { return result; } -/// Returns true if ch is a control character (in range [0,32[). -static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; } - enum { /// Constant that specify the size of the buffer that must be passed to /// uintToString. @@ -142,14 +157,14 @@ enum { typedef char UIntToStringBuffer[uintToStringBufferSize]; /** Converts an unsigned integer to string. - * @param value Unsigned interger to convert to string + * @param value Unsigned integer to convert to string * @param current Input/Output string buffer. * Must have at least uintToStringBufferSize chars free. */ static inline void uintToString(LargestUInt value, char*& current) { *--current = 0; do { - *--current = char(value % 10) + '0'; + *--current = static_cast(value % 10U + static_cast('0')); value /= 10; } while (value != 0); } @@ -168,6 +183,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 @@ -185,7 +212,8 @@ static inline void fixNumericLocale(char* begin, char* end) { // Beginning of content of file: src/lib_json/json_reader.cpp // ////////////////////////////////////////////////////////////////////// -// Copyright 2007-2011 Baptiste Lepilleur +// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors +// Copyright (C) 2016 InfoTeCS JSC. All rights reserved. // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -204,24 +232,47 @@ static inline void fixNumericLocale(char* begin, char* end) { #include #include #include +#include -#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 || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr CharReaderPtr; +#else typedef std::auto_ptr CharReaderPtr; - +#endif // Implementation of class Features // //////////////////////////////// @@ -244,7 +295,7 @@ Features Features::strictMode() { // Implementation of class Reader // //////////////////////////////// -static bool containsNewLine(Reader::Location begin, Reader::Location end) { +bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) { for (; begin < end; ++begin) if (*begin == '\n' || *begin == '\r') return true; @@ -266,7 +317,7 @@ Reader::Reader(const Features& features) bool Reader::parse(const std::string& document, Value& root, bool collectComments) { - document_ = document; + document_.assign(document.begin(), document.end()); const char* begin = document_.c_str(); const char* end = begin + document_.length(); return parse(begin, end, root, collectComments); @@ -278,11 +329,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, @@ -299,13 +350,12 @@ bool Reader::parse(const char* beginDoc, current_ = begin_; lastValueEnd_ = 0; lastValue_ = 0; - commentsBefore_ = ""; + commentsBefore_.clear(); errors_.clear(); while (!nodes_.empty()) nodes_.pop(); nodes_.push(&root); - stackDepth_g = 0; // Yes, this is bad coding, but options are limited. bool successful = readValue(); Token token; skipCommentTokens(token); @@ -328,12 +378,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); @@ -341,7 +389,7 @@ bool Reader::readValue() { if (collectComments_ && !commentsBefore_.empty()) { currentValue().setComment(commentsBefore_, commentBefore); - commentsBefore_ = ""; + commentsBefore_.clear(); } switch (token.type_) { @@ -407,7 +455,6 @@ bool Reader::readValue() { lastValue_ = ¤tValue(); } - --stackDepth_g; return successful; } @@ -536,9 +583,9 @@ bool Reader::readComment() { return true; } -static std::string normalizeEOL(Reader::Location begin, Reader::Location end) { - std::string normalized; - normalized.reserve(end - begin); +JSONCPP_STRING Reader::normalizeEOL(Reader::Location begin, Reader::Location end) { + JSONCPP_STRING normalized; + normalized.reserve(static_cast(end - begin)); Reader::Location current = begin; while (current != end) { char c = *current++; @@ -558,7 +605,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); @@ -568,7 +615,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; @@ -597,25 +644,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 == '\\') @@ -628,7 +675,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_); @@ -640,7 +687,7 @@ bool Reader::readObject(Token& tokenStart) { break; if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object return true; - name = ""; + name.clear(); if (tokenName.type_ == tokenString) { if (!decodeString(tokenName, name)) return recoverFromError(tokenObjectEnd); @@ -648,7 +695,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; } @@ -687,7 +734,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); @@ -740,7 +787,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; @@ -748,7 +795,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(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 @@ -761,7 +808,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); @@ -782,34 +831,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; @@ -817,7 +842,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); @@ -827,8 +852,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(token.end_ - token.start_ - 2)); Location current = token.start_ + 1; // skip '"' Location end = token.end_ - 1; // do not include '"' while (current != end) { @@ -912,13 +937,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; @@ -934,11 +959,12 @@ bool Reader::decodeUnicodeEscapeSequence(Token& token, token, current); } + ret_unicode = static_cast(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; @@ -948,7 +974,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)) @@ -960,7 +986,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); @@ -998,29 +1024,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) { @@ -1050,8 +1068,8 @@ std::vector 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; @@ -1067,8 +1085,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) @@ -1093,7 +1111,6 @@ bool Reader::good() const { class OurFeatures { public: static OurFeatures all(); - OurFeatures(); bool allowComments_; bool strictRoot_; bool allowDroppedNullPlaceholders_; @@ -1101,20 +1118,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 @@ -1126,9 +1136,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); @@ -1136,10 +1146,10 @@ public: const char* endDoc, Value& root, bool collectComments = true); - std::string getFormattedErrorMessages() const; + JSONCPP_STRING getFormattedErrorMessages() const; std::vector 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: @@ -1157,6 +1167,9 @@ private: tokenTrue, tokenFalse, tokenNull, + tokenNaN, + tokenPosInf, + tokenNegInf, tokenArraySeparator, tokenMemberSeparator, tokenComment, @@ -1173,7 +1186,7 @@ private: class ErrorInfo { public: Token token_; - std::string message_; + JSONCPP_STRING message_; Location extra_; }; @@ -1187,14 +1200,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, @@ -1205,9 +1218,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(); @@ -1215,21 +1228,23 @@ 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); + static JSONCPP_STRING normalizeEOL(Location begin, Location end); + static bool containsNewLine(Location begin, Location end); + typedef std::stack 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_; @@ -1237,9 +1252,17 @@ private: // complete copy of Read impl, for OurReader +bool OurReader::containsNewLine(OurReader::Location begin, OurReader::Location end) { + for (; begin < end; ++begin) + if (*begin == '\n' || *begin == '\r') + return true; + return false; +} + OurReader::OurReader(OurFeatures const& features) : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), - lastValue_(), commentsBefore_(), features_(features), collectComments_() { + lastValue_(), commentsBefore_(), + features_(features), collectComments_() { } bool OurReader::parse(const char* beginDoc, @@ -1256,18 +1279,17 @@ bool OurReader::parse(const char* beginDoc, current_ = begin_; lastValueEnd_ = 0; lastValue_ = 0; - commentsBefore_ = ""; + commentsBefore_.clear(); errors_.clear(); while (!nodes_.empty()) 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; } @@ -1291,15 +1313,15 @@ 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(nodes_.size()) > features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); Token token; skipCommentTokens(token); bool successful = true; if (collectComments_ && !commentsBefore_.empty()) { currentValue().setComment(commentsBefore_, commentBefore); - commentsBefore_ = ""; + commentsBefore_.clear(); } switch (token.type_) { @@ -1341,6 +1363,30 @@ bool OurReader::readValue() { currentValue().setOffsetLimit(token.end_ - begin_); } break; + case tokenNaN: + { + Value v(std::numeric_limits::quiet_NaN()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenPosInf: + { + Value v(std::numeric_limits::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNegInf: + { + Value v(-std::numeric_limits::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; case tokenArraySeparator: case tokenObjectEnd: case tokenArrayEnd: @@ -1365,7 +1411,6 @@ bool OurReader::readValue() { lastValue_ = ¤tValue(); } - --stackDepth_; return successful; } @@ -1406,7 +1451,7 @@ bool OurReader::readToken(Token& token) { token.type_ = tokenString; ok = readStringSingleQuote(); break; - } // else continue + } // else fall through case '/': token.type_ = tokenComment; ok = readComment(); @@ -1421,9 +1466,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; @@ -1437,6 +1489,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; @@ -1500,10 +1568,29 @@ bool OurReader::readComment() { return true; } +JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin, OurReader::Location end) { + JSONCPP_STRING normalized; + normalized.reserve(static_cast(end - begin)); + OurReader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + void OurReader::addComment(Location begin, Location end, CommentPlacement placement) { assert(collectComments_); - const std::string& normalized = normalizeEOL(begin, end); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); if (placement == commentAfterOnSameLine) { assert(lastValue_ != 0); lastValue_->setComment(normalized, placement); @@ -1513,7 +1600,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; @@ -1537,26 +1624,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; @@ -1585,7 +1677,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_); @@ -1597,7 +1689,7 @@ bool OurReader::readObject(Token& tokenStart) { break; if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object return true; - name = ""; + name.clear(); if (tokenName.type_ == tokenString) { if (!decodeString(tokenName, name)) return recoverFromError(tokenObjectEnd); @@ -1617,7 +1709,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); } @@ -1650,7 +1742,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); @@ -1711,7 +1803,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(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 @@ -1747,12 +1839,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(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 @@ -1763,16 +1856,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; @@ -1780,7 +1874,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); @@ -1790,8 +1884,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(token.end_ - token.start_ - 2)); Location current = token.start_ + 1; // skip '"' Location end = token.end_ - 1; // do not include '"' while (current != end) { @@ -1875,13 +1969,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; @@ -1897,11 +1991,12 @@ bool OurReader::decodeUnicodeEscapeSequence(Token& token, token, current); } + ret_unicode = static_cast(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; @@ -1911,7 +2006,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)) @@ -1923,7 +2018,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); @@ -1961,24 +2056,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) { @@ -2008,8 +2095,8 @@ std::vector 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; @@ -2025,8 +2112,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) @@ -2058,9 +2145,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(); @@ -2087,9 +2174,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* valid_keys) +static void getValidReaderKeys(std::set* valid_keys) { valid_keys->clear(); valid_keys->insert("collectComments"); @@ -2101,25 +2189,26 @@ static void getValidReaderKeys(std::set* 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 valid_keys; + std::set 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]; } @@ -2132,8 +2221,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 @@ -2149,6 +2240,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) (*settings)["stackLimit"] = 1000; (*settings)["failIfExtra"] = false; (*settings)["rejectDupKeys"] = false; + (*settings)["allowSpecialFloats"] = false; //! [CharReaderBuilderDefaults] } @@ -2156,12 +2248,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. @@ -2169,16 +2261,12 @@ 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; } @@ -2198,7 +2286,7 @@ std::istream& operator>>(std::istream& sin, Value& root) { // Beginning of content of file: src/lib_json/json_valueiterator.inl // ////////////////////////////////////////////////////////////////////// -// Copyright 2007-2010 Baptiste Lepilleur +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -2292,27 +2380,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; } // ////////////////////////////////////////////////////////////////// @@ -2329,6 +2417,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); @@ -2349,7 +2440,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) {} @@ -2374,7 +2467,7 @@ ValueIterator& ValueIterator::operator=(const SelfType& other) { // Beginning of content of file: src/lib_json/json_value.cpp // ////////////////////////////////////////////////////////////////////// -// Copyright 2011 Baptiste Lepilleur +// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -2407,10 +2500,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(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(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); @@ -2431,11 +2536,14 @@ const LargestUInt Value::maxLargestUInt = LargestUInt(-1); #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) template 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(min) && d <= static_cast(max); return d >= min && d <= max; } #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) static inline double integerToDouble(Json::UInt64 value) { - return static_cast(Int64(value / 2)) * 2.0 + Int64(value & 1); + return static_cast(Int64(value / 2)) * 2.0 + static_cast(Int64(value & 1)); } template static inline double integerToDouble(T value) { @@ -2456,10 +2564,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(Value::maxInt)) length = Value::maxInt - 1; char* newString = static_cast(malloc(length + 1)); @@ -2481,10 +2590,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(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(sizeof(unsigned)) + 1U; char* newString = static_cast(malloc(actualLength)); if (newString == 0) { throwRuntimeError( @@ -2501,7 +2610,7 @@ inline static void decodePrefixedString( unsigned* length, char const** value) { if (!isPrefixed) { - *length = strlen(prefixed); + *length = static_cast(strlen(prefixed)); *value = prefixed; } else { *length = *reinterpret_cast(prefixed); @@ -2510,7 +2619,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 @@ -2528,43 +2659,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); } @@ -2577,16 +2691,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); @@ -2608,31 +2723,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(other.cstr_ + ? (static_cast(other.storage_.policy_) == noDuplication ? noDuplication : duplicate) - : other.storage_.policy_); + : static_cast(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(cstr_)); + if (cstr_ && storage_.policy_ == duplicate) { + releaseStringValue(const_cast(cstr_), storage_.length_ + 1u); //+1 for null terminating character for sake of completeness but not actually necessary + } } void Value::CZString::swap(CZString& other) { @@ -2640,18 +2761,29 @@ void Value::CZString::swap(CZString& other) { std::swap(index_, other.index_); } -Value::CZString& Value::CZString::operator=(CZString other) { - swap(other); +Value::CZString& Value::CZString::operator=(const CZString& other) { + cstr_ = other.cstr_; + index_ = other.index_; return *this; } +#if JSON_HAS_RVALUE_REFERENCES +Value::CZString& Value::CZString::operator=(CZString&& other) { + cstr_ = other.cstr_; + index_ = other.index_; + other.cstr_ = nullptr; + return *this; +} +#endif + bool Value::CZString::operator<(const CZString& other) const { if (!cstr_) return index_ < other.index_; //return strcmp(cstr_, other.cstr_) < 0; // 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(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; @@ -2665,6 +2797,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; } @@ -2688,9 +2821,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: @@ -2701,7 +2835,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(static_cast(emptyString)); break; case arrayValue: case objectValue: @@ -2742,6 +2877,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(strlen(value))); } @@ -2751,7 +2887,7 @@ Value::Value(const char* beginValue, const char* endValue) { duplicateAndPrefixStringValue(beginValue, static_cast(endValue - beginValue)); } -Value::Value(const std::string& value) { +Value::Value(const JSONCPP_STRING& value) { initBasic(stringValue, true); value_.string_ = duplicateAndPrefixStringValue(value.data(), static_cast(value.length())); @@ -2818,6 +2954,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: @@ -2828,7 +2972,7 @@ Value::~Value() { break; case stringValue: if (allocated_) - releaseStringValue(value_.string_); + releasePrefixedStringValue(value_.string_); break; case arrayValue: case objectValue: @@ -2838,8 +2982,9 @@ Value::~Value() { JSON_ASSERT_UNREACHABLE; } - if (comments_) - delete[] comments_; + delete[] comments_; + + value_.uint_ = 0; } Value& Value::operator=(Value other) { @@ -2854,7 +2999,13 @@ 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::copyPayload(const Value& other) { + type_ = other.type_; + value_ = other.value_; + allocated_ = other.allocated_; } void Value::swap(Value& other) { @@ -2864,6 +3015,13 @@ void Value::swap(Value& other) { std::swap(limit_, other.limit_); } +void Value::copy(const Value& other) { + copyPayload(other); + comments_ = other.comments_; + start_ = other.start_; + limit_ = other.limit_; +} + ValueType Value::type() const { return type_; } int Value::compare(const Value& other) const { @@ -2901,7 +3059,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(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; @@ -2957,6 +3116,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; } @@ -2982,16 +3142,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 ""; @@ -3001,7 +3173,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"; @@ -3161,7 +3333,8 @@ float Value::asFloat() const { #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) return static_cast(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(integerToDouble(value_.uint_)); #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) case realValue: return static_cast(value_.real_); @@ -3186,7 +3359,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; } @@ -3198,7 +3372,7 @@ bool Value::isConvertibleTo(ValueType other) const { case nullValue: return (isNumeric() && asDouble() == 0.0) || (type_ == booleanValue && value_.bool_ == false) || - (type_ == stringValue && asString() == "") || + (type_ == stringValue && asString().empty()) || (type_ == arrayValue && value_.map_->size() == 0) || (type_ == objectValue && value_.map_->size() == 0) || type_ == nullValue; @@ -3257,7 +3431,7 @@ bool Value::empty() const { return false; } -bool Value::operator!() const { return isNull(); } +Value::operator bool() const { return ! isNull(); } void Value::clear() { JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || @@ -3289,7 +3463,7 @@ void Value::resize(ArrayIndex newSize) { for (ArrayIndex index = newSize; index < oldSize; ++index) { value_.map_->erase(index); } - assert(size() == newSize); + JSON_ASSERT(size() == newSize); } } @@ -3304,7 +3478,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; } @@ -3321,11 +3495,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; } @@ -3336,8 +3510,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; @@ -3359,14 +3533,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, @@ -3374,12 +3548,12 @@ Value& Value::resolveReference(char const* key, char const* end) if (type_ == nullValue) *this = Value(objectValue); CZString actualKey( - key, static_cast(end-key), CZString::duplicateOnCopy); + key, static_cast(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; @@ -3387,18 +3561,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(end-key), CZString::noDuplication); + CZString actualKey(key, static_cast(cend-key), CZString::noDuplication); ObjectValues::const_iterator it = value_.map_->find(actualKey); if (it == value_.map_->end()) return NULL; return &(*it).second; @@ -3406,13 +3580,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; } @@ -3420,7 +3594,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()); } @@ -3435,34 +3609,38 @@ 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 +#if JSON_HAS_RVALUE_REFERENCES + Value& Value::append(Value&& value) { return (*this)[size()] = std::move(value); } +#endif + +Value Value::get(char const* key, char const* cend, Value const& defaultValue) const { - Value const* found = find(key, 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(end-key), CZString::noDuplication); + CZString actualKey(key, static_cast(cend-key), CZString::noDuplication); ObjectValues::iterator it = value_.map_->find(actualKey); if (it == value_.map_->end()) return false; @@ -3474,24 +3652,23 @@ 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); } -Value Value::removeMember(const char* key) +void Value::removeMember(const char* key) { JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, "in Json::Value::removeMember(): requires objectValue"); if (type_ == nullValue) - return nullRef; + return; - Value removed; // null - removeMember(key, key + strlen(key), &removed); - return removed; // still null if removeMember() did nothing + CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication); + value_.map_->erase(actualKey); } -Value Value::removeMember(const std::string& key) +void Value::removeMember(const JSONCPP_STRING& key) { - return removeMember(key.c_str()); + removeMember(key.c_str()); } bool Value::removeIndex(ArrayIndex index, Value* removed) { @@ -3507,8 +3684,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); @@ -3524,16 +3701,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()); } @@ -3555,7 +3732,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; @@ -3598,7 +3775,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: @@ -3613,9 +3794,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_); @@ -3666,16 +3855,28 @@ bool Value::isUInt64() const { } bool Value::isIntegral() const { + switch (type_) { + case intValue: + case uintValue: + return true; + case realValue: #if defined(JSON_HAS_INT64) - return isInt64() || isUInt64(); + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_); #else - return isInt() || isUInt(); -#endif + return value_.real_ >= minInt && value_.real_ <= maxUInt && IsIntegral(value_.real_); +#endif // JSON_HAS_INT64 + default: + break; + } + return false; } -bool Value::isDouble() const { return type_ == 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; } @@ -3697,7 +3898,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); } @@ -3705,23 +3906,28 @@ 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 { - StyledWriter writer; - return writer.write(*this); +JSONCPP_STRING Value::toStyledString() const { + StreamWriterBuilder builder; + + JSONCPP_STRING out = this->hasComment(commentBefore) ? "\n" : ""; + out += Json::writeString(builder, *this); + out += "\n"; + + return out; } Value::const_iterator Value::begin() const { @@ -3787,19 +3993,20 @@ 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, const PathArgument& a4, const PathArgument& a5) { InArgs in; + in.reserve(5); in.push_back(&a1); in.push_back(&a2); in.push_back(&a3); @@ -3808,7 +4015,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(); @@ -3823,23 +4030,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) { @@ -3848,11 +4055,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. } @@ -3863,16 +4070,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; } } } @@ -3891,7 +4101,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; } } @@ -3932,7 +4142,7 @@ Value& Path::make(Value& root) const { // Beginning of content of file: src/lib_json/json_writer.cpp // ////////////////////////////////////////////////////////////////////// -// Copyright 2011 Baptiste Lepilleur +// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE @@ -3954,19 +4164,52 @@ Value& Path::make(Value& root) const { #include #define isfinite _finite #elif defined(__sun) && defined(__SVR4) //Solaris +#if !defined(isfinite) #include #define isfinite finite +#endif +#elif defined(_AIX) +#if !defined(isfinite) +#include +#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 +#define isfinite finite +#endif +#endif #else #include +#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 -#define snprintf _snprintf -#elif defined(WIN32) -#define snprintf _snprintf -#elif __cplusplus >= 201103L +#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 +#define isfinite _finite +#define snprintf _snprintf #endif #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 @@ -3976,40 +4219,29 @@ Value& Path::make(Value& root) const { namespace Json { +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr StreamWriterPtr; +#else typedef std::auto_ptr StreamWriterPtr; +#endif -static bool containsControlCharacter(const char* str) { - while (*str) { - if (isControlCharacter(*(str++))) - return true; - } - return false; -} - -static bool containsControlCharacter0(const char* str, unsigned len) { - char const* end = str + len; - while (end != str) { - if (isControlCharacter(*str) || 0==*str) - return true; - ++str; - } - return false; -} - -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); @@ -4019,145 +4251,161 @@ 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[15]; + snprintf(formatString, sizeof(formatString), "%%.%ug", precision); + + // Print into the buffer. We need not request the alternative representation + // that always has a decimal point because JSON doesn't distinguish the + // concepts of reals and integers. if (isfinite(value)) { - len = snprintf(buffer, sizeof(buffer), "%.17g", value); + len = snprintf(buffer, sizeof(buffer), formatString, value); + fixNumericLocale(buffer, buffer + len); + + // try to ensure we preserve the fact that this was given to us as a double on input + if (!strchr(buffer, '.') && !strchr(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; } - -std::string valueToString(bool value) { return value ? "true" : "false"; } - -std::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 + "\""; - // We have to walk value and escape any special characters. - // Appending to std::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 = - strlen(value) * 2 + 3; // allescaped+quotes+NULL - std::string result; - result.reserve(maxsize); // to avoid lots of mallocs - result += "\""; - for (const char* c = value; *c != 0; ++c) { - switch (*c) { - case '\"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - case '\b': - result += "\\b"; - break; - case '\f': - result += "\\f"; - break; - case '\n': - result += "\\n"; - break; - case '\r': - result += "\\r"; - break; - case '\t': - result += "\\t"; - break; - // case '/': - // Even though \/ is considered a legal escape in JSON, a bare - // slash is also legal, so I see no reason to escape it. - // (I hope I am not misunderstanding something. - // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); - result += oss.str(); - } else { - result += *c; - } - break; - } - } - result += "\""; - return result; } -// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp -static char const* strnpbrk(char const* s, char const* accept, size_t n) { - assert((s || !n) && accept); +JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); } + +JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; } + +static bool isAnyCharRequiredQuoting(char const* s, size_t n) { + assert(s || !n); char const* const end = s + n; for (char const* cur = s; cur < end; ++cur) { - int const c = *cur; - for (char const* a = accept; *a; ++a) { - if (*a == c) { - return cur; - } - } + if (*cur == '\\' || *cur == '\"' || *cur < ' ' + || static_cast(*cur) < 0x80) + return true; } - return NULL; + return false; } -static std::string valueToQuotedStringN(const char* value, unsigned length) { + +static unsigned int utf8ToCodepoint(const char*& s, const char* e) { + const unsigned int REPLACEMENT_CHARACTER = 0xFFFD; + + unsigned int firstByte = static_cast(*s); + + if (firstByte < 0x80) + return firstByte; + + if (firstByte < 0xE0) { + if (e - s < 2) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = ((firstByte & 0x1F) << 6) + | (static_cast(s[1]) & 0x3F); + s += 1; + // oversized encoded characters are invalid + return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated; + } + + if (firstByte < 0xF0) { + if (e - s < 3) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = ((firstByte & 0x0F) << 12) + | ((static_cast(s[1]) & 0x3F) << 6) + | (static_cast(s[2]) & 0x3F); + s += 2; + // surrogates aren't valid codepoints itself + // shouldn't be UTF-8 encoded + if (calculated >= 0xD800 && calculated <= 0xDFFF) + return REPLACEMENT_CHARACTER; + // oversized encoded characters are invalid + return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated; + } + + if (firstByte < 0xF8) { + if (e - s < 4) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = ((firstByte & 0x07) << 24) + | ((static_cast(s[1]) & 0x3F) << 12) + | ((static_cast(s[2]) & 0x3F) << 6) + | (static_cast(s[3]) & 0x3F); + s += 3; + // oversized encoded characters are invalid + return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated; + } + + return REPLACEMENT_CHARACTER; +} + +static const char hex2[] = + "000102030405060708090a0b0c0d0e0f" + "101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f" + "303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f" + "505152535455565758595a5b5c5d5e5f" + "606162636465666768696a6b6c6d6e6f" + "707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; + +static JSONCPP_STRING toHex16Bit(unsigned int x) { + const unsigned int hi = (x >> 8) & 0xff; + const unsigned int lo = x & 0xff; + JSONCPP_STRING result(4, ' '); + result[0] = hex2[2 * hi]; + result[1] = hex2[2 * hi + 1]; + result[2] = hex2[2 * lo]; + result[3] = hex2[2 * lo + 1]; + return result; +} + +static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { if (value == NULL) return ""; - // Not sure how to handle unicode... - if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL && - !containsControlCharacter0(value, length)) - return std::string("\"") + value + "\""; + + if (!isAnyCharRequiredQuoting(value, length)) + 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; @@ -4192,14 +4440,24 @@ static std::string valueToQuotedStringN(const char* value, unsigned length) { // sequence. // Should add a flag to allow this compatibility mode and prevent this // sequence from occurring. - default: - if ((isControlCharacter(*c)) || (*c == 0)) { - std::ostringstream oss; - oss << "\\u" << std::hex << std::uppercase << std::setfill('0') - << std::setw(4) << static_cast(*c); - result += oss.str(); - } else { - result += *c; + default: { + unsigned int cp = utf8ToCodepoint(c, end); + // don't escape non-control characters + // (short escape sequence are applied above) + if (cp < 0x80 && cp >= 0x20) + result += static_cast(cp); + else if (cp < 0x10000) { // codepoint is in Basic Multilingual Plane + result += "\\u"; + result += toHex16Bit(cp); + } + else { // codepoint is not in Basic Multilingual Plane + // convert to surrogate pair first + cp -= 0x10000; + result += "\\u"; + result += toHex16Bit((cp >> 10) + 0xD800); + result += "\\u"; + result += toHex16Bit((cp & 0x3FF) + 0xDC00); + } } break; } @@ -4208,6 +4466,10 @@ static std::string valueToQuotedStringN(const char* value, unsigned length) { return result; } +JSONCPP_STRING valueToQuotedString(const char* value) { + return valueToQuotedStringN(value, static_cast(strlen(value))); +} + // Class Writer // ////////////////////////////////////////////////////////////////// Writer::~Writer() {} @@ -4216,17 +4478,17 @@ Writer::~Writer() {} // ////////////////////////////////////////////////////////////////// FastWriter::FastWriter() - : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), + : yamlCompatibilityEnabled_(false), dropNullPlaceholders_(false), omitEndingLineFeed_(false) {} -void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } +void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; } void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } -std::string FastWriter::write(const Value& root) { - document_ = ""; +JSONCPP_STRING FastWriter::write(const Value& root) { + document_.clear(); writeValue(root); if (!omitEndingLineFeed_) document_ += "\n"; @@ -4249,15 +4511,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(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]); @@ -4269,11 +4537,11 @@ 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_ += yamlCompatiblityEnabled_ ? ": " : ":"; + document_ += valueToQuotedStringN(name.data(), static_cast(name.length())); + document_ += yamlCompatibilityEnabled_ ? ": " : ":"; writeValue(value[name]); } document_ += '}'; @@ -4287,10 +4555,10 @@ void FastWriter::writeValue(const Value& value) { StyledWriter::StyledWriter() : rightMargin_(74), indentSize_(3), addChildValues_() {} -std::string StyledWriter::write(const Value& root) { - document_ = ""; +JSONCPP_STRING StyledWriter::write(const Value& root) { + document_.clear(); addChildValues_ = false; - indentString_ = ""; + indentString_.clear(); writeCommentBeforeValue(root); writeValue(root); writeCommentAfterValueOnSameLine(root); @@ -4314,7 +4582,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); @@ -4337,7 +4605,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())); @@ -4362,7 +4630,7 @@ void StyledWriter::writeArrayValue(const Value& value) { if (size == 0) pushValue("[]"); else { - bool isArrayMultiLine = isMultineArray(value); + bool isArrayMultiLine = isMultilineArray(value); if (isArrayMultiLine) { writeWithIndent("["); indent(); @@ -4400,27 +4668,26 @@ void StyledWriter::writeArrayValue(const Value& value) { } } -bool StyledWriter::isMultineArray(const Value& value) { - int size = value.size(); +bool StyledWriter::isMultilineArray(const Value& value) { + 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(childValues_[index].length()); } addChildValues_ = false; isMultiLine = isMultiLine || lineLength >= rightMargin_; @@ -4428,7 +4695,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 @@ -4446,15 +4713,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_); } @@ -4464,12 +4731,12 @@ 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' && - (iter != comment.end() && *(iter + 1) == '/')) + ((iter+1) != comment.end() && *(iter + 1) == '/')) writeIndent(); ++iter; } @@ -4498,14 +4765,14 @@ 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_ = ""; + indentString_.clear(); indented_ = true; writeCommentBeforeValue(root); if (!indented_) writeIndent(); @@ -4531,8 +4798,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(end-str))); + else pushValue(""); break; + } case booleanValue: pushValue(valueToString(value.asBool())); break; @@ -4548,7 +4822,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())); @@ -4573,7 +4847,7 @@ void StyledStreamWriter::writeArrayValue(const Value& value) { if (size == 0) pushValue("[]"); else { - bool isArrayMultiLine = isMultineArray(value); + bool isArrayMultiLine = isMultilineArray(value); if (isArrayMultiLine) { writeWithIndent("["); indent(); @@ -4613,27 +4887,26 @@ void StyledStreamWriter::writeArrayValue(const Value& value) { } } -bool StyledStreamWriter::isMultineArray(const Value& value) { - int size = value.size(); +bool StyledStreamWriter::isMultilineArray(const Value& value) { + 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(childValues_[index].length()); } addChildValues_ = false; isMultiLine = isMultiLine || lineLength >= rightMargin_; @@ -4641,7 +4914,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 @@ -4656,7 +4929,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; @@ -4674,12 +4947,12 @@ 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' && - (iter != comment.end() && *(iter + 1) == '/')) + ((iter+1) != comment.end() && *(iter + 1) == '/')) // writeIndent(); // would include newline *document_ << indentString_; ++iter; @@ -4720,44 +4993,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); + bool isMultilineArray(Value 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 ChildValues; + typedef std::vector 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) @@ -4766,14 +5045,16 @@ 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; indented_ = true; - indentString_ = ""; + indentString_.clear(); writeCommentBeforeValue(root); if (!indented_) writeIndent(); indented_ = true; @@ -4795,11 +5076,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); @@ -4822,10 +5103,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(name.length()))); *sout_ << colonSymbol_; writeValue(childValue); if (++it == members.end()) { @@ -4847,7 +5128,7 @@ void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { if (size == 0) pushValue("[]"); else { - bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value); + bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value); if (isMultiLine) { writeWithIndent("["); indent(); @@ -4880,7 +5161,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_ << " "; @@ -4889,27 +5170,26 @@ void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { } } -bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { - int size = value.size(); +bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) { + 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(childValues_[index].length()); } addChildValues_ = false; isMultiLine = isMultiLine || lineLength >= rightMargin_; @@ -4917,7 +5197,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 @@ -4936,7 +5216,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; @@ -4955,12 +5235,12 @@ 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' && - (iter != comment.end() && *(iter + 1) == '/')) + ((iter+1) != comment.end() && *(iter + 1) == '/')) // writeIndent(); // would write extra newline *sout_ << indentString_; ++iter; @@ -5006,10 +5286,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; @@ -5018,47 +5300,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 = ""; + nullSymbol.clear(); } - 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* valid_keys) +static void getValidWriterKeys(std::set* 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 valid_keys; + std::set 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]; } @@ -5070,17 +5355,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);