Compare commits

...

142 Commits
1.2.0 ... 0.8.0

Author SHA1 Message Date
Christopher Dunn
b31d224fd6 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-02-11 11:22:07 -06:00
Christopher Dunn
a901a04c28 partially revert 'fix bug for static init'
re: 28836b8acc

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-02-11 11:22:07 -06:00
Christopher Dunn
c9afea87e3 revert 'Made it possible to drop null placeholders from array output.'
revert ae3c7a7aab
2015-02-11 11:22:07 -06:00
Christopher Dunn
edf9369493 Revert "added option to FastWriter which omits the trailing new line character"
This reverts commit 5bf16105b5.
2015-02-11 11:22:06 -06:00
Christopher Dunn
18ae85b44c revert 'Added structured error reporting to Reader.'
revert 68db655347
issue #147
2015-02-11 11:22:06 -06:00
Christopher Dunn
bd2aa77b94 revert 'Add public semantic error reporting'
for binary-compatibility with 0.6.0
issue #147
was #57
2015-02-11 11:22:06 -06:00
Christopher Dunn
6a12fb8999 Revert "Switch to copy-and-swap idiom for operator=."
This reverts commit 45cd9490cd.

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

  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-02-11 11:22:06 -06:00
Christopher Dunn
a1ca466e04 NOT C++11 2015-02-11 11:22:06 -06:00
Christopher Dunn
5a14ab5ea3 0.8.0 2015-02-11 11:22:06 -06:00
Christopher Dunn
3ebba5cea8 stop calling validate() in newReader/Writer()
By not calling validate(), we can add
non-invasive features which will be simply ignored when user-code
is compiled against an old version. That way, we can often
avoid a minor version-bump.

The user can call validate() himself if he prefers that behavior.
2015-02-11 11:15:32 -06:00
Christopher Dunn
acbf4eb2ef Merge pull request #166 from cdunn2001/stackLimit
Fixes #88 and #56.
2015-02-11 10:35:16 -06:00
Christopher Dunn
56df206847 limit stackDepth for old (deprecated) Json::Reader too
This is an improper solution. If multiple Readers exist,
then the effect stackLimit is reduced because of side-effects.
But our options are limited. We need to address the security
hole without breaking binary-compatibility.

However, this is not likely to cause any practical problems because:

* Anyone using `operator>>(istream, Json::Value)` will be using the
new code already
* Multiple Readers are uncommon.
* The stackLimit is quite high.
* Deeply nested JSON probably would have hit the system limits anyway.
2015-02-11 10:20:53 -06:00
Christopher Dunn
4dca80da49 limit stackDepth 2015-02-11 10:20:47 -06:00
Christopher Dunn
249ad9f47f stackLimit 2015-02-11 10:01:58 -06:00
Christopher Dunn
99b8e856f6 stackLimit_ 2015-02-11 10:01:58 -06:00
Christopher Dunn
89b72e1653 test stackLimit 2015-02-11 10:01:58 -06:00
Christopher Dunn
2474989f24 Old -> Our 2015-02-11 09:48:24 -06:00
Christopher Dunn
315b8c9f2c 1st StreamWriterTest 2015-02-10 23:29:14 -06:00
Christopher Dunn
29501c4d9f clarify comments
And throw instead of return null for invalid settings.
2015-02-10 23:03:27 -06:00
Christopher Dunn
7796f20eab Merge pull request #165 from cdunn2001/master
Remove some experimental classes that are not needed for 1.4.0. This also helps 0.8.0 binary compatibility with 0.6.0-rc2.
2015-02-10 22:45:32 -06:00
Christopher Dunn
20d09676c2 drop experimental OldCompressingStreamWriterBuilder 2015-02-10 21:29:35 -06:00
Christopher Dunn
5a744708fc enableYAMLCompatibility and dropNullPlaceholders for StreamWriterBuilder 2015-02-10 21:28:13 -06:00
Christopher Dunn
07f0e9308d nullRef, since we had to add that kludge to 0.8.0 2015-02-10 21:28:13 -06:00
Christopher Dunn
052050df07 copy Features to OldFeatures 2015-02-10 17:01:08 -06:00
Christopher Dunn
435d2a2f8d passes 2015-02-10 17:01:08 -06:00
Christopher Dunn
6123bd1505 copy Reader impl to OldReader 2015-02-10 17:01:08 -06:00
Christopher Dunn
7477bcfa3a renames for OldReader 2015-02-10 17:01:08 -06:00
Christopher Dunn
5e3e68af2e OldReader copied from Reader 2015-02-10 17:01:08 -06:00
Christopher Dunn
04a607d95b Merge pull request #163 from cdunn2001/master
Reimplement the new Builders.

Issue #131.
2015-02-09 18:55:55 -06:00
Christopher Dunn
db75cdf21e mv CommentStyle to .cpp 2015-02-09 18:54:58 -06:00
Christopher Dunn
c41609b9f9 set output stream in write(), not in builder 2015-02-09 18:44:53 -06:00
Christopher Dunn
b56381a636 <stdexcept> 2015-02-09 18:29:11 -06:00
Christopher Dunn
f757c18ca0 add all features 2015-02-09 18:24:56 -06:00
Christopher Dunn
3cf9175bde remark defaults via doxygen snippet 2015-02-09 18:16:24 -06:00
Christopher Dunn
a9e1ab302d Builder::settings_
We use Json::Value to configure the builders so we can maintain
binary-compatibility easily.
2015-02-09 17:30:11 -06:00
Christopher Dunn
694dbcb328 update docs, writeString() 2015-02-09 15:25:57 -06:00
Christopher Dunn
732abb80ef Merge pull request #162 from cdunn2001/master
Deprecate the new Builders.
2015-02-09 11:55:54 -06:00
Christopher Dunn
f3b3358a0e deprecate current Builders 2015-02-09 11:51:06 -06:00
Christopher Dunn
1357cddf1e deprecate Builders
see issue #131
2015-02-09 11:46:27 -06:00
Christopher Dunn
8df98f6112 deprecate old Reader; separate Advanced Usage section 2015-02-09 11:15:39 -06:00
Christopher Dunn
16bdfd8af3 --in=doc/web_doxyfile.in 2015-02-09 11:15:11 -06:00
Christopher Dunn
ce799b3aa3 copy doxyfile.in 2015-02-09 10:36:55 -06:00
Christopher Dunn
3a65581b20 drop an old impl 2015-02-09 09:54:26 -06:00
Christopher Dunn
6451412c99 simplify basic docs 2015-02-09 09:44:26 -06:00
Christopher Dunn
66a8ba255f clarify Builders 2015-02-09 01:29:43 -06:00
Christopher Dunn
249fd18114 put version into docs 2015-02-09 00:50:27 -06:00
Christopher Dunn
a587d04f77 Merge pull request #161 from cdunn2001/master
CharReader/Builder

I guess we should but the patch-level version. We will set the version properly soon...
2015-02-08 13:25:08 -06:00
Christopher Dunn
2c1197c2c8 CharReader/Builder
* CharReaderBuilder is similar to StreamWriterBuilder.
* use rdbuf(), since getline(string) is not required to handle EOF as delimiter
2015-02-08 13:22:09 -06:00
Christopher Dunn
2a94618589 Merge pull request #160 from cdunn2001/master
rm unique_ptr<>/shared_ptr<>, for pre-C++11
2015-02-08 13:10:18 -06:00
Christopher Dunn
dee4602b8f rm unique_ptr<>/shared_ptr<>, for pre-C++11 2015-02-08 11:54:49 -06:00
Christopher Dunn
ea2d167a38 Merge pull request #158 from cdunn2001/travis-with-cmake-package
JSONCPP_WITH_CMAKE_PACKAGE in Travis

I guess we don't really need to shared and static separately either. Saves a little time, maybe?
2015-02-07 12:24:58 -06:00
Christopher Dunn
41edda5ebe JSONCPP_WITH_CMAKE_PACKAGE in Travis 2015-02-07 12:18:20 -06:00
Christopher Dunn
2941cb3fe2 Merge pull request #156 from cdunn2001/with-cmake-package
fix JSONCPP_WITH_CMAKE_PACKAGE #155
2015-02-07 11:44:24 -06:00
Christopher Dunn
636121485c fix JSONCPP_WITH_CMAKE_PACKAGE #155
mv JSONCPP_WITH_CMAKE_PACKAGE ahead of INSTALL def.
2015-02-07 11:39:16 -06:00
Christopher Dunn
fe855fb4dd drop nullptr
See issue #153.
2015-02-02 15:33:47 -06:00
Christopher Dunn
198cc350c5 drop scoped enum, for pre-C++11 compatibility 2015-01-29 13:49:21 -06:00
Peter Spiess-Knafl
5e8595c0e2 added cmake option to build static and shared libraries at once
See #147 and #149.
2015-01-27 18:22:43 -06:00
Christopher Dunn
38042b3892 docs 2015-01-26 11:38:38 -06:00
Christopher Dunn
3b5f2b85ca Merge pull request #145 from cdunn2001/simplify-builder
Simplify builder
2015-01-26 11:33:16 -06:00
Christopher Dunn
7eca3b4e88 gcc-4.6 (Travis CI) does not support 2015-01-26 11:17:42 -06:00
Christopher Dunn
999f5912f0 docs 2015-01-26 11:12:53 -06:00
Christopher Dunn
472d29f57b fix doc 2015-01-26 11:04:03 -06:00
Christopher Dunn
6065a1c142 make StreamWriterBuilder concrete 2015-01-26 11:01:15 -06:00
Christopher Dunn
28a20917b0 Move old FastWriter stuff out of new Builder 2015-01-26 10:47:42 -06:00
Christopher Dunn
177b7b8f22 OldCompressingStreamWriterBuilder 2015-01-26 10:44:20 -06:00
Christopher Dunn
9da9f84903 improve docs
including `writeString()`
2015-01-26 10:43:53 -06:00
Christopher Dunn
54b8e6939a Merge pull request #132 from cdunn2001/builder
StreamWriter::Builder

Deprecate old Writers, but include them in tests.

This should still be binary-compatible with 1.3.0.
2015-01-25 18:52:09 -06:00
Christopher Dunn
c7b39c2e25 deprecate old Writers
also, use withers instead of setters, and update docs
2015-01-25 18:45:59 -06:00
Christopher Dunn
d78caa3851 implement strange setting from FastWriter 2015-01-25 18:15:54 -06:00
Christopher Dunn
c6e0688e5a implement CommentStyle::None/indentation_=="" 2015-01-25 17:32:36 -06:00
Christopher Dunn
1e21e63853 default \t indentation, All comments 2015-01-25 16:01:59 -06:00
Christopher Dunn
dea6f8d9a6 incorporate 'proper newlines for comments' into new StreamWriter 2015-01-25 15:55:18 -06:00
Christopher Dunn
648843d148 clarify CommentStyle 2015-01-25 15:54:40 -06:00
Christopher Dunn
fe3979cd8a drop StreamWriterBuilderFactory, for now 2015-01-25 15:54:40 -06:00
Christopher Dunn
94665eab72 copy fixes from StyledStreamWriter 2015-01-25 15:54:40 -06:00
Christopher Dunn
9e4bcf354f test BuiltStyledStreamWriter too 2015-01-25 15:54:40 -06:00
Christopher Dunn
9243d602fe const stuff 2015-01-25 15:54:40 -06:00
Christopher Dunn
beb6f35c63 non-const write 2015-01-25 15:54:40 -06:00
Christopher Dunn
ceef7f5219 copied impl of StyledStreamWriter 2015-01-25 15:54:40 -06:00
Christopher Dunn
77ce057f14 fix comment 2015-01-25 15:54:40 -06:00
Christopher Dunn
d49ab5aee1 use new BuiltStyledStreamWriter in operator<<() 2015-01-25 15:54:40 -06:00
Christopher Dunn
4d649402b0 setIndentation() 2015-01-25 15:54:40 -06:00
Christopher Dunn
489707ff60 StreamWriter::Builder 2015-01-25 15:54:39 -06:00
Christopher Dunn
5fbfe3cdb9 StreamWriter 2015-01-25 15:54:39 -06:00
Christopher Dunn
948f29032e update docs 2015-01-25 15:54:07 -06:00
Christopher Dunn
964affd333 add back space before trailing comment 2015-01-25 15:49:02 -06:00
Christopher Dunn
c038e08efc Merge pull request #144 from cdunn2001/proper-comment-lfs
proper newlines for comments

This alters `StyledStreamWriter`, but not `StyledWriter`.
2015-01-25 15:10:38 -06:00
Christopher Dunn
74c2d82e19 proper newlines for comments
The logic is still messy, but it seems to work.
2015-01-25 15:05:09 -06:00
Christopher Dunn
30726082f3 Merge pull request #143 from cdunn2001/rm-trailing-newlines
rm trailing newlines for *all* comments
2015-01-25 14:35:24 -06:00
Christopher Dunn
1e3149ab75 rm trailing newlines for *all* comments
This will make it easier to fix newlines consistently.
2015-01-25 14:32:13 -06:00
Christopher Dunn
7312b1022d Merge pull request #141 from cdunn2001/set-comment
Fix a border case which causes Value::CommentInfo::setComment() to crash
2015-01-25 11:37:02 -06:00
datadiode
2f046b584d Fix a border case which causes Value::CommentInfo::setComment() to crash
re: pull #140
2015-01-25 11:19:51 -06:00
Christopher Dunn
dd91914b1b TravisCI gcc-4.6 does not yet support -Wpedantic 2015-01-25 10:34:49 -06:00
Christopher Dunn
2a46e295ec Merge pull request #139 from cdunn2001/some-python-changes
Some python changes.

* Better messaging.
* Make `doxybuild.py` work with python3.4
2015-01-24 16:24:12 -06:00
Christopher Dunn
f4bc0bf4ec README.md 2015-01-24 16:21:12 -06:00
Christopher Dunn
f357688893 make doxybuild.py work with python3.4 2015-01-24 16:21:12 -06:00
Florian Meier
bb0c80b3e5 Doxybuild: Error message if doxygen not found
This patch introduces a better error message.

See discussion at pull #129.
2015-01-24 16:21:12 -06:00
Christopher Dunn
ff5abe76a5 update doxbuild.py 2015-01-24 16:21:12 -06:00
Christopher Dunn
9cc0bb80b2 update TarFile usage 2015-01-24 16:21:12 -06:00
Christopher Dunn
494950a63d rm extra whitespace in python, per PEP8 2015-01-24 16:21:12 -06:00
Christopher Dunn
7d82b14726 fix issue #90
We are static-casting to U, so we really have no reason to use
references.

However, if this comes up again, try applying -ffloat-store to
the target executable, per
    https://github.com/open-source-parsers/jsoncpp/issues/90
2015-01-24 14:34:54 -06:00
Christopher Dunn
2bc6137ada fix gcc warnings 2015-01-24 13:42:37 -06:00
Christopher Dunn
201904bfbb Merge pull request #138 from cdunn2001/fix-103
Fix #103.
2015-01-23 14:51:31 -06:00
Christopher Dunn
216ecd3085 fix test_comment_00 for #103 2015-01-23 14:28:44 -06:00
Christopher Dunn
8d15e51228 add test_comment_00
one-element array with comment, for issue #103
2015-01-23 14:28:21 -06:00
Christopher Dunn
9fbd12b27c Merge pull request #137 from cdunn2001/avoid-extra-newline
Avoid extra newline
2015-01-23 14:24:52 -06:00
Christopher Dunn
f8ca6cbb25 1.4.0 <- 1.3.0
Minor version bump, but we will wait for a few more commits this time
before tagging the release.
2015-01-23 14:23:31 -06:00
Christopher Dunn
d383056fbb avoid extra newlines in StyledStreamWriter
Add indented_ as a bitfield. (Verified that sizeof(StyledStreamWriter)
remains 96 for binary compatibility. But the new symbol requires a minor
version-bump.)
2015-01-23 14:23:31 -06:00
Christopher Dunn
ddb4ff7dec Merge pull request #136 from cdunn2001/test-both-styled-writers
Test both styled writers

Not only does this now test StyledStreamWriter the same way as StyledWriter, but it also makes the former work more like the latter, indenting separate lines of a comment before a value. Might break some user tests (as `operator<<()` uses `StyledStreamWriter`) but basically a harmless improvement.

All tests pass.
2015-01-23 13:55:45 -06:00
Christopher Dunn
3efc587fba make StyledStreamWriter work more like StyledWriter
tests pass
2015-01-23 13:36:10 -06:00
Christopher Dunn
70704b9a70 test both StyledWriter and StyledStreamWriter 2015-01-23 13:36:10 -06:00
Christopher Dunn
ac6bbbc739 show cmd in runjsontests.py 2015-01-23 13:36:10 -06:00
Christopher Dunn
26c52861b9 pass --json-writer StyledWriter 2015-01-23 13:36:10 -06:00
Christopher Dunn
3682f60927 --json-writer arg 2015-01-23 13:36:10 -06:00
Christopher Dunn
58c31ac550 mv try-block 2015-01-23 12:35:12 -06:00
Christopher Dunn
08cfd02d8c fix minor bugs in test-runner 2015-01-23 12:35:12 -06:00
Christopher Dunn
79211e1aeb Options class for test 2015-01-23 12:35:12 -06:00
Christopher Dunn
632c9b5032 cleaner 2015-01-23 12:35:12 -06:00
Christopher Dunn
05810a7607 cleaner 2015-01-23 12:35:12 -06:00
Christopher Dunn
942e2c999a unindent test-code 2015-01-23 12:35:12 -06:00
Christopher Dunn
2160c9a042 switch from StyledWriter to StyledStream writer in tests 2015-01-23 09:02:44 -06:00
Christopher Dunn
ee8b58f82f Merge pull request #135 from cdunn2001/removeMember
Deprecate old `removeMember()`. Add new.

[Deprecated methods will be removed at the next major version bump](http://apr.apache.org/versioning.html#binary).
2015-01-22 19:26:46 -06:00
Christopher Dunn
9132aa94b1 1.3.0
http://apr.apache.org/versioning.html#binary
2015-01-22 19:25:44 -06:00
Christopher Dunn
76746b09fc deprecate old removeMember() 2015-01-22 19:25:44 -06:00
Christopher Dunn
70b795bd45 Merge pull request #133 from cdunn2001/travis-11
upgrade -std=c++ version
2015-01-22 19:21:24 -06:00
Christopher Dunn
26842530f2 upgrade -std=c++ version
Travis CI does not yet support gcc-4.8, needed for c++11, so we
will try c++0x for now.
2015-01-22 19:12:23 -06:00
Christopher Dunn
e3f24286c1 Merge pull request #130 from connormanning/master
Build without warnings with -pedantic enabled.
2015-01-22 11:48:58 -06:00
Connor Manning
00b8ce81db Build without warnings with -pedantic enabled. 2015-01-22 10:48:45 -06:00
Christopher Dunn
40810fe326 Merge pull request #127 from cdunn2001/removeIndex
`Value::removeIndex()`

See issue #28.
2015-01-21 16:08:25 -06:00
Christopher Dunn
59167d8627 more changes per cr 2015-01-21 16:05:08 -06:00
Christopher Dunn
05c1b8344d drop this-> (team preference) 2015-01-21 15:43:48 -06:00
Christopher Dunn
e893625e88 test removeIndex/Member() 2015-01-20 17:04:03 -06:00
Christopher Dunn
e87e41cdb0 from Itzik S; see issue #28
with minor corrections
2015-01-20 17:03:58 -06:00
Christopher Dunn
9de2c2d84d partial 2015-01-20 17:02:48 -06:00
Christopher Dunn
7956ccd61e allow stream ops for JSON_FAIL_MESSAGE
http://www.iar.com/Global/Resources/Developers_Toolbox/C_Cplusplus_Programming/Tips%20and%20tricks%20using%20the%20preprocessor%20%28part%20two%29.pdf
2015-01-20 16:25:26 -06:00
datadiode
9454e687a3 Specialize std::swap() for Json::Value in a C++ standard compliant way
originally from pull #119
2015-01-20 15:25:41 -06:00
Christopher Dunn
46a925ba4a fix compiler warning for a test 2015-01-20 15:19:22 -06:00
Christopher Dunn
c407f1407f test-data for #103
passes
2015-01-20 15:16:46 -06:00
Christopher Dunn
ec251df6b7 Merge pull request #125 from cdunn2001/issue-116
1.2.1

Fix issue #116, DOS line-endings. Never output \r.
2015-01-20 15:14:50 -06:00
Christopher Dunn
51c0afab22 1.2.1 <- 1.2.0
This can affect existing round-trip tests, but we never made any
guarantees about whitespace constancy.
2015-01-20 15:12:49 -06:00
Mark Zeren
e39fb0083c Normalize comment EOLs while reading instead of while writing
Tests are currently failing when git cloning on Windows with autocrlf = true. In
that setup multiline comments contain \r\n EOLs. The test code assumes that
comments contain \n EOLs and opens the .actual files (etc.) with "wt" which
converts \n to \r\n. Thus we end up with \r\r\n EOLs in the output, which
triggers a test failure.

Instead we should cannonicalize comments while reading so that they contain only
\n EOLs. This approach simplifies other parts of the reader and writer logic,
and requires no changes to the test. It is a breaking change, but probably the
Right Thing going forward.

This change also fixes dereferencing past the end of the comment string in
StyledWriter::writeCommentBeforeValue.

Tests should be added with appropriate .gitattributes for the input files to
ensure that we run tests for DOS, Mac, and Unix EOL files on all platforms. For
now this change is enough to unblock Windows builds.

issue #116
2015-01-20 13:45:44 -06:00
Christopher Dunn
ec727e2f6b -Wall for Clang/GCC 2015-01-20 13:45:28 -06:00
47 changed files with 5098 additions and 1079 deletions

View File

@@ -7,12 +7,11 @@ language: cpp
compiler:
- gcc
- clang
script: cmake -DJSONCPP_LIB_BUILD_SHARED=$SHARED_LIBRARY -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_VERBOSE_MAKEFILE=$VERBOSE_MAKE . && make
script: cmake -DJSONCPP_WITH_CMAKE_PACKAGE=$CMAKE_PKG -DJSONCPP_LIB_BUILD_SHARED=$SHARED_LIB -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_VERBOSE_MAKEFILE=$VERBOSE_MAKE . && make
env:
matrix:
- SHARED_LIBRARY=ON BUILD_TYPE=release VERBOSE_MAKE=false
- SHARED_LIBRARY=OFF BUILD_TYPE=release VERBOSE_MAKE=false
- SHARED_LIBRARY=OFF BUILD_TYPE=debug VERBOSE VERBOSE_MAKE=true
- SHARED_LIB=ON STATIC_LIB=ON CMAKE_PKG=ON BUILD_TYPE=release VERBOSE_MAKE=false
- SHARED_LIB=OFF STATIC_LIB=ON CMAKE_PKG=OFF BUILD_TYPE=debug VERBOSE_MAKE=true VERBOSE
notifications:
email:
- aaronjjacobs@gmail.com

View File

@@ -83,6 +83,14 @@ if ( MSVC )
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /W4 ")
endif( MSVC )
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# using regular Clang or AppleClang
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# using GCC
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic")
endif()
IF(JSONCPP_WITH_WARNING_AS_ERROR)
UseCompilationWarningAsError()
ENDIF(JSONCPP_WITH_WARNING_AS_ERROR)

View File

@@ -80,7 +80,7 @@ New in SVN
(e.g. MSVC 2008 command prompt in start menu) before running scons.
- Added support for amalgamated source and header generation (a la sqlite).
Refer to README.txt section "Generating amalgamated source and header"
Refer to README.md section "Generating amalgamated source and header"
for detail.
* Value

View File

@@ -66,7 +66,7 @@ Alternatively, from the command-line on Unix in the source directory:
mkdir -p build/debug
cd build/debug
cmake -DCMAKE_BUILD_TYPE=debug -DJSONCPP_LIB_BUILD_SHARED=OFF -G "Unix Makefiles" ../..
cmake -DCMAKE_BUILD_TYPE=debug -DJSONCPP_LIB_BUILD_STATIC=ON -DJSONCPP_LIB_BUILD_SHARED=OFF -G "Unix Makefiles" ../..
make
Running `cmake -`" will display the list of available generators (passed using

View File

@@ -237,7 +237,7 @@ RunUnitTests = ActionFactory(runUnitTests_action, runUnitTests_string )
env.Alias( 'check' )
srcdist_cmd = env['SRCDIST_ADD']( source = """
AUTHORS README.txt SConstruct
AUTHORS README.md SConstruct
""".split() )
env.Alias( 'src-dist', srcdist_cmd )

View File

@@ -211,18 +211,15 @@ def generate_html_report( html_report_path, builds ):
build_status = 'ok' if build.build_succeeded else 'FAILED'
cmake_log_url = os.path.relpath(build.cmake_log_path, report_dir)
build_log_url = os.path.relpath(build.build_log_path, report_dir)
td = '<td class="%s"><a href="%s" class="%s">CMake: %s</a>' % (
build_status.lower(), cmake_log_url, cmake_status.lower(), cmake_status)
td = '<td class="%s"><a href="%s" class="%s">CMake: %s</a>' % ( build_status.lower(), cmake_log_url, cmake_status.lower(), cmake_status)
if build.cmake_succeeded:
td += '<br><a href="%s" class="%s">Build: %s</a>' % (
build_log_url, build_status.lower(), build_status)
td += '<br><a href="%s" class="%s">Build: %s</a>' % ( build_log_url, build_status.lower(), build_status)
td += '</td>'
else:
td = '<td></td>'
tds.append(td)
tr_builds.append('<tr>%s</tr>' % '\n'.join(tds))
html = HTML_TEMPLATE.substitute(
title='Batch build report',
html = HTML_TEMPLATE.substitute( title='Batch build report',
th_vars=' '.join(th_vars),
th_build_types=' '.join(th_build_types),
tr_builds='\n'.join(tr_builds))

View File

@@ -1,5 +1,5 @@
import os.path
import gzip
from contextlib import closing
import os
import tarfile
TARGZ_DEFAULT_COMPRESSION_LEVEL = 9
@@ -29,25 +29,19 @@ def make_tarball(tarball_path, sources, base_dir, prefix_dir=''):
path_in_tar = archive_name(path)
tar.add(path, path_in_tar)
compression = TARGZ_DEFAULT_COMPRESSION_LEVEL
tar = tarfile.TarFile.gzopen( tarball_path, 'w', compresslevel=compression )
try:
with closing(tarfile.TarFile.open(tarball_path, 'w:gz',
compresslevel=compression)) as tar:
for source in sources:
source_path = source
if os.path.isdir(source):
os.path.walk(source_path, visit, tar)
for dirpath, dirnames, filenames in os.walk(source_path):
visit(tar, dirpath, filenames)
else:
path_in_tar = archive_name(source_path)
tar.add(source_path, path_in_tar) # filename, arcname
finally:
tar.close()
def decompress(tarball_path, base_dir):
"""Decompress the gzipped tarball into directory base_dir.
"""
# !!! This class method is not documented in the online doc
# nor is bz2open!
tar = tarfile.TarFile.gzopen(tarball_path, mode='r')
try:
with closing(tarfile.TarFile.open(tarball_path)) as tar:
tar.extractall(base_dir)
finally:
tar.close()

View File

@@ -819,7 +819,7 @@ EXCLUDE_SYMBOLS =
# that contain example code fragments that are included (see the \include
# command).
EXAMPLE_PATH =
EXAMPLE_PATH = ..
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and

View File

@@ -16,7 +16,7 @@ JsonCpp - JSON data format manipulation library
</a>
</td>
<td width="40%" align="right" valign="center">
<a href="https://github.com/open-source-parsers/jsoncpp">JsonCpp home page</a>
<a href="http://open-source-parsers.github.io/jsoncpp-docs/doxygen/">JsonCpp home page</a>
</td>
</tr>
</table>

View File

@@ -4,11 +4,21 @@
<a HREF="http://www.json.org/">JSON (JavaScript Object Notation)</a>
is a lightweight data-interchange format.
It can represent integer, real number, string, an ordered sequence of value, and
a collection of name/value pairs.
Here is an example of JSON data:
\verbatim
{
"encoding" : "UTF-8",
"plug-ins" : [
"python",
"c++",
"ruby"
],
"indent" : { "length" : 3, "use_space": true }
}
\endverbatim
<b>JsonCpp</b> supports comments as <i>meta-data</i>:
\code
// Configuration options
{
// Default encoding for text
@@ -17,22 +27,22 @@ Here is an example of JSON data:
// Plug-ins loaded at start-up
"plug-ins" : [
"python",
"c++",
"c++", // trailing comment
"ruby"
],
// Tab indent size
"indent" : { "length" : 3, "use_space": true }
// (multi-line comment)
"indent" : { /*embedded comment*/ "length" : 3, "use_space": true }
}
\endverbatim
<code>jsoncpp</code> supports comments as <i>meta-data</i>.
\endcode
\section _features Features
- read and write JSON document
- attach C++ style comments to element during parsing
- rewrite JSON document preserving original comments
Notes: Comments used to be supported in JSON but where removed for
Notes: Comments used to be supported in JSON but were removed for
portability (C like comments are not supported in Python). Since
comments are useful in configuration/input file, this feature was
preserved.
@@ -40,47 +50,73 @@ preserved.
\section _example Code example
\code
Json::Value root; // will contains the root value after parsing.
Json::Reader reader;
bool parsingSuccessful = reader.parse( config_doc, root );
if ( !parsingSuccessful )
{
// report to the user the failure and their locations in the document.
std::cout << "Failed to parse configuration\n"
<< reader.getFormattedErrorMessages();
return;
}
Json::Value root; // 'root' will contain the root value after parsing.
std::cin >> root;
// You can also read into a particular sub-value.
std::cin >> root["subtree"];
// Get the value of the member of root named 'encoding', return 'UTF-8' if there is no
// such member.
std::string encoding = root.get("encoding", "UTF-8" ).asString();
// Get the value of the member of root named 'encoding', return a 'null' value if
// Get the value of the member of root named 'encoding'; return a 'null' value if
// there is no such member.
const Json::Value plugins = root["plug-ins"];
for ( int index = 0; index < plugins.size(); ++index ) // Iterates over the sequence elements.
loadPlugIn( plugins[index].asString() );
setIndentLength( root["indent"].get("length", 3).asInt() );
setIndentUseSpace( root["indent"].get("use_space", true).asBool() );
foo::setIndentLength( root["indent"].get("length", 3).asInt() );
foo::setIndentUseSpace( root["indent"].get("use_space", true).asBool() );
// ...
// At application shutdown to make the new configuration document:
// Since Json::Value has implicit constructor for all value types, it is not
// necessary to explicitly construct the Json::Value object:
root["encoding"] = getCurrentEncoding();
root["indent"]["length"] = getCurrentIndentLength();
root["indent"]["use_space"] = getCurrentIndentUseSpace();
root["encoding"] = foo::getCurrentEncoding();
root["indent"]["length"] = foo::getCurrentIndentLength();
root["indent"]["use_space"] = foo::getCurrentIndentUseSpace();
Json::StyledWriter writer;
// Make a new JSON document for the configuration. Preserve original comments.
std::string outputConfig = writer.write( root );
// You can also use streams. This will put the contents of any JSON
// stream at a particular sub-value, if you'd like.
std::cin >> root["subtree"];
// And you can write to a stream, using the StyledWriter automatically.
// If you like the defaults, you can insert directly into a stream.
std::cout << root;
// Of course, you can write to `std::ostringstream` if you prefer.
// If desired, remember to add a linefeed and flush.
std::cout << std::endl;
\endcode
\section _advanced Advanced usage
Configure *builders* to create *readers* and *writers*. For
configuration, we use our own `Json::Value` (rather than
standard setters/getters) so that we can add
features without losing binary-compatibility.
\code
// For convenience, use `writeString()` with a specialized builder.
Json::StreamWriterBuilder wbuilder;
wbuilder.settings_["indentation"] = "\t"; // simple Json::Value
std::string document = Json::writeString(wbuilder, root);
// Here, using a specialized Builder, we discard comments and
// record errors as we parse.
Json::CharReaderBuilder rbuilder;
rbuilder.settings_["collectComments"] = false; // simple Json::Value
std::string errs;
bool ok = Json::parseFromStream(rbuilder, std::cin, &root, &errs);
\endcode
Yes, compile-time configuration-checking would be helpful,
but `Json::Value` lets you
write and read the builder configuration, which is better! In other words,
you can configure your JSON parser using JSON.
CharReaders and StreamWriters are not thread-safe, but they are re-usable.
\code
Json::CharReaderBuilder rbuilder;
cfg >> rbuilder.settings_;
std::unique_ptr<Json::CharReader> const reader(rbuilder.newCharReader());
reader->parse(start, stop, &value1, &errs);
// ...
reader->parse(start, stop, &value2, &errs);
// etc.
\endcode
\section _pbuild Build instructions
@@ -116,4 +152,8 @@ Basically JsonCpp is licensed under MIT license, or public domain if desired
and recognized in your jurisdiction.
\author Baptiste Lepilleur <blep@users.sourceforge.net> (originator)
\version \include version
We make strong guarantees about binary-compatibility, consistent with
<a href="http://apr.apache.org/versioning.html">the Apache versioning scheme</a>.
\sa version.h
*/

2302
doc/web_doxyfile.in Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,28 @@
"""Script to generate doxygen documentation.
"""
from __future__ import print_function
from __future__ import unicode_literals
from devtools import tarball
from contextlib import contextmanager
import subprocess
import traceback
import re
import os
import os.path
import sys
import shutil
@contextmanager
def cd(newdir):
"""
http://stackoverflow.com/questions/431684/how-do-i-cd-in-python
"""
prevdir = os.getcwd()
os.chdir(newdir)
try:
yield
finally:
os.chdir(prevdir)
def find_program(*filenames):
"""find a program in folders path_lst, and sets env[var]
@param filenames: a list of possible names of the program to search for
@@ -28,51 +43,54 @@ def do_subst_in_file(targetfile, sourcefile, dict):
For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'},
then all instances of %VERSION% in the file will be replaced with 1.2345 etc.
"""
try:
f = open(sourcefile, 'rb')
with open(sourcefile, 'r') as f:
contents = f.read()
f.close()
except:
print("Can't read source file %s"%sourcefile)
raise
for (k,v) in list(dict.items()):
v = v.replace('\\','\\\\')
contents = re.sub(k, v, contents)
try:
f = open(targetfile, 'wb')
with open(targetfile, 'w') as f:
f.write(contents)
f.close()
def getstatusoutput(cmd):
"""cmd is a list.
"""
try:
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output, _ = process.communicate()
status = process.returncode
except:
print("Can't write target file %s"%targetfile)
raise
status = -1
output = traceback.format_exc()
return status, output
def run_cmd(cmd, silent=False):
"""Raise exception on failure.
"""
info = 'Running: %r in %r' %(' '.join(cmd), os.getcwd())
print(info)
sys.stdout.flush()
if silent:
status, output = getstatusoutput(cmd)
else:
status, output = os.system(' '.join(cmd)), ''
if status:
msg = 'Error while %s ...\n\terror=%d, output="""%s"""' %(info, status, output)
raise Exception(msg)
def assert_is_exe(path):
if not path:
raise Exception('path is empty.')
if not os.path.isfile(path):
raise Exception('%r is not a file.' %path)
if not os.access(path, os.X_OK):
raise Exception('%r is not executable by this user.' %path)
def run_doxygen(doxygen_path, config_file, working_dir, is_silent):
assert_is_exe(doxygen_path)
config_file = os.path.abspath(config_file)
doxygen_path = doxygen_path
old_cwd = os.getcwd()
try:
os.chdir( working_dir )
with cd(working_dir):
cmd = [doxygen_path, config_file]
print('Running:', ' '.join( cmd ))
try:
import subprocess
except:
if os.system( ' '.join( cmd ) ) != 0:
print('Documentation generation failed')
return False
else:
if is_silent:
process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
else:
process = subprocess.Popen( cmd )
stdout, _ = process.communicate()
if process.returncode:
print('Documentation generation failed:')
print(stdout)
return False
return True
finally:
os.chdir( old_cwd )
run_cmd(cmd, is_silent)
def build_doc(options, make_release=False):
if make_release:
@@ -112,10 +130,10 @@ def build_doc( options, make_release=False ):
if not os.path.isdir(output_dir):
os.makedirs(output_dir)
do_subst_in_file( 'doc/doxyfile', 'doc/doxyfile.in', subst_keys )
ok = run_doxygen( options.doxygen_path, 'doc/doxyfile', 'doc', is_silent=options.silent )
do_subst_in_file('doc/doxyfile', options.doxyfile_input_path, subst_keys)
run_doxygen(options.doxygen_path, 'doc/doxyfile', 'doc', is_silent=options.silent)
if not options.silent:
print(open(warning_log_path, 'rb').read())
print(open(warning_log_path, 'r').read())
index_path = os.path.abspath(os.path.join('doc', subst_keys['%HTML_OUTPUT%'], 'index.html'))
print('Generated documentation can be found in:')
print(index_path)
@@ -126,7 +144,7 @@ def build_doc( options, make_release=False ):
print('Generating doc tarball to', tarball_path)
tarball_sources = [
output_dir,
'README.txt',
'README.md',
'LICENSE',
'NEWS.txt',
'version'
@@ -151,6 +169,8 @@ def main():
help="""Path to GraphViz dot tool. Must be full qualified path. [Default: %default]""")
parser.add_option('--doxygen', dest="doxygen_path", action='store', default=find_program('doxygen'),
help="""Path to Doxygen tool. [Default: %default]""")
parser.add_option('--in', dest="doxyfile_input_path", action='store', default='doc/doxyfile.in',
help="""Path to doxygen inputs. [Default: %default]""")
parser.add_option('--with-html-help', dest="with_html_help", action='store_true', default=False,
help="""Enable generation of Microsoft HTML HELP""")
parser.add_option('--no-uml-look', dest="with_uml_look", action='store_false', default=True,

View File

@@ -7,6 +7,7 @@
#define CPPTL_JSON_ASSERTIONS_H_INCLUDED
#include <stdlib.h>
#include <sstream>
#if !defined(JSON_IS_AMALGAMATION)
#include "config.h"
@@ -16,26 +17,26 @@
#include <stdexcept>
#define JSON_ASSERT(condition) \
assert(condition); // @todo <= change this into an exception throw
#define JSON_FAIL_MESSAGE(message) throw std::runtime_error(message);
#define JSON_FAIL_MESSAGE(message) do{std::ostringstream oss; oss << message; throw std::runtime_error(oss.str());}while(0)
//#define JSON_FAIL_MESSAGE(message) throw std::runtime_error(message)
#else // JSON_USE_EXCEPTION
#define JSON_ASSERT(condition) assert(condition);
// The call to assert() will show the failure message in debug builds. In
// release bugs we write to invalid memory in order to crash hard, so that a
// debugger or crash reporter gets the chance to take over. We still call exit()
// afterward in order to tell the compiler that this macro doesn't return.
// release bugs we abort, for a core-dump or debugger.
#define JSON_FAIL_MESSAGE(message) \
{ \
assert(false&& message); \
strcpy(reinterpret_cast<char*>(666), message); \
exit(123); \
std::ostringstream oss; oss << message; \
assert(false && oss.str().c_str()); \
abort(); \
}
#endif
#define JSON_ASSERT_MESSAGE(condition, message) \
if (!(condition)) { \
JSON_FAIL_MESSAGE(message) \
JSON_FAIL_MESSAGE(message); \
}
#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED

View File

@@ -44,12 +44,6 @@ public:
/// \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

View File

@@ -14,6 +14,7 @@
#include <iosfwd>
#include <stack>
#include <string>
#include <istream>
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
@@ -27,24 +28,13 @@ namespace Json {
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
*Value.
*
* \deprecated Use CharReader and CharReaderBuilder.
*/
class JSON_API Reader {
public:
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.
*/
@@ -78,7 +68,7 @@ public:
document to read.
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
document to read.
\ Must be >= beginDoc.
* Must be >= beginDoc.
* \param root [out] Contains the root value of the document if it was
* successfully parsed.
* \param collectComments \c true to collect comment and allow writing them
@@ -121,38 +111,6 @@ public:
*/
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:
enum TokenType {
tokenEndOfStream = 0,
@@ -238,8 +196,119 @@ private:
std::string commentsBefore_;
Features features_;
bool collectComments_;
}; // Reader
/** Interface for reading JSON from a char array.
*/
class JSON_API CharReader {
public:
virtual ~CharReader() {}
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
document.
* The document must be a UTF-8 encoded string containing the document to read.
*
* \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
document to read.
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
document to read.
* Must be >= beginDoc.
* \param root [out] Contains the root value of the document if it was
* successfully parsed.
* \param errs [out] Formatted error messages (if not NULL)
* a user friendly string that lists errors in the parsed
* document.
* \return \c true if the document was successfully parsed, \c false if an
error occurred.
*/
virtual bool parse(
char const* beginDoc, char const* endDoc,
Value* root, std::string* errs) = 0;
class Factory {
public:
/** \brief Allocate a CharReader via operator new().
* \throw std::exception if something goes wrong (e.g. invalid settings)
*/
virtual CharReader* newCharReader() const = 0;
}; // Factory
}; // CharReader
/** \brief Build a CharReader implementation.
\deprecated This is experimental and will be altered before the next release.
Usage:
\code
using namespace Json;
CharReaderBuilder builder;
builder.settings_["collectComments"] = false;
Value value;
std::string errs;
bool ok = parseFromStream(builder, std::cin, &value, &errs);
\endcode
*/
class JSON_API CharReaderBuilder : public CharReader::Factory {
public:
// Note: We use a Json::Value so that we can add data-members to this class
// without a major version bump.
/** Configuration of this builder.
These are case-sensitive.
Available settings (case-sensitive):
- "collectComments": false or true
- true to collect comment and allow writing them
back during serialization, false to discard comments.
This parameter is ignored if allowComments is false.
- "allowComments": false or true
- true if comments are allowed.
- "strictRoot": false or true
- true if root must be either an array or an object value
- "allowDroppedNullPlaceholders": false or true
- true if dropped null placeholders are allowed. (See StreamWriterBuilder.)
- "allowNumericKeys": false or true
- true if numeric object keys are allowed.
- "stackLimit": integer
- This is a security issue (seg-faults caused by deeply nested JSON),
so the default is low.
You can examine 'settings_` yourself
to see the defaults. You can also write and read them just like any
JSON Value.
\sa setDefaults()
*/
Json::Value settings_;
CharReaderBuilder();
virtual ~CharReaderBuilder();
virtual CharReader* newCharReader() const;
/** \return true if 'settings' are legal and consistent;
* otherwise, indicate bad settings via 'invalid'.
*/
bool validate(Json::Value* invalid) const;
/** Called by ctor, but you can use this to reset settings_.
* \pre 'settings' != NULL (but Json::null is fine)
* \remark Defaults:
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode
*/
static void setDefaults(Json::Value* settings);
/** Same as old Features::strictMode().
* \pre 'settings' != NULL (but Json::null is fine)
* \remark Defaults:
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults
*/
static void strictMode(Json::Value* settings);
};
/** Consume entire stream and use its begin/end.
* Someday we might have a real StreamReader, but for now this
* is convenient.
*/
bool parseFromStream(
CharReader::Factory const&,
std::istream&,
Value* root, std::string* errs);
/** \brief Read from 'sin' into 'root'.
Always keep comments from the input JSON.

View File

@@ -133,7 +133,11 @@ public:
typedef Json::LargestUInt LargestUInt;
typedef Json::ArrayIndex ArrayIndex;
static const Value& 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.
@@ -171,7 +175,7 @@ private:
CZString(const char* cstr, DuplicationPolicy allocate);
CZString(const CZString& other);
~CZString();
CZString& operator=(CZString other);
CZString &operator=(const CZString &other);
bool operator<(const CZString& other) const;
bool operator==(const CZString& other) const;
ArrayIndex index() const;
@@ -240,7 +244,7 @@ Json::Value obj_value(Json::objectValue); // {}
~Value();
// Deep copy, then swap(other).
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.
@@ -392,9 +396,24 @@ Json::Value obj_value(Json::objectValue); // {}
/// \return the removed Value, or null.
/// \pre type() is objectValue or nullValue
/// \post type() is unchanged
/// \deprecated
Value removeMember(const char* key);
/// Same as removeMember(const char*)
/// \deprecated
Value removeMember(const std::string& key);
/** \brief Remove the named map member.
Update 'removed' iff removed.
\return true iff removed (no exceptions)
*/
bool removeMember(const char* key, Value* removed);
/** \brief Remove the indexed array element.
O(n) expensive operations.
Update 'removed' iff removed.
\return true iff removed (no exceptions)
*/
bool removeIndex(ArrayIndex i, Value* removed);
/// Return true if the object has a member named key.
bool isMember(const char* key) const;
@@ -417,9 +436,11 @@ Json::Value obj_value(Json::objectValue); // {}
// EnumValues enumValues() const;
//# endif
/// Comments must be //... or /* ... */
/// \deprecated Always pass len.
void setComment(const char* comment, CommentPlacement placement);
/// Comments must be //... or /* ... */
void setComment(const char* comment, size_t len, CommentPlacement placement);
/// Comments must be //... or /* ... */
void setComment(const std::string& comment, CommentPlacement placement);
bool hasComment(CommentPlacement placement) const;
/// Include delimiters and embedded newlines.
@@ -433,13 +454,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);
@@ -462,7 +476,7 @@ private:
CommentInfo();
~CommentInfo();
void setComment(const char* text);
void setComment(const char* text, size_t len);
char* comment_;
};
@@ -490,17 +504,12 @@ private:
#endif
} value_;
ValueType type_ : 8;
int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
#ifdef JSON_VALUE_USE_INTERNAL_MAP
unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container.
int memberNameIsStatic_ : 1; // used by the ValueInternalMap container.
unsigned int memberNameIsStatic_ : 1; // used by the ValueInternalMap container.
#endif
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
@@ -1082,6 +1091,14 @@ public:
} // namespace Json
namespace std {
/// Specialize std::swap() for Json::Value.
template<>
inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); }
}
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(pop)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)

View File

@@ -4,9 +4,9 @@
#ifndef JSON_VERSION_H_INCLUDED
# define JSON_VERSION_H_INCLUDED
# define JSONCPP_VERSION_STRING "1.2.0"
# define JSONCPP_VERSION_MAJOR 1
# define JSONCPP_VERSION_MINOR 2
# define JSONCPP_VERSION_STRING "0.8.0"
# define JSONCPP_VERSION_MAJOR 0
# define JSONCPP_VERSION_MINOR 8
# define JSONCPP_VERSION_PATCH 0
# define JSONCPP_VERSION_QUALIFIER
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))

View File

@@ -11,6 +11,7 @@
#endif // if !defined(JSON_IS_AMALGAMATION)
#include <vector>
#include <string>
#include <ostream>
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
@@ -23,7 +24,111 @@ namespace Json {
class Value;
/**
Usage:
\code
using namespace Json;
void writeToStdout(StreamWriter::Factory const& factory, Value const& value) {
std::unique_ptr<StreamWriter> const writer(
factory.newStreamWriter());
writer->write(value, &std::cout);
std::cout << std::endl; // add lf and flush
}
\endcode
*/
class JSON_API StreamWriter {
protected:
std::ostream* sout_; // not owned; will not delete
public:
StreamWriter();
virtual ~StreamWriter();
/** Write Value into document as configured in sub-class.
Do not take ownership of sout, but maintain a reference during function.
\pre sout != NULL
\return zero on success
\throw std::exception possibly, depending on configuration
*/
virtual int write(Value const& root, std::ostream* sout) = 0;
/** \brief A simple abstract factory.
*/
class JSON_API Factory {
public:
virtual ~Factory();
/** \brief Allocate a CharReader via operator new().
* \throw std::exception if something goes wrong (e.g. invalid settings)
*/
virtual StreamWriter* newStreamWriter() const = 0;
}; // Factory
}; // StreamWriter
/** \brief Write into stringstream, then return string, for convenience.
* A StreamWriter will be created from the factory, used, and then deleted.
*/
std::string writeString(StreamWriter::Factory const& factory, Value const& root);
/** \brief Build a StreamWriter implementation.
Usage:
\code
using namespace Json;
Value value = ...;
StreamWriterBuilder builder;
builder.settings_["commentStyle"] = "None";
builder.settings_["indentation"] = " "; // or whatever you like
std::unique_ptr<Json::StreamWriter> writer(
builder.newStreamWriter());
writer->write(value, &std::cout);
std::cout << std::endl; // add lf and flush
\endcode
*/
class JSON_API StreamWriterBuilder : public StreamWriter::Factory {
public:
// Note: We use a Json::Value so that we can add data-members to this class
// without a major version bump.
/** Configuration of this builder.
Available settings (case-sensitive):
- "commentStyle": "None" or "All"
- "indentation": "<anything>"
- "enableYAMLCompatibility": false or true
- slightly change the whitespace around colons
- "dropNullPlaceholders": false or true
- Drop the "null" string from the writer's output for nullValues.
Strictly speaking, this is not valid JSON. But when the output is being
fed to a browser's Javascript, it makes for smaller output and the
browser can handle the output just fine.
You can examine 'settings_` yourself
to see the defaults. You can also write and read them just like any
JSON Value.
\sa setDefaults()
*/
Json::Value settings_;
StreamWriterBuilder();
virtual ~StreamWriterBuilder();
/**
* \throw std::exception if something goes wrong (e.g. invalid settings)
*/
virtual StreamWriter* newStreamWriter() const;
/** \return true if 'settings' are legal and consistent;
* otherwise, indicate bad settings via 'invalid'.
*/
bool validate(Json::Value* invalid) const;
/** Called by ctor, but you can use this to reset settings_.
* \pre 'settings' != NULL (but Json::null is fine)
* \remark Defaults:
* \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults
*/
static void setDefaults(Json::Value* settings);
};
/** \brief Abstract class for writers.
* \deprecated Use StreamWriter.
*/
class JSON_API Writer {
public:
@@ -39,6 +144,7 @@ public:
*consumption,
* but may be usefull to support feature such as RPC where bandwith is limited.
* \sa Reader, Value
* \deprecated Use StreamWriterBuilder.
*/
class JSON_API FastWriter : public Writer {
public:
@@ -47,15 +153,6 @@ public:
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);
@@ -64,8 +161,6 @@ private:
std::string document_;
bool yamlCompatiblityEnabled_;
bool dropNullPlaceholders_;
bool omitEndingLineFeed_;
};
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
@@ -90,6 +185,7 @@ private:
*#CommentPlacement.
*
* \sa Reader, Value, Value::setComment()
* \deprecated Use StreamWriterBuilder.
*/
class JSON_API StyledWriter : public Writer {
public:
@@ -151,6 +247,7 @@ private:
*
* \param indentation Each level will be indented by this amount extra.
* \sa Reader, Value, Value::setComment()
* \deprecated Use StreamWriterBuilder.
*/
class JSON_API StyledStreamWriter {
public:
@@ -187,7 +284,8 @@ private:
std::string indentString_;
int rightMargin_;
std::string indentation_;
bool addChildValues_;
bool addChildValues_ : 1;
bool indented_ : 1;
};
#if defined(JSON_HAS_INT64)

View File

@@ -161,8 +161,7 @@ def generate(env):
Add builders and construction variables for the
SrcDist tool.
"""
## doxyfile_scanner = env.Scanner(
## DoxySourceScan,
## doxyfile_scanner = env.Scanner(## DoxySourceScan,
## "DoxySourceScan",
## scan_check = DoxySourceScanCheck,
##)

View File

@@ -7,7 +7,13 @@ ENDIF(JSONCPP_LIB_BUILD_SHARED)
ADD_EXECUTABLE(jsontestrunner_exe
main.cpp
)
IF(JSONCPP_LIB_BUILD_SHARED)
TARGET_LINK_LIBRARIES(jsontestrunner_exe jsoncpp_lib)
ELSE(JSONCPP_LIB_BUILD_SHARED)
TARGET_LINK_LIBRARIES(jsontestrunner_exe jsoncpp_lib_static)
ENDIF(JSONCPP_LIB_BUILD_SHARED)
SET_TARGET_PROPERTIES(jsontestrunner_exe PROPERTIES OUTPUT_NAME jsontestrunner_exe)
IF(PYTHONINTERP_FOUND)

View File

@@ -8,12 +8,22 @@
#include <json/json.h>
#include <algorithm> // sort
#include <sstream>
#include <stdio.h>
#if defined(_MSC_VER) && _MSC_VER >= 1310
#pragma warning(disable : 4996) // disable fopen deprecation warning
#endif
struct Options
{
std::string path;
Json::Features features;
bool parseOnly;
typedef std::string (*writeFuncType)(Json::Value const&);
writeFuncType write;
};
static std::string normalizeFloatingPointStr(double value) {
char buffer[32];
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
@@ -129,43 +139,67 @@ printValueTree(FILE* fout, Json::Value& value, const std::string& path = ".") {
static int parseAndSaveValueTree(const std::string& input,
const std::string& actual,
const std::string& kind,
Json::Value& root,
const Json::Features& features,
bool parseOnly) {
bool parseOnly,
Json::Value* root)
{
Json::Reader reader(features);
bool parsingSuccessful = reader.parse(input, root);
bool parsingSuccessful = reader.parse(input, *root);
if (!parsingSuccessful) {
printf("Failed to parse %s file: \n%s\n",
kind.c_str(),
reader.getFormattedErrorMessages().c_str());
return 1;
}
if (!parseOnly) {
FILE* factual = fopen(actual.c_str(), "wt");
if (!factual) {
printf("Failed to create %s actual file.\n", kind.c_str());
return 2;
}
printValueTree(factual, root);
printValueTree(factual, *root);
fclose(factual);
}
return 0;
}
static int rewriteValueTree(const std::string& rewritePath,
const Json::Value& root,
std::string& rewrite) {
// static std::string useFastWriter(Json::Value const& root) {
// Json::FastWriter writer;
// writer.enableYAMLCompatibility();
// return writer.write(root);
// }
static std::string useStyledWriter(
Json::Value const& root)
{
Json::StyledWriter writer;
rewrite = writer.write(root);
return writer.write(root);
}
static std::string useStyledStreamWriter(
Json::Value const& root)
{
Json::StyledStreamWriter writer;
std::ostringstream sout;
writer.write(sout, root);
return sout.str();
}
static std::string useBuiltStyledStreamWriter(
Json::Value const& root)
{
Json::StreamWriterBuilder builder;
return Json::writeString(builder, root);
}
static int rewriteValueTree(
const std::string& rewritePath,
const Json::Value& root,
Options::writeFuncType write,
std::string* rewrite)
{
*rewrite = write(root);
FILE* fout = fopen(rewritePath.c_str(), "wt");
if (!fout) {
printf("Failed to create rewrite file: %s\n", rewritePath.c_str());
return 2;
}
fprintf(fout, "%s\n", rewrite.c_str());
fprintf(fout, "%s\n", rewrite->c_str());
fclose(fout);
return 0;
}
@@ -194,84 +228,98 @@ static int printUsage(const char* argv[]) {
return 3;
}
int parseCommandLine(int argc,
const char* argv[],
Json::Features& features,
std::string& path,
bool& parseOnly) {
parseOnly = false;
static int parseCommandLine(
int argc, const char* argv[], Options* opts)
{
opts->parseOnly = false;
opts->write = &useStyledWriter;
if (argc < 2) {
return printUsage(argv);
}
int index = 1;
if (std::string(argv[1]) == "--json-checker") {
features = Json::Features::strictMode();
parseOnly = true;
if (std::string(argv[index]) == "--json-checker") {
opts->features = Json::Features::strictMode();
opts->parseOnly = true;
++index;
}
if (std::string(argv[1]) == "--json-config") {
if (std::string(argv[index]) == "--json-config") {
printConfig();
return 3;
}
if (std::string(argv[index]) == "--json-writer") {
++index;
std::string const writerName(argv[index++]);
if (writerName == "StyledWriter") {
opts->write = &useStyledWriter;
} else if (writerName == "StyledStreamWriter") {
opts->write = &useStyledStreamWriter;
} else if (writerName == "BuiltStyledStreamWriter") {
opts->write = &useBuiltStyledStreamWriter;
} else {
printf("Unknown '--json-writer %s'\n", writerName.c_str());
return 4;
}
}
if (index == argc || index + 1 < argc) {
return printUsage(argv);
}
path = argv[index];
opts->path = argv[index];
return 0;
}
static int runTest(Options const& opts)
{
int exitCode = 0;
int main(int argc, const char* argv[]) {
std::string path;
Json::Features features;
bool parseOnly;
int exitCode = parseCommandLine(argc, argv, features, path, parseOnly);
if (exitCode != 0) {
return exitCode;
}
try {
std::string input = readInputTestFile(path.c_str());
std::string input = readInputTestFile(opts.path.c_str());
if (input.empty()) {
printf("Failed to read input or empty input: %s\n", path.c_str());
printf("Failed to read input or empty input: %s\n", opts.path.c_str());
return 3;
}
std::string basePath = removeSuffix(argv[1], ".json");
if (!parseOnly && basePath.empty()) {
std::string basePath = removeSuffix(opts.path, ".json");
if (!opts.parseOnly && basePath.empty()) {
printf("Bad input path. Path does not end with '.expected':\n%s\n",
path.c_str());
opts.path.c_str());
return 3;
}
std::string actualPath = basePath + ".actual";
std::string rewritePath = basePath + ".rewrite";
std::string rewriteActualPath = basePath + ".actual-rewrite";
std::string const actualPath = basePath + ".actual";
std::string const rewritePath = basePath + ".rewrite";
std::string const rewriteActualPath = basePath + ".actual-rewrite";
Json::Value root;
exitCode = parseAndSaveValueTree(
input, actualPath, "input", root, features, parseOnly);
if (exitCode == 0 && !parseOnly) {
input, actualPath, "input",
opts.features, opts.parseOnly, &root);
if (exitCode || opts.parseOnly) {
return exitCode;
}
std::string rewrite;
exitCode = rewriteValueTree(rewritePath, root, rewrite);
if (exitCode == 0) {
exitCode = rewriteValueTree(rewritePath, root, opts.write, &rewrite);
if (exitCode) {
return exitCode;
}
Json::Value rewriteRoot;
exitCode = parseAndSaveValueTree(rewrite,
rewriteActualPath,
"rewrite",
rewriteRoot,
features,
parseOnly);
exitCode = parseAndSaveValueTree(
rewrite, rewriteActualPath, "rewrite",
opts.features, opts.parseOnly, &rewriteRoot);
if (exitCode) {
return exitCode;
}
return 0;
}
int main(int argc, const char* argv[]) {
Options opts;
int exitCode = parseCommandLine(argc, argv, &opts);
if (exitCode != 0) {
printf("Failed to parse command-line.");
return exitCode;
}
try {
return runTest(opts);
}
catch (const std::exception& e) {
printf("Unhandled exception:\n%s\n", e.what());
exitCode = 1;
return 1;
}
return exitCode;
}

View File

@@ -1,15 +1,10 @@
OPTION(JSONCPP_LIB_BUILD_SHARED "Build jsoncpp_lib as a shared library." OFF)
OPTION(JSONCPP_LIB_BUILD_STATIC "Build jsoncpp_lib static library." ON)
IF(BUILD_SHARED_LIBS)
SET(JSONCPP_LIB_BUILD_SHARED ON)
ENDIF(BUILD_SHARED_LIBS)
IF(JSONCPP_LIB_BUILD_SHARED)
SET(JSONCPP_LIB_TYPE SHARED)
ADD_DEFINITIONS( -DJSON_DLL_BUILD )
ELSE(JSONCPP_LIB_BUILD_SHARED)
SET(JSONCPP_LIB_TYPE STATIC)
ENDIF(JSONCPP_LIB_BUILD_SHARED)
if( CMAKE_COMPILER_IS_GNUCXX )
#Get compiler version.
execute_process( COMMAND ${CMAKE_CXX_COMPILER} -dumpversion
@@ -36,25 +31,14 @@ SET( PUBLIC_HEADERS
SOURCE_GROUP( "Public API" FILES ${PUBLIC_HEADERS} )
ADD_LIBRARY( jsoncpp_lib ${JSONCPP_LIB_TYPE}
${PUBLIC_HEADERS}
SET(jsoncpp_sources
json_tool.h
json_reader.cpp
json_batchallocator.h
json_valueiterator.inl
json_value.cpp
json_writer.cpp
version.h.in
)
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES OUTPUT_NAME jsoncpp )
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_VERSION_MAJOR} )
IF(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
TARGET_INCLUDE_DIRECTORIES( jsoncpp_lib PUBLIC
$<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
)
ENDIF(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
version.h.in)
# Install instructions for this target
IF(JSONCPP_WITH_CMAKE_PACKAGE)
@@ -63,8 +47,40 @@ ELSE(JSONCPP_WITH_CMAKE_PACKAGE)
SET(INSTALL_EXPORT)
ENDIF(JSONCPP_WITH_CMAKE_PACKAGE)
IF(JSONCPP_LIB_BUILD_SHARED)
ADD_DEFINITIONS( -DJSON_DLL_BUILD )
ADD_LIBRARY(jsoncpp_lib SHARED ${PUBLIC_HEADERS} ${jsoncpp_sources})
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_VERSION_MAJOR})
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES OUTPUT_NAME jsoncpp )
INSTALL( TARGETS jsoncpp_lib ${INSTALL_EXPORT}
RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR}
LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR}
ARCHIVE DESTINATION ${ARCHIVE_INSTALL_DIR}
ARCHIVE DESTINATION ${ARCHIVE_INSTALL_DIR})
IF(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
TARGET_INCLUDE_DIRECTORIES( jsoncpp_lib PUBLIC
$<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>)
ENDIF(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
ENDIF()
IF(JSONCPP_LIB_BUILD_STATIC)
ADD_LIBRARY(jsoncpp_lib_static STATIC ${PUBLIC_HEADERS} ${jsoncpp_sources})
SET_TARGET_PROPERTIES( jsoncpp_lib_static PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_VERSION_MAJOR})
SET_TARGET_PROPERTIES( jsoncpp_lib_static PROPERTIES OUTPUT_NAME jsoncpp )
INSTALL( TARGETS jsoncpp_lib_static ${INSTALL_EXPORT}
RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR}
LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR}
ARCHIVE DESTINATION ${ARCHIVE_INSTALL_DIR})
IF(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
TARGET_INCLUDE_DIRECTORIES( jsoncpp_lib_static PUBLIC
$<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
)
ENDIF(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
ENDIF()

File diff suppressed because it is too large Load Diff

View File

@@ -31,11 +31,13 @@ namespace Json {
#if defined(__ARMEL__)
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
#else
// This exists for binary compatibility only. Use nullRef.
static const 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<const Value&>(kNullRef);
const Value& Value::nullRef = reinterpret_cast<const Value&>(kNullRef);
const Int Value::minInt = Int(~(UInt(-1) / 2));
const Int Value::maxInt = Int(UInt(-1) / 2);
@@ -141,15 +143,17 @@ Value::CommentInfo::~CommentInfo() {
releaseStringValue(comment_);
}
void Value::CommentInfo::setComment(const char* text) {
if (comment_)
void Value::CommentInfo::setComment(const char* text, size_t len) {
if (comment_) {
releaseStringValue(comment_);
comment_ = 0;
}
JSON_ASSERT(text != 0);
JSON_ASSERT_MESSAGE(
text[0] == '\0' || text[0] == '/',
"in Json::Value::setComment(): Comments must start with /");
// It seems that /**/ style comments are acceptable as well.
comment_ = duplicateStringValue(text);
comment_ = duplicateStringValue(text, len);
}
// //////////////////////////////////////////////////////////////////
@@ -189,8 +193,9 @@ void Value::CZString::swap(CZString& other) {
std::swap(index_, other.index_);
}
Value::CZString& Value::CZString::operator=(CZString other) {
swap(other);
Value::CZString &Value::CZString::operator=(const CZString &other) {
CZString temp(other);
swap(temp);
return *this;
}
@@ -328,7 +333,7 @@ Value::Value(const Value& other)
itemIsUsed_(0)
#endif
,
comments_(0), start_(other.start_), limit_(other.limit_) {
comments_(0) {
switch (type_) {
case nullValue:
case intValue:
@@ -367,7 +372,8 @@ Value::Value(const Value& other)
for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {
const CommentInfo& otherComment = other.comments_[comment];
if (otherComment.comment_)
comments_[comment].setComment(otherComment.comment_);
comments_[comment].setComment(
otherComment.comment_, strlen(otherComment.comment_));
}
}
}
@@ -405,8 +411,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;
}
@@ -423,8 +430,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_; }
@@ -799,8 +804,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_) {
#ifndef JSON_VALUE_USE_INTERNAL_MAP
case arrayValue:
@@ -854,7 +857,7 @@ Value& Value::operator[](ArrayIndex index) {
if (it != value_.map_->end() && (*it).first == key)
return (*it).second;
ObjectValues::value_type defaultValue(key, null);
ObjectValues::value_type defaultValue(key, nullRef);
it = value_.map_->insert(it, defaultValue);
return (*it).second;
#else
@@ -874,16 +877,16 @@ const Value& Value::operator[](ArrayIndex index) const {
type_ == nullValue || type_ == arrayValue,
"in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
if (type_ == nullValue)
return null;
return nullRef;
#ifndef JSON_VALUE_USE_INTERNAL_MAP
CZString key(index);
ObjectValues::const_iterator it = value_.map_->find(key);
if (it == value_.map_->end())
return null;
return nullRef;
return (*it).second;
#else
Value* value = value_.array_->find(index);
return value ? *value : null;
return value ? *value : nullRef;
#endif
}
@@ -905,8 +908,6 @@ void Value::initBasic(ValueType type, bool allocated) {
itemIsUsed_ = 0;
#endif
comments_ = 0;
start_ = 0;
limit_ = 0;
}
Value& Value::resolveReference(const char* key, bool isStatic) {
@@ -922,7 +923,7 @@ Value& Value::resolveReference(const char* key, bool isStatic) {
if (it != value_.map_->end() && (*it).first == actualKey)
return (*it).second;
ObjectValues::value_type defaultValue(actualKey, null);
ObjectValues::value_type defaultValue(actualKey, nullRef);
it = value_.map_->insert(it, defaultValue);
Value& value = (*it).second;
return value;
@@ -933,7 +934,7 @@ Value& Value::resolveReference(const char* key, bool isStatic) {
Value Value::get(ArrayIndex index, const Value& defaultValue) const {
const Value* value = &((*this)[index]);
return value == &null ? defaultValue : *value;
return value == &nullRef ? defaultValue : *value;
}
bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
@@ -943,16 +944,16 @@ const Value& Value::operator[](const char* key) const {
type_ == nullValue || type_ == objectValue,
"in Json::Value::operator[](char const*)const: requires objectValue");
if (type_ == nullValue)
return null;
return nullRef;
#ifndef JSON_VALUE_USE_INTERNAL_MAP
CZString actualKey(key, CZString::noDuplication);
ObjectValues::const_iterator it = value_.map_->find(actualKey);
if (it == value_.map_->end())
return null;
return nullRef;
return (*it).second;
#else
const Value* value = value_.map_->find(key);
return value ? *value : null;
return value ? *value : nullRef;
#endif
}
@@ -982,42 +983,81 @@ Value& Value::append(const Value& value) { return (*this)[size()] = value; }
Value Value::get(const char* key, const Value& defaultValue) const {
const Value* value = &((*this)[key]);
return value == &null ? defaultValue : *value;
return value == &nullRef ? defaultValue : *value;
}
Value Value::get(const std::string& key, const Value& defaultValue) const {
return get(key.c_str(), defaultValue);
}
Value Value::removeMember(const char* key) {
JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
"in Json::Value::removeMember(): requires objectValue");
if (type_ == nullValue)
return null;
bool Value::removeMember(const char* key, Value* removed) {
if (type_ != objectValue) {
return false;
}
#ifndef JSON_VALUE_USE_INTERNAL_MAP
CZString actualKey(key, CZString::noDuplication);
ObjectValues::iterator it = value_.map_->find(actualKey);
if (it == value_.map_->end())
return null;
Value old(it->second);
return false;
*removed = it->second;
value_.map_->erase(it);
return old;
return true;
#else
Value* value = value_.map_->find(key);
if (value) {
Value old(*value);
*removed = *value;
value_.map_.remove(key);
return old;
return true;
} else {
return null;
return false;
}
#endif
}
Value Value::removeMember(const char* key) {
JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
"in Json::Value::removeMember(): requires objectValue");
if (type_ == nullValue)
return nullRef;
Value removed; // null
removeMember(key, &removed);
return removed; // still null if removeMember() did nothing
}
Value Value::removeMember(const std::string& key) {
return removeMember(key.c_str());
}
bool Value::removeIndex(ArrayIndex index, Value* removed) {
if (type_ != arrayValue) {
return false;
}
#ifdef JSON_VALUE_USE_INTERNAL_MAP
JSON_FAIL_MESSAGE("removeIndex is not implemented for ValueInternalArray.");
return false;
#else
CZString key(index);
ObjectValues::iterator it = value_.map_->find(key);
if (it == value_.map_->end()) {
return false;
}
*removed = it->second;
ArrayIndex oldSize = size();
// shift left all items left, into the place of the "removed"
for (ArrayIndex i = index; i < (oldSize - 1); ++i){
CZString key(i);
(*value_.map_)[key] = (*this)[i + 1];
}
// erase the last one ("leftover")
CZString keyLast(oldSize - 1);
ObjectValues::iterator itLast = value_.map_->find(keyLast);
value_.map_->erase(itLast);
return true;
#endif
}
#ifdef JSON_USE_CPPTL
Value Value::get(const CppTL::ConstString& key,
const Value& defaultValue) const {
@@ -1027,7 +1067,7 @@ Value Value::get(const CppTL::ConstString& key,
bool Value::isMember(const char* key) const {
const Value* value = &((*this)[key]);
return value != &null;
return value != &nullRef;
}
bool Value::isMember(const std::string& key) const {
@@ -1186,14 +1226,22 @@ bool Value::isArray() const { return type_ == arrayValue; }
bool Value::isObject() const { return type_ == objectValue; }
void Value::setComment(const char* comment, CommentPlacement placement) {
void Value::setComment(const char* comment, size_t len, CommentPlacement placement) {
if (!comments_)
comments_ = new CommentInfo[numberOfCommentPlacement];
comments_[placement].setComment(comment);
if ((len > 0) && (comment[len-1] == '\n')) {
// Always discard trailing newline, to aid indentation.
len -= 1;
}
comments_[placement].setComment(comment, len);
}
void Value::setComment(const char* comment, CommentPlacement placement) {
setComment(comment, strlen(comment), placement);
}
void Value::setComment(const std::string& comment, CommentPlacement placement) {
setComment(comment.c_str(), placement);
setComment(comment.c_str(), comment.length(), placement);
}
bool Value::hasComment(CommentPlacement placement) const {
@@ -1206,14 +1254,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);
@@ -1433,7 +1473,7 @@ const Value& Path::resolve(const Value& root) const {
// Error: unable to resolve path (object value expected at position...)
}
node = &((*node)[arg.key_]);
if (node == &Value::null) {
if (node == &Value::nullRef) {
// Error: unable to resolve path (object has no member named '' at
// position...)
}
@@ -1454,7 +1494,7 @@ Value Path::resolve(const Value& root, const Value& defaultValue) const {
if (!node->isObject())
return defaultValue;
node = &((*node)[arg.key_]);
if (node == &Value::null)
if (node == &Value::nullRef)
return defaultValue;
}
}

View File

@@ -7,13 +7,16 @@
#include <json/writer.h>
#include "json_tool.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
#include <iomanip>
#include <memory>
#include <sstream>
#include <utility>
#include <set>
#include <stdexcept>
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <sstream>
#include <iomanip>
#include <math.h>
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
#include <float.h>
@@ -33,6 +36,12 @@
namespace Json {
#if __cplusplus >= 201103L
typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
#else
typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
#endif
static bool containsControlCharacter(const char* str) {
while (*str) {
if (isControlCharacter(*(str++)))
@@ -183,19 +192,13 @@ 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";
return document_;
}
@@ -203,7 +206,6 @@ std::string FastWriter::write(const Value& root) {
void FastWriter::writeValue(const Value& value) {
switch (value.type()) {
case nullValue:
if (!dropNullPlaceholders_)
document_ += "null";
break;
case intValue:
@@ -376,6 +378,9 @@ bool StyledWriter::isMultineArray(const Value& value) {
addChildValues_ = true;
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
for (int index = 0; index < size; ++index) {
if (hasCommentForValue(value[index])) {
isMultiLine = true;
}
writeValue(value[index]);
lineLength += int(childValues_[index].length());
}
@@ -421,26 +426,27 @@ void StyledWriter::writeCommentBeforeValue(const Value& root) {
document_ += "\n";
writeIndent();
std::string normalizedComment = normalizeEOL(root.getComment(commentBefore));
std::string::const_iterator iter = normalizedComment.begin();
while (iter != normalizedComment.end()) {
const std::string& comment = root.getComment(commentBefore);
std::string::const_iterator iter = comment.begin();
while (iter != comment.end()) {
document_ += *iter;
if (*iter == '\n' && *(iter + 1) == '/')
if (*iter == '\n' &&
(iter != comment.end() && *(iter + 1) == '/'))
writeIndent();
++iter;
}
// Comments are stripped of newlines, so add one here
// Comments are stripped of trailing newlines, so add one here
document_ += "\n";
}
void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
if (root.hasComment(commentAfterOnSameLine))
document_ += " " + normalizeEOL(root.getComment(commentAfterOnSameLine));
document_ += " " + root.getComment(commentAfterOnSameLine);
if (root.hasComment(commentAfter)) {
document_ += "\n";
document_ += normalizeEOL(root.getComment(commentAfter));
document_ += root.getComment(commentAfter);
document_ += "\n";
}
}
@@ -451,25 +457,6 @@ bool StyledWriter::hasCommentForValue(const Value& value) {
value.hasComment(commentAfter);
}
std::string StyledWriter::normalizeEOL(const std::string& text) {
std::string normalized;
normalized.reserve(text.length());
const char* begin = text.c_str();
const char* end = begin + text.length();
const char* current = begin;
while (current != end) {
char c = *current++;
if (c == '\r') // mac or dos EOL
{
if (*current == '\n') // convert dos EOL
++current;
normalized += '\n';
} else // handle unix EOL & other char
normalized += c;
}
return normalized;
}
// Class StyledStreamWriter
// //////////////////////////////////////////////////////////////////
@@ -481,7 +468,10 @@ void StyledStreamWriter::write(std::ostream& out, const Value& root) {
document_ = &out;
addChildValues_ = false;
indentString_ = "";
indented_ = true;
writeCommentBeforeValue(root);
if (!indented_) writeIndent();
indented_ = true;
writeValue(root);
writeCommentAfterValueOnSameLine(root);
*document_ << "\n";
@@ -557,8 +547,10 @@ void StyledStreamWriter::writeArrayValue(const Value& value) {
if (hasChildValue)
writeWithIndent(childValues_[index]);
else {
writeIndent();
if (!indented_) writeIndent();
indented_ = true;
writeValue(childValue);
indented_ = false;
}
if (++index == size) {
writeCommentAfterValueOnSameLine(childValue);
@@ -599,6 +591,9 @@ bool StyledStreamWriter::isMultineArray(const Value& value) {
addChildValues_ = true;
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
for (int index = 0; index < size; ++index) {
if (hasCommentForValue(value[index])) {
isMultiLine = true;
}
writeValue(value[index]);
lineLength += int(childValues_[index].length());
}
@@ -616,24 +611,17 @@ void StyledStreamWriter::pushValue(const std::string& value) {
}
void StyledStreamWriter::writeIndent() {
/*
Some comments in this method would have been nice. ;-)
if ( !document_.empty() )
{
char last = document_[document_.length()-1];
if ( last == ' ' ) // already indented
return;
if ( last != '\n' ) // Comments may add new-line
*document_ << '\n';
}
*/
// blep intended this to look at the so-far-written string
// to determine whether we are already indented, but
// with a stream we cannot do that. So we rely on some saved state.
// The caller checks indented_.
*document_ << '\n' << indentString_;
}
void StyledStreamWriter::writeWithIndent(const std::string& value) {
writeIndent();
if (!indented_) writeIndent();
*document_ << value;
indented_ = false;
}
void StyledStreamWriter::indent() { indentString_ += indentation_; }
@@ -646,19 +634,30 @@ void StyledStreamWriter::unindent() {
void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
if (!root.hasComment(commentBefore))
return;
*document_ << normalizeEOL(root.getComment(commentBefore));
*document_ << "\n";
if (!indented_) writeIndent();
const std::string& comment = root.getComment(commentBefore);
std::string::const_iterator iter = comment.begin();
while (iter != comment.end()) {
*document_ << *iter;
if (*iter == '\n' &&
(iter != comment.end() && *(iter + 1) == '/'))
// writeIndent(); // would include newline
*document_ << indentString_;
++iter;
}
indented_ = false;
}
void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
if (root.hasComment(commentAfterOnSameLine))
*document_ << " " + normalizeEOL(root.getComment(commentAfterOnSameLine));
*document_ << ' ' << root.getComment(commentAfterOnSameLine);
if (root.hasComment(commentAfter)) {
*document_ << "\n";
*document_ << normalizeEOL(root.getComment(commentAfter));
*document_ << "\n";
writeIndent();
*document_ << root.getComment(commentAfter);
}
indented_ = false;
}
bool StyledStreamWriter::hasCommentForValue(const Value& value) {
@@ -667,28 +666,376 @@ bool StyledStreamWriter::hasCommentForValue(const Value& value) {
value.hasComment(commentAfter);
}
std::string StyledStreamWriter::normalizeEOL(const std::string& text) {
std::string normalized;
normalized.reserve(text.length());
const char* begin = text.c_str();
const char* end = begin + text.length();
const char* current = begin;
while (current != end) {
char c = *current++;
if (c == '\r') // mac or dos EOL
//////////////////////////
// BuiltStyledStreamWriter
/// Scoped enums are not available until C++11.
struct CommentStyle {
/// Decide whether to write comments.
enum Enum {
None, ///< Drop all comments.
Most, ///< Recover odd behavior of previous versions (not implemented yet).
All ///< Keep all comments.
};
};
struct BuiltStyledStreamWriter : public StreamWriter
{
BuiltStyledStreamWriter(
std::string const& indentation,
CommentStyle::Enum cs,
std::string const& colonSymbol,
std::string const& nullSymbol,
std::string const& endingLineFeedSymbol);
virtual int write(Value const& root, std::ostream* sout);
private:
void writeValue(Value const& value);
void writeArrayValue(Value const& value);
bool isMultineArray(Value const& value);
void pushValue(std::string const& value);
void writeIndent();
void writeWithIndent(std::string const& value);
void indent();
void unindent();
void writeCommentBeforeValue(Value const& root);
void writeCommentAfterValueOnSameLine(Value const& root);
static bool hasCommentForValue(const Value& value);
typedef std::vector<std::string> ChildValues;
ChildValues childValues_;
std::string indentString_;
int rightMargin_;
std::string indentation_;
CommentStyle::Enum cs_;
std::string colonSymbol_;
std::string nullSymbol_;
std::string endingLineFeedSymbol_;
bool addChildValues_ : 1;
bool indented_ : 1;
};
BuiltStyledStreamWriter::BuiltStyledStreamWriter(
std::string const& indentation,
CommentStyle::Enum cs,
std::string const& colonSymbol,
std::string const& nullSymbol,
std::string const& endingLineFeedSymbol)
: rightMargin_(74)
, indentation_(indentation)
, cs_(cs)
, colonSymbol_(colonSymbol)
, nullSymbol_(nullSymbol)
, endingLineFeedSymbol_(endingLineFeedSymbol)
, addChildValues_(false)
, indented_(false)
{
if (*current == '\n') // convert dos EOL
++current;
normalized += '\n';
} else // handle unix EOL & other char
normalized += c;
}
return normalized;
int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout)
{
sout_ = sout;
addChildValues_ = false;
indented_ = true;
indentString_ = "";
writeCommentBeforeValue(root);
if (!indented_) writeIndent();
indented_ = true;
writeValue(root);
writeCommentAfterValueOnSameLine(root);
*sout_ << endingLineFeedSymbol_;
sout_ = NULL;
return 0;
}
void BuiltStyledStreamWriter::writeValue(Value const& value) {
switch (value.type()) {
case nullValue:
pushValue(nullSymbol_);
break;
case intValue:
pushValue(valueToString(value.asLargestInt()));
break;
case uintValue:
pushValue(valueToString(value.asLargestUInt()));
break;
case realValue:
pushValue(valueToString(value.asDouble()));
break;
case stringValue:
pushValue(valueToQuotedString(value.asCString()));
break;
case booleanValue:
pushValue(valueToString(value.asBool()));
break;
case arrayValue:
writeArrayValue(value);
break;
case objectValue: {
Value::Members members(value.getMemberNames());
if (members.empty())
pushValue("{}");
else {
writeWithIndent("{");
indent();
Value::Members::iterator it = members.begin();
for (;;) {
std::string const& name = *it;
Value const& childValue = value[name];
writeCommentBeforeValue(childValue);
writeWithIndent(valueToQuotedString(name.c_str()));
*sout_ << colonSymbol_;
writeValue(childValue);
if (++it == members.end()) {
writeCommentAfterValueOnSameLine(childValue);
break;
}
*sout_ << ",";
writeCommentAfterValueOnSameLine(childValue);
}
unindent();
writeWithIndent("}");
}
} break;
}
}
std::ostream& operator<<(std::ostream& sout, const Value& root) {
Json::StyledStreamWriter writer;
writer.write(sout, root);
void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
unsigned size = value.size();
if (size == 0)
pushValue("[]");
else {
bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value);
if (isMultiLine) {
writeWithIndent("[");
indent();
bool hasChildValue = !childValues_.empty();
unsigned index = 0;
for (;;) {
Value const& childValue = value[index];
writeCommentBeforeValue(childValue);
if (hasChildValue)
writeWithIndent(childValues_[index]);
else {
if (!indented_) writeIndent();
indented_ = true;
writeValue(childValue);
indented_ = false;
}
if (++index == size) {
writeCommentAfterValueOnSameLine(childValue);
break;
}
*sout_ << ",";
writeCommentAfterValueOnSameLine(childValue);
}
unindent();
writeWithIndent("]");
} else // output on a single line
{
assert(childValues_.size() == size);
*sout_ << "[";
if (!indentation_.empty()) *sout_ << " ";
for (unsigned index = 0; index < size; ++index) {
if (index > 0)
*sout_ << ", ";
*sout_ << childValues_[index];
}
if (!indentation_.empty()) *sout_ << " ";
*sout_ << "]";
}
}
}
bool BuiltStyledStreamWriter::isMultineArray(Value const& value) {
int size = value.size();
bool isMultiLine = size * 3 >= rightMargin_;
childValues_.clear();
for (int index = 0; index < size && !isMultiLine; ++index) {
Value const& childValue = value[index];
isMultiLine =
isMultiLine || ((childValue.isArray() || childValue.isObject()) &&
childValue.size() > 0);
}
if (!isMultiLine) // check if line length > max line length
{
childValues_.reserve(size);
addChildValues_ = true;
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
for (int index = 0; index < size; ++index) {
if (hasCommentForValue(value[index])) {
isMultiLine = true;
}
writeValue(value[index]);
lineLength += int(childValues_[index].length());
}
addChildValues_ = false;
isMultiLine = isMultiLine || lineLength >= rightMargin_;
}
return isMultiLine;
}
void BuiltStyledStreamWriter::pushValue(std::string const& value) {
if (addChildValues_)
childValues_.push_back(value);
else
*sout_ << value;
}
void BuiltStyledStreamWriter::writeIndent() {
// blep intended this to look at the so-far-written string
// to determine whether we are already indented, but
// with a stream we cannot do that. So we rely on some saved state.
// The caller checks indented_.
if (!indentation_.empty()) {
// In this case, drop newlines too.
*sout_ << '\n' << indentString_;
}
}
void BuiltStyledStreamWriter::writeWithIndent(std::string const& value) {
if (!indented_) writeIndent();
*sout_ << value;
indented_ = false;
}
void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
void BuiltStyledStreamWriter::unindent() {
assert(indentString_.size() >= indentation_.size());
indentString_.resize(indentString_.size() - indentation_.size());
}
void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
if (cs_ == CommentStyle::None) return;
if (!root.hasComment(commentBefore))
return;
if (!indented_) writeIndent();
const std::string& comment = root.getComment(commentBefore);
std::string::const_iterator iter = comment.begin();
while (iter != comment.end()) {
*sout_ << *iter;
if (*iter == '\n' &&
(iter != comment.end() && *(iter + 1) == '/'))
// writeIndent(); // would write extra newline
*sout_ << indentString_;
++iter;
}
indented_ = false;
}
void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) {
if (cs_ == CommentStyle::None) return;
if (root.hasComment(commentAfterOnSameLine))
*sout_ << " " + root.getComment(commentAfterOnSameLine);
if (root.hasComment(commentAfter)) {
writeIndent();
*sout_ << root.getComment(commentAfter);
}
}
// static
bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
return value.hasComment(commentBefore) ||
value.hasComment(commentAfterOnSameLine) ||
value.hasComment(commentAfter);
}
///////////////
// StreamWriter
StreamWriter::StreamWriter()
: sout_(NULL)
{
}
StreamWriter::~StreamWriter()
{
}
StreamWriter::Factory::~Factory()
{}
StreamWriterBuilder::StreamWriterBuilder()
{
setDefaults(&settings_);
}
StreamWriterBuilder::~StreamWriterBuilder()
{}
StreamWriter* StreamWriterBuilder::newStreamWriter() const
{
std::string indentation = settings_["indentation"].asString();
std::string cs_str = settings_["commentStyle"].asString();
bool eyc = settings_["enableYAMLCompatibility"].asBool();
bool dnp = settings_["dropNullPlaceholders"].asBool();
CommentStyle::Enum cs = CommentStyle::All;
if (cs_str == "All") {
cs = CommentStyle::All;
} else if (cs_str == "None") {
cs = CommentStyle::None;
} else {
throw std::runtime_error("commentStyle must be 'All' or 'None'");
}
std::string colonSymbol = " : ";
if (eyc) {
colonSymbol = ": ";
} else if (indentation.empty()) {
colonSymbol = ":";
}
std::string nullSymbol = "null";
if (dnp) {
nullSymbol = "";
}
std::string endingLineFeedSymbol = "";
return new BuiltStyledStreamWriter(
indentation, cs,
colonSymbol, nullSymbol, endingLineFeedSymbol);
}
static void getValidWriterKeys(std::set<std::string>* valid_keys)
{
valid_keys->clear();
valid_keys->insert("indentation");
valid_keys->insert("commentStyle");
valid_keys->insert("enableYAMLCompatibility");
valid_keys->insert("dropNullPlaceholders");
}
bool StreamWriterBuilder::validate(Json::Value* invalid) const
{
Json::Value my_invalid;
if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
Json::Value& inv = *invalid;
bool valid = true;
std::set<std::string> valid_keys;
getValidWriterKeys(&valid_keys);
Value::Members keys = settings_.getMemberNames();
size_t n = keys.size();
for (size_t i = 0; i < n; ++i) {
std::string const& key = keys[i];
if (valid_keys.find(key) == valid_keys.end()) {
inv[key] = settings_[key];
}
}
return valid;
}
// static
void StreamWriterBuilder::setDefaults(Json::Value* settings)
{
//! [StreamWriterBuilderDefaults]
(*settings)["commentStyle"] = "All";
(*settings)["indentation"] = "\t";
(*settings)["enableYAMLCompatibility"] = false;
(*settings)["dropNullPlaceholders"] = false;
//! [StreamWriterBuilderDefaults]
}
std::string writeString(StreamWriter::Factory const& builder, Value const& root) {
std::ostringstream sout;
StreamWriterPtr const writer(builder.newStreamWriter());
writer->write(root, &sout);
return sout.str();
}
std::ostream& operator<<(std::ostream& sout, Value const& root) {
StreamWriterBuilder builder;
StreamWriterPtr const writer(builder.newStreamWriter());
writer->write(root, &sout);
return sout;
}

View File

@@ -9,7 +9,15 @@ ADD_EXECUTABLE( jsoncpp_test
main.cpp
)
IF(JSONCPP_LIB_BUILD_SHARED)
TARGET_LINK_LIBRARIES(jsoncpp_test jsoncpp_lib)
ELSE(JSONCPP_LIB_BUILD_SHARED)
TARGET_LINK_LIBRARIES(jsoncpp_test jsoncpp_lib_static)
ENDIF(JSONCPP_LIB_BUILD_SHARED)
# another way to solve issue #90
#set_target_properties(jsoncpp_test PROPERTIES COMPILE_FLAGS -ffloat-store)
# Run unit tests in post-build
# (default cmake workflow hides away the test result into a file, resulting in poor dev workflow?!?)

View File

@@ -323,7 +323,7 @@ void Runner::listTests() const {
}
int Runner::runCommandLine(int argc, const char* argv[]) const {
typedef std::deque<std::string> TestNames;
// typedef std::deque<std::string> TestNames;
Runner subrunner;
for (int index = 1; index < argc; ++index) {
std::string opt = argv[index];

View File

@@ -178,8 +178,8 @@ private:
template <typename T, typename U>
TestResult& checkEqual(TestResult& result,
const T& expected,
const U& actual,
T expected,
U actual,
const char* file,
unsigned int line,
const char* expr) {
@@ -214,7 +214,7 @@ TestResult& checkStringEqual(TestResult& result,
#define JSONTEST_ASSERT_PRED(expr) \
{ \
JsonTest::PredicateContext _minitest_Context = { \
result_->predicateId_, __FILE__, __LINE__, #expr \
result_->predicateId_, __FILE__, __LINE__, #expr, NULL, NULL \
}; \
result_->predicateStackTail_->next_ = &_minitest_Context; \
result_->predicateId_ += 1; \

View File

@@ -7,6 +7,7 @@
#include <json/config.h>
#include <json/json.h>
#include <stdexcept>
#include <cstring>
// Make numeric limits more convenient to talk about.
// Assumes int type in 32 bits.
@@ -17,8 +18,8 @@
#define kint64min Json::Value::minInt64
#define kuint64max Json::Value::maxUInt64
static const double kdint64max = double(kint64max);
static const float kfint64max = float(kint64max);
//static const double kdint64max = double(kint64max);
//static const float kfint64max = float(kint64max);
static const float kfint32max = float(kint32max);
static const float kfuint32max = float(kuint32max);
@@ -198,6 +199,18 @@ JSONTEST_FIXTURE(ValueTest, objects) {
object1_["some other id"] = "foo";
JSONTEST_ASSERT_EQUAL(Json::Value("foo"), object1_["some other id"]);
JSONTEST_ASSERT_EQUAL(Json::Value("foo"), object1_["some other id"]);
// Remove.
Json::Value got;
bool did;
did = object1_.removeMember("some other id", &got);
JSONTEST_ASSERT_EQUAL(Json::Value("foo"), got);
JSONTEST_ASSERT_EQUAL(true, did);
got = Json::Value("bar");
did = object1_.removeMember("some other id", &got);
JSONTEST_ASSERT_EQUAL(Json::Value("bar"), got);
JSONTEST_ASSERT_EQUAL(false, did);
}
JSONTEST_FIXTURE(ValueTest, arrays) {
@@ -240,6 +253,10 @@ JSONTEST_FIXTURE(ValueTest, arrays) {
array1_[2] = Json::Value(17);
JSONTEST_ASSERT_EQUAL(Json::Value(), array1_[1]);
JSONTEST_ASSERT_EQUAL(Json::Value(17), array1_[2]);
Json::Value got;
JSONTEST_ASSERT_EQUAL(true, array1_.removeIndex(2, &got));
JSONTEST_ASSERT_EQUAL(Json::Value(17), got);
JSONTEST_ASSERT_EQUAL(false, array1_.removeIndex(2, &got)); // gone now
}
JSONTEST_FIXTURE(ValueTest, null) {
@@ -1480,34 +1497,15 @@ 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);
}
struct StreamWriterTest : JsonTest::TestCase {};
struct WriterTest : JsonTest::TestCase {};
JSONTEST_FIXTURE(WriterTest, dropNullPlaceholders) {
Json::FastWriter writer;
JSONTEST_FIXTURE(StreamWriterTest, dropNullPlaceholders) {
Json::StreamWriterBuilder b;
Json::Value nullValue;
JSONTEST_ASSERT(writer.write(nullValue) == "null\n");
writer.dropNullPlaceholders();
JSONTEST_ASSERT(writer.write(nullValue) == "\n");
b.settings_["dropNullPlaceholders"] = false;
JSONTEST_ASSERT(Json::writeString(b, nullValue) == "null");
b.settings_["dropNullPlaceholders"] = true;
JSONTEST_ASSERT(Json::writeString(b, nullValue) == "");
}
struct ReaderTest : JsonTest::TestCase {};
@@ -1518,7 +1516,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) {
@@ -1530,25 +1527,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) {
@@ -1559,13 +1537,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithOneError) {
JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
"* Line 1, Column 15\n Syntax error: value, object or array "
"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) {
@@ -1576,13 +1547,6 @@ JSONTEST_FIXTURE(ReaderTest, parseChineseWithOneError) {
JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
"* Line 1, Column 19\n Syntax error: value, object or array "
"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) {
@@ -1593,12 +1557,118 @@ 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<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 {};
JSONTEST_FIXTURE(CharReaderTest, parseWithNoErrors) {
Json::CharReaderBuilder b;
Json::CharReader* reader(b.newCharReader());
std::string errs;
Json::Value root;
char const doc[] = "{ \"property\" : \"value\" }";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.size() == 0);
delete reader;
}
JSONTEST_FIXTURE(CharReaderTest, parseWithNoErrorsTestingOffsets) {
Json::CharReaderBuilder b;
Json::CharReader* reader(b.newCharReader());
std::string errs;
Json::Value root;
char const doc[] =
"{ \"property\" : [\"value\", \"value2\"], \"obj\" : "
"{ \"nested\" : 123, \"bool\" : true}, \"null\" : "
"null, \"false\" : false }";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.size() == 0);
delete reader;
}
JSONTEST_FIXTURE(CharReaderTest, parseWithOneError) {
Json::CharReaderBuilder b;
Json::CharReader* reader(b.newCharReader());
std::string errs;
Json::Value root;
char const doc[] =
"{ \"property\" :: \"value\" }";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs ==
"* Line 1, Column 15\n Syntax error: value, object or array "
"expected.\n");
delete reader;
}
JSONTEST_FIXTURE(CharReaderTest, parseChineseWithOneError) {
Json::CharReaderBuilder b;
Json::CharReader* reader(b.newCharReader());
std::string errs;
Json::Value root;
char const doc[] =
"{ \"pr佐藤erty\" :: \"value\" }";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs ==
"* Line 1, Column 19\n Syntax error: value, object or array "
"expected.\n");
delete reader;
}
JSONTEST_FIXTURE(CharReaderTest, parseWithDetailError) {
Json::CharReaderBuilder b;
Json::CharReader* reader(b.newCharReader());
std::string errs;
Json::Value root;
char const doc[] =
"{ \"property\" : \"v\\alue\" }";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs ==
"* Line 1, Column 16\n Bad escape sequence in string\nSee "
"Line 1, Column 20 for detail.\n");
delete reader;
}
JSONTEST_FIXTURE(CharReaderTest, parseWithStackLimit) {
Json::CharReaderBuilder b;
Json::Value root;
char const doc[] =
"{ \"property\" : \"value\" }";
{
b.settings_["stackLimit"] = 2;
Json::CharReader* reader(b.newCharReader());
std::string errs;
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs == "");
JSONTEST_ASSERT_EQUAL("value", root["property"]);
delete reader;
}
{
b.settings_["stackLimit"] = 1;
Json::CharReader* reader(b.newCharReader());
std::string errs;
JSONTEST_ASSERT_THROWS(reader->parse(
doc, doc + std::strlen(doc),
&root, &errs));
delete reader;
}
}
int main(int argc, const char* argv[]) {
@@ -1621,7 +1691,6 @@ 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, ReaderTest, parseWithNoErrors);
@@ -1631,7 +1700,15 @@ int main(int argc, const char* argv[]) {
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseChineseWithOneError);
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithDetailError);
JSONTEST_REGISTER_FIXTURE(runner, WriterTest, dropNullPlaceholders);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithNoErrors);
JSONTEST_REGISTER_FIXTURE(
runner, CharReaderTest, parseWithNoErrorsTestingOffsets);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithOneError);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseChineseWithOneError);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithDetailError);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithStackLimit);
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders);
return runner.runCommandLine(argc, argv);
}

View File

@@ -0,0 +1,4 @@
// Comment for array
.=[]
// Comment within array
.[0]="one-element"

View File

@@ -0,0 +1,5 @@
// Comment for array
[
// Comment within array
"one-element"
]

View File

@@ -1,6 +1,7 @@
.={}
// Comment for array
.test=[]
// Comment within array
.test[0]={}
.test[0].a="aaa"
.test[1]={}

View File

@@ -2,6 +2,7 @@
"test":
// Comment for array
[
// Comment within array
{ "a" : "aaa" }, // Comment for a
{ "b" : "bbb" }, // Comment for b
{ "c" : "ccc" } // Comment for c

View File

@@ -14,6 +14,7 @@ def getStatusOutput(cmd):
Return int, unicode (for both Python 2 and 3).
Note: os.popen().close() would return None for 0.
"""
print(cmd, file=sys.stderr)
pipe = os.popen(cmd)
process_output = pipe.read()
try:
@@ -57,7 +58,8 @@ def safeReadFile( path ):
return '<File "%s" is missing: %s>' % (path,e)
def runAllTests(jsontest_executable_path, input_dir = None,
use_valgrind=False, with_json_checker=False ):
use_valgrind=False, with_json_checker=False,
writerClass='StyledWriter'):
if not input_dir:
input_dir = os.path.join(os.getcwd(), 'data')
tests = glob(os.path.join(input_dir, '*.json'))
@@ -72,8 +74,8 @@ def runAllTests( jsontest_executable_path, input_dir = None,
is_json_checker_test = (input_path in test_jsonchecker) or expect_failure
print('TESTING:', input_path, end=' ')
options = is_json_checker_test and '--json-checker' or ''
cmd = '%s%s %s "%s"' % (
valgrind_path, jsontest_executable_path, options,
options += ' --json-writer %s'%writerClass
cmd = '%s%s %s "%s"' % ( valgrind_path, jsontest_executable_path, options,
input_path)
status, process_output = getStatusOutput(cmd)
if is_json_checker_test:
@@ -145,7 +147,22 @@ def main():
else:
input_path = None
status = runAllTests(jsontest_executable_path, input_path,
use_valgrind=options.valgrind, with_json_checker=options.with_json_checker )
use_valgrind=options.valgrind,
with_json_checker=options.with_json_checker,
writerClass='StyledWriter')
if status:
sys.exit(status)
status = runAllTests(jsontest_executable_path, input_path,
use_valgrind=options.valgrind,
with_json_checker=options.with_json_checker,
writerClass='StyledStreamWriter')
if status:
sys.exit(status)
status = runAllTests(jsontest_executable_path, input_path,
use_valgrind=options.valgrind,
with_json_checker=options.with_json_checker,
writerClass='BuiltStyledStreamWriter')
if status:
sys.exit(status)
if __name__ == '__main__':

View File

@@ -53,8 +53,7 @@ def runAllTests( exe_path, use_valgrind=False ):
print()
for name, result in failures:
print(result)
print('%d/%d tests passed (%d failure(s))' % (
pass_count, len(test_names), failed_count))
print('%d/%d tests passed (%d failure(s))' % ( pass_count, len(test_names), failed_count))
return 1
else:
print('All %d tests passed' % len(test_names))

View File

@@ -1 +1 @@
1.2.0
0.8.0