Merge branch 'master' (1.4.1) into v0.8.z (0.8.1)

This commit is contained in:
Christopher Dunn 2015-02-13 10:26:07 -06:00
commit 721de4b9fd
7 changed files with 176 additions and 43 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

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

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

@ -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.1"
# 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 1
# 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_) {
@ -1704,6 +1711,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 +1723,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 +1751,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 +1764,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

@ -1671,6 +1671,126 @@ 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;
}
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);
@ -1708,6 +1828,12 @@ 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, 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, StreamWriterTest, dropNullPlaceholders); JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders);
return runner.runCommandLine(argc, argv); return runner.runCommandLine(argc, argv);

View File

@ -1 +1 @@
0.8.0 0.8.1