mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2025-10-15 23:20:05 +02:00
Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
cbe7e7c9cb | ||
![]() |
be183def8f | ||
![]() |
951bd3d05d | ||
![]() |
1c58876185 | ||
![]() |
2f2034629e | ||
![]() |
7020451b44 | ||
![]() |
80497f102e | ||
![]() |
f9feb66be2 | ||
![]() |
ed495edcc1 | ||
![]() |
3c0a383877 | ||
![]() |
5003983029 | ||
![]() |
871b311e7e | ||
![]() |
cdbc35f6ac | ||
![]() |
4e30c4fcdb | ||
![]() |
0d33cb3639 | ||
![]() |
2250b3c29d | ||
![]() |
9376368d86 | ||
![]() |
5383794cc9 | ||
![]() |
75279ccec2 | ||
![]() |
717b08695e |
@@ -60,7 +60,7 @@ ENDMACRO(jsoncpp_parse_version)
|
|||||||
#SET( JSONCPP_VERSION_MAJOR X )
|
#SET( JSONCPP_VERSION_MAJOR X )
|
||||||
#SET( JSONCPP_VERSION_MINOR Y )
|
#SET( JSONCPP_VERSION_MINOR Y )
|
||||||
#SET( JSONCPP_VERSION_PATCH Z )
|
#SET( JSONCPP_VERSION_PATCH Z )
|
||||||
SET( JSONCPP_VERSION 0.9.4 )
|
SET( JSONCPP_VERSION 1.6.0 )
|
||||||
jsoncpp_parse_version( ${JSONCPP_VERSION} JSONCPP_VERSION )
|
jsoncpp_parse_version( ${JSONCPP_VERSION} JSONCPP_VERSION )
|
||||||
#IF(NOT JSONCPP_VERSION_FOUND)
|
#IF(NOT JSONCPP_VERSION_FOUND)
|
||||||
# MESSAGE(FATAL_ERROR "Failed to parse version string properly. Expect X.Y.Z")
|
# MESSAGE(FATAL_ERROR "Failed to parse version string properly. Expect X.Y.Z")
|
||||||
@@ -94,10 +94,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} -Wall")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -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} -Wall -Wextra -pedantic")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -Wextra -pedantic")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
IF(JSONCPP_WITH_WARNING_AS_ERROR)
|
IF(JSONCPP_WITH_WARNING_AS_ERROR)
|
||||||
|
@@ -13,22 +13,30 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
|
||||||
|
/** It should not be possible for a maliciously designed file to
|
||||||
|
* cause an abort() or seg-fault, so these macros are used only
|
||||||
|
* for pre-condition violations and internal logic errors.
|
||||||
|
*/
|
||||||
#if JSON_USE_EXCEPTION
|
#if JSON_USE_EXCEPTION
|
||||||
#include <stdexcept>
|
|
||||||
#define JSON_ASSERT(condition) \
|
// @todo <= add detail about condition in exception
|
||||||
{if (!(condition)) {throw std::logic_error( "assert json failed" );}} // @todo <= add detail about condition in exception
|
# define JSON_ASSERT(condition) \
|
||||||
#define JSON_FAIL_MESSAGE(message) \
|
{if (!(condition)) {Json::throwLogicError( "assert json failed" );}}
|
||||||
|
|
||||||
|
# define JSON_FAIL_MESSAGE(message) \
|
||||||
{ \
|
{ \
|
||||||
std::ostringstream oss; oss << message; \
|
std::ostringstream oss; oss << message; \
|
||||||
throw std::logic_error(oss.str()); \
|
Json::throwLogicError(oss.str()); \
|
||||||
|
abort(); \
|
||||||
}
|
}
|
||||||
//#define JSON_FAIL_MESSAGE(message) throw std::logic_error(message)
|
|
||||||
#else // JSON_USE_EXCEPTION
|
#else // JSON_USE_EXCEPTION
|
||||||
#define JSON_ASSERT(condition) assert(condition)
|
|
||||||
|
# define JSON_ASSERT(condition) assert(condition)
|
||||||
|
|
||||||
// The call to assert() will show the failure message in debug builds. In
|
// The call to assert() will show the failure message in debug builds. In
|
||||||
// release bugs we abort, for a core-dump or debugger.
|
// release builds we abort, for a core-dump or debugger.
|
||||||
#define JSON_FAIL_MESSAGE(message) \
|
# define JSON_FAIL_MESSAGE(message) \
|
||||||
{ \
|
{ \
|
||||||
std::ostringstream oss; oss << message; \
|
std::ostringstream oss; oss << message; \
|
||||||
assert(false && oss.str().c_str()); \
|
assert(false && oss.str().c_str()); \
|
||||||
|
@@ -70,6 +70,14 @@
|
|||||||
#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008
|
#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008
|
||||||
/// Indicates that the following function is deprecated.
|
/// Indicates that the following function is deprecated.
|
||||||
#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
|
#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
|
||||||
|
#elif defined(__clang__) && defined(__has_feature)
|
||||||
|
#if __has_feature(attribute_deprecated_with_message)
|
||||||
|
#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message)))
|
||||||
|
#endif
|
||||||
|
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
|
||||||
|
#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message)))
|
||||||
|
#elif defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||||
|
#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(JSONCPP_DEPRECATED)
|
#if !defined(JSONCPP_DEPRECATED)
|
||||||
|
@@ -44,6 +44,12 @@ 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,6 +35,18 @@ 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.
|
||||||
*/
|
*/
|
||||||
@@ -98,7 +110,7 @@ public:
|
|||||||
* during parsing.
|
* during parsing.
|
||||||
* \deprecated Use getFormattedErrorMessages() instead (typo fix).
|
* \deprecated Use getFormattedErrorMessages() instead (typo fix).
|
||||||
*/
|
*/
|
||||||
JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead")
|
JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.")
|
||||||
std::string getFormatedErrorMessages() const;
|
std::string getFormatedErrorMessages() const;
|
||||||
|
|
||||||
/** \brief Returns a user friendly string that list errors in the parsed
|
/** \brief Returns a user friendly string that list errors in the parsed
|
||||||
@@ -111,6 +123,38 @@ 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,
|
||||||
@@ -226,6 +270,7 @@ public:
|
|||||||
|
|
||||||
class Factory {
|
class Factory {
|
||||||
public:
|
public:
|
||||||
|
virtual ~Factory() {}
|
||||||
/** \brief Allocate a CharReader via operator new().
|
/** \brief Allocate a CharReader via operator new().
|
||||||
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
||||||
*/
|
*/
|
||||||
@@ -235,8 +280,6 @@ public:
|
|||||||
|
|
||||||
/** \brief Build a CharReader implementation.
|
/** \brief Build a CharReader implementation.
|
||||||
|
|
||||||
\deprecated This is experimental and will be altered before the next release.
|
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
\code
|
\code
|
||||||
using namespace Json;
|
using namespace Json;
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
#ifndef JSON_USE_CPPTL_SMALLMAP
|
#ifndef JSON_USE_CPPTL_SMALLMAP
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -32,6 +33,31 @@
|
|||||||
*/
|
*/
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
|
/** Base class for all exceptions we throw.
|
||||||
|
*
|
||||||
|
* We use nothing but these internally. Of course, STL can throw others.
|
||||||
|
*/
|
||||||
|
class JSON_API Exception;
|
||||||
|
/** 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;
|
||||||
|
/** 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;
|
||||||
|
|
||||||
|
/// used internally
|
||||||
|
void throwRuntimeError(std::string const& msg);
|
||||||
|
/// used internally
|
||||||
|
void throwLogicError(std::string const& msg);
|
||||||
|
|
||||||
/** \brief Type of the value held by a Value object.
|
/** \brief Type of the value held by a Value object.
|
||||||
*/
|
*/
|
||||||
enum ValueType {
|
enum ValueType {
|
||||||
@@ -134,11 +160,8 @@ public:
|
|||||||
typedef Json::LargestUInt LargestUInt;
|
typedef Json::LargestUInt LargestUInt;
|
||||||
typedef Json::ArrayIndex ArrayIndex;
|
typedef Json::ArrayIndex ArrayIndex;
|
||||||
|
|
||||||
static const Value& nullRef;
|
static const Value& null; ///< We regret this reference to a global instance; prefer the simpler Value().
|
||||||
#if !defined(__ARMEL__)
|
static const Value& nullRef; ///< just a kludge for binary-compatibility; same as null
|
||||||
/// \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.
|
||||||
@@ -260,7 +283,7 @@ Json::Value obj_value(Json::objectValue); // {}
|
|||||||
|
|
||||||
/// Deep copy, then swap(other).
|
/// Deep copy, then swap(other).
|
||||||
/// \note Over-write existing comments. To preserve comments, use #swapPayload().
|
/// \note Over-write existing comments. To preserve comments, use #swapPayload().
|
||||||
Value &operator=(const Value &other);
|
Value& operator=(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.
|
||||||
@@ -506,6 +529,13 @@ 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);
|
||||||
|
|
||||||
@@ -542,6 +572,11 @@ private:
|
|||||||
unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
|
unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
|
||||||
// If not allocated_, string_ must be null-terminated.
|
// If not allocated_, string_ must be null-terminated.
|
||||||
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
|
||||||
@@ -632,16 +667,22 @@ public:
|
|||||||
/// Value.
|
/// Value.
|
||||||
Value key() const;
|
Value key() const;
|
||||||
|
|
||||||
/// Return the index of the referenced Value. -1 if it is not an arrayValue.
|
/// Return the index of the referenced Value, or -1 if it is not an arrayValue.
|
||||||
UInt index() const;
|
UInt index() const;
|
||||||
|
|
||||||
|
/// Return the member name of the referenced Value, or "" if it is not an
|
||||||
|
/// objectValue.
|
||||||
|
/// \note Avoid `c_str()` on result, as embedded zeroes are possible.
|
||||||
|
std::string name() const;
|
||||||
|
|
||||||
/// Return the member name of the referenced Value. "" if it is not an
|
/// Return the member name of the referenced Value. "" if it is not an
|
||||||
/// objectValue.
|
/// objectValue.
|
||||||
/// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls.
|
/// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls.
|
||||||
|
JSONCPP_DEPRECATED("Use `key = name();` instead.")
|
||||||
char const* memberName() const;
|
char const* memberName() const;
|
||||||
/// Return the member name of the referenced Value, or NULL if it is not an
|
/// Return the member name of the referenced Value, or NULL if it is not an
|
||||||
/// objectValue.
|
/// objectValue.
|
||||||
/// Better version than memberName(). Allows embedded nulls.
|
/// \note Better version than memberName(). Allows embedded nulls.
|
||||||
char const* memberName(char const** end) const;
|
char const* memberName(char const** end) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@@ -4,10 +4,10 @@
|
|||||||
#ifndef JSON_VERSION_H_INCLUDED
|
#ifndef JSON_VERSION_H_INCLUDED
|
||||||
# define JSON_VERSION_H_INCLUDED
|
# define JSON_VERSION_H_INCLUDED
|
||||||
|
|
||||||
# define JSONCPP_VERSION_STRING "0.9.4"
|
# define JSONCPP_VERSION_STRING "1.6.0"
|
||||||
# define JSONCPP_VERSION_MAJOR 0
|
# define JSONCPP_VERSION_MAJOR 1
|
||||||
# define JSONCPP_VERSION_MINOR 9
|
# define JSONCPP_VERSION_MINOR 6
|
||||||
# define JSONCPP_VERSION_PATCH 4
|
# define JSONCPP_VERSION_PATCH 0
|
||||||
# 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))
|
||||||
|
|
||||||
|
@@ -46,7 +46,7 @@ public:
|
|||||||
/** Write Value into document as configured in sub-class.
|
/** Write Value into document as configured in sub-class.
|
||||||
Do not take ownership of sout, but maintain a reference during function.
|
Do not take ownership of sout, but maintain a reference during function.
|
||||||
\pre sout != NULL
|
\pre sout != NULL
|
||||||
\return zero on success
|
\return zero on success (For now, we always return zero, so check the stream instead.)
|
||||||
\throw std::exception possibly, depending on configuration
|
\throw std::exception possibly, depending on configuration
|
||||||
*/
|
*/
|
||||||
virtual int write(Value const& root, std::ostream* sout) = 0;
|
virtual int write(Value const& root, std::ostream* sout) = 0;
|
||||||
@@ -132,7 +132,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** \brief Abstract class for writers.
|
/** \brief Abstract class for writers.
|
||||||
* \deprecated Use StreamWriter.
|
* \deprecated Use StreamWriter. (And really, this is an implementation detail.)
|
||||||
*/
|
*/
|
||||||
class JSON_API Writer {
|
class JSON_API Writer {
|
||||||
public:
|
public:
|
||||||
@@ -151,12 +151,22 @@ public:
|
|||||||
* \deprecated Use StreamWriterBuilder.
|
* \deprecated Use StreamWriterBuilder.
|
||||||
*/
|
*/
|
||||||
class JSON_API FastWriter : public Writer {
|
class JSON_API FastWriter : public Writer {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FastWriter();
|
FastWriter();
|
||||||
virtual ~FastWriter() {}
|
virtual ~FastWriter() {}
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
@@ -165,6 +175,8 @@ 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
|
||||||
|
@@ -17,7 +17,6 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
|
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
@@ -43,14 +42,17 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +147,7 @@ bool Reader::readValue() {
|
|||||||
// But this deprecated class has a security problem: Bad input can
|
// But this deprecated class has a security problem: Bad input can
|
||||||
// cause a seg-fault. This seems like a fair, binary-compatible way
|
// cause a seg-fault. This seems like a fair, binary-compatible way
|
||||||
// to prevent the problem.
|
// to prevent the problem.
|
||||||
if (stackDepth_g >= stackLimit_g) throw std::runtime_error("Exceeded stackLimit in readValue().");
|
if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
|
||||||
++stackDepth_g;
|
++stackDepth_g;
|
||||||
|
|
||||||
Token token;
|
Token token;
|
||||||
@@ -160,9 +162,11 @@ 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);
|
||||||
@@ -174,22 +178,42 @@ 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;
|
||||||
// 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:
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,11 +441,12 @@ 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)
|
||||||
@@ -434,6 +459,11 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -467,9 +497,10 @@ 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
|
||||||
{
|
{
|
||||||
@@ -509,6 +540,8 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -557,6 +590,8 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -602,6 +637,8 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -813,8 +850,59 @@ std::string Reader::getFormattedErrorMessages() const {
|
|||||||
return formattedMessage;
|
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
|
// exact copy of Features
|
||||||
class OurFeatures {
|
class OurFeatures {
|
||||||
@@ -864,6 +952,10 @@ 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
|
||||||
@@ -1014,7 +1106,7 @@ bool OurReader::parse(const char* beginDoc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool OurReader::readValue() {
|
bool OurReader::readValue() {
|
||||||
if (stackDepth_ >= features_.stackLimit_) throw std::runtime_error("Exceeded stackLimit in readValue().");
|
if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");
|
||||||
++stackDepth_;
|
++stackDepth_;
|
||||||
Token token;
|
Token token;
|
||||||
skipCommentTokens(token);
|
skipCommentTokens(token);
|
||||||
@@ -1028,9 +1120,11 @@ 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);
|
||||||
@@ -1042,18 +1136,24 @@ 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:
|
||||||
@@ -1065,9 +1165,13 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1299,6 +1403,7 @@ 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)
|
||||||
@@ -1325,7 +1430,7 @@ bool OurReader::readObject(Token& tokenStart) {
|
|||||||
return addErrorAndRecover(
|
return addErrorAndRecover(
|
||||||
"Missing ':' after object member name", colon, tokenObjectEnd);
|
"Missing ':' after object member name", colon, tokenObjectEnd);
|
||||||
}
|
}
|
||||||
if (name.length() >= (1U<<30)) throw std::runtime_error("keylength >= 2^30");
|
if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");
|
||||||
if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
|
if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
|
||||||
std::string msg = "Duplicate key: '" + name + "'";
|
std::string msg = "Duplicate key: '" + name + "'";
|
||||||
return addErrorAndRecover(
|
return addErrorAndRecover(
|
||||||
@@ -1358,6 +1463,7 @@ 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
|
||||||
{
|
{
|
||||||
@@ -1397,6 +1503,8 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1445,6 +1553,8 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1490,6 +1600,8 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1696,6 +1808,60 @@ 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_;
|
||||||
@@ -1827,7 +1993,7 @@ std::istream& operator>>(std::istream& sin, Value& root) {
|
|||||||
"Error from reader: %s",
|
"Error from reader: %s",
|
||||||
errs.c_str());
|
errs.c_str());
|
||||||
|
|
||||||
JSON_FAIL_MESSAGE("reader error");
|
throwRuntimeError("reader error");
|
||||||
}
|
}
|
||||||
return sin;
|
return sin;
|
||||||
}
|
}
|
||||||
|
@@ -29,13 +29,12 @@ 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.
|
|
||||||
const Value Value::null;
|
|
||||||
#define ALIGNAS(byte_alignment)
|
#define ALIGNAS(byte_alignment)
|
||||||
#endif
|
#endif
|
||||||
static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
|
static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
|
||||||
const unsigned char& kNullRef = kNull[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::minInt = Int(~(UInt(-1) / 2));
|
||||||
const Int Value::maxInt = Int(UInt(-1) / 2);
|
const Int Value::maxInt = Int(UInt(-1) / 2);
|
||||||
@@ -88,9 +87,11 @@ static inline char* duplicateStringValue(const char* value,
|
|||||||
length = Value::maxInt - 1;
|
length = Value::maxInt - 1;
|
||||||
|
|
||||||
char* newString = static_cast<char*>(malloc(length + 1));
|
char* newString = static_cast<char*>(malloc(length + 1));
|
||||||
JSON_ASSERT_MESSAGE(newString != 0,
|
if (newString == NULL) {
|
||||||
|
throwRuntimeError(
|
||||||
"in Json::Value::duplicateStringValue(): "
|
"in Json::Value::duplicateStringValue(): "
|
||||||
"Failed to allocate string value buffer");
|
"Failed to allocate string value buffer");
|
||||||
|
}
|
||||||
memcpy(newString, value, length);
|
memcpy(newString, value, length);
|
||||||
newString[length] = 0;
|
newString[length] = 0;
|
||||||
return newString;
|
return newString;
|
||||||
@@ -109,9 +110,11 @@ static inline char* duplicateAndPrefixStringValue(
|
|||||||
"length too big for prefixing");
|
"length too big for prefixing");
|
||||||
unsigned actualLength = length + sizeof(unsigned) + 1U;
|
unsigned actualLength = length + sizeof(unsigned) + 1U;
|
||||||
char* newString = static_cast<char*>(malloc(actualLength));
|
char* newString = static_cast<char*>(malloc(actualLength));
|
||||||
JSON_ASSERT_MESSAGE(newString != 0,
|
if (newString == 0) {
|
||||||
|
throwRuntimeError(
|
||||||
"in Json::Value::duplicateAndPrefixStringValue(): "
|
"in Json::Value::duplicateAndPrefixStringValue(): "
|
||||||
"Failed to allocate string value buffer");
|
"Failed to allocate string value buffer");
|
||||||
|
}
|
||||||
*reinterpret_cast<unsigned*>(newString) = length;
|
*reinterpret_cast<unsigned*>(newString) = length;
|
||||||
memcpy(newString + sizeof(unsigned), value, length);
|
memcpy(newString + sizeof(unsigned), value, length);
|
||||||
newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later
|
newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later
|
||||||
@@ -149,6 +152,47 @@ static inline void releaseStringValue(char* value) { free(value); }
|
|||||||
|
|
||||||
namespace Json {
|
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)
|
||||||
|
{}
|
||||||
|
Exception::~Exception() throw()
|
||||||
|
{}
|
||||||
|
char const* Exception::what() const throw()
|
||||||
|
{
|
||||||
|
return msg_.c_str();
|
||||||
|
}
|
||||||
|
RuntimeError::RuntimeError(std::string const& msg)
|
||||||
|
: Exception(msg)
|
||||||
|
{}
|
||||||
|
LogicError::LogicError(std::string const& msg)
|
||||||
|
: Exception(msg)
|
||||||
|
{}
|
||||||
|
void throwRuntimeError(std::string const& msg)
|
||||||
|
{
|
||||||
|
throw RuntimeError(msg);
|
||||||
|
}
|
||||||
|
void throwLogicError(std::string const& msg)
|
||||||
|
{
|
||||||
|
throw LogicError(msg);
|
||||||
|
}
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
@@ -357,7 +401,7 @@ Value::Value(bool value) {
|
|||||||
Value::Value(Value const& other)
|
Value::Value(Value const& other)
|
||||||
: type_(other.type_), allocated_(false)
|
: type_(other.type_), allocated_(false)
|
||||||
,
|
,
|
||||||
comments_(0)
|
comments_(0), start_(other.start_), limit_(other.limit_)
|
||||||
{
|
{
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
case nullValue:
|
case nullValue:
|
||||||
@@ -422,9 +466,8 @@ Value::~Value() {
|
|||||||
delete[] comments_;
|
delete[] comments_;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value &Value::operator=(const Value &other) {
|
Value& Value::operator=(Value other) {
|
||||||
Value temp(other);
|
swap(other);
|
||||||
swap(temp);
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -441,6 +484,8 @@ 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_; }
|
||||||
@@ -842,6 +887,8 @@ 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_) {
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
@@ -917,6 +964,8 @@ void Value::initBasic(ValueType type, bool allocated) {
|
|||||||
type_ = type;
|
type_ = type;
|
||||||
allocated_ = allocated;
|
allocated_ = allocated;
|
||||||
comments_ = 0;
|
comments_ = 0;
|
||||||
|
start_ = 0;
|
||||||
|
limit_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Access an object value by name, create a null member if it does not exist.
|
// Access an object value by name, create a null member if it does not exist.
|
||||||
@@ -1286,6 +1335,14 @@ 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);
|
||||||
|
@@ -92,6 +92,14 @@ UInt ValueIteratorBase::index() const {
|
|||||||
return Value::UInt(-1);
|
return Value::UInt(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ValueIteratorBase::name() const {
|
||||||
|
char const* key;
|
||||||
|
char const* end;
|
||||||
|
key = memberName(&end);
|
||||||
|
if (!key) return std::string();
|
||||||
|
return std::string(key, end);
|
||||||
|
}
|
||||||
|
|
||||||
char const* ValueIteratorBase::memberName() const {
|
char const* ValueIteratorBase::memberName() const {
|
||||||
const char* name = (*current_).first.data();
|
const char* name = (*current_).first.data();
|
||||||
return name ? name : "";
|
return name ? name : "";
|
||||||
|
@@ -12,16 +12,25 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <stdexcept>
|
#include <cassert>
|
||||||
#include <assert.h>
|
#include <cstring>
|
||||||
#include <math.h>
|
#include <cstdio>
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
|
#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#define isfinite _finite
|
#define isfinite _finite
|
||||||
|
#elif defined(__sun) && defined(__SVR4) //Solaris
|
||||||
|
#include <ieeefp.h>
|
||||||
|
#define isfinite finite
|
||||||
|
#else
|
||||||
|
#include <cmath>
|
||||||
|
#define isfinite std::isfinite
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
|
#else
|
||||||
|
#define snprintf std::snprintf
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
|
#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
|
||||||
@@ -29,11 +38,6 @@
|
|||||||
#pragma warning(disable : 4996)
|
#pragma warning(disable : 4996)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__sun) && defined(__SVR4) //Solaris
|
|
||||||
#include <ieeefp.h>
|
|
||||||
#define isfinite finite
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
#if __cplusplus >= 201103L
|
#if __cplusplus >= 201103L
|
||||||
@@ -280,13 +284,19 @@ Writer::~Writer() {}
|
|||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
FastWriter::FastWriter()
|
FastWriter::FastWriter()
|
||||||
: yamlCompatiblityEnabled_(false) {}
|
: yamlCompatiblityEnabled_(false), dropNullPlaceholders_(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_;
|
||||||
}
|
}
|
||||||
@@ -294,6 +304,7 @@ std::string FastWriter::write(const Value& root) {
|
|||||||
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:
|
||||||
@@ -1073,7 +1084,7 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
|
|||||||
} else if (cs_str == "None") {
|
} else if (cs_str == "None") {
|
||||||
cs = CommentStyle::None;
|
cs = CommentStyle::None;
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("commentStyle must be 'All' or 'None'");
|
throwRuntimeError("commentStyle must be 'All' or 'None'");
|
||||||
}
|
}
|
||||||
std::string colonSymbol = " : ";
|
std::string colonSymbol = " : ";
|
||||||
if (eyc) {
|
if (eyc) {
|
||||||
|
@@ -6,7 +6,6 @@
|
|||||||
#include "jsontest.h"
|
#include "jsontest.h"
|
||||||
#include <json/config.h>
|
#include <json/config.h>
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <stdexcept>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
// Make numeric limits more convenient to talk about.
|
// Make numeric limits more convenient to talk about.
|
||||||
@@ -1499,6 +1498,25 @@ 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);
|
||||||
|
}
|
||||||
|
|
||||||
JSONTEST_FIXTURE(ValueTest, StaticString) {
|
JSONTEST_FIXTURE(ValueTest, StaticString) {
|
||||||
char mutant[] = "hello";
|
char mutant[] = "hello";
|
||||||
Json::StaticString ss(mutant);
|
Json::StaticString ss(mutant);
|
||||||
@@ -1619,6 +1637,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 {};
|
struct StreamWriterTest : JsonTest::TestCase {};
|
||||||
|
|
||||||
JSONTEST_FIXTURE(StreamWriterTest, dropNullPlaceholders) {
|
JSONTEST_FIXTURE(StreamWriterTest, dropNullPlaceholders) {
|
||||||
@@ -1660,6 +1689,7 @@ 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) {
|
||||||
@@ -1671,6 +1701,25 @@ 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) {
|
||||||
@@ -1681,6 +1730,13 @@ 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) {
|
||||||
@@ -1691,6 +1747,13 @@ 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) {
|
||||||
@@ -1701,6 +1764,12 @@ 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 {};
|
||||||
@@ -2213,6 +2282,42 @@ JSONTEST_FIXTURE(IteratorTest, distance) {
|
|||||||
JSONTEST_ASSERT_STRING_EQUAL("b", str);
|
JSONTEST_ASSERT_STRING_EQUAL("b", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSONTEST_FIXTURE(IteratorTest, names) {
|
||||||
|
Json::Value json;
|
||||||
|
json["k1"] = "a";
|
||||||
|
json["k2"] = "b";
|
||||||
|
Json::ValueIterator it = json.begin();
|
||||||
|
JSONTEST_ASSERT(it != json.end());
|
||||||
|
JSONTEST_ASSERT_EQUAL(Json::Value("k1"), it.key());
|
||||||
|
JSONTEST_ASSERT_STRING_EQUAL("k1", it.name());
|
||||||
|
JSONTEST_ASSERT_EQUAL(-1, it.index());
|
||||||
|
++it;
|
||||||
|
JSONTEST_ASSERT(it != json.end());
|
||||||
|
JSONTEST_ASSERT_EQUAL(Json::Value("k2"), it.key());
|
||||||
|
JSONTEST_ASSERT_STRING_EQUAL("k2", it.name());
|
||||||
|
JSONTEST_ASSERT_EQUAL(-1, it.index());
|
||||||
|
++it;
|
||||||
|
JSONTEST_ASSERT(it == json.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONTEST_FIXTURE(IteratorTest, indexes) {
|
||||||
|
Json::Value json;
|
||||||
|
json[0] = "a";
|
||||||
|
json[1] = "b";
|
||||||
|
Json::ValueIterator it = json.begin();
|
||||||
|
JSONTEST_ASSERT(it != json.end());
|
||||||
|
JSONTEST_ASSERT_EQUAL(Json::Value(Json::ArrayIndex(0)), it.key());
|
||||||
|
JSONTEST_ASSERT_STRING_EQUAL("", it.name());
|
||||||
|
JSONTEST_ASSERT_EQUAL(0, it.index());
|
||||||
|
++it;
|
||||||
|
JSONTEST_ASSERT(it != json.end());
|
||||||
|
JSONTEST_ASSERT_EQUAL(Json::Value(Json::ArrayIndex(1)), it.key());
|
||||||
|
JSONTEST_ASSERT_STRING_EQUAL("", it.name());
|
||||||
|
JSONTEST_ASSERT_EQUAL(1, it.index());
|
||||||
|
++it;
|
||||||
|
JSONTEST_ASSERT(it == json.end());
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
@@ -2233,6 +2338,7 @@ 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, ValueTest, StaticString);
|
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, StaticString);
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, CommentBefore);
|
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, CommentBefore);
|
||||||
@@ -2240,6 +2346,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroes);
|
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroes);
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroesInKeys);
|
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroesInKeys);
|
||||||
|
|
||||||
|
JSONTEST_REGISTER_FIXTURE(runner, WriterTest, dropNullPlaceholders);
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders);
|
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders);
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, writeZeroes);
|
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, writeZeroes);
|
||||||
|
|
||||||
@@ -2275,6 +2382,8 @@ int main(int argc, const char* argv[]) {
|
|||||||
JSONTEST_REGISTER_FIXTURE(runner, BuilderTest, settings);
|
JSONTEST_REGISTER_FIXTURE(runner, BuilderTest, settings);
|
||||||
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, IteratorTest, distance);
|
JSONTEST_REGISTER_FIXTURE(runner, IteratorTest, distance);
|
||||||
|
JSONTEST_REGISTER_FIXTURE(runner, IteratorTest, names);
|
||||||
|
JSONTEST_REGISTER_FIXTURE(runner, IteratorTest, indexes);
|
||||||
|
|
||||||
return runner.runCommandLine(argc, argv);
|
return runner.runCommandLine(argc, argv);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user