Compare commits

..

37 Commits
0.8.0 ... 0.8.4

Author SHA1 Message Date
Christopher Dunn
1ec069c974 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-03-03 09:04:10 -06:00
Christopher Dunn
525c8950c5 test Json::Value::null 2015-03-03 09:03:00 -06:00
Christopher Dunn
75665630c3 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-03-03 09:02:53 -06:00
Christopher Dunn
fd709f6885 revert 'Made it possible to drop null placeholders from array output.'
revert ae3c7a7aab
2015-03-03 09:02:14 -06:00
Christopher Dunn
e1ed392e7c Revert "added option to FastWriter which omits the trailing new line character"
This reverts commit 5bf16105b5.
2015-03-03 09:02:14 -06:00
Christopher Dunn
e6ba425a73 revert 'Added structured error reporting to Reader.'
revert 68db655347
issue #147
2015-03-03 09:02:14 -06:00
Christopher Dunn
48a617179a revert 'Add public semantic error reporting'
for binary-compatibility with 0.6.0
issue #147
was #57
2015-03-03 09:02:14 -06:00
Christopher Dunn
5d9eb1f3dc 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-03-03 09:02:13 -06:00
Christopher Dunn
fbe9157981 NOT C++11 2015-03-03 09:02:13 -06:00
Christopher Dunn
c92bad4a5e 0.8.z 2015-03-03 09:02:09 -06:00
Christopher Dunn
f9db82af17 1.4.4 < 1.4.3
* fixed Readers when `allowDropNullPlaceholders`
2015-02-19 15:37:57 -06:00
Christopher Dunn
ae71879549 Merge pull request #179 from cdunn2001/drop-null
Fix failures for `allowDroppedNullPlaceholders`.
2015-02-19 12:38:16 -06:00
Christopher Dunn
7b3683ccd1 apply fix to old Reader 2015-02-19 11:37:17 -06:00
Christopher Dunn
58499031a4 fix all cases from issue -- all pass! 2015-02-19 11:35:28 -06:00
Christopher Dunn
2c8c1ac0ec all 8 failing cases from issue 2015-02-19 11:35:20 -06:00
Christopher Dunn
c58e93b014 fix failing object case 2015-02-19 11:34:35 -06:00
Christopher Dunn
eed193e151 object cases; 1st passes, 2nd fails 2015-02-19 11:34:35 -06:00
Christopher Dunn
4382a7b585 cases 0,1,5,9,12 from issue -- passing 2015-02-19 11:32:42 -06:00
Christopher Dunn
30d923f155 1.4.3 <- 1.4.2 2015-02-18 09:20:28 -06:00
Christopher Dunn
2f4e40bc95 fix typo: issue #177 2015-02-18 09:17:06 -06:00
Christopher Dunn
505e086ebc Merge pull request #173 from cdunn2001/fix-include-amal
help use of amalgamated header

Reviewed by "Lightness Races in Orbit" at StackOverflow.
2015-02-15 13:11:38 -06:00
Christopher Dunn
c6582415d8 fix typos 2015-02-15 13:06:48 -06:00
Christopher Dunn
0ee7e2426f help use of amalgamated header
* Include from same-directory first, so `-I DIR` is rarely needed.
* Double-check that proper header has been included.

http://stackoverflow.com/questions/28510109/linking-problems-with-jsoncpp
2015-02-15 13:06:48 -06:00
Christopher Dunn
1522e4dfb1 Merge pull request #174 from kobigurk/kobigurk-patch-asserts
only throws exceptions JSON_USE_EXCEPTION
2015-02-15 12:05:28 -06:00
Kobi Gurkan
09b8670536 only throws exceptions JSON_USE_EXCEPTION
JSON_ASSERT now throws a runtime_error
2015-02-15 18:00:31 +02:00
Christopher Dunn
f164288646 help rebasing 2015-02-15 03:01:26 -06:00
Christopher Dunn
3bfd215938 1.4.2 < 1.4.1
* Bug-fix for ValueIterator::operator-() (issue #169)
2015-02-15 02:49:34 -06:00
Christopher Dunn
400b744195 Merge pull request #172 from cdunn2001/master
Fix bug in ValueIteratorBase::operator- 

Fixes #169.
2015-02-15 02:44:17 -06:00
Christopher Dunn
bd55164089 reverse sense for CPPTL too 2015-02-15 02:38:31 -06:00
Kevin Grant
4c5832a0be Fix bug in ValueIteratorBase::operator- 2015-02-15 02:38:31 -06:00
Christopher Dunn
8ba9875962 IteratorTest 2015-02-15 02:38:31 -06:00
Christopher Dunn
9c91b995dd rules for signing and doc-generation 2015-02-14 10:20:45 -06:00
Christopher Dunn
e7233bf056 1.4.1 <- 1.4.0 2015-02-13 10:00:38 -06:00
Christopher Dunn
9c90456890 Merge pull request #167 from cdunn2001/fail-if-extra
Add `failIfExtra` feature to `CharReaderBuilder`.
2015-02-13 09:55:11 -06:00
Christopher Dunn
f4be815c86 failIfExtra
1. failing regression tests, from #164 and #107
2. implemented; tests pass
3. allow trailing comments
2015-02-13 09:39:08 -06:00
Christopher Dunn
aa13a8ba40 comments/minor typos 2015-02-13 09:38:49 -06:00
Christopher Dunn
da0fcfbaa2 link web docs 2015-02-12 11:45:21 -06:00
13 changed files with 387 additions and 56 deletions

View File

@@ -7,17 +7,20 @@ pairs.
[json-org]: http://json.org/ [json-org]: http://json.org/
JsonCpp is a C++ library that allows manipulating JSON values, including [JsonCpp][] is a C++ library that allows manipulating JSON values, including
serialization and deserialization to and from strings. It can also preserve serialization and deserialization to and from strings. It can also preserve
existing comment in unserialization/serialization steps, making it a convenient existing comment in unserialization/serialization steps, making it a convenient
format to store user input files. format to store user input files.
[JsonCpp]: http://open-source-parsers.github.io/jsoncpp-docs/doxygen/index.html
## A note on backward-compatibility ## A note on backward-compatibility
Very soon, we are switching to C++11 only. For older compilers, try the `pre-C++11` branch. * `1.y.z` is built with C++11.
* `0.8.z` can be used with older compilers.
* Major versions maintain binary-compatibility.
Using JsonCpp in your project Using JsonCpp in your project
----------------------------- -----------------------------
The recommended approach to integrating JsonCpp in your project is to build The recommended approach to integrating JsonCpp in your project is to build
the amalgamated source (a single `.cpp` file) with your own build system. This the amalgamated source (a single `.cpp` file) with your own build system. This
ensures consistency of compilation flags and ABI compatibility. See the section ensures consistency of compilation flags and ABI compatibility. See the section
@@ -28,13 +31,11 @@ should be included as follow:
#include <json/json.h> #include <json/json.h>
If JsonCpp was build as a dynamic library on Windows, then your project needs to If JsonCpp was built as a dynamic library on Windows, then your project needs to
define the macro `JSON_DLL`. define the macro `JSON_DLL`.
Building and testing with CMake
Building and testing with new CMake -------------------------------
-----------------------------------
[CMake][] is a C++ Makefiles/Solution generator. It is usually available on most [CMake][] is a C++ Makefiles/Solution generator. It is usually available on most
Linux system as package. On Ubuntu: Linux system as package. On Ubuntu:
@@ -75,10 +76,8 @@ the `-G` option).
By default CMake hides compilation commands. This can be modified by specifying By default CMake hides compilation commands. This can be modified by specifying
`-DCMAKE_VERBOSE_MAKEFILE=true` when generating makefiles. `-DCMAKE_VERBOSE_MAKEFILE=true` when generating makefiles.
Building and testing with SCons Building and testing with SCons
------------------------------- -------------------------------
**Note:** The SCons-based build system is deprecated. Please use CMake; see the **Note:** The SCons-based build system is deprecated. Please use CMake; see the
section above. section above.
@@ -107,14 +106,7 @@ If you are building with Microsoft Visual Studio 2008, you need to set up the
environment by running `vcvars32.bat` (e.g. MSVC 2008 command prompt) before environment by running `vcvars32.bat` (e.g. MSVC 2008 command prompt) before
running SCons. running SCons.
# Running the tests manually
Running the tests manually
--------------------------
Note that test can be run using SCons using the `check` target:
scons platform=$PLATFORM check
You need to run tests manually only if you are troubleshooting an issue. You need to run tests manually only if you are troubleshooting an issue.
In the instructions below, replace `path/to/jsontest` with the path of the In the instructions below, replace `path/to/jsontest` with the path of the
@@ -137,20 +129,21 @@ In the instructions below, replace `path/to/jsontest` with the path of the
# You can run the tests using valgrind: # You can run the tests using valgrind:
python rununittests.py --valgrind path/to/test_lib_json python rununittests.py --valgrind path/to/test_lib_json
## Running the tests using scons
Note that tests can be run using SCons using the `check` target:
scons platform=$PLATFORM check
Building the documentation Building the documentation
-------------------------- --------------------------
Run the Python script `doxybuild.py` from the top directory: Run the Python script `doxybuild.py` from the top directory:
python doxybuild.py --doxygen=$(which doxygen) --open --with-dot python doxybuild.py --doxygen=$(which doxygen) --open --with-dot
See `doxybuild.py --help` for options. See `doxybuild.py --help` for options.
Generating amalgamated source and header Generating amalgamated source and header
---------------------------------------- ----------------------------------------
JsonCpp is provided with a script to generate a single header and a single JsonCpp is provided with a script to generate a single header and a single
source file to ease inclusion into an existing project. The amalgamated source source file to ease inclusion into an existing project. The amalgamated source
can be generated at any time by running the following command from the can be generated at any time by running the following command from the
@@ -172,10 +165,8 @@ The amalgamated sources are generated by concatenating JsonCpp source in the
correct order and defining the macro `JSON_IS_AMALGAMATION` to prevent inclusion correct order and defining the macro `JSON_IS_AMALGAMATION` to prevent inclusion
of other headers. of other headers.
Adding a reader/writer test Adding a reader/writer test
--------------------------- ---------------------------
To add a test, you need to create two files in test/data: To add a test, you need to create two files in test/data:
* a `TESTNAME.json` file, that contains the input document in JSON format. * a `TESTNAME.json` file, that contains the input document in JSON format.
@@ -195,10 +186,8 @@ The `TESTNAME.expected` file format is as follows:
See the examples `test_complex_01.json` and `test_complex_01.expected` to better See the examples `test_complex_01.json` and `test_complex_01.expected` to better
understand element paths. understand element paths.
Understanding reader/writer test output Understanding reader/writer test output
--------------------------------------- ---------------------------------------
When a test is run, output files are generated beside the input test files. When a test is run, output files are generated beside the input test files.
Below is a short description of the content of each file: Below is a short description of the content of each file:
@@ -215,10 +204,7 @@ Below is a short description of the content of each file:
* `test_complex_01.process-output`: `jsontest` output, typically useful for * `test_complex_01.process-output`: `jsontest` output, typically useful for
understanding parsing errors. understanding parsing errors.
License License
------- -------
See the `LICENSE` file for details. In summary, JsonCpp is licensed under the See the `LICENSE` file for details. In summary, JsonCpp is licensed under the
MIT license, or public domain if desired and recognized in your jurisdiction. MIT license, or public domain if desired and recognized in your jurisdiction.

View File

@@ -59,7 +59,7 @@ def amalgamate_source(source_top_dir=None,
print("Amalgating header...") print("Amalgating header...")
header = AmalgamationFile(source_top_dir) header = AmalgamationFile(source_top_dir)
header.add_text("/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/).") header.add_text("/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/).")
header.add_text("/// It is intented to be used with #include <%s>" % header_include_path) header.add_text('/// It is intended to be used with #include "%s"' % header_include_path)
header.add_file("LICENSE", wrap_in_comment=True) header.add_file("LICENSE", wrap_in_comment=True)
header.add_text("#ifndef JSON_AMALGATED_H_INCLUDED") header.add_text("#ifndef JSON_AMALGATED_H_INCLUDED")
header.add_text("# define JSON_AMALGATED_H_INCLUDED") header.add_text("# define JSON_AMALGATED_H_INCLUDED")
@@ -85,7 +85,7 @@ def amalgamate_source(source_top_dir=None,
print("Amalgating forward header...") print("Amalgating forward header...")
header = AmalgamationFile(source_top_dir) header = AmalgamationFile(source_top_dir)
header.add_text("/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/).") header.add_text("/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/).")
header.add_text("/// It is intented to be used with #include <%s>" % forward_header_include_path) header.add_text('/// It is intended to be used with #include "%s"' % forward_header_include_path)
header.add_text("/// This header provides forward declaration for all JsonCpp types.") header.add_text("/// This header provides forward declaration for all JsonCpp types.")
header.add_file("LICENSE", wrap_in_comment=True) header.add_file("LICENSE", wrap_in_comment=True)
header.add_text("#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED") header.add_text("#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED")
@@ -105,10 +105,15 @@ def amalgamate_source(source_top_dir=None,
print("Amalgating source...") print("Amalgating source...")
source = AmalgamationFile(source_top_dir) source = AmalgamationFile(source_top_dir)
source.add_text("/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/).") source.add_text("/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/).")
source.add_text("/// It is intented to be used with #include <%s>" % header_include_path) source.add_text('/// It is intended to be used with #include "%s"' % header_include_path)
source.add_file("LICENSE", wrap_in_comment=True) source.add_file("LICENSE", wrap_in_comment=True)
source.add_text("") source.add_text("")
source.add_text("#include <%s>" % header_include_path) source.add_text('#include "%s"' % header_include_path)
source.add_text("""
#ifndef JSON_IS_AMALGAMATION
#error "Compile with -I PATH_TO_JSON_DIRECTORY"
#endif
""")
source.add_text("") source.add_text("")
lib_json = "src/lib_json" lib_json = "src/lib_json"
source.add_file(os.path.join(lib_json, "json_tool.h")) source.add_file(os.path.join(lib_json, "json_tool.h"))

View File

@@ -1,5 +1,19 @@
all: build test-amalgamate # This is only for jsoncpp developers/contributors.
# We use this to sign releases, generate documentation, etc.
VER?=$(shell cat version)
default:
@echo "VER=${VER}"
sign: jsoncpp-${VER}.tar.gz
gpg --armor --detach-sign $<
gpg --verify $<.asc
# Then upload .asc to the release.
jsoncpp-%.tar.gz:
curl https://github.com/open-source-parsers/jsoncpp/archive/$*.tar.gz -o $@
dox:
python doxybuild.py --doxygen=$$(which doxygen) --in doc/web_doxyfile.in
rsync -va --delete dist/doxygen/jsoncpp-api-html-${VER}/ ../jsoncpp-docs/doxygen/
# Then 'git add -A' and 'git push' in jsoncpp-docs.
build: build:
mkdir -p build/debug mkdir -p build/debug
cd build/debug; cmake -DCMAKE_BUILD_TYPE=debug -DJSONCPP_LIB_BUILD_SHARED=ON -G "Unix Makefiles" ../.. cd build/debug; cmake -DCMAKE_BUILD_TYPE=debug -DJSONCPP_LIB_BUILD_SHARED=ON -G "Unix Makefiles" ../..
@@ -7,8 +21,11 @@ build:
# Currently, this depends on include/json/version.h generated # Currently, this depends on include/json/version.h generated
# by cmake. # by cmake.
test-amalgamate: build test-amalgamate:
python2.7 amalgamate.py python2.7 amalgamate.py
python3.4 amalgamate.py python3.4 amalgamate.py
clean:
\rm -rf *.gz *.asc dist/
.PHONY: build .PHONY: build

View File

@@ -56,20 +56,24 @@ std::cin >> root;
// You can also read into a particular sub-value. // You can also read into a particular sub-value.
std::cin >> root["subtree"]; std::cin >> root["subtree"];
// Get the value of the member of root named 'encoding', return 'UTF-8' if there is no // Get the value of the member of root named 'encoding',
// such member. // and return 'UTF-8' if there is no such member.
std::string encoding = root.get("encoding", "UTF-8" ).asString(); 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 'plug-ins'; return a 'null' value if
// there is no such member. // there is no such member.
const Json::Value plugins = root["plug-ins"]; const Json::Value plugins = root["plug-ins"];
for ( int index = 0; index < plugins.size(); ++index ) // Iterates over the sequence elements.
// Iterate over the sequence elements.
for ( int index = 0; index < plugins.size(); ++index )
loadPlugIn( plugins[index].asString() ); loadPlugIn( plugins[index].asString() );
// Try other datatypes. Some are auto-convertible to others.
foo::setIndentLength( root["indent"].get("length", 3).asInt() ); foo::setIndentLength( root["indent"].get("length", 3).asInt() );
foo::setIndentUseSpace( root["indent"].get("use_space", true).asBool() ); foo::setIndentUseSpace( root["indent"].get("use_space", true).asBool() );
// Since Json::Value has implicit constructor for all value types, it is not // Since Json::Value has an implicit constructor for all value types, it is not
// necessary to explicitly construct the Json::Value object: // necessary to explicitly construct the Json::Value object.
root["encoding"] = foo::getCurrentEncoding(); root["encoding"] = foo::getCurrentEncoding();
root["indent"]["length"] = foo::getCurrentIndentLength(); root["indent"]["length"] = foo::getCurrentIndentLength();
root["indent"]["use_space"] = foo::getCurrentIndentUseSpace(); root["indent"]["use_space"] = foo::getCurrentIndentUseSpace();
@@ -152,6 +156,7 @@ Basically JsonCpp is licensed under MIT license, or public domain if desired
and recognized in your jurisdiction. and recognized in your jurisdiction.
\author Baptiste Lepilleur <blep@users.sourceforge.net> (originator) \author Baptiste Lepilleur <blep@users.sourceforge.net> (originator)
\author Christopher Dunn <cdunn2001@gmail.com> (primary maintainer)
\version \include version \version \include version
We make strong guarantees about binary-compatibility, consistent with We make strong guarantees about binary-compatibility, consistent with
<a href="http://apr.apache.org/versioning.html">the Apache versioning scheme</a>. <a href="http://apr.apache.org/versioning.html">the Apache versioning scheme</a>.

View File

@@ -16,7 +16,7 @@
#if JSON_USE_EXCEPTION #if JSON_USE_EXCEPTION
#include <stdexcept> #include <stdexcept>
#define JSON_ASSERT(condition) \ #define JSON_ASSERT(condition) \
assert(condition); // @todo <= change this into an exception throw if (!(condition)) {throw std::runtime_error( "assert json failed" );} // @todo <= add detail about condition in exception
#define JSON_FAIL_MESSAGE(message) do{std::ostringstream oss; oss << message; throw std::runtime_error(oss.str());}while(0) #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) //#define JSON_FAIL_MESSAGE(message) throw std::runtime_error(message)
#else // JSON_USE_EXCEPTION #else // JSON_USE_EXCEPTION

View File

@@ -254,21 +254,26 @@ public:
/** Configuration of this builder. /** Configuration of this builder.
These are case-sensitive. These are case-sensitive.
Available settings (case-sensitive): Available settings (case-sensitive):
- "collectComments": false or true - `"collectComments": false or true`
- true to collect comment and allow writing them - true to collect comment and allow writing them
back during serialization, false to discard comments. back during serialization, false to discard comments.
This parameter is ignored if allowComments is false. This parameter is ignored if allowComments is false.
- "allowComments": false or true - `"allowComments": false or true`
- true if comments are allowed. - true if comments are allowed.
- "strictRoot": false or true - `"strictRoot": false or true`
- true if root must be either an array or an object value - true if root must be either an array or an object value
- "allowDroppedNullPlaceholders": false or true - `"allowDroppedNullPlaceholders": false or true`
- true if dropped null placeholders are allowed. (See StreamWriterBuilder.) - true if dropped null placeholders are allowed. (See StreamWriterBuilder.)
- "allowNumericKeys": false or true - `"allowNumericKeys": false or true`
- true if numeric object keys are allowed. - true if numeric object keys are allowed.
- "stackLimit": integer - `"stackLimit": integer`
- Exceeding stackLimit (recursive depth of `readValue()`) will
cause an exception.
- This is a security issue (seg-faults caused by deeply nested JSON), - This is a security issue (seg-faults caused by deeply nested JSON),
so the default is low. so the default is low.
- `"failIfExtra": false or true`
- If true, `parse()` returns false when extra non-whitespace trails
the JSON value in the input string.
You can examine 'settings_` yourself You can examine 'settings_` yourself
to see the defaults. You can also write and read them just like any to see the defaults. You can also write and read them just like any

View File

@@ -937,7 +937,7 @@ public:
bool operator!=(const SelfType& other) const { return !isEqual(other); } bool operator!=(const SelfType& other) const { return !isEqual(other); }
difference_type operator-(const SelfType& other) const { difference_type operator-(const SelfType& other) const {
return computeDistance(other); return other.computeDistance(*this);
} }
/// Return either the index or the member name of the referenced value as a /// Return either the index or the member name of the referenced value as a

View File

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

View File

@@ -826,6 +826,7 @@ public:
bool strictRoot_; bool strictRoot_;
bool allowDroppedNullPlaceholders_; bool allowDroppedNullPlaceholders_;
bool allowNumericKeys_; bool allowNumericKeys_;
bool failIfExtra_;
int stackLimit_; int stackLimit_;
}; // OurFeatures }; // OurFeatures
@@ -991,6 +992,12 @@ bool OurReader::parse(const char* beginDoc,
bool successful = readValue(); bool successful = readValue();
Token token; Token token;
skipCommentTokens(token); skipCommentTokens(token);
if (features_.failIfExtra_) {
if (token.type_ != tokenError && token.type_ != tokenEndOfStream) {
addError("Extra non-whitespace after JSON value.", token);
return false;
}
}
if (collectComments_ && !commentsBefore_.empty()) if (collectComments_ && !commentsBefore_.empty())
root.setComment(commentsBefore_, commentAfter); root.setComment(commentsBefore_, commentAfter);
if (features_.strictRoot_) { if (features_.strictRoot_) {
@@ -1053,6 +1060,8 @@ bool OurReader::readValue() {
} }
break; break;
case tokenArraySeparator: case tokenArraySeparator:
case tokenObjectEnd:
case tokenArrayEnd:
if (features_.allowDroppedNullPlaceholders_) { if (features_.allowDroppedNullPlaceholders_) {
// "Un-read" the current token and mark the current value as a null // "Un-read" the current token and mark the current value as a null
// token. // token.
@@ -1060,8 +1069,7 @@ bool OurReader::readValue() {
Value v; Value v;
currentValue().swapPayload(v); currentValue().swapPayload(v);
break; break;
} } // else, fall through ...
// Else, fall through...
default: default:
return addError("Syntax error: value, object or array expected.", token); return addError("Syntax error: value, object or array expected.", token);
} }
@@ -1704,6 +1712,7 @@ CharReader* CharReaderBuilder::newCharReader() const
features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool(); features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
features.stackLimit_ = settings_["stackLimit"].asInt(); features.stackLimit_ = settings_["stackLimit"].asInt();
features.failIfExtra_ = settings_["failIfExtra"].asBool();
return new OurCharReader(collectComments, features); return new OurCharReader(collectComments, features);
} }
static void getValidReaderKeys(std::set<std::string>* valid_keys) static void getValidReaderKeys(std::set<std::string>* valid_keys)
@@ -1715,6 +1724,7 @@ static void getValidReaderKeys(std::set<std::string>* valid_keys)
valid_keys->insert("allowDroppedNullPlaceholders"); valid_keys->insert("allowDroppedNullPlaceholders");
valid_keys->insert("allowNumericKeys"); valid_keys->insert("allowNumericKeys");
valid_keys->insert("stackLimit"); valid_keys->insert("stackLimit");
valid_keys->insert("failIfExtra");
} }
bool CharReaderBuilder::validate(Json::Value* invalid) const bool CharReaderBuilder::validate(Json::Value* invalid) const
{ {
@@ -1742,6 +1752,7 @@ void CharReaderBuilder::strictMode(Json::Value* settings)
(*settings)["strictRoot"] = true; (*settings)["strictRoot"] = true;
(*settings)["allowDroppedNullPlaceholders"] = false; (*settings)["allowDroppedNullPlaceholders"] = false;
(*settings)["allowNumericKeys"] = false; (*settings)["allowNumericKeys"] = false;
(*settings)["failIfExtra"] = true;
//! [CharReaderBuilderStrictMode] //! [CharReaderBuilderStrictMode]
} }
// static // static
@@ -1754,6 +1765,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings)
(*settings)["allowDroppedNullPlaceholders"] = false; (*settings)["allowDroppedNullPlaceholders"] = false;
(*settings)["allowNumericKeys"] = false; (*settings)["allowNumericKeys"] = false;
(*settings)["stackLimit"] = 1000; (*settings)["stackLimit"] = 1000;
(*settings)["failIfExtra"] = false;
//! [CharReaderBuilderDefaults] //! [CharReaderBuilderDefaults]
} }

View File

@@ -32,7 +32,7 @@ namespace Json {
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) #define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
#else #else
// This exists for binary compatibility only. Use nullRef. // This exists for binary compatibility only. Use nullRef.
static const Value null; const Value Value::null;
#define ALIGNAS(byte_alignment) #define ALIGNAS(byte_alignment)
#endif #endif
static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };

View File

@@ -77,7 +77,7 @@ ValueIteratorBase::difference_type
ValueIteratorBase::computeDistance(const SelfType& other) const { ValueIteratorBase::computeDistance(const SelfType& other) const {
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
#ifdef JSON_USE_CPPTL_SMALLMAP #ifdef JSON_USE_CPPTL_SMALLMAP
return current_ - other.current_; return other.current_ - current_;
#else #else
// Iterator for null value are initialized using the default // Iterator for null value are initialized using the default
// constructor, which initialize current_ to the default // constructor, which initialize current_ to the default

View File

@@ -282,6 +282,8 @@ JSONTEST_FIXTURE(ValueTest, null) {
JSONTEST_ASSERT_EQUAL(0.0, null_.asDouble()); JSONTEST_ASSERT_EQUAL(0.0, null_.asDouble());
JSONTEST_ASSERT_EQUAL(0.0, null_.asFloat()); JSONTEST_ASSERT_EQUAL(0.0, null_.asFloat());
JSONTEST_ASSERT_STRING_EQUAL("", null_.asString()); JSONTEST_ASSERT_STRING_EQUAL("", null_.asString());
JSONTEST_ASSERT_EQUAL(Json::Value::null, null_);
} }
JSONTEST_FIXTURE(ValueTest, strings) { JSONTEST_FIXTURE(ValueTest, strings) {
@@ -1671,6 +1673,295 @@ JSONTEST_FIXTURE(CharReaderTest, parseWithStackLimit) {
} }
} }
struct CharReaderFailIfExtraTest : JsonTest::TestCase {};
JSONTEST_FIXTURE(CharReaderFailIfExtraTest, issue164) {
// This is interpretted as a string value followed by a colon.
Json::CharReaderBuilder b;
Json::Value root;
char const doc[] =
" \"property\" : \"value\" }";
{
b.settings_["failIfExtra"] = false;
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("property", root);
delete reader;
}
{
b.settings_["failIfExtra"] = true;
Json::CharReader* reader(b.newCharReader());
std::string errs;
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT_STRING_EQUAL(errs,
"* Line 1, Column 13\n"
" Extra non-whitespace after JSON value.\n");
JSONTEST_ASSERT_EQUAL("property", root);
delete reader;
}
{
b.settings_["failIfExtra"] = false;
b.strictMode(&b.settings_);
Json::CharReader* reader(b.newCharReader());
std::string errs;
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT_STRING_EQUAL(errs,
"* Line 1, Column 13\n"
" Extra non-whitespace after JSON value.\n");
JSONTEST_ASSERT_EQUAL("property", root);
delete reader;
}
}
JSONTEST_FIXTURE(CharReaderFailIfExtraTest, issue107) {
// This is interpretted as an int value followed by a colon.
Json::CharReaderBuilder b;
Json::Value root;
char const doc[] =
"1:2:3";
b.settings_["failIfExtra"] = true;
Json::CharReader* reader(b.newCharReader());
std::string errs;
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT_STRING_EQUAL(
"* Line 1, Column 2\n"
" Extra non-whitespace after JSON value.\n",
errs);
JSONTEST_ASSERT_EQUAL(1, root.asInt());
delete reader;
}
JSONTEST_FIXTURE(CharReaderFailIfExtraTest, commentAfterObject) {
Json::CharReaderBuilder b;
Json::Value root;
{
char const doc[] =
"{ \"property\" : \"value\" } //trailing\n//comment\n";
b.settings_["failIfExtra"] = true;
Json::CharReader* reader(b.newCharReader());
std::string errs;
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL("value", root["property"]);
delete reader;
}
}
JSONTEST_FIXTURE(CharReaderFailIfExtraTest, commentAfterArray) {
Json::CharReaderBuilder b;
Json::Value root;
char const doc[] =
"[ \"property\" , \"value\" ] //trailing\n//comment\n";
b.settings_["failIfExtra"] = true;
Json::CharReader* reader(b.newCharReader());
std::string errs;
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL("value", root[1u]);
delete reader;
}
JSONTEST_FIXTURE(CharReaderFailIfExtraTest, commentAfterBool) {
Json::CharReaderBuilder b;
Json::Value root;
char const doc[] =
" true /*trailing\ncomment*/";
b.settings_["failIfExtra"] = true;
Json::CharReader* reader(b.newCharReader());
std::string errs;
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL(true, root.asBool());
delete reader;
}
struct CharReaderAllowDropNullTest : JsonTest::TestCase {};
JSONTEST_FIXTURE(CharReaderAllowDropNullTest, issue178) {
Json::CharReaderBuilder b;
b.settings_["allowDroppedNullPlaceholders"] = true;
Json::Value root;
std::string errs;
Json::CharReader* reader(b.newCharReader());
{
char const doc[] = "{\"a\":,\"b\":true}";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL(2u, root.size());
JSONTEST_ASSERT_EQUAL(Json::nullValue, root.get("a", true));
}
{
char const doc[] = "{\"a\":}";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL(1u, root.size());
JSONTEST_ASSERT_EQUAL(Json::nullValue, root.get("a", true));
}
{
char const doc[] = "[]";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs == "");
JSONTEST_ASSERT_EQUAL(0u, root.size());
JSONTEST_ASSERT_EQUAL(Json::arrayValue, root);
}
{
char const doc[] = "[null]";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs == "");
JSONTEST_ASSERT_EQUAL(1u, root.size());
}
{
char const doc[] = "[,]";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL(2u, root.size());
}
{
char const doc[] = "[,,,]";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL(4u, root.size());
}
{
char const doc[] = "[null,]";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL(2u, root.size());
}
{
char const doc[] = "[,null]";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs == "");
JSONTEST_ASSERT_EQUAL(2u, root.size());
}
{
char const doc[] = "[,,]";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL(3u, root.size());
}
{
char const doc[] = "[null,,]";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL(3u, root.size());
}
{
char const doc[] = "[,null,]";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL(3u, root.size());
}
{
char const doc[] = "[,,null]";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs == "");
JSONTEST_ASSERT_EQUAL(3u, root.size());
}
{
char const doc[] = "[[],,,]";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL(4u, root.size());
JSONTEST_ASSERT_EQUAL(Json::arrayValue, root[0u]);
}
{
char const doc[] = "[,[],,]";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL(4u, root.size());
JSONTEST_ASSERT_EQUAL(Json::arrayValue, root[1u]);
}
{
char const doc[] = "[,,,[]]";
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs == "");
JSONTEST_ASSERT_EQUAL(4u, root.size());
JSONTEST_ASSERT_EQUAL(Json::arrayValue, root[3u]);
}
delete reader;
}
struct IteratorTest : JsonTest::TestCase {};
JSONTEST_FIXTURE(IteratorTest, distance) {
Json::Value json;
json["k1"] = "a";
json["k2"] = "b";
int dist;
std::string str;
for (Json::ValueIterator it = json.begin(); it != json.end(); ++it) {
dist = it - json.begin();
str = it->asString().c_str();
}
JSONTEST_ASSERT_EQUAL(1, dist);
JSONTEST_ASSERT_STRING_EQUAL("b", str);
}
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
JsonTest::Runner runner; JsonTest::Runner runner;
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, checkNormalizeFloatingPointStr); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, checkNormalizeFloatingPointStr);
@@ -1693,6 +1984,8 @@ int main(int argc, const char* argv[]) {
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareType); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareType);
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, typeChecksThrowExceptions); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, typeChecksThrowExceptions);
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders);
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithNoErrors); JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithNoErrors);
JSONTEST_REGISTER_FIXTURE( JSONTEST_REGISTER_FIXTURE(
runner, ReaderTest, parseWithNoErrorsTestingOffsets); runner, ReaderTest, parseWithNoErrorsTestingOffsets);
@@ -1708,7 +2001,15 @@ int main(int argc, const char* argv[]) {
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithDetailError); JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithDetailError);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithStackLimit); JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithStackLimit);
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders); JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, issue164);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, issue107);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, commentAfterObject);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, commentAfterArray);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, commentAfterBool);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderAllowDropNullTest, issue178);
JSONTEST_REGISTER_FIXTURE(runner, IteratorTest, distance);
return runner.runCommandLine(argc, argv); return runner.runCommandLine(argc, argv);
} }

View File

@@ -1 +1 @@
0.8.0 0.8.4