mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2025-10-15 15:16:47 +02:00
Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5b3e8a8984 | ||
![]() |
4a6b5a33ed | ||
![]() |
37ea604585 | ||
![]() |
fd288c3750 | ||
![]() |
27c5762141 | ||
![]() |
bc67af2210 | ||
![]() |
83f10358f8 | ||
![]() |
115f9b91cf | ||
![]() |
c56d73b9a2 | ||
![]() |
f164288646 | ||
![]() |
3bfd215938 | ||
![]() |
400b744195 | ||
![]() |
bd55164089 | ||
![]() |
4c5832a0be | ||
![]() |
8ba9875962 | ||
![]() |
9c91b995dd | ||
![]() |
e7233bf056 | ||
![]() |
9c90456890 | ||
![]() |
f4be815c86 | ||
![]() |
aa13a8ba40 | ||
![]() |
da0fcfbaa2 |
@@ -85,10 +85,10 @@ endif( MSVC )
|
|||||||
|
|
||||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
# using regular Clang or AppleClang
|
# using regular Clang or AppleClang
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||||
# using GCC
|
# using GCC
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -Wextra -pedantic")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
IF(JSONCPP_WITH_WARNING_AS_ERROR)
|
IF(JSONCPP_WITH_WARNING_AS_ERROR)
|
||||||
|
42
README.md
42
README.md
@@ -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.
|
||||||
|
|
||||||
|
21
dev.makefile
21
dev.makefile
@@ -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
|
||||||
|
@@ -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>.
|
||||||
|
@@ -44,12 +44,6 @@ public:
|
|||||||
/// \c true if root must be either an array or an object value. Default: \c
|
/// \c true if root must be either an array or an object value. Default: \c
|
||||||
/// false.
|
/// false.
|
||||||
bool strictRoot_;
|
bool strictRoot_;
|
||||||
|
|
||||||
/// \c true if dropped null placeholders are allowed. Default: \c false.
|
|
||||||
bool allowDroppedNullPlaceholders_;
|
|
||||||
|
|
||||||
/// \c true if numeric object key are allowed. Default: \c false.
|
|
||||||
bool allowNumericKeys_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Json
|
} // namespace Json
|
||||||
|
@@ -35,18 +35,6 @@ public:
|
|||||||
typedef char Char;
|
typedef char Char;
|
||||||
typedef const Char* Location;
|
typedef const Char* Location;
|
||||||
|
|
||||||
/** \brief An error tagged with where in the JSON text it was encountered.
|
|
||||||
*
|
|
||||||
* The offsets give the [start, limit) range of bytes within the text. Note
|
|
||||||
* that this is bytes, not codepoints.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
struct StructuredError {
|
|
||||||
size_t offset_start;
|
|
||||||
size_t offset_limit;
|
|
||||||
std::string message;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \brief Constructs a Reader allowing all features
|
/** \brief Constructs a Reader allowing all features
|
||||||
* for parsing.
|
* for parsing.
|
||||||
*/
|
*/
|
||||||
@@ -123,38 +111,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
std::string getFormattedErrorMessages() const;
|
std::string getFormattedErrorMessages() const;
|
||||||
|
|
||||||
/** \brief Returns a vector of structured erros encounted while parsing.
|
|
||||||
* \return A (possibly empty) vector of StructuredError objects. Currently
|
|
||||||
* only one error can be returned, but the caller should tolerate
|
|
||||||
* multiple
|
|
||||||
* errors. This can occur if the parser recovers from a non-fatal
|
|
||||||
* parse error and then encounters additional errors.
|
|
||||||
*/
|
|
||||||
std::vector<StructuredError> getStructuredErrors() const;
|
|
||||||
|
|
||||||
/** \brief Add a semantic error message.
|
|
||||||
* \param value JSON Value location associated with the error
|
|
||||||
* \param message The error message.
|
|
||||||
* \return \c true if the error was successfully added, \c false if the
|
|
||||||
* Value offset exceeds the document size.
|
|
||||||
*/
|
|
||||||
bool pushError(const Value& value, const std::string& message);
|
|
||||||
|
|
||||||
/** \brief Add a semantic error message with extra context.
|
|
||||||
* \param value JSON Value location associated with the error
|
|
||||||
* \param message The error message.
|
|
||||||
* \param extra Additional JSON Value location to contextualize the error
|
|
||||||
* \return \c true if the error was successfully added, \c false if either
|
|
||||||
* Value offset exceeds the document size.
|
|
||||||
*/
|
|
||||||
bool pushError(const Value& value, const std::string& message, const Value& extra);
|
|
||||||
|
|
||||||
/** \brief Return whether there are any errors.
|
|
||||||
* \return \c true if there are no errors to report \c false if
|
|
||||||
* errors have occurred.
|
|
||||||
*/
|
|
||||||
bool good() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum TokenType {
|
enum TokenType {
|
||||||
tokenEndOfStream = 0,
|
tokenEndOfStream = 0,
|
||||||
@@ -298,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
|
||||||
|
@@ -133,8 +133,11 @@ public:
|
|||||||
typedef Json::LargestUInt LargestUInt;
|
typedef Json::LargestUInt LargestUInt;
|
||||||
typedef Json::ArrayIndex ArrayIndex;
|
typedef Json::ArrayIndex ArrayIndex;
|
||||||
|
|
||||||
static const Value& null; ///! We regret this reference to a global instance; prefer the simpler Value().
|
static const Value& nullRef;
|
||||||
static const Value& nullRef; ///! just a kludge for binary-compatibility; same as null
|
#if !defined(__ARMEL__)
|
||||||
|
/// \deprecated This exists for binary compatibility only. Use nullRef.
|
||||||
|
static const Value null;
|
||||||
|
#endif
|
||||||
/// Minimum signed integer value that can be stored in a Json::Value.
|
/// Minimum signed integer value that can be stored in a Json::Value.
|
||||||
static const LargestInt minLargestInt;
|
static const LargestInt minLargestInt;
|
||||||
/// Maximum signed integer value that can be stored in a Json::Value.
|
/// Maximum signed integer value that can be stored in a Json::Value.
|
||||||
@@ -172,7 +175,7 @@ private:
|
|||||||
CZString(const char* cstr, DuplicationPolicy allocate);
|
CZString(const char* cstr, DuplicationPolicy allocate);
|
||||||
CZString(const CZString& other);
|
CZString(const CZString& other);
|
||||||
~CZString();
|
~CZString();
|
||||||
CZString& operator=(CZString other);
|
CZString &operator=(const CZString &other);
|
||||||
bool operator<(const CZString& other) const;
|
bool operator<(const CZString& other) const;
|
||||||
bool operator==(const CZString& other) const;
|
bool operator==(const CZString& other) const;
|
||||||
ArrayIndex index() const;
|
ArrayIndex index() const;
|
||||||
@@ -241,7 +244,7 @@ Json::Value obj_value(Json::objectValue); // {}
|
|||||||
~Value();
|
~Value();
|
||||||
|
|
||||||
// Deep copy, then swap(other).
|
// Deep copy, then swap(other).
|
||||||
Value& operator=(Value other);
|
Value &operator=(const Value &other);
|
||||||
/// Swap everything.
|
/// Swap everything.
|
||||||
void swap(Value& other);
|
void swap(Value& other);
|
||||||
/// Swap values but leave comments and source offsets in place.
|
/// Swap values but leave comments and source offsets in place.
|
||||||
@@ -451,13 +454,6 @@ Json::Value obj_value(Json::objectValue); // {}
|
|||||||
iterator begin();
|
iterator begin();
|
||||||
iterator end();
|
iterator end();
|
||||||
|
|
||||||
// Accessors for the [start, limit) range of bytes within the JSON text from
|
|
||||||
// which this value was parsed, if any.
|
|
||||||
void setOffsetStart(size_t start);
|
|
||||||
void setOffsetLimit(size_t limit);
|
|
||||||
size_t getOffsetStart() const;
|
|
||||||
size_t getOffsetLimit() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initBasic(ValueType type, bool allocated = false);
|
void initBasic(ValueType type, bool allocated = false);
|
||||||
|
|
||||||
@@ -514,11 +510,6 @@ private:
|
|||||||
unsigned int memberNameIsStatic_ : 1; // used by the ValueInternalMap container.
|
unsigned int memberNameIsStatic_ : 1; // used by the ValueInternalMap container.
|
||||||
#endif
|
#endif
|
||||||
CommentInfo* comments_;
|
CommentInfo* comments_;
|
||||||
|
|
||||||
// [start, limit) byte offsets in the source JSON text from which this Value
|
|
||||||
// was extracted.
|
|
||||||
size_t start_;
|
|
||||||
size_t limit_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \brief Experimental and untested: represents an element of the "path" to
|
/** \brief Experimental and untested: represents an element of the "path" to
|
||||||
@@ -946,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
|
||||||
|
@@ -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 "1.4.0"
|
# define JSONCPP_VERSION_STRING "0.8.2"
|
||||||
# define JSONCPP_VERSION_MAJOR 1
|
# define JSONCPP_VERSION_MAJOR 0
|
||||||
# define JSONCPP_VERSION_MINOR 4
|
# define JSONCPP_VERSION_MINOR 8
|
||||||
# define JSONCPP_VERSION_PATCH 0
|
# define JSONCPP_VERSION_PATCH 2
|
||||||
# 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))
|
||||||
|
|
||||||
|
@@ -153,15 +153,6 @@ public:
|
|||||||
|
|
||||||
void enableYAMLCompatibility();
|
void enableYAMLCompatibility();
|
||||||
|
|
||||||
/** \brief Drop the "null" string from the writer's output for nullValues.
|
|
||||||
* Strictly speaking, this is not valid JSON. But when the output is being
|
|
||||||
* fed to a browser's Javascript, it makes for smaller output and the
|
|
||||||
* browser can handle the output just fine.
|
|
||||||
*/
|
|
||||||
void dropNullPlaceholders();
|
|
||||||
|
|
||||||
void omitEndingLineFeed();
|
|
||||||
|
|
||||||
public: // overridden from Writer
|
public: // overridden from Writer
|
||||||
virtual std::string write(const Value& root);
|
virtual std::string write(const Value& root);
|
||||||
|
|
||||||
@@ -170,8 +161,6 @@ private:
|
|||||||
|
|
||||||
std::string document_;
|
std::string document_;
|
||||||
bool yamlCompatiblityEnabled_;
|
bool yamlCompatiblityEnabled_;
|
||||||
bool dropNullPlaceholders_;
|
|
||||||
bool omitEndingLineFeed_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
|
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
|
||||||
|
@@ -43,17 +43,14 @@ typedef std::auto_ptr<CharReader> CharReaderPtr;
|
|||||||
// ////////////////////////////////
|
// ////////////////////////////////
|
||||||
|
|
||||||
Features::Features()
|
Features::Features()
|
||||||
: allowComments_(true), strictRoot_(false),
|
: allowComments_(true), strictRoot_(false)
|
||||||
allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
|
{}
|
||||||
|
|
||||||
Features Features::all() { return Features(); }
|
Features Features::all() { return Features(); }
|
||||||
|
|
||||||
Features Features::strictMode() {
|
Features Features::strictMode() {
|
||||||
Features features;
|
Features features;
|
||||||
features.allowComments_ = false;
|
features.allowComments_ = false;
|
||||||
features.strictRoot_ = true;
|
features.strictRoot_ = true;
|
||||||
features.allowDroppedNullPlaceholders_ = false;
|
|
||||||
features.allowNumericKeys_ = false;
|
|
||||||
return features;
|
return features;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,11 +160,9 @@ bool Reader::readValue() {
|
|||||||
switch (token.type_) {
|
switch (token.type_) {
|
||||||
case tokenObjectBegin:
|
case tokenObjectBegin:
|
||||||
successful = readObject(token);
|
successful = readObject(token);
|
||||||
currentValue().setOffsetLimit(current_ - begin_);
|
|
||||||
break;
|
break;
|
||||||
case tokenArrayBegin:
|
case tokenArrayBegin:
|
||||||
successful = readArray(token);
|
successful = readArray(token);
|
||||||
currentValue().setOffsetLimit(current_ - begin_);
|
|
||||||
break;
|
break;
|
||||||
case tokenNumber:
|
case tokenNumber:
|
||||||
successful = decodeNumber(token);
|
successful = decodeNumber(token);
|
||||||
@@ -179,41 +174,22 @@ bool Reader::readValue() {
|
|||||||
{
|
{
|
||||||
Value v(true);
|
Value v(true);
|
||||||
currentValue().swapPayload(v);
|
currentValue().swapPayload(v);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case tokenFalse:
|
case tokenFalse:
|
||||||
{
|
{
|
||||||
Value v(false);
|
Value v(false);
|
||||||
currentValue().swapPayload(v);
|
currentValue().swapPayload(v);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case tokenNull:
|
case tokenNull:
|
||||||
{
|
{
|
||||||
Value v;
|
Value v;
|
||||||
currentValue().swapPayload(v);
|
currentValue().swapPayload(v);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case tokenArraySeparator:
|
|
||||||
if (features_.allowDroppedNullPlaceholders_) {
|
|
||||||
// "Un-read" the current token and mark the current value as a null
|
|
||||||
// token.
|
|
||||||
current_--;
|
|
||||||
Value v;
|
|
||||||
currentValue().swapPayload(v);
|
|
||||||
currentValue().setOffsetStart(current_ - begin_ - 1);
|
|
||||||
currentValue().setOffsetLimit(current_ - begin_);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Else, fall through...
|
// Else, fall through...
|
||||||
default:
|
default:
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
|
||||||
return addError("Syntax error: value, object or array expected.", token);
|
return addError("Syntax error: value, object or array expected.", token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -441,12 +417,11 @@ bool Reader::readString() {
|
|||||||
return c == '"';
|
return c == '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Reader::readObject(Token& tokenStart) {
|
bool Reader::readObject(Token& /*tokenStart*/) {
|
||||||
Token tokenName;
|
Token tokenName;
|
||||||
std::string name;
|
std::string name;
|
||||||
Value init(objectValue);
|
Value init(objectValue);
|
||||||
currentValue().swapPayload(init);
|
currentValue().swapPayload(init);
|
||||||
currentValue().setOffsetStart(tokenStart.start_ - begin_);
|
|
||||||
while (readToken(tokenName)) {
|
while (readToken(tokenName)) {
|
||||||
bool initialTokenOk = true;
|
bool initialTokenOk = true;
|
||||||
while (tokenName.type_ == tokenComment && initialTokenOk)
|
while (tokenName.type_ == tokenComment && initialTokenOk)
|
||||||
@@ -459,11 +434,6 @@ bool Reader::readObject(Token& tokenStart) {
|
|||||||
if (tokenName.type_ == tokenString) {
|
if (tokenName.type_ == tokenString) {
|
||||||
if (!decodeString(tokenName, name))
|
if (!decodeString(tokenName, name))
|
||||||
return recoverFromError(tokenObjectEnd);
|
return recoverFromError(tokenObjectEnd);
|
||||||
} else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
|
|
||||||
Value numberName;
|
|
||||||
if (!decodeNumber(tokenName, numberName))
|
|
||||||
return recoverFromError(tokenObjectEnd);
|
|
||||||
name = numberName.asString();
|
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -497,10 +467,9 @@ bool Reader::readObject(Token& tokenStart) {
|
|||||||
"Missing '}' or object member name", tokenName, tokenObjectEnd);
|
"Missing '}' or object member name", tokenName, tokenObjectEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Reader::readArray(Token& tokenStart) {
|
bool Reader::readArray(Token& /*tokenStart*/) {
|
||||||
Value init(arrayValue);
|
Value init(arrayValue);
|
||||||
currentValue().swapPayload(init);
|
currentValue().swapPayload(init);
|
||||||
currentValue().setOffsetStart(tokenStart.start_ - begin_);
|
|
||||||
skipSpaces();
|
skipSpaces();
|
||||||
if (*current_ == ']') // empty array
|
if (*current_ == ']') // empty array
|
||||||
{
|
{
|
||||||
@@ -540,8 +509,6 @@ bool Reader::decodeNumber(Token& token) {
|
|||||||
if (!decodeNumber(token, decoded))
|
if (!decodeNumber(token, decoded))
|
||||||
return false;
|
return false;
|
||||||
currentValue().swapPayload(decoded);
|
currentValue().swapPayload(decoded);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,8 +557,6 @@ bool Reader::decodeDouble(Token& token) {
|
|||||||
if (!decodeDouble(token, decoded))
|
if (!decodeDouble(token, decoded))
|
||||||
return false;
|
return false;
|
||||||
currentValue().swapPayload(decoded);
|
currentValue().swapPayload(decoded);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,8 +602,6 @@ bool Reader::decodeString(Token& token) {
|
|||||||
return false;
|
return false;
|
||||||
Value decoded(decoded_string);
|
Value decoded(decoded_string);
|
||||||
currentValue().swapPayload(decoded);
|
currentValue().swapPayload(decoded);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -850,59 +813,8 @@ std::string Reader::getFormattedErrorMessages() const {
|
|||||||
return formattedMessage;
|
return formattedMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
|
// Reader
|
||||||
std::vector<Reader::StructuredError> allErrors;
|
/////////////////////////
|
||||||
for (Errors::const_iterator itError = errors_.begin();
|
|
||||||
itError != errors_.end();
|
|
||||||
++itError) {
|
|
||||||
const ErrorInfo& error = *itError;
|
|
||||||
Reader::StructuredError structured;
|
|
||||||
structured.offset_start = error.token_.start_ - begin_;
|
|
||||||
structured.offset_limit = error.token_.end_ - begin_;
|
|
||||||
structured.message = error.message_;
|
|
||||||
allErrors.push_back(structured);
|
|
||||||
}
|
|
||||||
return allErrors;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Reader::pushError(const Value& value, const std::string& message) {
|
|
||||||
size_t length = end_ - begin_;
|
|
||||||
if(value.getOffsetStart() > length
|
|
||||||
|| value.getOffsetLimit() > length)
|
|
||||||
return false;
|
|
||||||
Token token;
|
|
||||||
token.type_ = tokenError;
|
|
||||||
token.start_ = begin_ + value.getOffsetStart();
|
|
||||||
token.end_ = end_ + value.getOffsetLimit();
|
|
||||||
ErrorInfo info;
|
|
||||||
info.token_ = token;
|
|
||||||
info.message_ = message;
|
|
||||||
info.extra_ = 0;
|
|
||||||
errors_.push_back(info);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Reader::pushError(const Value& value, const std::string& message, const Value& extra) {
|
|
||||||
size_t length = end_ - begin_;
|
|
||||||
if(value.getOffsetStart() > length
|
|
||||||
|| value.getOffsetLimit() > length
|
|
||||||
|| extra.getOffsetLimit() > length)
|
|
||||||
return false;
|
|
||||||
Token token;
|
|
||||||
token.type_ = tokenError;
|
|
||||||
token.start_ = begin_ + value.getOffsetStart();
|
|
||||||
token.end_ = begin_ + value.getOffsetLimit();
|
|
||||||
ErrorInfo info;
|
|
||||||
info.token_ = token;
|
|
||||||
info.message_ = message;
|
|
||||||
info.extra_ = begin_ + extra.getOffsetStart();
|
|
||||||
errors_.push_back(info);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Reader::good() const {
|
|
||||||
return !errors_.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
// exact copy of Features
|
// exact copy of Features
|
||||||
class OurFeatures {
|
class OurFeatures {
|
||||||
@@ -914,6 +826,7 @@ public:
|
|||||||
bool strictRoot_;
|
bool strictRoot_;
|
||||||
bool allowDroppedNullPlaceholders_;
|
bool allowDroppedNullPlaceholders_;
|
||||||
bool allowNumericKeys_;
|
bool allowNumericKeys_;
|
||||||
|
bool failIfExtra_;
|
||||||
int stackLimit_;
|
int stackLimit_;
|
||||||
}; // OurFeatures
|
}; // OurFeatures
|
||||||
|
|
||||||
@@ -955,10 +868,6 @@ public:
|
|||||||
Value& root,
|
Value& root,
|
||||||
bool collectComments = true);
|
bool collectComments = true);
|
||||||
std::string getFormattedErrorMessages() const;
|
std::string getFormattedErrorMessages() const;
|
||||||
std::vector<StructuredError> getStructuredErrors() const;
|
|
||||||
bool pushError(const Value& value, const std::string& message);
|
|
||||||
bool pushError(const Value& value, const std::string& message, const Value& extra);
|
|
||||||
bool good() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OurReader(OurReader const&); // no impl
|
OurReader(OurReader const&); // no impl
|
||||||
@@ -1083,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_) {
|
||||||
@@ -1116,11 +1031,9 @@ bool OurReader::readValue() {
|
|||||||
switch (token.type_) {
|
switch (token.type_) {
|
||||||
case tokenObjectBegin:
|
case tokenObjectBegin:
|
||||||
successful = readObject(token);
|
successful = readObject(token);
|
||||||
currentValue().setOffsetLimit(current_ - begin_);
|
|
||||||
break;
|
break;
|
||||||
case tokenArrayBegin:
|
case tokenArrayBegin:
|
||||||
successful = readArray(token);
|
successful = readArray(token);
|
||||||
currentValue().setOffsetLimit(current_ - begin_);
|
|
||||||
break;
|
break;
|
||||||
case tokenNumber:
|
case tokenNumber:
|
||||||
successful = decodeNumber(token);
|
successful = decodeNumber(token);
|
||||||
@@ -1132,24 +1045,18 @@ bool OurReader::readValue() {
|
|||||||
{
|
{
|
||||||
Value v(true);
|
Value v(true);
|
||||||
currentValue().swapPayload(v);
|
currentValue().swapPayload(v);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case tokenFalse:
|
case tokenFalse:
|
||||||
{
|
{
|
||||||
Value v(false);
|
Value v(false);
|
||||||
currentValue().swapPayload(v);
|
currentValue().swapPayload(v);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case tokenNull:
|
case tokenNull:
|
||||||
{
|
{
|
||||||
Value v;
|
Value v;
|
||||||
currentValue().swapPayload(v);
|
currentValue().swapPayload(v);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case tokenArraySeparator:
|
case tokenArraySeparator:
|
||||||
@@ -1159,14 +1066,10 @@ bool OurReader::readValue() {
|
|||||||
current_--;
|
current_--;
|
||||||
Value v;
|
Value v;
|
||||||
currentValue().swapPayload(v);
|
currentValue().swapPayload(v);
|
||||||
currentValue().setOffsetStart(current_ - begin_ - 1);
|
|
||||||
currentValue().setOffsetLimit(current_ - begin_);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Else, fall through...
|
// Else, fall through...
|
||||||
default:
|
default:
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
|
||||||
return addError("Syntax error: value, object or array expected.", token);
|
return addError("Syntax error: value, object or array expected.", token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1380,7 +1283,6 @@ bool OurReader::readObject(Token& tokenStart) {
|
|||||||
std::string name;
|
std::string name;
|
||||||
Value init(objectValue);
|
Value init(objectValue);
|
||||||
currentValue().swapPayload(init);
|
currentValue().swapPayload(init);
|
||||||
currentValue().setOffsetStart(tokenStart.start_ - begin_);
|
|
||||||
while (readToken(tokenName)) {
|
while (readToken(tokenName)) {
|
||||||
bool initialTokenOk = true;
|
bool initialTokenOk = true;
|
||||||
while (tokenName.type_ == tokenComment && initialTokenOk)
|
while (tokenName.type_ == tokenComment && initialTokenOk)
|
||||||
@@ -1434,7 +1336,6 @@ bool OurReader::readObject(Token& tokenStart) {
|
|||||||
bool OurReader::readArray(Token& tokenStart) {
|
bool OurReader::readArray(Token& tokenStart) {
|
||||||
Value init(arrayValue);
|
Value init(arrayValue);
|
||||||
currentValue().swapPayload(init);
|
currentValue().swapPayload(init);
|
||||||
currentValue().setOffsetStart(tokenStart.start_ - begin_);
|
|
||||||
skipSpaces();
|
skipSpaces();
|
||||||
if (*current_ == ']') // empty array
|
if (*current_ == ']') // empty array
|
||||||
{
|
{
|
||||||
@@ -1474,8 +1375,6 @@ bool OurReader::decodeNumber(Token& token) {
|
|||||||
if (!decodeNumber(token, decoded))
|
if (!decodeNumber(token, decoded))
|
||||||
return false;
|
return false;
|
||||||
currentValue().swapPayload(decoded);
|
currentValue().swapPayload(decoded);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1524,8 +1423,6 @@ bool OurReader::decodeDouble(Token& token) {
|
|||||||
if (!decodeDouble(token, decoded))
|
if (!decodeDouble(token, decoded))
|
||||||
return false;
|
return false;
|
||||||
currentValue().swapPayload(decoded);
|
currentValue().swapPayload(decoded);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1571,8 +1468,6 @@ bool OurReader::decodeString(Token& token) {
|
|||||||
return false;
|
return false;
|
||||||
Value decoded(decoded_string);
|
Value decoded(decoded_string);
|
||||||
currentValue().swapPayload(decoded);
|
currentValue().swapPayload(decoded);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1779,60 +1674,6 @@ std::string OurReader::getFormattedErrorMessages() const {
|
|||||||
return formattedMessage;
|
return formattedMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
|
|
||||||
std::vector<OurReader::StructuredError> allErrors;
|
|
||||||
for (Errors::const_iterator itError = errors_.begin();
|
|
||||||
itError != errors_.end();
|
|
||||||
++itError) {
|
|
||||||
const ErrorInfo& error = *itError;
|
|
||||||
OurReader::StructuredError structured;
|
|
||||||
structured.offset_start = error.token_.start_ - begin_;
|
|
||||||
structured.offset_limit = error.token_.end_ - begin_;
|
|
||||||
structured.message = error.message_;
|
|
||||||
allErrors.push_back(structured);
|
|
||||||
}
|
|
||||||
return allErrors;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OurReader::pushError(const Value& value, const std::string& message) {
|
|
||||||
size_t length = end_ - begin_;
|
|
||||||
if(value.getOffsetStart() > length
|
|
||||||
|| value.getOffsetLimit() > length)
|
|
||||||
return false;
|
|
||||||
Token token;
|
|
||||||
token.type_ = tokenError;
|
|
||||||
token.start_ = begin_ + value.getOffsetStart();
|
|
||||||
token.end_ = end_ + value.getOffsetLimit();
|
|
||||||
ErrorInfo info;
|
|
||||||
info.token_ = token;
|
|
||||||
info.message_ = message;
|
|
||||||
info.extra_ = 0;
|
|
||||||
errors_.push_back(info);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OurReader::pushError(const Value& value, const std::string& message, const Value& extra) {
|
|
||||||
size_t length = end_ - begin_;
|
|
||||||
if(value.getOffsetStart() > length
|
|
||||||
|| value.getOffsetLimit() > length
|
|
||||||
|| extra.getOffsetLimit() > length)
|
|
||||||
return false;
|
|
||||||
Token token;
|
|
||||||
token.type_ = tokenError;
|
|
||||||
token.start_ = begin_ + value.getOffsetStart();
|
|
||||||
token.end_ = begin_ + value.getOffsetLimit();
|
|
||||||
ErrorInfo info;
|
|
||||||
info.token_ = token;
|
|
||||||
info.message_ = message;
|
|
||||||
info.extra_ = begin_ + extra.getOffsetStart();
|
|
||||||
errors_.push_back(info);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OurReader::good() const {
|
|
||||||
return !errors_.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class OurCharReader : public CharReader {
|
class OurCharReader : public CharReader {
|
||||||
bool const collectComments_;
|
bool const collectComments_;
|
||||||
@@ -1870,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)
|
||||||
@@ -1881,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
|
||||||
{
|
{
|
||||||
@@ -1908,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
|
||||||
@@ -1920,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]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -31,12 +31,13 @@ namespace Json {
|
|||||||
#if defined(__ARMEL__)
|
#if defined(__ARMEL__)
|
||||||
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
|
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
|
||||||
#else
|
#else
|
||||||
|
// This exists for binary compatibility only. Use nullRef.
|
||||||
|
static const Value null;
|
||||||
#define ALIGNAS(byte_alignment)
|
#define ALIGNAS(byte_alignment)
|
||||||
#endif
|
#endif
|
||||||
static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
|
static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
|
||||||
const unsigned char& kNullRef = kNull[0];
|
const unsigned char& kNullRef = kNull[0];
|
||||||
const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
|
const Value& Value::nullRef = reinterpret_cast<const Value&>(kNullRef);
|
||||||
const Value& Value::nullRef = null;
|
|
||||||
|
|
||||||
const Int Value::minInt = Int(~(UInt(-1) / 2));
|
const Int Value::minInt = Int(~(UInt(-1) / 2));
|
||||||
const Int Value::maxInt = Int(UInt(-1) / 2);
|
const Int Value::maxInt = Int(UInt(-1) / 2);
|
||||||
@@ -192,8 +193,9 @@ void Value::CZString::swap(CZString& other) {
|
|||||||
std::swap(index_, other.index_);
|
std::swap(index_, other.index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::CZString& Value::CZString::operator=(CZString other) {
|
Value::CZString &Value::CZString::operator=(const CZString &other) {
|
||||||
swap(other);
|
CZString temp(other);
|
||||||
|
swap(temp);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,7 +333,7 @@ Value::Value(const Value& other)
|
|||||||
itemIsUsed_(0)
|
itemIsUsed_(0)
|
||||||
#endif
|
#endif
|
||||||
,
|
,
|
||||||
comments_(0), start_(other.start_), limit_(other.limit_) {
|
comments_(0) {
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
case nullValue:
|
case nullValue:
|
||||||
case intValue:
|
case intValue:
|
||||||
@@ -409,8 +411,9 @@ Value::~Value() {
|
|||||||
delete[] comments_;
|
delete[] comments_;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value& Value::operator=(Value other) {
|
Value &Value::operator=(const Value &other) {
|
||||||
swap(other);
|
Value temp(other);
|
||||||
|
swap(temp);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,8 +430,6 @@ void Value::swapPayload(Value& other) {
|
|||||||
void Value::swap(Value& other) {
|
void Value::swap(Value& other) {
|
||||||
swapPayload(other);
|
swapPayload(other);
|
||||||
std::swap(comments_, other.comments_);
|
std::swap(comments_, other.comments_);
|
||||||
std::swap(start_, other.start_);
|
|
||||||
std::swap(limit_, other.limit_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueType Value::type() const { return type_; }
|
ValueType Value::type() const { return type_; }
|
||||||
@@ -803,8 +804,6 @@ void Value::clear() {
|
|||||||
JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue ||
|
JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue ||
|
||||||
type_ == objectValue,
|
type_ == objectValue,
|
||||||
"in Json::Value::clear(): requires complex value");
|
"in Json::Value::clear(): requires complex value");
|
||||||
start_ = 0;
|
|
||||||
limit_ = 0;
|
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
@@ -858,7 +857,7 @@ Value& Value::operator[](ArrayIndex index) {
|
|||||||
if (it != value_.map_->end() && (*it).first == key)
|
if (it != value_.map_->end() && (*it).first == key)
|
||||||
return (*it).second;
|
return (*it).second;
|
||||||
|
|
||||||
ObjectValues::value_type defaultValue(key, null);
|
ObjectValues::value_type defaultValue(key, nullRef);
|
||||||
it = value_.map_->insert(it, defaultValue);
|
it = value_.map_->insert(it, defaultValue);
|
||||||
return (*it).second;
|
return (*it).second;
|
||||||
#else
|
#else
|
||||||
@@ -878,16 +877,16 @@ const Value& Value::operator[](ArrayIndex index) const {
|
|||||||
type_ == nullValue || type_ == arrayValue,
|
type_ == nullValue || type_ == arrayValue,
|
||||||
"in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
|
"in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
|
||||||
if (type_ == nullValue)
|
if (type_ == nullValue)
|
||||||
return null;
|
return nullRef;
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
CZString key(index);
|
CZString key(index);
|
||||||
ObjectValues::const_iterator it = value_.map_->find(key);
|
ObjectValues::const_iterator it = value_.map_->find(key);
|
||||||
if (it == value_.map_->end())
|
if (it == value_.map_->end())
|
||||||
return null;
|
return nullRef;
|
||||||
return (*it).second;
|
return (*it).second;
|
||||||
#else
|
#else
|
||||||
Value* value = value_.array_->find(index);
|
Value* value = value_.array_->find(index);
|
||||||
return value ? *value : null;
|
return value ? *value : nullRef;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -909,8 +908,6 @@ void Value::initBasic(ValueType type, bool allocated) {
|
|||||||
itemIsUsed_ = 0;
|
itemIsUsed_ = 0;
|
||||||
#endif
|
#endif
|
||||||
comments_ = 0;
|
comments_ = 0;
|
||||||
start_ = 0;
|
|
||||||
limit_ = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value& Value::resolveReference(const char* key, bool isStatic) {
|
Value& Value::resolveReference(const char* key, bool isStatic) {
|
||||||
@@ -926,7 +923,7 @@ Value& Value::resolveReference(const char* key, bool isStatic) {
|
|||||||
if (it != value_.map_->end() && (*it).first == actualKey)
|
if (it != value_.map_->end() && (*it).first == actualKey)
|
||||||
return (*it).second;
|
return (*it).second;
|
||||||
|
|
||||||
ObjectValues::value_type defaultValue(actualKey, null);
|
ObjectValues::value_type defaultValue(actualKey, nullRef);
|
||||||
it = value_.map_->insert(it, defaultValue);
|
it = value_.map_->insert(it, defaultValue);
|
||||||
Value& value = (*it).second;
|
Value& value = (*it).second;
|
||||||
return value;
|
return value;
|
||||||
@@ -937,7 +934,7 @@ Value& Value::resolveReference(const char* key, bool isStatic) {
|
|||||||
|
|
||||||
Value Value::get(ArrayIndex index, const Value& defaultValue) const {
|
Value Value::get(ArrayIndex index, const Value& defaultValue) const {
|
||||||
const Value* value = &((*this)[index]);
|
const Value* value = &((*this)[index]);
|
||||||
return value == &null ? defaultValue : *value;
|
return value == &nullRef ? defaultValue : *value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
|
bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
|
||||||
@@ -947,16 +944,16 @@ const Value& Value::operator[](const char* key) const {
|
|||||||
type_ == nullValue || type_ == objectValue,
|
type_ == nullValue || type_ == objectValue,
|
||||||
"in Json::Value::operator[](char const*)const: requires objectValue");
|
"in Json::Value::operator[](char const*)const: requires objectValue");
|
||||||
if (type_ == nullValue)
|
if (type_ == nullValue)
|
||||||
return null;
|
return nullRef;
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
CZString actualKey(key, CZString::noDuplication);
|
CZString actualKey(key, CZString::noDuplication);
|
||||||
ObjectValues::const_iterator it = value_.map_->find(actualKey);
|
ObjectValues::const_iterator it = value_.map_->find(actualKey);
|
||||||
if (it == value_.map_->end())
|
if (it == value_.map_->end())
|
||||||
return null;
|
return nullRef;
|
||||||
return (*it).second;
|
return (*it).second;
|
||||||
#else
|
#else
|
||||||
const Value* value = value_.map_->find(key);
|
const Value* value = value_.map_->find(key);
|
||||||
return value ? *value : null;
|
return value ? *value : nullRef;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -986,7 +983,7 @@ Value& Value::append(const Value& value) { return (*this)[size()] = value; }
|
|||||||
|
|
||||||
Value Value::get(const char* key, const Value& defaultValue) const {
|
Value Value::get(const char* key, const Value& defaultValue) const {
|
||||||
const Value* value = &((*this)[key]);
|
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 {
|
Value Value::get(const std::string& key, const Value& defaultValue) const {
|
||||||
@@ -1022,7 +1019,7 @@ Value Value::removeMember(const char* key) {
|
|||||||
JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
|
JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
|
||||||
"in Json::Value::removeMember(): requires objectValue");
|
"in Json::Value::removeMember(): requires objectValue");
|
||||||
if (type_ == nullValue)
|
if (type_ == nullValue)
|
||||||
return null;
|
return nullRef;
|
||||||
|
|
||||||
Value removed; // null
|
Value removed; // null
|
||||||
removeMember(key, &removed);
|
removeMember(key, &removed);
|
||||||
@@ -1070,7 +1067,7 @@ Value Value::get(const CppTL::ConstString& key,
|
|||||||
|
|
||||||
bool Value::isMember(const char* key) const {
|
bool Value::isMember(const char* key) const {
|
||||||
const Value* value = &((*this)[key]);
|
const Value* value = &((*this)[key]);
|
||||||
return value != &null;
|
return value != &nullRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Value::isMember(const std::string& key) const {
|
bool Value::isMember(const std::string& key) const {
|
||||||
@@ -1257,14 +1254,6 @@ std::string Value::getComment(CommentPlacement placement) const {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::setOffsetStart(size_t start) { start_ = start; }
|
|
||||||
|
|
||||||
void Value::setOffsetLimit(size_t limit) { limit_ = limit; }
|
|
||||||
|
|
||||||
size_t Value::getOffsetStart() const { return start_; }
|
|
||||||
|
|
||||||
size_t Value::getOffsetLimit() const { return limit_; }
|
|
||||||
|
|
||||||
std::string Value::toStyledString() const {
|
std::string Value::toStyledString() const {
|
||||||
StyledWriter writer;
|
StyledWriter writer;
|
||||||
return writer.write(*this);
|
return writer.write(*this);
|
||||||
@@ -1484,7 +1473,7 @@ const Value& Path::resolve(const Value& root) const {
|
|||||||
// Error: unable to resolve path (object value expected at position...)
|
// Error: unable to resolve path (object value expected at position...)
|
||||||
}
|
}
|
||||||
node = &((*node)[arg.key_]);
|
node = &((*node)[arg.key_]);
|
||||||
if (node == &Value::null) {
|
if (node == &Value::nullRef) {
|
||||||
// Error: unable to resolve path (object has no member named '' at
|
// Error: unable to resolve path (object has no member named '' at
|
||||||
// position...)
|
// position...)
|
||||||
}
|
}
|
||||||
@@ -1505,7 +1494,7 @@ Value Path::resolve(const Value& root, const Value& defaultValue) const {
|
|||||||
if (!node->isObject())
|
if (!node->isObject())
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
node = &((*node)[arg.key_]);
|
node = &((*node)[arg.key_]);
|
||||||
if (node == &Value::null)
|
if (node == &Value::nullRef)
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
@@ -192,28 +192,21 @@ Writer::~Writer() {}
|
|||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
FastWriter::FastWriter()
|
FastWriter::FastWriter()
|
||||||
: yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false),
|
: yamlCompatiblityEnabled_(false) {}
|
||||||
omitEndingLineFeed_(false) {}
|
|
||||||
|
|
||||||
void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
|
void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
|
||||||
|
|
||||||
void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
|
|
||||||
|
|
||||||
void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
|
|
||||||
|
|
||||||
std::string FastWriter::write(const Value& root) {
|
std::string FastWriter::write(const Value& root) {
|
||||||
document_ = "";
|
document_ = "";
|
||||||
writeValue(root);
|
writeValue(root);
|
||||||
if (!omitEndingLineFeed_)
|
document_ += "\n";
|
||||||
document_ += "\n";
|
|
||||||
return document_;
|
return document_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FastWriter::writeValue(const Value& value) {
|
void FastWriter::writeValue(const Value& value) {
|
||||||
switch (value.type()) {
|
switch (value.type()) {
|
||||||
case nullValue:
|
case nullValue:
|
||||||
if (!dropNullPlaceholders_)
|
document_ += "null";
|
||||||
document_ += "null";
|
|
||||||
break;
|
break;
|
||||||
case intValue:
|
case intValue:
|
||||||
document_ += valueToString(value.asLargestInt());
|
document_ += valueToString(value.asLargestInt());
|
||||||
|
@@ -1497,36 +1497,6 @@ JSONTEST_FIXTURE(ValueTest, typeChecksThrowExceptions) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONTEST_FIXTURE(ValueTest, offsetAccessors) {
|
|
||||||
Json::Value x;
|
|
||||||
JSONTEST_ASSERT(x.getOffsetStart() == 0);
|
|
||||||
JSONTEST_ASSERT(x.getOffsetLimit() == 0);
|
|
||||||
x.setOffsetStart(10);
|
|
||||||
x.setOffsetLimit(20);
|
|
||||||
JSONTEST_ASSERT(x.getOffsetStart() == 10);
|
|
||||||
JSONTEST_ASSERT(x.getOffsetLimit() == 20);
|
|
||||||
Json::Value y(x);
|
|
||||||
JSONTEST_ASSERT(y.getOffsetStart() == 10);
|
|
||||||
JSONTEST_ASSERT(y.getOffsetLimit() == 20);
|
|
||||||
Json::Value z;
|
|
||||||
z.swap(y);
|
|
||||||
JSONTEST_ASSERT(z.getOffsetStart() == 10);
|
|
||||||
JSONTEST_ASSERT(z.getOffsetLimit() == 20);
|
|
||||||
JSONTEST_ASSERT(y.getOffsetStart() == 0);
|
|
||||||
JSONTEST_ASSERT(y.getOffsetLimit() == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WriterTest : JsonTest::TestCase {};
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(WriterTest, dropNullPlaceholders) {
|
|
||||||
Json::FastWriter writer;
|
|
||||||
Json::Value nullValue;
|
|
||||||
JSONTEST_ASSERT(writer.write(nullValue) == "null\n");
|
|
||||||
|
|
||||||
writer.dropNullPlaceholders();
|
|
||||||
JSONTEST_ASSERT(writer.write(nullValue) == "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
struct StreamWriterTest : JsonTest::TestCase {};
|
struct StreamWriterTest : JsonTest::TestCase {};
|
||||||
|
|
||||||
JSONTEST_FIXTURE(StreamWriterTest, dropNullPlaceholders) {
|
JSONTEST_FIXTURE(StreamWriterTest, dropNullPlaceholders) {
|
||||||
@@ -1546,7 +1516,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithNoErrors) {
|
|||||||
bool ok = reader.parse("{ \"property\" : \"value\" }", root);
|
bool ok = reader.parse("{ \"property\" : \"value\" }", root);
|
||||||
JSONTEST_ASSERT(ok);
|
JSONTEST_ASSERT(ok);
|
||||||
JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0);
|
JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0);
|
||||||
JSONTEST_ASSERT(reader.getStructuredErrors().size() == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONTEST_FIXTURE(ReaderTest, parseWithNoErrorsTestingOffsets) {
|
JSONTEST_FIXTURE(ReaderTest, parseWithNoErrorsTestingOffsets) {
|
||||||
@@ -1558,25 +1527,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithNoErrorsTestingOffsets) {
|
|||||||
root);
|
root);
|
||||||
JSONTEST_ASSERT(ok);
|
JSONTEST_ASSERT(ok);
|
||||||
JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0);
|
JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0);
|
||||||
JSONTEST_ASSERT(reader.getStructuredErrors().size() == 0);
|
|
||||||
JSONTEST_ASSERT(root["property"].getOffsetStart() == 15);
|
|
||||||
JSONTEST_ASSERT(root["property"].getOffsetLimit() == 34);
|
|
||||||
JSONTEST_ASSERT(root["property"][0].getOffsetStart() == 16);
|
|
||||||
JSONTEST_ASSERT(root["property"][0].getOffsetLimit() == 23);
|
|
||||||
JSONTEST_ASSERT(root["property"][1].getOffsetStart() == 25);
|
|
||||||
JSONTEST_ASSERT(root["property"][1].getOffsetLimit() == 33);
|
|
||||||
JSONTEST_ASSERT(root["obj"].getOffsetStart() == 44);
|
|
||||||
JSONTEST_ASSERT(root["obj"].getOffsetLimit() == 76);
|
|
||||||
JSONTEST_ASSERT(root["obj"]["nested"].getOffsetStart() == 57);
|
|
||||||
JSONTEST_ASSERT(root["obj"]["nested"].getOffsetLimit() == 60);
|
|
||||||
JSONTEST_ASSERT(root["obj"]["bool"].getOffsetStart() == 71);
|
|
||||||
JSONTEST_ASSERT(root["obj"]["bool"].getOffsetLimit() == 75);
|
|
||||||
JSONTEST_ASSERT(root["null"].getOffsetStart() == 87);
|
|
||||||
JSONTEST_ASSERT(root["null"].getOffsetLimit() == 91);
|
|
||||||
JSONTEST_ASSERT(root["false"].getOffsetStart() == 103);
|
|
||||||
JSONTEST_ASSERT(root["false"].getOffsetLimit() == 108);
|
|
||||||
JSONTEST_ASSERT(root.getOffsetStart() == 0);
|
|
||||||
JSONTEST_ASSERT(root.getOffsetLimit() == 110);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONTEST_FIXTURE(ReaderTest, parseWithOneError) {
|
JSONTEST_FIXTURE(ReaderTest, parseWithOneError) {
|
||||||
@@ -1587,13 +1537,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithOneError) {
|
|||||||
JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
|
JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
|
||||||
"* Line 1, Column 15\n Syntax error: value, object or array "
|
"* Line 1, Column 15\n Syntax error: value, object or array "
|
||||||
"expected.\n");
|
"expected.\n");
|
||||||
std::vector<Json::Reader::StructuredError> errors =
|
|
||||||
reader.getStructuredErrors();
|
|
||||||
JSONTEST_ASSERT(errors.size() == 1);
|
|
||||||
JSONTEST_ASSERT(errors.at(0).offset_start == 14);
|
|
||||||
JSONTEST_ASSERT(errors.at(0).offset_limit == 15);
|
|
||||||
JSONTEST_ASSERT(errors.at(0).message ==
|
|
||||||
"Syntax error: value, object or array expected.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONTEST_FIXTURE(ReaderTest, parseChineseWithOneError) {
|
JSONTEST_FIXTURE(ReaderTest, parseChineseWithOneError) {
|
||||||
@@ -1604,13 +1547,6 @@ JSONTEST_FIXTURE(ReaderTest, parseChineseWithOneError) {
|
|||||||
JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
|
JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
|
||||||
"* Line 1, Column 19\n Syntax error: value, object or array "
|
"* Line 1, Column 19\n Syntax error: value, object or array "
|
||||||
"expected.\n");
|
"expected.\n");
|
||||||
std::vector<Json::Reader::StructuredError> errors =
|
|
||||||
reader.getStructuredErrors();
|
|
||||||
JSONTEST_ASSERT(errors.size() == 1);
|
|
||||||
JSONTEST_ASSERT(errors.at(0).offset_start == 18);
|
|
||||||
JSONTEST_ASSERT(errors.at(0).offset_limit == 19);
|
|
||||||
JSONTEST_ASSERT(errors.at(0).message ==
|
|
||||||
"Syntax error: value, object or array expected.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONTEST_FIXTURE(ReaderTest, parseWithDetailError) {
|
JSONTEST_FIXTURE(ReaderTest, parseWithDetailError) {
|
||||||
@@ -1621,12 +1557,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithDetailError) {
|
|||||||
JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
|
JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
|
||||||
"* Line 1, Column 16\n Bad escape sequence in string\nSee "
|
"* Line 1, Column 16\n Bad escape sequence in string\nSee "
|
||||||
"Line 1, Column 20 for detail.\n");
|
"Line 1, Column 20 for detail.\n");
|
||||||
std::vector<Json::Reader::StructuredError> errors =
|
|
||||||
reader.getStructuredErrors();
|
|
||||||
JSONTEST_ASSERT(errors.size() == 1);
|
|
||||||
JSONTEST_ASSERT(errors.at(0).offset_start == 15);
|
|
||||||
JSONTEST_ASSERT(errors.at(0).offset_limit == 23);
|
|
||||||
JSONTEST_ASSERT(errors.at(0).message == "Bad escape sequence in string");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CharReaderTest : JsonTest::TestCase {};
|
struct CharReaderTest : JsonTest::TestCase {};
|
||||||
@@ -1741,6 +1671,143 @@ 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 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);
|
||||||
@@ -1761,9 +1828,10 @@ int main(int argc, const char* argv[]) {
|
|||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareArray);
|
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareArray);
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareObject);
|
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareObject);
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareType);
|
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareType);
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, offsetAccessors);
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, typeChecksThrowExceptions);
|
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, typeChecksThrowExceptions);
|
||||||
|
|
||||||
|
JSONTEST_REGISTER_FIXTURE(runner, 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);
|
||||||
@@ -1779,8 +1847,13 @@ 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, WriterTest, dropNullPlaceholders);
|
JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, issue164);
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders);
|
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, IteratorTest, distance);
|
||||||
|
|
||||||
return runner.runCommandLine(argc, argv);
|
return runner.runCommandLine(argc, argv);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user