mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2025-10-14 15:05:34 +02:00
Compare commits
44 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d84702c903 | ||
![]() |
949babd7b0 | ||
![]() |
6ed877c77c | ||
![]() |
1c69568f8d | ||
![]() |
770fdda28b | ||
![]() |
81cf237917 | ||
![]() |
cac79543f8 | ||
![]() |
d8186f36a6 | ||
![]() |
7f240623d3 | ||
![]() |
784433ac72 | ||
![]() |
7275e3ce3c | ||
![]() |
46aa9d75fa | ||
![]() |
f94a0e8989 | ||
![]() |
e22a2f36f7 | ||
![]() |
fac87108a4 | ||
![]() |
14fc9f124e | ||
![]() |
658fa37e63 | ||
![]() |
056e5f9b64 | ||
![]() |
d8e8c14ffc | ||
![]() |
f4e6fccd46 | ||
![]() |
2428889813 | ||
![]() |
89704039a0 | ||
![]() |
6ca8ffcb91 | ||
![]() |
b5e70f950e | ||
![]() |
b26804d1c2 | ||
![]() |
702a539762 | ||
![]() |
81cb7e5c5b | ||
![]() |
d259f608fd | ||
![]() |
4652f818fe | ||
![]() |
ce32274ba5 | ||
![]() |
717c791d4e | ||
![]() |
6e52e272da | ||
![]() |
6416350438 | ||
![]() |
bcb83b921c | ||
![]() |
3f05b1a897 | ||
![]() |
de2c85f576 | ||
![]() |
b389d81bf9 | ||
![]() |
89c51f3457 | ||
![]() |
e6f1cffdd3 | ||
![]() |
64441486ac | ||
![]() |
d5e54d2609 | ||
![]() |
97e093a361 | ||
![]() |
d57ac97db8 | ||
![]() |
31e9962754 |
34
.travis.yml
34
.travis.yml
@@ -2,13 +2,31 @@
|
||||
# http://about.travis-ci.org/docs/user/build-configuration/
|
||||
# This file can be validated on:
|
||||
# http://lint.travis-ci.org/
|
||||
# See also
|
||||
# http://stackoverflow.com/questions/22111549/travis-ci-with-clang-3-4-and-c11/30925448#30925448
|
||||
# to allow C++11, though we are not yet building with -std=c++11
|
||||
|
||||
#before_install: sudo apt-get install -y cmake
|
||||
# cmake is pre-installed in Travis for both linux and osx
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq valgrind
|
||||
install:
|
||||
# /usr/bin/gcc is 4.6 always, but gcc-X.Y is available.
|
||||
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.9" CC="gcc-4.9"; fi
|
||||
# /usr/bin/clang is our version already, and clang-X.Y does not exist.
|
||||
#- if [ "$CXX" = "clang++" ]; then export CXX="clang++-3.7" CC="clang-3.7"; fi
|
||||
- echo ${PATH}
|
||||
- ls /usr/local
|
||||
- ls /usr/local/bin
|
||||
- export PATH=/usr/local/bin:/usr/bin:${PATH}
|
||||
- echo ${CXX}
|
||||
- ${CXX} --version
|
||||
- which valgrind
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-4.9
|
||||
- g++-4.9
|
||||
- clang
|
||||
- valgrind
|
||||
os:
|
||||
- linux
|
||||
language: cpp
|
||||
@@ -21,5 +39,5 @@ env:
|
||||
- SHARED_LIB=ON STATIC_LIB=ON CMAKE_PKG=ON BUILD_TYPE=release VERBOSE_MAKE=false
|
||||
- SHARED_LIB=OFF STATIC_LIB=ON CMAKE_PKG=OFF BUILD_TYPE=debug VERBOSE_MAKE=true VERBOSE
|
||||
notifications:
|
||||
email:
|
||||
- aaronjjacobs@gmail.com
|
||||
email: false
|
||||
sudo: false
|
||||
|
@@ -21,15 +21,16 @@ IF(NOT WIN32)
|
||||
ENDIF(NOT CMAKE_BUILD_TYPE)
|
||||
ENDIF(NOT WIN32)
|
||||
|
||||
SET(DEBUG_LIBNAME_SUFFIX "" CACHE STRING "Optional suffix to append to the library name for a debug build")
|
||||
SET(LIB_SUFFIX "" CACHE STRING "Optional arch-dependent suffix for the library installation directory")
|
||||
|
||||
SET(RUNTIME_INSTALL_DIR bin
|
||||
CACHE PATH "Install dir for executables and dlls")
|
||||
SET(ARCHIVE_INSTALL_DIR lib${LIB_SUFFIX}
|
||||
SET(ARCHIVE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}
|
||||
CACHE PATH "Install dir for static libraries")
|
||||
SET(LIBRARY_INSTALL_DIR lib${LIB_SUFFIX}
|
||||
SET(LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}
|
||||
CACHE PATH "Install dir for shared libraries")
|
||||
SET(INCLUDE_INSTALL_DIR include
|
||||
SET(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include
|
||||
CACHE PATH "Install dir for headers")
|
||||
SET(PACKAGE_INSTALL_DIR lib${LIB_SUFFIX}/cmake
|
||||
CACHE PATH "Install dir for cmake package config files")
|
||||
@@ -62,7 +63,7 @@ ENDMACRO(jsoncpp_parse_version)
|
||||
#SET( JSONCPP_VERSION_MAJOR X )
|
||||
#SET( JSONCPP_VERSION_MINOR Y )
|
||||
#SET( JSONCPP_VERSION_PATCH Z )
|
||||
SET( JSONCPP_VERSION 0.10.2 )
|
||||
SET( JSONCPP_VERSION 1.6.5 )
|
||||
jsoncpp_parse_version( ${JSONCPP_VERSION} JSONCPP_VERSION )
|
||||
#IF(NOT JSONCPP_VERSION_FOUND)
|
||||
# MESSAGE(FATAL_ERROR "Failed to parse version string properly. Expect X.Y.Z")
|
||||
@@ -96,10 +97,11 @@ endif( MSVC )
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# using regular Clang or AppleClang
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Werror -Wall -Wconversion -Wshadow -Wno-sign-conversion")
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
# using GCC
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Werror -Wall -Wconversion -Wshadow -Wextra -pedantic")
|
||||
# not yet ready for -Wsign-conversion
|
||||
endif()
|
||||
|
||||
IF(JSONCPP_WITH_WARNING_AS_ERROR)
|
||||
|
66
README.md
66
README.md
@@ -19,12 +19,14 @@ format to store user input files.
|
||||
* `0.y.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 amalgamated source (a single `.cpp` file) with your own build system. This
|
||||
ensures consistency of compilation flags and ABI compatibility. See the section
|
||||
"Generating amalgamated source and header" for instructions.
|
||||
The recommended approach to integrating JsonCpp in your project is to include
|
||||
the [amalgamated source](#generating-amalgamated-source-and-header) (a single
|
||||
`.cpp` file and two `.h` files) in your project, and compile and build as you
|
||||
would any other source file. This ensures consistency of compilation flags and
|
||||
ABI compatibility, issues which arise when building shared or static
|
||||
libraries. See the next section for instructions.
|
||||
|
||||
The `include/` should be added to your compiler include path. Jsoncpp headers
|
||||
should be included as follow:
|
||||
@@ -34,6 +36,31 @@ should be included as follow:
|
||||
If JsonCpp was built as a dynamic library on Windows, then your project needs to
|
||||
define the macro `JSON_DLL`.
|
||||
|
||||
Generating amalgamated source and header
|
||||
----------------------------------------
|
||||
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
|
||||
can be generated at any time by running the following command from the
|
||||
top-directory (this requires Python 2.6):
|
||||
|
||||
python amalgamate.py
|
||||
|
||||
It is possible to specify header name. See the `-h` option for detail.
|
||||
|
||||
By default, the following files are generated:
|
||||
* `dist/jsoncpp.cpp`: source file that needs to be added to your project.
|
||||
* `dist/json/json.h`: corresponding header file for use in your project. It is
|
||||
equivalent to including `json/json.h` in non-amalgamated source. This header
|
||||
only depends on standard headers.
|
||||
* `dist/json/json-forwards.h`: header that provides forward declaration of all
|
||||
JsonCpp types.
|
||||
|
||||
The amalgamated sources are generated by concatenating JsonCpp source in the
|
||||
correct order and defining the macro `JSON_IS_AMALGAMATION` to prevent inclusion
|
||||
of other headers.
|
||||
|
||||
# Contributing to JsonCpp
|
||||
|
||||
Building and testing with CMake
|
||||
-------------------------------
|
||||
[CMake][] is a C++ Makefiles/Solution generator. It is usually available on most
|
||||
@@ -67,10 +94,10 @@ Alternatively, from the command-line on Unix in the source directory:
|
||||
|
||||
mkdir -p build/debug
|
||||
cd build/debug
|
||||
cmake -DCMAKE_BUILD_TYPE=debug -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=OFF -G "Unix Makefiles" ../..
|
||||
cmake -DCMAKE_BUILD_TYPE=debug -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=OFF -DARCHIVE_INSTALL_DIR=. -G "Unix Makefiles" ../..
|
||||
make
|
||||
|
||||
Running `cmake -`" will display the list of available generators (passed using
|
||||
Running `cmake -h` will display the list of available generators (passed using
|
||||
the `-G` option).
|
||||
|
||||
By default CMake hides compilation commands. This can be modified by specifying
|
||||
@@ -106,7 +133,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
|
||||
running SCons.
|
||||
|
||||
# Running the tests manually
|
||||
## Running the tests manually
|
||||
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
|
||||
@@ -142,29 +169,6 @@ Run the Python script `doxybuild.py` from the top directory:
|
||||
|
||||
See `doxybuild.py --help` for options.
|
||||
|
||||
Generating amalgamated source and header
|
||||
----------------------------------------
|
||||
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
|
||||
can be generated at any time by running the following command from the
|
||||
top-directory (this requires Python 2.6):
|
||||
|
||||
python amalgamate.py
|
||||
|
||||
It is possible to specify header name. See the `-h` option for detail.
|
||||
|
||||
By default, the following files are generated:
|
||||
* `dist/jsoncpp.cpp`: source file that needs to be added to your project.
|
||||
* `dist/json/json.h`: corresponding header file for use in your project. It is
|
||||
equivalent to including `json/json.h` in non-amalgamated source. This header
|
||||
only depends on standard headers.
|
||||
* `dist/json/json-forwards.h`: header that provides forward declaration of all
|
||||
JsonCpp types.
|
||||
|
||||
The amalgamated sources are generated by concatenating JsonCpp source in the
|
||||
correct order and defining the macro `JSON_IS_AMALGAMATION` to prevent inclusion
|
||||
of other headers.
|
||||
|
||||
Adding a reader/writer test
|
||||
---------------------------
|
||||
To add a test, you need to create two files in test/data:
|
||||
|
@@ -19,6 +19,7 @@ before_build:
|
||||
- echo "Running cmake..."
|
||||
- cd c:\projects\jsoncpp
|
||||
- cmake --version
|
||||
- set PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH%
|
||||
- if %PLATFORM% == Win32 cmake .
|
||||
- if %PLATFORM% == x64 cmake -G "Visual Studio 12 2013 Win64" .
|
||||
|
||||
|
@@ -5,6 +5,7 @@
|
||||
|
||||
from __future__ import print_function
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
def fix_source_eol(path, is_dry_run = True, verbose = True, eol = '\n'):
|
||||
"""Makes sure that all sources have the specified eol sequence (default: unix)."""
|
||||
|
@@ -72,7 +72,7 @@ def run_cmd(cmd, silent=False):
|
||||
if silent:
|
||||
status, output = getstatusoutput(cmd)
|
||||
else:
|
||||
status, output = os.system(' '.join(cmd)), ''
|
||||
status, output = subprocess.call(cmd), ''
|
||||
if status:
|
||||
msg = 'Error while %s ...\n\terror=%d, output="""%s"""' %(info, status, output)
|
||||
raise Exception(msg)
|
||||
|
@@ -44,6 +44,12 @@ public:
|
||||
/// \c true if root must be either an array or an object value. Default: \c
|
||||
/// false.
|
||||
bool strictRoot_;
|
||||
|
||||
/// \c true if dropped null placeholders are allowed. Default: \c false.
|
||||
bool allowDroppedNullPlaceholders_;
|
||||
|
||||
/// \c true if numeric object key are allowed. Default: \c false.
|
||||
bool allowNumericKeys_;
|
||||
};
|
||||
|
||||
} // namespace Json
|
||||
|
@@ -35,6 +35,18 @@ public:
|
||||
typedef char Char;
|
||||
typedef const Char* Location;
|
||||
|
||||
/** \brief An error tagged with where in the JSON text it was encountered.
|
||||
*
|
||||
* The offsets give the [start, limit) range of bytes within the text. Note
|
||||
* that this is bytes, not codepoints.
|
||||
*
|
||||
*/
|
||||
struct StructuredError {
|
||||
size_t offset_start;
|
||||
size_t offset_limit;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
/** \brief Constructs a Reader allowing all features
|
||||
* for parsing.
|
||||
*/
|
||||
@@ -111,6 +123,38 @@ public:
|
||||
*/
|
||||
std::string getFormattedErrorMessages() const;
|
||||
|
||||
/** \brief Returns a vector of structured erros encounted while parsing.
|
||||
* \return A (possibly empty) vector of StructuredError objects. Currently
|
||||
* only one error can be returned, but the caller should tolerate
|
||||
* multiple
|
||||
* errors. This can occur if the parser recovers from a non-fatal
|
||||
* parse error and then encounters additional errors.
|
||||
*/
|
||||
std::vector<StructuredError> getStructuredErrors() const;
|
||||
|
||||
/** \brief Add a semantic error message.
|
||||
* \param value JSON Value location associated with the error
|
||||
* \param message The error message.
|
||||
* \return \c true if the error was successfully added, \c false if the
|
||||
* Value offset exceeds the document size.
|
||||
*/
|
||||
bool pushError(const Value& value, const std::string& message);
|
||||
|
||||
/** \brief Add a semantic error message with extra context.
|
||||
* \param value JSON Value location associated with the error
|
||||
* \param message The error message.
|
||||
* \param extra Additional JSON Value location to contextualize the error
|
||||
* \return \c true if the error was successfully added, \c false if either
|
||||
* Value offset exceeds the document size.
|
||||
*/
|
||||
bool pushError(const Value& value, const std::string& message, const Value& extra);
|
||||
|
||||
/** \brief Return whether there are any errors.
|
||||
* \return \c true if there are no errors to report \c false if
|
||||
* errors have occurred.
|
||||
*/
|
||||
bool good() const;
|
||||
|
||||
private:
|
||||
enum TokenType {
|
||||
tokenEndOfStream = 0,
|
||||
|
@@ -37,21 +37,36 @@ namespace Json {
|
||||
*
|
||||
* We use nothing but these internally. Of course, STL can throw others.
|
||||
*/
|
||||
class JSON_API Exception;
|
||||
class JSON_API Exception : public std::exception {
|
||||
public:
|
||||
Exception(std::string const& msg);
|
||||
virtual ~Exception() throw();
|
||||
virtual char const* what() const throw();
|
||||
protected:
|
||||
std::string const msg_;
|
||||
};
|
||||
|
||||
/** Exceptions which the user cannot easily avoid.
|
||||
*
|
||||
* E.g. out-of-memory (when we use malloc), stack-overflow, malicious input
|
||||
*
|
||||
* \remark derived from Json::Exception
|
||||
*/
|
||||
class JSON_API RuntimeError;
|
||||
class JSON_API RuntimeError : public Exception {
|
||||
public:
|
||||
RuntimeError(std::string const& msg);
|
||||
};
|
||||
|
||||
/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros.
|
||||
*
|
||||
* These are precondition-violations (user bugs) and internal errors (our bugs).
|
||||
*
|
||||
* \remark derived from Json::Exception
|
||||
*/
|
||||
class JSON_API LogicError;
|
||||
class JSON_API LogicError : public Exception {
|
||||
public:
|
||||
LogicError(std::string const& msg);
|
||||
};
|
||||
|
||||
/// used internally
|
||||
void throwRuntimeError(std::string const& msg);
|
||||
@@ -160,11 +175,8 @@ public:
|
||||
typedef Json::LargestUInt LargestUInt;
|
||||
typedef Json::ArrayIndex ArrayIndex;
|
||||
|
||||
static const Value& nullRef;
|
||||
#if !defined(__ARMEL__)
|
||||
/// \deprecated This exists for binary compatibility only. Use nullRef.
|
||||
static const Value null;
|
||||
#endif
|
||||
static const Value& null; ///< We regret this reference to a global instance; prefer the simpler Value().
|
||||
static const Value& nullRef; ///< just a kludge for binary-compatibility; same as null
|
||||
/// Minimum signed integer value that can be stored in a Json::Value.
|
||||
static const LargestInt minLargestInt;
|
||||
/// Maximum signed integer value that can be stored in a Json::Value.
|
||||
@@ -258,7 +270,7 @@ Json::Value obj_value(Json::objectValue); // {}
|
||||
#endif // if defined(JSON_HAS_INT64)
|
||||
Value(double value);
|
||||
Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.)
|
||||
Value(const char* beginValue, const char* endValue); ///< Copy all, incl zeroes.
|
||||
Value(const char* begin, const char* end); ///< Copy all, incl zeroes.
|
||||
/** \brief Constructs a value from a static string.
|
||||
|
||||
* Like other value string constructor but do not duplicate the string for
|
||||
@@ -286,7 +298,7 @@ Json::Value obj_value(Json::objectValue); // {}
|
||||
|
||||
/// Deep copy, then swap(other).
|
||||
/// \note Over-write existing comments. To preserve comments, use #swapPayload().
|
||||
Value &operator=(const Value &other);
|
||||
Value& operator=(Value other);
|
||||
/// Swap everything.
|
||||
void swap(Value& other);
|
||||
/// Swap values but leave comments and source offsets in place.
|
||||
@@ -309,7 +321,7 @@ Json::Value obj_value(Json::objectValue); // {}
|
||||
* \return false if !string. (Seg-fault if str or end are NULL.)
|
||||
*/
|
||||
bool getString(
|
||||
char const** str, char const** end) const;
|
||||
char const** begin, char const** end) const;
|
||||
#ifdef JSON_USE_CPPTL
|
||||
CppTL::ConstString asConstString() const;
|
||||
#endif
|
||||
@@ -438,8 +450,8 @@ Json::Value obj_value(Json::objectValue); // {}
|
||||
Value get(const char* key, const Value& defaultValue) const;
|
||||
/// Return the member named key if it exist, defaultValue otherwise.
|
||||
/// \note deep copy
|
||||
/// \param key may contain embedded nulls.
|
||||
Value get(const char* key, const char* end, const Value& defaultValue) const;
|
||||
/// \note key may contain embedded nulls.
|
||||
Value get(const char* begin, const char* end, const Value& defaultValue) const;
|
||||
/// Return the member named key if it exist, defaultValue otherwise.
|
||||
/// \note deep copy
|
||||
/// \param key may contain embedded nulls.
|
||||
@@ -451,12 +463,12 @@ Json::Value obj_value(Json::objectValue); // {}
|
||||
#endif
|
||||
/// Most general and efficient version of isMember()const, get()const,
|
||||
/// and operator[]const
|
||||
/// \note As stated elsewhere, behavior is undefined if (end-key) >= 2^30
|
||||
Value const* find(char const* key, char const* end) const;
|
||||
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
|
||||
Value const* find(char const* begin, char const* end) const;
|
||||
/// Most general and efficient version of object-mutators.
|
||||
/// \note As stated elsewhere, behavior is undefined if (end-key) >= 2^30
|
||||
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
|
||||
/// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
|
||||
Value const* demand(char const* key, char const* end);
|
||||
Value const* demand(char const* begin, char const* end);
|
||||
/// \brief Remove and return the named member.
|
||||
///
|
||||
/// Do nothing if it did not exist.
|
||||
@@ -469,7 +481,7 @@ Json::Value obj_value(Json::objectValue); // {}
|
||||
/// \param key may contain embedded nulls.
|
||||
/// \deprecated
|
||||
Value removeMember(const std::string& key);
|
||||
/// Same as removeMember(const char* key, const char* end, Value* removed),
|
||||
/// Same as removeMember(const char* begin, const char* end, Value* removed),
|
||||
/// but 'key' is null-terminated.
|
||||
bool removeMember(const char* key, Value* removed);
|
||||
/** \brief Remove the named map member.
|
||||
@@ -480,7 +492,7 @@ Json::Value obj_value(Json::objectValue); // {}
|
||||
*/
|
||||
bool removeMember(std::string const& key, Value* removed);
|
||||
/// Same as removeMember(std::string const& key, Value* removed)
|
||||
bool removeMember(const char* key, const char* end, Value* removed);
|
||||
bool removeMember(const char* begin, const char* end, Value* removed);
|
||||
/** \brief Remove the indexed array element.
|
||||
|
||||
O(n) expensive operations.
|
||||
@@ -496,7 +508,7 @@ Json::Value obj_value(Json::objectValue); // {}
|
||||
/// \param key may contain embedded nulls.
|
||||
bool isMember(const std::string& key) const;
|
||||
/// Same as isMember(std::string const& key)const
|
||||
bool isMember(const char* key, const char* end) const;
|
||||
bool isMember(const char* begin, const char* end) const;
|
||||
#ifdef JSON_USE_CPPTL
|
||||
/// Return true if the object has a member named key.
|
||||
bool isMember(const CppTL::ConstString& key) const;
|
||||
@@ -533,6 +545,13 @@ Json::Value obj_value(Json::objectValue); // {}
|
||||
iterator begin();
|
||||
iterator end();
|
||||
|
||||
// Accessors for the [start, limit) range of bytes within the JSON text from
|
||||
// which this value was parsed, if any.
|
||||
void setOffsetStart(size_t start);
|
||||
void setOffsetLimit(size_t limit);
|
||||
size_t getOffsetStart() const;
|
||||
size_t getOffsetLimit() const;
|
||||
|
||||
private:
|
||||
void initBasic(ValueType type, bool allocated = false);
|
||||
|
||||
@@ -569,6 +588,11 @@ private:
|
||||
unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
|
||||
// If not allocated_, string_ must be null-terminated.
|
||||
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
|
||||
|
@@ -1,13 +1,12 @@
|
||||
// DO NOT EDIT. This file is generated by CMake from "version"
|
||||
// and "version.h.in" files.
|
||||
// DO NOT EDIT. This file (and "version") is generated by CMake.
|
||||
// Run CMake configure step to update it.
|
||||
#ifndef JSON_VERSION_H_INCLUDED
|
||||
# define JSON_VERSION_H_INCLUDED
|
||||
|
||||
# define JSONCPP_VERSION_STRING "0.10.2"
|
||||
# define JSONCPP_VERSION_MAJOR 0
|
||||
# define JSONCPP_VERSION_MINOR 10
|
||||
# define JSONCPP_VERSION_PATCH 2
|
||||
# define JSONCPP_VERSION_STRING "1.6.5"
|
||||
# define JSONCPP_VERSION_MAJOR 1
|
||||
# define JSONCPP_VERSION_MINOR 6
|
||||
# define JSONCPP_VERSION_PATCH 5
|
||||
# define JSONCPP_VERSION_QUALIFIER
|
||||
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
|
||||
|
||||
|
@@ -158,6 +158,15 @@ public:
|
||||
|
||||
void enableYAMLCompatibility();
|
||||
|
||||
/** \brief Drop the "null" string from the writer's output for nullValues.
|
||||
* Strictly speaking, this is not valid JSON. But when the output is being
|
||||
* fed to a browser's Javascript, it makes for smaller output and the
|
||||
* browser can handle the output just fine.
|
||||
*/
|
||||
void dropNullPlaceholders();
|
||||
|
||||
void omitEndingLineFeed();
|
||||
|
||||
public: // overridden from Writer
|
||||
virtual std::string write(const Value& root);
|
||||
|
||||
@@ -166,6 +175,8 @@ private:
|
||||
|
||||
std::string document_;
|
||||
bool yamlCompatiblityEnabled_;
|
||||
bool dropNullPlaceholders_;
|
||||
bool omitEndingLineFeed_;
|
||||
};
|
||||
|
||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
|
||||
|
@@ -1,7 +1,7 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${exec_prefix}/@LIBRARY_INSTALL_DIR@
|
||||
includedir=${prefix}/@INCLUDE_INSTALL_DIR@
|
||||
libdir=@LIBRARY_INSTALL_DIR@
|
||||
includedir=@INCLUDE_INSTALL_DIR@
|
||||
|
||||
Name: jsoncpp
|
||||
Description: A C++ library for interacting with JSON
|
||||
|
@@ -2,7 +2,7 @@ if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
#Get compiler version.
|
||||
execute_process( COMMAND ${CMAKE_CXX_COMPILER} -dumpversion
|
||||
OUTPUT_VARIABLE GNUCXX_VERSION )
|
||||
|
||||
|
||||
#-Werror=* was introduced -after- GCC 4.1.2
|
||||
if( GNUCXX_VERSION VERSION_GREATER 4.1.2 )
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=strict-aliasing")
|
||||
@@ -43,7 +43,8 @@ IF(BUILD_SHARED_LIBS)
|
||||
ADD_DEFINITIONS( -DJSON_DLL_BUILD )
|
||||
ADD_LIBRARY(jsoncpp_lib SHARED ${PUBLIC_HEADERS} ${jsoncpp_sources})
|
||||
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_VERSION_MAJOR})
|
||||
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES OUTPUT_NAME jsoncpp )
|
||||
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES OUTPUT_NAME jsoncpp
|
||||
DEBUG_OUTPUT_NAME jsoncpp${DEBUG_LIBNAME_SUFFIX} )
|
||||
|
||||
INSTALL( TARGETS jsoncpp_lib ${INSTALL_EXPORT}
|
||||
RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR}
|
||||
@@ -61,7 +62,8 @@ ENDIF()
|
||||
IF(BUILD_STATIC_LIBS)
|
||||
ADD_LIBRARY(jsoncpp_lib_static STATIC ${PUBLIC_HEADERS} ${jsoncpp_sources})
|
||||
SET_TARGET_PROPERTIES( jsoncpp_lib_static PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_VERSION_MAJOR})
|
||||
SET_TARGET_PROPERTIES( jsoncpp_lib_static PROPERTIES OUTPUT_NAME jsoncpp )
|
||||
SET_TARGET_PROPERTIES( jsoncpp_lib_static PROPERTIES OUTPUT_NAME jsoncpp
|
||||
DEBUG_OUTPUT_NAME jsoncpp${DEBUG_LIBNAME_SUFFIX} )
|
||||
|
||||
INSTALL( TARGETS jsoncpp_lib_static ${INSTALL_EXPORT}
|
||||
RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR}
|
||||
|
@@ -32,20 +32,27 @@ static int stackDepth_g = 0; // see readValue()
|
||||
|
||||
namespace Json {
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
typedef std::unique_ptr<CharReader> CharReaderPtr;
|
||||
#else
|
||||
typedef std::auto_ptr<CharReader> CharReaderPtr;
|
||||
#endif
|
||||
|
||||
// Implementation of class Features
|
||||
// ////////////////////////////////
|
||||
|
||||
Features::Features()
|
||||
: allowComments_(true), strictRoot_(false)
|
||||
{}
|
||||
: allowComments_(true), strictRoot_(false),
|
||||
allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
|
||||
|
||||
Features Features::all() { return Features(); }
|
||||
|
||||
Features Features::strictMode() {
|
||||
Features features;
|
||||
features.allowComments_ = false;
|
||||
features.strictRoot_ = true;
|
||||
features.allowDroppedNullPlaceholders_ = false;
|
||||
features.allowNumericKeys_ = false;
|
||||
return features;
|
||||
}
|
||||
|
||||
@@ -155,9 +162,11 @@ bool Reader::readValue() {
|
||||
switch (token.type_) {
|
||||
case tokenObjectBegin:
|
||||
successful = readObject(token);
|
||||
currentValue().setOffsetLimit(current_ - begin_);
|
||||
break;
|
||||
case tokenArrayBegin:
|
||||
successful = readArray(token);
|
||||
currentValue().setOffsetLimit(current_ - begin_);
|
||||
break;
|
||||
case tokenNumber:
|
||||
successful = decodeNumber(token);
|
||||
@@ -169,22 +178,42 @@ bool Reader::readValue() {
|
||||
{
|
||||
Value v(true);
|
||||
currentValue().swapPayload(v);
|
||||
currentValue().setOffsetStart(token.start_ - begin_);
|
||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||
}
|
||||
break;
|
||||
case tokenFalse:
|
||||
{
|
||||
Value v(false);
|
||||
currentValue().swapPayload(v);
|
||||
currentValue().setOffsetStart(token.start_ - begin_);
|
||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||
}
|
||||
break;
|
||||
case tokenNull:
|
||||
{
|
||||
Value v;
|
||||
currentValue().swapPayload(v);
|
||||
currentValue().setOffsetStart(token.start_ - begin_);
|
||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||
}
|
||||
break;
|
||||
// Else, fall through...
|
||||
case tokenArraySeparator:
|
||||
case tokenObjectEnd:
|
||||
case tokenArrayEnd:
|
||||
if (features_.allowDroppedNullPlaceholders_) {
|
||||
// "Un-read" the current token and mark the current value as a null
|
||||
// token.
|
||||
current_--;
|
||||
Value v;
|
||||
currentValue().swapPayload(v);
|
||||
currentValue().setOffsetStart(current_ - begin_ - 1);
|
||||
currentValue().setOffsetLimit(current_ - begin_);
|
||||
break;
|
||||
} // Else, fall through...
|
||||
default:
|
||||
currentValue().setOffsetStart(token.start_ - begin_);
|
||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||
return addError("Syntax error: value, object or array expected.", token);
|
||||
}
|
||||
|
||||
@@ -412,11 +441,12 @@ bool Reader::readString() {
|
||||
return c == '"';
|
||||
}
|
||||
|
||||
bool Reader::readObject(Token& /*tokenStart*/) {
|
||||
bool Reader::readObject(Token& tokenStart) {
|
||||
Token tokenName;
|
||||
std::string name;
|
||||
Value init(objectValue);
|
||||
currentValue().swapPayload(init);
|
||||
currentValue().setOffsetStart(tokenStart.start_ - begin_);
|
||||
while (readToken(tokenName)) {
|
||||
bool initialTokenOk = true;
|
||||
while (tokenName.type_ == tokenComment && initialTokenOk)
|
||||
@@ -429,6 +459,11 @@ bool Reader::readObject(Token& /*tokenStart*/) {
|
||||
if (tokenName.type_ == tokenString) {
|
||||
if (!decodeString(tokenName, name))
|
||||
return recoverFromError(tokenObjectEnd);
|
||||
} else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
|
||||
Value numberName;
|
||||
if (!decodeNumber(tokenName, numberName))
|
||||
return recoverFromError(tokenObjectEnd);
|
||||
name = numberName.asString();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -462,9 +497,10 @@ bool Reader::readObject(Token& /*tokenStart*/) {
|
||||
"Missing '}' or object member name", tokenName, tokenObjectEnd);
|
||||
}
|
||||
|
||||
bool Reader::readArray(Token& /*tokenStart*/) {
|
||||
bool Reader::readArray(Token& tokenStart) {
|
||||
Value init(arrayValue);
|
||||
currentValue().swapPayload(init);
|
||||
currentValue().setOffsetStart(tokenStart.start_ - begin_);
|
||||
skipSpaces();
|
||||
if (*current_ == ']') // empty array
|
||||
{
|
||||
@@ -504,6 +540,8 @@ bool Reader::decodeNumber(Token& token) {
|
||||
if (!decodeNumber(token, decoded))
|
||||
return false;
|
||||
currentValue().swapPayload(decoded);
|
||||
currentValue().setOffsetStart(token.start_ - begin_);
|
||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -552,38 +590,16 @@ bool Reader::decodeDouble(Token& token) {
|
||||
if (!decodeDouble(token, decoded))
|
||||
return false;
|
||||
currentValue().swapPayload(decoded);
|
||||
currentValue().setOffsetStart(token.start_ - begin_);
|
||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Reader::decodeDouble(Token& token, Value& decoded) {
|
||||
double value = 0;
|
||||
const int bufferSize = 32;
|
||||
int count;
|
||||
int length = int(token.end_ - token.start_);
|
||||
|
||||
// Sanity check to avoid buffer overflow exploits.
|
||||
if (length < 0) {
|
||||
return addError("Unable to parse token length", token);
|
||||
}
|
||||
|
||||
// Avoid using a string constant for the format control string given to
|
||||
// sscanf, as this can cause hard to debug crashes on OS X. See here for more
|
||||
// info:
|
||||
//
|
||||
// http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
|
||||
char format[] = "%lf";
|
||||
|
||||
if (length <= bufferSize) {
|
||||
Char buffer[bufferSize + 1];
|
||||
memcpy(buffer, token.start_, length);
|
||||
buffer[length] = 0;
|
||||
count = sscanf(buffer, format, &value);
|
||||
} else {
|
||||
std::string buffer(token.start_, token.end_);
|
||||
count = sscanf(buffer.c_str(), format, &value);
|
||||
}
|
||||
|
||||
if (count != 1)
|
||||
std::string buffer(token.start_, token.end_);
|
||||
std::istringstream is(buffer);
|
||||
if (!(is >> value))
|
||||
return addError("'" + std::string(token.start_, token.end_) +
|
||||
"' is not a number.",
|
||||
token);
|
||||
@@ -597,6 +613,8 @@ bool Reader::decodeString(Token& token) {
|
||||
return false;
|
||||
Value decoded(decoded_string);
|
||||
currentValue().swapPayload(decoded);
|
||||
currentValue().setOffsetStart(token.start_ - begin_);
|
||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -808,8 +826,59 @@ std::string Reader::getFormattedErrorMessages() const {
|
||||
return formattedMessage;
|
||||
}
|
||||
|
||||
// Reader
|
||||
/////////////////////////
|
||||
std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
|
||||
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
|
||||
class OurFeatures {
|
||||
@@ -859,6 +928,10 @@ public:
|
||||
Value& root,
|
||||
bool collectComments = true);
|
||||
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:
|
||||
OurReader(OurReader const&); // no impl
|
||||
@@ -1023,9 +1096,11 @@ bool OurReader::readValue() {
|
||||
switch (token.type_) {
|
||||
case tokenObjectBegin:
|
||||
successful = readObject(token);
|
||||
currentValue().setOffsetLimit(current_ - begin_);
|
||||
break;
|
||||
case tokenArrayBegin:
|
||||
successful = readArray(token);
|
||||
currentValue().setOffsetLimit(current_ - begin_);
|
||||
break;
|
||||
case tokenNumber:
|
||||
successful = decodeNumber(token);
|
||||
@@ -1037,18 +1112,24 @@ bool OurReader::readValue() {
|
||||
{
|
||||
Value v(true);
|
||||
currentValue().swapPayload(v);
|
||||
currentValue().setOffsetStart(token.start_ - begin_);
|
||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||
}
|
||||
break;
|
||||
case tokenFalse:
|
||||
{
|
||||
Value v(false);
|
||||
currentValue().swapPayload(v);
|
||||
currentValue().setOffsetStart(token.start_ - begin_);
|
||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||
}
|
||||
break;
|
||||
case tokenNull:
|
||||
{
|
||||
Value v;
|
||||
currentValue().swapPayload(v);
|
||||
currentValue().setOffsetStart(token.start_ - begin_);
|
||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||
}
|
||||
break;
|
||||
case tokenArraySeparator:
|
||||
@@ -1060,9 +1141,13 @@ bool OurReader::readValue() {
|
||||
current_--;
|
||||
Value v;
|
||||
currentValue().swapPayload(v);
|
||||
currentValue().setOffsetStart(current_ - begin_ - 1);
|
||||
currentValue().setOffsetLimit(current_ - begin_);
|
||||
break;
|
||||
} // else, fall through ...
|
||||
default:
|
||||
currentValue().setOffsetStart(token.start_ - begin_);
|
||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||
return addError("Syntax error: value, object or array expected.", token);
|
||||
}
|
||||
|
||||
@@ -1294,6 +1379,7 @@ bool OurReader::readObject(Token& tokenStart) {
|
||||
std::string name;
|
||||
Value init(objectValue);
|
||||
currentValue().swapPayload(init);
|
||||
currentValue().setOffsetStart(tokenStart.start_ - begin_);
|
||||
while (readToken(tokenName)) {
|
||||
bool initialTokenOk = true;
|
||||
while (tokenName.type_ == tokenComment && initialTokenOk)
|
||||
@@ -1353,6 +1439,7 @@ bool OurReader::readObject(Token& tokenStart) {
|
||||
bool OurReader::readArray(Token& tokenStart) {
|
||||
Value init(arrayValue);
|
||||
currentValue().swapPayload(init);
|
||||
currentValue().setOffsetStart(tokenStart.start_ - begin_);
|
||||
skipSpaces();
|
||||
if (*current_ == ']') // empty array
|
||||
{
|
||||
@@ -1392,6 +1479,8 @@ bool OurReader::decodeNumber(Token& token) {
|
||||
if (!decodeNumber(token, decoded))
|
||||
return false;
|
||||
currentValue().swapPayload(decoded);
|
||||
currentValue().setOffsetStart(token.start_ - begin_);
|
||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1440,6 +1529,8 @@ bool OurReader::decodeDouble(Token& token) {
|
||||
if (!decodeDouble(token, decoded))
|
||||
return false;
|
||||
currentValue().swapPayload(decoded);
|
||||
currentValue().setOffsetStart(token.start_ - begin_);
|
||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1485,6 +1576,8 @@ bool OurReader::decodeString(Token& token) {
|
||||
return false;
|
||||
Value decoded(decoded_string);
|
||||
currentValue().swapPayload(decoded);
|
||||
currentValue().setOffsetStart(token.start_ - begin_);
|
||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1691,6 +1784,60 @@ std::string OurReader::getFormattedErrorMessages() const {
|
||||
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 {
|
||||
bool const collectComments_;
|
||||
|
@@ -30,8 +30,8 @@ static inline std::string codePointToUTF8(unsigned int cp) {
|
||||
} else if (cp <= 0xFFFF) {
|
||||
result.resize(3);
|
||||
result[2] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
|
||||
result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
|
||||
result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
|
||||
result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));
|
||||
} else if (cp <= 0x10FFFF) {
|
||||
result.resize(4);
|
||||
result[3] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
@@ -43,7 +43,7 @@ static inline std::string codePointToUTF8(unsigned int cp) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Returns true if ch is a control character (in range [0,32[).
|
||||
/// Returns true if ch is a control character (in range [1,31]).
|
||||
static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; }
|
||||
|
||||
enum {
|
||||
@@ -63,7 +63,7 @@ typedef char UIntToStringBuffer[uintToStringBufferSize];
|
||||
static inline void uintToString(LargestUInt value, char*& current) {
|
||||
*--current = 0;
|
||||
do {
|
||||
*--current = char(value % 10) + '0';
|
||||
*--current = static_cast<signed char>(value % 10U + static_cast<unsigned>('0'));
|
||||
value /= 10;
|
||||
} while (value != 0);
|
||||
}
|
||||
|
@@ -29,13 +29,12 @@ namespace Json {
|
||||
#if defined(__ARMEL__)
|
||||
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
|
||||
#else
|
||||
// This exists for binary compatibility only. Use nullRef.
|
||||
const Value Value::null;
|
||||
#define ALIGNAS(byte_alignment)
|
||||
#endif
|
||||
static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
|
||||
const unsigned char& kNullRef = kNull[0];
|
||||
const Value& Value::nullRef = reinterpret_cast<const Value&>(kNullRef);
|
||||
const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
|
||||
const Value& Value::nullRef = null;
|
||||
|
||||
const Int Value::minInt = Int(~(UInt(-1) / 2));
|
||||
const Int Value::maxInt = Int(UInt(-1) / 2);
|
||||
@@ -109,7 +108,7 @@ static inline char* duplicateAndPrefixStringValue(
|
||||
JSON_ASSERT_MESSAGE(length <= (unsigned)Value::maxInt - sizeof(unsigned) - 1U,
|
||||
"in Json::Value::duplicateAndPrefixStringValue(): "
|
||||
"length too big for prefixing");
|
||||
unsigned actualLength = length + sizeof(unsigned) + 1U;
|
||||
unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U;
|
||||
char* newString = static_cast<char*>(malloc(actualLength));
|
||||
if (newString == 0) {
|
||||
throwRuntimeError(
|
||||
@@ -126,7 +125,7 @@ inline static void decodePrefixedString(
|
||||
unsigned* length, char const** value)
|
||||
{
|
||||
if (!isPrefixed) {
|
||||
*length = strlen(prefixed);
|
||||
*length = static_cast<unsigned>(strlen(prefixed));
|
||||
*value = prefixed;
|
||||
} else {
|
||||
*length = *reinterpret_cast<unsigned const*>(prefixed);
|
||||
@@ -153,23 +152,6 @@ static inline void releaseStringValue(char* value) { free(value); }
|
||||
|
||||
namespace Json {
|
||||
|
||||
class JSON_API Exception : public std::exception {
|
||||
public:
|
||||
Exception(std::string const& msg);
|
||||
virtual ~Exception() throw();
|
||||
virtual char const* what() const throw();
|
||||
protected:
|
||||
std::string const msg_;
|
||||
};
|
||||
class JSON_API RuntimeError : public Exception {
|
||||
public:
|
||||
RuntimeError(std::string const& msg);
|
||||
};
|
||||
class JSON_API LogicError : public Exception {
|
||||
public:
|
||||
LogicError(std::string const& msg);
|
||||
};
|
||||
|
||||
Exception::Exception(std::string const& msg)
|
||||
: msg_(msg)
|
||||
{}
|
||||
@@ -233,14 +215,14 @@ void Value::CommentInfo::setComment(const char* text, size_t len) {
|
||||
// Notes: policy_ indicates if the string was allocated when
|
||||
// a string is stored.
|
||||
|
||||
Value::CZString::CZString(ArrayIndex index) : cstr_(0), index_(index) {}
|
||||
Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {}
|
||||
|
||||
Value::CZString::CZString(char const* str, unsigned length, DuplicationPolicy allocate)
|
||||
Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate)
|
||||
: cstr_(str)
|
||||
{
|
||||
// allocate != duplicate
|
||||
storage_.policy_ = allocate;
|
||||
storage_.length_ = length;
|
||||
storage_.policy_ = allocate & 0x3;
|
||||
storage_.length_ = ulength & 0x3FFFFFFF;
|
||||
}
|
||||
|
||||
Value::CZString::CZString(const CZString& other)
|
||||
@@ -249,9 +231,9 @@ Value::CZString::CZString(const CZString& other)
|
||||
: other.cstr_)
|
||||
{
|
||||
storage_.policy_ = (other.cstr_
|
||||
? (other.storage_.policy_ == noDuplication
|
||||
? (static_cast<DuplicationPolicy>(other.storage_.policy_) == noDuplication
|
||||
? noDuplication : duplicate)
|
||||
: other.storage_.policy_);
|
||||
: static_cast<DuplicationPolicy>(other.storage_.policy_));
|
||||
storage_.length_ = other.storage_.length_;
|
||||
}
|
||||
|
||||
@@ -313,9 +295,9 @@ bool Value::CZString::isStaticString() const { return storage_.policy_ == noDupl
|
||||
* memset( this, 0, sizeof(Value) )
|
||||
* This optimization is used in ValueInternalMap fast allocator.
|
||||
*/
|
||||
Value::Value(ValueType type) {
|
||||
initBasic(type);
|
||||
switch (type) {
|
||||
Value::Value(ValueType vtype) {
|
||||
initBasic(vtype);
|
||||
switch (vtype) {
|
||||
case nullValue:
|
||||
break;
|
||||
case intValue:
|
||||
@@ -402,7 +384,7 @@ Value::Value(bool value) {
|
||||
Value::Value(Value const& other)
|
||||
: type_(other.type_), allocated_(false)
|
||||
,
|
||||
comments_(0)
|
||||
comments_(0), start_(other.start_), limit_(other.limit_)
|
||||
{
|
||||
switch (type_) {
|
||||
case nullValue:
|
||||
@@ -467,9 +449,8 @@ Value::~Value() {
|
||||
delete[] comments_;
|
||||
}
|
||||
|
||||
Value &Value::operator=(const Value &other) {
|
||||
Value temp(other);
|
||||
swap(temp);
|
||||
Value& Value::operator=(Value other) {
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -480,12 +461,14 @@ void Value::swapPayload(Value& other) {
|
||||
std::swap(value_, other.value_);
|
||||
int temp2 = allocated_;
|
||||
allocated_ = other.allocated_;
|
||||
other.allocated_ = temp2;
|
||||
other.allocated_ = temp2 & 0x1;
|
||||
}
|
||||
|
||||
void Value::swap(Value& other) {
|
||||
swapPayload(other);
|
||||
std::swap(comments_, other.comments_);
|
||||
std::swap(start_, other.start_);
|
||||
std::swap(limit_, other.limit_);
|
||||
}
|
||||
|
||||
ValueType Value::type() const { return type_; }
|
||||
@@ -606,12 +589,12 @@ const char* Value::asCString() const {
|
||||
return this_str;
|
||||
}
|
||||
|
||||
bool Value::getString(char const** str, char const** end) const {
|
||||
bool Value::getString(char const** str, char const** cend) const {
|
||||
if (type_ != stringValue) return false;
|
||||
if (value_.string_ == 0) return false;
|
||||
unsigned length;
|
||||
decodePrefixedString(this->allocated_, this->value_.string_, &length, str);
|
||||
*end = *str + length;
|
||||
*cend = *str + length;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -810,7 +793,8 @@ bool Value::asBool() const {
|
||||
case uintValue:
|
||||
return value_.uint_ ? true : false;
|
||||
case realValue:
|
||||
return value_.real_ ? true : false;
|
||||
// This is kind of strange. Not recommended.
|
||||
return (value_.real_ != 0.0) ? true : false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -887,6 +871,8 @@ void Value::clear() {
|
||||
JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue ||
|
||||
type_ == objectValue,
|
||||
"in Json::Value::clear(): requires complex value");
|
||||
start_ = 0;
|
||||
limit_ = 0;
|
||||
switch (type_) {
|
||||
case arrayValue:
|
||||
case objectValue:
|
||||
@@ -958,10 +944,12 @@ const Value& Value::operator[](int index) const {
|
||||
return (*this)[ArrayIndex(index)];
|
||||
}
|
||||
|
||||
void Value::initBasic(ValueType type, bool allocated) {
|
||||
type_ = type;
|
||||
void Value::initBasic(ValueType vtype, bool allocated) {
|
||||
type_ = vtype;
|
||||
allocated_ = allocated;
|
||||
comments_ = 0;
|
||||
start_ = 0;
|
||||
limit_ = 0;
|
||||
}
|
||||
|
||||
// Access an object value by name, create a null member if it does not exist.
|
||||
@@ -986,7 +974,7 @@ Value& Value::resolveReference(const char* key) {
|
||||
}
|
||||
|
||||
// @param key is not null-terminated.
|
||||
Value& Value::resolveReference(char const* key, char const* end)
|
||||
Value& Value::resolveReference(char const* key, char const* cend)
|
||||
{
|
||||
JSON_ASSERT_MESSAGE(
|
||||
type_ == nullValue || type_ == objectValue,
|
||||
@@ -994,7 +982,7 @@ Value& Value::resolveReference(char const* key, char const* end)
|
||||
if (type_ == nullValue)
|
||||
*this = Value(objectValue);
|
||||
CZString actualKey(
|
||||
key, static_cast<unsigned>(end-key), CZString::duplicateOnCopy);
|
||||
key, static_cast<unsigned>(cend-key), CZString::duplicateOnCopy);
|
||||
ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
|
||||
if (it != value_.map_->end() && (*it).first == actualKey)
|
||||
return (*it).second;
|
||||
@@ -1012,13 +1000,13 @@ Value Value::get(ArrayIndex index, const Value& defaultValue) const {
|
||||
|
||||
bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
|
||||
|
||||
Value const* Value::find(char const* key, char const* end) const
|
||||
Value const* Value::find(char const* key, char const* cend) const
|
||||
{
|
||||
JSON_ASSERT_MESSAGE(
|
||||
type_ == nullValue || type_ == objectValue,
|
||||
"in Json::Value::find(key, end, found): requires objectValue or nullValue");
|
||||
if (type_ == nullValue) return NULL;
|
||||
CZString actualKey(key, static_cast<unsigned>(end-key), CZString::noDuplication);
|
||||
CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
|
||||
ObjectValues::const_iterator it = value_.map_->find(actualKey);
|
||||
if (it == value_.map_->end()) return NULL;
|
||||
return &(*it).second;
|
||||
@@ -1062,9 +1050,9 @@ Value const& Value::operator[](CppTL::ConstString const& key) const
|
||||
|
||||
Value& Value::append(const Value& value) { return (*this)[size()] = value; }
|
||||
|
||||
Value Value::get(char const* key, char const* end, Value const& defaultValue) const
|
||||
Value Value::get(char const* key, char const* cend, Value const& defaultValue) const
|
||||
{
|
||||
Value const* found = find(key, end);
|
||||
Value const* found = find(key, cend);
|
||||
return !found ? defaultValue : *found;
|
||||
}
|
||||
Value Value::get(char const* key, Value const& defaultValue) const
|
||||
@@ -1077,12 +1065,12 @@ Value Value::get(std::string const& key, Value const& defaultValue) const
|
||||
}
|
||||
|
||||
|
||||
bool Value::removeMember(const char* key, const char* end, Value* removed)
|
||||
bool Value::removeMember(const char* key, const char* cend, Value* removed)
|
||||
{
|
||||
if (type_ != objectValue) {
|
||||
return false;
|
||||
}
|
||||
CZString actualKey(key, static_cast<unsigned>(end-key), CZString::noDuplication);
|
||||
CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
|
||||
ObjectValues::iterator it = value_.map_->find(actualKey);
|
||||
if (it == value_.map_->end())
|
||||
return false;
|
||||
@@ -1127,8 +1115,8 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) {
|
||||
ArrayIndex oldSize = size();
|
||||
// shift left all items left, into the place of the "removed"
|
||||
for (ArrayIndex i = index; i < (oldSize - 1); ++i){
|
||||
CZString key(i);
|
||||
(*value_.map_)[key] = (*this)[i + 1];
|
||||
CZString keey(i);
|
||||
(*value_.map_)[keey] = (*this)[i + 1];
|
||||
}
|
||||
// erase the last one ("leftover")
|
||||
CZString keyLast(oldSize - 1);
|
||||
@@ -1144,9 +1132,9 @@ Value Value::get(const CppTL::ConstString& key,
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Value::isMember(char const* key, char const* end) const
|
||||
bool Value::isMember(char const* key, char const* cend) const
|
||||
{
|
||||
Value const* value = find(key, end);
|
||||
Value const* value = find(key, cend);
|
||||
return NULL != value;
|
||||
}
|
||||
bool Value::isMember(char const* key) const
|
||||
@@ -1331,6 +1319,14 @@ std::string Value::getComment(CommentPlacement placement) const {
|
||||
return "";
|
||||
}
|
||||
|
||||
void Value::setOffsetStart(size_t start) { start_ = start; }
|
||||
|
||||
void Value::setOffsetLimit(size_t limit) { limit_ = limit; }
|
||||
|
||||
size_t Value::getOffsetStart() const { return start_; }
|
||||
|
||||
size_t Value::getOffsetLimit() const { return limit_; }
|
||||
|
||||
std::string Value::toStyledString() const {
|
||||
StyledWriter writer;
|
||||
return writer.write(*this);
|
||||
|
@@ -93,26 +93,26 @@ UInt ValueIteratorBase::index() const {
|
||||
}
|
||||
|
||||
std::string ValueIteratorBase::name() const {
|
||||
char const* key;
|
||||
char const* keey;
|
||||
char const* end;
|
||||
key = memberName(&end);
|
||||
if (!key) return std::string();
|
||||
return std::string(key, end);
|
||||
keey = memberName(&end);
|
||||
if (!keey) return std::string();
|
||||
return std::string(keey, end);
|
||||
}
|
||||
|
||||
char const* ValueIteratorBase::memberName() const {
|
||||
const char* name = (*current_).first.data();
|
||||
return name ? name : "";
|
||||
const char* cname = (*current_).first.data();
|
||||
return cname ? cname : "";
|
||||
}
|
||||
|
||||
char const* ValueIteratorBase::memberName(char const** end) const {
|
||||
const char* name = (*current_).first.data();
|
||||
if (!name) {
|
||||
const char* cname = (*current_).first.data();
|
||||
if (!cname) {
|
||||
*end = NULL;
|
||||
return NULL;
|
||||
}
|
||||
*end = name + (*current_).first.length();
|
||||
return name;
|
||||
*end = cname + (*current_).first.length();
|
||||
return cname;
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
@@ -29,6 +29,8 @@
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
|
||||
#define snprintf _snprintf
|
||||
#elif defined(__ANDROID__)
|
||||
#define snprintf snprintf
|
||||
#elif __cplusplus >= 201103L
|
||||
#define snprintf std::snprintf
|
||||
#endif
|
||||
@@ -46,7 +48,11 @@
|
||||
|
||||
namespace Json {
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
|
||||
#else
|
||||
typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
|
||||
#endif
|
||||
|
||||
static bool containsControlCharacter(const char* str) {
|
||||
while (*str) {
|
||||
@@ -286,21 +292,28 @@ Writer::~Writer() {}
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
FastWriter::FastWriter()
|
||||
: yamlCompatiblityEnabled_(false) {}
|
||||
: yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false),
|
||||
omitEndingLineFeed_(false) {}
|
||||
|
||||
void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
|
||||
|
||||
void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
|
||||
|
||||
void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
|
||||
|
||||
std::string FastWriter::write(const Value& root) {
|
||||
document_ = "";
|
||||
writeValue(root);
|
||||
document_ += "\n";
|
||||
if (!omitEndingLineFeed_)
|
||||
document_ += "\n";
|
||||
return document_;
|
||||
}
|
||||
|
||||
void FastWriter::writeValue(const Value& value) {
|
||||
switch (value.type()) {
|
||||
case nullValue:
|
||||
document_ += "null";
|
||||
if (!dropNullPlaceholders_)
|
||||
document_ += "null";
|
||||
break;
|
||||
case intValue:
|
||||
document_ += valueToString(value.asLargestInt());
|
||||
@@ -341,7 +354,7 @@ void FastWriter::writeValue(const Value& value) {
|
||||
const std::string& name = *it;
|
||||
if (it != members.begin())
|
||||
document_ += ',';
|
||||
document_ += valueToQuotedStringN(name.data(), name.length());
|
||||
document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()));
|
||||
document_ += yamlCompatiblityEnabled_ ? ": " : ":";
|
||||
writeValue(value[name]);
|
||||
}
|
||||
@@ -901,7 +914,7 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
||||
std::string const& name = *it;
|
||||
Value const& childValue = value[name];
|
||||
writeCommentBeforeValue(childValue);
|
||||
writeWithIndent(valueToQuotedStringN(name.data(), name.length()));
|
||||
writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())));
|
||||
*sout_ << colonSymbol_;
|
||||
writeValue(childValue);
|
||||
if (++it == members.end()) {
|
||||
|
@@ -1,5 +1,4 @@
|
||||
// DO NOT EDIT. This file is generated by CMake from "version"
|
||||
// and "version.h.in" files.
|
||||
// DO NOT EDIT. This file (and "version") is generated by CMake.
|
||||
// Run CMake configure step to update it.
|
||||
#ifndef JSON_VERSION_H_INCLUDED
|
||||
# define JSON_VERSION_H_INCLUDED
|
||||
|
@@ -296,10 +296,7 @@ JSONTEST_FIXTURE(ValueTest, null) {
|
||||
JSONTEST_ASSERT_EQUAL(0.0, null_.asFloat());
|
||||
JSONTEST_ASSERT_STRING_EQUAL("", null_.asString());
|
||||
|
||||
#if !defined(__ARMEL__)
|
||||
// See line #165 of include/json/value.h
|
||||
JSONTEST_ASSERT_EQUAL(Json::Value::null, null_);
|
||||
#endif
|
||||
}
|
||||
|
||||
JSONTEST_FIXTURE(ValueTest, strings) {
|
||||
@@ -1515,6 +1512,25 @@ JSONTEST_FIXTURE(ValueTest, typeChecksThrowExceptions) {
|
||||
#endif
|
||||
}
|
||||
|
||||
JSONTEST_FIXTURE(ValueTest, offsetAccessors) {
|
||||
Json::Value x;
|
||||
JSONTEST_ASSERT(x.getOffsetStart() == 0);
|
||||
JSONTEST_ASSERT(x.getOffsetLimit() == 0);
|
||||
x.setOffsetStart(10);
|
||||
x.setOffsetLimit(20);
|
||||
JSONTEST_ASSERT(x.getOffsetStart() == 10);
|
||||
JSONTEST_ASSERT(x.getOffsetLimit() == 20);
|
||||
Json::Value y(x);
|
||||
JSONTEST_ASSERT(y.getOffsetStart() == 10);
|
||||
JSONTEST_ASSERT(y.getOffsetLimit() == 20);
|
||||
Json::Value z;
|
||||
z.swap(y);
|
||||
JSONTEST_ASSERT(z.getOffsetStart() == 10);
|
||||
JSONTEST_ASSERT(z.getOffsetLimit() == 20);
|
||||
JSONTEST_ASSERT(y.getOffsetStart() == 0);
|
||||
JSONTEST_ASSERT(y.getOffsetLimit() == 0);
|
||||
}
|
||||
|
||||
JSONTEST_FIXTURE(ValueTest, StaticString) {
|
||||
char mutant[] = "hello";
|
||||
Json::StaticString ss(mutant);
|
||||
@@ -1635,6 +1651,17 @@ JSONTEST_FIXTURE(ValueTest, zeroesInKeys) {
|
||||
}
|
||||
}
|
||||
|
||||
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 {};
|
||||
|
||||
JSONTEST_FIXTURE(StreamWriterTest, dropNullPlaceholders) {
|
||||
@@ -1676,6 +1703,7 @@ JSONTEST_FIXTURE(ReaderTest, parseWithNoErrors) {
|
||||
bool ok = reader.parse("{ \"property\" : \"value\" }", root);
|
||||
JSONTEST_ASSERT(ok);
|
||||
JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0);
|
||||
JSONTEST_ASSERT(reader.getStructuredErrors().size() == 0);
|
||||
}
|
||||
|
||||
JSONTEST_FIXTURE(ReaderTest, parseWithNoErrorsTestingOffsets) {
|
||||
@@ -1687,6 +1715,25 @@ JSONTEST_FIXTURE(ReaderTest, parseWithNoErrorsTestingOffsets) {
|
||||
root);
|
||||
JSONTEST_ASSERT(ok);
|
||||
JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0);
|
||||
JSONTEST_ASSERT(reader.getStructuredErrors().size() == 0);
|
||||
JSONTEST_ASSERT(root["property"].getOffsetStart() == 15);
|
||||
JSONTEST_ASSERT(root["property"].getOffsetLimit() == 34);
|
||||
JSONTEST_ASSERT(root["property"][0].getOffsetStart() == 16);
|
||||
JSONTEST_ASSERT(root["property"][0].getOffsetLimit() == 23);
|
||||
JSONTEST_ASSERT(root["property"][1].getOffsetStart() == 25);
|
||||
JSONTEST_ASSERT(root["property"][1].getOffsetLimit() == 33);
|
||||
JSONTEST_ASSERT(root["obj"].getOffsetStart() == 44);
|
||||
JSONTEST_ASSERT(root["obj"].getOffsetLimit() == 76);
|
||||
JSONTEST_ASSERT(root["obj"]["nested"].getOffsetStart() == 57);
|
||||
JSONTEST_ASSERT(root["obj"]["nested"].getOffsetLimit() == 60);
|
||||
JSONTEST_ASSERT(root["obj"]["bool"].getOffsetStart() == 71);
|
||||
JSONTEST_ASSERT(root["obj"]["bool"].getOffsetLimit() == 75);
|
||||
JSONTEST_ASSERT(root["null"].getOffsetStart() == 87);
|
||||
JSONTEST_ASSERT(root["null"].getOffsetLimit() == 91);
|
||||
JSONTEST_ASSERT(root["false"].getOffsetStart() == 103);
|
||||
JSONTEST_ASSERT(root["false"].getOffsetLimit() == 108);
|
||||
JSONTEST_ASSERT(root.getOffsetStart() == 0);
|
||||
JSONTEST_ASSERT(root.getOffsetLimit() == 110);
|
||||
}
|
||||
|
||||
JSONTEST_FIXTURE(ReaderTest, parseWithOneError) {
|
||||
@@ -1697,6 +1744,13 @@ JSONTEST_FIXTURE(ReaderTest, parseWithOneError) {
|
||||
JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
|
||||
"* Line 1, Column 15\n Syntax error: value, object or array "
|
||||
"expected.\n");
|
||||
std::vector<Json::Reader::StructuredError> errors =
|
||||
reader.getStructuredErrors();
|
||||
JSONTEST_ASSERT(errors.size() == 1);
|
||||
JSONTEST_ASSERT(errors.at(0).offset_start == 14);
|
||||
JSONTEST_ASSERT(errors.at(0).offset_limit == 15);
|
||||
JSONTEST_ASSERT(errors.at(0).message ==
|
||||
"Syntax error: value, object or array expected.");
|
||||
}
|
||||
|
||||
JSONTEST_FIXTURE(ReaderTest, parseChineseWithOneError) {
|
||||
@@ -1707,6 +1761,13 @@ JSONTEST_FIXTURE(ReaderTest, parseChineseWithOneError) {
|
||||
JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
|
||||
"* Line 1, Column 19\n Syntax error: value, object or array "
|
||||
"expected.\n");
|
||||
std::vector<Json::Reader::StructuredError> errors =
|
||||
reader.getStructuredErrors();
|
||||
JSONTEST_ASSERT(errors.size() == 1);
|
||||
JSONTEST_ASSERT(errors.at(0).offset_start == 18);
|
||||
JSONTEST_ASSERT(errors.at(0).offset_limit == 19);
|
||||
JSONTEST_ASSERT(errors.at(0).message ==
|
||||
"Syntax error: value, object or array expected.");
|
||||
}
|
||||
|
||||
JSONTEST_FIXTURE(ReaderTest, parseWithDetailError) {
|
||||
@@ -1717,6 +1778,12 @@ JSONTEST_FIXTURE(ReaderTest, parseWithDetailError) {
|
||||
JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
|
||||
"* Line 1, Column 16\n Bad escape sequence in string\nSee "
|
||||
"Line 1, Column 20 for detail.\n");
|
||||
std::vector<Json::Reader::StructuredError> errors =
|
||||
reader.getStructuredErrors();
|
||||
JSONTEST_ASSERT(errors.size() == 1);
|
||||
JSONTEST_ASSERT(errors.at(0).offset_start == 15);
|
||||
JSONTEST_ASSERT(errors.at(0).offset_limit == 23);
|
||||
JSONTEST_ASSERT(errors.at(0).message == "Bad escape sequence in string");
|
||||
}
|
||||
|
||||
struct CharReaderTest : JsonTest::TestCase {};
|
||||
@@ -2288,6 +2355,7 @@ int main(int argc, const char* argv[]) {
|
||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareArray);
|
||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareObject);
|
||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareType);
|
||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, offsetAccessors);
|
||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, typeChecksThrowExceptions);
|
||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, StaticString);
|
||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, CommentBefore);
|
||||
@@ -2295,6 +2363,7 @@ int main(int argc, const char* argv[]) {
|
||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroes);
|
||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroesInKeys);
|
||||
|
||||
JSONTEST_REGISTER_FIXTURE(runner, WriterTest, dropNullPlaceholders);
|
||||
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders);
|
||||
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, writeZeroes);
|
||||
|
||||
|
Reference in New Issue
Block a user