mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2025-01-31 14:39:52 +01:00
Ran clang-format over all .h and .cpp files.
clang-format -i $(find . -name '*.h' -or -name '*.cpp')
This commit is contained in:
parent
1b137a3802
commit
9fa4e849a1
@ -14,7 +14,8 @@
|
||||
|
||||
#if JSON_USE_EXCEPTION
|
||||
#include <stdexcept>
|
||||
#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw
|
||||
#define JSON_ASSERT(condition) \
|
||||
assert(condition); // @todo <= change this into an exception throw
|
||||
#define JSON_FAIL_MESSAGE(message) throw std::runtime_error(message);
|
||||
#else // JSON_USE_EXCEPTION
|
||||
#define JSON_ASSERT(condition) assert(condition);
|
||||
@ -23,10 +24,18 @@
|
||||
// release bugs we write to invalid memory in order to crash hard, so that a
|
||||
// debugger or crash reporter gets the chance to take over. We still call exit()
|
||||
// afterward in order to tell the compiler that this macro doesn't return.
|
||||
#define JSON_FAIL_MESSAGE( message ) { assert(false && message); strcpy(reinterpret_cast<char*>(666), message); exit(123); }
|
||||
#define JSON_FAIL_MESSAGE(message) \
|
||||
{ \
|
||||
assert(false &&message); \
|
||||
strcpy(reinterpret_cast<char *>(666), message); \
|
||||
exit(123); \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) { JSON_FAIL_MESSAGE( message ) }
|
||||
#define JSON_ASSERT_MESSAGE(condition, message) \
|
||||
if (!(condition)) { \
|
||||
JSON_FAIL_MESSAGE(message) \
|
||||
}
|
||||
|
||||
#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED
|
||||
|
@ -12,7 +12,8 @@
|
||||
#include <cpptl/cpptl_autolink.h>
|
||||
#endif
|
||||
|
||||
# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL)
|
||||
#if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && \
|
||||
!defined(JSON_IN_CPPTL)
|
||||
#define CPPTL_AUTOLINK_NAME "json"
|
||||
#undef CPPTL_AUTOLINK_DLL
|
||||
#ifdef JSON_DLL
|
||||
|
@ -11,15 +11,18 @@
|
||||
|
||||
/// If defined, indicates that json may leverage CppTL library
|
||||
//# define JSON_USE_CPPTL 1
|
||||
/// If defined, indicates that cpptl vector based map should be used instead of std::map
|
||||
/// If defined, indicates that cpptl vector based map should be used instead of
|
||||
/// std::map
|
||||
/// as Value container.
|
||||
//# define JSON_USE_CPPTL_SMALLMAP 1
|
||||
/// If defined, indicates that Json specific container should be used
|
||||
/// (hash table & simple deque container with customizable allocator).
|
||||
/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332
|
||||
//# define JSON_VALUE_USE_INTERNAL_MAP 1
|
||||
/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.
|
||||
/// The memory pools allocator used optimization (initializing Value and ValueInternalLink
|
||||
/// Force usage of standard new/malloc based allocator instead of memory pool
|
||||
/// based allocator.
|
||||
/// The memory pools allocator used optimization (initializing Value and
|
||||
/// ValueInternalLink
|
||||
/// as if it was a POD) that may cause some validation tool to report errors.
|
||||
/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
|
||||
//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
|
||||
@ -35,7 +38,6 @@
|
||||
/// Remarks: it is automatically defined in the generated amalgated header.
|
||||
// #define JSON_IS_AMALGAMATION
|
||||
|
||||
|
||||
#ifdef JSON_IN_CPPTL
|
||||
#include <cpptl/config.h>
|
||||
#ifndef JSON_USE_CPPTL
|
||||
@ -60,7 +62,8 @@
|
||||
#define JSON_API
|
||||
#endif
|
||||
|
||||
// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for integer
|
||||
// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
|
||||
// integer
|
||||
// Storages, and 64 bits integer support is disabled.
|
||||
// #define JSON_NO_INT64 1
|
||||
|
||||
@ -68,8 +71,10 @@
|
||||
// Microsoft Visual Studio 6 only support conversion from __int64 to double
|
||||
// (no conversion from unsigned __int64).
|
||||
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
|
||||
// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' characters in the debug information)
|
||||
// All projects I've ever seen with VS6 were using this globally (not bothering with pragma push/pop).
|
||||
// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
|
||||
// characters in the debug information)
|
||||
// All projects I've ever seen with VS6 were using this globally (not bothering
|
||||
// with pragma push/pop).
|
||||
#pragma warning(disable : 4786)
|
||||
#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6
|
||||
|
||||
@ -104,5 +109,4 @@ namespace Json {
|
||||
#endif // if defined(JSON_NO_INT64)
|
||||
} // end namespace Json
|
||||
|
||||
|
||||
#endif // JSON_CONFIG_H_INCLUDED
|
||||
|
@ -16,17 +16,18 @@ namespace Json {
|
||||
* This configuration object can be used to force the Reader or Writer
|
||||
* to behave in a standard conforming way.
|
||||
*/
|
||||
class JSON_API Features
|
||||
{
|
||||
class JSON_API Features {
|
||||
public:
|
||||
/** \brief A configuration that allows all features and assumes all strings are UTF-8.
|
||||
/** \brief A configuration that allows all features and assumes all strings
|
||||
* are UTF-8.
|
||||
* - C & C++ comments are allowed
|
||||
* - Root object can be any JSON value
|
||||
* - Assumes Value strings are encoded in UTF-8
|
||||
*/
|
||||
static Features all();
|
||||
|
||||
/** \brief A configuration that is strictly compatible with the JSON specification.
|
||||
/** \brief A configuration that is strictly compatible with the JSON
|
||||
* specification.
|
||||
* - Comments are forbidden.
|
||||
* - Root object must be either an array or an object value.
|
||||
* - Assumes Value strings are encoded in UTF-8
|
||||
@ -40,7 +41,8 @@ namespace Json {
|
||||
/// \c true if comments are allowed. Default: \c true.
|
||||
bool allowComments_;
|
||||
|
||||
/// \c true if root must be either an array or an object value. Default: \c false.
|
||||
/// \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.
|
||||
|
@ -40,5 +40,4 @@ namespace Json {
|
||||
|
||||
} // namespace Json
|
||||
|
||||
|
||||
#endif // JSON_FORWARDS_H_INCLUDED
|
||||
|
@ -15,20 +15,20 @@
|
||||
#include <stack>
|
||||
#include <string>
|
||||
|
||||
// Disable warning C4251: <data member>: <type> needs to have dll-interface to be used by...
|
||||
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
|
||||
// be used by...
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
|
||||
namespace Json {
|
||||
|
||||
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
|
||||
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
|
||||
*Value.
|
||||
*
|
||||
*/
|
||||
class JSON_API Reader
|
||||
{
|
||||
class JSON_API Reader {
|
||||
public:
|
||||
typedef char Char;
|
||||
typedef const Char *Location;
|
||||
@ -39,8 +39,7 @@ namespace Json {
|
||||
* that this is bytes, not codepoints.
|
||||
*
|
||||
*/
|
||||
struct StructuredError
|
||||
{
|
||||
struct StructuredError {
|
||||
size_t offset_start;
|
||||
size_t offset_limit;
|
||||
std::string message;
|
||||
@ -56,69 +55,83 @@ namespace Json {
|
||||
*/
|
||||
Reader(const Features &features);
|
||||
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
||||
* document.
|
||||
* \param document UTF-8 encoded string containing the document to read.
|
||||
* \param root [out] Contains the root value of the document if it was
|
||||
* successfully parsed.
|
||||
* \param collectComments \c true to collect comment and allow writing them back during
|
||||
* \param collectComments \c true to collect comment and allow writing them
|
||||
* back during
|
||||
* serialization, \c false to discard comments.
|
||||
* This parameter is ignored if Features::allowComments_
|
||||
* This parameter is ignored if
|
||||
* Features::allowComments_
|
||||
* is \c false.
|
||||
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||
* \return \c true if the document was successfully parsed, \c false if an
|
||||
* error occurred.
|
||||
*/
|
||||
bool parse( const std::string &document,
|
||||
Value &root,
|
||||
bool collectComments = true );
|
||||
bool
|
||||
parse(const std::string &document, Value &root, bool collectComments = true);
|
||||
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
||||
* \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the document to read.
|
||||
* \param endDoc Pointer on the end of the UTF-8 encoded string of the document to read.
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
||||
document.
|
||||
* \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
|
||||
document to read.
|
||||
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
|
||||
document to read.
|
||||
\ Must be >= beginDoc.
|
||||
* \param root [out] Contains the root value of the document if it was
|
||||
* successfully parsed.
|
||||
* \param collectComments \c true to collect comment and allow writing them back during
|
||||
* \param collectComments \c true to collect comment and allow writing them
|
||||
back during
|
||||
* serialization, \c false to discard comments.
|
||||
* This parameter is ignored if Features::allowComments_
|
||||
* This parameter is ignored if
|
||||
Features::allowComments_
|
||||
* is \c false.
|
||||
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||
* \return \c true if the document was successfully parsed, \c false if an
|
||||
error occurred.
|
||||
*/
|
||||
bool parse( const char *beginDoc, const char *endDoc,
|
||||
bool parse(const char *beginDoc,
|
||||
const char *endDoc,
|
||||
Value &root,
|
||||
bool collectComments = true);
|
||||
|
||||
/// \brief Parse from input stream.
|
||||
/// \see Json::operator>>(std::istream&, Json::Value&).
|
||||
bool parse( std::istream &is,
|
||||
Value &root,
|
||||
bool collectComments = true );
|
||||
bool parse(std::istream &is, Value &root, bool collectComments = true);
|
||||
|
||||
/** \brief Returns a user friendly string that list errors in the parsed document.
|
||||
* \return Formatted error message with the list of errors with their location in
|
||||
* the parsed document. An empty string is returned if no error occurred
|
||||
/** \brief Returns a user friendly string that list errors in the parsed
|
||||
* document.
|
||||
* \return Formatted error message with the list of errors with their location
|
||||
* in
|
||||
* the parsed document. An empty string is returned if no error
|
||||
* occurred
|
||||
* during parsing.
|
||||
* \deprecated Use getFormattedErrorMessages() instead (typo fix).
|
||||
*/
|
||||
JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead")
|
||||
std::string getFormatedErrorMessages() const;
|
||||
|
||||
/** \brief Returns a user friendly string that list errors in the parsed document.
|
||||
* \return Formatted error message with the list of errors with their location in
|
||||
* the parsed document. An empty string is returned if no error occurred
|
||||
/** \brief Returns a user friendly string that list errors in the parsed
|
||||
* document.
|
||||
* \return Formatted error message with the list of errors with their location
|
||||
* in
|
||||
* the parsed document. An empty string is returned if no error
|
||||
* occurred
|
||||
* during parsing.
|
||||
*/
|
||||
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
|
||||
* 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;
|
||||
|
||||
private:
|
||||
enum TokenType
|
||||
{
|
||||
enum TokenType {
|
||||
tokenEndOfStream = 0,
|
||||
tokenObjectBegin,
|
||||
tokenObjectEnd,
|
||||
@ -135,16 +148,14 @@ namespace Json {
|
||||
tokenError
|
||||
};
|
||||
|
||||
class Token
|
||||
{
|
||||
class Token {
|
||||
public:
|
||||
TokenType type_;
|
||||
Location start_;
|
||||
Location end_;
|
||||
};
|
||||
|
||||
class ErrorInfo
|
||||
{
|
||||
class ErrorInfo {
|
||||
public:
|
||||
Token token_;
|
||||
std::string message_;
|
||||
@ -156,8 +167,7 @@ namespace Json {
|
||||
bool expectToken(TokenType type, Token &token, const char *message);
|
||||
bool readToken(Token &token);
|
||||
void skipSpaces();
|
||||
bool match( Location pattern,
|
||||
int patternLength );
|
||||
bool match(Location pattern, int patternLength);
|
||||
bool readComment();
|
||||
bool readCStyleComment();
|
||||
bool readCppStyleComment();
|
||||
@ -180,9 +190,7 @@ namespace Json {
|
||||
Location ¤t,
|
||||
Location end,
|
||||
unsigned int &unicode);
|
||||
bool addError( const std::string &message,
|
||||
Token &token,
|
||||
Location extra = 0 );
|
||||
bool addError(const std::string &message, Token &token, Location extra = 0);
|
||||
bool recoverFromError(TokenType skipUntilToken);
|
||||
bool addErrorAndRecover(const std::string &message,
|
||||
Token &token,
|
||||
@ -190,13 +198,10 @@ namespace Json {
|
||||
void skipUntilSpace();
|
||||
Value ¤tValue();
|
||||
Char getNextChar();
|
||||
void getLocationLineAndColumn( Location location,
|
||||
int &line,
|
||||
int &column ) const;
|
||||
void
|
||||
getLocationLineAndColumn(Location location, int &line, int &column) const;
|
||||
std::string getLocationLineAndColumn(Location location) const;
|
||||
void addComment( Location begin,
|
||||
Location end,
|
||||
CommentPlacement placement );
|
||||
void addComment(Location begin, Location end, CommentPlacement placement);
|
||||
void skipCommentTokens(Token &token);
|
||||
|
||||
typedef std::stack<Value *> Nodes;
|
||||
@ -245,5 +250,4 @@ namespace Json {
|
||||
#pragma warning(pop)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
|
||||
#endif // CPPTL_JSON_READER_H_INCLUDED
|
||||
|
@ -21,21 +21,20 @@
|
||||
#include <cpptl/forwards.h>
|
||||
#endif
|
||||
|
||||
// Disable warning C4251: <data member>: <type> needs to have dll-interface to be used by...
|
||||
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
|
||||
// be used by...
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
|
||||
/** \brief JSON (JavaScript Object Notation).
|
||||
*/
|
||||
namespace Json {
|
||||
|
||||
/** \brief Type of the value held by a Value object.
|
||||
*/
|
||||
enum ValueType
|
||||
{
|
||||
enum ValueType {
|
||||
nullValue = 0, ///< 'null' value
|
||||
intValue, ///< signed integer value
|
||||
uintValue, ///< unsigned integer value
|
||||
@ -46,11 +45,11 @@ namespace Json {
|
||||
objectValue ///< object value (collection of name/value pairs).
|
||||
};
|
||||
|
||||
enum CommentPlacement
|
||||
{
|
||||
enum CommentPlacement {
|
||||
commentBefore = 0, ///< a comment placed on the line before a value
|
||||
commentAfterOnSameLine, ///< a comment just after a value on the same line
|
||||
commentAfter, ///< a comment on the line after a value (only make sense for root value)
|
||||
commentAfter, ///< a comment on the line after a value (only make sense for
|
||||
///root value)
|
||||
numberOfCommentPlacement
|
||||
};
|
||||
|
||||
@ -73,23 +72,13 @@ namespace Json {
|
||||
* object[code] = 1234;
|
||||
* \endcode
|
||||
*/
|
||||
class JSON_API StaticString
|
||||
{
|
||||
class JSON_API StaticString {
|
||||
public:
|
||||
explicit StaticString( const char *czstring )
|
||||
: str_( czstring )
|
||||
{
|
||||
}
|
||||
explicit StaticString(const char *czstring) : str_(czstring) {}
|
||||
|
||||
operator const char *() const
|
||||
{
|
||||
return str_;
|
||||
}
|
||||
operator const char *() const { return str_; }
|
||||
|
||||
const char *c_str() const
|
||||
{
|
||||
return str_;
|
||||
}
|
||||
const char *c_str() const { return str_; }
|
||||
|
||||
private:
|
||||
const char *str_;
|
||||
@ -110,20 +99,21 @@ namespace Json {
|
||||
* The type of the held value is represented by a #ValueType and
|
||||
* can be obtained using type().
|
||||
*
|
||||
* values of an #objectValue or #arrayValue can be accessed using operator[]() methods.
|
||||
* values of an #objectValue or #arrayValue can be accessed using operator[]()
|
||||
*methods.
|
||||
* Non const methods will automatically create the a #nullValue element
|
||||
* if it does not exist.
|
||||
* The sequence of an #arrayValue will be automatically resize and initialized
|
||||
* with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
|
||||
*
|
||||
* The get() methods can be used to obtanis default value in the case the required element
|
||||
* The get() methods can be used to obtanis default value in the case the
|
||||
*required element
|
||||
* does not exist.
|
||||
*
|
||||
* It is possible to iterate over the list of a #objectValue values using
|
||||
* the getMemberNames() method.
|
||||
*/
|
||||
class JSON_API Value
|
||||
{
|
||||
class JSON_API Value {
|
||||
friend class ValueIteratorBase;
|
||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||
friend class ValueInternalLink;
|
||||
@ -170,11 +160,9 @@ namespace Json {
|
||||
private:
|
||||
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
class CZString
|
||||
{
|
||||
class CZString {
|
||||
public:
|
||||
enum DuplicationPolicy
|
||||
{
|
||||
enum DuplicationPolicy {
|
||||
noDuplication = 0,
|
||||
duplicate,
|
||||
duplicateOnCopy
|
||||
@ -189,6 +177,7 @@ namespace Json {
|
||||
ArrayIndex index() const;
|
||||
const char *c_str() const;
|
||||
bool isStaticString() const;
|
||||
|
||||
private:
|
||||
void swap(CZString &other);
|
||||
const char *cstr_;
|
||||
@ -322,14 +311,16 @@ namespace Json {
|
||||
void resize(ArrayIndex size);
|
||||
|
||||
/// Access an array element (zero based index ).
|
||||
/// If the array contains less than index element, then null value are inserted
|
||||
/// If the array contains less than index element, then null value are
|
||||
/// inserted
|
||||
/// in the array so that its size is index+1.
|
||||
/// (You may need to say 'value[0u]' to get your compiler to distinguish
|
||||
/// this from the operator[] which takes a string.)
|
||||
Value &operator[](ArrayIndex index);
|
||||
|
||||
/// Access an array element (zero based index ).
|
||||
/// If the array contains less than index element, then null value are inserted
|
||||
/// If the array contains less than index element, then null value are
|
||||
/// inserted
|
||||
/// in the array so that its size is index+1.
|
||||
/// (You may need to say 'value[0u]' to get your compiler to distinguish
|
||||
/// this from the operator[] which takes a string.)
|
||||
@ -345,10 +336,10 @@ namespace Json {
|
||||
/// this from the operator[] which takes a string.)
|
||||
const Value &operator[](int index) const;
|
||||
|
||||
/// If the array contains at least index+1 elements, returns the element value,
|
||||
/// If the array contains at least index+1 elements, returns the element
|
||||
/// value,
|
||||
/// otherwise returns defaultValue.
|
||||
Value get( ArrayIndex index,
|
||||
const Value &defaultValue ) const;
|
||||
Value get(ArrayIndex index, const Value &defaultValue) const;
|
||||
/// Return true if index < size().
|
||||
bool isValidIndex(ArrayIndex index) const;
|
||||
/// \brief Append value to array at the end.
|
||||
@ -358,13 +349,16 @@ namespace Json {
|
||||
|
||||
/// Access an object value by name, create a null member if it does not exist.
|
||||
Value &operator[](const char *key);
|
||||
/// Access an object value by name, returns null if there is no member with that name.
|
||||
/// Access an object value by name, returns null if there is no member with
|
||||
/// that name.
|
||||
const Value &operator[](const char *key) const;
|
||||
/// Access an object value by name, create a null member if it does not exist.
|
||||
Value &operator[](const std::string &key);
|
||||
/// Access an object value by name, returns null if there is no member with that name.
|
||||
/// Access an object value by name, returns null if there is no member with
|
||||
/// that name.
|
||||
const Value &operator[](const std::string &key) const;
|
||||
/** \brief Access an object value by name, create a null member if it does not exist.
|
||||
/** \brief Access an object value by name, create a null member if it does not
|
||||
exist.
|
||||
|
||||
* If the object as no entry for that name, then the member name used to store
|
||||
* the new entry is not duplicated.
|
||||
@ -379,19 +373,17 @@ namespace Json {
|
||||
#ifdef JSON_USE_CPPTL
|
||||
/// Access an object value by name, create a null member if it does not exist.
|
||||
Value &operator[](const CppTL::ConstString &key);
|
||||
/// Access an object value by name, returns null if there is no member with that name.
|
||||
/// Access an object value by name, returns null if there is no member with
|
||||
/// that name.
|
||||
const Value &operator[](const CppTL::ConstString &key) const;
|
||||
#endif
|
||||
/// Return the member named key if it exist, defaultValue otherwise.
|
||||
Value get( const char *key,
|
||||
const Value &defaultValue ) const;
|
||||
Value get(const char *key, const Value &defaultValue) const;
|
||||
/// Return the member named key if it exist, defaultValue otherwise.
|
||||
Value get( const std::string &key,
|
||||
const Value &defaultValue ) const;
|
||||
Value get(const std::string &key, const Value &defaultValue) const;
|
||||
#ifdef JSON_USE_CPPTL
|
||||
/// Return the member named key if it exist, defaultValue otherwise.
|
||||
Value get( const CppTL::ConstString &key,
|
||||
const Value &defaultValue ) const;
|
||||
Value get(const CppTL::ConstString &key, const Value &defaultValue) const;
|
||||
#endif
|
||||
/// \brief Remove and return the named member.
|
||||
///
|
||||
@ -425,11 +417,9 @@ namespace Json {
|
||||
//# endif
|
||||
|
||||
/// Comments must be //... or /* ... */
|
||||
void setComment( const char *comment,
|
||||
CommentPlacement placement );
|
||||
void setComment(const char *comment, CommentPlacement placement);
|
||||
/// Comments must be //... or /* ... */
|
||||
void setComment( const std::string &comment,
|
||||
CommentPlacement placement );
|
||||
void setComment(const std::string &comment, CommentPlacement placement);
|
||||
bool hasComment(CommentPlacement placement) const;
|
||||
/// Include delimiters and embedded newlines.
|
||||
std::string getComment(CommentPlacement placement) const;
|
||||
@ -450,34 +440,22 @@ namespace Json {
|
||||
size_t getOffsetLimit() const;
|
||||
|
||||
private:
|
||||
Value &resolveReference( const char *key,
|
||||
bool isStatic );
|
||||
Value &resolveReference(const char *key, bool isStatic);
|
||||
|
||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||
inline bool isItemAvailable() const
|
||||
{
|
||||
return itemIsUsed_ == 0;
|
||||
}
|
||||
inline bool isItemAvailable() const { return itemIsUsed_ == 0; }
|
||||
|
||||
inline void setItemUsed( bool isUsed = true )
|
||||
{
|
||||
itemIsUsed_ = isUsed ? 1 : 0;
|
||||
}
|
||||
inline void setItemUsed(bool isUsed = true) { itemIsUsed_ = isUsed ? 1 : 0; }
|
||||
|
||||
inline bool isMemberNameStatic() const
|
||||
{
|
||||
return memberNameIsStatic_ == 0;
|
||||
}
|
||||
inline bool isMemberNameStatic() const { return memberNameIsStatic_ == 0; }
|
||||
|
||||
inline void setMemberNameIsStatic( bool isStatic )
|
||||
{
|
||||
inline void setMemberNameIsStatic(bool isStatic) {
|
||||
memberNameIsStatic_ = isStatic ? 1 : 0;
|
||||
}
|
||||
#endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||
|
||||
private:
|
||||
struct CommentInfo
|
||||
{
|
||||
struct CommentInfo {
|
||||
CommentInfo();
|
||||
~CommentInfo();
|
||||
|
||||
@ -495,8 +473,7 @@ namespace Json {
|
||||
// }
|
||||
//};
|
||||
|
||||
union ValueHolder
|
||||
{
|
||||
union ValueHolder {
|
||||
LargestInt int_;
|
||||
LargestUInt uint_;
|
||||
double real_;
|
||||
@ -523,11 +500,10 @@ namespace Json {
|
||||
size_t limit_;
|
||||
};
|
||||
|
||||
|
||||
/** \brief Experimental and untested: represents an element of the "path" to access a node.
|
||||
/** \brief Experimental and untested: represents an element of the "path" to
|
||||
* access a node.
|
||||
*/
|
||||
class JSON_API PathArgument
|
||||
{
|
||||
class JSON_API PathArgument {
|
||||
public:
|
||||
friend class Path;
|
||||
|
||||
@ -537,8 +513,7 @@ namespace Json {
|
||||
PathArgument(const std::string &key);
|
||||
|
||||
private:
|
||||
enum Kind
|
||||
{
|
||||
enum Kind {
|
||||
kindNone = 0,
|
||||
kindIndex,
|
||||
kindKey
|
||||
@ -559,8 +534,7 @@ namespace Json {
|
||||
* - ".%" => member name is provided as parameter
|
||||
* - ".[%]" => index is provied as parameter
|
||||
*/
|
||||
class JSON_API Path
|
||||
{
|
||||
class JSON_API Path {
|
||||
public:
|
||||
Path(const std::string &path,
|
||||
const PathArgument &a1 = PathArgument(),
|
||||
@ -570,32 +544,29 @@ namespace Json {
|
||||
const PathArgument &a5 = PathArgument());
|
||||
|
||||
const Value &resolve(const Value &root) const;
|
||||
Value resolve( const Value &root,
|
||||
const Value &defaultValue ) const;
|
||||
/// Creates the "path" to access the specified node and returns a reference on the node.
|
||||
Value resolve(const Value &root, const Value &defaultValue) const;
|
||||
/// Creates the "path" to access the specified node and returns a reference on
|
||||
/// the node.
|
||||
Value &make(Value &root) const;
|
||||
|
||||
private:
|
||||
typedef std::vector<const PathArgument *> InArgs;
|
||||
typedef std::vector<PathArgument> Args;
|
||||
|
||||
void makePath( const std::string &path,
|
||||
const InArgs &in );
|
||||
void makePath(const std::string &path, const InArgs &in);
|
||||
void addPathInArg(const std::string &path,
|
||||
const InArgs &in,
|
||||
InArgs::const_iterator &itInArg,
|
||||
PathArgument::Kind kind);
|
||||
void invalidPath( const std::string &path,
|
||||
int location );
|
||||
void invalidPath(const std::string &path, int location);
|
||||
|
||||
Args args_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||
/** \brief Allocator to customize Value internal map.
|
||||
* Below is an example of a simple implementation (default implementation actually
|
||||
* Below is an example of a simple implementation (default implementation
|
||||
actually
|
||||
* use memory pool for speed).
|
||||
* \code
|
||||
class DefaultValueMapAllocator : public ValueMapAllocator
|
||||
@ -638,8 +609,7 @@ namespace Json {
|
||||
};
|
||||
* \endcode
|
||||
*/
|
||||
class JSON_API ValueMapAllocator
|
||||
{
|
||||
class JSON_API ValueMapAllocator {
|
||||
public:
|
||||
virtual ~ValueMapAllocator();
|
||||
virtual ValueInternalMap *newMap() = 0;
|
||||
@ -654,10 +624,11 @@ namespace Json {
|
||||
/** \brief ValueInternalMap hash-map bucket chain link (for internal use only).
|
||||
* \internal previous_ & next_ allows for bidirectional traversal.
|
||||
*/
|
||||
class JSON_API ValueInternalLink
|
||||
{
|
||||
class JSON_API ValueInternalLink {
|
||||
public:
|
||||
enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture.
|
||||
enum {
|
||||
itemPerLink = 6
|
||||
}; // sizeof(ValueInternalLink) = 128 on 32 bits architecture.
|
||||
enum InternalFlags {
|
||||
flagAvailable = 0,
|
||||
flagUsed = 1
|
||||
@ -673,37 +644,34 @@ namespace Json {
|
||||
ValueInternalLink *next_;
|
||||
};
|
||||
|
||||
|
||||
/** \brief A linked page based hash-table implementation used internally by Value.
|
||||
* \internal ValueInternalMap is a tradional bucket based hash-table, with a linked
|
||||
/** \brief A linked page based hash-table implementation used internally by
|
||||
*Value.
|
||||
* \internal ValueInternalMap is a tradional bucket based hash-table, with a
|
||||
*linked
|
||||
* list in each bucket to handle collision. There is an addional twist in that
|
||||
* each node of the collision linked list is a page containing a fixed amount of
|
||||
* value. This provides a better compromise between memory usage and speed.
|
||||
*
|
||||
* Each bucket is made up of a chained list of ValueInternalLink. The last
|
||||
* link of a given bucket can be found in the 'previous_' field of the following bucket.
|
||||
* The last link of the last bucket is stored in tailLink_ as it has no following bucket.
|
||||
* Only the last link of a bucket may contains 'available' item. The last link always
|
||||
* link of a given bucket can be found in the 'previous_' field of the following
|
||||
*bucket.
|
||||
* The last link of the last bucket is stored in tailLink_ as it has no
|
||||
*following bucket.
|
||||
* Only the last link of a bucket may contains 'available' item. The last link
|
||||
*always
|
||||
* contains at least one element unless is it the bucket one very first link.
|
||||
*/
|
||||
class JSON_API ValueInternalMap
|
||||
{
|
||||
class JSON_API ValueInternalMap {
|
||||
friend class ValueIteratorBase;
|
||||
friend class Value;
|
||||
|
||||
public:
|
||||
typedef unsigned int HashKey;
|
||||
typedef unsigned int BucketIndex;
|
||||
|
||||
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||
struct IteratorState
|
||||
{
|
||||
IteratorState()
|
||||
: map_(0)
|
||||
, link_(0)
|
||||
, itemIndex_(0)
|
||||
, bucketIndex_(0)
|
||||
{
|
||||
}
|
||||
struct IteratorState {
|
||||
IteratorState() : map_(0), link_(0), itemIndex_(0), bucketIndex_(0) {}
|
||||
ValueInternalMap *map_;
|
||||
ValueInternalLink *link_;
|
||||
BucketIndex itemIndex_;
|
||||
@ -730,8 +698,7 @@ namespace Json {
|
||||
|
||||
Value *find(const char *key);
|
||||
|
||||
Value &resolveReference( const char *key,
|
||||
bool isStatic );
|
||||
Value &resolveReference(const char *key, bool isStatic);
|
||||
|
||||
void remove(const char *key);
|
||||
|
||||
@ -746,9 +713,7 @@ namespace Json {
|
||||
ValueInternalLink *link,
|
||||
BucketIndex index);
|
||||
|
||||
Value &unsafeAdd( const char *key,
|
||||
bool isStatic,
|
||||
HashKey hashedKey );
|
||||
Value &unsafeAdd(const char *key, bool isStatic, HashKey hashedKey);
|
||||
|
||||
HashKey hash(const char *key) const;
|
||||
|
||||
@ -775,33 +740,33 @@ namespace Json {
|
||||
|
||||
/** \brief A simplified deque implementation used internally by Value.
|
||||
* \internal
|
||||
* It is based on a list of fixed "page", each page contains a fixed number of items.
|
||||
* Instead of using a linked-list, a array of pointer is used for fast item look-up.
|
||||
* It is based on a list of fixed "page", each page contains a fixed number of
|
||||
*items.
|
||||
* Instead of using a linked-list, a array of pointer is used for fast item
|
||||
*look-up.
|
||||
* Look-up for an element is as follow:
|
||||
* - compute page index: pageIndex = itemIndex / itemsPerPage
|
||||
* - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage]
|
||||
*
|
||||
* Insertion is amortized constant time (only the array containing the index of pointers
|
||||
* Insertion is amortized constant time (only the array containing the index of
|
||||
*pointers
|
||||
* need to be reallocated when items are appended).
|
||||
*/
|
||||
class JSON_API ValueInternalArray
|
||||
{
|
||||
class JSON_API ValueInternalArray {
|
||||
friend class Value;
|
||||
friend class ValueIteratorBase;
|
||||
|
||||
public:
|
||||
enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo.
|
||||
enum {
|
||||
itemsPerPage = 8
|
||||
}; // should be a power of 2 for fast divide and modulo.
|
||||
typedef Value::ArrayIndex ArrayIndex;
|
||||
typedef unsigned int PageIndex;
|
||||
|
||||
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||
struct IteratorState // Must be a POD
|
||||
{
|
||||
IteratorState()
|
||||
: array_(0)
|
||||
, currentPageIndex_(0)
|
||||
, currentItemIndex_(0)
|
||||
{
|
||||
}
|
||||
IteratorState() : array_(0), currentPageIndex_(0), currentItemIndex_(0) {}
|
||||
ValueInternalArray *array_;
|
||||
Value **currentPageIndex_;
|
||||
unsigned int currentItemIndex_;
|
||||
@ -844,7 +809,8 @@ namespace Json {
|
||||
PageIndex pageCount_;
|
||||
};
|
||||
|
||||
/** \brief Experimental: do not use. Allocator to customize Value internal array.
|
||||
/** \brief Experimental: do not use. Allocator to customize Value internal
|
||||
array.
|
||||
* Below is an example of a simple implementation (actual implementation use
|
||||
* memory pool).
|
||||
\code
|
||||
@ -871,8 +837,10 @@ public: // overridden from ValueArrayAllocator
|
||||
}
|
||||
|
||||
virtual void reallocateArrayPageIndex( Value **&indexes,
|
||||
ValueInternalArray::PageIndex &indexCount,
|
||||
ValueInternalArray::PageIndex minNewIndexCount )
|
||||
ValueInternalArray::PageIndex
|
||||
&indexCount,
|
||||
ValueInternalArray::PageIndex
|
||||
minNewIndexCount )
|
||||
{
|
||||
ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
|
||||
if ( minNewIndexCount > newIndexCount )
|
||||
@ -892,7 +860,8 @@ public: // overridden from ValueArrayAllocator
|
||||
|
||||
virtual Value *allocateArrayPage()
|
||||
{
|
||||
return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );
|
||||
return static_cast<Value *>( malloc( sizeof(Value) *
|
||||
ValueInternalArray::itemsPerPage ) );
|
||||
}
|
||||
|
||||
virtual void releaseArrayPage( Value *value )
|
||||
@ -903,8 +872,7 @@ public: // overridden from ValueArrayAllocator
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
class JSON_API ValueArrayAllocator
|
||||
{
|
||||
class JSON_API ValueArrayAllocator {
|
||||
public:
|
||||
virtual ~ValueArrayAllocator();
|
||||
virtual ValueInternalArray *newArray() = 0;
|
||||
@ -918,25 +886,26 @@ public: // overridden from ValueArrayAllocator
|
||||
* \param indexCount [input] current number of pages in the index.
|
||||
* [output] number of page the reallocated index can handle.
|
||||
* \b MUST be >= \a minNewIndexCount.
|
||||
* \param minNewIndexCount Minimum number of page the new index must be able to
|
||||
* \param minNewIndexCount Minimum number of page the new index must be able
|
||||
* to
|
||||
* handle.
|
||||
*/
|
||||
virtual void reallocateArrayPageIndex( Value **&indexes,
|
||||
virtual void
|
||||
reallocateArrayPageIndex(Value **&indexes,
|
||||
ValueInternalArray::PageIndex &indexCount,
|
||||
ValueInternalArray::PageIndex minNewIndexCount) = 0;
|
||||
virtual void releaseArrayPageIndex( Value **indexes,
|
||||
virtual void
|
||||
releaseArrayPageIndex(Value **indexes,
|
||||
ValueInternalArray::PageIndex indexCount) = 0;
|
||||
virtual Value *allocateArrayPage() = 0;
|
||||
virtual void releaseArrayPage(Value *value) = 0;
|
||||
};
|
||||
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||
|
||||
|
||||
/** \brief base class for Value iterators.
|
||||
*
|
||||
*/
|
||||
class JSON_API ValueIteratorBase
|
||||
{
|
||||
class JSON_API ValueIteratorBase {
|
||||
public:
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
typedef unsigned int size_t;
|
||||
@ -951,28 +920,23 @@ public: // overridden from ValueArrayAllocator
|
||||
ValueIteratorBase(const ValueInternalMap::IteratorState &state);
|
||||
#endif
|
||||
|
||||
bool operator ==( const SelfType &other ) const
|
||||
{
|
||||
return isEqual( other );
|
||||
}
|
||||
bool operator==(const SelfType &other) const { return isEqual(other); }
|
||||
|
||||
bool operator !=( const SelfType &other ) const
|
||||
{
|
||||
return !isEqual( other );
|
||||
}
|
||||
bool operator!=(const SelfType &other) const { return !isEqual(other); }
|
||||
|
||||
difference_type operator -( const SelfType &other ) const
|
||||
{
|
||||
difference_type operator-(const SelfType &other) const {
|
||||
return computeDistance(other);
|
||||
}
|
||||
|
||||
/// Return either the index or the member name of the referenced value as a Value.
|
||||
/// Return either the index or the member name of the referenced value as a
|
||||
/// Value.
|
||||
Value key() const;
|
||||
|
||||
/// Return the index of the referenced Value. -1 if it is not an arrayValue.
|
||||
UInt index() const;
|
||||
|
||||
/// Return the member name of the referenced Value. "" if it is not an objectValue.
|
||||
/// Return the member name of the referenced Value. "" if it is not an
|
||||
/// objectValue.
|
||||
const char *memberName() const;
|
||||
|
||||
protected:
|
||||
@ -994,8 +958,7 @@ public: // overridden from ValueArrayAllocator
|
||||
// Indicates that iterator is for a null value.
|
||||
bool isNull_;
|
||||
#else
|
||||
union
|
||||
{
|
||||
union {
|
||||
ValueInternalArray::IteratorState array_;
|
||||
ValueInternalMap::IteratorState map_;
|
||||
} iterator_;
|
||||
@ -1006,9 +969,9 @@ public: // overridden from ValueArrayAllocator
|
||||
/** \brief const iterator for object and array value.
|
||||
*
|
||||
*/
|
||||
class JSON_API ValueConstIterator : public ValueIteratorBase
|
||||
{
|
||||
class JSON_API ValueConstIterator : public ValueIteratorBase {
|
||||
friend class Value;
|
||||
|
||||
public:
|
||||
typedef const Value value_type;
|
||||
typedef unsigned int size_t;
|
||||
@ -1018,6 +981,7 @@ public: // overridden from ValueArrayAllocator
|
||||
typedef ValueConstIterator SelfType;
|
||||
|
||||
ValueConstIterator();
|
||||
|
||||
private:
|
||||
/*! \internal Use by Value to create an iterator.
|
||||
*/
|
||||
@ -1030,44 +994,36 @@ public: // overridden from ValueArrayAllocator
|
||||
public:
|
||||
SelfType &operator=(const ValueIteratorBase &other);
|
||||
|
||||
SelfType operator++( int )
|
||||
{
|
||||
SelfType operator++(int) {
|
||||
SelfType temp(*this);
|
||||
++*this;
|
||||
return temp;
|
||||
}
|
||||
|
||||
SelfType operator--( int )
|
||||
{
|
||||
SelfType operator--(int) {
|
||||
SelfType temp(*this);
|
||||
--*this;
|
||||
return temp;
|
||||
}
|
||||
|
||||
SelfType &operator--()
|
||||
{
|
||||
SelfType &operator--() {
|
||||
decrement();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SelfType &operator++()
|
||||
{
|
||||
SelfType &operator++() {
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
reference operator *() const
|
||||
{
|
||||
return deref();
|
||||
}
|
||||
reference operator*() const { return deref(); }
|
||||
};
|
||||
|
||||
|
||||
/** \brief Iterator for object and array value.
|
||||
*/
|
||||
class JSON_API ValueIterator : public ValueIteratorBase
|
||||
{
|
||||
class JSON_API ValueIterator : public ValueIteratorBase {
|
||||
friend class Value;
|
||||
|
||||
public:
|
||||
typedef Value value_type;
|
||||
typedef unsigned int size_t;
|
||||
@ -1079,6 +1035,7 @@ public: // overridden from ValueArrayAllocator
|
||||
ValueIterator();
|
||||
ValueIterator(const ValueConstIterator &other);
|
||||
ValueIterator(const ValueIterator &other);
|
||||
|
||||
private:
|
||||
/*! \internal Use by Value to create an iterator.
|
||||
*/
|
||||
@ -1089,48 +1046,37 @@ public: // overridden from ValueArrayAllocator
|
||||
ValueIterator(const ValueInternalMap::IteratorState &state);
|
||||
#endif
|
||||
public:
|
||||
|
||||
SelfType &operator=(const SelfType &other);
|
||||
|
||||
SelfType operator++( int )
|
||||
{
|
||||
SelfType operator++(int) {
|
||||
SelfType temp(*this);
|
||||
++*this;
|
||||
return temp;
|
||||
}
|
||||
|
||||
SelfType operator--( int )
|
||||
{
|
||||
SelfType operator--(int) {
|
||||
SelfType temp(*this);
|
||||
--*this;
|
||||
return temp;
|
||||
}
|
||||
|
||||
SelfType &operator--()
|
||||
{
|
||||
SelfType &operator--() {
|
||||
decrement();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SelfType &operator++()
|
||||
{
|
||||
SelfType &operator++() {
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
reference operator *() const
|
||||
{
|
||||
return deref();
|
||||
}
|
||||
reference operator*() const { return deref(); }
|
||||
};
|
||||
|
||||
|
||||
} // namespace Json
|
||||
|
||||
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
#pragma warning(pop)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
|
||||
#endif // CPPTL_JSON_H_INCLUDED
|
||||
|
@ -9,6 +9,8 @@
|
||||
#define JSONCPP_VERSION_MINOR 6
|
||||
#define JSONCPP_VERSION_PATCH 0
|
||||
#define JSONCPP_VERSION_QUALIFIER -dev
|
||||
# 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))
|
||||
|
||||
#endif // JSON_VERSION_H_INCLUDED
|
||||
|
@ -12,35 +12,35 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// Disable warning C4251: <data member>: <type> needs to have dll-interface to be used by...
|
||||
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
|
||||
// be used by...
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
|
||||
namespace Json {
|
||||
|
||||
class Value;
|
||||
|
||||
/** \brief Abstract class for writers.
|
||||
*/
|
||||
class JSON_API Writer
|
||||
{
|
||||
class JSON_API Writer {
|
||||
public:
|
||||
virtual ~Writer();
|
||||
|
||||
virtual std::string write(const Value &root) = 0;
|
||||
};
|
||||
|
||||
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly).
|
||||
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format
|
||||
*without formatting (not human friendly).
|
||||
*
|
||||
* The JSON document is written in a single line. It is not intended for 'human' consumption,
|
||||
* The JSON document is written in a single line. It is not intended for 'human'
|
||||
*consumption,
|
||||
* but may be usefull to support feature such as RPC where bandwith is limited.
|
||||
* \sa Reader, Value
|
||||
*/
|
||||
class JSON_API FastWriter : public Writer
|
||||
{
|
||||
class JSON_API FastWriter : public Writer {
|
||||
public:
|
||||
FastWriter();
|
||||
virtual ~FastWriter() {}
|
||||
@ -65,26 +65,30 @@ namespace Json {
|
||||
bool dropNullPlaceholders_;
|
||||
};
|
||||
|
||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way.
|
||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
|
||||
*human friendly way.
|
||||
*
|
||||
* The rules for line break and indent are as follow:
|
||||
* - Object value:
|
||||
* - if empty then print {} without indent and line break
|
||||
* - if not empty the print '{', line break & indent, print one value per line
|
||||
* - if not empty the print '{', line break & indent, print one value per
|
||||
*line
|
||||
* and then unindent and line break and print '}'.
|
||||
* - Array value:
|
||||
* - if empty then print [] without indent and line break
|
||||
* - if the array contains no object value, empty array or some other value types,
|
||||
* and all the values fit on one lines, then print the array on a single line.
|
||||
* - if the array contains no object value, empty array or some other value
|
||||
*types,
|
||||
* and all the values fit on one lines, then print the array on a single
|
||||
*line.
|
||||
* - otherwise, it the values do not fit on one line, or the array contains
|
||||
* object or non empty array, then print one value per line.
|
||||
*
|
||||
* If the Value have comments then they are outputed according to their #CommentPlacement.
|
||||
* If the Value have comments then they are outputed according to their
|
||||
*#CommentPlacement.
|
||||
*
|
||||
* \sa Reader, Value, Value::setComment()
|
||||
*/
|
||||
class JSON_API StyledWriter: public Writer
|
||||
{
|
||||
class JSON_API StyledWriter : public Writer {
|
||||
public:
|
||||
StyledWriter();
|
||||
virtual ~StyledWriter() {}
|
||||
@ -120,28 +124,32 @@ namespace Json {
|
||||
bool addChildValues_;
|
||||
};
|
||||
|
||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way,
|
||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
|
||||
human friendly way,
|
||||
to a stream rather than to a string.
|
||||
*
|
||||
* The rules for line break and indent are as follow:
|
||||
* - Object value:
|
||||
* - if empty then print {} without indent and line break
|
||||
* - if not empty the print '{', line break & indent, print one value per line
|
||||
* - if not empty the print '{', line break & indent, print one value per
|
||||
line
|
||||
* and then unindent and line break and print '}'.
|
||||
* - Array value:
|
||||
* - if empty then print [] without indent and line break
|
||||
* - if the array contains no object value, empty array or some other value types,
|
||||
* and all the values fit on one lines, then print the array on a single line.
|
||||
* - if the array contains no object value, empty array or some other value
|
||||
types,
|
||||
* and all the values fit on one lines, then print the array on a single
|
||||
line.
|
||||
* - otherwise, it the values do not fit on one line, or the array contains
|
||||
* object or non empty array, then print one value per line.
|
||||
*
|
||||
* If the Value have comments then they are outputed according to their #CommentPlacement.
|
||||
* If the Value have comments then they are outputed according to their
|
||||
#CommentPlacement.
|
||||
*
|
||||
* \param indentation Each level will be indented by this amount extra.
|
||||
* \sa Reader, Value, Value::setComment()
|
||||
*/
|
||||
class JSON_API StyledStreamWriter
|
||||
{
|
||||
class JSON_API StyledStreamWriter {
|
||||
public:
|
||||
StyledStreamWriter(std::string indentation = "\t");
|
||||
~StyledStreamWriter() {}
|
||||
@ -150,7 +158,8 @@ namespace Json {
|
||||
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||
* \param out Stream to write to. (Can be ostringstream, e.g.)
|
||||
* \param root Value to serialize.
|
||||
* \note There is no point in deriving from Writer, since write() should not return a value.
|
||||
* \note There is no point in deriving from Writer, since write() should not
|
||||
* return a value.
|
||||
*/
|
||||
void write(std::ostream &out, const Value &root);
|
||||
|
||||
@ -194,10 +203,8 @@ namespace Json {
|
||||
|
||||
} // namespace Json
|
||||
|
||||
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
#pragma warning(pop)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
|
||||
#endif // JSON_WRITER_H_INCLUDED
|
||||
|
@ -6,7 +6,6 @@
|
||||
/* This executable is used for testing parser/writer using real JSON files.
|
||||
*/
|
||||
|
||||
|
||||
#include <json/json.h>
|
||||
#include <algorithm> // sort
|
||||
#include <stdio.h>
|
||||
@ -15,9 +14,7 @@
|
||||
#pragma warning(disable : 4996) // disable fopen deprecation warning
|
||||
#endif
|
||||
|
||||
static std::string
|
||||
normalizeFloatingPointStr( double value )
|
||||
{
|
||||
static std::string normalizeFloatingPointStr(double value) {
|
||||
char buffer[32];
|
||||
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
|
||||
sprintf_s(buffer, sizeof(buffer), "%.16g", value);
|
||||
@ -27,14 +24,16 @@ normalizeFloatingPointStr( double value )
|
||||
buffer[sizeof(buffer) - 1] = 0;
|
||||
std::string s(buffer);
|
||||
std::string::size_type index = s.find_last_of("eE");
|
||||
if ( index != std::string::npos )
|
||||
{
|
||||
std::string::size_type hasSign = (s[index+1] == '+' || s[index+1] == '-') ? 1 : 0;
|
||||
if (index != std::string::npos) {
|
||||
std::string::size_type hasSign =
|
||||
(s[index + 1] == '+' || s[index + 1] == '-') ? 1 : 0;
|
||||
std::string::size_type exponentStartIndex = index + 1 + hasSign;
|
||||
std::string normalized = s.substr(0, exponentStartIndex);
|
||||
std::string::size_type indexDigit = s.find_first_not_of( '0', exponentStartIndex );
|
||||
std::string::size_type indexDigit =
|
||||
s.find_first_not_of('0', exponentStartIndex);
|
||||
std::string exponent = "0";
|
||||
if ( indexDigit != std::string::npos ) // There is an exponent different from 0
|
||||
if (indexDigit !=
|
||||
std::string::npos) // There is an exponent different from 0
|
||||
{
|
||||
exponent = s.substr(indexDigit);
|
||||
}
|
||||
@ -43,10 +42,7 @@ normalizeFloatingPointStr( double value )
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
static std::string
|
||||
readInputTestFile( const char *path )
|
||||
{
|
||||
static std::string readInputTestFile(const char *path) {
|
||||
FILE *file = fopen(path, "rb");
|
||||
if (!file)
|
||||
return std::string("");
|
||||
@ -64,21 +60,28 @@ readInputTestFile( const char *path )
|
||||
}
|
||||
|
||||
static void
|
||||
printValueTree( FILE *fout, Json::Value &value, const std::string &path = "." )
|
||||
{
|
||||
switch ( value.type() )
|
||||
{
|
||||
printValueTree(FILE *fout, Json::Value &value, const std::string &path = ".") {
|
||||
switch (value.type()) {
|
||||
case Json::nullValue:
|
||||
fprintf(fout, "%s=null\n", path.c_str());
|
||||
break;
|
||||
case Json::intValue:
|
||||
fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asLargestInt() ).c_str() );
|
||||
fprintf(fout,
|
||||
"%s=%s\n",
|
||||
path.c_str(),
|
||||
Json::valueToString(value.asLargestInt()).c_str());
|
||||
break;
|
||||
case Json::uintValue:
|
||||
fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asLargestUInt() ).c_str() );
|
||||
fprintf(fout,
|
||||
"%s=%s\n",
|
||||
path.c_str(),
|
||||
Json::valueToString(value.asLargestUInt()).c_str());
|
||||
break;
|
||||
case Json::realValue:
|
||||
fprintf( fout, "%s=%s\n", path.c_str(), normalizeFloatingPointStr(value.asDouble()).c_str() );
|
||||
fprintf(fout,
|
||||
"%s=%s\n",
|
||||
path.c_str(),
|
||||
normalizeFloatingPointStr(value.asDouble()).c_str());
|
||||
break;
|
||||
case Json::stringValue:
|
||||
fprintf(fout, "%s=\"%s\"\n", path.c_str(), value.asString().c_str());
|
||||
@ -86,12 +89,10 @@ printValueTree( FILE *fout, Json::Value &value, const std::string &path = "." )
|
||||
case Json::booleanValue:
|
||||
fprintf(fout, "%s=%s\n", path.c_str(), value.asBool() ? "true" : "false");
|
||||
break;
|
||||
case Json::arrayValue:
|
||||
{
|
||||
case Json::arrayValue: {
|
||||
fprintf(fout, "%s=[]\n", path.c_str());
|
||||
int size = value.size();
|
||||
for ( int index =0; index < size; ++index )
|
||||
{
|
||||
for (int index = 0; index < size; ++index) {
|
||||
static char buffer[16];
|
||||
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
|
||||
sprintf_s(buffer, sizeof(buffer), "[%d]", index);
|
||||
@ -100,52 +101,42 @@ printValueTree( FILE *fout, Json::Value &value, const std::string &path = "." )
|
||||
#endif
|
||||
printValueTree(fout, value[index], path + buffer);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Json::objectValue:
|
||||
{
|
||||
} break;
|
||||
case Json::objectValue: {
|
||||
fprintf(fout, "%s={}\n", path.c_str());
|
||||
Json::Value::Members members(value.getMemberNames());
|
||||
std::sort(members.begin(), members.end());
|
||||
std::string suffix = *(path.end() - 1) == '.' ? "" : ".";
|
||||
for (Json::Value::Members::iterator it = members.begin();
|
||||
it != members.end();
|
||||
++it )
|
||||
{
|
||||
++it) {
|
||||
const std::string &name = *it;
|
||||
printValueTree(fout, value[name], path + suffix + name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
parseAndSaveValueTree( const std::string &input,
|
||||
static int parseAndSaveValueTree(const std::string &input,
|
||||
const std::string &actual,
|
||||
const std::string &kind,
|
||||
Json::Value &root,
|
||||
const Json::Features &features,
|
||||
bool parseOnly )
|
||||
{
|
||||
bool parseOnly) {
|
||||
Json::Reader reader(features);
|
||||
bool parsingSuccessful = reader.parse(input, root);
|
||||
if ( !parsingSuccessful )
|
||||
{
|
||||
if (!parsingSuccessful) {
|
||||
printf("Failed to parse %s file: \n%s\n",
|
||||
kind.c_str(),
|
||||
reader.getFormattedErrorMessages().c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( !parseOnly )
|
||||
{
|
||||
if (!parseOnly) {
|
||||
FILE *factual = fopen(actual.c_str(), "wt");
|
||||
if ( !factual )
|
||||
{
|
||||
if (!factual) {
|
||||
printf("Failed to create %s actual file.\n", kind.c_str());
|
||||
return 2;
|
||||
}
|
||||
@ -155,19 +146,15 @@ parseAndSaveValueTree( const std::string &input,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
rewriteValueTree( const std::string &rewritePath,
|
||||
static int rewriteValueTree(const std::string &rewritePath,
|
||||
const Json::Value &root,
|
||||
std::string &rewrite )
|
||||
{
|
||||
std::string &rewrite) {
|
||||
// Json::FastWriter writer;
|
||||
// writer.enableYAMLCompatibility();
|
||||
Json::StyledWriter writer;
|
||||
rewrite = writer.write(root);
|
||||
FILE *fout = fopen(rewritePath.c_str(), "wt");
|
||||
if ( !fout )
|
||||
{
|
||||
if (!fout) {
|
||||
printf("Failed to create rewrite file: %s\n", rewritePath.c_str());
|
||||
return 2;
|
||||
}
|
||||
@ -176,11 +163,8 @@ rewriteValueTree( const std::string &rewritePath,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static std::string
|
||||
removeSuffix( const std::string &path,
|
||||
const std::string &extension )
|
||||
{
|
||||
static std::string removeSuffix(const std::string &path,
|
||||
const std::string &extension) {
|
||||
if (extension.length() >= path.length())
|
||||
return std::string("");
|
||||
std::string suffix = path.substr(path.length() - extension.length());
|
||||
@ -189,10 +173,7 @@ removeSuffix( const std::string &path,
|
||||
return path.substr(0, path.length() - extension.length());
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
printConfig()
|
||||
{
|
||||
static void printConfig() {
|
||||
// Print the configuration used to compile JsonCpp
|
||||
#if defined(JSON_NO_INT64)
|
||||
printf("JSON_NO_INT64=1\n");
|
||||
@ -201,42 +182,34 @@ printConfig()
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
printUsage( const char *argv[] )
|
||||
{
|
||||
static int printUsage(const char *argv[]) {
|
||||
printf("Usage: %s [--strict] input-json-file", argv[0]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
parseCommandLine( int argc, const char *argv[],
|
||||
Json::Features &features, std::string &path,
|
||||
bool &parseOnly )
|
||||
{
|
||||
int parseCommandLine(int argc,
|
||||
const char *argv[],
|
||||
Json::Features &features,
|
||||
std::string &path,
|
||||
bool &parseOnly) {
|
||||
parseOnly = false;
|
||||
if ( argc < 2 )
|
||||
{
|
||||
if (argc < 2) {
|
||||
return printUsage(argv);
|
||||
}
|
||||
|
||||
int index = 1;
|
||||
if ( std::string(argv[1]) == "--json-checker" )
|
||||
{
|
||||
if (std::string(argv[1]) == "--json-checker") {
|
||||
features = Json::Features::strictMode();
|
||||
parseOnly = true;
|
||||
++index;
|
||||
}
|
||||
|
||||
if ( std::string(argv[1]) == "--json-config" )
|
||||
{
|
||||
if (std::string(argv[1]) == "--json-config") {
|
||||
printConfig();
|
||||
return 3;
|
||||
}
|
||||
|
||||
if ( index == argc || index + 1 < argc )
|
||||
{
|
||||
if (index == argc || index + 1 < argc) {
|
||||
return printUsage(argv);
|
||||
}
|
||||
|
||||
@ -244,31 +217,26 @@ parseCommandLine( int argc, const char *argv[],
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, const char *argv[] )
|
||||
{
|
||||
int main(int argc, const char *argv[]) {
|
||||
std::string path;
|
||||
Json::Features features;
|
||||
bool parseOnly;
|
||||
int exitCode = parseCommandLine(argc, argv, features, path, parseOnly);
|
||||
if ( exitCode != 0 )
|
||||
{
|
||||
if (exitCode != 0) {
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
std::string input = readInputTestFile(path.c_str());
|
||||
if ( input.empty() )
|
||||
{
|
||||
if (input.empty()) {
|
||||
printf("Failed to read input or empty input: %s\n", path.c_str());
|
||||
return 3;
|
||||
}
|
||||
|
||||
std::string basePath = removeSuffix(argv[1], ".json");
|
||||
if ( !parseOnly && basePath.empty() )
|
||||
{
|
||||
printf( "Bad input path. Path does not end with '.expected':\n%s\n", path.c_str() );
|
||||
if (!parseOnly && basePath.empty()) {
|
||||
printf("Bad input path. Path does not end with '.expected':\n%s\n",
|
||||
path.c_str());
|
||||
return 3;
|
||||
}
|
||||
|
||||
@ -277,21 +245,23 @@ int main( int argc, const char *argv[] )
|
||||
std::string rewriteActualPath = basePath + ".actual-rewrite";
|
||||
|
||||
Json::Value root;
|
||||
exitCode = parseAndSaveValueTree( input, actualPath, "input", root, features, parseOnly );
|
||||
if ( exitCode == 0 && !parseOnly )
|
||||
{
|
||||
exitCode = parseAndSaveValueTree(
|
||||
input, actualPath, "input", root, features, parseOnly);
|
||||
if (exitCode == 0 && !parseOnly) {
|
||||
std::string rewrite;
|
||||
exitCode = rewriteValueTree(rewritePath, root, rewrite);
|
||||
if ( exitCode == 0 )
|
||||
{
|
||||
if (exitCode == 0) {
|
||||
Json::Value rewriteRoot;
|
||||
exitCode = parseAndSaveValueTree( rewrite, rewriteActualPath,
|
||||
"rewrite", rewriteRoot, features, parseOnly );
|
||||
exitCode = parseAndSaveValueTree(rewrite,
|
||||
rewriteActualPath,
|
||||
"rewrite",
|
||||
rewriteRoot,
|
||||
features,
|
||||
parseOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( const std::exception &e )
|
||||
{
|
||||
catch (const std::exception &e) {
|
||||
printf("Unhandled exception:\n%s\n", e.what());
|
||||
exitCode = 1;
|
||||
}
|
||||
|
@ -18,33 +18,33 @@ namespace Json {
|
||||
* This memory allocator allocates memory for a batch of object (specified by
|
||||
* the page size, the number of object in each page).
|
||||
*
|
||||
* It does not allow the destruction of a single object. All the allocated objects
|
||||
* can be destroyed at once. The memory can be either released or reused for future
|
||||
* It does not allow the destruction of a single object. All the allocated
|
||||
*objects
|
||||
* can be destroyed at once. The memory can be either released or reused for
|
||||
*future
|
||||
* allocation.
|
||||
*
|
||||
* The in-place new operator must be used to construct the object using the pointer
|
||||
* The in-place new operator must be used to construct the object using the
|
||||
*pointer
|
||||
* returned by allocate.
|
||||
*/
|
||||
template<typename AllocatedType
|
||||
,const unsigned int objectPerAllocation>
|
||||
class BatchAllocator
|
||||
{
|
||||
template <typename AllocatedType, const unsigned int objectPerAllocation>
|
||||
class BatchAllocator {
|
||||
public:
|
||||
BatchAllocator(unsigned int objectsPerPage = 255)
|
||||
: freeHead_( 0 )
|
||||
, objectsPerPage_( objectsPerPage )
|
||||
{
|
||||
// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
|
||||
assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.
|
||||
: freeHead_(0), objectsPerPage_(objectsPerPage) {
|
||||
// printf( "Size: %d => %s\n", sizeof(AllocatedType),
|
||||
// typeid(AllocatedType).name() );
|
||||
assert(sizeof(AllocatedType) * objectPerAllocation >=
|
||||
sizeof(AllocatedType *)); // We must be able to store a slist in the
|
||||
// object free space.
|
||||
assert(objectsPerPage >= 16);
|
||||
batches_ = allocateBatch(0); // allocated a dummy page
|
||||
currentBatch_ = batches_;
|
||||
}
|
||||
|
||||
~BatchAllocator()
|
||||
{
|
||||
for ( BatchInfo *batch = batches_; batch; )
|
||||
{
|
||||
~BatchAllocator() {
|
||||
for (BatchInfo *batch = batches_; batch;) {
|
||||
BatchInfo *nextBatch = batch->next_;
|
||||
free(batch);
|
||||
batch = nextBatch;
|
||||
@ -52,17 +52,16 @@ public:
|
||||
}
|
||||
|
||||
/// allocate space for an array of objectPerAllocation object.
|
||||
/// @warning it is the responsability of the caller to call objects constructors.
|
||||
AllocatedType *allocate()
|
||||
{
|
||||
/// @warning it is the responsability of the caller to call objects
|
||||
/// constructors.
|
||||
AllocatedType *allocate() {
|
||||
if (freeHead_) // returns node from free list.
|
||||
{
|
||||
AllocatedType *object = freeHead_;
|
||||
freeHead_ = *(AllocatedType **)object;
|
||||
return object;
|
||||
}
|
||||
if ( currentBatch_->used_ == currentBatch_->end_ )
|
||||
{
|
||||
if (currentBatch_->used_ == currentBatch_->end_) {
|
||||
currentBatch_ = currentBatch_->next_;
|
||||
while (currentBatch_ && currentBatch_->used_ == currentBatch_->end_)
|
||||
currentBatch_ = currentBatch_->next_;
|
||||
@ -80,17 +79,16 @@ public:
|
||||
}
|
||||
|
||||
/// Release the object.
|
||||
/// @warning it is the responsability of the caller to actually destruct the object.
|
||||
void release( AllocatedType *object )
|
||||
{
|
||||
/// @warning it is the responsability of the caller to actually destruct the
|
||||
/// object.
|
||||
void release(AllocatedType *object) {
|
||||
assert(object != 0);
|
||||
*(AllocatedType **)object = freeHead_;
|
||||
freeHead_ = object;
|
||||
}
|
||||
|
||||
private:
|
||||
struct BatchInfo
|
||||
{
|
||||
struct BatchInfo {
|
||||
BatchInfo *next_;
|
||||
AllocatedType *used_;
|
||||
AllocatedType *end_;
|
||||
@ -101,10 +99,10 @@ private:
|
||||
BatchAllocator(const BatchAllocator &);
|
||||
void operator=(const BatchAllocator &);
|
||||
|
||||
static BatchInfo *allocateBatch( unsigned int objectsPerPage )
|
||||
{
|
||||
const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation
|
||||
+ sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
|
||||
static BatchInfo *allocateBatch(unsigned int objectsPerPage) {
|
||||
const unsigned int mallocSize =
|
||||
sizeof(BatchInfo) - sizeof(AllocatedType) * objectPerAllocation +
|
||||
sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
|
||||
BatchInfo *batch = static_cast<BatchInfo *>(malloc(mallocSize));
|
||||
batch->next_ = 0;
|
||||
batch->used_ = batch->buffer_;
|
||||
@ -119,7 +117,6 @@ private:
|
||||
unsigned int objectsPerPage_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
|
||||
|
@ -16,7 +16,8 @@
|
||||
#include <istream>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
|
||||
#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
|
||||
#pragma warning(disable \
|
||||
: 4996) // disable warning about strdup being deprecated.
|
||||
#endif
|
||||
|
||||
namespace Json {
|
||||
@ -25,24 +26,12 @@ namespace Json {
|
||||
// ////////////////////////////////
|
||||
|
||||
Features::Features()
|
||||
: allowComments_( true )
|
||||
, strictRoot_( false )
|
||||
, allowDroppedNullPlaceholders_ ( false )
|
||||
, allowNumericKeys_ ( 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.allowComments_ = false;
|
||||
features.strictRoot_ = true;
|
||||
@ -54,81 +43,52 @@ Features::strictMode()
|
||||
// Implementation of class Reader
|
||||
// ////////////////////////////////
|
||||
|
||||
|
||||
static inline bool
|
||||
in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
|
||||
{
|
||||
static inline bool in(Reader::Char c,
|
||||
Reader::Char c1,
|
||||
Reader::Char c2,
|
||||
Reader::Char c3,
|
||||
Reader::Char c4) {
|
||||
return c == c1 || c == c2 || c == c3 || c == c4;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 )
|
||||
{
|
||||
static inline bool in(Reader::Char c,
|
||||
Reader::Char c1,
|
||||
Reader::Char c2,
|
||||
Reader::Char c3,
|
||||
Reader::Char c4,
|
||||
Reader::Char c5) {
|
||||
return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
containsNewLine( Reader::Location begin,
|
||||
Reader::Location end )
|
||||
{
|
||||
static bool containsNewLine(Reader::Location begin, Reader::Location end) {
|
||||
for (; begin < end; ++begin)
|
||||
if (*begin == '\n' || *begin == '\r')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Class Reader
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
Reader::Reader()
|
||||
: errors_(),
|
||||
document_(),
|
||||
begin_(),
|
||||
end_(),
|
||||
current_(),
|
||||
lastValueEnd_(),
|
||||
lastValue_(),
|
||||
commentsBefore_(),
|
||||
features_( Features::all() ),
|
||||
collectComments_()
|
||||
{
|
||||
}
|
||||
|
||||
: errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
|
||||
lastValue_(), commentsBefore_(), features_(Features::all()),
|
||||
collectComments_() {}
|
||||
|
||||
Reader::Reader(const Features &features)
|
||||
: errors_(),
|
||||
document_(),
|
||||
begin_(),
|
||||
end_(),
|
||||
current_(),
|
||||
lastValueEnd_(),
|
||||
lastValue_(),
|
||||
commentsBefore_(),
|
||||
features_( features ),
|
||||
collectComments_()
|
||||
{
|
||||
: errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
|
||||
lastValue_(), commentsBefore_(), features_(features), collectComments_() {
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::parse( const std::string &document,
|
||||
Value &root,
|
||||
bool collectComments )
|
||||
{
|
||||
Reader::parse(const std::string &document, Value &root, bool collectComments) {
|
||||
document_ = document;
|
||||
const char *begin = document_.c_str();
|
||||
const char *end = begin + document_.length();
|
||||
return parse(begin, end, root, collectComments);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::parse( std::istream& sin,
|
||||
Value &root,
|
||||
bool collectComments )
|
||||
{
|
||||
bool Reader::parse(std::istream &sin, Value &root, bool collectComments) {
|
||||
// std::istream_iterator<char> begin(sin);
|
||||
// std::istream_iterator<char> end;
|
||||
// Those would allow streamed input from a file, if parse() were a
|
||||
@ -141,13 +101,11 @@ Reader::parse( std::istream& sin,
|
||||
return parse(doc, root, collectComments);
|
||||
}
|
||||
|
||||
bool
|
||||
Reader::parse( const char *beginDoc, const char *endDoc,
|
||||
bool Reader::parse(const char *beginDoc,
|
||||
const char *endDoc,
|
||||
Value &root,
|
||||
bool collectComments )
|
||||
{
|
||||
if ( !features_.allowComments_ )
|
||||
{
|
||||
bool collectComments) {
|
||||
if (!features_.allowComments_) {
|
||||
collectComments = false;
|
||||
}
|
||||
|
||||
@ -168,15 +126,15 @@ Reader::parse( const char *beginDoc, const char *endDoc,
|
||||
skipCommentTokens(token);
|
||||
if (collectComments_ && !commentsBefore_.empty())
|
||||
root.setComment(commentsBefore_, commentAfter);
|
||||
if ( features_.strictRoot_ )
|
||||
{
|
||||
if ( !root.isArray() && !root.isObject() )
|
||||
{
|
||||
// Set error location to start of doc, ideally should be first token found in doc
|
||||
if (features_.strictRoot_) {
|
||||
if (!root.isArray() && !root.isObject()) {
|
||||
// Set error location to start of doc, ideally should be first token found
|
||||
// in doc
|
||||
token.type_ = tokenError;
|
||||
token.start_ = beginDoc;
|
||||
token.end_ = endDoc;
|
||||
addError( "A valid JSON document must be either an array or an object value.",
|
||||
addError(
|
||||
"A valid JSON document must be either an array or an object value.",
|
||||
token);
|
||||
return false;
|
||||
}
|
||||
@ -184,24 +142,17 @@ Reader::parse( const char *beginDoc, const char *endDoc,
|
||||
return successful;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readValue()
|
||||
{
|
||||
bool Reader::readValue() {
|
||||
Token token;
|
||||
skipCommentTokens(token);
|
||||
bool successful = true;
|
||||
|
||||
if ( collectComments_ && !commentsBefore_.empty() )
|
||||
{
|
||||
if (collectComments_ && !commentsBefore_.empty()) {
|
||||
// Remove newline characters at the end of the comments
|
||||
size_t lastNonNewline = commentsBefore_.find_last_not_of("\r\n");
|
||||
if (lastNonNewline != std::string::npos)
|
||||
{
|
||||
if (lastNonNewline != std::string::npos) {
|
||||
commentsBefore_.erase(lastNonNewline + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
commentsBefore_.clear();
|
||||
}
|
||||
|
||||
@ -209,9 +160,7 @@ Reader::readValue()
|
||||
commentsBefore_ = "";
|
||||
}
|
||||
|
||||
|
||||
switch ( token.type_ )
|
||||
{
|
||||
switch (token.type_) {
|
||||
case tokenObjectBegin:
|
||||
successful = readObject(token);
|
||||
currentValue().setOffsetLimit(current_ - begin_);
|
||||
@ -242,8 +191,7 @@ Reader::readValue()
|
||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||
break;
|
||||
case tokenArraySeparator:
|
||||
if ( features_.allowDroppedNullPlaceholders_ )
|
||||
{
|
||||
if (features_.allowDroppedNullPlaceholders_) {
|
||||
// "Un-read" the current token and mark the current value as a null
|
||||
// token.
|
||||
current_--;
|
||||
@ -259,8 +207,7 @@ Reader::readValue()
|
||||
return addError("Syntax error: value, object or array expected.", token);
|
||||
}
|
||||
|
||||
if ( collectComments_ )
|
||||
{
|
||||
if (collectComments_) {
|
||||
lastValueEnd_ = current_;
|
||||
lastValue_ = ¤tValue();
|
||||
}
|
||||
@ -268,44 +215,29 @@ Reader::readValue()
|
||||
return successful;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Reader::skipCommentTokens( Token &token )
|
||||
{
|
||||
if ( features_.allowComments_ )
|
||||
{
|
||||
do
|
||||
{
|
||||
void Reader::skipCommentTokens(Token &token) {
|
||||
if (features_.allowComments_) {
|
||||
do {
|
||||
readToken(token);
|
||||
}
|
||||
while ( token.type_ == tokenComment );
|
||||
}
|
||||
else
|
||||
{
|
||||
} while (token.type_ == tokenComment);
|
||||
} else {
|
||||
readToken(token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::expectToken( TokenType type, Token &token, const char *message )
|
||||
{
|
||||
bool Reader::expectToken(TokenType type, Token &token, const char *message) {
|
||||
readToken(token);
|
||||
if (token.type_ != type)
|
||||
return addError(message, token);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readToken( Token &token )
|
||||
{
|
||||
bool Reader::readToken(Token &token) {
|
||||
skipSpaces();
|
||||
token.start_ = current_;
|
||||
Char c = getNextChar();
|
||||
bool ok = true;
|
||||
switch ( c )
|
||||
{
|
||||
switch (c) {
|
||||
case '{':
|
||||
token.type_ = tokenObjectBegin;
|
||||
break;
|
||||
@ -371,12 +303,8 @@ Reader::readToken( Token &token )
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Reader::skipSpaces()
|
||||
{
|
||||
while ( current_ != end_ )
|
||||
{
|
||||
void Reader::skipSpaces() {
|
||||
while (current_ != end_) {
|
||||
Char c = *current_;
|
||||
if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
|
||||
++current_;
|
||||
@ -385,11 +313,7 @@ Reader::skipSpaces()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::match( Location pattern,
|
||||
int patternLength )
|
||||
{
|
||||
bool Reader::match(Location pattern, int patternLength) {
|
||||
if (end_ - current_ < patternLength)
|
||||
return false;
|
||||
int index = patternLength;
|
||||
@ -400,10 +324,7 @@ Reader::match( Location pattern,
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readComment()
|
||||
{
|
||||
bool Reader::readComment() {
|
||||
Location commentBegin = current_ - 1;
|
||||
Char c = getNextChar();
|
||||
bool successful = false;
|
||||
@ -414,11 +335,9 @@ Reader::readComment()
|
||||
if (!successful)
|
||||
return false;
|
||||
|
||||
if ( collectComments_ )
|
||||
{
|
||||
if (collectComments_) {
|
||||
CommentPlacement placement = commentBefore;
|
||||
if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) )
|
||||
{
|
||||
if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
|
||||
if (c != '*' || !containsNewLine(commentBegin, current_))
|
||||
placement = commentAfterOnSameLine;
|
||||
}
|
||||
@ -428,32 +347,21 @@ Reader::readComment()
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Reader::addComment( Location begin,
|
||||
Location end,
|
||||
CommentPlacement placement )
|
||||
{
|
||||
Reader::addComment(Location begin, Location end, CommentPlacement placement) {
|
||||
assert(collectComments_);
|
||||
if ( placement == commentAfterOnSameLine )
|
||||
{
|
||||
if (placement == commentAfterOnSameLine) {
|
||||
assert(lastValue_ != 0);
|
||||
lastValue_->setComment(std::string(begin, end), placement);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
if (!commentsBefore_.empty())
|
||||
commentsBefore_ += "\n";
|
||||
commentsBefore_ += std::string(begin, end);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readCStyleComment()
|
||||
{
|
||||
while ( current_ != end_ )
|
||||
{
|
||||
bool Reader::readCStyleComment() {
|
||||
while (current_ != end_) {
|
||||
Char c = getNextChar();
|
||||
if (c == '*' && *current_ == '/')
|
||||
break;
|
||||
@ -461,12 +369,8 @@ Reader::readCStyleComment()
|
||||
return getNextChar() == '/';
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readCppStyleComment()
|
||||
{
|
||||
while ( current_ != end_ )
|
||||
{
|
||||
bool Reader::readCppStyleComment() {
|
||||
while (current_ != end_) {
|
||||
Char c = getNextChar();
|
||||
if (c == '\r' || c == '\n')
|
||||
break;
|
||||
@ -474,12 +378,8 @@ Reader::readCppStyleComment()
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Reader::readNumber()
|
||||
{
|
||||
while ( current_ != end_ )
|
||||
{
|
||||
void Reader::readNumber() {
|
||||
while (current_ != end_) {
|
||||
if (!(*current_ >= '0' && *current_ <= '9') &&
|
||||
!in(*current_, '.', 'e', 'E', '+', '-'))
|
||||
break;
|
||||
@ -487,12 +387,9 @@ Reader::readNumber()
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Reader::readString()
|
||||
{
|
||||
bool Reader::readString() {
|
||||
Char c = 0;
|
||||
while ( current_ != end_ )
|
||||
{
|
||||
while (current_ != end_) {
|
||||
c = getNextChar();
|
||||
if (c == '\\')
|
||||
getNextChar();
|
||||
@ -502,16 +399,12 @@ Reader::readString()
|
||||
return c == '"';
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readObject( Token &tokenStart )
|
||||
{
|
||||
bool Reader::readObject(Token &tokenStart) {
|
||||
Token tokenName;
|
||||
std::string name;
|
||||
currentValue() = Value(objectValue);
|
||||
currentValue().setOffsetStart(tokenStart.start_ - begin_);
|
||||
while ( readToken( tokenName ) )
|
||||
{
|
||||
while (readToken(tokenName)) {
|
||||
bool initialTokenOk = true;
|
||||
while (tokenName.type_ == tokenComment && initialTokenOk)
|
||||
initialTokenOk = readToken(tokenName);
|
||||
@ -520,30 +413,22 @@ Reader::readObject( Token &tokenStart )
|
||||
if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
|
||||
return true;
|
||||
name = "";
|
||||
if ( tokenName.type_ == tokenString )
|
||||
{
|
||||
if (tokenName.type_ == tokenString) {
|
||||
if (!decodeString(tokenName, name))
|
||||
return recoverFromError(tokenObjectEnd);
|
||||
}
|
||||
else if ( tokenName.type_ == tokenNumber &&
|
||||
features_.allowNumericKeys_ )
|
||||
{
|
||||
} else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
|
||||
Value numberName;
|
||||
if (!decodeNumber(tokenName, numberName))
|
||||
return recoverFromError(tokenObjectEnd);
|
||||
name = numberName.asString();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
Token colon;
|
||||
if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator )
|
||||
{
|
||||
return addErrorAndRecover( "Missing ':' after object member name",
|
||||
colon,
|
||||
tokenObjectEnd );
|
||||
if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
|
||||
return addErrorAndRecover(
|
||||
"Missing ':' after object member name", colon, tokenObjectEnd);
|
||||
}
|
||||
Value &value = currentValue()[name];
|
||||
nodes_.push(&value);
|
||||
@ -553,31 +438,23 @@ Reader::readObject( Token &tokenStart )
|
||||
return recoverFromError(tokenObjectEnd);
|
||||
|
||||
Token comma;
|
||||
if ( !readToken( comma )
|
||||
|| ( comma.type_ != tokenObjectEnd &&
|
||||
comma.type_ != tokenArraySeparator &&
|
||||
comma.type_ != tokenComment ) )
|
||||
{
|
||||
return addErrorAndRecover( "Missing ',' or '}' in object declaration",
|
||||
comma,
|
||||
tokenObjectEnd );
|
||||
if (!readToken(comma) ||
|
||||
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
|
||||
comma.type_ != tokenComment)) {
|
||||
return addErrorAndRecover(
|
||||
"Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
|
||||
}
|
||||
bool finalizeTokenOk = true;
|
||||
while ( comma.type_ == tokenComment &&
|
||||
finalizeTokenOk )
|
||||
while (comma.type_ == tokenComment && finalizeTokenOk)
|
||||
finalizeTokenOk = readToken(comma);
|
||||
if (comma.type_ == tokenObjectEnd)
|
||||
return true;
|
||||
}
|
||||
return addErrorAndRecover( "Missing '}' or object member name",
|
||||
tokenName,
|
||||
tokenObjectEnd );
|
||||
return addErrorAndRecover(
|
||||
"Missing '}' or object member name", tokenName, tokenObjectEnd);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readArray( Token &tokenStart )
|
||||
{
|
||||
bool Reader::readArray(Token &tokenStart) {
|
||||
currentValue() = Value(arrayValue);
|
||||
currentValue().setOffsetStart(tokenStart.start_ - begin_);
|
||||
skipSpaces();
|
||||
@ -588,8 +465,7 @@ Reader::readArray( Token &tokenStart )
|
||||
return true;
|
||||
}
|
||||
int index = 0;
|
||||
for (;;)
|
||||
{
|
||||
for (;;) {
|
||||
Value &value = currentValue()[index++];
|
||||
nodes_.push(&value);
|
||||
bool ok = readValue();
|
||||
@ -600,17 +476,14 @@ Reader::readArray( Token &tokenStart )
|
||||
Token token;
|
||||
// Accept Comment after last item in the array.
|
||||
ok = readToken(token);
|
||||
while ( token.type_ == tokenComment && ok )
|
||||
{
|
||||
while (token.type_ == tokenComment && ok) {
|
||||
ok = readToken(token);
|
||||
}
|
||||
bool badTokenType = ( token.type_ != tokenArraySeparator &&
|
||||
token.type_ != tokenArrayEnd );
|
||||
if ( !ok || badTokenType )
|
||||
{
|
||||
return addErrorAndRecover( "Missing ',' or ']' in array declaration",
|
||||
token,
|
||||
tokenArrayEnd );
|
||||
bool badTokenType =
|
||||
(token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
|
||||
if (!ok || badTokenType) {
|
||||
return addErrorAndRecover(
|
||||
"Missing ',' or ']' in array declaration", token, tokenArrayEnd);
|
||||
}
|
||||
if (token.type_ == tokenArrayEnd)
|
||||
break;
|
||||
@ -618,10 +491,7 @@ Reader::readArray( Token &tokenStart )
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::decodeNumber( Token &token )
|
||||
{
|
||||
bool Reader::decodeNumber(Token &token) {
|
||||
Value decoded;
|
||||
if (!decodeNumber(token, decoded))
|
||||
return false;
|
||||
@ -631,16 +501,11 @@ Reader::decodeNumber( Token &token )
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::decodeNumber( Token &token, Value &decoded )
|
||||
{
|
||||
bool Reader::decodeNumber(Token &token, Value &decoded) {
|
||||
bool isDouble = false;
|
||||
for ( Location inspect = token.start_; inspect != token.end_; ++inspect )
|
||||
{
|
||||
isDouble = isDouble
|
||||
|| in( *inspect, '.', 'e', 'E', '+' )
|
||||
|| ( *inspect == '-' && inspect != token.start_ );
|
||||
for (Location inspect = token.start_; inspect != token.end_; ++inspect) {
|
||||
isDouble = isDouble || in(*inspect, '.', 'e', 'E', '+') ||
|
||||
(*inspect == '-' && inspect != token.start_);
|
||||
}
|
||||
if (isDouble)
|
||||
return decodeDouble(token, decoded);
|
||||
@ -651,26 +516,25 @@ Reader::decodeNumber( Token &token, Value &decoded )
|
||||
bool isNegative = *current == '-';
|
||||
if (isNegative)
|
||||
++current;
|
||||
Value::LargestUInt maxIntegerValue = isNegative ? Value::LargestUInt(-Value::minLargestInt)
|
||||
Value::LargestUInt maxIntegerValue =
|
||||
isNegative ? Value::LargestUInt(-Value::minLargestInt)
|
||||
: Value::maxLargestUInt;
|
||||
Value::LargestUInt threshold = maxIntegerValue / 10;
|
||||
Value::LargestUInt value = 0;
|
||||
while ( current < token.end_ )
|
||||
{
|
||||
while (current < token.end_) {
|
||||
Char c = *current++;
|
||||
if (c < '0' || c > '9')
|
||||
return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
|
||||
return addError("'" + std::string(token.start_, token.end_) +
|
||||
"' is not a number.",
|
||||
token);
|
||||
Value::UInt digit(c - '0');
|
||||
if ( value >= threshold )
|
||||
{
|
||||
if (value >= threshold) {
|
||||
// We've hit or exceeded the max value divided by 10 (rounded down). If
|
||||
// a) we've only just touched the limit, b) this is the last digit, and
|
||||
// c) it's small enough to fit in that rounding delta, we're okay.
|
||||
// Otherwise treat this number as a double to avoid overflow.
|
||||
if (value > threshold ||
|
||||
current != token.end_ ||
|
||||
digit > maxIntegerValue % 10)
|
||||
{
|
||||
if (value > threshold || current != token.end_ ||
|
||||
digit > maxIntegerValue % 10) {
|
||||
return decodeDouble(token, decoded);
|
||||
}
|
||||
}
|
||||
@ -685,10 +549,7 @@ Reader::decodeNumber( Token &token, Value &decoded )
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::decodeDouble( Token &token )
|
||||
{
|
||||
bool Reader::decodeDouble(Token &token) {
|
||||
Value decoded;
|
||||
if (!decodeDouble(token, decoded))
|
||||
return false;
|
||||
@ -698,10 +559,7 @@ Reader::decodeDouble( Token &token )
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::decodeDouble( Token &token, Value &decoded )
|
||||
{
|
||||
bool Reader::decodeDouble(Token &token, Value &decoded) {
|
||||
double value = 0;
|
||||
const int bufferSize = 32;
|
||||
int count;
|
||||
@ -719,29 +577,25 @@ Reader::decodeDouble( Token &token, Value &decoded )
|
||||
// http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
|
||||
char format[] = "%lf";
|
||||
|
||||
if ( length <= bufferSize )
|
||||
{
|
||||
if (length <= bufferSize) {
|
||||
Char buffer[bufferSize + 1];
|
||||
memcpy(buffer, token.start_, length);
|
||||
buffer[length] = 0;
|
||||
count = sscanf(buffer, format, &value);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
std::string buffer(token.start_, token.end_);
|
||||
count = sscanf(buffer.c_str(), format, &value);
|
||||
}
|
||||
|
||||
if (count != 1)
|
||||
return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
|
||||
return addError("'" + std::string(token.start_, token.end_) +
|
||||
"' is not a number.",
|
||||
token);
|
||||
decoded = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::decodeString( Token &token )
|
||||
{
|
||||
bool Reader::decodeString(Token &token) {
|
||||
std::string decoded;
|
||||
if (!decodeString(token, decoded))
|
||||
return false;
|
||||
@ -751,94 +605,99 @@ Reader::decodeString( Token &token )
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::decodeString( Token &token, std::string &decoded )
|
||||
{
|
||||
bool Reader::decodeString(Token &token, std::string &decoded) {
|
||||
decoded.reserve(token.end_ - token.start_ - 2);
|
||||
Location current = token.start_ + 1; // skip '"'
|
||||
Location end = token.end_ - 1; // do not include '"'
|
||||
while ( current != end )
|
||||
{
|
||||
while (current != end) {
|
||||
Char c = *current++;
|
||||
if (c == '"')
|
||||
break;
|
||||
else if ( c == '\\' )
|
||||
{
|
||||
else if (c == '\\') {
|
||||
if (current == end)
|
||||
return addError("Empty escape sequence in string", token, current);
|
||||
Char escape = *current++;
|
||||
switch ( escape )
|
||||
{
|
||||
case '"': decoded += '"'; break;
|
||||
case '/': decoded += '/'; break;
|
||||
case '\\': decoded += '\\'; break;
|
||||
case 'b': decoded += '\b'; break;
|
||||
case 'f': decoded += '\f'; break;
|
||||
case 'n': decoded += '\n'; break;
|
||||
case 'r': decoded += '\r'; break;
|
||||
case 't': decoded += '\t'; break;
|
||||
case 'u':
|
||||
{
|
||||
switch (escape) {
|
||||
case '"':
|
||||
decoded += '"';
|
||||
break;
|
||||
case '/':
|
||||
decoded += '/';
|
||||
break;
|
||||
case '\\':
|
||||
decoded += '\\';
|
||||
break;
|
||||
case 'b':
|
||||
decoded += '\b';
|
||||
break;
|
||||
case 'f':
|
||||
decoded += '\f';
|
||||
break;
|
||||
case 'n':
|
||||
decoded += '\n';
|
||||
break;
|
||||
case 'r':
|
||||
decoded += '\r';
|
||||
break;
|
||||
case 't':
|
||||
decoded += '\t';
|
||||
break;
|
||||
case 'u': {
|
||||
unsigned int unicode;
|
||||
if (!decodeUnicodeCodePoint(token, current, end, unicode))
|
||||
return false;
|
||||
decoded += codePointToUTF8(unicode);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
default:
|
||||
return addError("Bad escape sequence in string", token, current);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
decoded += c;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Reader::decodeUnicodeCodePoint( Token &token,
|
||||
bool Reader::decodeUnicodeCodePoint(Token &token,
|
||||
Location ¤t,
|
||||
Location end,
|
||||
unsigned int &unicode )
|
||||
{
|
||||
unsigned int &unicode) {
|
||||
|
||||
if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
|
||||
return false;
|
||||
if (unicode >= 0xD800 && unicode <= 0xDBFF)
|
||||
{
|
||||
if (unicode >= 0xD800 && unicode <= 0xDBFF) {
|
||||
// surrogate pairs
|
||||
if (end - current < 6)
|
||||
return addError( "additional six characters expected to parse unicode surrogate pair.", token, current );
|
||||
return addError(
|
||||
"additional six characters expected to parse unicode surrogate pair.",
|
||||
token,
|
||||
current);
|
||||
unsigned int surrogatePair;
|
||||
if (*(current++) == '\\' && *(current++)== 'u')
|
||||
{
|
||||
if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))
|
||||
{
|
||||
if (*(current++) == '\\' && *(current++) == 'u') {
|
||||
if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
|
||||
unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
|
||||
}
|
||||
else
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current );
|
||||
} else
|
||||
return addError("expecting another \\u token to begin the second half of "
|
||||
"a unicode surrogate pair",
|
||||
token,
|
||||
current);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Reader::decodeUnicodeEscapeSequence( Token &token,
|
||||
bool Reader::decodeUnicodeEscapeSequence(Token &token,
|
||||
Location ¤t,
|
||||
Location end,
|
||||
unsigned int &unicode )
|
||||
{
|
||||
unsigned int &unicode) {
|
||||
if (end - current < 4)
|
||||
return addError( "Bad unicode escape sequence in string: four digits expected.", token, current );
|
||||
return addError(
|
||||
"Bad unicode escape sequence in string: four digits expected.",
|
||||
token,
|
||||
current);
|
||||
unicode = 0;
|
||||
for ( int index =0; index < 4; ++index )
|
||||
{
|
||||
for (int index = 0; index < 4; ++index) {
|
||||
Char c = *current++;
|
||||
unicode *= 16;
|
||||
if (c >= '0' && c <= '9')
|
||||
@ -848,17 +707,16 @@ Reader::decodeUnicodeEscapeSequence( Token &token,
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
unicode += c - 'A' + 10;
|
||||
else
|
||||
return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current );
|
||||
return addError(
|
||||
"Bad unicode escape sequence in string: hexadecimal digit expected.",
|
||||
token,
|
||||
current);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::addError( const std::string &message,
|
||||
Token &token,
|
||||
Location extra )
|
||||
{
|
||||
Reader::addError(const std::string &message, Token &token, Location extra) {
|
||||
ErrorInfo info;
|
||||
info.token_ = token;
|
||||
info.message_ = message;
|
||||
@ -867,14 +725,10 @@ Reader::addError( const std::string &message,
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::recoverFromError( TokenType skipUntilToken )
|
||||
{
|
||||
bool Reader::recoverFromError(TokenType skipUntilToken) {
|
||||
int errorCount = int(errors_.size());
|
||||
Token skip;
|
||||
for (;;)
|
||||
{
|
||||
for (;;) {
|
||||
if (!readToken(skip))
|
||||
errors_.resize(errorCount); // discard errors caused by recovery
|
||||
if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
|
||||
@ -884,53 +738,35 @@ Reader::recoverFromError( TokenType skipUntilToken )
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::addErrorAndRecover( const std::string &message,
|
||||
bool Reader::addErrorAndRecover(const std::string &message,
|
||||
Token &token,
|
||||
TokenType skipUntilToken )
|
||||
{
|
||||
TokenType skipUntilToken) {
|
||||
addError(message, token);
|
||||
return recoverFromError(skipUntilToken);
|
||||
}
|
||||
|
||||
Value &Reader::currentValue() { return *(nodes_.top()); }
|
||||
|
||||
Value &
|
||||
Reader::currentValue()
|
||||
{
|
||||
return *(nodes_.top());
|
||||
}
|
||||
|
||||
|
||||
Reader::Char
|
||||
Reader::getNextChar()
|
||||
{
|
||||
Reader::Char Reader::getNextChar() {
|
||||
if (current_ == end_)
|
||||
return 0;
|
||||
return *current_++;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Reader::getLocationLineAndColumn( Location location,
|
||||
void Reader::getLocationLineAndColumn(Location location,
|
||||
int &line,
|
||||
int &column ) const
|
||||
{
|
||||
int &column) const {
|
||||
Location current = begin_;
|
||||
Location lastLineStart = current;
|
||||
line = 0;
|
||||
while ( current < location && current != end_ )
|
||||
{
|
||||
while (current < location && current != end_) {
|
||||
Char c = *current++;
|
||||
if ( c == '\r' )
|
||||
{
|
||||
if (c == '\r') {
|
||||
if (*current == '\n')
|
||||
++current;
|
||||
lastLineStart = current;
|
||||
++line;
|
||||
}
|
||||
else if ( c == '\n' )
|
||||
{
|
||||
} else if (c == '\n') {
|
||||
lastLineStart = current;
|
||||
++line;
|
||||
}
|
||||
@ -940,10 +776,7 @@ Reader::getLocationLineAndColumn( Location location,
|
||||
++line;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
Reader::getLocationLineAndColumn( Location location ) const
|
||||
{
|
||||
std::string Reader::getLocationLineAndColumn(Location location) const {
|
||||
int line, column;
|
||||
getLocationLineAndColumn(location, line, column);
|
||||
char buffer[18 + 16 + 16 + 1];
|
||||
@ -955,41 +788,32 @@ Reader::getLocationLineAndColumn( Location location ) const
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
// Deprecated. Preserved for backward compatibility
|
||||
std::string
|
||||
Reader::getFormatedErrorMessages() const
|
||||
{
|
||||
std::string Reader::getFormatedErrorMessages() const {
|
||||
return getFormattedErrorMessages();
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
Reader::getFormattedErrorMessages() const
|
||||
{
|
||||
std::string Reader::getFormattedErrorMessages() const {
|
||||
std::string formattedMessage;
|
||||
for (Errors::const_iterator itError = errors_.begin();
|
||||
itError != errors_.end();
|
||||
++itError )
|
||||
{
|
||||
++itError) {
|
||||
const ErrorInfo &error = *itError;
|
||||
formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n";
|
||||
formattedMessage +=
|
||||
"* " + getLocationLineAndColumn(error.token_.start_) + "\n";
|
||||
formattedMessage += " " + error.message_ + "\n";
|
||||
if (error.extra_)
|
||||
formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n";
|
||||
formattedMessage +=
|
||||
"See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
|
||||
}
|
||||
return formattedMessage;
|
||||
}
|
||||
|
||||
|
||||
std::vector<Reader::StructuredError>
|
||||
Reader::getStructuredErrors() const
|
||||
{
|
||||
std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
|
||||
std::vector<Reader::StructuredError> allErrors;
|
||||
for (Errors::const_iterator itError = errors_.begin();
|
||||
itError != errors_.end();
|
||||
++itError )
|
||||
{
|
||||
++itError) {
|
||||
const ErrorInfo &error = *itError;
|
||||
Reader::StructuredError structured;
|
||||
structured.offset_start = error.token_.start_ - begin_;
|
||||
@ -1000,14 +824,11 @@ Reader::getStructuredErrors() const
|
||||
return allErrors;
|
||||
}
|
||||
|
||||
|
||||
std::istream& operator>>( std::istream &sin, Value &root )
|
||||
{
|
||||
std::istream &operator>>(std::istream &sin, Value &root) {
|
||||
Json::Reader reader;
|
||||
bool ok = reader.parse(sin, root, true);
|
||||
if (!ok) {
|
||||
fprintf(
|
||||
stderr,
|
||||
fprintf(stderr,
|
||||
"Error from reader: %s",
|
||||
reader.getFormattedErrorMessages().c_str());
|
||||
|
||||
@ -1016,6 +837,5 @@ std::istream& operator>>( std::istream &sin, Value &root )
|
||||
return sin;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Json
|
||||
// vim: et ts=3 sts=3 sw=3 tw=0
|
||||
|
@ -15,33 +15,24 @@
|
||||
namespace Json {
|
||||
|
||||
/// Converts a unicode code-point to UTF-8.
|
||||
static inline std::string
|
||||
codePointToUTF8(unsigned int cp)
|
||||
{
|
||||
static inline std::string codePointToUTF8(unsigned int cp) {
|
||||
std::string result;
|
||||
|
||||
// based on description from http://en.wikipedia.org/wiki/UTF-8
|
||||
|
||||
if (cp <= 0x7f)
|
||||
{
|
||||
if (cp <= 0x7f) {
|
||||
result.resize(1);
|
||||
result[0] = static_cast<char>(cp);
|
||||
}
|
||||
else if (cp <= 0x7FF)
|
||||
{
|
||||
} else if (cp <= 0x7FF) {
|
||||
result.resize(2);
|
||||
result[1] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
|
||||
}
|
||||
else if (cp <= 0xFFFF)
|
||||
{
|
||||
} 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)));
|
||||
}
|
||||
else if (cp <= 0x10FFFF)
|
||||
{
|
||||
} else if (cp <= 0x10FFFF) {
|
||||
result.resize(4);
|
||||
result[3] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
|
||||
@ -52,40 +43,29 @@ codePointToUTF8(unsigned int cp)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// Returns true if ch is a control character (in range [0,32[).
|
||||
static inline bool
|
||||
isControlCharacter(char ch)
|
||||
{
|
||||
return ch > 0 && ch <= 0x1F;
|
||||
}
|
||||
|
||||
static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; }
|
||||
|
||||
enum {
|
||||
/// Constant that specify the size of the buffer that must be passed to uintToString.
|
||||
/// Constant that specify the size of the buffer that must be passed to
|
||||
/// uintToString.
|
||||
uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
|
||||
};
|
||||
|
||||
// Defines a char buffer for use with uintToString().
|
||||
typedef char UIntToStringBuffer[uintToStringBufferSize];
|
||||
|
||||
|
||||
/** Converts an unsigned integer to string.
|
||||
* @param value Unsigned interger to convert to string
|
||||
* @param current Input/Output string buffer.
|
||||
* Must have at least uintToStringBufferSize chars free.
|
||||
*/
|
||||
static inline void
|
||||
uintToString( LargestUInt value,
|
||||
char *¤t )
|
||||
{
|
||||
static inline void uintToString(LargestUInt value, char *¤t) {
|
||||
*--current = 0;
|
||||
do
|
||||
{
|
||||
do {
|
||||
*--current = char(value % 10) + '0';
|
||||
value /= 10;
|
||||
}
|
||||
while ( value != 0 );
|
||||
} while (value != 0);
|
||||
}
|
||||
|
||||
} // namespace Json {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -15,24 +15,21 @@
|
||||
#include <iomanip>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
|
||||
#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
|
||||
#pragma warning(disable \
|
||||
: 4996) // disable warning about strdup being deprecated.
|
||||
#endif
|
||||
|
||||
namespace Json {
|
||||
|
||||
static bool containsControlCharacter( const char* str )
|
||||
{
|
||||
while ( *str )
|
||||
{
|
||||
static bool containsControlCharacter(const char *str) {
|
||||
while (*str) {
|
||||
if (isControlCharacter(*(str++)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
std::string valueToString( LargestInt value )
|
||||
{
|
||||
std::string valueToString(LargestInt value) {
|
||||
UIntToStringBuffer buffer;
|
||||
char *current = buffer + sizeof(buffer);
|
||||
bool isNegative = value < 0;
|
||||
@ -45,9 +42,7 @@ std::string valueToString( LargestInt value )
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
std::string valueToString( LargestUInt value )
|
||||
{
|
||||
std::string valueToString(LargestUInt value) {
|
||||
UIntToStringBuffer buffer;
|
||||
char *current = buffer + sizeof(buffer);
|
||||
uintToString(value, current);
|
||||
@ -57,22 +52,17 @@ std::string valueToString( LargestUInt value )
|
||||
|
||||
#if defined(JSON_HAS_INT64)
|
||||
|
||||
std::string valueToString( Int value )
|
||||
{
|
||||
std::string valueToString(Int value) {
|
||||
return valueToString(LargestInt(value));
|
||||
}
|
||||
|
||||
|
||||
std::string valueToString( UInt value )
|
||||
{
|
||||
std::string valueToString(UInt value) {
|
||||
return valueToString(LargestUInt(value));
|
||||
}
|
||||
|
||||
#endif // # if defined(JSON_HAS_INT64)
|
||||
|
||||
|
||||
std::string valueToString( double value )
|
||||
{
|
||||
std::string valueToString(double value) {
|
||||
// Allocate a buffer that is more than large enough to store the 16 digits of
|
||||
// precision requested below.
|
||||
char buffer[32];
|
||||
@ -80,7 +70,9 @@ std::string valueToString( double value )
|
||||
// Print into the buffer. We need not request the alternative representation
|
||||
// that always has a decimal point because JSON doesn't distingish the
|
||||
// concepts of reals and integers.
|
||||
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning.
|
||||
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with
|
||||
// visual studio 2005 to
|
||||
// avoid warning.
|
||||
sprintf_s(buffer, sizeof(buffer), "%.16g", value);
|
||||
#else
|
||||
snprintf(buffer, sizeof(buffer), "%.16g", value);
|
||||
@ -89,30 +81,25 @@ std::string valueToString( double value )
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::string valueToString(bool value) { return value ? "true" : "false"; }
|
||||
|
||||
std::string valueToString( bool value )
|
||||
{
|
||||
return value ? "true" : "false";
|
||||
}
|
||||
|
||||
std::string valueToQuotedString( const char *value )
|
||||
{
|
||||
std::string valueToQuotedString(const char *value) {
|
||||
if (value == NULL)
|
||||
return "";
|
||||
// Not sure how to handle unicode...
|
||||
if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value ))
|
||||
if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL &&
|
||||
!containsControlCharacter(value))
|
||||
return std::string("\"") + value + "\"";
|
||||
// We have to walk value and escape any special characters.
|
||||
// Appending to std::string is not efficient, but this should be rare.
|
||||
// (Note: forward slashes are *not* rare, but I am not escaping them.)
|
||||
std::string::size_type maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL
|
||||
std::string::size_type maxsize =
|
||||
strlen(value) * 2 + 3; // allescaped+quotes+NULL
|
||||
std::string result;
|
||||
result.reserve(maxsize); // to avoid lots of mallocs
|
||||
result += "\"";
|
||||
for (const char* c=value; *c != 0; ++c)
|
||||
{
|
||||
switch(*c)
|
||||
{
|
||||
for (const char *c = value; *c != 0; ++c) {
|
||||
switch (*c) {
|
||||
case '\"':
|
||||
result += "\\\"";
|
||||
break;
|
||||
@ -143,14 +130,12 @@ std::string valueToQuotedString( const char *value )
|
||||
// Should add a flag to allow this compatibility mode and prevent this
|
||||
// sequence from occurring.
|
||||
default:
|
||||
if ( isControlCharacter( *c ) )
|
||||
{
|
||||
if (isControlCharacter(*c)) {
|
||||
std::ostringstream oss;
|
||||
oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c);
|
||||
oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
|
||||
<< std::setw(4) << static_cast<int>(*c);
|
||||
result += oss.str();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
result += *c;
|
||||
}
|
||||
break;
|
||||
@ -162,52 +147,30 @@ std::string valueToQuotedString( const char *value )
|
||||
|
||||
// Class Writer
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
Writer::~Writer()
|
||||
{
|
||||
}
|
||||
|
||||
Writer::~Writer() {}
|
||||
|
||||
// Class FastWriter
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
FastWriter::FastWriter()
|
||||
: yamlCompatiblityEnabled_( false ),
|
||||
dropNullPlaceholders_( false )
|
||||
{
|
||||
}
|
||||
: yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false) {}
|
||||
|
||||
void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
|
||||
|
||||
void
|
||||
FastWriter::enableYAMLCompatibility()
|
||||
{
|
||||
yamlCompatiblityEnabled_ = true;
|
||||
}
|
||||
void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
|
||||
|
||||
|
||||
void
|
||||
FastWriter::dropNullPlaceholders()
|
||||
{
|
||||
dropNullPlaceholders_ = true;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
FastWriter::write( const Value &root )
|
||||
{
|
||||
std::string FastWriter::write(const Value &root) {
|
||||
document_ = "";
|
||||
writeValue(root);
|
||||
document_ += "\n";
|
||||
return document_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FastWriter::writeValue( const Value &value )
|
||||
{
|
||||
switch ( value.type() )
|
||||
{
|
||||
void FastWriter::writeValue(const Value &value) {
|
||||
switch (value.type()) {
|
||||
case nullValue:
|
||||
if (!dropNullPlaceholders_) document_ += "null";
|
||||
if (!dropNullPlaceholders_)
|
||||
document_ += "null";
|
||||
break;
|
||||
case intValue:
|
||||
document_ += valueToString(value.asLargestInt());
|
||||
@ -224,56 +187,40 @@ FastWriter::writeValue( const Value &value )
|
||||
case booleanValue:
|
||||
document_ += valueToString(value.asBool());
|
||||
break;
|
||||
case arrayValue:
|
||||
{
|
||||
case arrayValue: {
|
||||
document_ += "[";
|
||||
int size = value.size();
|
||||
for ( int index =0; index < size; ++index )
|
||||
{
|
||||
for (int index = 0; index < size; ++index) {
|
||||
if (index > 0)
|
||||
document_ += ",";
|
||||
writeValue(value[index]);
|
||||
}
|
||||
document_ += "]";
|
||||
}
|
||||
break;
|
||||
case objectValue:
|
||||
{
|
||||
} break;
|
||||
case objectValue: {
|
||||
Value::Members members(value.getMemberNames());
|
||||
document_ += "{";
|
||||
for ( Value::Members::iterator it = members.begin();
|
||||
it != members.end();
|
||||
++it )
|
||||
{
|
||||
for (Value::Members::iterator it = members.begin(); it != members.end();
|
||||
++it) {
|
||||
const std::string &name = *it;
|
||||
if (it != members.begin())
|
||||
document_ += ",";
|
||||
document_ += valueToQuotedString(name.c_str());
|
||||
document_ += yamlCompatiblityEnabled_ ? ": "
|
||||
: ":";
|
||||
document_ += yamlCompatiblityEnabled_ ? ": " : ":";
|
||||
writeValue(value[name]);
|
||||
}
|
||||
document_ += "}";
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Class StyledWriter
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
StyledWriter::StyledWriter()
|
||||
: rightMargin_( 74 )
|
||||
, indentSize_( 3 )
|
||||
, addChildValues_()
|
||||
{
|
||||
}
|
||||
: rightMargin_(74), indentSize_(3), addChildValues_() {}
|
||||
|
||||
|
||||
std::string
|
||||
StyledWriter::write( const Value &root )
|
||||
{
|
||||
std::string StyledWriter::write(const Value &root) {
|
||||
document_ = "";
|
||||
addChildValues_ = false;
|
||||
indentString_ = "";
|
||||
@ -284,12 +231,8 @@ StyledWriter::write( const Value &root )
|
||||
return document_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeValue( const Value &value )
|
||||
{
|
||||
switch ( value.type() )
|
||||
{
|
||||
void StyledWriter::writeValue(const Value &value) {
|
||||
switch (value.type()) {
|
||||
case nullValue:
|
||||
pushValue("null");
|
||||
break;
|
||||
@ -311,26 +254,22 @@ StyledWriter::writeValue( const Value &value )
|
||||
case arrayValue:
|
||||
writeArrayValue(value);
|
||||
break;
|
||||
case objectValue:
|
||||
{
|
||||
case objectValue: {
|
||||
Value::Members members(value.getMemberNames());
|
||||
if (members.empty())
|
||||
pushValue("{}");
|
||||
else
|
||||
{
|
||||
else {
|
||||
writeWithIndent("{");
|
||||
indent();
|
||||
Value::Members::iterator it = members.begin();
|
||||
for (;;)
|
||||
{
|
||||
for (;;) {
|
||||
const std::string &name = *it;
|
||||
const Value &childValue = value[name];
|
||||
writeCommentBeforeValue(childValue);
|
||||
writeWithIndent(valueToQuotedString(name.c_str()));
|
||||
document_ += " : ";
|
||||
writeValue(childValue);
|
||||
if ( ++it == members.end() )
|
||||
{
|
||||
if (++it == members.end()) {
|
||||
writeCommentAfterValueOnSameLine(childValue);
|
||||
break;
|
||||
}
|
||||
@ -340,40 +279,31 @@ StyledWriter::writeValue( const Value &value )
|
||||
unindent();
|
||||
writeWithIndent("}");
|
||||
}
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeArrayValue( const Value &value )
|
||||
{
|
||||
void StyledWriter::writeArrayValue(const Value &value) {
|
||||
unsigned size = value.size();
|
||||
if (size == 0)
|
||||
pushValue("[]");
|
||||
else
|
||||
{
|
||||
else {
|
||||
bool isArrayMultiLine = isMultineArray(value);
|
||||
if ( isArrayMultiLine )
|
||||
{
|
||||
if (isArrayMultiLine) {
|
||||
writeWithIndent("[");
|
||||
indent();
|
||||
bool hasChildValue = !childValues_.empty();
|
||||
unsigned index = 0;
|
||||
for (;;)
|
||||
{
|
||||
for (;;) {
|
||||
const Value &childValue = value[index];
|
||||
writeCommentBeforeValue(childValue);
|
||||
if (hasChildValue)
|
||||
writeWithIndent(childValues_[index]);
|
||||
else
|
||||
{
|
||||
else {
|
||||
writeIndent();
|
||||
writeValue(childValue);
|
||||
}
|
||||
if ( ++index == size )
|
||||
{
|
||||
if (++index == size) {
|
||||
writeCommentAfterValueOnSameLine(childValue);
|
||||
break;
|
||||
}
|
||||
@ -382,13 +312,11 @@ StyledWriter::writeArrayValue( const Value &value )
|
||||
}
|
||||
unindent();
|
||||
writeWithIndent("]");
|
||||
}
|
||||
else // output on a single line
|
||||
} else // output on a single line
|
||||
{
|
||||
assert(childValues_.size() == size);
|
||||
document_ += "[ ";
|
||||
for ( unsigned index =0; index < size; ++index )
|
||||
{
|
||||
for (unsigned index = 0; index < size; ++index) {
|
||||
if (index > 0)
|
||||
document_ += ", ";
|
||||
document_ += childValues_[index];
|
||||
@ -398,18 +326,14 @@ StyledWriter::writeArrayValue( const Value &value )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
StyledWriter::isMultineArray( const Value &value )
|
||||
{
|
||||
bool StyledWriter::isMultineArray(const Value &value) {
|
||||
int size = value.size();
|
||||
bool isMultiLine = size * 3 >= rightMargin_;
|
||||
childValues_.clear();
|
||||
for ( int index =0; index < size && !isMultiLine; ++index )
|
||||
{
|
||||
for (int index = 0; index < size && !isMultiLine; ++index) {
|
||||
const Value &childValue = value[index];
|
||||
isMultiLine = isMultiLine ||
|
||||
( (childValue.isArray() || childValue.isObject()) &&
|
||||
isMultiLine =
|
||||
isMultiLine || ((childValue.isArray() || childValue.isObject()) &&
|
||||
childValue.size() > 0);
|
||||
}
|
||||
if (!isMultiLine) // check if line length > max line length
|
||||
@ -417,8 +341,7 @@ StyledWriter::isMultineArray( const Value &value )
|
||||
childValues_.reserve(size);
|
||||
addChildValues_ = true;
|
||||
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
|
||||
for ( int index =0; index < size && !isMultiLine; ++index )
|
||||
{
|
||||
for (int index = 0; index < size && !isMultiLine; ++index) {
|
||||
writeValue(value[index]);
|
||||
lineLength += int(childValues_[index].length());
|
||||
isMultiLine = isMultiLine && hasCommentForValue(value[index]);
|
||||
@ -429,22 +352,15 @@ StyledWriter::isMultineArray( const Value &value )
|
||||
return isMultiLine;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::pushValue( const std::string &value )
|
||||
{
|
||||
void StyledWriter::pushValue(const std::string &value) {
|
||||
if (addChildValues_)
|
||||
childValues_.push_back(value);
|
||||
else
|
||||
document_ += value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeIndent()
|
||||
{
|
||||
if ( !document_.empty() )
|
||||
{
|
||||
void StyledWriter::writeIndent() {
|
||||
if (!document_.empty()) {
|
||||
char last = document_[document_.length() - 1];
|
||||
if (last == ' ') // already indented
|
||||
return;
|
||||
@ -454,33 +370,19 @@ StyledWriter::writeIndent()
|
||||
document_ += indentString_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeWithIndent( const std::string &value )
|
||||
{
|
||||
void StyledWriter::writeWithIndent(const std::string &value) {
|
||||
writeIndent();
|
||||
document_ += value;
|
||||
}
|
||||
|
||||
void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); }
|
||||
|
||||
void
|
||||
StyledWriter::indent()
|
||||
{
|
||||
indentString_ += std::string( indentSize_, ' ' );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::unindent()
|
||||
{
|
||||
void StyledWriter::unindent() {
|
||||
assert(int(indentString_.size()) >= indentSize_);
|
||||
indentString_.resize(indentString_.size() - indentSize_);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeCommentBeforeValue( const Value &root )
|
||||
{
|
||||
void StyledWriter::writeCommentBeforeValue(const Value &root) {
|
||||
if (!root.hasComment(commentBefore))
|
||||
return;
|
||||
|
||||
@ -488,8 +390,7 @@ StyledWriter::writeCommentBeforeValue( const Value &root )
|
||||
writeIndent();
|
||||
std::string normalizedComment = normalizeEOL(root.getComment(commentBefore));
|
||||
std::string::const_iterator iter = normalizedComment.begin();
|
||||
while ( iter != normalizedComment.end() )
|
||||
{
|
||||
while (iter != normalizedComment.end()) {
|
||||
document_ += *iter;
|
||||
if (*iter == '\n' && *(iter + 1) == '/')
|
||||
writeIndent();
|
||||
@ -500,70 +401,50 @@ StyledWriter::writeCommentBeforeValue( const Value &root )
|
||||
document_ += "\n";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeCommentAfterValueOnSameLine( const Value &root )
|
||||
{
|
||||
void StyledWriter::writeCommentAfterValueOnSameLine(const Value &root) {
|
||||
if (root.hasComment(commentAfterOnSameLine))
|
||||
document_ += " " + normalizeEOL(root.getComment(commentAfterOnSameLine));
|
||||
|
||||
if ( root.hasComment( commentAfter ) )
|
||||
{
|
||||
if (root.hasComment(commentAfter)) {
|
||||
document_ += "\n";
|
||||
document_ += normalizeEOL(root.getComment(commentAfter));
|
||||
document_ += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
StyledWriter::hasCommentForValue( const Value &value )
|
||||
{
|
||||
return value.hasComment( commentBefore )
|
||||
|| value.hasComment( commentAfterOnSameLine )
|
||||
|| value.hasComment( commentAfter );
|
||||
bool StyledWriter::hasCommentForValue(const Value &value) {
|
||||
return value.hasComment(commentBefore) ||
|
||||
value.hasComment(commentAfterOnSameLine) ||
|
||||
value.hasComment(commentAfter);
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
StyledWriter::normalizeEOL( const std::string &text )
|
||||
{
|
||||
std::string StyledWriter::normalizeEOL(const std::string &text) {
|
||||
std::string normalized;
|
||||
normalized.reserve(text.length());
|
||||
const char *begin = text.c_str();
|
||||
const char *end = begin + text.length();
|
||||
const char *current = begin;
|
||||
while ( current != end )
|
||||
{
|
||||
while (current != end) {
|
||||
char c = *current++;
|
||||
if (c == '\r') // mac or dos EOL
|
||||
{
|
||||
if (*current == '\n') // convert dos EOL
|
||||
++current;
|
||||
normalized += '\n';
|
||||
}
|
||||
else // handle unix EOL & other char
|
||||
} else // handle unix EOL & other char
|
||||
normalized += c;
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
|
||||
// Class StyledStreamWriter
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
StyledStreamWriter::StyledStreamWriter(std::string indentation)
|
||||
: document_(NULL)
|
||||
, rightMargin_( 74 )
|
||||
, indentation_( indentation )
|
||||
, addChildValues_()
|
||||
{
|
||||
}
|
||||
: document_(NULL), rightMargin_(74), indentation_(indentation),
|
||||
addChildValues_() {}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::write( std::ostream &out, const Value &root )
|
||||
{
|
||||
void StyledStreamWriter::write(std::ostream &out, const Value &root) {
|
||||
document_ = &out;
|
||||
addChildValues_ = false;
|
||||
indentString_ = "";
|
||||
@ -574,12 +455,8 @@ StyledStreamWriter::write( std::ostream &out, const Value &root )
|
||||
document_ = NULL; // Forget the stream, for safety.
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeValue( const Value &value )
|
||||
{
|
||||
switch ( value.type() )
|
||||
{
|
||||
void StyledStreamWriter::writeValue(const Value &value) {
|
||||
switch (value.type()) {
|
||||
case nullValue:
|
||||
pushValue("null");
|
||||
break;
|
||||
@ -601,26 +478,22 @@ StyledStreamWriter::writeValue( const Value &value )
|
||||
case arrayValue:
|
||||
writeArrayValue(value);
|
||||
break;
|
||||
case objectValue:
|
||||
{
|
||||
case objectValue: {
|
||||
Value::Members members(value.getMemberNames());
|
||||
if (members.empty())
|
||||
pushValue("{}");
|
||||
else
|
||||
{
|
||||
else {
|
||||
writeWithIndent("{");
|
||||
indent();
|
||||
Value::Members::iterator it = members.begin();
|
||||
for (;;)
|
||||
{
|
||||
for (;;) {
|
||||
const std::string &name = *it;
|
||||
const Value &childValue = value[name];
|
||||
writeCommentBeforeValue(childValue);
|
||||
writeWithIndent(valueToQuotedString(name.c_str()));
|
||||
*document_ << " : ";
|
||||
writeValue(childValue);
|
||||
if ( ++it == members.end() )
|
||||
{
|
||||
if (++it == members.end()) {
|
||||
writeCommentAfterValueOnSameLine(childValue);
|
||||
break;
|
||||
}
|
||||
@ -630,40 +503,31 @@ StyledStreamWriter::writeValue( const Value &value )
|
||||
unindent();
|
||||
writeWithIndent("}");
|
||||
}
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeArrayValue( const Value &value )
|
||||
{
|
||||
void StyledStreamWriter::writeArrayValue(const Value &value) {
|
||||
unsigned size = value.size();
|
||||
if (size == 0)
|
||||
pushValue("[]");
|
||||
else
|
||||
{
|
||||
else {
|
||||
bool isArrayMultiLine = isMultineArray(value);
|
||||
if ( isArrayMultiLine )
|
||||
{
|
||||
if (isArrayMultiLine) {
|
||||
writeWithIndent("[");
|
||||
indent();
|
||||
bool hasChildValue = !childValues_.empty();
|
||||
unsigned index = 0;
|
||||
for (;;)
|
||||
{
|
||||
for (;;) {
|
||||
const Value &childValue = value[index];
|
||||
writeCommentBeforeValue(childValue);
|
||||
if (hasChildValue)
|
||||
writeWithIndent(childValues_[index]);
|
||||
else
|
||||
{
|
||||
else {
|
||||
writeIndent();
|
||||
writeValue(childValue);
|
||||
}
|
||||
if ( ++index == size )
|
||||
{
|
||||
if (++index == size) {
|
||||
writeCommentAfterValueOnSameLine(childValue);
|
||||
break;
|
||||
}
|
||||
@ -672,13 +536,11 @@ StyledStreamWriter::writeArrayValue( const Value &value )
|
||||
}
|
||||
unindent();
|
||||
writeWithIndent("]");
|
||||
}
|
||||
else // output on a single line
|
||||
} else // output on a single line
|
||||
{
|
||||
assert(childValues_.size() == size);
|
||||
*document_ << "[ ";
|
||||
for ( unsigned index =0; index < size; ++index )
|
||||
{
|
||||
for (unsigned index = 0; index < size; ++index) {
|
||||
if (index > 0)
|
||||
*document_ << ", ";
|
||||
*document_ << childValues_[index];
|
||||
@ -688,18 +550,14 @@ StyledStreamWriter::writeArrayValue( const Value &value )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
StyledStreamWriter::isMultineArray( const Value &value )
|
||||
{
|
||||
bool StyledStreamWriter::isMultineArray(const Value &value) {
|
||||
int size = value.size();
|
||||
bool isMultiLine = size * 3 >= rightMargin_;
|
||||
childValues_.clear();
|
||||
for ( int index =0; index < size && !isMultiLine; ++index )
|
||||
{
|
||||
for (int index = 0; index < size && !isMultiLine; ++index) {
|
||||
const Value &childValue = value[index];
|
||||
isMultiLine = isMultiLine ||
|
||||
( (childValue.isArray() || childValue.isObject()) &&
|
||||
isMultiLine =
|
||||
isMultiLine || ((childValue.isArray() || childValue.isObject()) &&
|
||||
childValue.size() > 0);
|
||||
}
|
||||
if (!isMultiLine) // check if line length > max line length
|
||||
@ -707,8 +565,7 @@ StyledStreamWriter::isMultineArray( const Value &value )
|
||||
childValues_.reserve(size);
|
||||
addChildValues_ = true;
|
||||
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
|
||||
for ( int index =0; index < size && !isMultiLine; ++index )
|
||||
{
|
||||
for (int index = 0; index < size && !isMultiLine; ++index) {
|
||||
writeValue(value[index]);
|
||||
lineLength += int(childValues_[index].length());
|
||||
isMultiLine = isMultiLine && hasCommentForValue(value[index]);
|
||||
@ -719,20 +576,14 @@ StyledStreamWriter::isMultineArray( const Value &value )
|
||||
return isMultiLine;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::pushValue( const std::string &value )
|
||||
{
|
||||
void StyledStreamWriter::pushValue(const std::string &value) {
|
||||
if (addChildValues_)
|
||||
childValues_.push_back(value);
|
||||
else
|
||||
*document_ << value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeIndent()
|
||||
{
|
||||
void StyledStreamWriter::writeIndent() {
|
||||
/*
|
||||
Some comments in this method would have been nice. ;-)
|
||||
|
||||
@ -748,95 +599,66 @@ StyledStreamWriter::writeIndent()
|
||||
*document_ << '\n' << indentString_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeWithIndent( const std::string &value )
|
||||
{
|
||||
void StyledStreamWriter::writeWithIndent(const std::string &value) {
|
||||
writeIndent();
|
||||
*document_ << value;
|
||||
}
|
||||
|
||||
void StyledStreamWriter::indent() { indentString_ += indentation_; }
|
||||
|
||||
void
|
||||
StyledStreamWriter::indent()
|
||||
{
|
||||
indentString_ += indentation_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::unindent()
|
||||
{
|
||||
void StyledStreamWriter::unindent() {
|
||||
assert(indentString_.size() >= indentation_.size());
|
||||
indentString_.resize(indentString_.size() - indentation_.size());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeCommentBeforeValue( const Value &root )
|
||||
{
|
||||
void StyledStreamWriter::writeCommentBeforeValue(const Value &root) {
|
||||
if (!root.hasComment(commentBefore))
|
||||
return;
|
||||
*document_ << normalizeEOL(root.getComment(commentBefore));
|
||||
*document_ << "\n";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )
|
||||
{
|
||||
void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value &root) {
|
||||
if (root.hasComment(commentAfterOnSameLine))
|
||||
*document_ << " " + normalizeEOL(root.getComment(commentAfterOnSameLine));
|
||||
|
||||
if ( root.hasComment( commentAfter ) )
|
||||
{
|
||||
if (root.hasComment(commentAfter)) {
|
||||
*document_ << "\n";
|
||||
*document_ << normalizeEOL(root.getComment(commentAfter));
|
||||
*document_ << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
StyledStreamWriter::hasCommentForValue( const Value &value )
|
||||
{
|
||||
return value.hasComment( commentBefore )
|
||||
|| value.hasComment( commentAfterOnSameLine )
|
||||
|| value.hasComment( commentAfter );
|
||||
bool StyledStreamWriter::hasCommentForValue(const Value &value) {
|
||||
return value.hasComment(commentBefore) ||
|
||||
value.hasComment(commentAfterOnSameLine) ||
|
||||
value.hasComment(commentAfter);
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
StyledStreamWriter::normalizeEOL( const std::string &text )
|
||||
{
|
||||
std::string StyledStreamWriter::normalizeEOL(const std::string &text) {
|
||||
std::string normalized;
|
||||
normalized.reserve(text.length());
|
||||
const char *begin = text.c_str();
|
||||
const char *end = begin + text.length();
|
||||
const char *current = begin;
|
||||
while ( current != end )
|
||||
{
|
||||
while (current != end) {
|
||||
char c = *current++;
|
||||
if (c == '\r') // mac or dos EOL
|
||||
{
|
||||
if (*current == '\n') // convert dos EOL
|
||||
++current;
|
||||
normalized += '\n';
|
||||
}
|
||||
else // handle unix EOL & other char
|
||||
} else // handle unix EOL & other char
|
||||
normalized += c;
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<( std::ostream &sout, const Value &root )
|
||||
{
|
||||
std::ostream &operator<<(std::ostream &sout, const Value &root) {
|
||||
Json::StyledStreamWriter writer;
|
||||
writer.write(sout, root);
|
||||
return sout;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Json
|
||||
// vim: et ts=3 sts=3 sw=3 tw=0
|
||||
|
@ -70,42 +70,31 @@
|
||||
|
||||
namespace JsonTest {
|
||||
|
||||
|
||||
// class TestResult
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
TestResult::TestResult()
|
||||
: predicateId_( 1 )
|
||||
, lastUsedPredicateId_( 0 )
|
||||
, messageTarget_( 0 )
|
||||
{
|
||||
: predicateId_(1), lastUsedPredicateId_(0), messageTarget_(0) {
|
||||
// The root predicate has id 0
|
||||
rootPredicateNode_.id_ = 0;
|
||||
rootPredicateNode_.next_ = 0;
|
||||
predicateStackTail_ = &rootPredicateNode_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestResult::setTestName( const std::string &name )
|
||||
{
|
||||
name_ = name;
|
||||
}
|
||||
void TestResult::setTestName(const std::string &name) { name_ = name; }
|
||||
|
||||
TestResult &
|
||||
TestResult::addFailure( const char *file, unsigned int line,
|
||||
const char *expr )
|
||||
{
|
||||
/// Walks the PredicateContext stack adding them to failures_ if not already added.
|
||||
TestResult::addFailure(const char *file, unsigned int line, const char *expr) {
|
||||
/// Walks the PredicateContext stack adding them to failures_ if not already
|
||||
/// added.
|
||||
unsigned int nestingLevel = 0;
|
||||
PredicateContext *lastNode = rootPredicateNode_.next_;
|
||||
for ( ; lastNode != 0; lastNode = lastNode->next_ )
|
||||
{
|
||||
for (; lastNode != 0; lastNode = lastNode->next_) {
|
||||
if (lastNode->id_ > lastUsedPredicateId_) // new PredicateContext
|
||||
{
|
||||
lastUsedPredicateId_ = lastNode->id_;
|
||||
addFailureInfo( lastNode->file_, lastNode->line_, lastNode->expr_,
|
||||
nestingLevel );
|
||||
addFailureInfo(
|
||||
lastNode->file_, lastNode->line_, lastNode->expr_, nestingLevel);
|
||||
// Link the PredicateContext to the failure for message target when
|
||||
// popping the PredicateContext.
|
||||
lastNode->failure_ = &(failures_.back());
|
||||
@ -119,35 +108,28 @@ TestResult::addFailure( const char *file, unsigned int line,
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestResult::addFailureInfo( const char *file, unsigned int line,
|
||||
const char *expr, unsigned int nestingLevel )
|
||||
{
|
||||
void TestResult::addFailureInfo(const char *file,
|
||||
unsigned int line,
|
||||
const char *expr,
|
||||
unsigned int nestingLevel) {
|
||||
Failure failure;
|
||||
failure.file_ = file;
|
||||
failure.line_ = line;
|
||||
if ( expr )
|
||||
{
|
||||
if (expr) {
|
||||
failure.expr_ = expr;
|
||||
}
|
||||
failure.nestingLevel_ = nestingLevel;
|
||||
failures_.push_back(failure);
|
||||
}
|
||||
|
||||
|
||||
TestResult &
|
||||
TestResult::popPredicateContext()
|
||||
{
|
||||
TestResult &TestResult::popPredicateContext() {
|
||||
PredicateContext *lastNode = &rootPredicateNode_;
|
||||
while ( lastNode->next_ != 0 && lastNode->next_->next_ != 0 )
|
||||
{
|
||||
while (lastNode->next_ != 0 && lastNode->next_->next_ != 0) {
|
||||
lastNode = lastNode->next_;
|
||||
}
|
||||
// Set message target to popped failure
|
||||
PredicateContext *tail = lastNode->next_;
|
||||
if ( tail != 0 && tail->failure_ != 0 )
|
||||
{
|
||||
if (tail != 0 && tail->failure_ != 0) {
|
||||
messageTarget_ = tail->failure_;
|
||||
}
|
||||
// Remove tail from list
|
||||
@ -156,79 +138,54 @@ TestResult::popPredicateContext()
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool TestResult::failed() const { return !failures_.empty(); }
|
||||
|
||||
bool
|
||||
TestResult::failed() const
|
||||
{
|
||||
return !failures_.empty();
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
TestResult::getAssertionNestingLevel() const
|
||||
{
|
||||
unsigned int TestResult::getAssertionNestingLevel() const {
|
||||
unsigned int level = 0;
|
||||
const PredicateContext *lastNode = &rootPredicateNode_;
|
||||
while ( lastNode->next_ != 0 )
|
||||
{
|
||||
while (lastNode->next_ != 0) {
|
||||
lastNode = lastNode->next_;
|
||||
++level;
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestResult::printFailure( bool printTestName ) const
|
||||
{
|
||||
if ( failures_.empty() )
|
||||
{
|
||||
void TestResult::printFailure(bool printTestName) const {
|
||||
if (failures_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( printTestName )
|
||||
{
|
||||
if (printTestName) {
|
||||
printf("* Detail of %s test failure:\n", name_.c_str());
|
||||
}
|
||||
|
||||
// Print in reverse to display the callstack in the right order
|
||||
Failures::const_iterator itEnd = failures_.end();
|
||||
for ( Failures::const_iterator it = failures_.begin(); it != itEnd; ++it )
|
||||
{
|
||||
for (Failures::const_iterator it = failures_.begin(); it != itEnd; ++it) {
|
||||
const Failure &failure = *it;
|
||||
std::string indent(failure.nestingLevel_ * 2, ' ');
|
||||
if ( failure.file_ )
|
||||
{
|
||||
if (failure.file_) {
|
||||
printf("%s%s(%d): ", indent.c_str(), failure.file_, failure.line_);
|
||||
}
|
||||
if ( !failure.expr_.empty() )
|
||||
{
|
||||
if (!failure.expr_.empty()) {
|
||||
printf("%s\n", failure.expr_.c_str());
|
||||
}
|
||||
else if ( failure.file_ )
|
||||
{
|
||||
} else if (failure.file_) {
|
||||
printf("\n");
|
||||
}
|
||||
if ( !failure.message_.empty() )
|
||||
{
|
||||
if (!failure.message_.empty()) {
|
||||
std::string reindented = indentText(failure.message_, indent + " ");
|
||||
printf("%s\n", reindented.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
TestResult::indentText( const std::string &text,
|
||||
const std::string &indent )
|
||||
{
|
||||
std::string TestResult::indentText(const std::string &text,
|
||||
const std::string &indent) {
|
||||
std::string reindented;
|
||||
std::string::size_type lastIndex = 0;
|
||||
while ( lastIndex < text.size() )
|
||||
{
|
||||
while (lastIndex < text.size()) {
|
||||
std::string::size_type nextIndex = text.find('\n', lastIndex);
|
||||
if ( nextIndex == std::string::npos )
|
||||
{
|
||||
if (nextIndex == std::string::npos) {
|
||||
nextIndex = text.size() - 1;
|
||||
}
|
||||
reindented += indent;
|
||||
@ -238,170 +195,119 @@ TestResult::indentText( const std::string &text,
|
||||
return reindented;
|
||||
}
|
||||
|
||||
|
||||
TestResult &
|
||||
TestResult::addToLastFailure( const std::string &message )
|
||||
{
|
||||
if ( messageTarget_ != 0 )
|
||||
{
|
||||
TestResult &TestResult::addToLastFailure(const std::string &message) {
|
||||
if (messageTarget_ != 0) {
|
||||
messageTarget_->message_ += message;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
TestResult &
|
||||
TestResult::operator << ( Json::Int64 value ) {
|
||||
TestResult &TestResult::operator<<(Json::Int64 value) {
|
||||
return addToLastFailure(Json::valueToString(value));
|
||||
}
|
||||
|
||||
|
||||
TestResult &
|
||||
TestResult::operator << ( Json::UInt64 value ) {
|
||||
TestResult &TestResult::operator<<(Json::UInt64 value) {
|
||||
return addToLastFailure(Json::valueToString(value));
|
||||
}
|
||||
|
||||
|
||||
TestResult &
|
||||
TestResult::operator << ( bool value ) {
|
||||
TestResult &TestResult::operator<<(bool value) {
|
||||
return addToLastFailure(value ? "true" : "false");
|
||||
}
|
||||
|
||||
|
||||
// class TestCase
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
TestCase::TestCase()
|
||||
: result_( 0 )
|
||||
{
|
||||
}
|
||||
TestCase::TestCase() : result_(0) {}
|
||||
|
||||
TestCase::~TestCase() {}
|
||||
|
||||
TestCase::~TestCase()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TestCase::run( TestResult &result )
|
||||
{
|
||||
void TestCase::run(TestResult &result) {
|
||||
result_ = &result;
|
||||
runTestCase();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// class Runner
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
Runner::Runner()
|
||||
{
|
||||
}
|
||||
Runner::Runner() {}
|
||||
|
||||
|
||||
Runner &
|
||||
Runner::add( TestCaseFactory factory )
|
||||
{
|
||||
Runner &Runner::add(TestCaseFactory factory) {
|
||||
tests_.push_back(factory);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
Runner::testCount() const
|
||||
{
|
||||
unsigned int Runner::testCount() const {
|
||||
return static_cast<unsigned int>(tests_.size());
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
Runner::testNameAt( unsigned int index ) const
|
||||
{
|
||||
std::string Runner::testNameAt(unsigned int index) const {
|
||||
TestCase *test = tests_[index]();
|
||||
std::string name = test->testName();
|
||||
delete test;
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Runner::runTestAt( unsigned int index, TestResult &result ) const
|
||||
{
|
||||
void Runner::runTestAt(unsigned int index, TestResult &result) const {
|
||||
TestCase *test = tests_[index]();
|
||||
result.setTestName(test->testName());
|
||||
printf("Testing %s: ", test->testName());
|
||||
fflush(stdout);
|
||||
#if JSON_USE_EXCEPTION
|
||||
try
|
||||
{
|
||||
try {
|
||||
#endif // if JSON_USE_EXCEPTION
|
||||
test->run(result);
|
||||
#if JSON_USE_EXCEPTION
|
||||
}
|
||||
catch ( const std::exception &e )
|
||||
{
|
||||
result.addFailure( __FILE__, __LINE__,
|
||||
"Unexpected exception caught:" ) << e.what();
|
||||
catch (const std::exception &e) {
|
||||
result.addFailure(__FILE__, __LINE__, "Unexpected exception caught:")
|
||||
<< e.what();
|
||||
}
|
||||
#endif // if JSON_USE_EXCEPTION
|
||||
delete test;
|
||||
const char *status = result.failed() ? "FAILED"
|
||||
: "OK";
|
||||
const char *status = result.failed() ? "FAILED" : "OK";
|
||||
printf("%s\n", status);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Runner::runAllTest( bool printSummary ) const
|
||||
{
|
||||
bool Runner::runAllTest(bool printSummary) const {
|
||||
unsigned int count = testCount();
|
||||
std::deque<TestResult> failures;
|
||||
for ( unsigned int index = 0; index < count; ++index )
|
||||
{
|
||||
for (unsigned int index = 0; index < count; ++index) {
|
||||
TestResult result;
|
||||
runTestAt(index, result);
|
||||
if ( result.failed() )
|
||||
{
|
||||
if (result.failed()) {
|
||||
failures.push_back(result);
|
||||
}
|
||||
}
|
||||
|
||||
if ( failures.empty() )
|
||||
{
|
||||
if ( printSummary )
|
||||
{
|
||||
if (failures.empty()) {
|
||||
if (printSummary) {
|
||||
printf("All %d tests passed\n", count);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( unsigned int index = 0; index < failures.size(); ++index )
|
||||
{
|
||||
} else {
|
||||
for (unsigned int index = 0; index < failures.size(); ++index) {
|
||||
TestResult &result = failures[index];
|
||||
result.printFailure(count > 1);
|
||||
}
|
||||
|
||||
if ( printSummary )
|
||||
{
|
||||
if (printSummary) {
|
||||
unsigned int failedCount = static_cast<unsigned int>(failures.size());
|
||||
unsigned int passedCount = count - failedCount;
|
||||
printf( "%d/%d tests passed (%d failure(s))\n", passedCount, count, failedCount );
|
||||
printf("%d/%d tests passed (%d failure(s))\n",
|
||||
passedCount,
|
||||
count,
|
||||
failedCount);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Runner::testIndex( const std::string &testName,
|
||||
unsigned int &indexOut ) const
|
||||
{
|
||||
bool Runner::testIndex(const std::string &testName,
|
||||
unsigned int &indexOut) const {
|
||||
unsigned int count = testCount();
|
||||
for ( unsigned int index = 0; index < count; ++index )
|
||||
{
|
||||
if ( testNameAt(index) == testName )
|
||||
{
|
||||
for (unsigned int index = 0; index < count; ++index) {
|
||||
if (testNameAt(index) == testName) {
|
||||
indexOut = index;
|
||||
return true;
|
||||
}
|
||||
@ -409,97 +315,67 @@ Runner::testIndex( const std::string &testName,
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Runner::listTests() const
|
||||
{
|
||||
void Runner::listTests() const {
|
||||
unsigned int count = testCount();
|
||||
for ( unsigned int index = 0; index < count; ++index )
|
||||
{
|
||||
for (unsigned int index = 0; index < count; ++index) {
|
||||
printf("%s\n", testNameAt(index).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Runner::runCommandLine( int argc, const char *argv[] ) const
|
||||
{
|
||||
int Runner::runCommandLine(int argc, const char *argv[]) const {
|
||||
typedef std::deque<std::string> TestNames;
|
||||
Runner subrunner;
|
||||
for ( int index = 1; index < argc; ++index )
|
||||
{
|
||||
for (int index = 1; index < argc; ++index) {
|
||||
std::string opt = argv[index];
|
||||
if ( opt == "--list-tests" )
|
||||
{
|
||||
if (opt == "--list-tests") {
|
||||
listTests();
|
||||
return 0;
|
||||
}
|
||||
else if ( opt == "--test-auto" )
|
||||
{
|
||||
} else if (opt == "--test-auto") {
|
||||
preventDialogOnCrash();
|
||||
}
|
||||
else if ( opt == "--test" )
|
||||
{
|
||||
} else if (opt == "--test") {
|
||||
++index;
|
||||
if ( index < argc )
|
||||
{
|
||||
if (index < argc) {
|
||||
unsigned int testNameIndex;
|
||||
if ( testIndex( argv[index], testNameIndex ) )
|
||||
{
|
||||
if (testIndex(argv[index], testNameIndex)) {
|
||||
subrunner.add(tests_[testNameIndex]);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
fprintf(stderr, "Test '%s' does not exist!\n", argv[index]);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
printUsage(argv[0]);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
printUsage(argv[0]);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
bool succeeded;
|
||||
if ( subrunner.testCount() > 0 )
|
||||
{
|
||||
if (subrunner.testCount() > 0) {
|
||||
succeeded = subrunner.runAllTest(subrunner.testCount() > 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
succeeded = runAllTest(true);
|
||||
}
|
||||
return succeeded ? 0
|
||||
: 1;
|
||||
return succeeded ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
#if defined(_MSC_VER) && defined(_DEBUG)
|
||||
// Hook MSVCRT assertions to prevent dialog from appearing
|
||||
static int
|
||||
msvcrtSilentReportHook( int reportType, char *message, int * /*returnValue*/ )
|
||||
{
|
||||
msvcrtSilentReportHook(int reportType, char *message, int * /*returnValue*/) {
|
||||
// The default CRT handling of error and assertion is to display
|
||||
// an error dialog to the user.
|
||||
// Instead, when an error or an assertion occurs, we force the
|
||||
// application to terminate using abort() after display
|
||||
// the message on stderr.
|
||||
if ( reportType == _CRT_ERROR ||
|
||||
reportType == _CRT_ASSERT )
|
||||
{
|
||||
if (reportType == _CRT_ERROR || reportType == _CRT_ASSERT) {
|
||||
// calling abort() cause the ReportHook to be called
|
||||
// The following is used to detect this case and let's the
|
||||
// error handler fallback on its default behaviour (
|
||||
// display a warning message)
|
||||
static volatile bool isAborting = false;
|
||||
if ( isAborting )
|
||||
{
|
||||
if (isAborting) {
|
||||
return TRUE;
|
||||
}
|
||||
isAborting = true;
|
||||
@ -513,10 +389,7 @@ msvcrtSilentReportHook( int reportType, char *message, int * /*returnValue*/ )
|
||||
}
|
||||
#endif // if defined(_MSC_VER)
|
||||
|
||||
|
||||
void
|
||||
Runner::preventDialogOnCrash()
|
||||
{
|
||||
void Runner::preventDialogOnCrash() {
|
||||
#if defined(_MSC_VER) && defined(_DEBUG)
|
||||
// Install a hook to prevent MSVCRT error and assertion from
|
||||
// popping a dialog
|
||||
@ -531,17 +404,13 @@ Runner::preventDialogOnCrash()
|
||||
#if defined(_WIN32)
|
||||
// Prevents the system from popping a dialog for debugging if the
|
||||
// application fails due to invalid memory access.
|
||||
SetErrorMode( SEM_FAILCRITICALERRORS
|
||||
| SEM_NOGPFAULTERRORBOX
|
||||
| SEM_NOOPENFILEERRORBOX );
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
|
||||
SEM_NOOPENFILEERRORBOX);
|
||||
#endif // if defined(_WIN32)
|
||||
}
|
||||
|
||||
void
|
||||
Runner::printUsage( const char *appName )
|
||||
{
|
||||
printf(
|
||||
"Usage: %s [options]\n"
|
||||
void Runner::printUsage(const char *appName) {
|
||||
printf("Usage: %s [options]\n"
|
||||
"\n"
|
||||
"If --test is not specified, then all the test cases be run.\n"
|
||||
"\n"
|
||||
@ -550,22 +419,20 @@ Runner::printUsage( const char *appName )
|
||||
" output and exit.\n"
|
||||
"--test TESTNAME: executes the test case with the specified name.\n"
|
||||
" May be repeated.\n"
|
||||
"--test-auto: prevent dialog prompting for debugging on crash.\n"
|
||||
, appName );
|
||||
"--test-auto: prevent dialog prompting for debugging on crash.\n",
|
||||
appName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Assertion functions
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
TestResult &
|
||||
checkStringEqual( TestResult &result,
|
||||
const std::string &expected, const std::string &actual,
|
||||
const char *file, unsigned int line, const char *expr )
|
||||
{
|
||||
if ( expected != actual )
|
||||
{
|
||||
TestResult &checkStringEqual(TestResult &result,
|
||||
const std::string &expected,
|
||||
const std::string &actual,
|
||||
const char *file,
|
||||
unsigned int line,
|
||||
const char *expr) {
|
||||
if (expected != actual) {
|
||||
result.addFailure(file, line, expr);
|
||||
result << "Expected: '" << expected << "'\n";
|
||||
result << "Actual : '" << actual << "'";
|
||||
@ -573,6 +440,5 @@ checkStringEqual( TestResult &result,
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace JsonTest
|
||||
// vim: et ts=4 sts=4 sw=4 tw=0
|
||||
|
@ -20,8 +20,6 @@
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
/** \brief Unit testing framework.
|
||||
* \warning: all assertions are non-aborting, test case execution will continue
|
||||
* even if an assertion namespace.
|
||||
@ -30,9 +28,7 @@
|
||||
*/
|
||||
namespace JsonTest {
|
||||
|
||||
|
||||
class Failure
|
||||
{
|
||||
class Failure {
|
||||
public:
|
||||
const char *file_;
|
||||
unsigned int line_;
|
||||
@ -41,12 +37,10 @@ namespace JsonTest {
|
||||
unsigned int nestingLevel_;
|
||||
};
|
||||
|
||||
|
||||
/// Context used to create the assertion callstack on failure.
|
||||
/// Must be a POD to allow inline initialisation without stepping
|
||||
/// into the debugger.
|
||||
struct PredicateContext
|
||||
{
|
||||
struct PredicateContext {
|
||||
typedef unsigned int Id;
|
||||
Id id_;
|
||||
const char *file_;
|
||||
@ -58,8 +52,7 @@ namespace JsonTest {
|
||||
Failure *failure_;
|
||||
};
|
||||
|
||||
class TestResult
|
||||
{
|
||||
class TestResult {
|
||||
public:
|
||||
TestResult();
|
||||
|
||||
@ -75,8 +68,8 @@ namespace JsonTest {
|
||||
void setTestName(const std::string &name);
|
||||
|
||||
/// Adds an assertion failure.
|
||||
TestResult &addFailure( const char *file, unsigned int line,
|
||||
const char *expr = 0 );
|
||||
TestResult &
|
||||
addFailure(const char *file, unsigned int line, const char *expr = 0);
|
||||
|
||||
/// Removes the last PredicateContext added to the predicate stack
|
||||
/// chained list.
|
||||
@ -88,8 +81,7 @@ namespace JsonTest {
|
||||
void printFailure(bool printTestName) const;
|
||||
|
||||
// Generic operator that will work with anything ostream can deal with.
|
||||
template <typename T>
|
||||
TestResult &operator << ( const T& value ) {
|
||||
template <typename T> TestResult &operator<<(const T &value) {
|
||||
std::ostringstream oss;
|
||||
oss.precision(16);
|
||||
oss.setf(std::ios_base::floatfield);
|
||||
@ -107,8 +99,10 @@ namespace JsonTest {
|
||||
TestResult &addToLastFailure(const std::string &message);
|
||||
unsigned int getAssertionNestingLevel() const;
|
||||
/// Adds a failure or a predicate context
|
||||
void addFailureInfo( const char *file, unsigned int line,
|
||||
const char *expr, unsigned int nestingLevel );
|
||||
void addFailureInfo(const char *file,
|
||||
unsigned int line,
|
||||
const char *expr,
|
||||
unsigned int nestingLevel);
|
||||
static std::string indentText(const std::string &text,
|
||||
const std::string &indent);
|
||||
|
||||
@ -121,9 +115,7 @@ namespace JsonTest {
|
||||
Failure *messageTarget_;
|
||||
};
|
||||
|
||||
|
||||
class TestCase
|
||||
{
|
||||
class TestCase {
|
||||
public:
|
||||
TestCase();
|
||||
|
||||
@ -143,8 +135,7 @@ namespace JsonTest {
|
||||
/// Function pointer type for TestCase factory
|
||||
typedef TestCase *(*TestCaseFactory)();
|
||||
|
||||
class Runner
|
||||
{
|
||||
class Runner {
|
||||
public:
|
||||
Runner();
|
||||
|
||||
@ -186,12 +177,13 @@ namespace JsonTest {
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
TestResult &
|
||||
checkEqual( TestResult &result, const T &expected, const U &actual,
|
||||
const char *file, unsigned int line, const char *expr )
|
||||
{
|
||||
if ( static_cast< U >( expected ) != actual )
|
||||
{
|
||||
TestResult &checkEqual(TestResult &result,
|
||||
const T &expected,
|
||||
const U &actual,
|
||||
const char *file,
|
||||
unsigned int line,
|
||||
const char *expr) {
|
||||
if (static_cast<U>(expected) != actual) {
|
||||
result.addFailure(file, line, expr);
|
||||
result << "Expected: " << static_cast<U>(expected) << "\n";
|
||||
result << "Actual : " << actual;
|
||||
@ -199,31 +191,31 @@ namespace JsonTest {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
TestResult &
|
||||
checkStringEqual( TestResult &result,
|
||||
const std::string &expected, const std::string &actual,
|
||||
const char *file, unsigned int line, const char *expr );
|
||||
TestResult &checkStringEqual(TestResult &result,
|
||||
const std::string &expected,
|
||||
const std::string &actual,
|
||||
const char *file,
|
||||
unsigned int line,
|
||||
const char *expr);
|
||||
|
||||
} // namespace JsonTest
|
||||
|
||||
|
||||
/// \brief Asserts that the given expression is true.
|
||||
/// JSONTEST_ASSERT( x == y ) << "x=" << x << ", y=" << y;
|
||||
/// JSONTEST_ASSERT( x == y );
|
||||
#define JSONTEST_ASSERT(expr) \
|
||||
if ( expr ) \
|
||||
{ \
|
||||
} \
|
||||
else \
|
||||
if (expr) { \
|
||||
} else \
|
||||
result_->addFailure(__FILE__, __LINE__, #expr)
|
||||
|
||||
/// \brief Asserts that the given predicate is true.
|
||||
/// The predicate may do other assertions and be a member function of the fixture.
|
||||
/// The predicate may do other assertions and be a member function of the
|
||||
/// fixture.
|
||||
#define JSONTEST_ASSERT_PRED(expr) \
|
||||
{ \
|
||||
JsonTest::PredicateContext _minitest_Context = { \
|
||||
result_->predicateId_, __FILE__, __LINE__, #expr }; \
|
||||
result_->predicateId_, __FILE__, __LINE__, #expr \
|
||||
}; \
|
||||
result_->predicateStackTail_->next_ = &_minitest_Context; \
|
||||
result_->predicateId_ += 1; \
|
||||
result_->predicateStackTail_ = &_minitest_Context; \
|
||||
@ -233,31 +225,32 @@ namespace JsonTest {
|
||||
|
||||
/// \brief Asserts that two values are equals.
|
||||
#define JSONTEST_ASSERT_EQUAL(expected, actual) \
|
||||
JsonTest::checkEqual( *result_, expected, actual, \
|
||||
__FILE__, __LINE__, \
|
||||
JsonTest::checkEqual(*result_, \
|
||||
expected, \
|
||||
actual, \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
#expected " == " #actual)
|
||||
|
||||
/// \brief Asserts that two values are equals.
|
||||
#define JSONTEST_ASSERT_STRING_EQUAL(expected, actual) \
|
||||
JsonTest::checkStringEqual(*result_, \
|
||||
std::string(expected), std::string(actual), \
|
||||
__FILE__, __LINE__, \
|
||||
std::string(expected), \
|
||||
std::string(actual), \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
#expected " == " #actual)
|
||||
|
||||
/// \brief Begin a fixture test case.
|
||||
#define JSONTEST_FIXTURE(FixtureType, name) \
|
||||
class Test##FixtureType##name : public FixtureType \
|
||||
{ \
|
||||
class Test##FixtureType##name : public FixtureType { \
|
||||
public: \
|
||||
static JsonTest::TestCase *factory() \
|
||||
{ \
|
||||
static JsonTest::TestCase *factory() { \
|
||||
return new Test##FixtureType##name(); \
|
||||
} \
|
||||
\
|
||||
public: /* overidden from TestCase */ \
|
||||
virtual const char *testName() const \
|
||||
{ \
|
||||
return #FixtureType "/" #name; \
|
||||
} \
|
||||
virtual const char *testName() const { return #FixtureType "/" #name; } \
|
||||
virtual void runTestCase(); \
|
||||
}; \
|
||||
\
|
||||
|
@ -22,7 +22,6 @@ static const float kfint64max = float(kint64max);
|
||||
static const float kfint32max = float(kint32max);
|
||||
static const float kfuint32max = float(kuint32max);
|
||||
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// Json Library test cases
|
||||
@ -30,19 +29,17 @@ static const float kfuint32max = float(kuint32max);
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
||||
static inline double uint64ToDouble( Json::UInt64 value )
|
||||
{
|
||||
static inline double uint64ToDouble(Json::UInt64 value) {
|
||||
return static_cast<double>(value);
|
||||
}
|
||||
#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
||||
static inline double uint64ToDouble( Json::UInt64 value )
|
||||
{
|
||||
return static_cast<double>( Json::Int64(value/2) ) * 2.0 + Json::Int64(value & 1);
|
||||
static inline double uint64ToDouble(Json::UInt64 value) {
|
||||
return static_cast<double>(Json::Int64(value / 2)) * 2.0 +
|
||||
Json::Int64(value & 1);
|
||||
}
|
||||
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
||||
|
||||
struct ValueTest : JsonTest::TestCase
|
||||
{
|
||||
struct ValueTest : JsonTest::TestCase {
|
||||
Json::Value null_;
|
||||
Json::Value emptyArray_;
|
||||
Json::Value emptyObject_;
|
||||
@ -59,27 +56,17 @@ struct ValueTest : JsonTest::TestCase
|
||||
Json::Value true_;
|
||||
Json::Value false_;
|
||||
|
||||
|
||||
ValueTest()
|
||||
: emptyArray_( Json::arrayValue )
|
||||
, emptyObject_( Json::objectValue )
|
||||
, integer_( 123456789 )
|
||||
, unsignedInteger_( 34567890u )
|
||||
, smallUnsignedInteger_( Json::Value::UInt( Json::Value::maxInt ) )
|
||||
, real_( 1234.56789 )
|
||||
, float_( 0.00390625f )
|
||||
, emptyString_( "" )
|
||||
, string1_( "a" )
|
||||
, string_( "sometext with space" )
|
||||
, true_( true )
|
||||
, false_( false )
|
||||
{
|
||||
: emptyArray_(Json::arrayValue), emptyObject_(Json::objectValue),
|
||||
integer_(123456789), unsignedInteger_(34567890u),
|
||||
smallUnsignedInteger_(Json::Value::UInt(Json::Value::maxInt)),
|
||||
real_(1234.56789), float_(0.00390625f), emptyString_(""), string1_("a"),
|
||||
string_("sometext with space"), true_(true), false_(false) {
|
||||
array1_.append(1234);
|
||||
object1_["id"] = 1234;
|
||||
}
|
||||
|
||||
struct IsCheck
|
||||
{
|
||||
struct IsCheck {
|
||||
/// Initialize all checks to \c false by default.
|
||||
IsCheck();
|
||||
|
||||
@ -98,7 +85,8 @@ struct ValueTest : JsonTest::TestCase
|
||||
bool isNumeric_;
|
||||
};
|
||||
|
||||
void checkConstMemberCount( const Json::Value &value, unsigned int expectedCount );
|
||||
void checkConstMemberCount(const Json::Value &value,
|
||||
unsigned int expectedCount);
|
||||
|
||||
void checkMemberCount(Json::Value &value, unsigned int expectedCount);
|
||||
|
||||
@ -108,23 +96,23 @@ struct ValueTest : JsonTest::TestCase
|
||||
|
||||
void checkIsEqual(const Json::Value &x, const Json::Value &y);
|
||||
|
||||
/// Normalize the representation of floating-point number by stripped leading 0 in exponent.
|
||||
/// Normalize the representation of floating-point number by stripped leading
|
||||
/// 0 in exponent.
|
||||
static std::string normalizeFloatingPointStr(const std::string &s);
|
||||
};
|
||||
|
||||
|
||||
std::string
|
||||
ValueTest::normalizeFloatingPointStr( const std::string &s )
|
||||
{
|
||||
std::string ValueTest::normalizeFloatingPointStr(const std::string &s) {
|
||||
std::string::size_type index = s.find_last_of("eE");
|
||||
if ( index != std::string::npos )
|
||||
{
|
||||
std::string::size_type hasSign = (s[index+1] == '+' || s[index+1] == '-') ? 1 : 0;
|
||||
if (index != std::string::npos) {
|
||||
std::string::size_type hasSign =
|
||||
(s[index + 1] == '+' || s[index + 1] == '-') ? 1 : 0;
|
||||
std::string::size_type exponentStartIndex = index + 1 + hasSign;
|
||||
std::string normalized = s.substr(0, exponentStartIndex);
|
||||
std::string::size_type indexDigit = s.find_first_not_of( '0', exponentStartIndex );
|
||||
std::string::size_type indexDigit =
|
||||
s.find_first_not_of('0', exponentStartIndex);
|
||||
std::string exponent = "0";
|
||||
if ( indexDigit != std::string::npos ) // There is an exponent different from 0
|
||||
if (indexDigit !=
|
||||
std::string::npos) // There is an exponent different from 0
|
||||
{
|
||||
exponent = s.substr(indexDigit);
|
||||
}
|
||||
@ -133,27 +121,31 @@ ValueTest::normalizeFloatingPointStr( const std::string &s )
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, checkNormalizeFloatingPointStr )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, checkNormalizeFloatingPointStr) {
|
||||
JSONTEST_ASSERT_STRING_EQUAL("0.0", normalizeFloatingPointStr("0.0"));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("0e0", normalizeFloatingPointStr("0e0"));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1234.0", normalizeFloatingPointStr("1234.0"));
|
||||
JSONTEST_ASSERT_STRING_EQUAL( "1234.0e0", normalizeFloatingPointStr("1234.0e0") );
|
||||
JSONTEST_ASSERT_STRING_EQUAL( "1234.0e+0", normalizeFloatingPointStr("1234.0e+0") );
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1234.0e0",
|
||||
normalizeFloatingPointStr("1234.0e0"));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1234.0e+0",
|
||||
normalizeFloatingPointStr("1234.0e+0"));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1234e-1", normalizeFloatingPointStr("1234e-1"));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1234e10", normalizeFloatingPointStr("1234e10"));
|
||||
JSONTEST_ASSERT_STRING_EQUAL( "1234e10", normalizeFloatingPointStr("1234e010") );
|
||||
JSONTEST_ASSERT_STRING_EQUAL( "1234e+10", normalizeFloatingPointStr("1234e+010") );
|
||||
JSONTEST_ASSERT_STRING_EQUAL( "1234e-10", normalizeFloatingPointStr("1234e-010") );
|
||||
JSONTEST_ASSERT_STRING_EQUAL( "1234e+100", normalizeFloatingPointStr("1234e+100") );
|
||||
JSONTEST_ASSERT_STRING_EQUAL( "1234e-100", normalizeFloatingPointStr("1234e-100") );
|
||||
JSONTEST_ASSERT_STRING_EQUAL( "1234e+1", normalizeFloatingPointStr("1234e+001") );
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1234e10",
|
||||
normalizeFloatingPointStr("1234e010"));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1234e+10",
|
||||
normalizeFloatingPointStr("1234e+010"));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1234e-10",
|
||||
normalizeFloatingPointStr("1234e-010"));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1234e+100",
|
||||
normalizeFloatingPointStr("1234e+100"));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1234e-100",
|
||||
normalizeFloatingPointStr("1234e-100"));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1234e+1",
|
||||
normalizeFloatingPointStr("1234e+001"));
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, memberCount )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, memberCount) {
|
||||
JSONTEST_ASSERT_PRED(checkMemberCount(emptyArray_, 0));
|
||||
JSONTEST_ASSERT_PRED(checkMemberCount(emptyObject_, 0));
|
||||
JSONTEST_ASSERT_PRED(checkMemberCount(array1_, 1));
|
||||
@ -168,9 +160,7 @@ JSONTEST_FIXTURE( ValueTest, memberCount )
|
||||
JSONTEST_ASSERT_PRED(checkMemberCount(true_, 0));
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, objects )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, objects) {
|
||||
// Types
|
||||
IsCheck checks;
|
||||
checks.isObject_ = true;
|
||||
@ -210,9 +200,7 @@ JSONTEST_FIXTURE( ValueTest, objects )
|
||||
JSONTEST_ASSERT_EQUAL(Json::Value("foo"), object1_["some other id"]);
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, arrays )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, arrays) {
|
||||
const unsigned int index0 = 0;
|
||||
|
||||
// Types
|
||||
@ -254,9 +242,7 @@ JSONTEST_FIXTURE( ValueTest, arrays )
|
||||
JSONTEST_ASSERT_EQUAL(Json::Value(17), array1_[2]);
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, null )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, null) {
|
||||
JSONTEST_ASSERT_EQUAL(Json::nullValue, null_.type());
|
||||
|
||||
IsCheck checks;
|
||||
@ -281,9 +267,7 @@ JSONTEST_FIXTURE( ValueTest, null )
|
||||
JSONTEST_ASSERT_STRING_EQUAL("", null_.asString());
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, strings )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, strings) {
|
||||
JSONTEST_ASSERT_EQUAL(Json::stringValue, string1_.type());
|
||||
|
||||
IsCheck checks;
|
||||
@ -312,9 +296,7 @@ JSONTEST_FIXTURE( ValueTest, strings )
|
||||
JSONTEST_ASSERT_STRING_EQUAL("a", string1_.asCString());
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, bools )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, bools) {
|
||||
JSONTEST_ASSERT_EQUAL(Json::booleanValue, false_.type());
|
||||
|
||||
IsCheck checks;
|
||||
@ -356,9 +338,7 @@ JSONTEST_FIXTURE( ValueTest, bools )
|
||||
JSONTEST_ASSERT_EQUAL(0.0, false_.asFloat());
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, integers )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, integers) {
|
||||
IsCheck checks;
|
||||
Json::Value val;
|
||||
|
||||
@ -630,7 +610,8 @@ JSONTEST_FIXTURE( ValueTest, integers )
|
||||
JSONTEST_ASSERT_EQUAL((1 << 20), val.asDouble());
|
||||
JSONTEST_ASSERT_EQUAL((1 << 20), val.asFloat());
|
||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1048576", normalizeFloatingPointStr(val.asString()));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1048576",
|
||||
normalizeFloatingPointStr(val.asString()));
|
||||
|
||||
// -2^20
|
||||
val = Json::Value(-(1 << 20));
|
||||
@ -870,7 +851,8 @@ JSONTEST_FIXTURE( ValueTest, integers )
|
||||
JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asDouble());
|
||||
JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asFloat());
|
||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1099511627776", normalizeFloatingPointStr(val.asString()));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1099511627776",
|
||||
normalizeFloatingPointStr(val.asString()));
|
||||
|
||||
// -2^40
|
||||
val = Json::Value(-(Json::Int64(1) << 40));
|
||||
@ -941,9 +923,11 @@ JSONTEST_FIXTURE( ValueTest, integers )
|
||||
JSONTEST_ASSERT_EQUAL(Json::UInt64(1) << 63, val.asUInt64());
|
||||
JSONTEST_ASSERT_EQUAL(Json::UInt64(1) << 63, val.asLargestUInt());
|
||||
JSONTEST_ASSERT_EQUAL(uint64ToDouble(Json::UInt64(1) << 63), val.asDouble());
|
||||
JSONTEST_ASSERT_EQUAL(float(uint64ToDouble(Json::UInt64(1) << 63)), val.asFloat());
|
||||
JSONTEST_ASSERT_EQUAL(float(uint64ToDouble(Json::UInt64(1) << 63)),
|
||||
val.asFloat());
|
||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||
JSONTEST_ASSERT_STRING_EQUAL("9.223372036854776e+18", normalizeFloatingPointStr(val.asString()));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("9.223372036854776e+18",
|
||||
normalizeFloatingPointStr(val.asString()));
|
||||
|
||||
// int64 min
|
||||
val = Json::Value(Json::Int64(kint64min));
|
||||
@ -990,7 +974,8 @@ JSONTEST_FIXTURE( ValueTest, integers )
|
||||
JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asDouble());
|
||||
JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asFloat());
|
||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||
JSONTEST_ASSERT_STRING_EQUAL("-9.223372036854776e+18", normalizeFloatingPointStr(val.asString()));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("-9.223372036854776e+18",
|
||||
normalizeFloatingPointStr(val.asString()));
|
||||
|
||||
// 10^19
|
||||
const Json::UInt64 ten_to_19 = static_cast<Json::UInt64>(1e19);
|
||||
@ -1036,7 +1021,8 @@ JSONTEST_FIXTURE( ValueTest, integers )
|
||||
JSONTEST_ASSERT_EQUAL(1e19, val.asDouble());
|
||||
JSONTEST_ASSERT_EQUAL(1e19, val.asFloat());
|
||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1e+19", normalizeFloatingPointStr(val.asString()));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1e+19",
|
||||
normalizeFloatingPointStr(val.asString()));
|
||||
|
||||
// uint64 max
|
||||
val = Json::Value(Json::UInt64(kuint64max));
|
||||
@ -1079,13 +1065,12 @@ JSONTEST_FIXTURE( ValueTest, integers )
|
||||
JSONTEST_ASSERT_EQUAL(18446744073709551616.0, val.asDouble());
|
||||
JSONTEST_ASSERT_EQUAL(18446744073709551616.0, val.asFloat());
|
||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1.844674407370955e+19", normalizeFloatingPointStr(val.asString()));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1.844674407370955e+19",
|
||||
normalizeFloatingPointStr(val.asString()));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, nonIntegers )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, nonIntegers) {
|
||||
IsCheck checks;
|
||||
Json::Value val;
|
||||
|
||||
@ -1170,7 +1155,8 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers )
|
||||
JSONTEST_ASSERT_EQUAL(2147483647U, val.asLargestUInt());
|
||||
#endif
|
||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||
JSONTEST_ASSERT_EQUAL("2147483647.5", normalizeFloatingPointStr(val.asString()));
|
||||
JSONTEST_ASSERT_EQUAL("2147483647.5",
|
||||
normalizeFloatingPointStr(val.asString()));
|
||||
|
||||
// A bit under int32 min
|
||||
val = Json::Value(kint32min - 0.5);
|
||||
@ -1197,7 +1183,8 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers )
|
||||
JSONTEST_ASSERT_EQUAL(-Json::Int64(1) << 31, val.asLargestInt());
|
||||
#endif
|
||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||
JSONTEST_ASSERT_EQUAL("-2147483648.5", normalizeFloatingPointStr(val.asString()));
|
||||
JSONTEST_ASSERT_EQUAL("-2147483648.5",
|
||||
normalizeFloatingPointStr(val.asString()));
|
||||
|
||||
// A bit over uint32 max
|
||||
val = Json::Value(kuint32max + 0.5);
|
||||
@ -1222,52 +1209,53 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers )
|
||||
JSONTEST_ASSERT_EQUAL(float(4294967295.5), val.asFloat());
|
||||
#ifdef JSON_HAS_INT64
|
||||
JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 32) - 1, val.asLargestInt());
|
||||
JSONTEST_ASSERT_EQUAL((Json::UInt64(1) << 32)-Json::UInt64(1), val.asLargestUInt());
|
||||
JSONTEST_ASSERT_EQUAL((Json::UInt64(1) << 32) - Json::UInt64(1),
|
||||
val.asLargestUInt());
|
||||
#endif
|
||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||
JSONTEST_ASSERT_EQUAL("4294967295.5", normalizeFloatingPointStr(val.asString()));
|
||||
JSONTEST_ASSERT_EQUAL("4294967295.5",
|
||||
normalizeFloatingPointStr(val.asString()));
|
||||
|
||||
val = Json::Value(1.2345678901234);
|
||||
JSONTEST_ASSERT_STRING_EQUAL( "1.2345678901234", normalizeFloatingPointStr(val.asString()));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1.2345678901234",
|
||||
normalizeFloatingPointStr(val.asString()));
|
||||
|
||||
// A 16-digit floating point number.
|
||||
val = Json::Value(2199023255552000.0f);
|
||||
JSONTEST_ASSERT_EQUAL(float(2199023255552000), val.asFloat());
|
||||
JSONTEST_ASSERT_STRING_EQUAL("2199023255552000", normalizeFloatingPointStr(val.asString()));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("2199023255552000",
|
||||
normalizeFloatingPointStr(val.asString()));
|
||||
|
||||
// A very large floating point number.
|
||||
val = Json::Value(3.402823466385289e38);
|
||||
JSONTEST_ASSERT_EQUAL(float(3.402823466385289e38), val.asFloat());
|
||||
JSONTEST_ASSERT_STRING_EQUAL("3.402823466385289e+38", normalizeFloatingPointStr(val.asString()));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("3.402823466385289e+38",
|
||||
normalizeFloatingPointStr(val.asString()));
|
||||
|
||||
// An even larger floating point number.
|
||||
val = Json::Value(1.2345678e300);
|
||||
JSONTEST_ASSERT_EQUAL(double(1.2345678e300), val.asDouble());
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1.2345678e+300", normalizeFloatingPointStr(val.asString()));
|
||||
JSONTEST_ASSERT_STRING_EQUAL("1.2345678e+300",
|
||||
normalizeFloatingPointStr(val.asString()));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueTest::checkConstMemberCount( const Json::Value &value, unsigned int expectedCount )
|
||||
{
|
||||
void ValueTest::checkConstMemberCount(const Json::Value &value,
|
||||
unsigned int expectedCount) {
|
||||
unsigned int count = 0;
|
||||
Json::Value::const_iterator itEnd = value.end();
|
||||
for ( Json::Value::const_iterator it = value.begin(); it != itEnd; ++it )
|
||||
{
|
||||
for (Json::Value::const_iterator it = value.begin(); it != itEnd; ++it) {
|
||||
++count;
|
||||
}
|
||||
JSONTEST_ASSERT_EQUAL(expectedCount, count) << "Json::Value::const_iterator";
|
||||
}
|
||||
|
||||
void
|
||||
ValueTest::checkMemberCount( Json::Value &value, unsigned int expectedCount )
|
||||
{
|
||||
void ValueTest::checkMemberCount(Json::Value &value,
|
||||
unsigned int expectedCount) {
|
||||
JSONTEST_ASSERT_EQUAL(expectedCount, value.size());
|
||||
|
||||
unsigned int count = 0;
|
||||
Json::Value::iterator itEnd = value.end();
|
||||
for ( Json::Value::iterator it = value.begin(); it != itEnd; ++it )
|
||||
{
|
||||
for (Json::Value::iterator it = value.begin(); it != itEnd; ++it) {
|
||||
++count;
|
||||
}
|
||||
JSONTEST_ASSERT_EQUAL(expectedCount, count) << "Json::Value::iterator";
|
||||
@ -1275,27 +1263,13 @@ ValueTest::checkMemberCount( Json::Value &value, unsigned int expectedCount )
|
||||
JSONTEST_ASSERT_PRED(checkConstMemberCount(value, expectedCount));
|
||||
}
|
||||
|
||||
|
||||
ValueTest::IsCheck::IsCheck()
|
||||
: isObject_( false )
|
||||
, isArray_( false )
|
||||
, isBool_( false )
|
||||
, isString_( false )
|
||||
, isNull_( false )
|
||||
, isInt_( false )
|
||||
, isInt64_( false )
|
||||
, isUInt_( false )
|
||||
, isUInt64_( false )
|
||||
, isIntegral_( false )
|
||||
, isDouble_( false )
|
||||
, isNumeric_( false )
|
||||
{
|
||||
}
|
||||
: isObject_(false), isArray_(false), isBool_(false), isString_(false),
|
||||
isNull_(false), isInt_(false), isInt64_(false), isUInt_(false),
|
||||
isUInt64_(false), isIntegral_(false), isDouble_(false),
|
||||
isNumeric_(false) {}
|
||||
|
||||
|
||||
void
|
||||
ValueTest::checkIs( const Json::Value &value, const IsCheck &check )
|
||||
{
|
||||
void ValueTest::checkIs(const Json::Value &value, const IsCheck &check) {
|
||||
JSONTEST_ASSERT_EQUAL(check.isObject_, value.isObject());
|
||||
JSONTEST_ASSERT_EQUAL(check.isArray_, value.isArray());
|
||||
JSONTEST_ASSERT_EQUAL(check.isBool_, value.isBool());
|
||||
@ -1316,40 +1290,31 @@ ValueTest::checkIs( const Json::Value &value, const IsCheck &check )
|
||||
#endif
|
||||
}
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, compareNull )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, compareNull) {
|
||||
JSONTEST_ASSERT_PRED(checkIsEqual(Json::Value(), Json::Value()));
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, compareInt )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, compareInt) {
|
||||
JSONTEST_ASSERT_PRED(checkIsLess(0, 10));
|
||||
JSONTEST_ASSERT_PRED(checkIsEqual(10, 10));
|
||||
JSONTEST_ASSERT_PRED(checkIsEqual(-10, -10));
|
||||
JSONTEST_ASSERT_PRED(checkIsLess(-10, 0));
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, compareUInt )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, compareUInt) {
|
||||
JSONTEST_ASSERT_PRED(checkIsLess(0u, 10u));
|
||||
JSONTEST_ASSERT_PRED(checkIsLess(0u, Json::Value::maxUInt));
|
||||
JSONTEST_ASSERT_PRED(checkIsEqual(10u, 10u));
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, compareDouble )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, compareDouble) {
|
||||
JSONTEST_ASSERT_PRED(checkIsLess(0.0, 10.0));
|
||||
JSONTEST_ASSERT_PRED(checkIsEqual(10.0, 10.0));
|
||||
JSONTEST_ASSERT_PRED(checkIsEqual(-10.0, -10.0));
|
||||
JSONTEST_ASSERT_PRED(checkIsLess(-10.0, 0.0));
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, compareString )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, compareString) {
|
||||
JSONTEST_ASSERT_PRED(checkIsLess("", " "));
|
||||
JSONTEST_ASSERT_PRED(checkIsLess("", "a"));
|
||||
JSONTEST_ASSERT_PRED(checkIsLess("abcd", "zyui"));
|
||||
@ -1360,17 +1325,13 @@ JSONTEST_FIXTURE( ValueTest, compareString )
|
||||
JSONTEST_ASSERT_PRED(checkIsEqual("ABCD", "ABCD"));
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, compareBoolean )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, compareBoolean) {
|
||||
JSONTEST_ASSERT_PRED(checkIsLess(false, true));
|
||||
JSONTEST_ASSERT_PRED(checkIsEqual(false, false));
|
||||
JSONTEST_ASSERT_PRED(checkIsEqual(true, true));
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, compareArray )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, compareArray) {
|
||||
// array compare size then content
|
||||
Json::Value emptyArray(Json::arrayValue);
|
||||
Json::Value l1aArray;
|
||||
@ -1392,9 +1353,7 @@ JSONTEST_FIXTURE( ValueTest, compareArray )
|
||||
JSONTEST_ASSERT_PRED(checkIsEqual(l2bArray, Json::Value(l2bArray)));
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, compareObject )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, compareObject) {
|
||||
// object compare size then content
|
||||
Json::Value emptyObject(Json::objectValue);
|
||||
Json::Value l1aObject;
|
||||
@ -1412,23 +1371,20 @@ JSONTEST_FIXTURE( ValueTest, compareObject )
|
||||
JSONTEST_ASSERT_PRED(checkIsEqual(l2aObject, Json::Value(l2aObject)));
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, compareType )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, compareType) {
|
||||
// object of different type are ordered according to their type
|
||||
JSONTEST_ASSERT_PRED(checkIsLess(Json::Value(), Json::Value(1)));
|
||||
JSONTEST_ASSERT_PRED(checkIsLess(Json::Value(1), Json::Value(1u)));
|
||||
JSONTEST_ASSERT_PRED(checkIsLess(Json::Value(1u), Json::Value(1.0)));
|
||||
JSONTEST_ASSERT_PRED(checkIsLess(Json::Value(1.0), Json::Value("a")));
|
||||
JSONTEST_ASSERT_PRED(checkIsLess(Json::Value("a"), Json::Value(true)));
|
||||
JSONTEST_ASSERT_PRED( checkIsLess( Json::Value(true), Json::Value(Json::arrayValue) ) );
|
||||
JSONTEST_ASSERT_PRED( checkIsLess( Json::Value(Json::arrayValue), Json::Value(Json::objectValue) ) );
|
||||
JSONTEST_ASSERT_PRED(
|
||||
checkIsLess(Json::Value(true), Json::Value(Json::arrayValue)));
|
||||
JSONTEST_ASSERT_PRED(checkIsLess(Json::Value(Json::arrayValue),
|
||||
Json::Value(Json::objectValue)));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueTest::checkIsLess( const Json::Value &x, const Json::Value &y )
|
||||
{
|
||||
void ValueTest::checkIsLess(const Json::Value &x, const Json::Value &y) {
|
||||
JSONTEST_ASSERT(x < y);
|
||||
JSONTEST_ASSERT(y > x);
|
||||
JSONTEST_ASSERT(x <= y);
|
||||
@ -1443,10 +1399,7 @@ ValueTest::checkIsLess( const Json::Value &x, const Json::Value &y )
|
||||
JSONTEST_ASSERT(y.compare(x) >= 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueTest::checkIsEqual( const Json::Value &x, const Json::Value &y )
|
||||
{
|
||||
void ValueTest::checkIsEqual(const Json::Value &x, const Json::Value &y) {
|
||||
JSONTEST_ASSERT(x == y);
|
||||
JSONTEST_ASSERT(y == x);
|
||||
JSONTEST_ASSERT(x <= y);
|
||||
@ -1461,24 +1414,21 @@ ValueTest::checkIsEqual( const Json::Value &x, const Json::Value &y )
|
||||
JSONTEST_ASSERT(y.compare(x) == 0);
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, checkInteger )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, checkInteger) {
|
||||
#if JSON_USE_EXCEPTION
|
||||
try {
|
||||
Json::Value x = 1;
|
||||
x["key"]; // SIGABRT?
|
||||
// regression for https://sourceforge.net/p/jsoncpp/bugs/67/
|
||||
JSONTEST_ASSERT(0);
|
||||
} catch (std::runtime_error const&) {
|
||||
}
|
||||
catch (std::runtime_error const &) {
|
||||
JSONTEST_ASSERT(1); // good
|
||||
}
|
||||
#endif // JSON_USE_EXCEPTION
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ValueTest, offsetAccessors )
|
||||
{
|
||||
JSONTEST_FIXTURE(ValueTest, offsetAccessors) {
|
||||
Json::Value x;
|
||||
JSONTEST_ASSERT(x.getOffsetStart() == 0);
|
||||
JSONTEST_ASSERT(x.getOffsetLimit() == 0);
|
||||
@ -1497,13 +1447,9 @@ JSONTEST_FIXTURE( ValueTest, offsetAccessors )
|
||||
JSONTEST_ASSERT(y.getOffsetLimit() == 0);
|
||||
}
|
||||
|
||||
struct WriterTest : JsonTest::TestCase
|
||||
{
|
||||
};
|
||||
struct WriterTest : JsonTest::TestCase {};
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( WriterTest, dropNullPlaceholders )
|
||||
{
|
||||
JSONTEST_FIXTURE(WriterTest, dropNullPlaceholders) {
|
||||
Json::FastWriter writer;
|
||||
Json::Value nullValue;
|
||||
JSONTEST_ASSERT(writer.write(nullValue) == "null\n");
|
||||
@ -1512,31 +1458,23 @@ JSONTEST_FIXTURE( WriterTest, dropNullPlaceholders )
|
||||
JSONTEST_ASSERT(writer.write(nullValue) == "\n");
|
||||
}
|
||||
|
||||
struct ReaderTest : JsonTest::TestCase {};
|
||||
|
||||
struct ReaderTest : JsonTest::TestCase
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ReaderTest, parseWithNoErrors )
|
||||
{
|
||||
JSONTEST_FIXTURE(ReaderTest, parseWithNoErrors) {
|
||||
Json::Reader reader;
|
||||
Json::Value root;
|
||||
bool ok = reader.parse(
|
||||
"{ \"property\" : \"value\" }",
|
||||
root);
|
||||
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 )
|
||||
{
|
||||
JSONTEST_FIXTURE(ReaderTest, parseWithNoErrorsTestingOffsets) {
|
||||
Json::Reader reader;
|
||||
Json::Value root;
|
||||
bool ok = reader.parse(
|
||||
"{ \"property\" : [\"value\", \"value2\"], \"obj\" : { \"nested\" : 123, \"bool\" : true}, \"null\" : null, \"false\" : false }",
|
||||
bool ok = reader.parse("{ \"property\" : [\"value\", \"value2\"], \"obj\" : "
|
||||
"{ \"nested\" : 123, \"bool\" : true}, \"null\" : "
|
||||
"null, \"false\" : false }",
|
||||
root);
|
||||
JSONTEST_ASSERT(ok);
|
||||
JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0);
|
||||
@ -1561,17 +1499,14 @@ JSONTEST_FIXTURE( ReaderTest, parseWithNoErrorsTestingOffsets )
|
||||
JSONTEST_ASSERT(root.getOffsetLimit() == 110);
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ReaderTest, parseWithOneError )
|
||||
{
|
||||
JSONTEST_FIXTURE(ReaderTest, parseWithOneError) {
|
||||
Json::Reader reader;
|
||||
Json::Value root;
|
||||
bool ok = reader.parse(
|
||||
"{ \"property\" :: \"value\" }",
|
||||
root);
|
||||
bool ok = reader.parse("{ \"property\" :: \"value\" }", root);
|
||||
JSONTEST_ASSERT(!ok);
|
||||
JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
|
||||
"* Line 1, Column 15\n Syntax error: value, object or array expected.\n" );
|
||||
"* 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);
|
||||
@ -1581,17 +1516,14 @@ JSONTEST_FIXTURE( ReaderTest, parseWithOneError )
|
||||
"Syntax error: value, object or array expected.");
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ReaderTest, parseChineseWithOneError )
|
||||
{
|
||||
JSONTEST_FIXTURE(ReaderTest, parseChineseWithOneError) {
|
||||
Json::Reader reader;
|
||||
Json::Value root;
|
||||
bool ok = reader.parse(
|
||||
"{ \"pr佐藤erty\" :: \"value\" }",
|
||||
root);
|
||||
bool ok = reader.parse("{ \"pr佐藤erty\" :: \"value\" }", root);
|
||||
JSONTEST_ASSERT(!ok);
|
||||
JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
|
||||
"* Line 1, Column 19\n Syntax error: value, object or array expected.\n" );
|
||||
"* 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);
|
||||
@ -1601,29 +1533,23 @@ JSONTEST_FIXTURE( ReaderTest, parseChineseWithOneError )
|
||||
"Syntax error: value, object or array expected.");
|
||||
}
|
||||
|
||||
|
||||
JSONTEST_FIXTURE( ReaderTest, parseWithDetailError )
|
||||
{
|
||||
JSONTEST_FIXTURE(ReaderTest, parseWithDetailError) {
|
||||
Json::Reader reader;
|
||||
Json::Value root;
|
||||
bool ok = reader.parse(
|
||||
"{ \"property\" : \"v\\alue\" }",
|
||||
root);
|
||||
bool ok = reader.parse("{ \"property\" : \"v\\alue\" }", root);
|
||||
JSONTEST_ASSERT(!ok);
|
||||
JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
|
||||
"* Line 1, Column 16\n Bad escape sequence in string\nSee Line 1, Column 20 for detail.\n" );
|
||||
"* 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" );
|
||||
JSONTEST_ASSERT(errors.at(0).message == "Bad escape sequence in string");
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, const char *argv[] )
|
||||
{
|
||||
int main(int argc, const char *argv[]) {
|
||||
JsonTest::Runner runner;
|
||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, checkNormalizeFloatingPointStr);
|
||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, memberCount);
|
||||
@ -1647,7 +1573,8 @@ int main( int argc, const char *argv[] )
|
||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, offsetAccessors);
|
||||
|
||||
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithNoErrors);
|
||||
JSONTEST_REGISTER_FIXTURE( runner, ReaderTest, parseWithNoErrorsTestingOffsets );
|
||||
JSONTEST_REGISTER_FIXTURE(
|
||||
runner, ReaderTest, parseWithNoErrorsTestingOffsets);
|
||||
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithOneError);
|
||||
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseChineseWithOneError);
|
||||
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithDetailError);
|
||||
|
Loading…
x
Reference in New Issue
Block a user