Compare commits

...

68 Commits

Author SHA1 Message Date
Christopher Dunn
5ec82e482c 0.10.6 <- 0.10.5 2016-04-22 00:28:53 -05:00
Christopher Dunn
b84332249b Merge pull request #463 from jmealins/fix-errors-as-warnings
Fix JSONCPP_WITH_WARNING_AS_ERROR
2016-04-21 04:12:43 -05:00
jmealins
cb3b38c3ea fix if alignment 2016-04-20 15:04:27 -07:00
jmealins
226f7a2b6b Fix JSONCPP_WITH_WARNING_AS_ERROR
in 0.y.z branch -Werror was always being added regardless of the
what JSONCPP_WITH_WARNING_AS_ERROR was set to. Additionally,
-std=c++11 was being set on Clang builds.
2016-04-20 14:31:46 -07:00
Christopher Dunn
d2fc18af7f Merge pull request #446 from ya1gaurav/patch-37
NORETURN for throw functions in 0.x.y branch
2016-03-17 20:54:48 -05:00
Gaurav
aec261a899 NORETURN for throw functions in 0.x.y branch
Added in definition also.
2016-03-16 11:23:36 +05:30
Gaurav
20564b3f0c NORETURN for throw functions in 0.x.y branch
Resolve issue - https://github.com/open-source-parsers/jsoncpp/issues/389
2016-03-16 11:22:18 +05:30
Benjamin Knecht
0fc51120c0 Add test code for precision
Conflicts:
	src/test_lib_json/main.cpp
2016-02-06 09:32:31 -06:00
Benjamin Knecht
4a984c24b5 making precision unsigned int
adding precision as settings value for StreamBuilder

Conflicts:
	src/lib_json/json_writer.cpp
2016-02-06 09:32:30 -06:00
Benjamin Knecht
2f9a6a682c Create format string with sprintf.
For now use hardcoded precision '17' for now
2016-02-06 09:32:30 -06:00
Christopher Dunn
26159b96f1 Merge pull request #413 from cdunn2001/debian-patches
Debian patches - 0.y.z branch

See #411.
  http://anonscm.debian.org/cgit/collab-maint/libjsoncpp.git/tree/debian/patches
2016-02-06 09:31:31 -06:00
Christopher Dunn
e105003bb5 gcc-6 lacks auto_ptr<> 2016-02-06 08:24:20 -06:00
Christopher Dunn
dde8426ded 0001-multiarch-path-support.patch 2016-02-06 08:10:54 -06:00
Christopher Dunn
ecfd658e6a 0003-fix-arm.patch
Already applied to 0.y.x branch.
2016-02-06 08:04:11 -06:00
Christopher Dunn
eec6794106 fix-double-parsing.patch 2016-02-06 08:03:34 -06:00
Christopher Dunn
0ea25978d5 0004-fix-include-path.patch 2016-02-06 07:58:50 -06:00
Christopher Dunn
9297822cde Merge pull request #349 from cdunn2001/special-floats
Merge pull request #339 from Dani-Hub/master
2015-09-05 12:22:37 -05:00
Christopher Dunn
a4354d782b Merge pull request #339 from Dani-Hub/master
Floating-point NaN or Infinity values should be allowed as a feature …
2015-09-05 12:16:28 -05:00
Christopher Dunn
a7b80fea65 Merge pull request #337 from AMDmi3/patch-1
Specify float constant as float
2015-09-05 12:08:45 -05:00
Robert Dailey
8bdb07dd52 Clean up cmake END* (again)
(I missed a couple. ~cd)
2015-08-14 14:48:45 -07:00
Robert Dailey
22dade5c97 Clean up cmake END*
* Clean up closing statements for if conditions, functions, macros,
  and other entities. Newer versions of CMake do not require you to
  redundantly respecify the parameters to the opening arguments.
2015-08-14 14:42:55 -07:00
Christopher Dunn
1380aff595 add .gitattributes
helps #325
2015-08-09 17:11:16 -07:00
Christopher Dunn
8644269675 normalized some windows VS stuff 2015-08-09 17:11:00 -07:00
Robert Dailey
28dcc3589a Normalize line endings
This commit contains nothing but line ending normalization
changes. These changes were performed after the introduction
of .gitattributes into the repository.
2015-08-09 17:10:47 -07:00
Robert Dailey
aaf3417654 Add .gitattributes file 2015-08-09 17:10:28 -07:00
Aaron Jacobs
22ec823cc7 Remove undefined behavior from a left shift of a negative value.
Fixed by shifting a positive value, then negating the result.

(Credit: Richard Trieu)
2015-08-09 11:05:22 -07:00
Jörg Krause
ffea45bbe1 Remove Werror
-Werror shouldn't be used in released code since it can cause random build
failures on moderate warnings. It also depends on the used toolchain since
different toolchains may or may not print the same warnings.
2015-08-09 11:05:22 -07:00
Michael Shields
1b32e3e869 Fix cases where the most negative signed integer was negated, causing
undefined behavior.
2015-08-09 11:04:09 -07:00
Christopher Dunn
18e4d04e8e merged from 1.6.5 2015-07-23 00:32:47 -05:00
Christopher Dunn
d48bff5fcb gcc-4.6 in Travis
and clang-3.0, the default
2015-07-12 15:02:28 -05:00
Christopher Dunn
93d74678da Merge pull request #315 from cdunn2001/0.y.z
-Werror

and fixed a minor bug found by -Wshadow
2015-07-12 14:52:00 -05:00
Christopher Dunn
ed5d73fe1d 0.6.4 2015-07-12 14:47:59 -05:00
Christopher Dunn
b97e624ac1 -Werror 2015-07-12 14:47:58 -05:00
Christopher Dunn
542354902e fixed a bug found by -Wshadow 2015-07-12 14:47:37 -05:00
Christopher Dunn
17360f3d4b fix some warnings 2015-07-12 14:47:37 -05:00
Christopher Dunn
75747db30c -Wshadow
* https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
* http://programmers.stackexchange.com/questions/122608/clang-warning-flags-for-objective-c-development/124574#124574

In clang: `-Wconversion` implies `-Wshorten-64-to-32`, but we cannot use
`-Wconversion` yet.
2015-07-12 14:47:35 -05:00
Christopher Dunn
02839ef5b1 Merge pull request #310 from cdunn2001/0.y.z
gcc-4.6, clang-3.3
2015-07-12 09:55:20 -05:00
Christopher Dunn
138c48b7e8 gcc-4.6, clang-3.3 2015-07-12 09:50:14 -05:00
Christopher Dunn
72fb4a5b08 valgrind in Travis 2015-07-11 14:26:11 -05:00
Christopher Dunn
c6fa959318 dockerize the Travis build
Docker builds are *much* faster in Travis.

Also, we prepare to enable C++11.
2015-07-11 14:26:11 -05:00
Christopher Dunn
fb1301274f Merge pull request #308 from cdunn2001/0.y.z
0.10.3

No significant changes.
2015-07-11 14:07:55 -05:00
Christopher Dunn
7670e5151b 0.10.3 2015-07-11 13:53:05 -05:00
Mike Naberezny
2e185081b2 Fix undefined name "sys"
Same as #299 (bca0eff81a1c5ef160d9858b8e89b1c919b71c1f), but an earlier
commit needed to be rebased.
2015-07-11 13:52:27 -05:00
Stuart Eichert
cb8259f545 Fix #296: Explicitly cast size_t results to unsigned when needed
This is rebased from #297, where AppVeyor had been failing, and which
was not properly based on the master branch.
2015-07-11 13:52:27 -05:00
Stuart Eichert
bb5d0249ed Warn about implicit 64 to 32 bit conversions when using clang 2015-07-11 13:52:08 -05:00
Martyn Gigg
710260d070 Allow an optional suffix on the debug library name in CMake. 2015-07-11 13:51:40 -05:00
Christopher Dunn
dbda2aa36f Merge pull request #307 from cdunn2001/gaurav-fix-warnings
fix warnings (-Wno-long-long and unused tokenStart)

* closes #300
* closes #301
2015-07-11 12:02:22 -05:00
Gaurav
ef38374e99 Gcc warning unused "tokenStart"
(was #301)

In `0.y.z` branch, `tokenStart` is not used.
Comment it as done in other cases.
2015-07-11 11:57:21 -05:00
Gaurav
f1cafb6ded GCC warning removal for long long
(was #300)

I got below warning message on x86 linux machine :
```
"jsoncpp-0.10.2-p1/include/json/config.h💯 warning: ISO C++ 1998 does not support ‘long long’"
gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC)
```
In reference to

* https://github.com/open-source-parsers/jsoncpp/pull/292

**long long** is supported in c++-11; for old compilers i.e `0.y.z` branch this patch should be merged.
2015-07-11 11:55:13 -05:00
Christopher Dunn
a13303e456 Merge pull request #306 from cdunn2001/0.y.z
fix appveyor 32-bit windows build
2015-07-11 11:52:16 -05:00
Christopher Dunn
7bc97db496 fix appveyor 32-bit windows build
* http://help.appveyor.com/discussions/problems/2229-v140-not-found-on-vs2105rc
```
Done Building Project "C:\projects\jsoncpp\jsoncpp.sln" (default targets) -- FAILED.

Build FAILED.

"C:\projects\jsoncpp\jsoncpp.sln" (default target) (1) ->
"C:\projects\jsoncpp\ALL_BUILD.vcxproj.metaproj" (default target) (2) ->
"C:\projects\jsoncpp\ZERO_CHECK.vcxproj" (default target) (3) ->
(PlatformPrepareForBuild target) ->
  C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.Cpp.Platform.targets(64,5): error MSB8020: The build tools for v140 (Platform Toolset = 'v140') cannot be found. To build using the v140 build tools, please install v140 build tools.  Alternatively, you may upgrade to the current Visual Studio tools by selecting the Project menu or right-click the solution, and then selecting "Upgrade Solution...". [C:\projects\jsoncpp\ZERO_CHECK.vcxproj]
```
2015-07-11 11:36:28 -05:00
Christopher Dunn
17181acf74 Merge remote-tracking branch 'up/master' into 0.y.z
fix ,/. problem in #294
2015-06-19 00:11:52 -05:00
Christopher Dunn
07623b71f2 Merge branch 'master' into 0.y.z 2015-06-18 22:34:40 -05:00
Christopher Dunn
f1ff13767c Merge pull request #291 from cdunn2001/0.y.z
fix #290
2015-06-10 22:05:45 -05:00
Christopher Dunn
2760c7902a fix #290 2015-06-10 21:22:24 -05:00
Christopher Dunn
f40dd0f3ed Merge branch 'master' into 0.y.z
BORLANDC compilation issues
2015-04-28 05:09:58 +01:00
Christopher Dunn
c334ac0376 Merge branch 'master' into 0.y.z
- fix for "C++ Builder" IDE
- Travis CI/AppVeyor
- **cmake** tweak
- fix memory leak in unit-test

See #268 and #252.
2015-04-27 18:33:07 -07:00
Christopher Dunn
c66cc277f5 Merge pull request #249 from cdunn2001/master
Merge appveyor changes into 0.y.z
2015-04-18 18:27:32 -07:00
Sam Clegg
db7ad75794 Don't use unique_ptr on pre-c++11 branch
Don't use C++11 unique_ptr in the 0.y.z branch.
Although this usage is guarded with __cplusplus >= 201103
some build configurations (notably chromium) use a
C++11-compliant compiler but a pre-11 library.

pull #238
2015-04-12 00:39:25 -05:00
Christopher Dunn
f4bdc1b602 partially revert 'Added features that allow the reader to accept common non-standard JSON.'
revert '642befc836ac5093b528e7d8b4fd66b66735a98c',
but keep the *added* methods for `decodedNumber()` and `decodedDouble()`.
2015-04-11 14:49:59 -05:00
Christopher Dunn
93f45d065c partially revert 'fix bug for static init'
re: 28836b8acc2c002b0488c13dba28fd5be864970a

A global instance of a Value (viz. 'null') was a mistake,
but dropping it breaks binary-compatibility. So we will keep it
everywhere except the one platform where it was crashing, ARM.
2015-04-11 14:49:59 -05:00
Christopher Dunn
6f6ddaa91c revert 'Made it possible to drop null placeholders from array output.'
revert ae3c7a7aabfb345968a65001ea9bc25f1e2bb405
2015-04-11 14:49:59 -05:00
Christopher Dunn
254fe6a07a Revert "added option to FastWriter which omits the trailing new line character"
This reverts commit 5bf16105b5a90f9fa7d5d4d43452feee46603a52.
2015-04-11 14:49:59 -05:00
Christopher Dunn
00d7bea0f6 revert 'Added structured error reporting to Reader.'
revert 68db6553471bb9cb050b1bb888b5933ee758b82d
issue #147
2015-04-11 14:49:59 -05:00
Christopher Dunn
a9d06d2650 revert 'Add public semantic error reporting'
for binary-compatibility with 0.6.0
issue #147
was #57
2015-04-11 14:49:59 -05:00
Christopher Dunn
1c4f6a2d79 partially revert "Switch to copy-and-swap idiom for operator=."
This partially reverts commit 45cd9490cd261da31cef84a44d2c587be7e26e99.

Ignored ValueInternal* changes, since those did not produce symbols for
Debian build. (They must not have used the INTERNAL stuff.)

Ignored CZString changes since those are private (and sizeof struct did
not change).

  https://github.com/open-source-parsers/jsoncpp/issues/78

Conflicts:
	include/json/value.h
	src/lib_json/json_internalarray.inl
	src/lib_json/json_internalmap.inl
	src/lib_json/json_value.cpp
2015-04-11 14:49:59 -05:00
Christopher Dunn
e49bd30950 NOT C++11 2015-04-11 14:49:59 -05:00
Christopher Dunn
13d78e3da3 0.10.z (based on 1.6.z, but binary-compat w/ 0.6.0-rc2) 2015-04-11 14:49:59 -05:00
23 changed files with 937 additions and 1044 deletions

11
.gitattributes vendored Normal file
View File

@ -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

View File

@ -8,23 +8,22 @@
install: install:
# /usr/bin/gcc is 4.6 always, but gcc-X.Y is available. # /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. # /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} - echo ${PATH}
- ls /usr/local - ls /usr/local
- ls /usr/local/bin - export PATH=/usr/bin:${PATH}
- export PATH=/usr/local/bin:/usr/bin:${PATH}
- echo ${CXX} - echo ${CXX}
- ${CXX} --version - ${CXX} --version
- which valgrind
addons: addons:
apt: apt:
sources: sources:
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
packages: packages:
- gcc-4.9 - gcc-4.6
- g++-4.9 - g++-4.6
- clang - clang
- valgrind - valgrind
os: os:

View File

@ -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_SHARED_LIBS "Build jsoncpp_lib as a shared library." OFF)
OPTION(BUILD_STATIC_LIBS "Build jsoncpp_lib static library." ON) OPTION(BUILD_STATIC_LIBS "Build jsoncpp_lib static library." ON)
include(GNUInstallDirs)
# Ensures that CMAKE_BUILD_TYPE is visible in cmake-gui on Unix # Ensures that CMAKE_BUILD_TYPE is visible in cmake-gui on Unix
IF(NOT WIN32) IF(NOT WIN32)
IF(NOT CMAKE_BUILD_TYPE) IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE Release CACHE STRING SET(CMAKE_BUILD_TYPE Release CACHE STRING
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage." "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage."
FORCE) FORCE)
ENDIF(NOT CMAKE_BUILD_TYPE) ENDIF()
ENDIF(NOT WIN32) ENDIF()
SET(DEBUG_LIBNAME_SUFFIX "" CACHE STRING "Optional suffix to append to the library name for a debug build") 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") 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") CACHE PATH "Install dir for static libraries")
SET(LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX} SET(LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}
CACHE PATH "Install dir for shared libraries") 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") CACHE PATH "Install dir for headers")
SET(PACKAGE_INSTALL_DIR lib${LIB_SUFFIX}/cmake SET(PACKAGE_INSTALL_DIR lib${LIB_SUFFIX}/cmake
CACHE PATH "Install dir for cmake package config files") 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} # Set variable named ${VAR_NAME} to value ${VALUE}
FUNCTION(set_using_dynamic_name VAR_NAME VALUE) FUNCTION(set_using_dynamic_name VAR_NAME VALUE)
SET( "${VAR_NAME}" "${VALUE}" PARENT_SCOPE) SET( "${VAR_NAME}" "${VALUE}" PARENT_SCOPE)
ENDFUNCTION(set_using_dynamic_name) ENDFUNCTION()
# Extract major, minor, patch from version text # Extract major, minor, patch from version text
# Parse a version string "X.Y.Z" and outputs # 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 ) set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" TRUE )
ELSE( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} ) ELSE( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} )
set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" FALSE ) set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" FALSE )
ENDIF( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} ) ENDIF()
ENDMACRO(jsoncpp_parse_version) ENDMACRO()
# Read out version from "version" file # Read out version from "version" file
#FILE(STRINGS "version" JSONCPP_VERSION) #FILE(STRINGS "version" JSONCPP_VERSION)
#SET( JSONCPP_VERSION_MAJOR X ) #SET( JSONCPP_VERSION_MAJOR X )
#SET( JSONCPP_VERSION_MINOR Y ) #SET( JSONCPP_VERSION_MINOR Y )
#SET( JSONCPP_VERSION_PATCH Z ) #SET( JSONCPP_VERSION_PATCH Z )
SET( JSONCPP_VERSION 1.6.5 ) SET( JSONCPP_VERSION 0.10.6 )
jsoncpp_parse_version( ${JSONCPP_VERSION} JSONCPP_VERSION ) jsoncpp_parse_version( ${JSONCPP_VERSION} JSONCPP_VERSION )
#IF(NOT JSONCPP_VERSION_FOUND) #IF(NOT JSONCPP_VERSION_FOUND)
# MESSAGE(FATAL_ERROR "Failed to parse version string properly. Expect X.Y.Z") # 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 ) NEWLINE_STYLE UNIX )
macro(UseCompilationWarningAsError) macro(UseCompilationWarningAsError)
if ( MSVC ) if ( MSVC )
# Only enabled in debug because some old versions of VS STL generate # Only enabled in debug because some old versions of VS STL generate
# warnings when compiled in release configuration. # warnings when compiled in release configuration.
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /WX ") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /WX ")
endif( MSVC ) elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_XX_COMPILER_ID MATCHES "Clang" )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
endif()
endmacro() endmacro()
# Include our configuration header # Include our configuration header
@ -93,20 +97,20 @@ if ( MSVC )
# Only enabled in debug because some old versions of VS STL generate # Only enabled in debug because some old versions of VS STL generate
# unreachable code warning when compiled in release configuration. # unreachable code warning when compiled in release configuration.
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /W4 ") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /W4 ")
endif( MSVC ) endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# using regular Clang or AppleClang # using regular Clang or AppleClang
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Werror -Wall -Wconversion -Wshadow -Wno-sign-conversion") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wshadow -Wshorten-64-to-32")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# using GCC # 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 # not yet ready for -Wsign-conversion
endif() endif()
IF(JSONCPP_WITH_WARNING_AS_ERROR) IF(JSONCPP_WITH_WARNING_AS_ERROR)
UseCompilationWarningAsError() UseCompilationWarningAsError()
ENDIF(JSONCPP_WITH_WARNING_AS_ERROR) ENDIF()
IF(JSONCPP_WITH_PKGCONFIG_SUPPORT) IF(JSONCPP_WITH_PKGCONFIG_SUPPORT)
CONFIGURE_FILE( CONFIGURE_FILE(
@ -114,14 +118,14 @@ IF(JSONCPP_WITH_PKGCONFIG_SUPPORT)
"pkg-config/jsoncpp.pc" "pkg-config/jsoncpp.pc"
@ONLY) @ONLY)
INSTALL(FILES "${CMAKE_BINARY_DIR}/pkg-config/jsoncpp.pc" INSTALL(FILES "${CMAKE_BINARY_DIR}/pkg-config/jsoncpp.pc"
DESTINATION "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/pkgconfig") DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
ENDIF(JSONCPP_WITH_PKGCONFIG_SUPPORT) ENDIF()
IF(JSONCPP_WITH_CMAKE_PACKAGE) IF(JSONCPP_WITH_CMAKE_PACKAGE)
INSTALL(EXPORT jsoncpp INSTALL(EXPORT jsoncpp
DESTINATION ${PACKAGE_INSTALL_DIR}/jsoncpp DESTINATION ${PACKAGE_INSTALL_DIR}/jsoncpp
FILE jsoncppConfig.cmake) FILE jsoncppConfig.cmake)
ENDIF(JSONCPP_WITH_CMAKE_PACKAGE) ENDIF()
# Build the different applications # Build the different applications
ADD_SUBDIRECTORY( src ) ADD_SUBDIRECTORY( src )

View File

@ -44,12 +44,6 @@ public:
/// \c true if root must be either an array or an object value. Default: \c /// \c true if root must be either an array or an object value. Default: \c
/// false. /// false.
bool strictRoot_; 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 } // namespace Json

View File

@ -35,18 +35,6 @@ public:
typedef char Char; typedef char Char;
typedef const Char* Location; 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 /** \brief Constructs a Reader allowing all features
* for parsing. * for parsing.
*/ */
@ -123,38 +111,6 @@ public:
*/ */
std::string getFormattedErrorMessages() const; 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<StructuredError> 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: private:
enum TokenType { enum TokenType {
tokenEndOfStream = 0, tokenEndOfStream = 0,
@ -321,6 +277,9 @@ public:
the JSON value in the input string. the JSON value in the input string.
- `"rejectDupKeys": false or true` - `"rejectDupKeys": false or true`
- If true, `parse()` returns false when a key is duplicated within an object. - 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 You can examine 'settings_` yourself
to see the defaults. You can also write and read them just like any to see the defaults. You can also write and read them just like any

View File

@ -29,6 +29,19 @@
#pragma warning(disable : 4251) #pragma warning(disable : 4251)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #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). /** \brief JSON (JavaScript Object Notation).
*/ */
namespace Json { namespace Json {
@ -69,9 +82,9 @@ public:
}; };
/// used internally /// used internally
void throwRuntimeError(std::string const& msg); JSONCPP_NORETURN void throwRuntimeError(std::string const& msg);
/// used internally /// 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. /** \brief Type of the value held by a Value object.
*/ */
@ -175,8 +188,11 @@ public:
typedef Json::LargestUInt LargestUInt; typedef Json::LargestUInt LargestUInt;
typedef Json::ArrayIndex ArrayIndex; typedef Json::ArrayIndex ArrayIndex;
static const Value& null; ///< We regret this reference to a global instance; prefer the simpler Value(). static const Value& nullRef;
static const Value& nullRef; ///< just a kludge for binary-compatibility; same as null #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. /// Minimum signed integer value that can be stored in a Json::Value.
static const LargestInt minLargestInt; static const LargestInt minLargestInt;
/// Maximum signed integer value that can be stored in a Json::Value. /// Maximum signed integer value that can be stored in a Json::Value.
@ -298,7 +314,7 @@ Json::Value obj_value(Json::objectValue); // {}
/// Deep copy, then swap(other). /// Deep copy, then swap(other).
/// \note Over-write existing comments. To preserve comments, use #swapPayload(). /// \note Over-write existing comments. To preserve comments, use #swapPayload().
Value& operator=(Value other); Value &operator=(const Value &other);
/// Swap everything. /// Swap everything.
void swap(Value& other); void swap(Value& other);
/// Swap values but leave comments and source offsets in place. /// Swap values but leave comments and source offsets in place.
@ -545,13 +561,6 @@ Json::Value obj_value(Json::objectValue); // {}
iterator begin(); iterator begin();
iterator end(); 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: private:
void initBasic(ValueType type, bool allocated = false); void initBasic(ValueType type, bool allocated = false);
@ -588,11 +597,6 @@ private:
unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
// If not allocated_, string_ must be null-terminated. // If not allocated_, string_ must be null-terminated.
CommentInfo* comments_; 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 /** \brief Experimental and untested: represents an element of the "path" to

View File

@ -3,10 +3,10 @@
#ifndef JSON_VERSION_H_INCLUDED #ifndef JSON_VERSION_H_INCLUDED
# define JSON_VERSION_H_INCLUDED # define JSON_VERSION_H_INCLUDED
# define JSONCPP_VERSION_STRING "1.6.5" # define JSONCPP_VERSION_STRING "0.10.6"
# define JSONCPP_VERSION_MAJOR 1 # define JSONCPP_VERSION_MAJOR 0
# define JSONCPP_VERSION_MINOR 6 # define JSONCPP_VERSION_MINOR 10
# define JSONCPP_VERSION_PATCH 5 # define JSONCPP_VERSION_PATCH 6
# define JSONCPP_VERSION_QUALIFIER # define JSONCPP_VERSION_QUALIFIER
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) # define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))

View File

@ -99,6 +99,10 @@ public:
Strictly speaking, this is not valid JSON. But when the output is being 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. 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 You can examine 'settings_` yourself
to see the defaults. You can also write and read them just like any to see the defaults. You can also write and read them just like any
@ -158,15 +162,6 @@ public:
void enableYAMLCompatibility(); 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 public: // overridden from Writer
virtual std::string write(const Value& root); virtual std::string write(const Value& root);
@ -175,8 +170,6 @@ private:
std::string document_; std::string document_;
bool yamlCompatiblityEnabled_; bool yamlCompatiblityEnabled_;
bool dropNullPlaceholders_;
bool omitEndingLineFeed_;
}; };
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a

View File

@ -2,4 +2,4 @@ ADD_SUBDIRECTORY(lib_json)
IF(JSONCPP_WITH_TESTS) IF(JSONCPP_WITH_TESTS)
ADD_SUBDIRECTORY(jsontestrunner) ADD_SUBDIRECTORY(jsontestrunner)
ADD_SUBDIRECTORY(test_lib_json) ADD_SUBDIRECTORY(test_lib_json)
ENDIF(JSONCPP_WITH_TESTS) ENDIF()

View File

@ -9,7 +9,7 @@ IF(BUILD_SHARED_LIBS)
TARGET_LINK_LIBRARIES(jsontestrunner_exe jsoncpp_lib) TARGET_LINK_LIBRARIES(jsontestrunner_exe jsoncpp_lib)
ELSE(BUILD_SHARED_LIBS) ELSE(BUILD_SHARED_LIBS)
TARGET_LINK_LIBRARIES(jsontestrunner_exe jsoncpp_lib_static) TARGET_LINK_LIBRARIES(jsontestrunner_exe jsoncpp_lib_static)
ENDIF(BUILD_SHARED_LIBS) ENDIF()
SET_TARGET_PROPERTIES(jsontestrunner_exe PROPERTIES OUTPUT_NAME jsontestrunner_exe) SET_TARGET_PROPERTIES(jsontestrunner_exe PROPERTIES OUTPUT_NAME jsontestrunner_exe)
@ -22,4 +22,4 @@ IF(PYTHONINTERP_FOUND)
DEPENDS jsontestrunner_exe jsoncpp_test DEPENDS jsontestrunner_exe jsoncpp_test
) )
ADD_CUSTOM_TARGET(jsoncpp_check DEPENDS jsoncpp_readerwriter_tests) ADD_CUSTOM_TARGET(jsoncpp_check DEPENDS jsoncpp_readerwriter_tests)
ENDIF(PYTHONINTERP_FOUND) ENDIF()

View File

@ -37,7 +37,7 @@ IF(JSONCPP_WITH_CMAKE_PACKAGE)
SET(INSTALL_EXPORT EXPORT jsoncpp) SET(INSTALL_EXPORT EXPORT jsoncpp)
ELSE(JSONCPP_WITH_CMAKE_PACKAGE) ELSE(JSONCPP_WITH_CMAKE_PACKAGE)
SET(INSTALL_EXPORT) SET(INSTALL_EXPORT)
ENDIF(JSONCPP_WITH_CMAKE_PACKAGE) ENDIF()
IF(BUILD_SHARED_LIBS) IF(BUILD_SHARED_LIBS)
ADD_DEFINITIONS( -DJSON_DLL_BUILD ) ADD_DEFINITIONS( -DJSON_DLL_BUILD )
@ -48,14 +48,14 @@ IF(BUILD_SHARED_LIBS)
INSTALL( TARGETS jsoncpp_lib ${INSTALL_EXPORT} INSTALL( TARGETS jsoncpp_lib ${INSTALL_EXPORT}
RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR} RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR}
LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR} LIBRARY DESTINATION "${LIBRARY_INSTALL_DIR}/${CMAKE_LIBRARY_ARCHITECTURE}"
ARCHIVE DESTINATION ${ARCHIVE_INSTALL_DIR}) ARCHIVE DESTINATION "${ARCHIVE_INSTALL_DIR}/${CMAKE_LIBRARY_ARCHITECTURE}")
IF(NOT CMAKE_VERSION VERSION_LESS 2.8.11) IF(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
TARGET_INCLUDE_DIRECTORIES( jsoncpp_lib PUBLIC TARGET_INCLUDE_DIRECTORIES( jsoncpp_lib PUBLIC
$<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}> $<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>) $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>)
ENDIF(NOT CMAKE_VERSION VERSION_LESS 2.8.11) ENDIF()
ENDIF() ENDIF()
@ -67,14 +67,14 @@ IF(BUILD_STATIC_LIBS)
INSTALL( TARGETS jsoncpp_lib_static ${INSTALL_EXPORT} INSTALL( TARGETS jsoncpp_lib_static ${INSTALL_EXPORT}
RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR} RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR}
LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR} LIBRARY DESTINATION "${LIBRARY_INSTALL_DIR}/${CMAKE_LIBRARY_ARCHITECTURE}"
ARCHIVE DESTINATION ${ARCHIVE_INSTALL_DIR}) ARCHIVE DESTINATION "${ARCHIVE_INSTALL_DIR}/${CMAKE_LIBRARY_ARCHITECTURE}")
IF(NOT CMAKE_VERSION VERSION_LESS 2.8.11) IF(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
TARGET_INCLUDE_DIRECTORIES( jsoncpp_lib_static PUBLIC TARGET_INCLUDE_DIRECTORIES( jsoncpp_lib_static PUBLIC
$<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}> $<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
) )
ENDIF(NOT CMAKE_VERSION VERSION_LESS 2.8.11) ENDIF()
ENDIF() ENDIF()

View File

@ -17,10 +17,21 @@
#include <sstream> #include <sstream>
#include <memory> #include <memory>
#include <set> #include <set>
#include <limits>
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below #if defined(_MSC_VER)
#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
#define snprintf sprintf_s
#elif _MSC_VER >= 1900 // VC++ 14.0 and above
#define snprintf std::snprintf
#else
#define snprintf _snprintf #define snprintf _snprintf
#endif #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 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
// Disable warning about strdup being deprecated. // Disable warning about strdup being deprecated.
@ -32,27 +43,24 @@ static int stackDepth_g = 0; // see readValue()
namespace Json { namespace Json {
#if __cplusplus >= 201103L #if __GNUC__ >= 6
typedef std::unique_ptr<CharReader> CharReaderPtr; typedef std::scoped_ptr<CharReader> const CharReaderPtr;
#else #else
typedef std::auto_ptr<CharReader> CharReaderPtr; typedef std::auto_ptr<CharReader> CharReaderPtr;
#endif #endif
// Implementation of class Features // Implementation of class Features
// //////////////////////////////// // ////////////////////////////////
Features::Features() Features::Features()
: allowComments_(true), strictRoot_(false), : allowComments_(true), strictRoot_(false)
allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} {}
Features Features::all() { return Features(); } Features Features::all() { return Features(); }
Features Features::strictMode() { Features Features::strictMode() {
Features features; Features features;
features.allowComments_ = false; features.allowComments_ = false;
features.strictRoot_ = true; features.strictRoot_ = true;
features.allowDroppedNullPlaceholders_ = false;
features.allowNumericKeys_ = false;
return features; return features;
} }
@ -162,11 +170,9 @@ bool Reader::readValue() {
switch (token.type_) { switch (token.type_) {
case tokenObjectBegin: case tokenObjectBegin:
successful = readObject(token); successful = readObject(token);
currentValue().setOffsetLimit(current_ - begin_);
break; break;
case tokenArrayBegin: case tokenArrayBegin:
successful = readArray(token); successful = readArray(token);
currentValue().setOffsetLimit(current_ - begin_);
break; break;
case tokenNumber: case tokenNumber:
successful = decodeNumber(token); successful = decodeNumber(token);
@ -178,42 +184,22 @@ bool Reader::readValue() {
{ {
Value v(true); Value v(true);
currentValue().swapPayload(v); currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} }
break; break;
case tokenFalse: case tokenFalse:
{ {
Value v(false); Value v(false);
currentValue().swapPayload(v); currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} }
break; break;
case tokenNull: case tokenNull:
{ {
Value v; Value v;
currentValue().swapPayload(v); currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} }
break; break;
case tokenArraySeparator: // Else, fall through...
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...
default: default:
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return addError("Syntax error: value, object or array expected.", token); return addError("Syntax error: value, object or array expected.", token);
} }
@ -441,12 +427,11 @@ bool Reader::readString() {
return c == '"'; return c == '"';
} }
bool Reader::readObject(Token& tokenStart) { bool Reader::readObject(Token& /*tokenStart*/) {
Token tokenName; Token tokenName;
std::string name; std::string name;
Value init(objectValue); Value init(objectValue);
currentValue().swapPayload(init); currentValue().swapPayload(init);
currentValue().setOffsetStart(tokenStart.start_ - begin_);
while (readToken(tokenName)) { while (readToken(tokenName)) {
bool initialTokenOk = true; bool initialTokenOk = true;
while (tokenName.type_ == tokenComment && initialTokenOk) while (tokenName.type_ == tokenComment && initialTokenOk)
@ -459,11 +444,6 @@ bool Reader::readObject(Token& tokenStart) {
if (tokenName.type_ == tokenString) { if (tokenName.type_ == tokenString) {
if (!decodeString(tokenName, name)) if (!decodeString(tokenName, name))
return recoverFromError(tokenObjectEnd); return recoverFromError(tokenObjectEnd);
} else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
Value numberName;
if (!decodeNumber(tokenName, numberName))
return recoverFromError(tokenObjectEnd);
name = numberName.asString();
} else { } else {
break; break;
} }
@ -497,10 +477,9 @@ bool Reader::readObject(Token& tokenStart) {
"Missing '}' or object member name", tokenName, tokenObjectEnd); "Missing '}' or object member name", tokenName, tokenObjectEnd);
} }
bool Reader::readArray(Token& tokenStart) { bool Reader::readArray(Token& /*tokenStart*/) {
Value init(arrayValue); Value init(arrayValue);
currentValue().swapPayload(init); currentValue().swapPayload(init);
currentValue().setOffsetStart(tokenStart.start_ - begin_);
skipSpaces(); skipSpaces();
if (*current_ == ']') // empty array if (*current_ == ']') // empty array
{ {
@ -540,8 +519,6 @@ bool Reader::decodeNumber(Token& token) {
if (!decodeNumber(token, decoded)) if (!decodeNumber(token, decoded))
return false; return false;
currentValue().swapPayload(decoded); currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true; return true;
} }
@ -555,7 +532,7 @@ bool Reader::decodeNumber(Token& token, Value& decoded) {
++current; ++current;
// TODO: Help the compiler do the div and mod at compile time or get rid of them. // TODO: Help the compiler do the div and mod at compile time or get rid of them.
Value::LargestUInt maxIntegerValue = Value::LargestUInt maxIntegerValue =
isNegative ? Value::LargestUInt(-Value::minLargestInt) isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
: Value::maxLargestUInt; : Value::maxLargestUInt;
Value::LargestUInt threshold = maxIntegerValue / 10; Value::LargestUInt threshold = maxIntegerValue / 10;
Value::LargestUInt value = 0; Value::LargestUInt value = 0;
@ -576,7 +553,9 @@ bool Reader::decodeNumber(Token& token, Value& decoded) {
} }
value = value * 10 + digit; value = value * 10 + digit;
} }
if (isNegative) if (isNegative && value == maxIntegerValue)
decoded = Value::minLargestInt;
else if (isNegative)
decoded = -Value::LargestInt(value); decoded = -Value::LargestInt(value);
else if (value <= Value::LargestUInt(Value::maxInt)) else if (value <= Value::LargestUInt(Value::maxInt))
decoded = Value::LargestInt(value); decoded = Value::LargestInt(value);
@ -590,8 +569,6 @@ bool Reader::decodeDouble(Token& token) {
if (!decodeDouble(token, decoded)) if (!decodeDouble(token, decoded))
return false; return false;
currentValue().swapPayload(decoded); currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true; return true;
} }
@ -613,8 +590,6 @@ bool Reader::decodeString(Token& token) {
return false; return false;
Value decoded(decoded_string); Value decoded(decoded_string);
currentValue().swapPayload(decoded); currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true; return true;
} }
@ -793,15 +768,7 @@ std::string Reader::getLocationLineAndColumn(Location location) const {
int line, column; int line, column;
getLocationLineAndColumn(location, line, column); getLocationLineAndColumn(location, line, column);
char buffer[18 + 16 + 16 + 1]; 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); snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
#endif
return buffer; return buffer;
} }
@ -826,59 +793,8 @@ std::string Reader::getFormattedErrorMessages() const {
return formattedMessage; return formattedMessage;
} }
std::vector<Reader::StructuredError> Reader::getStructuredErrors() const { // Reader
std::vector<Reader::StructuredError> 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();
}
// exact copy of Features // exact copy of Features
class OurFeatures { class OurFeatures {
@ -892,6 +808,7 @@ public:
bool allowSingleQuotes_; bool allowSingleQuotes_;
bool failIfExtra_; bool failIfExtra_;
bool rejectDupKeys_; bool rejectDupKeys_;
bool allowSpecialFloats_;
int stackLimit_; int stackLimit_;
}; // OurFeatures }; // OurFeatures
@ -903,6 +820,7 @@ OurFeatures::OurFeatures()
, allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) , allowDroppedNullPlaceholders_(false), allowNumericKeys_(false)
, allowSingleQuotes_(false) , allowSingleQuotes_(false)
, failIfExtra_(false) , failIfExtra_(false)
, allowSpecialFloats_(false)
{ {
} }
@ -928,10 +846,6 @@ public:
Value& root, Value& root,
bool collectComments = true); bool collectComments = true);
std::string getFormattedErrorMessages() const; std::string getFormattedErrorMessages() const;
std::vector<StructuredError> getStructuredErrors() const;
bool pushError(const Value& value, const std::string& message);
bool pushError(const Value& value, const std::string& message, const Value& extra);
bool good() const;
private: private:
OurReader(OurReader const&); // no impl OurReader(OurReader const&); // no impl
@ -948,6 +862,9 @@ private:
tokenTrue, tokenTrue,
tokenFalse, tokenFalse,
tokenNull, tokenNull,
tokenNaN,
tokenPosInf,
tokenNegInf,
tokenArraySeparator, tokenArraySeparator,
tokenMemberSeparator, tokenMemberSeparator,
tokenComment, tokenComment,
@ -978,7 +895,7 @@ private:
bool readCppStyleComment(); bool readCppStyleComment();
bool readString(); bool readString();
bool readStringSingleQuote(); bool readStringSingleQuote();
void readNumber(); bool readNumber(bool checkInf);
bool readValue(); bool readValue();
bool readObject(Token& token); bool readObject(Token& token);
bool readArray(Token& token); bool readArray(Token& token);
@ -1096,11 +1013,9 @@ bool OurReader::readValue() {
switch (token.type_) { switch (token.type_) {
case tokenObjectBegin: case tokenObjectBegin:
successful = readObject(token); successful = readObject(token);
currentValue().setOffsetLimit(current_ - begin_);
break; break;
case tokenArrayBegin: case tokenArrayBegin:
successful = readArray(token); successful = readArray(token);
currentValue().setOffsetLimit(current_ - begin_);
break; break;
case tokenNumber: case tokenNumber:
successful = decodeNumber(token); successful = decodeNumber(token);
@ -1112,24 +1027,36 @@ bool OurReader::readValue() {
{ {
Value v(true); Value v(true);
currentValue().swapPayload(v); currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} }
break; break;
case tokenFalse: case tokenFalse:
{ {
Value v(false); Value v(false);
currentValue().swapPayload(v); currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} }
break; break;
case tokenNull: case tokenNull:
{ {
Value v; Value v;
currentValue().swapPayload(v); currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_); }
currentValue().setOffsetLimit(token.end_ - begin_); break;
case tokenNaN:
{
Value v(std::numeric_limits<double>::quiet_NaN());
currentValue().swapPayload(v);
}
break;
case tokenPosInf:
{
Value v(std::numeric_limits<double>::infinity());
currentValue().swapPayload(v);
}
break;
case tokenNegInf:
{
Value v(-std::numeric_limits<double>::infinity());
currentValue().swapPayload(v);
} }
break; break;
case tokenArraySeparator: case tokenArraySeparator:
@ -1141,13 +1068,9 @@ bool OurReader::readValue() {
current_--; current_--;
Value v; Value v;
currentValue().swapPayload(v); currentValue().swapPayload(v);
currentValue().setOffsetStart(current_ - begin_ - 1);
currentValue().setOffsetLimit(current_ - begin_);
break; break;
} // else, fall through ... } // else, fall through ...
default: default:
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return addError("Syntax error: value, object or array expected.", token); return addError("Syntax error: value, object or array expected.", token);
} }
@ -1212,9 +1135,16 @@ bool OurReader::readToken(Token& token) {
case '7': case '7':
case '8': case '8':
case '9': case '9':
case '-':
token.type_ = tokenNumber; 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; break;
case 't': case 't':
token.type_ = tokenTrue; token.type_ = tokenTrue;
@ -1228,6 +1158,22 @@ bool OurReader::readToken(Token& token) {
token.type_ = tokenNull; token.type_ = tokenNull;
ok = match("ull", 3); ok = match("ull", 3);
break; 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 ',': case ',':
token.type_ = tokenArraySeparator; token.type_ = tokenArraySeparator;
break; break;
@ -1328,8 +1274,12 @@ bool OurReader::readCppStyleComment() {
return true; return true;
} }
void OurReader::readNumber() { bool OurReader::readNumber(bool checkInf) {
const char *p = current_; const char *p = current_;
if (checkInf && p != end_ && *p == 'I') {
current_ = ++p;
return false;
}
char c = '0'; // stopgap for already consumed character char c = '0'; // stopgap for already consumed character
// integral part // integral part
while (c >= '0' && c <= '9') while (c >= '0' && c <= '9')
@ -1348,6 +1298,7 @@ void OurReader::readNumber() {
while (c >= '0' && c <= '9') while (c >= '0' && c <= '9')
c = (current_ = p) < end_ ? *p++ : 0; c = (current_ = p) < end_ ? *p++ : 0;
} }
return true;
} }
bool OurReader::readString() { bool OurReader::readString() {
Char c = 0; Char c = 0;
@ -1374,12 +1325,11 @@ bool OurReader::readStringSingleQuote() {
return c == '\''; return c == '\'';
} }
bool OurReader::readObject(Token& tokenStart) { bool OurReader::readObject(Token& /*tokenStart*/) {
Token tokenName; Token tokenName;
std::string name; std::string name;
Value init(objectValue); Value init(objectValue);
currentValue().swapPayload(init); currentValue().swapPayload(init);
currentValue().setOffsetStart(tokenStart.start_ - begin_);
while (readToken(tokenName)) { while (readToken(tokenName)) {
bool initialTokenOk = true; bool initialTokenOk = true;
while (tokenName.type_ == tokenComment && initialTokenOk) while (tokenName.type_ == tokenComment && initialTokenOk)
@ -1436,10 +1386,9 @@ bool OurReader::readObject(Token& tokenStart) {
"Missing '}' or object member name", tokenName, tokenObjectEnd); "Missing '}' or object member name", tokenName, tokenObjectEnd);
} }
bool OurReader::readArray(Token& tokenStart) { bool OurReader::readArray(Token& /*tokenStart*/) {
Value init(arrayValue); Value init(arrayValue);
currentValue().swapPayload(init); currentValue().swapPayload(init);
currentValue().setOffsetStart(tokenStart.start_ - begin_);
skipSpaces(); skipSpaces();
if (*current_ == ']') // empty array if (*current_ == ']') // empty array
{ {
@ -1479,8 +1428,6 @@ bool OurReader::decodeNumber(Token& token) {
if (!decodeNumber(token, decoded)) if (!decodeNumber(token, decoded))
return false; return false;
currentValue().swapPayload(decoded); currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true; return true;
} }
@ -1529,40 +1476,14 @@ bool OurReader::decodeDouble(Token& token) {
if (!decodeDouble(token, decoded)) if (!decodeDouble(token, decoded))
return false; return false;
currentValue().swapPayload(decoded); currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true; return true;
} }
bool OurReader::decodeDouble(Token& token, Value& decoded) { bool OurReader::decodeDouble(Token& token, Value& decoded) {
double value = 0; double value = 0;
const int bufferSize = 32; std::string buffer( token.start_, token.end_ );
int count; std::istringstream is(buffer);
int length = int(token.end_ - token.start_); if (!(is >> value))
// 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_) + return addError("'" + std::string(token.start_, token.end_) +
"' is not a number.", "' is not a number.",
token); token);
@ -1576,8 +1497,6 @@ bool OurReader::decodeString(Token& token) {
return false; return false;
Value decoded(decoded_string); Value decoded(decoded_string);
currentValue().swapPayload(decoded); currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true; return true;
} }
@ -1756,15 +1675,7 @@ std::string OurReader::getLocationLineAndColumn(Location location) const {
int line, column; int line, column;
getLocationLineAndColumn(location, line, column); getLocationLineAndColumn(location, line, column);
char buffer[18 + 16 + 16 + 1]; 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); snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
#endif
return buffer; return buffer;
} }
@ -1784,60 +1695,6 @@ std::string OurReader::getFormattedErrorMessages() const {
return formattedMessage; return formattedMessage;
} }
std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
std::vector<OurReader::StructuredError> 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 { class OurCharReader : public CharReader {
bool const collectComments_; bool const collectComments_;
@ -1878,6 +1735,7 @@ CharReader* CharReaderBuilder::newCharReader() const
features.stackLimit_ = settings_["stackLimit"].asInt(); features.stackLimit_ = settings_["stackLimit"].asInt();
features.failIfExtra_ = settings_["failIfExtra"].asBool(); features.failIfExtra_ = settings_["failIfExtra"].asBool();
features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
return new OurCharReader(collectComments, features); return new OurCharReader(collectComments, features);
} }
static void getValidReaderKeys(std::set<std::string>* valid_keys) static void getValidReaderKeys(std::set<std::string>* valid_keys)
@ -1892,6 +1750,7 @@ static void getValidReaderKeys(std::set<std::string>* valid_keys)
valid_keys->insert("stackLimit"); valid_keys->insert("stackLimit");
valid_keys->insert("failIfExtra"); valid_keys->insert("failIfExtra");
valid_keys->insert("rejectDupKeys"); valid_keys->insert("rejectDupKeys");
valid_keys->insert("allowSpecialFloats");
} }
bool CharReaderBuilder::validate(Json::Value* invalid) const bool CharReaderBuilder::validate(Json::Value* invalid) const
{ {
@ -1925,6 +1784,7 @@ void CharReaderBuilder::strictMode(Json::Value* settings)
(*settings)["allowSingleQuotes"] = false; (*settings)["allowSingleQuotes"] = false;
(*settings)["failIfExtra"] = true; (*settings)["failIfExtra"] = true;
(*settings)["rejectDupKeys"] = true; (*settings)["rejectDupKeys"] = true;
(*settings)["allowSpecialFloats"] = false;
//! [CharReaderBuilderStrictMode] //! [CharReaderBuilderStrictMode]
} }
// static // static
@ -1940,6 +1800,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings)
(*settings)["stackLimit"] = 1000; (*settings)["stackLimit"] = 1000;
(*settings)["failIfExtra"] = false; (*settings)["failIfExtra"] = false;
(*settings)["rejectDupKeys"] = false; (*settings)["rejectDupKeys"] = false;
(*settings)["allowSpecialFloats"] = false;
//! [CharReaderBuilderDefaults] //! [CharReaderBuilderDefaults]
} }

View File

@ -29,12 +29,13 @@ namespace Json {
#if defined(__ARMEL__) #if defined(__ARMEL__)
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) #define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
#else #else
// This exists for binary compatibility only. Use nullRef.
const Value Value::null;
#define ALIGNAS(byte_alignment) #define ALIGNAS(byte_alignment)
#endif #endif
static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
const unsigned char& kNullRef = kNull[0]; const unsigned char& kNullRef = kNull[0];
const Value& Value::null = reinterpret_cast<const Value&>(kNullRef); const Value& Value::nullRef = reinterpret_cast<const Value&>(kNullRef);
const Value& Value::nullRef = null;
const Int Value::minInt = Int(~(UInt(-1) / 2)); const Int Value::minInt = Int(~(UInt(-1) / 2));
const Int Value::maxInt = Int(UInt(-1) / 2); const Int Value::maxInt = Int(UInt(-1) / 2);
@ -167,11 +168,11 @@ RuntimeError::RuntimeError(std::string const& msg)
LogicError::LogicError(std::string const& msg) LogicError::LogicError(std::string const& msg)
: Exception(msg) : Exception(msg)
{} {}
void throwRuntimeError(std::string const& msg) JSONCPP_NORETURN void throwRuntimeError(std::string const& msg)
{ {
throw RuntimeError(msg); throw RuntimeError(msg);
} }
void throwLogicError(std::string const& msg) JSONCPP_NORETURN void throwLogicError(std::string const& msg)
{ {
throw LogicError(msg); throw LogicError(msg);
} }
@ -384,7 +385,7 @@ Value::Value(bool value) {
Value::Value(Value const& other) Value::Value(Value const& other)
: type_(other.type_), allocated_(false) : type_(other.type_), allocated_(false)
, ,
comments_(0), start_(other.start_), limit_(other.limit_) comments_(0)
{ {
switch (type_) { switch (type_) {
case nullValue: case nullValue:
@ -449,8 +450,9 @@ Value::~Value() {
delete[] comments_; delete[] comments_;
} }
Value& Value::operator=(Value other) { Value &Value::operator=(const Value &other) {
swap(other); Value temp(other);
swap(temp);
return *this; return *this;
} }
@ -467,8 +469,6 @@ void Value::swapPayload(Value& other) {
void Value::swap(Value& other) { void Value::swap(Value& other) {
swapPayload(other); swapPayload(other);
std::swap(comments_, other.comments_); std::swap(comments_, other.comments_);
std::swap(start_, other.start_);
std::swap(limit_, other.limit_);
} }
ValueType Value::type() const { return type_; } ValueType Value::type() const { return type_; }
@ -871,8 +871,6 @@ void Value::clear() {
JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue ||
type_ == objectValue, type_ == objectValue,
"in Json::Value::clear(): requires complex value"); "in Json::Value::clear(): requires complex value");
start_ = 0;
limit_ = 0;
switch (type_) { switch (type_) {
case arrayValue: case arrayValue:
case objectValue: case objectValue:
@ -948,8 +946,6 @@ void Value::initBasic(ValueType vtype, bool allocated) {
type_ = vtype; type_ = vtype;
allocated_ = allocated; allocated_ = allocated;
comments_ = 0; comments_ = 0;
start_ = 0;
limit_ = 0;
} }
// Access an object value by name, create a null member if it does not exist. // Access an object value by name, create a null member if it does not exist.
@ -1319,14 +1315,6 @@ std::string Value::getComment(CommentPlacement placement) const {
return ""; 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 { std::string Value::toStyledString() const {
StyledWriter writer; StyledWriter writer;
return writer.write(*this); return writer.write(*this);

View File

@ -27,8 +27,14 @@
#define isfinite std::isfinite #define isfinite std::isfinite
#endif #endif
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below #if defined(_MSC_VER)
#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
#define snprintf sprintf_s
#elif _MSC_VER >= 1900 // VC++ 14.0 and above
#define snprintf std::snprintf
#else
#define snprintf _snprintf #define snprintf _snprintf
#endif
#elif defined(__ANDROID__) #elif defined(__ANDROID__)
#define snprintf snprintf #define snprintf snprintf
#elif __cplusplus >= 201103L #elif __cplusplus >= 201103L
@ -48,10 +54,10 @@
namespace Json { namespace Json {
#if __cplusplus >= 201103L #if __GNUC__ >= 6
typedef std::unique_ptr<StreamWriter> StreamWriterPtr; typedef std::scoped_ptr<StreamWriter> const StreamWriterPtr;
#else #else
typedef std::auto_ptr<StreamWriter> StreamWriterPtr; typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
#endif #endif
static bool containsControlCharacter(const char* str) { static bool containsControlCharacter(const char* str) {
@ -75,12 +81,15 @@ static bool containsControlCharacter0(const char* str, unsigned len) {
std::string valueToString(LargestInt value) { std::string valueToString(LargestInt value) {
UIntToStringBuffer buffer; UIntToStringBuffer buffer;
char* current = buffer + sizeof(buffer); char* current = buffer + sizeof(buffer);
bool isNegative = value < 0; if (value == Value::minLargestInt) {
if (isNegative) uintToString(LargestUInt(Value::maxLargestInt) + 1, current);
value = -value;
uintToString(LargestUInt(value), current);
if (isNegative)
*--current = '-'; *--current = '-';
} else if (value < 0) {
uintToString(LargestUInt(-value), current);
*--current = '-';
} else {
uintToString(LargestUInt(value), current);
}
assert(current >= buffer); assert(current >= buffer);
return current; return current;
} }
@ -105,43 +114,38 @@ std::string valueToString(UInt value) {
#endif // # if defined(JSON_HAS_INT64) #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 // Allocate a buffer that is more than large enough to store the 16 digits of
// precision requested below. // precision requested below.
char buffer[32]; char buffer[32];
int len = -1; int len = -1;
// Print into the buffer. We need not request the alternative representation char formatString[6];
// that always has a decimal point because JSON doesn't distingish the sprintf(formatString, "%%.%dg", precision);
// concepts of reals and integers.
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with // Print into the buffer. We need not request the alternative representation
// visual studio 2005 to // that always has a decimal point because JSON doesn't distingish the
// avoid warning. // concepts of reals and integers.
#if defined(WINCE)
len = _snprintf(buffer, sizeof(buffer), "%.17g", value);
#else
len = sprintf_s(buffer, sizeof(buffer), "%.17g", value);
#endif
#else
if (isfinite(value)) { if (isfinite(value)) {
len = snprintf(buffer, sizeof(buffer), "%.17g", value); len = snprintf(buffer, sizeof(buffer), formatString, value);
} else { } else {
// IEEE standard states that NaN values will not compare to themselves // IEEE standard states that NaN values will not compare to themselves
if (value != value) { if (value != value) {
len = snprintf(buffer, sizeof(buffer), "null"); len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");
} else if (value < 0) { } else if (value < 0) {
len = snprintf(buffer, sizeof(buffer), "-1e+9999"); len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999");
} else { } 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. // For those, we do not need to call fixNumLoc, but it is fast.
} }
#endif
assert(len >= 0); assert(len >= 0);
fixNumericLocale(buffer, buffer + len); fixNumericLocale(buffer, buffer + len);
return buffer; return buffer;
} }
std::string valueToString(double value) { return valueToString(value, false, 17); }
std::string valueToString(bool value) { return value ? "true" : "false"; } std::string valueToString(bool value) { return value ? "true" : "false"; }
std::string valueToQuotedString(const char* value) { std::string valueToQuotedString(const char* value) {
@ -292,28 +296,21 @@ Writer::~Writer() {}
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
FastWriter::FastWriter() FastWriter::FastWriter()
: yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), : yamlCompatiblityEnabled_(false) {}
omitEndingLineFeed_(false) {}
void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
std::string FastWriter::write(const Value& root) { std::string FastWriter::write(const Value& root) {
document_ = ""; document_ = "";
writeValue(root); writeValue(root);
if (!omitEndingLineFeed_) document_ += "\n";
document_ += "\n";
return document_; return document_;
} }
void FastWriter::writeValue(const Value& value) { void FastWriter::writeValue(const Value& value) {
switch (value.type()) { switch (value.type()) {
case nullValue: case nullValue:
if (!dropNullPlaceholders_) document_ += "null";
document_ += "null";
break; break;
case intValue: case intValue:
document_ += valueToString(value.asLargestInt()); document_ += valueToString(value.asLargestInt());
@ -813,7 +810,9 @@ struct BuiltStyledStreamWriter : public StreamWriter
CommentStyle::Enum cs, CommentStyle::Enum cs,
std::string const& colonSymbol, std::string const& colonSymbol,
std::string const& nullSymbol, 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); virtual int write(Value const& root, std::ostream* sout);
private: private:
void writeValue(Value const& value); void writeValue(Value const& value);
@ -840,13 +839,17 @@ private:
std::string endingLineFeedSymbol_; std::string endingLineFeedSymbol_;
bool addChildValues_ : 1; bool addChildValues_ : 1;
bool indented_ : 1; bool indented_ : 1;
bool useSpecialFloats_ : 1;
unsigned int precision_;
}; };
BuiltStyledStreamWriter::BuiltStyledStreamWriter( BuiltStyledStreamWriter::BuiltStyledStreamWriter(
std::string const& indentation, std::string const& indentation,
CommentStyle::Enum cs, CommentStyle::Enum cs,
std::string const& colonSymbol, std::string const& colonSymbol,
std::string const& nullSymbol, std::string const& nullSymbol,
std::string const& endingLineFeedSymbol) std::string const& endingLineFeedSymbol,
bool useSpecialFloats,
unsigned int precision)
: rightMargin_(74) : rightMargin_(74)
, indentation_(indentation) , indentation_(indentation)
, cs_(cs) , cs_(cs)
@ -855,6 +858,8 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter(
, endingLineFeedSymbol_(endingLineFeedSymbol) , endingLineFeedSymbol_(endingLineFeedSymbol)
, addChildValues_(false) , addChildValues_(false)
, indented_(false) , indented_(false)
, useSpecialFloats_(useSpecialFloats)
, precision_(precision)
{ {
} }
int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout) int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout)
@ -884,7 +889,7 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
pushValue(valueToString(value.asLargestUInt())); pushValue(valueToString(value.asLargestUInt()));
break; break;
case realValue: case realValue:
pushValue(valueToString(value.asDouble())); pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
break; break;
case stringValue: case stringValue:
{ {
@ -1099,6 +1104,8 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
std::string cs_str = settings_["commentStyle"].asString(); std::string cs_str = settings_["commentStyle"].asString();
bool eyc = settings_["enableYAMLCompatibility"].asBool(); bool eyc = settings_["enableYAMLCompatibility"].asBool();
bool dnp = settings_["dropNullPlaceholders"].asBool(); bool dnp = settings_["dropNullPlaceholders"].asBool();
bool usf = settings_["useSpecialFloats"].asBool();
unsigned int pre = settings_["precision"].asUInt();
CommentStyle::Enum cs = CommentStyle::All; CommentStyle::Enum cs = CommentStyle::All;
if (cs_str == "All") { if (cs_str == "All") {
cs = CommentStyle::All; cs = CommentStyle::All;
@ -1117,10 +1124,11 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
if (dnp) { if (dnp) {
nullSymbol = ""; nullSymbol = "";
} }
if (pre > 17) pre = 17;
std::string endingLineFeedSymbol = ""; std::string endingLineFeedSymbol = "";
return new BuiltStyledStreamWriter( return new BuiltStyledStreamWriter(
indentation, cs, indentation, cs,
colonSymbol, nullSymbol, endingLineFeedSymbol); colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);
} }
static void getValidWriterKeys(std::set<std::string>* valid_keys) static void getValidWriterKeys(std::set<std::string>* valid_keys)
{ {
@ -1129,6 +1137,8 @@ static void getValidWriterKeys(std::set<std::string>* valid_keys)
valid_keys->insert("commentStyle"); valid_keys->insert("commentStyle");
valid_keys->insert("enableYAMLCompatibility"); valid_keys->insert("enableYAMLCompatibility");
valid_keys->insert("dropNullPlaceholders"); valid_keys->insert("dropNullPlaceholders");
valid_keys->insert("useSpecialFloats");
valid_keys->insert("precision");
} }
bool StreamWriterBuilder::validate(Json::Value* invalid) const bool StreamWriterBuilder::validate(Json::Value* invalid) const
{ {
@ -1159,6 +1169,8 @@ void StreamWriterBuilder::setDefaults(Json::Value* settings)
(*settings)["indentation"] = "\t"; (*settings)["indentation"] = "\t";
(*settings)["enableYAMLCompatibility"] = false; (*settings)["enableYAMLCompatibility"] = false;
(*settings)["dropNullPlaceholders"] = false; (*settings)["dropNullPlaceholders"] = false;
(*settings)["useSpecialFloats"] = false;
(*settings)["precision"] = 17;
//! [StreamWriterBuilderDefaults] //! [StreamWriterBuilderDefaults]
} }

View File

@ -12,7 +12,7 @@ IF(BUILD_SHARED_LIBS)
TARGET_LINK_LIBRARIES(jsoncpp_test jsoncpp_lib) TARGET_LINK_LIBRARIES(jsoncpp_test jsoncpp_lib)
ELSE(BUILD_SHARED_LIBS) ELSE(BUILD_SHARED_LIBS)
TARGET_LINK_LIBRARIES(jsoncpp_test jsoncpp_lib_static) TARGET_LINK_LIBRARIES(jsoncpp_test jsoncpp_lib_static)
ENDIF(BUILD_SHARED_LIBS) ENDIF()
# another way to solve issue #90 # another way to solve issue #90
#set_target_properties(jsoncpp_test PROPERTIES COMPILE_FLAGS -ffloat-store) #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 ADD_CUSTOM_COMMAND( TARGET jsoncpp_test
POST_BUILD POST_BUILD
COMMAND $<TARGET_FILE:jsoncpp_test>) COMMAND $<TARGET_FILE:jsoncpp_test>)
ENDIF(BUILD_SHARED_LIBS) ENDIF()
ENDIF(JSONCPP_WITH_POST_BUILD_UNITTEST) ENDIF()
SET_TARGET_PROPERTIES(jsoncpp_test PROPERTIES OUTPUT_NAME jsoncpp_test) SET_TARGET_PROPERTIES(jsoncpp_test PROPERTIES OUTPUT_NAME jsoncpp_test)

View File

@ -7,6 +7,7 @@
#include <json/config.h> #include <json/config.h>
#include <json/json.h> #include <json/json.h>
#include <cstring> #include <cstring>
#include <limits>
// Make numeric limits more convenient to talk about. // Make numeric limits more convenient to talk about.
// Assumes int type in 32 bits. // Assumes int type in 32 bits.
@ -296,7 +297,10 @@ JSONTEST_FIXTURE(ValueTest, null) {
JSONTEST_ASSERT_EQUAL(0.0, null_.asFloat()); JSONTEST_ASSERT_EQUAL(0.0, null_.asFloat());
JSONTEST_ASSERT_STRING_EQUAL("", null_.asString()); JSONTEST_ASSERT_STRING_EQUAL("", null_.asString());
#if !defined(__ARMEL__)
// See line #165 of include/json/value.h
JSONTEST_ASSERT_EQUAL(Json::Value::null, null_); JSONTEST_ASSERT_EQUAL(Json::Value::null, null_);
#endif
} }
JSONTEST_FIXTURE(ValueTest, strings) { JSONTEST_FIXTURE(ValueTest, strings) {
@ -1212,7 +1216,7 @@ JSONTEST_FIXTURE(ValueTest, nonIntegers) {
JSONTEST_ASSERT_EQUAL(-2147483648.5, val.asDouble()); JSONTEST_ASSERT_EQUAL(-2147483648.5, val.asDouble());
JSONTEST_ASSERT_EQUAL(float(-2147483648.5), val.asFloat()); JSONTEST_ASSERT_EQUAL(float(-2147483648.5), val.asFloat());
#ifdef JSON_HAS_INT64 #ifdef JSON_HAS_INT64
JSONTEST_ASSERT_EQUAL(-Json::Int64(1) << 31, val.asLargestInt()); JSONTEST_ASSERT_EQUAL(-(Json::Int64(1) << 31), val.asLargestInt());
#endif #endif
JSONTEST_ASSERT_EQUAL(true, val.asBool()); JSONTEST_ASSERT_EQUAL(true, val.asBool());
JSONTEST_ASSERT_EQUAL("-2147483648.5", JSONTEST_ASSERT_EQUAL("-2147483648.5",
@ -1254,7 +1258,7 @@ JSONTEST_FIXTURE(ValueTest, nonIntegers) {
// A 16-digit floating point number. // A 16-digit floating point number.
val = Json::Value(2199023255552000.0f); 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", JSONTEST_ASSERT_STRING_EQUAL("2199023255552000",
normalizeFloatingPointStr(val.asString())); normalizeFloatingPointStr(val.asString()));
@ -1512,25 +1516,6 @@ JSONTEST_FIXTURE(ValueTest, typeChecksThrowExceptions) {
#endif #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) { JSONTEST_FIXTURE(ValueTest, StaticString) {
char mutant[] = "hello"; char mutant[] = "hello";
Json::StaticString ss(mutant); 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;
JSONTEST_FIXTURE(WriterTest, dropNullPlaceholders) { Json::Value v = std::numeric_limits<double>::quiet_NaN();
Json::FastWriter writer; std::string expected = "NaN";
Json::Value nullValue; std::string result = Json::writeString(b, v);
JSONTEST_ASSERT(writer.write(nullValue) == "null\n"); JSONTEST_ASSERT_STRING_EQUAL(expected, result);
writer.dropNullPlaceholders(); v = std::numeric_limits<double>::infinity();
JSONTEST_ASSERT(writer.write(nullValue) == "\n"); expected = "Infinity";
result = Json::writeString(b, v);
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
v = -std::numeric_limits<double>::infinity();
expected = "-Infinity";
result = Json::writeString(b, v);
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
}
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);
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 {}; struct StreamWriterTest : JsonTest::TestCase {};
@ -1703,7 +1734,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithNoErrors) {
bool ok = reader.parse("{ \"property\" : \"value\" }", root); bool ok = reader.parse("{ \"property\" : \"value\" }", root);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0); JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0);
JSONTEST_ASSERT(reader.getStructuredErrors().size() == 0);
} }
JSONTEST_FIXTURE(ReaderTest, parseWithNoErrorsTestingOffsets) { JSONTEST_FIXTURE(ReaderTest, parseWithNoErrorsTestingOffsets) {
@ -1715,25 +1745,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithNoErrorsTestingOffsets) {
root); root);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0); 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) { JSONTEST_FIXTURE(ReaderTest, parseWithOneError) {
@ -1744,13 +1755,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithOneError) {
JSONTEST_ASSERT(reader.getFormattedErrorMessages() == JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
"* Line 1, Column 15\n Syntax error: value, object or array " "* Line 1, Column 15\n Syntax error: value, object or array "
"expected.\n"); "expected.\n");
std::vector<Json::Reader::StructuredError> 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) { JSONTEST_FIXTURE(ReaderTest, parseChineseWithOneError) {
@ -1761,13 +1765,6 @@ JSONTEST_FIXTURE(ReaderTest, parseChineseWithOneError) {
JSONTEST_ASSERT(reader.getFormattedErrorMessages() == JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
"* Line 1, Column 19\n Syntax error: value, object or array " "* Line 1, Column 19\n Syntax error: value, object or array "
"expected.\n"); "expected.\n");
std::vector<Json::Reader::StructuredError> 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) { JSONTEST_FIXTURE(ReaderTest, parseWithDetailError) {
@ -1778,12 +1775,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithDetailError) {
JSONTEST_ASSERT(reader.getFormattedErrorMessages() == JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
"* Line 1, Column 16\n Bad escape sequence in string\nSee " "* Line 1, Column 16\n Bad escape sequence in string\nSee "
"Line 1, Column 20 for detail.\n"); "Line 1, Column 20 for detail.\n");
std::vector<Json::Reader::StructuredError> 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 {}; struct CharReaderTest : JsonTest::TestCase {};
@ -1924,7 +1915,7 @@ JSONTEST_FIXTURE(CharReaderStrictModeTest, dupKeys) {
struct CharReaderFailIfExtraTest : JsonTest::TestCase {}; struct CharReaderFailIfExtraTest : JsonTest::TestCase {};
JSONTEST_FIXTURE(CharReaderFailIfExtraTest, issue164) { 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::CharReaderBuilder b;
Json::Value root; Json::Value root;
char const doc[] = char const doc[] =
@ -2259,6 +2250,81 @@ JSONTEST_FIXTURE(CharReaderAllowZeroesTest, issue176) {
delete reader; 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<double>::infinity(), root.get("b", 0.0));
JSONTEST_ASSERT_EQUAL(-std::numeric_limits<double>::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<double>::infinity(), root["posInf"].asDouble());
JSONTEST_ASSERT_EQUAL(-std::numeric_limits<double>::infinity(), root["NegInf"].asDouble());
}
delete reader;
}
struct BuilderTest : JsonTest::TestCase {}; struct BuilderTest : JsonTest::TestCase {};
JSONTEST_FIXTURE(BuilderTest, settings) { 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, compareArray);
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareObject); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareObject);
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareType); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareType);
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, offsetAccessors);
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, typeChecksThrowExceptions); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, typeChecksThrowExceptions);
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, StaticString); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, StaticString);
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, CommentBefore); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, CommentBefore);
//JSONTEST_REGISTER_FIXTURE(runner, ValueTest, nulls); //JSONTEST_REGISTER_FIXTURE(runner, ValueTest, nulls);
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroes); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroes);
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroesInKeys); 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, dropNullPlaceholders);
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, writeZeroes); 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, CharReaderAllowZeroesTest, issue176);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderAllowSpecialFloatsTest, issue209);
JSONTEST_REGISTER_FIXTURE(runner, BuilderTest, settings); JSONTEST_REGISTER_FIXTURE(runner, BuilderTest, settings);
JSONTEST_REGISTER_FIXTURE(runner, IteratorTest, distance); JSONTEST_REGISTER_FIXTURE(runner, IteratorTest, distance);

View File

@ -1 +1 @@
1.6.5 0.10.6