diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..22d2b7a45 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +* text=auto +*.h text +*.cpp text +*.json text +*.in text +*.sh eol=lf +*.bat eol=crlf +*.vcproj eol=crlf +*.vcxproj eol=crlf +*.sln eol=crlf +devtools/agent_vm* eol=crlf diff --git a/.travis.yml b/.travis.yml index 4957987f6..722a3a407 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,23 +8,22 @@ install: # /usr/bin/gcc is 4.6 always, but gcc-X.Y is available. -- if [ "$CXX" = "g++" ]; then export CXX="g++-4.9" CC="gcc-4.9"; fi +#- if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi +- if [ "$CXX" = "g++" ]; then export CXX="g++-4.6" CC="gcc-4.6"; fi # /usr/bin/clang is our version already, and clang-X.Y does not exist. -#- if [ "$CXX" = "clang++" ]; then export CXX="clang++-3.7" CC="clang-3.7"; fi +#- if [ "$CXX" = "clang++" ]; then export CXX="clang++-3.0" CC="clang-3.0"; fi - echo ${PATH} - ls /usr/local -- ls /usr/local/bin -- export PATH=/usr/local/bin:/usr/bin:${PATH} +- export PATH=/usr/bin:${PATH} - echo ${CXX} - ${CXX} --version -- which valgrind addons: apt: sources: - ubuntu-toolchain-r-test packages: - - gcc-4.9 - - g++-4.9 + - gcc-4.6 + - g++-4.6 - clang - valgrind os: diff --git a/CMakeLists.txt b/CMakeLists.txt index cab0de8c1..94883e000 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,14 +12,16 @@ OPTION(JSONCPP_WITH_CMAKE_PACKAGE "Generate and install cmake package files" OFF OPTION(BUILD_SHARED_LIBS "Build jsoncpp_lib as a shared library." OFF) OPTION(BUILD_STATIC_LIBS "Build jsoncpp_lib static library." ON) +include(GNUInstallDirs) + # Ensures that CMAKE_BUILD_TYPE is visible in cmake-gui on Unix IF(NOT WIN32) IF(NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage." FORCE) - ENDIF(NOT CMAKE_BUILD_TYPE) -ENDIF(NOT WIN32) + ENDIF() +ENDIF() SET(DEBUG_LIBNAME_SUFFIX "" CACHE STRING "Optional suffix to append to the library name for a debug build") SET(LIB_SUFFIX "" CACHE STRING "Optional arch-dependent suffix for the library installation directory") @@ -30,7 +32,7 @@ SET(ARCHIVE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX} CACHE PATH "Install dir for static libraries") SET(LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX} CACHE PATH "Install dir for shared libraries") -SET(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include +SET(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/jsoncpp CACHE PATH "Install dir for headers") SET(PACKAGE_INSTALL_DIR lib${LIB_SUFFIX}/cmake CACHE PATH "Install dir for cmake package config files") @@ -39,7 +41,7 @@ MARK_AS_ADVANCED( RUNTIME_INSTALL_DIR ARCHIVE_INSTALL_DIR INCLUDE_INSTALL_DIR PA # Set variable named ${VAR_NAME} to value ${VALUE} FUNCTION(set_using_dynamic_name VAR_NAME VALUE) SET( "${VAR_NAME}" "${VALUE}" PARENT_SCOPE) -ENDFUNCTION(set_using_dynamic_name) +ENDFUNCTION() # Extract major, minor, patch from version text # Parse a version string "X.Y.Z" and outputs @@ -55,15 +57,15 @@ MACRO(jsoncpp_parse_version VERSION_TEXT OUPUT_PREFIX) set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" TRUE ) ELSE( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} ) set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" FALSE ) - ENDIF( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} ) -ENDMACRO(jsoncpp_parse_version) + ENDIF() +ENDMACRO() # Read out version from "version" file #FILE(STRINGS "version" JSONCPP_VERSION) #SET( JSONCPP_VERSION_MAJOR X ) #SET( JSONCPP_VERSION_MINOR Y ) #SET( JSONCPP_VERSION_PATCH Z ) -SET( JSONCPP_VERSION 1.6.5 ) +SET( JSONCPP_VERSION 0.10.7 ) jsoncpp_parse_version( ${JSONCPP_VERSION} JSONCPP_VERSION ) #IF(NOT JSONCPP_VERSION_FOUND) # MESSAGE(FATAL_ERROR "Failed to parse version string properly. Expect X.Y.Z") @@ -79,11 +81,13 @@ CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/version.in" NEWLINE_STYLE UNIX ) macro(UseCompilationWarningAsError) - if ( MSVC ) - # Only enabled in debug because some old versions of VS STL generate - # warnings when compiled in release configuration. - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /WX ") - endif( MSVC ) + if ( MSVC ) + # Only enabled in debug because some old versions of VS STL generate + # warnings when compiled in release configuration. + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /WX ") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_XX_COMPILER_ID MATCHES "Clang" ) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") + endif() endmacro() # Include our configuration header @@ -93,20 +97,20 @@ if ( MSVC ) # Only enabled in debug because some old versions of VS STL generate # unreachable code warning when compiled in release configuration. set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /W4 ") -endif( MSVC ) +endif() if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") # using regular Clang or AppleClang - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Werror -Wall -Wconversion -Wshadow -Wno-sign-conversion") -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wshadow -Wshorten-64-to-32") +elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # using GCC - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Werror -Wall -Wconversion -Wshadow -Wextra -pedantic") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wshadow -Wextra -pedantic -Wno-long-long") # not yet ready for -Wsign-conversion endif() IF(JSONCPP_WITH_WARNING_AS_ERROR) UseCompilationWarningAsError() -ENDIF(JSONCPP_WITH_WARNING_AS_ERROR) +ENDIF() IF(JSONCPP_WITH_PKGCONFIG_SUPPORT) CONFIGURE_FILE( @@ -114,14 +118,14 @@ IF(JSONCPP_WITH_PKGCONFIG_SUPPORT) "pkg-config/jsoncpp.pc" @ONLY) INSTALL(FILES "${CMAKE_BINARY_DIR}/pkg-config/jsoncpp.pc" - DESTINATION "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/pkgconfig") -ENDIF(JSONCPP_WITH_PKGCONFIG_SUPPORT) + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") +ENDIF() IF(JSONCPP_WITH_CMAKE_PACKAGE) INSTALL(EXPORT jsoncpp DESTINATION ${PACKAGE_INSTALL_DIR}/jsoncpp FILE jsoncppConfig.cmake) -ENDIF(JSONCPP_WITH_CMAKE_PACKAGE) +ENDIF() # Build the different applications ADD_SUBDIRECTORY( src ) diff --git a/devtools/agent_vmw7.json b/devtools/agent_vmw7.json index 086ad9abb..cd7b777fe 100644 --- a/devtools/agent_vmw7.json +++ b/devtools/agent_vmw7.json @@ -1,33 +1,33 @@ -{ - "cmake_variants" : [ - {"name": "generator", - "generators": [ - {"generator": [ - "Visual Studio 7 .NET 2003", - "Visual Studio 9 2008", - "Visual Studio 9 2008 Win64", - "Visual Studio 10", - "Visual Studio 10 Win64", - "Visual Studio 11", - "Visual Studio 11 Win64" - ] - }, - {"generator": ["MinGW Makefiles"], - "env_prepend": [{"path": "c:/wut/prg/MinGW/bin"}] - } - ] - }, - {"name": "shared_dll", - "variables": [ - ["BUILD_SHARED_LIBS=true"], - ["BUILD_SHARED_LIBS=false"] - ] - }, - {"name": "build_type", - "build_types": [ - "debug", - "release" - ] - } - ] -} +{ + "cmake_variants" : [ + {"name": "generator", + "generators": [ + {"generator": [ + "Visual Studio 7 .NET 2003", + "Visual Studio 9 2008", + "Visual Studio 9 2008 Win64", + "Visual Studio 10", + "Visual Studio 10 Win64", + "Visual Studio 11", + "Visual Studio 11 Win64" + ] + }, + {"generator": ["MinGW Makefiles"], + "env_prepend": [{"path": "c:/wut/prg/MinGW/bin"}] + } + ] + }, + {"name": "shared_dll", + "variables": [ + ["BUILD_SHARED_LIBS=true"], + ["BUILD_SHARED_LIBS=false"] + ] + }, + {"name": "build_type", + "build_types": [ + "debug", + "release" + ] + } + ] +} diff --git a/devtools/agent_vmxp.json b/devtools/agent_vmxp.json index 997aa5efb..f82a0773a 100644 --- a/devtools/agent_vmxp.json +++ b/devtools/agent_vmxp.json @@ -1,26 +1,26 @@ -{ - "cmake_variants" : [ - {"name": "generator", - "generators": [ - {"generator": [ - "Visual Studio 6", - "Visual Studio 7", - "Visual Studio 8 2005" - ] - } - ] - }, - {"name": "shared_dll", - "variables": [ - ["BUILD_SHARED_LIBS=true"], - ["BUILD_SHARED_LIBS=false"] - ] - }, - {"name": "build_type", - "build_types": [ - "debug", - "release" - ] - } - ] -} +{ + "cmake_variants" : [ + {"name": "generator", + "generators": [ + {"generator": [ + "Visual Studio 6", + "Visual Studio 7", + "Visual Studio 8 2005" + ] + } + ] + }, + {"name": "shared_dll", + "variables": [ + ["BUILD_SHARED_LIBS=true"], + ["BUILD_SHARED_LIBS=false"] + ] + }, + {"name": "build_type", + "build_types": [ + "debug", + "release" + ] + } + ] +} diff --git a/include/json/config.h b/include/json/config.h index 0dcd8ae60..5ca322816 100644 --- a/include/json/config.h +++ b/include/json/config.h @@ -51,6 +51,16 @@ #define JSON_API #endif +#if !defined(JSON_HAS_UNIQUE_PTR) +#if __cplusplus >= 201103L +#define JSON_HAS_UNIQUE_PTR (1) +#elif _MSC_VER >= 1600 +#define JSON_HAS_UNIQUE_PTR (1) +#else +#define JSON_HAS_UNIQUE_PTR (0) +#endif +#endif + // If JSON_NO_INT64 is defined, then Json only support C++ "int" type for // integer // Storages, and 64 bits integer support is disabled. diff --git a/include/json/features.h b/include/json/features.h index 1bb7bb614..781354783 100644 --- a/include/json/features.h +++ b/include/json/features.h @@ -44,12 +44,6 @@ class JSON_API Features { /// \c true if root must be either an array or an object value. Default: \c /// false. bool strictRoot_; - - /// \c true if dropped null placeholders are allowed. Default: \c false. - bool allowDroppedNullPlaceholders_; - - /// \c true if numeric object key are allowed. Default: \c false. - bool allowNumericKeys_; }; } // namespace Json diff --git a/include/json/reader.h b/include/json/reader.h index c8ff747e4..9c9923a55 100644 --- a/include/json/reader.h +++ b/include/json/reader.h @@ -35,18 +35,6 @@ class JSON_API Reader { typedef char Char; typedef const Char* Location; - /** \brief An error tagged with where in the JSON text it was encountered. - * - * The offsets give the [start, limit) range of bytes within the text. Note - * that this is bytes, not codepoints. - * - */ - struct StructuredError { - size_t offset_start; - size_t offset_limit; - std::string message; - }; - /** \brief Constructs a Reader allowing all features * for parsing. */ @@ -123,38 +111,6 @@ class JSON_API Reader { */ std::string getFormattedErrorMessages() const; - /** \brief Returns a vector of structured erros encounted while parsing. - * \return A (possibly empty) vector of StructuredError objects. Currently - * only one error can be returned, but the caller should tolerate - * multiple - * errors. This can occur if the parser recovers from a non-fatal - * parse error and then encounters additional errors. - */ - std::vector getStructuredErrors() const; - - /** \brief Add a semantic error message. - * \param value JSON Value location associated with the error - * \param message The error message. - * \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); - - /** \brief Add a semantic error message with extra context. - * \param value JSON Value location associated with the error - * \param message The error message. - * \param extra Additional JSON Value location to contextualize the error - * \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); - - /** \brief Return whether there are any errors. - * \return \c true if there are no errors to report \c false if - * errors have occurred. - */ - bool good() const; - private: enum TokenType { tokenEndOfStream = 0, @@ -321,6 +277,9 @@ class JSON_API CharReaderBuilder : public CharReader::Factory { 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 diff --git a/include/json/value.h b/include/json/value.h index 8e996ae23..66433f888 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -29,6 +29,19 @@ #pragma warning(disable : 4251) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +//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 + /** \brief JSON (JavaScript Object Notation). */ namespace Json { @@ -69,9 +82,9 @@ class JSON_API LogicError : public Exception { }; /// used internally -void throwRuntimeError(std::string const& msg); +JSONCPP_NORETURN void throwRuntimeError(std::string const& msg); /// used internally -void throwLogicError(std::string const& msg); +JSONCPP_NORETURN void throwLogicError(std::string const& msg); /** \brief Type of the value held by a Value object. */ @@ -175,8 +188,11 @@ class JSON_API Value { typedef Json::LargestUInt LargestUInt; typedef Json::ArrayIndex ArrayIndex; - 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 const Value& nullRef; +#if !defined(__ARMEL__) + /// \deprecated This exists for binary compatibility only. Use nullRef. + static const Value null; +#endif /// 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. @@ -200,7 +216,12 @@ class JSON_API Value { static const UInt64 maxUInt64; #endif // defined(JSON_HAS_INT64) +//MW: workaround for bug in NVIDIAs CUDA 7.5 nvcc compiler +#ifdef __NVCC__ +public: +#else private: +#endif //__NVCC__ #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION class CZString { public: @@ -298,7 +319,7 @@ Json::Value obj_value(Json::objectValue); // {} /// Deep copy, then swap(other). /// \note Over-write existing comments. To preserve comments, use #swapPayload(). - Value& operator=(Value other); + Value &operator=(const Value &other); /// Swap everything. void swap(Value& other); /// Swap values but leave comments and source offsets in place. @@ -545,13 +566,6 @@ Json::Value obj_value(Json::objectValue); // {} iterator begin(); iterator end(); - // 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; - private: void initBasic(ValueType type, bool allocated = false); @@ -588,11 +602,6 @@ Json::Value obj_value(Json::objectValue); // {} unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. // If not allocated_, string_ must be null-terminated. CommentInfo* comments_; - - // [start, limit) byte offsets in the source JSON text from which this Value - // was extracted. - size_t start_; - size_t limit_; }; /** \brief Experimental and untested: represents an element of the "path" to diff --git a/include/json/version.h b/include/json/version.h index 9df36d7cd..d0f3dcb02 100644 --- a/include/json/version.h +++ b/include/json/version.h @@ -3,10 +3,10 @@ #ifndef JSON_VERSION_H_INCLUDED # define JSON_VERSION_H_INCLUDED -# define JSONCPP_VERSION_STRING "1.6.5" -# define JSONCPP_VERSION_MAJOR 1 -# define JSONCPP_VERSION_MINOR 6 -# define JSONCPP_VERSION_PATCH 5 +# define JSONCPP_VERSION_STRING "0.10.7" +# define JSONCPP_VERSION_MAJOR 0 +# define JSONCPP_VERSION_MINOR 10 +# define JSONCPP_VERSION_PATCH 7 # define JSONCPP_VERSION_QUALIFIER # define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) diff --git a/include/json/writer.h b/include/json/writer.h index f5f0a389e..a7fd11d2f 100644 --- a/include/json/writer.h +++ b/include/json/writer.h @@ -99,6 +99,10 @@ class JSON_API StreamWriterBuilder : public StreamWriter::Factory { 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 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 @@ -158,15 +162,6 @@ class JSON_API FastWriter : public Writer { 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 - * browser can handle the output just fine. - */ - void dropNullPlaceholders(); - - void omitEndingLineFeed(); - public: // overridden from Writer virtual std::string write(const Value& root); @@ -175,8 +170,6 @@ class JSON_API FastWriter : public Writer { std::string document_; bool yamlCompatiblityEnabled_; - bool dropNullPlaceholders_; - bool omitEndingLineFeed_; }; /** \brief Writes a Value in JSON format in a diff --git a/makefiles/vs71/jsoncpp.sln b/makefiles/vs71/jsoncpp.sln index 5bfa36654..dd2f91b44 100644 --- a/makefiles/vs71/jsoncpp.sln +++ b/makefiles/vs71/jsoncpp.sln @@ -1,46 +1,46 @@ -Microsoft Visual Studio Solution File, Format Version 8.00 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_json", "lib_json.vcproj", "{B84F7231-16CE-41D8-8C08-7B523FF4225B}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jsontest", "jsontest.vcproj", "{25AF2DD2-D396-4668-B188-488C33B8E620}" - ProjectSection(ProjectDependencies) = postProject - {B84F7231-16CE-41D8-8C08-7B523FF4225B} = {B84F7231-16CE-41D8-8C08-7B523FF4225B} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_lib_json", "test_lib_json.vcproj", "{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}" - ProjectSection(ProjectDependencies) = postProject - {B84F7231-16CE-41D8-8C08-7B523FF4225B} = {B84F7231-16CE-41D8-8C08-7B523FF4225B} - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfiguration) = preSolution - Debug = Debug - dummy = dummy - Release = Release - EndGlobalSection - GlobalSection(ProjectConfiguration) = postSolution - {B84F7231-16CE-41D8-8C08-7B523FF4225B}.Debug.ActiveCfg = Debug|Win32 - {B84F7231-16CE-41D8-8C08-7B523FF4225B}.Debug.Build.0 = Debug|Win32 - {B84F7231-16CE-41D8-8C08-7B523FF4225B}.dummy.ActiveCfg = dummy|Win32 - {B84F7231-16CE-41D8-8C08-7B523FF4225B}.dummy.Build.0 = dummy|Win32 - {B84F7231-16CE-41D8-8C08-7B523FF4225B}.Release.ActiveCfg = Release|Win32 - {B84F7231-16CE-41D8-8C08-7B523FF4225B}.Release.Build.0 = Release|Win32 - {25AF2DD2-D396-4668-B188-488C33B8E620}.Debug.ActiveCfg = Debug|Win32 - {25AF2DD2-D396-4668-B188-488C33B8E620}.Debug.Build.0 = Debug|Win32 - {25AF2DD2-D396-4668-B188-488C33B8E620}.dummy.ActiveCfg = Debug|Win32 - {25AF2DD2-D396-4668-B188-488C33B8E620}.dummy.Build.0 = Debug|Win32 - {25AF2DD2-D396-4668-B188-488C33B8E620}.Release.ActiveCfg = Release|Win32 - {25AF2DD2-D396-4668-B188-488C33B8E620}.Release.Build.0 = Release|Win32 - {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Debug.ActiveCfg = Debug|Win32 - {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Debug.Build.0 = Debug|Win32 - {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.dummy.ActiveCfg = Debug|Win32 - {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.dummy.Build.0 = Debug|Win32 - {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Release.ActiveCfg = Release|Win32 - {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Release.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_json", "lib_json.vcproj", "{B84F7231-16CE-41D8-8C08-7B523FF4225B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jsontest", "jsontest.vcproj", "{25AF2DD2-D396-4668-B188-488C33B8E620}" + ProjectSection(ProjectDependencies) = postProject + {B84F7231-16CE-41D8-8C08-7B523FF4225B} = {B84F7231-16CE-41D8-8C08-7B523FF4225B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_lib_json", "test_lib_json.vcproj", "{B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}" + ProjectSection(ProjectDependencies) = postProject + {B84F7231-16CE-41D8-8C08-7B523FF4225B} = {B84F7231-16CE-41D8-8C08-7B523FF4225B} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + dummy = dummy + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {B84F7231-16CE-41D8-8C08-7B523FF4225B}.Debug.ActiveCfg = Debug|Win32 + {B84F7231-16CE-41D8-8C08-7B523FF4225B}.Debug.Build.0 = Debug|Win32 + {B84F7231-16CE-41D8-8C08-7B523FF4225B}.dummy.ActiveCfg = dummy|Win32 + {B84F7231-16CE-41D8-8C08-7B523FF4225B}.dummy.Build.0 = dummy|Win32 + {B84F7231-16CE-41D8-8C08-7B523FF4225B}.Release.ActiveCfg = Release|Win32 + {B84F7231-16CE-41D8-8C08-7B523FF4225B}.Release.Build.0 = Release|Win32 + {25AF2DD2-D396-4668-B188-488C33B8E620}.Debug.ActiveCfg = Debug|Win32 + {25AF2DD2-D396-4668-B188-488C33B8E620}.Debug.Build.0 = Debug|Win32 + {25AF2DD2-D396-4668-B188-488C33B8E620}.dummy.ActiveCfg = Debug|Win32 + {25AF2DD2-D396-4668-B188-488C33B8E620}.dummy.Build.0 = Debug|Win32 + {25AF2DD2-D396-4668-B188-488C33B8E620}.Release.ActiveCfg = Release|Win32 + {25AF2DD2-D396-4668-B188-488C33B8E620}.Release.Build.0 = Release|Win32 + {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Debug.ActiveCfg = Debug|Win32 + {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Debug.Build.0 = Debug|Win32 + {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.dummy.ActiveCfg = Debug|Win32 + {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.dummy.Build.0 = Debug|Win32 + {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Release.ActiveCfg = Release|Win32 + {B7A96B78-2782-40D2-8F37-A2DEF2B9C26D}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/makefiles/vs71/jsontest.vcproj b/makefiles/vs71/jsontest.vcproj index 99a4dd697..562c71f61 100644 --- a/makefiles/vs71/jsontest.vcproj +++ b/makefiles/vs71/jsontest.vcproj @@ -1,119 +1,119 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/makefiles/vs71/lib_json.vcproj b/makefiles/vs71/lib_json.vcproj index fe66d8ac5..24c5dd411 100644 --- a/makefiles/vs71/lib_json.vcproj +++ b/makefiles/vs71/lib_json.vcproj @@ -1,205 +1,205 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/makefiles/vs71/test_lib_json.vcproj b/makefiles/vs71/test_lib_json.vcproj index df36700bd..9ebb986a6 100644 --- a/makefiles/vs71/test_lib_json.vcproj +++ b/makefiles/vs71/test_lib_json.vcproj @@ -1,130 +1,130 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 608d3f7b6..ca8ac15e2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,4 +2,4 @@ ADD_SUBDIRECTORY(lib_json) IF(JSONCPP_WITH_TESTS) ADD_SUBDIRECTORY(jsontestrunner) ADD_SUBDIRECTORY(test_lib_json) -ENDIF(JSONCPP_WITH_TESTS) +ENDIF() diff --git a/src/jsontestrunner/CMakeLists.txt b/src/jsontestrunner/CMakeLists.txt index 820a7cd35..20d01e626 100644 --- a/src/jsontestrunner/CMakeLists.txt +++ b/src/jsontestrunner/CMakeLists.txt @@ -9,7 +9,7 @@ IF(BUILD_SHARED_LIBS) TARGET_LINK_LIBRARIES(jsontestrunner_exe jsoncpp_lib) ELSE(BUILD_SHARED_LIBS) TARGET_LINK_LIBRARIES(jsontestrunner_exe jsoncpp_lib_static) -ENDIF(BUILD_SHARED_LIBS) +ENDIF() SET_TARGET_PROPERTIES(jsontestrunner_exe PROPERTIES OUTPUT_NAME jsontestrunner_exe) @@ -22,4 +22,4 @@ IF(PYTHONINTERP_FOUND) DEPENDS jsontestrunner_exe jsoncpp_test ) ADD_CUSTOM_TARGET(jsoncpp_check DEPENDS jsoncpp_readerwriter_tests) -ENDIF(PYTHONINTERP_FOUND) +ENDIF() diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index 79ffa2ec5..5861f035e 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -37,7 +37,7 @@ IF(JSONCPP_WITH_CMAKE_PACKAGE) SET(INSTALL_EXPORT EXPORT jsoncpp) ELSE(JSONCPP_WITH_CMAKE_PACKAGE) SET(INSTALL_EXPORT) -ENDIF(JSONCPP_WITH_CMAKE_PACKAGE) +ENDIF() IF(BUILD_SHARED_LIBS) ADD_DEFINITIONS( -DJSON_DLL_BUILD ) @@ -48,14 +48,14 @@ IF(BUILD_SHARED_LIBS) INSTALL( TARGETS jsoncpp_lib ${INSTALL_EXPORT} RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR} - LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR} - ARCHIVE DESTINATION ${ARCHIVE_INSTALL_DIR}) + LIBRARY DESTINATION "${LIBRARY_INSTALL_DIR}/${CMAKE_LIBRARY_ARCHITECTURE}" + ARCHIVE DESTINATION "${ARCHIVE_INSTALL_DIR}/${CMAKE_LIBRARY_ARCHITECTURE}") IF(NOT CMAKE_VERSION VERSION_LESS 2.8.11) TARGET_INCLUDE_DIRECTORIES( jsoncpp_lib PUBLIC $ $) - ENDIF(NOT CMAKE_VERSION VERSION_LESS 2.8.11) + ENDIF() ENDIF() @@ -67,14 +67,14 @@ IF(BUILD_STATIC_LIBS) INSTALL( TARGETS jsoncpp_lib_static ${INSTALL_EXPORT} RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR} - LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR} - ARCHIVE DESTINATION ${ARCHIVE_INSTALL_DIR}) + LIBRARY DESTINATION "${LIBRARY_INSTALL_DIR}/${CMAKE_LIBRARY_ARCHITECTURE}" + ARCHIVE DESTINATION "${ARCHIVE_INSTALL_DIR}/${CMAKE_LIBRARY_ARCHITECTURE}") IF(NOT CMAKE_VERSION VERSION_LESS 2.8.11) TARGET_INCLUDE_DIRECTORIES( jsoncpp_lib_static PUBLIC $ $ ) - ENDIF(NOT CMAKE_VERSION VERSION_LESS 2.8.11) + ENDIF() ENDIF() diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index ceff66c31..1bcb2eb7e 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -17,10 +17,23 @@ #include #include #include - -#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below +#include +#if defined(__BORLANDC__) +#include +#endif +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else #define snprintf _snprintf #endif +#elif defined(__ANDROID__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#define snprintf std::snprintf +#endif #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 // Disable warning about strdup being deprecated. @@ -32,27 +45,24 @@ static int stackDepth_g = 0; // see readValue() namespace Json { -#if __cplusplus >= 201103L -typedef std::unique_ptr CharReaderPtr; +#if JSON_HAS_UNIQUE_PTR +typedef std::unique_ptr const CharReaderPtr; #else -typedef std::auto_ptr CharReaderPtr; +typedef std::auto_ptr CharReaderPtr; #endif // Implementation of class Features // //////////////////////////////// Features::Features() - : allowComments_(true), strictRoot_(false), - allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} - + : allowComments_(true), strictRoot_(false) +{} Features Features::all() { return Features(); } Features Features::strictMode() { Features features; features.allowComments_ = false; features.strictRoot_ = true; - features.allowDroppedNullPlaceholders_ = false; - features.allowNumericKeys_ = false; return features; } @@ -162,11 +172,9 @@ bool Reader::readValue() { switch (token.type_) { case tokenObjectBegin: successful = readObject(token); - currentValue().setOffsetLimit(current_ - begin_); break; case tokenArrayBegin: successful = readArray(token); - currentValue().setOffsetLimit(current_ - begin_); break; case tokenNumber: successful = decodeNumber(token); @@ -178,42 +186,22 @@ bool Reader::readValue() { { Value v(true); currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); } break; case tokenFalse: { Value v(false); currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); } break; case tokenNull: { Value v; currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); } break; - case tokenArraySeparator: - case tokenObjectEnd: - case tokenArrayEnd: - if (features_.allowDroppedNullPlaceholders_) { - // "Un-read" the current token and mark the current value as a null - // token. - current_--; - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(current_ - begin_ - 1); - currentValue().setOffsetLimit(current_ - begin_); - break; - } // Else, fall through... + // Else, fall through... default: - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); return addError("Syntax error: value, object or array expected.", token); } @@ -441,12 +429,11 @@ bool Reader::readString() { return c == '"'; } -bool Reader::readObject(Token& tokenStart) { +bool Reader::readObject(Token& /*tokenStart*/) { Token tokenName; std::string name; Value init(objectValue); currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); while (readToken(tokenName)) { bool initialTokenOk = true; while (tokenName.type_ == tokenComment && initialTokenOk) @@ -459,11 +446,6 @@ bool Reader::readObject(Token& tokenStart) { if (tokenName.type_ == tokenString) { if (!decodeString(tokenName, name)) return recoverFromError(tokenObjectEnd); - } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { - Value numberName; - if (!decodeNumber(tokenName, numberName)) - return recoverFromError(tokenObjectEnd); - name = numberName.asString(); } else { break; } @@ -497,10 +479,9 @@ bool Reader::readObject(Token& tokenStart) { "Missing '}' or object member name", tokenName, tokenObjectEnd); } -bool Reader::readArray(Token& tokenStart) { +bool Reader::readArray(Token& /*tokenStart*/) { Value init(arrayValue); currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); skipSpaces(); if (*current_ == ']') // empty array { @@ -540,8 +521,6 @@ bool Reader::decodeNumber(Token& token) { if (!decodeNumber(token, decoded)) return false; currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); return true; } @@ -555,7 +534,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; @@ -576,7 +555,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); @@ -590,8 +571,6 @@ bool Reader::decodeDouble(Token& token) { if (!decodeDouble(token, decoded)) return false; currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); return true; } @@ -613,8 +592,6 @@ bool Reader::decodeString(Token& token) { return false; Value decoded(decoded_string); currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); return true; } @@ -793,15 +770,7 @@ std::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; } @@ -826,59 +795,8 @@ std::string Reader::getFormattedErrorMessages() const { return formattedMessage; } -std::vector Reader::getStructuredErrors() const { - std::vector allErrors; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; - Reader::StructuredError structured; - structured.offset_start = error.token_.start_ - begin_; - structured.offset_limit = error.token_.end_ - begin_; - structured.message = error.message_; - allErrors.push_back(structured); - } - return allErrors; -} - -bool Reader::pushError(const Value& value, const std::string& message) { - size_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = end_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = 0; - errors_.push_back(info); - return true; -} - -bool Reader::pushError(const Value& value, const std::string& message, const Value& extra) { - size_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length - || extra.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = begin_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = begin_ + extra.getOffsetStart(); - errors_.push_back(info); - return true; -} - -bool Reader::good() const { - return !errors_.size(); -} +// Reader +///////////////////////// // exact copy of Features class OurFeatures { @@ -892,6 +810,7 @@ class OurFeatures { bool allowSingleQuotes_; bool failIfExtra_; bool rejectDupKeys_; + bool allowSpecialFloats_; int stackLimit_; }; // OurFeatures @@ -903,6 +822,7 @@ OurFeatures::OurFeatures() , allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) , allowSingleQuotes_(false) , failIfExtra_(false) + , allowSpecialFloats_(false) { } @@ -928,10 +848,6 @@ class OurReader { Value& root, bool collectComments = true); std::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 good() const; private: OurReader(OurReader const&); // no impl @@ -948,6 +864,9 @@ class OurReader { tokenTrue, tokenFalse, tokenNull, + tokenNaN, + tokenPosInf, + tokenNegInf, tokenArraySeparator, tokenMemberSeparator, tokenComment, @@ -978,7 +897,7 @@ class OurReader { bool readCppStyleComment(); bool readString(); bool readStringSingleQuote(); - void readNumber(); + bool readNumber(bool checkInf); bool readValue(); bool readObject(Token& token); bool readArray(Token& token); @@ -1096,11 +1015,9 @@ bool OurReader::readValue() { switch (token.type_) { case tokenObjectBegin: successful = readObject(token); - currentValue().setOffsetLimit(current_ - begin_); break; case tokenArrayBegin: successful = readArray(token); - currentValue().setOffsetLimit(current_ - begin_); break; case tokenNumber: successful = decodeNumber(token); @@ -1112,24 +1029,36 @@ bool OurReader::readValue() { { Value v(true); currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); } break; case tokenFalse: { Value v(false); currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); } break; case tokenNull: { Value v; currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNaN: + { + Value v(std::numeric_limits::quiet_NaN()); + currentValue().swapPayload(v); + } + break; + case tokenPosInf: + { + Value v(std::numeric_limits::infinity()); + currentValue().swapPayload(v); + } + break; + case tokenNegInf: + { + Value v(-std::numeric_limits::infinity()); + currentValue().swapPayload(v); } break; case tokenArraySeparator: @@ -1141,13 +1070,9 @@ bool OurReader::readValue() { current_--; Value v; currentValue().swapPayload(v); - currentValue().setOffsetStart(current_ - begin_ - 1); - currentValue().setOffsetLimit(current_ - begin_); break; } // else, fall through ... default: - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); return addError("Syntax error: value, object or array expected.", token); } @@ -1212,9 +1137,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; @@ -1228,6 +1160,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; @@ -1328,8 +1276,12 @@ 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') @@ -1348,6 +1300,7 @@ void OurReader::readNumber() { while (c >= '0' && c <= '9') c = (current_ = p) < end_ ? *p++ : 0; } + return true; } bool OurReader::readString() { Char c = 0; @@ -1374,12 +1327,11 @@ bool OurReader::readStringSingleQuote() { return c == '\''; } -bool OurReader::readObject(Token& tokenStart) { +bool OurReader::readObject(Token& /*tokenStart*/) { Token tokenName; std::string name; Value init(objectValue); currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); while (readToken(tokenName)) { bool initialTokenOk = true; while (tokenName.type_ == tokenComment && initialTokenOk) @@ -1436,10 +1388,9 @@ bool OurReader::readObject(Token& tokenStart) { "Missing '}' or object member name", tokenName, tokenObjectEnd); } -bool OurReader::readArray(Token& tokenStart) { +bool OurReader::readArray(Token& /*tokenStart*/) { Value init(arrayValue); currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); skipSpaces(); if (*current_ == ']') // empty array { @@ -1479,8 +1430,6 @@ bool OurReader::decodeNumber(Token& token) { if (!decodeNumber(token, decoded)) return false; currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); return true; } @@ -1529,40 +1478,14 @@ bool OurReader::decodeDouble(Token& token) { if (!decodeDouble(token, decoded)) return false; currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); return true; } bool OurReader::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) + std::string buffer( token.start_, token.end_ ); + std::istringstream is(buffer); + if (!(is >> value)) return addError("'" + std::string(token.start_, token.end_) + "' is not a number.", token); @@ -1576,8 +1499,6 @@ bool OurReader::decodeString(Token& token) { return false; Value decoded(decoded_string); currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); return true; } @@ -1756,15 +1677,7 @@ std::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; } @@ -1784,60 +1697,6 @@ std::string OurReader::getFormattedErrorMessages() const { return formattedMessage; } -std::vector OurReader::getStructuredErrors() const { - std::vector allErrors; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; - OurReader::StructuredError structured; - structured.offset_start = error.token_.start_ - begin_; - structured.offset_limit = error.token_.end_ - begin_; - structured.message = error.message_; - allErrors.push_back(structured); - } - return allErrors; -} - -bool OurReader::pushError(const Value& value, const std::string& message) { - size_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = end_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = 0; - errors_.push_back(info); - return true; -} - -bool OurReader::pushError(const Value& value, const std::string& message, const Value& extra) { - size_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length - || extra.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = begin_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = begin_ + extra.getOffsetStart(); - errors_.push_back(info); - return true; -} - -bool OurReader::good() const { - return !errors_.size(); -} - class OurCharReader : public CharReader { bool const collectComments_; @@ -1878,6 +1737,7 @@ 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) @@ -1892,6 +1752,7 @@ 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 { @@ -1925,6 +1786,7 @@ void CharReaderBuilder::strictMode(Json::Value* settings) (*settings)["allowSingleQuotes"] = false; (*settings)["failIfExtra"] = true; (*settings)["rejectDupKeys"] = true; + (*settings)["allowSpecialFloats"] = false; //! [CharReaderBuilderStrictMode] } // static @@ -1940,6 +1802,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) (*settings)["stackLimit"] = 1000; (*settings)["failIfExtra"] = false; (*settings)["rejectDupKeys"] = false; + (*settings)["allowSpecialFloats"] = false; //! [CharReaderBuilderDefaults] } diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 9a16491d0..44b507012 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -18,7 +18,9 @@ #endif #include // size_t #include // min() - +#if defined(__BORLANDC__) +#include +#endif #define JSON_ASSERT_UNREACHABLE assert(false) namespace Json { @@ -29,12 +31,13 @@ namespace Json { #if defined(__ARMEL__) #define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) #else +// This exists for binary compatibility only. Use nullRef. +const Value Value::null; #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; +const Value& Value::nullRef = reinterpret_cast(kNullRef); const Int Value::minInt = Int(~(UInt(-1) / 2)); const Int Value::maxInt = Int(UInt(-1) / 2); @@ -167,11 +170,11 @@ RuntimeError::RuntimeError(std::string const& msg) LogicError::LogicError(std::string const& msg) : Exception(msg) {} -void throwRuntimeError(std::string const& msg) +JSONCPP_NORETURN void throwRuntimeError(std::string const& msg) { throw RuntimeError(msg); } -void throwLogicError(std::string const& msg) +JSONCPP_NORETURN void throwLogicError(std::string const& msg) { throw LogicError(msg); } @@ -384,7 +387,7 @@ Value::Value(bool value) { Value::Value(Value const& other) : type_(other.type_), allocated_(false) , - comments_(0), start_(other.start_), limit_(other.limit_) + comments_(0) { switch (type_) { case nullValue: @@ -449,8 +452,9 @@ Value::~Value() { delete[] comments_; } -Value& Value::operator=(Value other) { - swap(other); +Value &Value::operator=(const Value &other) { + Value temp(other); + swap(temp); return *this; } @@ -467,8 +471,6 @@ void Value::swapPayload(Value& other) { void Value::swap(Value& other) { swapPayload(other); std::swap(comments_, other.comments_); - std::swap(start_, other.start_); - std::swap(limit_, other.limit_); } ValueType Value::type() const { return type_; } @@ -871,8 +873,6 @@ void Value::clear() { JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || type_ == objectValue, "in Json::Value::clear(): requires complex value"); - start_ = 0; - limit_ = 0; switch (type_) { case arrayValue: case objectValue: @@ -948,8 +948,6 @@ void Value::initBasic(ValueType vtype, bool allocated) { type_ = vtype; allocated_ = allocated; comments_ = 0; - start_ = 0; - limit_ = 0; } // Access an object value by name, create a null member if it does not exist. @@ -1319,14 +1317,6 @@ std::string Value::getComment(CommentPlacement placement) const { return ""; } -void Value::setOffsetStart(size_t start) { start_ = start; } - -void Value::setOffsetLimit(size_t limit) { limit_ = limit; } - -size_t Value::getOffsetStart() const { return start_; } - -size_t Value::getOffsetLimit() const { return limit_; } - std::string Value::toStyledString() const { StyledWriter writer; return writer.write(*this); diff --git a/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp index 2f940c8a4..3646df435 100644 --- a/src/lib_json/json_writer.cpp +++ b/src/lib_json/json_writer.cpp @@ -16,6 +16,9 @@ #include #include +#if defined(__BORLANDC__) +#include +#endif #if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0 #include #define isfinite _finite @@ -27,8 +30,14 @@ #define isfinite std::isfinite #endif -#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else #define snprintf _snprintf +#endif #elif defined(__ANDROID__) #define snprintf snprintf #elif __cplusplus >= 201103L @@ -48,10 +57,10 @@ namespace Json { -#if __cplusplus >= 201103L -typedef std::unique_ptr StreamWriterPtr; +#if JSON_HAS_UNIQUE_PTR +typedef std::unique_ptr const StreamWriterPtr; #else -typedef std::auto_ptr StreamWriterPtr; +typedef std::auto_ptr StreamWriterPtr; #endif static bool containsControlCharacter(const char* str) { @@ -75,12 +84,15 @@ static bool containsControlCharacter0(const char* str, unsigned len) { std::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; } @@ -105,43 +117,38 @@ std::string valueToString(UInt value) { #endif // # if defined(JSON_HAS_INT64) -std::string valueToString(double value) { +std::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]; int len = -1; -// Print into the buffer. We need not request the alternative representation -// that always has a decimal point because JSON doesn't distingish the -// concepts of reals and integers. -#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with - // visual studio 2005 to - // avoid warning. -#if defined(WINCE) - len = _snprintf(buffer, sizeof(buffer), "%.17g", value); -#else - len = sprintf_s(buffer, sizeof(buffer), "%.17g", value); -#endif -#else + char formatString[6]; + sprintf(formatString, "%%.%dg", precision); + + // Print into the buffer. We need not request the alternative representation + // that always has a decimal point because JSON doesn't distingish the + // concepts of reals and integers. if (isfinite(value)) { - len = snprintf(buffer, sizeof(buffer), "%.17g", value); + len = snprintf(buffer, sizeof(buffer), formatString, value); } 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(double value) { return valueToString(value, false, 17); } + std::string valueToString(bool value) { return value ? "true" : "false"; } std::string valueToQuotedString(const char* value) { @@ -292,28 +299,21 @@ Writer::~Writer() {} // ////////////////////////////////////////////////////////////////// FastWriter::FastWriter() - : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), - omitEndingLineFeed_(false) {} + : yamlCompatiblityEnabled_(false) {} void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } -void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } - -void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } - std::string FastWriter::write(const Value& root) { document_ = ""; writeValue(root); - if (!omitEndingLineFeed_) - document_ += "\n"; + document_ += "\n"; return document_; } void FastWriter::writeValue(const Value& value) { switch (value.type()) { case nullValue: - if (!dropNullPlaceholders_) - document_ += "null"; + document_ += "null"; break; case intValue: document_ += valueToString(value.asLargestInt()); @@ -813,7 +813,9 @@ struct BuiltStyledStreamWriter : public StreamWriter CommentStyle::Enum cs, std::string const& colonSymbol, std::string const& nullSymbol, - std::string const& endingLineFeedSymbol); + std::string const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision); virtual int write(Value const& root, std::ostream* sout); private: void writeValue(Value const& value); @@ -840,13 +842,17 @@ struct BuiltStyledStreamWriter : public StreamWriter std::string endingLineFeedSymbol_; bool addChildValues_ : 1; bool indented_ : 1; + bool useSpecialFloats_ : 1; + unsigned int precision_; }; BuiltStyledStreamWriter::BuiltStyledStreamWriter( std::string const& indentation, CommentStyle::Enum cs, std::string const& colonSymbol, std::string const& nullSymbol, - std::string const& endingLineFeedSymbol) + std::string const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision) : rightMargin_(74) , indentation_(indentation) , cs_(cs) @@ -855,6 +861,8 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter( , endingLineFeedSymbol_(endingLineFeedSymbol) , addChildValues_(false) , indented_(false) + , useSpecialFloats_(useSpecialFloats) + , precision_(precision) { } int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout) @@ -884,7 +892,7 @@ 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: { @@ -1099,6 +1107,8 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const std::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; @@ -1117,10 +1127,11 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const if (dnp) { nullSymbol = ""; } + if (pre > 17) pre = 17; std::string endingLineFeedSymbol = ""; return new BuiltStyledStreamWriter( indentation, cs, - colonSymbol, nullSymbol, endingLineFeedSymbol); + colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre); } static void getValidWriterKeys(std::set* valid_keys) { @@ -1129,6 +1140,8 @@ static void getValidWriterKeys(std::set* valid_keys) 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 { @@ -1159,6 +1172,8 @@ void StreamWriterBuilder::setDefaults(Json::Value* settings) (*settings)["indentation"] = "\t"; (*settings)["enableYAMLCompatibility"] = false; (*settings)["dropNullPlaceholders"] = false; + (*settings)["useSpecialFloats"] = false; + (*settings)["precision"] = 17; //! [StreamWriterBuilderDefaults] } diff --git a/src/test_lib_json/CMakeLists.txt b/src/test_lib_json/CMakeLists.txt index f54c85f68..7000264a7 100644 --- a/src/test_lib_json/CMakeLists.txt +++ b/src/test_lib_json/CMakeLists.txt @@ -12,7 +12,7 @@ IF(BUILD_SHARED_LIBS) TARGET_LINK_LIBRARIES(jsoncpp_test jsoncpp_lib) ELSE(BUILD_SHARED_LIBS) TARGET_LINK_LIBRARIES(jsoncpp_test jsoncpp_lib_static) -ENDIF(BUILD_SHARED_LIBS) +ENDIF() # another way to solve issue #90 #set_target_properties(jsoncpp_test PROPERTIES COMPILE_FLAGS -ffloat-store) @@ -32,7 +32,7 @@ IF(JSONCPP_WITH_POST_BUILD_UNITTEST) ADD_CUSTOM_COMMAND( TARGET jsoncpp_test POST_BUILD COMMAND $) - ENDIF(BUILD_SHARED_LIBS) -ENDIF(JSONCPP_WITH_POST_BUILD_UNITTEST) + ENDIF() +ENDIF() SET_TARGET_PROPERTIES(jsoncpp_test PROPERTIES OUTPUT_NAME jsoncpp_test) diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 0d4284e53..b9ca9c290 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -7,6 +7,7 @@ #include #include #include +#include // Make numeric limits more convenient to talk about. // Assumes int type in 32 bits. @@ -296,7 +297,10 @@ JSONTEST_FIXTURE(ValueTest, null) { JSONTEST_ASSERT_EQUAL(0.0, null_.asFloat()); JSONTEST_ASSERT_STRING_EQUAL("", null_.asString()); +#if !defined(__ARMEL__) + // See line #165 of include/json/value.h JSONTEST_ASSERT_EQUAL(Json::Value::null, null_); +#endif } JSONTEST_FIXTURE(ValueTest, strings) { @@ -1212,7 +1216,7 @@ JSONTEST_FIXTURE(ValueTest, nonIntegers) { JSONTEST_ASSERT_EQUAL(-2147483648.5, val.asDouble()); JSONTEST_ASSERT_EQUAL(float(-2147483648.5), val.asFloat()); #ifdef JSON_HAS_INT64 - JSONTEST_ASSERT_EQUAL(-Json::Int64(1) << 31, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(-(Json::Int64(1) << 31), val.asLargestInt()); #endif JSONTEST_ASSERT_EQUAL(true, val.asBool()); JSONTEST_ASSERT_EQUAL("-2147483648.5", @@ -1254,7 +1258,7 @@ JSONTEST_FIXTURE(ValueTest, nonIntegers) { // A 16-digit floating point number. val = Json::Value(2199023255552000.0f); - JSONTEST_ASSERT_EQUAL(float(2199023255552000), val.asFloat()); + JSONTEST_ASSERT_EQUAL(float(2199023255552000.0f), val.asFloat()); JSONTEST_ASSERT_STRING_EQUAL("2199023255552000", normalizeFloatingPointStr(val.asString())); @@ -1512,25 +1516,6 @@ JSONTEST_FIXTURE(ValueTest, typeChecksThrowExceptions) { #endif } -JSONTEST_FIXTURE(ValueTest, offsetAccessors) { - Json::Value x; - JSONTEST_ASSERT(x.getOffsetStart() == 0); - JSONTEST_ASSERT(x.getOffsetLimit() == 0); - x.setOffsetStart(10); - x.setOffsetLimit(20); - JSONTEST_ASSERT(x.getOffsetStart() == 10); - JSONTEST_ASSERT(x.getOffsetLimit() == 20); - Json::Value y(x); - JSONTEST_ASSERT(y.getOffsetStart() == 10); - JSONTEST_ASSERT(y.getOffsetLimit() == 20); - Json::Value z; - z.swap(y); - JSONTEST_ASSERT(z.getOffsetStart() == 10); - JSONTEST_ASSERT(z.getOffsetLimit() == 20); - JSONTEST_ASSERT(y.getOffsetStart() == 0); - JSONTEST_ASSERT(y.getOffsetLimit() == 0); -} - JSONTEST_FIXTURE(ValueTest, StaticString) { char mutant[] = "hello"; Json::StaticString ss(mutant); @@ -1651,15 +1636,61 @@ JSONTEST_FIXTURE(ValueTest, zeroesInKeys) { } } -struct WriterTest : JsonTest::TestCase {}; +JSONTEST_FIXTURE(ValueTest, specialFloats) { + Json::StreamWriterBuilder b; + b.settings_["useSpecialFloats"] = true; + + Json::Value v = std::numeric_limits::quiet_NaN(); + std::string expected = "NaN"; + std::string result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + v = std::numeric_limits::infinity(); + expected = "Infinity"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + v = -std::numeric_limits::infinity(); + expected = "-Infinity"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); +} -JSONTEST_FIXTURE(WriterTest, dropNullPlaceholders) { - Json::FastWriter writer; - Json::Value nullValue; - JSONTEST_ASSERT(writer.write(nullValue) == "null\n"); +JSONTEST_FIXTURE(ValueTest, precision) { + Json::StreamWriterBuilder b; + b.settings_["precision"] = 5; + + Json::Value v = 100.0/3; + std::string expected = "33.333"; + std::string result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + v = 0.25000000; + expected = "0.25"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + v = 0.2563456; + expected = "0.25635"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); - writer.dropNullPlaceholders(); - JSONTEST_ASSERT(writer.write(nullValue) == "\n"); + b.settings_["precision"] = 1; + expected = "0.3"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + b.settings_["precision"] = 17; + v = 1234857476305.256345694873740545068; + expected = "1234857476305.2563"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + b.settings_["precision"] = 24; + v = 0.256345694873740545068; + expected = "0.25634569487374054"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); } struct StreamWriterTest : JsonTest::TestCase {}; @@ -1703,7 +1734,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithNoErrors) { bool ok = reader.parse("{ \"property\" : \"value\" }", root); JSONTEST_ASSERT(ok); JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0); - JSONTEST_ASSERT(reader.getStructuredErrors().size() == 0); } JSONTEST_FIXTURE(ReaderTest, parseWithNoErrorsTestingOffsets) { @@ -1715,25 +1745,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithNoErrorsTestingOffsets) { root); JSONTEST_ASSERT(ok); JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0); - JSONTEST_ASSERT(reader.getStructuredErrors().size() == 0); - JSONTEST_ASSERT(root["property"].getOffsetStart() == 15); - JSONTEST_ASSERT(root["property"].getOffsetLimit() == 34); - JSONTEST_ASSERT(root["property"][0].getOffsetStart() == 16); - JSONTEST_ASSERT(root["property"][0].getOffsetLimit() == 23); - JSONTEST_ASSERT(root["property"][1].getOffsetStart() == 25); - JSONTEST_ASSERT(root["property"][1].getOffsetLimit() == 33); - JSONTEST_ASSERT(root["obj"].getOffsetStart() == 44); - JSONTEST_ASSERT(root["obj"].getOffsetLimit() == 76); - JSONTEST_ASSERT(root["obj"]["nested"].getOffsetStart() == 57); - JSONTEST_ASSERT(root["obj"]["nested"].getOffsetLimit() == 60); - JSONTEST_ASSERT(root["obj"]["bool"].getOffsetStart() == 71); - JSONTEST_ASSERT(root["obj"]["bool"].getOffsetLimit() == 75); - JSONTEST_ASSERT(root["null"].getOffsetStart() == 87); - JSONTEST_ASSERT(root["null"].getOffsetLimit() == 91); - JSONTEST_ASSERT(root["false"].getOffsetStart() == 103); - JSONTEST_ASSERT(root["false"].getOffsetLimit() == 108); - JSONTEST_ASSERT(root.getOffsetStart() == 0); - JSONTEST_ASSERT(root.getOffsetLimit() == 110); } JSONTEST_FIXTURE(ReaderTest, parseWithOneError) { @@ -1744,13 +1755,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithOneError) { JSONTEST_ASSERT(reader.getFormattedErrorMessages() == "* Line 1, Column 15\n Syntax error: value, object or array " "expected.\n"); - std::vector errors = - reader.getStructuredErrors(); - JSONTEST_ASSERT(errors.size() == 1); - JSONTEST_ASSERT(errors.at(0).offset_start == 14); - JSONTEST_ASSERT(errors.at(0).offset_limit == 15); - JSONTEST_ASSERT(errors.at(0).message == - "Syntax error: value, object or array expected."); } JSONTEST_FIXTURE(ReaderTest, parseChineseWithOneError) { @@ -1761,13 +1765,6 @@ JSONTEST_FIXTURE(ReaderTest, parseChineseWithOneError) { JSONTEST_ASSERT(reader.getFormattedErrorMessages() == "* Line 1, Column 19\n Syntax error: value, object or array " "expected.\n"); - std::vector errors = - reader.getStructuredErrors(); - JSONTEST_ASSERT(errors.size() == 1); - JSONTEST_ASSERT(errors.at(0).offset_start == 18); - JSONTEST_ASSERT(errors.at(0).offset_limit == 19); - JSONTEST_ASSERT(errors.at(0).message == - "Syntax error: value, object or array expected."); } JSONTEST_FIXTURE(ReaderTest, parseWithDetailError) { @@ -1778,12 +1775,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithDetailError) { JSONTEST_ASSERT(reader.getFormattedErrorMessages() == "* Line 1, Column 16\n Bad escape sequence in string\nSee " "Line 1, Column 20 for detail.\n"); - std::vector errors = - reader.getStructuredErrors(); - JSONTEST_ASSERT(errors.size() == 1); - JSONTEST_ASSERT(errors.at(0).offset_start == 15); - JSONTEST_ASSERT(errors.at(0).offset_limit == 23); - JSONTEST_ASSERT(errors.at(0).message == "Bad escape sequence in string"); } struct CharReaderTest : JsonTest::TestCase {}; @@ -1924,7 +1915,7 @@ JSONTEST_FIXTURE(CharReaderStrictModeTest, dupKeys) { struct CharReaderFailIfExtraTest : JsonTest::TestCase {}; JSONTEST_FIXTURE(CharReaderFailIfExtraTest, issue164) { - // This is interpretted as a string value followed by a colon. + // This is interpreted as a string value followed by a colon. Json::CharReaderBuilder b; Json::Value root; char const doc[] = @@ -2259,6 +2250,81 @@ JSONTEST_FIXTURE(CharReaderAllowZeroesTest, issue176) { delete reader; } +struct CharReaderAllowSpecialFloatsTest : JsonTest::TestCase {}; + +JSONTEST_FIXTURE(CharReaderAllowSpecialFloatsTest, issue209) { + Json::CharReaderBuilder b; + b.settings_["allowSpecialFloats"] = true; + Json::Value root; + std::string errs; + Json::CharReader* reader(b.newCharReader()); + { + char const doc[] = "{\"a\":NaN,\"b\":Infinity,\"c\":-Infinity}"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(3u, root.size()); + double n = root["a"].asDouble(); + JSONTEST_ASSERT(n != n); + JSONTEST_ASSERT_EQUAL(std::numeric_limits::infinity(), root.get("b", 0.0)); + JSONTEST_ASSERT_EQUAL(-std::numeric_limits::infinity(), root.get("c", 0.0)); + } + + struct TestData { + int line; + bool ok; + std::string in; + }; + const TestData test_data[] = { + {__LINE__, 1, "{\"a\":9}"}, + {__LINE__, 0, "{\"a\":0Infinity}"}, + {__LINE__, 0, "{\"a\":1Infinity}"}, + {__LINE__, 0, "{\"a\":9Infinity}"}, + {__LINE__, 0, "{\"a\":0nfinity}"}, + {__LINE__, 0, "{\"a\":1nfinity}"}, + {__LINE__, 0, "{\"a\":9nfinity}"}, + {__LINE__, 0, "{\"a\":nfinity}"}, + {__LINE__, 0, "{\"a\":.nfinity}"}, + {__LINE__, 0, "{\"a\":9nfinity}"}, + {__LINE__, 0, "{\"a\":-nfinity}"}, + {__LINE__, 1, "{\"a\":Infinity}"}, + {__LINE__, 0, "{\"a\":.Infinity}"}, + {__LINE__, 0, "{\"a\":_Infinity}"}, + {__LINE__, 0, "{\"a\":_nfinity}"}, + {__LINE__, 1, "{\"a\":-Infinity}"} + }; + for (size_t tdi = 0; tdi < sizeof(test_data) / sizeof(*test_data); ++tdi) { + const TestData& td = test_data[tdi]; + bool ok = reader->parse(&*td.in.begin(), + &*td.in.begin() + td.in.size(), + &root, &errs); + JSONTEST_ASSERT(td.ok == ok) + << "line:" << td.line << "\n" + << " expected: {" + << "ok:" << td.ok + << ", in:\'" << td.in << "\'" + << "}\n" + << " actual: {" + << "ok:" << ok + << "}\n"; + } + + { + char const doc[] = "{\"posInf\": Infinity, \"NegInf\": -Infinity}"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(2u, root.size()); + JSONTEST_ASSERT_EQUAL(std::numeric_limits::infinity(), root["posInf"].asDouble()); + JSONTEST_ASSERT_EQUAL(-std::numeric_limits::infinity(), root["NegInf"].asDouble()); + } + delete reader; +} + struct BuilderTest : JsonTest::TestCase {}; JSONTEST_FIXTURE(BuilderTest, settings) { @@ -2355,15 +2421,15 @@ int main(int argc, const char* argv[]) { JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareArray); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareObject); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareType); - JSONTEST_REGISTER_FIXTURE(runner, ValueTest, offsetAccessors); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, typeChecksThrowExceptions); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, StaticString); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, CommentBefore); //JSONTEST_REGISTER_FIXTURE(runner, ValueTest, nulls); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroes); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroesInKeys); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, specialFloats); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, precision); - JSONTEST_REGISTER_FIXTURE(runner, WriterTest, dropNullPlaceholders); JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders); JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, writeZeroes); @@ -2396,6 +2462,8 @@ int main(int argc, const char* argv[]) { JSONTEST_REGISTER_FIXTURE(runner, CharReaderAllowZeroesTest, issue176); + JSONTEST_REGISTER_FIXTURE(runner, CharReaderAllowSpecialFloatsTest, issue209); + JSONTEST_REGISTER_FIXTURE(runner, BuilderTest, settings); JSONTEST_REGISTER_FIXTURE(runner, IteratorTest, distance); diff --git a/version b/version index 9f05f9f2c..2d993c425 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.6.5 +0.10.7