Rewrite and revert some code to build in pre-C++11

Rewerite and revert some code that this library can be built in pre-C++11 and C++11 env.
Main Change List:
1. using -> typedef
2. not using auto & decltype
3. not using raw string literals
4. ..., other c++11 features will be chosen to compile, depending on env.
This commit is contained in:
chenguoping 2020-04-30 11:24:36 +08:00
parent a4fb5db543
commit d2c205206d
22 changed files with 688 additions and 511 deletions

View File

@ -1,4 +1,5 @@
#include "json/json.h" #include "json/json.h"
#include <cstdlib>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
/** \brief Parse from stream, collect comments and capture error info. /** \brief Parse from stream, collect comments and capture error info.

View File

@ -1,4 +1,5 @@
#include "json/json.h" #include "json/json.h"
#include <cstdlib>
#include <iostream> #include <iostream>
/** /**
* \brief Parse a raw string into Value object using the CharReaderBuilder * \brief Parse a raw string into Value object using the CharReaderBuilder
@ -10,9 +11,9 @@
* 20 * 20
*/ */
int main() { int main() {
const std::string rawJson = R"({"Age": 20, "Name": "colin"})"; const std::string rawJson = "{\"Age\": 20, \"Name\": \"colin\"}";
const auto rawJsonLength = static_cast<int>(rawJson.length()); const int rawJsonLength = static_cast<int>(rawJson.length());
constexpr bool shouldUseOldWay = false; JSONCPP_CONST bool shouldUseOldWay = false;
JSONCPP_STRING err; JSONCPP_STRING err;
Json::Value root; Json::Value root;
@ -21,12 +22,13 @@ int main() {
reader.parse(rawJson, root); reader.parse(rawJson, root);
} else { } else {
Json::CharReaderBuilder builder; Json::CharReaderBuilder builder;
const std::unique_ptr<Json::CharReader> reader(builder.newCharReader()); Json::CharReader* reader(builder.newCharReader());
if (!reader->parse(rawJson.c_str(), rawJson.c_str() + rawJsonLength, &root, if (!reader->parse(rawJson.c_str(), rawJson.c_str() + rawJsonLength, &root,
&err)) { &err)) {
std::cout << "error" << std::endl; std::cout << "error" << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
delete reader;
} }
const std::string name = root["Name"].asString(); const std::string name = root["Name"].asString();
const int age = root["Age"].asInt(); const int age = root["Age"].asInt();

View File

@ -12,11 +12,11 @@
int main() { int main() {
Json::Value root; Json::Value root;
Json::StreamWriterBuilder builder; Json::StreamWriterBuilder builder;
const std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter()); Json::StreamWriter* writer(builder.newStreamWriter());
root["Name"] = "robin"; root["Name"] = "robin";
root["Age"] = 20; root["Age"] = 20;
writer->write(root, &std::cout); writer->write(root, &std::cout);
delete writer;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -1,4 +1,5 @@
#include "json/json.h" #include "json/json.h"
#include <cstdlib>
#include <iostream> #include <iostream>
/** \brief Write a Value object to a string. /** \brief Write a Value object to a string.
* Example Usage: * Example Usage:
@ -15,7 +16,7 @@
int main() { int main() {
Json::Value root; Json::Value root;
Json::Value data; Json::Value data;
constexpr bool shouldUseOldWay = false; JSONCPP_CONST bool shouldUseOldWay = false;
root["action"] = "run"; root["action"] = "run";
data["number"] = 1; data["number"] = 1;
root["data"] = data; root["data"] = data;

View File

@ -58,4 +58,10 @@
} \ } \
} while (0) } while (0)
#if JSONCPP_CXX_STD_11
#define JSONCPP_STATIC_ASSERT static_assert
#else
#define JSONCPP_STATIC_ASSERT JSON_ASSERT_MESSAGE
#endif
#endif // JSON_ASSERTIONS_H_INCLUDED #endif // JSON_ASSERTIONS_H_INCLUDED

View File

@ -5,14 +5,20 @@
#ifndef JSON_CONFIG_H_INCLUDED #ifndef JSON_CONFIG_H_INCLUDED
#define JSON_CONFIG_H_INCLUDED #define JSON_CONFIG_H_INCLUDED
#include <cstddef>
#include <cstdint>
#include <istream> #include <istream>
#include <memory> #include <memory>
#include <ostream> #include <ostream>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <type_traits>
#if JSONCPP_CXX_STD_11
#include <cstddef> // typedef ptrdiff_t
#include <cstdint> // typedef int64_t, uint64_t
#else
#include <stddef.h>
#include <stdint.h>
#endif
// If non-zero, the library uses exceptions to report bad input instead of C // If non-zero, the library uses exceptions to report bad input instead of C
// assertion macros. The default is to use exceptions. // assertion macros. The default is to use exceptions.
@ -50,11 +56,6 @@
#define JSON_API #define JSON_API
#endif #endif
#if defined(_MSC_VER) && _MSC_VER < 1800
#error \
"ERROR: Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities"
#endif
#if defined(_MSC_VER) && _MSC_VER < 1900 #if defined(_MSC_VER) && _MSC_VER < 1900
// As recommended at // As recommended at
// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 // https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
@ -70,10 +71,41 @@ extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
// Storages, and 64 bits integer support is disabled. // Storages, and 64 bits integer support is disabled.
// #define JSON_NO_INT64 1 // #define JSON_NO_INT64 1
// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools. #if __cplusplus >= 201103L || defined(_MSC_VER)
// C++11 should be used directly in JSONCPP. #define JSONCPP_OP_EXPLICIT explicit
#define JSONCPP_OVERRIDE override #else
#define JSONCPP_OP_EXPLICIT
#endif
// These Macros are maintained for backwards compatibility of external tools.
#if (defined(_MSC_VER) && _MSC_VER >= 1900) || \
(defined(__GNUC__) && __cplusplus >= 201103L) || \
(defined(__clang__) && __clang_major__ == 3 && __clang_minor__ >= 3)
#define JSONCPP_CXX_STD_11 1
#else
#define JSONCPP_CXX_STD_11 0
#endif
#if JSONCPP_CXX_STD_11
#define JSONCPP_NULL nullptr
#define JSONCPP_CONST constexpr
#define JSONCPP_CTOR_DELETE = delete
#define JSONCPP_NOEXCEPT noexcept
#define JSONCPP_OVERRIDE override
#define JSONCPP_MOVE(value) std::move(value)
#else
#define JSONCPP_NULL NULL
#define JSONCPP_CONST const
#define JSONCPP_CTOR_DELETE
#define JSONCPP_NOEXCEPT throw()
#define JSONCPP_OVERRIDE
#define JSONCPP_MOVE(value) value
#endif
// Define *deprecated* attribute
// [[deprecated]] is in C++14 or in Visual Studio 2015 and later
// For compatibility, [[deprecated]] is not used
#ifdef __clang__ #ifdef __clang__
#if __has_extension(attribute_deprecated_with_message) #if __has_extension(attribute_deprecated_with_message)
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) #define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
@ -98,33 +130,36 @@ extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
#endif #endif
#if !defined(JSON_IS_AMALGAMATION) #if !defined(JSON_IS_AMALGAMATION)
#if JSONCPP_CXX_STD_11
#include "allocator.h" #include "allocator.h"
#endif
#include "version.h" #include "version.h"
#endif // if !defined(JSON_IS_AMALGAMATION) #endif // if !defined(JSON_IS_AMALGAMATION)
namespace Json { namespace Json {
using Int = int;
using UInt = unsigned int; typedef int Int;
typedef unsigned int UInt;
#if defined(JSON_NO_INT64) #if defined(JSON_NO_INT64)
using LargestInt = int; typedef int LargestInt;
using LargestUInt = unsigned int; typedef unsigned int LargestUInt;
#undef JSON_HAS_INT64 #undef JSON_HAS_INT64
#else // if defined(JSON_NO_INT64) #else // if defined(JSON_NO_INT64)
// For Microsoft Visual use specific types as long long is not supported // For Microsoft Visual use specific types as long long is not supported
#if defined(_MSC_VER) // Microsoft Visual Studio #if defined(_MSC_VER) // Microsoft Visual Studio
using Int64 = __int64; typedef __int64 Int64;
using UInt64 = unsigned __int64; typedef unsigned __int64 UInt64;
#else // if defined(_MSC_VER) // Other platforms, use long long #else // if defined(_MSC_VER) // Other platforms, use long long
using Int64 = int64_t; typedef int64_t Int64;
using UInt64 = uint64_t; typedef uint64_t UInt64;
#endif // if defined(_MSC_VER) #endif // if defined(_MSC_VER)
using LargestInt = Int64; typedef Int64 LargestInt;
using LargestUInt = UInt64; typedef UInt64 LargestUInt;
#define JSON_HAS_INT64 #define JSON_HAS_INT64
#endif // if defined(JSON_NO_INT64) #endif // if defined(JSON_NO_INT64)
#if JSONCPP_CXX_STD_11
template <typename T> template <typename T>
using Allocator = using Allocator =
typename std::conditional<JSONCPP_USING_SECURE_MEMORY, SecureAllocator<T>, typename std::conditional<JSONCPP_USING_SECURE_MEMORY, SecureAllocator<T>,
@ -138,13 +173,20 @@ using OStringStream =
String::allocator_type>; String::allocator_type>;
using IStream = std::istream; using IStream = std::istream;
using OStream = std::ostream; using OStream = std::ostream;
#else
typedef std::string String;
typedef std::istringstream IStringStream;
typedef std::ostringstream OStringStream;
typedef std::istream IStream;
typedef std::ostream OStream;
#endif // JSONCPP_CXX_STD_11
} // namespace Json } // namespace Json
// Legacy names (formerly macros). // Legacy names (formerly macros).
using JSONCPP_STRING = Json::String; typedef Json::String JSONCPP_STRING;
using JSONCPP_ISTRINGSTREAM = Json::IStringStream; typedef Json::IStringStream JSONCPP_ISTRINGSTREAM;
using JSONCPP_OSTRINGSTREAM = Json::OStringStream; typedef Json::OStringStream JSONCPP_OSTRINGSTREAM;
using JSONCPP_ISTREAM = Json::IStream; typedef Json::IStream JSONCPP_ISTREAM;
using JSONCPP_OSTREAM = Json::OStream; typedef Json::OStream JSONCPP_OSTREAM;
#endif // JSON_CONFIG_H_INCLUDED #endif // JSON_CONFIG_H_INCLUDED

View File

@ -29,7 +29,7 @@ class CharReaderBuilder;
class Features; class Features;
// value.h // value.h
using ArrayIndex = unsigned int; typedef unsigned int ArrayIndex;
class StaticString; class StaticString;
class Path; class Path;
class PathArgument; class PathArgument;

View File

@ -41,17 +41,17 @@ public:
Features(); Features();
/// \c true if comments are allowed. Default: \c true. /// \c true if comments are allowed. Default: \c true.
bool allowComments_{true}; bool allowComments_;
/// \c true if root must be either an array or an object value. Default: \c /// \c true if root must be either an array or an object value. Default: \c
/// false. /// false.
bool strictRoot_{false}; bool strictRoot_;
/// \c true if dropped null placeholders are allowed. Default: \c false. /// \c true if dropped null placeholders are allowed. Default: \c false.
bool allowDroppedNullPlaceholders_{false}; bool allowDroppedNullPlaceholders_;
/// \c true if numeric object key are allowed. Default: \c false. /// \c true if numeric object key are allowed. Default: \c false.
bool allowNumericKeys_{false}; bool allowNumericKeys_;
}; };
} // namespace Json } // namespace Json

View File

@ -36,8 +36,8 @@ namespace Json {
class JSONCPP_DEPRECATED( class JSONCPP_DEPRECATED(
"Use CharReader and CharReaderBuilder instead.") JSON_API Reader { "Use CharReader and CharReaderBuilder instead.") JSON_API Reader {
public: public:
using Char = char; typedef char Char;
using Location = const Char*; typedef const Char* Location;
/** \brief An error tagged with where in the JSON text it was encountered. /** \brief An error tagged with where in the JSON text it was encountered.
* *
@ -187,7 +187,7 @@ private:
Location extra_; Location extra_;
}; };
using Errors = std::deque<ErrorInfo>; typedef std::deque<ErrorInfo> Errors;
bool readToken(Token& token); bool readToken(Token& token);
void skipSpaces(); void skipSpaces();
@ -210,7 +210,8 @@ private:
unsigned int& unicode); unsigned int& unicode);
bool decodeUnicodeEscapeSequence(Token& token, Location& current, bool decodeUnicodeEscapeSequence(Token& token, Location& current,
Location end, unsigned int& unicode); Location end, unsigned int& unicode);
bool addError(const String& message, Token& token, Location extra = nullptr); bool addError(const String& message, Token& token,
Location extra = JSONCPP_NULL);
bool recoverFromError(TokenType skipUntilToken); bool recoverFromError(TokenType skipUntilToken);
bool addErrorAndRecover(const String& message, Token& token, bool addErrorAndRecover(const String& message, Token& token,
TokenType skipUntilToken); TokenType skipUntilToken);
@ -226,25 +227,25 @@ private:
static bool containsNewLine(Location begin, Location end); static bool containsNewLine(Location begin, Location end);
static String normalizeEOL(Location begin, Location end); static String normalizeEOL(Location begin, Location end);
using Nodes = std::stack<Value*>; typedef std::stack<Value*> Nodes;
Nodes nodes_; Nodes nodes_;
Errors errors_; Errors errors_;
String document_; String document_;
Location begin_{}; Location begin_;
Location end_{}; Location end_;
Location current_{}; Location current_;
Location lastValueEnd_{}; Location lastValueEnd_;
Value* lastValue_{}; Value* lastValue_;
String commentsBefore_; String commentsBefore_;
Features features_; Features features_;
bool collectComments_{}; bool collectComments_;
}; // Reader }; // Reader
/** Interface for reading JSON from a char array. /** Interface for reading JSON from a char array.
*/ */
class JSON_API CharReader { class JSON_API CharReader {
public: public:
virtual ~CharReader() = default; virtual ~CharReader() {}
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
* document. The document must be a UTF-8 encoded string containing the * document. The document must be a UTF-8 encoded string containing the
* document to read. * document to read.
@ -266,7 +267,7 @@ public:
class JSON_API Factory { class JSON_API Factory {
public: public:
virtual ~Factory() = default; virtual ~Factory() {}
/** \brief Allocate a CharReader via operator new(). /** \brief Allocate a CharReader via operator new().
* \throw std::exception if something goes wrong (e.g. invalid settings) * \throw std::exception if something goes wrong (e.g. invalid settings)
*/ */
@ -332,9 +333,9 @@ public:
Json::Value settings_; Json::Value settings_;
CharReaderBuilder(); CharReaderBuilder();
~CharReaderBuilder() override; ~CharReaderBuilder() JSONCPP_OVERRIDE;
CharReader* newCharReader() const override; CharReader* newCharReader() const JSONCPP_OVERRIDE;
/** \return true if 'settings' are legal and consistent; /** \return true if 'settings' are legal and consistent;
* otherwise, indicate bad settings via 'invalid'. * otherwise, indicate bad settings via 'invalid'.

View File

@ -13,13 +13,16 @@
// Conditional NORETURN attribute on the throw functions would: // Conditional NORETURN attribute on the throw functions would:
// a) suppress false positives from static code analysis // a) suppress false positives from static code analysis
// b) possibly improve optimization opportunities. // b) possibly improve optimization opportunities.
// For compatibility, [[noreturn]] is not used
#if !defined(JSONCPP_NORETURN) #if !defined(JSONCPP_NORETURN)
#if defined(_MSC_VER) && _MSC_VER == 1800 #if defined(_MSC_VER)
#define JSONCPP_NORETURN __declspec(noreturn) #define JSONCPP_NORETURN __declspec(noreturn)
#elif defined(__GNUC__) || defined(__clang__)
#define JSONCPP_NORETURN __attribute__((noreturn))
#else #else
#define JSONCPP_NORETURN [[noreturn]] #define JSONCPP_NORETURN
#endif
#endif #endif
#endif // if !defined(JSONCPP_NORETURN)
// Support for '= delete' with template declarations was a late addition // Support for '= delete' with template declarations was a late addition
// to the c++11 standard and is rejected by clang 3.8 and Apple clang 8.2 // to the c++11 standard and is rejected by clang 3.8 and Apple clang 8.2
@ -39,10 +42,15 @@
#endif #endif
#endif #endif
#include <array> #if JSONCPP_CXX_STD_11
#else
#undef JSONCPP_TEMPLATE_DELETE
#define JSONCPP_TEMPLATE_DELETE
#include <string.h>
#endif
#include <exception> #include <exception>
#include <map> #include <map>
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
@ -67,8 +75,8 @@ namespace Json {
class JSON_API Exception : public std::exception { class JSON_API Exception : public std::exception {
public: public:
Exception(String msg); Exception(String msg);
~Exception() noexcept override; ~Exception() JSONCPP_NOEXCEPT JSONCPP_OVERRIDE;
char const* what() const noexcept override; char const* what() const JSONCPP_NOEXCEPT JSONCPP_OVERRIDE;
protected: protected:
String msg_; String msg_;
@ -146,7 +154,7 @@ enum PrecisionType {
*/ */
class JSON_API StaticString { class JSON_API StaticString {
public: public:
explicit StaticString(const char* czstring) : c_str_(czstring) {} JSONCPP_OP_EXPLICIT StaticString(const char* czstring) : c_str_(czstring) {}
operator const char*() const { return c_str_; } operator const char*() const { return c_str_; }
@ -194,21 +202,21 @@ class JSON_API Value {
friend class ValueIteratorBase; friend class ValueIteratorBase;
public: public:
using Members = std::vector<String>; typedef std::vector<String> Members;
using iterator = ValueIterator; typedef ValueIterator iterator;
using const_iterator = ValueConstIterator; typedef ValueConstIterator const_iterator;
using UInt = Json::UInt; typedef Json::UInt UInt;
using Int = Json::Int; typedef Json::Int Int;
#if defined(JSON_HAS_INT64) #if defined(JSON_HAS_INT64)
using UInt64 = Json::UInt64; typedef Json::UInt64 UInt64;
using Int64 = Json::Int64; typedef Json::Int64 Int64;
#endif // defined(JSON_HAS_INT64) #endif // defined(JSON_HAS_INT64)
using LargestInt = Json::LargestInt; typedef Json::LargestInt LargestInt;
using LargestUInt = Json::LargestUInt; typedef Json::LargestUInt LargestUInt;
using ArrayIndex = Json::ArrayIndex; typedef Json::ArrayIndex ArrayIndex;
// Required for boost integration, e. g. BOOST_TEST // Required for boost integration, e. g. BOOST_TEST
using value_type = std::string; typedef std::string value_type;
#if JSON_USE_NULLREF #if JSON_USE_NULLREF
// Binary compatibility kludges, do not use. // Binary compatibility kludges, do not use.
@ -220,34 +228,35 @@ public:
static Value const& nullSingleton(); static Value const& nullSingleton();
/// Minimum signed integer value that can be stored in a Json::Value. /// Minimum signed integer value that can be stored in a Json::Value.
static constexpr LargestInt minLargestInt = static JSONCPP_CONST LargestInt minLargestInt =
LargestInt(~(LargestUInt(-1) / 2)); LargestInt(~(LargestUInt(-1) / 2));
/// Maximum signed integer value that can be stored in a Json::Value. /// Maximum signed integer value that can be stored in a Json::Value.
static constexpr LargestInt maxLargestInt = LargestInt(LargestUInt(-1) / 2); static JSONCPP_CONST LargestInt maxLargestInt =
LargestInt(LargestUInt(-1) / 2);
/// Maximum unsigned integer value that can be stored in a Json::Value. /// Maximum unsigned integer value that can be stored in a Json::Value.
static constexpr LargestUInt maxLargestUInt = LargestUInt(-1); static JSONCPP_CONST LargestUInt maxLargestUInt = LargestUInt(-1);
/// Minimum signed int value that can be stored in a Json::Value. /// Minimum signed int value that can be stored in a Json::Value.
static constexpr Int minInt = Int(~(UInt(-1) / 2)); static JSONCPP_CONST Int minInt = Int(~(UInt(-1) / 2));
/// Maximum signed int value that can be stored in a Json::Value. /// Maximum signed int value that can be stored in a Json::Value.
static constexpr Int maxInt = Int(UInt(-1) / 2); static JSONCPP_CONST Int maxInt = Int(UInt(-1) / 2);
/// Maximum unsigned int value that can be stored in a Json::Value. /// Maximum unsigned int value that can be stored in a Json::Value.
static constexpr UInt maxUInt = UInt(-1); static JSONCPP_CONST UInt maxUInt = UInt(-1);
#if defined(JSON_HAS_INT64) #if defined(JSON_HAS_INT64)
/// Minimum signed 64 bits int value that can be stored in a Json::Value. /// Minimum signed 64 bits int value that can be stored in a Json::Value.
static constexpr Int64 minInt64 = Int64(~(UInt64(-1) / 2)); static JSONCPP_CONST Int64 minInt64 = Int64(~(UInt64(-1) / 2));
/// Maximum signed 64 bits int value that can be stored in a Json::Value. /// Maximum signed 64 bits int value that can be stored in a Json::Value.
static constexpr Int64 maxInt64 = Int64(UInt64(-1) / 2); static JSONCPP_CONST Int64 maxInt64 = Int64(UInt64(-1) / 2);
/// Maximum unsigned 64 bits int value that can be stored in a Json::Value. /// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
static constexpr UInt64 maxUInt64 = UInt64(-1); static JSONCPP_CONST UInt64 maxUInt64 = UInt64(-1);
#endif // defined(JSON_HAS_INT64) #endif // defined(JSON_HAS_INT64)
/// Default precision for real value for string representation. /// Default precision for real value for string representation.
static constexpr UInt defaultRealPrecision = 17; static JSONCPP_CONST UInt defaultRealPrecision = 17;
// The constant is hard-coded because some compiler have trouble // The constant is hard-coded because some compiler have trouble
// converting Value::maxUInt64 to a double correctly (AIX/xlC). // converting Value::maxUInt64 to a double correctly (AIX/xlC).
// Assumes that UInt64 is a 64 bits integer. // Assumes that UInt64 is a 64 bits integer.
static constexpr double maxUInt64AsDouble = 18446744073709551615.0; static JSONCPP_CONST double maxUInt64AsDouble = 18446744073709551615.0;
// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler // Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler
// when using gcc and clang backend compilers. CZString // when using gcc and clang backend compilers. CZString
// cannot be defined as private. See issue #486 // cannot be defined as private. See issue #486
@ -263,11 +272,14 @@ private:
CZString(ArrayIndex index); CZString(ArrayIndex index);
CZString(char const* str, unsigned length, DuplicationPolicy allocate); CZString(char const* str, unsigned length, DuplicationPolicy allocate);
CZString(CZString const& other); CZString(CZString const& other);
#if JSONCPP_CXX_STD_11
CZString(CZString&& other); CZString(CZString&& other);
#endif
~CZString(); ~CZString();
CZString& operator=(const CZString& other); CZString& operator=(const CZString& other);
#if JSONCPP_CXX_STD_11
CZString& operator=(CZString&& other); CZString& operator=(CZString&& other);
#endif
bool operator<(CZString const& other) const; bool operator<(CZString const& other) const;
bool operator==(CZString const& other) const; bool operator==(CZString const& other) const;
ArrayIndex index() const; ArrayIndex index() const;
@ -343,13 +355,17 @@ public:
Value(const String& value); Value(const String& value);
Value(bool value); Value(bool value);
Value(const Value& other); Value(const Value& other);
#if JSONCPP_CXX_STD_11
Value(Value&& other); Value(Value&& other);
#endif
~Value(); ~Value();
/// \note Overwrite existing comments. To preserve comments, use /// \note Overwrite existing comments. To preserve comments, use
/// #swapPayload(). /// #swapPayload().
Value& operator=(const Value& other); Value& operator=(const Value& other);
#if JSONCPP_CXX_STD_11
Value& operator=(Value&& other); Value& operator=(Value&& other);
#endif
/// Swap everything. /// Swap everything.
void swap(Value& other); void swap(Value& other);
@ -421,7 +437,7 @@ public:
bool empty() const; bool empty() const;
/// Return !isNull() /// Return !isNull()
explicit operator bool() const; JSONCPP_OP_EXPLICIT operator bool() const;
/// Remove all object members and array elements. /// Remove all object members and array elements.
/// \pre type() is arrayValue, objectValue, or nullValue /// \pre type() is arrayValue, objectValue, or nullValue
@ -462,11 +478,15 @@ public:
/// ///
/// Equivalent to jsonvalue[jsonvalue.size()] = value; /// Equivalent to jsonvalue[jsonvalue.size()] = value;
Value& append(const Value& value); Value& append(const Value& value);
#if JSONCPP_CXX_STD_11
Value& append(Value&& value); Value& append(Value&& value);
#endif
/// \brief Insert value in array at specific index /// \brief Insert value in array at specific index
bool insert(ArrayIndex index, const Value& newValue); bool insert(ArrayIndex index, const Value& newValue);
#if JSONCPP_CXX_STD_11
bool insert(ArrayIndex index, Value&& newValue); bool insert(ArrayIndex index, Value&& newValue);
#endif
/// Access an object value by name, create a null member if it does not exist. /// Access an object value by name, create a null member if it does not exist.
/// \note Because of our implementation, keys are limited to 2^30 -1 chars. /// \note Because of our implementation, keys are limited to 2^30 -1 chars.
@ -562,15 +582,11 @@ public:
/// \deprecated Always pass len. /// \deprecated Always pass len.
JSONCPP_DEPRECATED("Use setComment(String const&) instead.") JSONCPP_DEPRECATED("Use setComment(String const&) instead.")
void setComment(const char* comment, CommentPlacement placement) { void setComment(const char* comment, CommentPlacement placement);
setComment(String(comment, strlen(comment)), placement);
}
/// Comments must be //... or /* ... */ /// Comments must be //... or /* ... */
void setComment(const char* comment, size_t len, CommentPlacement placement) { void setComment(const char* comment, size_t len, CommentPlacement placement);
setComment(String(comment, len), placement);
}
/// Comments must be //... or /* ... */ /// Comments must be //... or /* ... */
void setComment(String comment, CommentPlacement placement); void setComment(const String& comment, CommentPlacement placement);
bool hasComment(CommentPlacement placement) const; bool hasComment(CommentPlacement placement) const;
/// Include delimiters and embedded newlines. /// Include delimiters and embedded newlines.
String getComment(CommentPlacement placement) const; String getComment(CommentPlacement placement) const;
@ -632,18 +648,15 @@ private:
class Comments { class Comments {
public: public:
Comments() = default; Comments() {}
Comments(const Comments& that); Comments(const Comments& that);
Comments(Comments&& that);
Comments& operator=(const Comments& that); Comments& operator=(const Comments& that);
Comments& operator=(Comments&& that);
bool has(CommentPlacement slot) const; bool has(CommentPlacement slot) const;
String get(CommentPlacement slot) const; String get(CommentPlacement slot) const;
void set(CommentPlacement slot, String comment); void set(CommentPlacement slot, String s);
private: private:
using Array = std::array<String, numberOfCommentPlacement>; String ptr_[numberOfCommentPlacement];
std::unique_ptr<Array> ptr_;
}; };
Comments comments_; Comments comments_;
@ -698,8 +711,8 @@ public:
private: private:
enum Kind { kindNone = 0, kindIndex, kindKey }; enum Kind { kindNone = 0, kindIndex, kindKey };
String key_; String key_;
ArrayIndex index_{}; ArrayIndex index_;
Kind kind_{kindNone}; Kind kind_;
}; };
/** \brief Experimental and untested: represents a "path" to access a node. /** \brief Experimental and untested: represents a "path" to access a node.
@ -728,8 +741,8 @@ public:
Value& make(Value& root) const; Value& make(Value& root) const;
private: private:
using InArgs = std::vector<const PathArgument*>; typedef std::vector<const PathArgument*> InArgs;
using Args = std::vector<PathArgument>; typedef std::vector<PathArgument> Args;
void makePath(const String& path, const InArgs& in); void makePath(const String& path, const InArgs& in);
void addPathInArg(const String& path, const InArgs& in, void addPathInArg(const String& path, const InArgs& in,
@ -744,10 +757,10 @@ private:
*/ */
class JSON_API ValueIteratorBase { class JSON_API ValueIteratorBase {
public: public:
using iterator_category = std::bidirectional_iterator_tag; typedef std::bidirectional_iterator_tag iterator_category;
using size_t = unsigned int; typedef unsigned int size_t;
using difference_type = int; typedef int difference_type;
using SelfType = ValueIteratorBase; typedef ValueIteratorBase SelfType;
bool operator==(const SelfType& other) const { return isEqual(other); } bool operator==(const SelfType& other) const { return isEqual(other); }
@ -804,13 +817,14 @@ protected:
private: private:
Value::ObjectValues::iterator current_; Value::ObjectValues::iterator current_;
// Indicates that iterator is for a null value. // Indicates that iterator is for a null value.
bool isNull_{true}; bool isNull_;
public: public:
// For some reason, BORLAND needs these at the end, rather // For some reason, BORLAND needs these at the end, rather
// than earlier. No idea why. // than earlier. No idea why.
ValueIteratorBase(); ValueIteratorBase();
explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); JSONCPP_OP_EXPLICIT
ValueIteratorBase(const Value::ObjectValues::iterator& current);
}; };
/** \brief const iterator for object and array value. /** \brief const iterator for object and array value.
@ -820,12 +834,12 @@ class JSON_API ValueConstIterator : public ValueIteratorBase {
friend class Value; friend class Value;
public: public:
using value_type = const Value; typedef const Value value_type;
// typedef unsigned int size_t; // typedef unsigned int size_t;
// typedef int difference_type; // typedef int difference_type;
using reference = const Value&; typedef const Value& reference;
using pointer = const Value*; typedef const Value* pointer;
using SelfType = ValueConstIterator; typedef ValueConstIterator SelfType;
ValueConstIterator(); ValueConstIterator();
ValueConstIterator(ValueIterator const& other); ValueConstIterator(ValueIterator const& other);
@ -833,7 +847,8 @@ public:
private: private:
/*! \internal Use by Value to create an iterator. /*! \internal Use by Value to create an iterator.
*/ */
explicit ValueConstIterator(const Value::ObjectValues::iterator& current); JSONCPP_OP_EXPLICIT
ValueConstIterator(const Value::ObjectValues::iterator& current);
public: public:
SelfType& operator=(const ValueIteratorBase& other); SelfType& operator=(const ValueIteratorBase& other);
@ -871,21 +886,22 @@ class JSON_API ValueIterator : public ValueIteratorBase {
friend class Value; friend class Value;
public: public:
using value_type = Value; typedef Value value_type;
using size_t = unsigned int; typedef unsigned int size_t;
using difference_type = int; typedef int difference_type;
using reference = Value&; typedef Value& reference;
using pointer = Value*; typedef Value* pointer;
using SelfType = ValueIterator; typedef ValueIterator SelfType;
ValueIterator(); ValueIterator();
explicit ValueIterator(const ValueConstIterator& other); JSONCPP_OP_EXPLICIT ValueIterator(const ValueConstIterator& other);
ValueIterator(const ValueIterator& other); ValueIterator(const ValueIterator& other);
private: private:
/*! \internal Use by Value to create an iterator. /*! \internal Use by Value to create an iterator.
*/ */
explicit ValueIterator(const Value::ObjectValues::iterator& current); JSONCPP_OP_EXPLICIT
ValueIterator(const Value::ObjectValues::iterator& current);
public: public:
SelfType& operator=(const SelfType& other); SelfType& operator=(const SelfType& other);

View File

@ -9,10 +9,10 @@
// 3. /CMakeLists.txt // 3. /CMakeLists.txt
// IMPORTANT: also update the SOVERSION!! // IMPORTANT: also update the SOVERSION!!
#define JSONCPP_VERSION_STRING "1.9.3" #define JSONCPP_VERSION_STRING "00.11.0"
#define JSONCPP_VERSION_MAJOR 1 #define JSONCPP_VERSION_MAJOR 00
#define JSONCPP_VERSION_MINOR 9 #define JSONCPP_VERSION_MINOR 11
#define JSONCPP_VERSION_PATCH 3 #define JSONCPP_VERSION_PATCH 0
#define JSONCPP_VERSION_QUALIFIER #define JSONCPP_VERSION_QUALIFIER
#define JSONCPP_VERSION_HEXA \ #define JSONCPP_VERSION_HEXA \
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \

View File

@ -119,12 +119,12 @@ public:
Json::Value settings_; Json::Value settings_;
StreamWriterBuilder(); StreamWriterBuilder();
~StreamWriterBuilder() override; ~StreamWriterBuilder() JSONCPP_OVERRIDE;
/** /**
* \throw std::exception if something goes wrong (e.g. invalid settings) * \throw std::exception if something goes wrong (e.g. invalid settings)
*/ */
StreamWriter* newStreamWriter() const override; StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE;
/** \return true if 'settings' are legal and consistent; /** \return true if 'settings' are legal and consistent;
* otherwise, indicate bad settings via 'invalid'. * otherwise, indicate bad settings via 'invalid'.
@ -169,7 +169,7 @@ class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter
: public Writer { : public Writer {
public: public:
FastWriter(); FastWriter();
~FastWriter() override = default; ~FastWriter() JSONCPP_OVERRIDE {}
void enableYAMLCompatibility(); void enableYAMLCompatibility();
@ -183,15 +183,15 @@ public:
void omitEndingLineFeed(); void omitEndingLineFeed();
public: // overridden from Writer public: // overridden from Writer
String write(const Value& root) override; String write(const Value& root) JSONCPP_OVERRIDE;
private: private:
void writeValue(const Value& value); void writeValue(const Value& value);
String document_; String document_;
bool yamlCompatibilityEnabled_{false}; bool yamlCompatibilityEnabled_;
bool dropNullPlaceholders_{false}; bool dropNullPlaceholders_;
bool omitEndingLineFeed_{false}; bool omitEndingLineFeed_;
}; };
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma warning(pop) #pragma warning(pop)
@ -229,14 +229,14 @@ class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
StyledWriter : public Writer { StyledWriter : public Writer {
public: public:
StyledWriter(); StyledWriter();
~StyledWriter() override = default; ~StyledWriter() JSONCPP_OVERRIDE {}
public: // overridden from Writer public: // overridden from Writer
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
* \param root Value to serialize. * \param root Value to serialize.
* \return String containing the JSON document that represents the root value. * \return String containing the JSON document that represents the root value.
*/ */
String write(const Value& root) override; String write(const Value& root) JSONCPP_OVERRIDE;
private: private:
void writeValue(const Value& value); void writeValue(const Value& value);
@ -252,14 +252,14 @@ private:
static bool hasCommentForValue(const Value& value); static bool hasCommentForValue(const Value& value);
static String normalizeEOL(const String& text); static String normalizeEOL(const String& text);
using ChildValues = std::vector<String>; typedef std::vector<String> ChildValues;
ChildValues childValues_; ChildValues childValues_;
String document_; String document_;
String indentString_; String indentString_;
unsigned int rightMargin_{74}; unsigned int rightMargin_;
unsigned int indentSize_{3}; unsigned int indentSize_;
bool addChildValues_{false}; bool addChildValues_;
}; };
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma warning(pop) #pragma warning(pop)
@ -301,7 +301,7 @@ public:
* \param indentation Each level will be indented by this amount extra. * \param indentation Each level will be indented by this amount extra.
*/ */
StyledStreamWriter(String indentation = "\t"); StyledStreamWriter(String indentation = "\t");
~StyledStreamWriter() = default; ~StyledStreamWriter() {}
public: public:
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
@ -326,12 +326,12 @@ private:
static bool hasCommentForValue(const Value& value); static bool hasCommentForValue(const Value& value);
static String normalizeEOL(const String& text); static String normalizeEOL(const String& text);
using ChildValues = std::vector<String>; typedef std::vector<String> ChildValues;
ChildValues childValues_; ChildValues childValues_;
OStream* document_; OStream* document_;
String indentString_; String indentString_;
unsigned int rightMargin_{74}; unsigned int rightMargin_;
String indentation_; String indentation_;
bool addChildValues_ : 1; bool addChildValues_ : 1;
bool indented_ : 1; bool indented_ : 1;
@ -348,7 +348,7 @@ String JSON_API valueToString(LargestInt value);
String JSON_API valueToString(LargestUInt value); String JSON_API valueToString(LargestUInt value);
String JSON_API valueToString( String JSON_API valueToString(
double value, unsigned int precision = Value::defaultRealPrecision, double value, unsigned int precision = Value::defaultRealPrecision,
PrecisionType precisionType = PrecisionType::significantDigits); PrecisionType precisionType = significantDigits);
String JSON_API valueToString(bool value); String JSON_API valueToString(bool value);
String JSON_API valueToQuotedString(const char* value); String JSON_API valueToQuotedString(const char* value);

View File

@ -24,7 +24,9 @@ struct Options {
Json::String path; Json::String path;
Json::Features features; Json::Features features;
bool parseOnly; bool parseOnly;
using writeFuncType = Json::String (*)(Json::Value const&);
typedef Json::String (*writeFuncType)(Json::Value const&);
writeFuncType write; writeFuncType write;
}; };
@ -57,11 +59,11 @@ static Json::String readInputTestFile(const char* path) {
if (!file) if (!file)
return ""; return "";
fseek(file, 0, SEEK_END); fseek(file, 0, SEEK_END);
auto const size = ftell(file); long const size = ftell(file);
auto const usize = static_cast<size_t>(size); size_t const usize = static_cast<size_t>(size);
fseek(file, 0, SEEK_SET); fseek(file, 0, SEEK_SET);
auto buffer = new char[size + 1]; char* buffer = new char[usize + 1];
buffer[size] = 0; buffer[usize] = 0;
Json::String text; Json::String text;
if (fread(buffer, 1, usize, file) == usize) if (fread(buffer, 1, usize, file) == usize)
text = buffer; text = buffer;
@ -111,7 +113,9 @@ static void printValueTree(FILE* fout, Json::Value& value,
Json::Value::Members members(value.getMemberNames()); Json::Value::Members members(value.getMemberNames());
std::sort(members.begin(), members.end()); std::sort(members.begin(), members.end());
Json::String suffix = *(path.end() - 1) == '.' ? "" : "."; Json::String suffix = *(path.end() - 1) == '.' ? "" : ".";
for (const auto& name : members) { for (Json::Value::Members::const_iterator it = members.begin();
it != members.end(); it++) {
const Json::String& name = *it;
printValueTree(fout, value[name], path + suffix + name); printValueTree(fout, value[name], path + suffix + name);
} }
} break; } break;
@ -138,7 +142,7 @@ static int parseAndSaveValueTree(const Json::String& input,
features.allowDroppedNullPlaceholders_; features.allowDroppedNullPlaceholders_;
builder.settings_["allowNumericKeys"] = features.allowNumericKeys_; builder.settings_["allowNumericKeys"] = features.allowNumericKeys_;
std::unique_ptr<Json::CharReader> reader(builder.newCharReader()); Json::CharReader* reader(builder.newCharReader());
Json::String errors; Json::String errors;
const bool parsingSuccessful = const bool parsingSuccessful =
reader->parse(input.data(), input.data() + input.size(), root, &errors); reader->parse(input.data(), input.data() + input.size(), root, &errors);
@ -148,7 +152,7 @@ static int parseAndSaveValueTree(const Json::String& input,
<< errors << std::endl; << errors << std::endl;
return 1; return 1;
} }
delete reader;
// We may instead check the legacy implementation (to ensure it doesn't // We may instead check the legacy implementation (to ensure it doesn't
// randomly get broken). // randomly get broken).
} else { } else {

View File

@ -51,18 +51,15 @@ static size_t const stackLimit_g =
namespace Json { namespace Json {
#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) typedef CharReader* CharReaderPtr;
using CharReaderPtr = std::unique_ptr<CharReader>;
#else
using CharReaderPtr = std::auto_ptr<CharReader>;
#endif
// Implementation of class Features // Implementation of class Features
// //////////////////////////////// // ////////////////////////////////
Features::Features() = default; Features::Features()
: allowComments_(true), strictRoot_(false),
Features Features::all() { return {}; } allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
Features Features::all() { return Features(); }
Features Features::strictMode() { Features Features::strictMode() {
Features features; Features features;
@ -86,9 +83,15 @@ bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
// Class Reader // Class Reader
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
Reader::Reader() : features_(Features::all()) {} Reader::Reader()
: errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
lastValue_(), commentsBefore_(), features_(Features::all()),
collectComments_() {}
Reader::Reader(const Features& features) : features_(features) {} Reader::Reader(const Features& features)
: errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
lastValue_(), commentsBefore_(), features_(features), collectComments_() {
}
bool Reader::parse(const std::string& document, Value& root, bool Reader::parse(const std::string& document, Value& root,
bool collectComments) { bool collectComments) {
@ -121,8 +124,8 @@ bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root,
end_ = endDoc; end_ = endDoc;
collectComments_ = collectComments; collectComments_ = collectComments;
current_ = begin_; current_ = begin_;
lastValueEnd_ = nullptr; lastValueEnd_ = JSONCPP_NULL;
lastValue_ = nullptr; lastValue_ = JSONCPP_NULL;
commentsBefore_.clear(); commentsBefore_.clear();
errors_.clear(); errors_.clear();
while (!nodes_.empty()) while (!nodes_.empty())
@ -376,7 +379,7 @@ void Reader::addComment(Location begin, Location end,
assert(collectComments_); assert(collectComments_);
const String& normalized = normalizeEOL(begin, end); const String& normalized = normalizeEOL(begin, end);
if (placement == commentAfterOnSameLine) { if (placement == commentAfterOnSameLine) {
assert(lastValue_ != nullptr); assert(lastValue_ != JSONCPP_NULL);
lastValue_->setComment(normalized, placement); lastValue_->setComment(normalized, placement);
} else { } else {
commentsBefore_ += normalized; commentsBefore_ += normalized;
@ -565,7 +568,7 @@ bool Reader::decodeNumber(Token& token, Value& decoded) {
Char c = *current++; Char c = *current++;
if (c < '0' || c > '9') if (c < '0' || c > '9')
return decodeDouble(token, decoded); return decodeDouble(token, decoded);
auto digit(static_cast<Value::UInt>(c - '0')); Value::UInt digit(static_cast<Value::UInt>(c - '0'));
if (value >= threshold) { if (value >= threshold) {
// We've hit or exceeded the max value divided by 10 (rounded down). If // 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 // a) we've only just touched the limit, b) this is the last digit, and
@ -798,7 +801,9 @@ String Reader::getFormatedErrorMessages() const {
String Reader::getFormattedErrorMessages() const { String Reader::getFormattedErrorMessages() const {
String formattedMessage; String formattedMessage;
for (const auto& error : errors_) { for (Errors::const_iterator itError = errors_.begin();
itError != errors_.end(); ++itError) {
const ErrorInfo& error = *itError;
formattedMessage += formattedMessage +=
"* " + getLocationLineAndColumn(error.token_.start_) + "\n"; "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
formattedMessage += " " + error.message_ + "\n"; formattedMessage += " " + error.message_ + "\n";
@ -811,7 +816,9 @@ String Reader::getFormattedErrorMessages() const {
std::vector<Reader::StructuredError> Reader::getStructuredErrors() const { std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
std::vector<Reader::StructuredError> allErrors; std::vector<Reader::StructuredError> allErrors;
for (const auto& error : errors_) { for (Errors::const_iterator itError = errors_.begin();
itError != errors_.end(); ++itError) {
const ErrorInfo& error = *itError;
Reader::StructuredError structured; Reader::StructuredError structured;
structured.offset_start = error.token_.start_ - begin_; structured.offset_start = error.token_.start_ - begin_;
structured.offset_limit = error.token_.end_ - begin_; structured.offset_limit = error.token_.end_ - begin_;
@ -832,7 +839,7 @@ bool Reader::pushError(const Value& value, const String& message) {
ErrorInfo info; ErrorInfo info;
info.token_ = token; info.token_ = token;
info.message_ = message; info.message_ = message;
info.extra_ = nullptr; info.extra_ = JSONCPP_NULL;
errors_.push_back(info); errors_.push_back(info);
return true; return true;
} }
@ -875,7 +882,7 @@ public:
size_t stackLimit_; size_t stackLimit_;
}; // OurFeatures }; // OurFeatures
OurFeatures OurFeatures::all() { return {}; } OurFeatures OurFeatures::all() { return OurFeatures(); }
// Implementation of class Reader // Implementation of class Reader
// //////////////////////////////// // ////////////////////////////////
@ -884,15 +891,15 @@ OurFeatures OurFeatures::all() { return {}; }
// for implementing JSON reading. // for implementing JSON reading.
class OurReader { class OurReader {
public: public:
using Char = char; typedef char Char;
using Location = const Char*; typedef const Char* Location;
struct StructuredError { struct StructuredError {
ptrdiff_t offset_start; ptrdiff_t offset_start;
ptrdiff_t offset_limit; ptrdiff_t offset_limit;
String message; String message;
}; };
explicit OurReader(OurFeatures const& features); JSONCPP_OP_EXPLICIT OurReader(OurFeatures const& features);
bool parse(const char* beginDoc, const char* endDoc, Value& root, bool parse(const char* beginDoc, const char* endDoc, Value& root,
bool collectComments = true); bool collectComments = true);
String getFormattedErrorMessages() const; String getFormattedErrorMessages() const;
@ -936,7 +943,7 @@ private:
Location extra_; Location extra_;
}; };
using Errors = std::deque<ErrorInfo>; typedef std::deque<ErrorInfo> Errors;
bool readToken(Token& token); bool readToken(Token& token);
void skipSpaces(); void skipSpaces();
@ -961,7 +968,8 @@ private:
unsigned int& unicode); unsigned int& unicode);
bool decodeUnicodeEscapeSequence(Token& token, Location& current, bool decodeUnicodeEscapeSequence(Token& token, Location& current,
Location end, unsigned int& unicode); Location end, unsigned int& unicode);
bool addError(const String& message, Token& token, Location extra = nullptr); bool addError(const String& message, Token& token,
Location extra = JSONCPP_NULL);
bool recoverFromError(TokenType skipUntilToken); bool recoverFromError(TokenType skipUntilToken);
bool addErrorAndRecover(const String& message, Token& token, bool addErrorAndRecover(const String& message, Token& token,
TokenType skipUntilToken); TokenType skipUntilToken);
@ -977,21 +985,21 @@ private:
static String normalizeEOL(Location begin, Location end); static String normalizeEOL(Location begin, Location end);
static bool containsNewLine(Location begin, Location end); static bool containsNewLine(Location begin, Location end);
using Nodes = std::stack<Value*>; typedef std::stack<Value*> Nodes;
Nodes nodes_{}; Nodes nodes_;
Errors errors_{}; Errors errors_;
String document_{}; String document_;
Location begin_ = nullptr; Location begin_;
Location end_ = nullptr; Location end_;
Location current_ = nullptr; Location current_;
Location lastValueEnd_ = nullptr; Location lastValueEnd_;
Value* lastValue_ = nullptr; Value* lastValue_;
bool lastValueHasAComment_ = false; bool lastValueHasAComment_;
String commentsBefore_{}; String commentsBefore_;
OurFeatures const features_; OurFeatures const features_;
bool collectComments_ = false; bool collectComments_;
}; // OurReader }; // OurReader
// complete copy of Read impl, for OurReader // complete copy of Read impl, for OurReader
@ -1004,7 +1012,11 @@ bool OurReader::containsNewLine(OurReader::Location begin,
return false; return false;
} }
OurReader::OurReader(OurFeatures const& features) : features_(features) {} OurReader::OurReader(OurFeatures const& features)
: errors_(), document_(), begin_(JSONCPP_NULL), end_(JSONCPP_NULL),
current_(JSONCPP_NULL), lastValueEnd_(JSONCPP_NULL),
lastValue_(JSONCPP_NULL), lastValueHasAComment_(false), commentsBefore_(),
features_(features), collectComments_(false) {}
bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root, bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
bool collectComments) { bool collectComments) {
@ -1016,8 +1028,8 @@ bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
end_ = endDoc; end_ = endDoc;
collectComments_ = collectComments; collectComments_ = collectComments;
current_ = begin_; current_ = begin_;
lastValueEnd_ = nullptr; lastValueEnd_ = JSONCPP_NULL;
lastValue_ = nullptr; lastValue_ = JSONCPP_NULL;
commentsBefore_.clear(); commentsBefore_.clear();
errors_.clear(); errors_.clear();
while (!nodes_.empty()) while (!nodes_.empty())
@ -1352,7 +1364,7 @@ void OurReader::addComment(Location begin, Location end,
assert(collectComments_); assert(collectComments_);
const String& normalized = normalizeEOL(begin, end); const String& normalized = normalizeEOL(begin, end);
if (placement == commentAfterOnSameLine) { if (placement == commentAfterOnSameLine) {
assert(lastValue_ != nullptr); assert(lastValue_ != JSONCPP_NULL);
lastValue_->setComment(normalized, placement); lastValue_->setComment(normalized, placement);
} else { } else {
commentsBefore_ += normalized; commentsBefore_ += normalized;
@ -1568,32 +1580,36 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) {
// We assume we can represent the largest and smallest integer types as // We assume we can represent the largest and smallest integer types as
// unsigned integers with separate sign. This is only true if they can fit // unsigned integers with separate sign. This is only true if they can fit
// into an unsigned integer. // into an unsigned integer.
static_assert(Value::maxLargestInt <= Value::maxLargestUInt, JSONCPP_STATIC_ASSERT(LargestUInt(Value::maxLargestInt) <=
"Int must be smaller than UInt"); Value::maxLargestUInt,
"Int must be smaller than Uint");
// We need to convert minLargestInt into a positive number. The easiest way // We need to convert minLargestInt into a positive number. The easiest way
// to do this conversion is to assume our "threshold" value of minLargestInt // to do this conversion is to assume our "threshold" value of minLargestInt
// divided by 10 can fit in maxLargestInt when absolute valued. This should // divided by 10 can fit in maxLargestInt when absolute valued. This should
// be a safe assumption. // be a safe assumption.
static_assert(Value::minLargestInt <= -Value::maxLargestInt, JSONCPP_STATIC_ASSERT(
"The absolute value of minLargestInt must be greater than or " Value::minLargestInt <= -Value::maxLargestInt,
"equal to maxLargestInt"); "The absolute value of minLargestInt must ve greater than or"
static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt, "equal to maxLargestInt");
"The absolute value of minLargestInt must be only 1 magnitude "
"larger than maxLargest Int");
static constexpr Value::LargestUInt positive_threshold = JSONCPP_STATIC_ASSERT(
Value::minLargestInt / 10 >= -Value::maxLargestInt,
"The absolute value of minLargestInt must be only 1 magnitude"
"larger than maxLargestInt");
static JSONCPP_CONST Value::LargestUInt positive_threshold =
Value::maxLargestUInt / 10; Value::maxLargestUInt / 10;
static constexpr Value::UInt positive_last_digit = Value::maxLargestUInt % 10; static JSONCPP_CONST Value::UInt positive_last_digit =
Value::maxLargestUInt % 10;
// For the negative values, we have to be more careful. Since typically // For the negative values, we have to be more careful. Since typically
// -Value::minLargestInt will cause an overflow, we first divide by 10 and // -Value::minLargestInt will cause an overflow, we first divide by 10 and
// then take the inverse. This assumes that minLargestInt is only a single // then take the inverse. This assumes that minLargestInt is only a single
// power of 10 different in magnitude, which we check above. For the last // power of 10 different in magnitude, which we check above. For the last
// digit, we take the modulus before negating for the same reason. // digit, we take the modulus before negating for the same reason.
static constexpr auto negative_threshold = static JSONCPP_CONST Value::LargestUInt negative_threshold =
Value::LargestUInt(-(Value::minLargestInt / 10)); Value::LargestUInt(-(Value::minLargestInt / 10));
static constexpr auto negative_last_digit = static JSONCPP_CONST Value::UInt negative_last_digit =
Value::UInt(-(Value::minLargestInt % 10)); Value::UInt(-(Value::minLargestInt % 10));
const Value::LargestUInt threshold = const Value::LargestUInt threshold =
@ -1607,7 +1623,7 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) {
if (c < '0' || c > '9') if (c < '0' || c > '9')
return decodeDouble(token, decoded); return decodeDouble(token, decoded);
const auto digit(static_cast<Value::UInt>(c - '0')); const Value::UInt digit(static_cast<Value::UInt>(c - '0'));
if (value >= threshold) { if (value >= threshold) {
// We've hit or exceeded the max value divided by 10 (rounded down). If // We've hit or exceeded the max value divided by 10 (rounded down). If
// a) we've only just touched the limit, meaing value == threshold, // a) we've only just touched the limit, meaing value == threshold,
@ -1624,7 +1640,7 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) {
if (isNegative) { if (isNegative) {
// We use the same magnitude assumption here, just in case. // We use the same magnitude assumption here, just in case.
const auto last_digit = static_cast<Value::UInt>(value % 10); const Value::UInt last_digit = static_cast<Value::UInt>(value % 10);
decoded = -Value::LargestInt(value / 10) * 10 - last_digit; decoded = -Value::LargestInt(value / 10) * 10 - last_digit;
} else if (value <= Value::LargestUInt(Value::maxLargestInt)) { } else if (value <= Value::LargestUInt(Value::maxLargestInt)) {
decoded = Value::LargestInt(value); decoded = Value::LargestInt(value);
@ -1840,7 +1856,9 @@ String OurReader::getLocationLineAndColumn(Location location) const {
String OurReader::getFormattedErrorMessages() const { String OurReader::getFormattedErrorMessages() const {
String formattedMessage; String formattedMessage;
for (const auto& error : errors_) { for (Errors::const_iterator itError = errors_.begin();
itError != errors_.end(); ++itError) {
const ErrorInfo& error = *itError;
formattedMessage += formattedMessage +=
"* " + getLocationLineAndColumn(error.token_.start_) + "\n"; "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
formattedMessage += " " + error.message_ + "\n"; formattedMessage += " " + error.message_ + "\n";
@ -1853,7 +1871,9 @@ String OurReader::getFormattedErrorMessages() const {
std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const { std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
std::vector<OurReader::StructuredError> allErrors; std::vector<OurReader::StructuredError> allErrors;
for (const auto& error : errors_) { for (Errors::const_iterator itError = errors_.begin();
itError != errors_.end(); ++itError) {
const ErrorInfo& error = *itError;
OurReader::StructuredError structured; OurReader::StructuredError structured;
structured.offset_start = error.token_.start_ - begin_; structured.offset_start = error.token_.start_ - begin_;
structured.offset_limit = error.token_.end_ - begin_; structured.offset_limit = error.token_.end_ - begin_;
@ -1871,7 +1891,7 @@ public:
OurCharReader(bool collectComments, OurFeatures const& features) OurCharReader(bool collectComments, OurFeatures const& features)
: collectComments_(collectComments), reader_(features) {} : collectComments_(collectComments), reader_(features) {}
bool parse(char const* beginDoc, char const* endDoc, Value* root, bool parse(char const* beginDoc, char const* endDoc, Value* root,
String* errs) override { String* errs) JSONCPP_OVERRIDE {
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
if (errs) { if (errs) {
*errs = reader_.getFormattedErrorMessages(); *errs = reader_.getFormattedErrorMessages();
@ -1881,7 +1901,7 @@ public:
}; };
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); } CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
CharReaderBuilder::~CharReaderBuilder() = default; CharReaderBuilder::~CharReaderBuilder() {}
CharReader* CharReaderBuilder::newCharReader() const { CharReader* CharReaderBuilder::newCharReader() const {
bool collectComments = settings_["collectComments"].asBool(); bool collectComments = settings_["collectComments"].asBool();
OurFeatures features = OurFeatures::all(); OurFeatures features = OurFeatures::all();
@ -1983,7 +2003,9 @@ bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root,
char const* end = begin + doc.size(); char const* end = begin + doc.size();
// Note that we do not actually need a null-terminator. // Note that we do not actually need a null-terminator.
CharReaderPtr const reader(fact.newCharReader()); CharReaderPtr const reader(fact.newCharReader());
return reader->parse(begin, end, root, errs); bool ret = reader->parse(begin, end, root, errs);
delete reader;
return ret;
} }
IStream& operator>>(IStream& sin, Value& root) { IStream& operator>>(IStream& sin, Value& root) {

View File

@ -71,7 +71,7 @@ enum {
}; };
// Defines a char buffer for use with uintToString(). // Defines a char buffer for use with uintToString().
using UIntToStringBuffer = char[uintToStringBufferSize]; typedef char UIntToStringBuffer[uintToStringBufferSize];
/** Converts an unsigned integer to string. /** Converts an unsigned integer to string.
* @param value Unsigned integer to convert to string * @param value Unsigned integer to convert to string

View File

@ -48,14 +48,6 @@ int JSON_API msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
#define JSON_ASSERT_UNREACHABLE assert(false) #define JSON_ASSERT_UNREACHABLE assert(false)
namespace Json { namespace Json {
template <typename T>
static std::unique_ptr<T> cloneUnique(const std::unique_ptr<T>& p) {
std::unique_ptr<T> r;
if (p) {
r = std::unique_ptr<T>(new T(*p));
}
return r;
}
// This is a walkaround to avoid the static initialization of Value::null. // This is a walkaround to avoid the static initialization of Value::null.
// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of // kNull must be word-aligned to avoid crashing on ARM. We use an alignment of
@ -118,8 +110,8 @@ static inline char* duplicateStringValue(const char* value, size_t length) {
if (length >= static_cast<size_t>(Value::maxInt)) if (length >= static_cast<size_t>(Value::maxInt))
length = Value::maxInt - 1; length = Value::maxInt - 1;
auto newString = static_cast<char*>(malloc(length + 1)); char* newString = static_cast<char*>(malloc(length + 1));
if (newString == nullptr) { if (newString == JSONCPP_NULL) {
throwRuntimeError("in Json::Value::duplicateStringValue(): " throwRuntimeError("in Json::Value::duplicateStringValue(): "
"Failed to allocate string value buffer"); "Failed to allocate string value buffer");
} }
@ -139,8 +131,8 @@ static inline char* duplicateAndPrefixStringValue(const char* value,
"in Json::Value::duplicateAndPrefixStringValue(): " "in Json::Value::duplicateAndPrefixStringValue(): "
"length too big for prefixing"); "length too big for prefixing");
size_t actualLength = sizeof(length) + length + 1; size_t actualLength = sizeof(length) + length + 1;
auto newString = static_cast<char*>(malloc(actualLength)); char* newString = static_cast<char*>(malloc(actualLength));
if (newString == nullptr) { if (newString == JSONCPP_NULL) {
throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): " throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "
"Failed to allocate string value buffer"); "Failed to allocate string value buffer");
} }
@ -200,9 +192,9 @@ static inline void releaseStringValue(char* value, unsigned) { free(value); }
namespace Json { namespace Json {
#if JSON_USE_EXCEPTION #if JSON_USE_EXCEPTION
Exception::Exception(String msg) : msg_(std::move(msg)) {} Exception::Exception(String msg) : msg_(JSONCPP_MOVE(msg)) {}
Exception::~Exception() noexcept = default; Exception::~Exception() JSONCPP_NOEXCEPT {}
char const* Exception::what() const noexcept { return msg_.c_str(); } char const* Exception::what() const JSONCPP_NOEXCEPT { return msg_.c_str(); }
RuntimeError::RuntimeError(String const& msg) : Exception(msg) {} RuntimeError::RuntimeError(String const& msg) : Exception(msg) {}
LogicError::LogicError(String const& msg) : Exception(msg) {} LogicError::LogicError(String const& msg) : Exception(msg) {}
JSONCPP_NORETURN void throwRuntimeError(String const& msg) { JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
@ -233,7 +225,8 @@ JSONCPP_NORETURN void throwLogicError(String const& msg) {
// Notes: policy_ indicates if the string was allocated when // Notes: policy_ indicates if the string was allocated when
// a string is stored. // a string is stored.
Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {} Value::CZString::CZString(ArrayIndex index)
: cstr_(JSONCPP_NULL), index_(index) {}
Value::CZString::CZString(char const* str, unsigned length, Value::CZString::CZString(char const* str, unsigned length,
DuplicationPolicy allocate) DuplicationPolicy allocate)
@ -244,9 +237,10 @@ Value::CZString::CZString(char const* str, unsigned length,
} }
Value::CZString::CZString(const CZString& other) { Value::CZString::CZString(const CZString& other) {
cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr cstr_ =
? duplicateStringValue(other.cstr_, other.storage_.length_) (other.storage_.policy_ != noDuplication && other.cstr_ != JSONCPP_NULL
: other.cstr_); ? duplicateStringValue(other.cstr_, other.storage_.length_)
: other.cstr_);
storage_.policy_ = storage_.policy_ =
static_cast<unsigned>( static_cast<unsigned>(
other.cstr_ other.cstr_
@ -258,12 +252,12 @@ Value::CZString::CZString(const CZString& other) {
3U; 3U;
storage_.length_ = other.storage_.length_; storage_.length_ = other.storage_.length_;
} }
#if JSONCPP_CXX_STD_11
Value::CZString::CZString(CZString&& other) Value::CZString::CZString(CZString&& other)
: cstr_(other.cstr_), index_(other.index_) { : cstr_(other.cstr_), index_(other.index_) {
other.cstr_ = nullptr; other.cstr_ = JSONCPP_NULL;
} }
#endif
Value::CZString::~CZString() { Value::CZString::~CZString() {
if (cstr_ && storage_.policy_ == duplicate) { if (cstr_ && storage_.policy_ == duplicate) {
releaseStringValue(const_cast<char*>(cstr_), releaseStringValue(const_cast<char*>(cstr_),
@ -284,14 +278,14 @@ Value::CZString& Value::CZString::operator=(const CZString& other) {
index_ = other.index_; index_ = other.index_;
return *this; return *this;
} }
#if JSONCPP_CXX_STD_11
Value::CZString& Value::CZString::operator=(CZString&& other) { Value::CZString& Value::CZString::operator=(CZString&& other) {
cstr_ = other.cstr_; cstr_ = other.cstr_;
index_ = other.index_; index_ = other.index_;
other.cstr_ = nullptr; other.cstr_ = JSONCPP_NULL;
return *this; return *this;
} }
#endif
bool Value::CZString::operator<(const CZString& other) const { bool Value::CZString::operator<(const CZString& other) const {
if (!cstr_) if (!cstr_)
return index_ < other.index_; return index_ < other.index_;
@ -400,7 +394,7 @@ Value::Value(double value) {
Value::Value(const char* value) { Value::Value(const char* value) {
initBasic(stringValue, true); initBasic(stringValue, true);
JSON_ASSERT_MESSAGE(value != nullptr, JSON_ASSERT_MESSAGE(value != JSONCPP_NULL,
"Null Value Passed to Value Constructor"); "Null Value Passed to Value Constructor");
value_.string_ = duplicateAndPrefixStringValue( value_.string_ = duplicateAndPrefixStringValue(
value, static_cast<unsigned>(strlen(value))); value, static_cast<unsigned>(strlen(value)));
@ -432,11 +426,12 @@ Value::Value(const Value& other) {
dupPayload(other); dupPayload(other);
dupMeta(other); dupMeta(other);
} }
#if JSONCPP_CXX_STD_11
Value::Value(Value&& other) { Value::Value(Value&& other) {
initBasic(nullValue); initBasic(nullValue);
swap(other); swap(other);
} }
#endif
Value::~Value() { Value::~Value() {
releasePayload(); releasePayload();
@ -447,11 +442,12 @@ Value& Value::operator=(const Value& other) {
Value(other).swap(*this); Value(other).swap(*this);
return *this; return *this;
} }
#if JSONCPP_CXX_STD_11
Value& Value::operator=(Value&& other) { Value& Value::operator=(Value&& other) {
other.swap(*this); other.swap(*this);
return *this; return *this;
} }
#endif
void Value::swapPayload(Value& other) { void Value::swapPayload(Value& other) {
std::swap(bits_, other.bits_); std::swap(bits_, other.bits_);
@ -503,8 +499,9 @@ bool Value::operator<(const Value& other) const {
case booleanValue: case booleanValue:
return value_.bool_ < other.value_.bool_; return value_.bool_ < other.value_.bool_;
case stringValue: { case stringValue: {
if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) { if ((value_.string_ == JSONCPP_NULL) ||
return other.value_.string_ != nullptr; (other.value_.string_ == JSONCPP_NULL)) {
return other.value_.string_ != JSONCPP_NULL;
} }
unsigned this_len; unsigned this_len;
unsigned other_len; unsigned other_len;
@ -525,8 +522,8 @@ bool Value::operator<(const Value& other) const {
} }
case arrayValue: case arrayValue:
case objectValue: { case objectValue: {
auto thisSize = value_.map_->size(); long unsigned int thisSize = value_.map_->size();
auto otherSize = other.value_.map_->size(); long unsigned int otherSize = other.value_.map_->size();
if (thisSize != otherSize) if (thisSize != otherSize)
return thisSize < otherSize; return thisSize < otherSize;
return (*value_.map_) < (*other.value_.map_); return (*value_.map_) < (*other.value_.map_);
@ -558,7 +555,8 @@ bool Value::operator==(const Value& other) const {
case booleanValue: case booleanValue:
return value_.bool_ == other.value_.bool_; return value_.bool_ == other.value_.bool_;
case stringValue: { case stringValue: {
if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) { if ((value_.string_ == JSONCPP_NULL) ||
(other.value_.string_ == JSONCPP_NULL)) {
return (value_.string_ == other.value_.string_); return (value_.string_ == other.value_.string_);
} }
unsigned this_len; unsigned this_len;
@ -590,8 +588,8 @@ bool Value::operator!=(const Value& other) const { return !(*this == other); }
const char* Value::asCString() const { const char* Value::asCString() const {
JSON_ASSERT_MESSAGE(type() == stringValue, JSON_ASSERT_MESSAGE(type() == stringValue,
"in Json::Value::asCString(): requires stringValue"); "in Json::Value::asCString(): requires stringValue");
if (value_.string_ == nullptr) if (value_.string_ == JSONCPP_NULL)
return nullptr; return JSONCPP_NULL;
unsigned this_len; unsigned this_len;
char const* this_str; char const* this_str;
decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
@ -616,7 +614,7 @@ unsigned Value::getCStringLength() const {
bool Value::getString(char const** begin, char const** end) const { bool Value::getString(char const** begin, char const** end) const {
if (type() != stringValue) if (type() != stringValue)
return false; return false;
if (value_.string_ == nullptr) if (value_.string_ == JSONCPP_NULL)
return false; return false;
unsigned length; unsigned length;
decodePrefixedString(this->isAllocated(), this->value_.string_, &length, decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
@ -630,7 +628,7 @@ String Value::asString() const {
case nullValue: case nullValue:
return ""; return "";
case stringValue: { case stringValue: {
if (value_.string_ == nullptr) if (value_.string_ == JSONCPP_NULL)
return ""; return "";
unsigned this_len; unsigned this_len;
char const* this_str; char const* this_str;
@ -813,7 +811,7 @@ bool Value::asBool() const {
return value_.uint_ != 0; return value_.uint_ != 0;
case realValue: { case realValue: {
// According to JavaScript language zero or NaN is regarded as false // According to JavaScript language zero or NaN is regarded as false
const auto value_classification = std::fpclassify(value_.real_); const int value_classification = std::fpclassify(value_.real_);
return value_classification != FP_ZERO && value_classification != FP_NAN; return value_classification != FP_ZERO && value_classification != FP_NAN;
} }
default: default:
@ -928,7 +926,7 @@ Value& Value::operator[](ArrayIndex index) {
if (type() == nullValue) if (type() == nullValue)
*this = Value(arrayValue); *this = Value(arrayValue);
CZString key(index); CZString key(index);
auto it = value_.map_->lower_bound(key); ObjectValues::iterator it = value_.map_->lower_bound(key);
if (it != value_.map_->end() && (*it).first == key) if (it != value_.map_->end() && (*it).first == key)
return (*it).second; return (*it).second;
@ -967,7 +965,7 @@ const Value& Value::operator[](int index) const {
void Value::initBasic(ValueType type, bool allocated) { void Value::initBasic(ValueType type, bool allocated) {
setType(type); setType(type);
setIsAllocated(allocated); setIsAllocated(allocated);
comments_ = Comments{}; comments_ = Comments();
start_ = 0; start_ = 0;
limit_ = 0; limit_ = 0;
} }
@ -1042,7 +1040,7 @@ Value& Value::resolveReference(const char* key) {
*this = Value(objectValue); *this = Value(objectValue);
CZString actualKey(key, static_cast<unsigned>(strlen(key)), CZString actualKey(key, static_cast<unsigned>(strlen(key)),
CZString::noDuplication); // NOTE! CZString::noDuplication); // NOTE!
auto it = value_.map_->lower_bound(actualKey); ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
if (it != value_.map_->end() && (*it).first == actualKey) if (it != value_.map_->end() && (*it).first == actualKey)
return (*it).second; return (*it).second;
@ -1061,7 +1059,7 @@ Value& Value::resolveReference(char const* key, char const* end) {
*this = Value(objectValue); *this = Value(objectValue);
CZString actualKey(key, static_cast<unsigned>(end - key), CZString actualKey(key, static_cast<unsigned>(end - key),
CZString::duplicateOnCopy); CZString::duplicateOnCopy);
auto it = value_.map_->lower_bound(actualKey); ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
if (it != value_.map_->end() && (*it).first == actualKey) if (it != value_.map_->end() && (*it).first == actualKey)
return (*it).second; return (*it).second;
@ -1083,12 +1081,12 @@ Value const* Value::find(char const* begin, char const* end) const {
"in Json::Value::find(begin, end): requires " "in Json::Value::find(begin, end): requires "
"objectValue or nullValue"); "objectValue or nullValue");
if (type() == nullValue) if (type() == nullValue)
return nullptr; return JSONCPP_NULL;
CZString actualKey(begin, static_cast<unsigned>(end - begin), CZString actualKey(begin, static_cast<unsigned>(end - begin),
CZString::noDuplication); CZString::noDuplication);
ObjectValues::const_iterator it = value_.map_->find(actualKey); ObjectValues::const_iterator it = value_.map_->find(actualKey);
if (it == value_.map_->end()) if (it == value_.map_->end())
return nullptr; return JSONCPP_NULL;
return &(*it).second; return &(*it).second;
} }
Value* Value::demand(char const* begin, char const* end) { Value* Value::demand(char const* begin, char const* end) {
@ -1122,8 +1120,8 @@ Value& Value::operator[](const StaticString& key) {
return resolveReference(key.c_str()); return resolveReference(key.c_str());
} }
#if JSONCPP_CXX_STD_11
Value& Value::append(const Value& value) { return append(Value(value)); } Value& Value::append(const Value& value) { return append(Value(value)); }
Value& Value::append(Value&& value) { Value& Value::append(Value&& value) {
JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
"in Json::Value::append: requires arrayValue"); "in Json::Value::append: requires arrayValue");
@ -1132,12 +1130,19 @@ Value& Value::append(Value&& value) {
} }
return this->value_.map_->emplace(size(), std::move(value)).first->second; return this->value_.map_->emplace(size(), std::move(value)).first->second;
} }
#else
Value& Value::append(const Value& value) { return (*this)[size()] = value; }
#endif
#if JSONCPP_CXX_STD_11
bool Value::insert(ArrayIndex index, const Value& newValue) { bool Value::insert(ArrayIndex index, const Value& newValue) {
return insert(index, Value(newValue)); return insert(index, Value(newValue));
} }
bool Value::insert(ArrayIndex index, Value&& newValue) { bool Value::insert(ArrayIndex index, Value&& newValue) {
#else
bool Value::insert(ArrayIndex index, const Value& newValue) {
#endif
JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
"in Json::Value::insert: requires arrayValue"); "in Json::Value::insert: requires arrayValue");
ArrayIndex length = size(); ArrayIndex length = size();
@ -1145,12 +1150,11 @@ bool Value::insert(ArrayIndex index, Value&& newValue) {
return false; return false;
} }
for (ArrayIndex i = length; i > index; i--) { for (ArrayIndex i = length; i > index; i--) {
(*this)[i] = std::move((*this)[i - 1]); (*this)[i] = JSONCPP_MOVE((*this)[i - 1]);
} }
(*this)[index] = std::move(newValue); (*this)[index] = JSONCPP_MOVE(newValue);
return true; return true;
} }
Value Value::get(char const* begin, char const* end, Value Value::get(char const* begin, char const* end,
Value const& defaultValue) const { Value const& defaultValue) const {
Value const* found = find(begin, end); Value const* found = find(begin, end);
@ -1169,11 +1173,11 @@ bool Value::removeMember(const char* begin, const char* end, Value* removed) {
} }
CZString actualKey(begin, static_cast<unsigned>(end - begin), CZString actualKey(begin, static_cast<unsigned>(end - begin),
CZString::noDuplication); CZString::noDuplication);
auto it = value_.map_->find(actualKey); ObjectValues::iterator it = value_.map_->find(actualKey);
if (it == value_.map_->end()) if (it == value_.map_->end())
return false; return false;
if (removed) if (removed)
*removed = std::move(it->second); *removed = JSONCPP_MOVE(it->second);
value_.map_->erase(it); value_.map_->erase(it);
return true; return true;
} }
@ -1199,7 +1203,7 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) {
return false; return false;
} }
CZString key(index); CZString key(index);
auto it = value_.map_->find(key); ObjectValues::iterator it = value_.map_->find(key);
if (it == value_.map_->end()) { if (it == value_.map_->end()) {
return false; return false;
} }
@ -1213,14 +1217,14 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) {
} }
// erase the last one ("leftover") // erase the last one ("leftover")
CZString keyLast(oldSize - 1); CZString keyLast(oldSize - 1);
auto itLast = value_.map_->find(keyLast); ObjectValues::iterator itLast = value_.map_->find(keyLast);
value_.map_->erase(itLast); value_.map_->erase(itLast);
return true; return true;
} }
bool Value::isMember(char const* begin, char const* end) const { bool Value::isMember(char const* begin, char const* end) const {
Value const* value = find(begin, end); Value const* value = find(begin, end);
return nullptr != value; return JSONCPP_NULL != value;
} }
bool Value::isMember(char const* key) const { bool Value::isMember(char const* key) const {
return isMember(key, key + strlen(key)); return isMember(key, key + strlen(key));
@ -1370,53 +1374,44 @@ bool Value::isArray() const { return type() == arrayValue; }
bool Value::isObject() const { return type() == objectValue; } bool Value::isObject() const { return type() == objectValue; }
Value::Comments::Comments(const Comments& that) Value::Comments::Comments(const Comments& that) {
: ptr_{cloneUnique(that.ptr_)} {} for (size_t i = 0; i < numberOfCommentPlacement; i++) {
ptr_[i] = that.ptr_[i];
Value::Comments::Comments(Comments&& that) : ptr_{std::move(that.ptr_)} {} }
}
Value::Comments& Value::Comments::operator=(const Comments& that) { Value::Comments& Value::Comments::operator=(const Comments& that) {
ptr_ = cloneUnique(that.ptr_); for (size_t i = 0; i < numberOfCommentPlacement; i++) {
ptr_[i] = that.ptr_[i];
}
return *this; return *this;
} }
Value::Comments& Value::Comments::operator=(Comments&& that) {
ptr_ = std::move(that.ptr_);
return *this;
}
bool Value::Comments::has(CommentPlacement slot) const { bool Value::Comments::has(CommentPlacement slot) const {
return ptr_ && !(*ptr_)[slot].empty(); return !ptr_[slot].empty();
} }
String Value::Comments::get(CommentPlacement slot) const { String Value::Comments::get(CommentPlacement slot) const { return ptr_[slot]; }
if (!ptr_)
return {};
return (*ptr_)[slot];
}
void Value::Comments::set(CommentPlacement slot, String comment) { void Value::Comments::set(CommentPlacement slot, String comment) {
if (!ptr_) {
ptr_ = std::unique_ptr<Array>(new Array());
}
// check comments array boundry. // check comments array boundry.
if (slot < CommentPlacement::numberOfCommentPlacement) { if (slot < numberOfCommentPlacement) {
(*ptr_)[slot] = std::move(comment); ptr_[slot] = comment;
} }
} }
void Value::setComment(String comment, CommentPlacement placement) { void Value::setComment(const char* comment, CommentPlacement placement) {
if (!comment.empty() && (comment.back() == '\n')) { setComment(comment, strlen(comment), placement);
}
void Value::setComment(const char* comment, size_t len,
CommentPlacement placement) {
if ((len > 0) && (comment[len - 1] == '\n')) {
// Always discard trailing newline, to aid indentation. // Always discard trailing newline, to aid indentation.
comment.pop_back(); len -= 1;
} }
JSON_ASSERT(!comment.empty()); comments_.set(placement, String(comment, len));
JSON_ASSERT_MESSAGE( }
comment[0] == '\0' || comment[0] == '/', void Value::setComment(const String& comment, CommentPlacement placement) {
"in Json::Value::setComment(): Comments must start with /"); setComment(comment.c_str(), comment.length(), placement);
comments_.set(placement, std::move(comment));
} }
bool Value::hasComment(CommentPlacement placement) const { bool Value::hasComment(CommentPlacement placement) const {
return comments_.has(placement); return comments_.has(placement);
} }
@ -1453,7 +1448,7 @@ Value::const_iterator Value::begin() const {
default: default:
break; break;
} }
return {}; return const_iterator();
} }
Value::const_iterator Value::end() const { Value::const_iterator Value::end() const {
@ -1466,7 +1461,7 @@ Value::const_iterator Value::end() const {
default: default:
break; break;
} }
return {}; return const_iterator();
} }
Value::iterator Value::begin() { Value::iterator Value::begin() {
@ -1498,14 +1493,15 @@ Value::iterator Value::end() {
// class PathArgument // class PathArgument
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
PathArgument::PathArgument() = default; PathArgument::PathArgument() {}
PathArgument::PathArgument(ArrayIndex index) PathArgument::PathArgument(ArrayIndex index)
: index_(index), kind_(kindIndex) {} : index_(index), kind_(kindIndex) {}
PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {} PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {}
PathArgument::PathArgument(String key) : key_(std::move(key)), kind_(kindKey) {} PathArgument::PathArgument(String key)
: key_(JSONCPP_MOVE(key)), kind_(kindKey) {}
// class Path // class Path
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
@ -1526,7 +1522,7 @@ Path::Path(const String& path, const PathArgument& a1, const PathArgument& a2,
void Path::makePath(const String& path, const InArgs& in) { void Path::makePath(const String& path, const InArgs& in) {
const char* current = path.c_str(); const char* current = path.c_str();
const char* end = current + path.length(); const char* end = current + path.length();
auto itInArg = in.begin(); InArgs::const_iterator itInArg = in.begin();
while (current != end) { while (current != end) {
if (*current == '[') { if (*current == '[') {
++current; ++current;
@ -1572,7 +1568,9 @@ void Path::invalidPath(const String& /*path*/, int /*location*/) {
const Value& Path::resolve(const Value& root) const { const Value& Path::resolve(const Value& root) const {
const Value* node = &root; const Value* node = &root;
for (const auto& arg : args_) { for (Args::const_iterator itArg = args_.begin(); itArg != args_.end();
++itArg) {
const PathArgument& arg = *itArg;
if (arg.kind_ == PathArgument::kindIndex) { if (arg.kind_ == PathArgument::kindIndex) {
if (!node->isArray() || !node->isValidIndex(arg.index_)) { if (!node->isArray() || !node->isValidIndex(arg.index_)) {
// Error: unable to resolve path (array value expected at position... ) // Error: unable to resolve path (array value expected at position... )
@ -1597,7 +1595,9 @@ const Value& Path::resolve(const Value& root) const {
Value Path::resolve(const Value& root, const Value& defaultValue) const { Value Path::resolve(const Value& root, const Value& defaultValue) const {
const Value* node = &root; const Value* node = &root;
for (const auto& arg : args_) { for (Args::const_iterator itArg = args_.begin(); itArg != args_.end();
++itArg) {
const PathArgument& arg = *itArg;
if (arg.kind_ == PathArgument::kindIndex) { if (arg.kind_ == PathArgument::kindIndex) {
if (!node->isArray() || !node->isValidIndex(arg.index_)) if (!node->isArray() || !node->isValidIndex(arg.index_))
return defaultValue; return defaultValue;
@ -1615,7 +1615,9 @@ Value Path::resolve(const Value& root, const Value& defaultValue) const {
Value& Path::make(Value& root) const { Value& Path::make(Value& root) const {
Value* node = &root; Value* node = &root;
for (const auto& arg : args_) { for (Args::const_iterator itArg = args_.begin(); itArg != args_.end();
++itArg) {
const PathArgument& arg = *itArg;
if (arg.kind_ == PathArgument::kindIndex) { if (arg.kind_ == PathArgument::kindIndex) {
if (!node->isArray()) { if (!node->isArray()) {
// Error: node is not an array at position ... // Error: node is not an array at position ...

View File

@ -15,7 +15,7 @@ namespace Json {
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
ValueIteratorBase::ValueIteratorBase() : current_() {} ValueIteratorBase::ValueIteratorBase() : current_(), isNull_(true) {}
ValueIteratorBase::ValueIteratorBase( ValueIteratorBase::ValueIteratorBase(
const Value::ObjectValues::iterator& current) const Value::ObjectValues::iterator& current)
@ -98,8 +98,8 @@ char const* ValueIteratorBase::memberName() const {
char const* ValueIteratorBase::memberName(char const** end) const { char const* ValueIteratorBase::memberName(char const** end) const {
const char* cname = (*current_).first.data(); const char* cname = (*current_).first.data();
if (!cname) { if (!cname) {
*end = nullptr; *end = JSONCPP_NULL;
return nullptr; return JSONCPP_NULL;
} }
*end = cname + (*current_).first.length(); *end = cname + (*current_).first.length();
return cname; return cname;
@ -113,7 +113,7 @@ char const* ValueIteratorBase::memberName(char const** end) const {
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
ValueConstIterator::ValueConstIterator() = default; ValueConstIterator::ValueConstIterator() {}
ValueConstIterator::ValueConstIterator( ValueConstIterator::ValueConstIterator(
const Value::ObjectValues::iterator& current) const Value::ObjectValues::iterator& current)
@ -136,7 +136,7 @@ operator=(const ValueIteratorBase& other) {
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
ValueIterator::ValueIterator() = default; ValueIterator::ValueIterator() {}
ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
: ValueIteratorBase(current) {} : ValueIteratorBase(current) {}
@ -146,7 +146,8 @@ ValueIterator::ValueIterator(const ValueConstIterator& other)
throwRuntimeError("ConstIterator to Iterator should never be allowed."); throwRuntimeError("ConstIterator to Iterator should never be allowed.");
} }
ValueIterator::ValueIterator(const ValueIterator& other) = default; ValueIterator::ValueIterator(const ValueIterator& other)
: ValueIteratorBase(other) {}
ValueIterator& ValueIterator::operator=(const SelfType& other) { ValueIterator& ValueIterator::operator=(const SelfType& other) {
copy(other); copy(other);

View File

@ -83,11 +83,7 @@
namespace Json { namespace Json {
#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) typedef StreamWriter* StreamWriterPtr;
using StreamWriterPtr = std::unique_ptr<StreamWriter>;
#else
using StreamWriterPtr = std::auto_ptr<StreamWriter>;
#endif
String valueToString(LargestInt value) { String valueToString(LargestInt value) {
UIntToStringBuffer buffer; UIntToStringBuffer buffer;
@ -136,12 +132,12 @@ String valueToString(double value, bool useSpecialFloats,
String buffer(size_t(36), '\0'); String buffer(size_t(36), '\0');
while (true) { while (true) {
int len = jsoncpp_snprintf( int len =
&*buffer.begin(), buffer.size(), jsoncpp_snprintf(&*buffer.begin(), buffer.size(),
(precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f", (precisionType == significantDigits) ? "%.*g" : "%.*f",
precision, value); precision, value);
assert(len >= 0); assert(len >= 0);
auto wouldPrint = static_cast<size_t>(len); size_t wouldPrint = static_cast<size_t>(len);
if (wouldPrint >= buffer.size()) { if (wouldPrint >= buffer.size()) {
buffer.resize(wouldPrint + 1); buffer.resize(wouldPrint + 1);
continue; continue;
@ -153,7 +149,7 @@ String valueToString(double value, bool useSpecialFloats,
buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end()); buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end());
// strip the zero padding from the right // strip the zero padding from the right
if (precisionType == PrecisionType::decimalPlaces) { if (precisionType == decimalPlaces) {
buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end()); buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end());
} }
@ -267,7 +263,7 @@ static String toHex16Bit(unsigned int x) {
static String valueToQuotedStringN(const char* value, unsigned length, static String valueToQuotedStringN(const char* value, unsigned length,
bool emitUTF8 = false) { bool emitUTF8 = false) {
if (value == nullptr) if (value == JSONCPP_NULL)
return ""; return "";
if (!isAnyCharRequiredQuoting(value, length)) if (!isAnyCharRequiredQuoting(value, length))
@ -351,14 +347,14 @@ String valueToQuotedString(const char* value) {
// Class Writer // Class Writer
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
Writer::~Writer() = default; Writer::~Writer() {}
// Class FastWriter // Class FastWriter
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
FastWriter::FastWriter() FastWriter::FastWriter()
: yamlCompatibilityEnabled_(false), dropNullPlaceholders_(false),
= default; omitEndingLineFeed_(false) {}
void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; } void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; }
@ -414,7 +410,8 @@ void FastWriter::writeValue(const Value& value) {
case objectValue: { case objectValue: {
Value::Members members(value.getMemberNames()); Value::Members members(value.getMemberNames());
document_ += '{'; document_ += '{';
for (auto it = members.begin(); it != members.end(); ++it) { for (Value::Members::const_iterator it = members.begin();
it != members.end(); ++it) {
const String& name = *it; const String& name = *it;
if (it != members.begin()) if (it != members.begin())
document_ += ','; document_ += ',';
@ -431,7 +428,8 @@ void FastWriter::writeValue(const Value& value) {
// Class StyledWriter // Class StyledWriter
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
StyledWriter::StyledWriter() = default; StyledWriter::StyledWriter()
: rightMargin_(74), indentSize_(3), addChildValues_() {}
String StyledWriter::write(const Value& root) { String StyledWriter::write(const Value& root) {
document_.clear(); document_.clear();
@ -482,7 +480,7 @@ void StyledWriter::writeValue(const Value& value) {
else { else {
writeWithIndent("{"); writeWithIndent("{");
indent(); indent();
auto it = members.begin(); Value::Members::const_iterator it = members.begin();
for (;;) { for (;;) {
const String& name = *it; const String& name = *it;
const Value& childValue = value[name]; const Value& childValue = value[name];
@ -644,8 +642,9 @@ bool StyledWriter::hasCommentForValue(const Value& value) {
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
StyledStreamWriter::StyledStreamWriter(String indentation) StyledStreamWriter::StyledStreamWriter(String indentation)
: document_(nullptr), indentation_(std::move(indentation)), : document_(JSONCPP_NULL), rightMargin_(74),
addChildValues_(), indented_(false) {} indentation_(JSONCPP_MOVE(indentation)), addChildValues_(),
indented_(false) {}
void StyledStreamWriter::write(OStream& out, const Value& root) { void StyledStreamWriter::write(OStream& out, const Value& root) {
document_ = &out; document_ = &out;
@ -659,7 +658,7 @@ void StyledStreamWriter::write(OStream& out, const Value& root) {
writeValue(root); writeValue(root);
writeCommentAfterValueOnSameLine(root); writeCommentAfterValueOnSameLine(root);
*document_ << "\n"; *document_ << "\n";
document_ = nullptr; // Forget the stream, for safety. document_ = JSONCPP_NULL; // Forget the stream, for safety.
} }
void StyledStreamWriter::writeValue(const Value& value) { void StyledStreamWriter::writeValue(const Value& value) {
@ -700,7 +699,7 @@ void StyledStreamWriter::writeValue(const Value& value) {
else { else {
writeWithIndent("{"); writeWithIndent("{");
indent(); indent();
auto it = members.begin(); Value::Members::const_iterator it = members.begin();
for (;;) { for (;;) {
const String& name = *it; const String& name = *it;
const Value& childValue = value[name]; const Value& childValue = value[name];
@ -878,7 +877,7 @@ struct BuiltStyledStreamWriter : public StreamWriter {
String endingLineFeedSymbol, bool useSpecialFloats, String endingLineFeedSymbol, bool useSpecialFloats,
bool emitUTF8, unsigned int precision, bool emitUTF8, unsigned int precision,
PrecisionType precisionType); PrecisionType precisionType);
int write(Value const& root, OStream* sout) override; int write(Value const& root, OStream* sout) JSONCPP_OVERRIDE;
private: private:
void writeValue(Value const& value); void writeValue(Value const& value);
@ -893,7 +892,7 @@ private:
void writeCommentAfterValueOnSameLine(Value const& root); void writeCommentAfterValueOnSameLine(Value const& root);
static bool hasCommentForValue(const Value& value); static bool hasCommentForValue(const Value& value);
using ChildValues = std::vector<String>; typedef std::vector<String> ChildValues;
ChildValues childValues_; ChildValues childValues_;
String indentString_; String indentString_;
@ -914,9 +913,10 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter(
String indentation, CommentStyle::Enum cs, String colonSymbol, String indentation, CommentStyle::Enum cs, String colonSymbol,
String nullSymbol, String endingLineFeedSymbol, bool useSpecialFloats, String nullSymbol, String endingLineFeedSymbol, bool useSpecialFloats,
bool emitUTF8, unsigned int precision, PrecisionType precisionType) bool emitUTF8, unsigned int precision, PrecisionType precisionType)
: rightMargin_(74), indentation_(std::move(indentation)), cs_(cs), : rightMargin_(74), indentation_(JSONCPP_MOVE(indentation)), cs_(cs),
colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)), colonSymbol_(JSONCPP_MOVE(colonSymbol)),
endingLineFeedSymbol_(std::move(endingLineFeedSymbol)), nullSymbol_(JSONCPP_MOVE(nullSymbol)),
endingLineFeedSymbol_(JSONCPP_MOVE(endingLineFeedSymbol)),
addChildValues_(false), indented_(false), addChildValues_(false), indented_(false),
useSpecialFloats_(useSpecialFloats), emitUTF8_(emitUTF8), useSpecialFloats_(useSpecialFloats), emitUTF8_(emitUTF8),
precision_(precision), precisionType_(precisionType) {} precision_(precision), precisionType_(precisionType) {}
@ -932,7 +932,7 @@ int BuiltStyledStreamWriter::write(Value const& root, OStream* sout) {
writeValue(root); writeValue(root);
writeCommentAfterValueOnSameLine(root); writeCommentAfterValueOnSameLine(root);
*sout_ << endingLineFeedSymbol_; *sout_ << endingLineFeedSymbol_;
sout_ = nullptr; sout_ = JSONCPP_NULL;
return 0; return 0;
} }
void BuiltStyledStreamWriter::writeValue(Value const& value) { void BuiltStyledStreamWriter::writeValue(Value const& value) {
@ -975,7 +975,7 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
else { else {
writeWithIndent("{"); writeWithIndent("{");
indent(); indent();
auto it = members.begin(); Value::Members::const_iterator it = members.begin();
for (;;) { for (;;) {
String const& name = *it; String const& name = *it;
Value const& childValue = value[name]; Value const& childValue = value[name];
@ -1151,11 +1151,11 @@ bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
/////////////// ///////////////
// StreamWriter // StreamWriter
StreamWriter::StreamWriter() : sout_(nullptr) {} StreamWriter::StreamWriter() : sout_(JSONCPP_NULL) {}
StreamWriter::~StreamWriter() = default; StreamWriter::~StreamWriter() {}
StreamWriter::Factory::~Factory() = default; StreamWriter::Factory::~Factory() {}
StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); } StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); }
StreamWriterBuilder::~StreamWriterBuilder() = default; StreamWriterBuilder::~StreamWriterBuilder() {}
StreamWriter* StreamWriterBuilder::newStreamWriter() const { StreamWriter* StreamWriterBuilder::newStreamWriter() const {
const String indentation = settings_["indentation"].asString(); const String indentation = settings_["indentation"].asString();
const String cs_str = settings_["commentStyle"].asString(); const String cs_str = settings_["commentStyle"].asString();
@ -1175,9 +1175,9 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const {
} }
PrecisionType precisionType(significantDigits); PrecisionType precisionType(significantDigits);
if (pt_str == "significant") { if (pt_str == "significant") {
precisionType = PrecisionType::significantDigits; precisionType = significantDigits;
} else if (pt_str == "decimal") { } else if (pt_str == "decimal") {
precisionType = PrecisionType::decimalPlaces; precisionType = decimalPlaces;
} else { } else {
throwRuntimeError("precisionType must be 'significant' or 'decimal'"); throwRuntimeError("precisionType must be 'significant' or 'decimal'");
} }
@ -1247,6 +1247,7 @@ String writeString(StreamWriter::Factory const& factory, Value const& root) {
OStringStream sout; OStringStream sout;
StreamWriterPtr const writer(factory.newStreamWriter()); StreamWriterPtr const writer(factory.newStreamWriter());
writer->write(root, &sout); writer->write(root, &sout);
delete writer;
return sout.str(); return sout.str();
} }
@ -1254,6 +1255,7 @@ OStream& operator<<(OStream& sout, Value const& root) {
StreamWriterBuilder builder; StreamWriterBuilder builder;
StreamWriterPtr const writer(builder.newStreamWriter()); StreamWriterPtr const writer(builder.newStreamWriter());
writer->write(root, &sout); writer->write(root, &sout);
delete writer;
return sout; return sout;
} }

View File

@ -5,7 +5,6 @@
#include "fuzz.h" #include "fuzz.h"
#include <cstdint>
#include <json/config.h> #include <json/config.h>
#include <json/json.h> #include <json/json.h>
#include <memory> #include <memory>
@ -41,14 +40,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
builder.settings_["collectComments"] = hash_settings & (1 << 9); builder.settings_["collectComments"] = hash_settings & (1 << 9);
builder.settings_["allowTrailingCommas_"] = hash_settings & (1 << 10); builder.settings_["allowTrailingCommas_"] = hash_settings & (1 << 10);
std::unique_ptr<Json::CharReader> reader(builder.newCharReader()); Json::CharReader* reader(builder.newCharReader());
Json::Value root; Json::Value root;
const auto data_str = reinterpret_cast<const char*>(data); const char* data_str = reinterpret_cast<const char*>(data);
try { try {
reader->parse(data_str, data_str + size, &root, nullptr); reader->parse(data_str, data_str + size, &root, JSONCPP_NULL);
} catch (Json::Exception const&) { } catch (Json::Exception const&) {
} }
delete reader;
// Whether it succeeded or not doesn't matter. // Whether it succeeded or not doesn't matter.
return 0; return 0;
} }

View File

@ -73,10 +73,11 @@ namespace JsonTest {
// class TestResult // class TestResult
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
TestResult::TestResult() { TestResult::TestResult()
: predicateId_(1), lastUsedPredicateId_(0), messageTarget_(JSONCPP_NULL) {
// The root predicate has id 0 // The root predicate has id 0
rootPredicateNode_.id_ = 0; rootPredicateNode_.id_ = 0;
rootPredicateNode_.next_ = nullptr; rootPredicateNode_.next_ = JSONCPP_NULL;
predicateStackTail_ = &rootPredicateNode_; predicateStackTail_ = &rootPredicateNode_;
} }
@ -88,7 +89,7 @@ TestResult& TestResult::addFailure(const char* file, unsigned int line,
/// added. /// added.
unsigned int nestingLevel = 0; unsigned int nestingLevel = 0;
PredicateContext* lastNode = rootPredicateNode_.next_; PredicateContext* lastNode = rootPredicateNode_.next_;
for (; lastNode != nullptr; lastNode = lastNode->next_) { for (; lastNode != JSONCPP_NULL; lastNode = lastNode->next_) {
if (lastNode->id_ > lastUsedPredicateId_) // new PredicateContext if (lastNode->id_ > lastUsedPredicateId_) // new PredicateContext
{ {
lastUsedPredicateId_ = lastNode->id_; lastUsedPredicateId_ = lastNode->id_;
@ -121,17 +122,18 @@ void TestResult::addFailureInfo(const char* file, unsigned int line,
TestResult& TestResult::popPredicateContext() { TestResult& TestResult::popPredicateContext() {
PredicateContext* lastNode = &rootPredicateNode_; PredicateContext* lastNode = &rootPredicateNode_;
while (lastNode->next_ != nullptr && lastNode->next_->next_ != nullptr) { while (lastNode->next_ != JSONCPP_NULL &&
lastNode->next_->next_ != JSONCPP_NULL) {
lastNode = lastNode->next_; lastNode = lastNode->next_;
} }
// Set message target to popped failure // Set message target to popped failure
PredicateContext* tail = lastNode->next_; PredicateContext* tail = lastNode->next_;
if (tail != nullptr && tail->failure_ != nullptr) { if (tail != JSONCPP_NULL && tail->failure_ != JSONCPP_NULL) {
messageTarget_ = tail->failure_; messageTarget_ = tail->failure_;
} }
// Remove tail from list // Remove tail from list
predicateStackTail_ = lastNode; predicateStackTail_ = lastNode;
lastNode->next_ = nullptr; lastNode->next_ = JSONCPP_NULL;
return *this; return *this;
} }
@ -147,7 +149,9 @@ void TestResult::printFailure(bool printTestName) const {
} }
// Print in reverse to display the callstack in the right order // Print in reverse to display the callstack in the right order
for (const auto& failure : failures_) { for (Failures::const_iterator it = failures_.begin(); it != failures_.end();
++it) {
const Failure& failure = *it;
Json::String indent(failure.nestingLevel_ * 2, ' '); Json::String indent(failure.nestingLevel_ * 2, ' ');
if (failure.file_) { if (failure.file_) {
printf("%s%s(%u): ", indent.c_str(), failure.file_, failure.line_); printf("%s%s(%u): ", indent.c_str(), failure.file_, failure.line_);
@ -181,7 +185,7 @@ Json::String TestResult::indentText(const Json::String& text,
} }
TestResult& TestResult::addToLastFailure(const Json::String& message) { TestResult& TestResult::addToLastFailure(const Json::String& message) {
if (messageTarget_ != nullptr) { if (messageTarget_ != JSONCPP_NULL) {
messageTarget_->message_ += message; messageTarget_->message_ += message;
} }
return *this; return *this;
@ -202,9 +206,9 @@ TestResult& TestResult::operator<<(bool value) {
// class TestCase // class TestCase
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
TestCase::TestCase() = default; TestCase::TestCase() : result_(JSONCPP_NULL) {}
TestCase::~TestCase() = default; TestCase::~TestCase() {}
void TestCase::run(TestResult& result) { void TestCase::run(TestResult& result) {
result_ = &result; result_ = &result;
@ -214,7 +218,7 @@ void TestCase::run(TestResult& result) {
// class Runner // class Runner
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
Runner::Runner() = default; Runner::Runner() {}
Runner& Runner::add(TestCaseFactory factory) { Runner& Runner::add(TestCaseFactory factory) {
tests_.push_back(factory); tests_.push_back(factory);
@ -268,7 +272,8 @@ bool Runner::runAllTest(bool printSummary) const {
} }
return true; return true;
} }
for (auto& result : failures) { for (size_t index = 0; index < failures.size(); ++index) {
TestResult& result = failures[index];
result.printFailure(count > 1); result.printFailure(count > 1);
} }

View File

@ -42,7 +42,7 @@ public:
/// Must be a POD to allow inline initialisation without stepping /// Must be a POD to allow inline initialisation without stepping
/// into the debugger. /// into the debugger.
struct PredicateContext { struct PredicateContext {
using Id = unsigned int; typedef unsigned int Id;
Id id_; Id id_;
const char* file_; const char* file_;
unsigned int line_; unsigned int line_;
@ -61,7 +61,7 @@ public:
/// Not encapsulated to prevent step into when debugging failed assertions /// Not encapsulated to prevent step into when debugging failed assertions
/// Incremented by one on assertion predicate entry, decreased by one /// Incremented by one on assertion predicate entry, decreased by one
/// by addPredicateContext(). /// by addPredicateContext().
PredicateContext::Id predicateId_{1}; PredicateContext::Id predicateId_;
/// \internal Implementation detail for predicate macros /// \internal Implementation detail for predicate macros
PredicateContext* predicateStackTail_; PredicateContext* predicateStackTail_;
@ -70,7 +70,7 @@ public:
/// Adds an assertion failure. /// Adds an assertion failure.
TestResult& addFailure(const char* file, unsigned int line, TestResult& addFailure(const char* file, unsigned int line,
const char* expr = nullptr); const char* expr = JSONCPP_NULL);
/// Removes the last PredicateContext added to the predicate stack /// Removes the last PredicateContext added to the predicate stack
/// chained list. /// chained list.
@ -84,7 +84,9 @@ public:
// Generic operator that will work with anything ostream can deal with. // 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) {
Json::OStringStream oss; Json::OStringStream oss;
oss << std::setprecision(16) << std::hexfloat << value; oss.precision(16);
oss.setf(std::ios_base::floatfield);
oss << value;
return addToLastFailure(oss.str()); return addToLastFailure(oss.str());
} }
@ -102,13 +104,13 @@ private:
static Json::String indentText(const Json::String& text, static Json::String indentText(const Json::String& text,
const Json::String& indent); const Json::String& indent);
using Failures = std::deque<Failure>; typedef std::deque<Failure> Failures;
Failures failures_; Failures failures_;
Json::String name_; Json::String name_;
PredicateContext rootPredicateNode_; PredicateContext rootPredicateNode_;
PredicateContext::Id lastUsedPredicateId_{0}; PredicateContext::Id lastUsedPredicateId_;
/// Failure which is the target of the messages added using operator << /// Failure which is the target of the messages added using operator <<
Failure* messageTarget_{nullptr}; Failure* messageTarget_;
}; };
class TestCase { class TestCase {
@ -122,14 +124,14 @@ public:
virtual const char* testName() const = 0; virtual const char* testName() const = 0;
protected: protected:
TestResult* result_{nullptr}; TestResult* result_;
private: private:
virtual void runTestCase() = 0; virtual void runTestCase() = 0;
}; };
/// Function pointer type for TestCase factory /// Function pointer type for TestCase factory
using TestCaseFactory = TestCase* (*)(); typedef TestCase* (*TestCaseFactory)();
class Runner { class Runner {
public: public:
@ -159,8 +161,8 @@ public:
static void printUsage(const char* appName); static void printUsage(const char* appName);
private: // prevents copy construction and assignment private: // prevents copy construction and assignment
Runner(const Runner& other) = delete; Runner(const Runner& other) JSONCPP_CTOR_DELETE;
Runner& operator=(const Runner& other) = delete; Runner& operator=(const Runner& other) JSONCPP_CTOR_DELETE;
private: private:
void listTests() const; void listTests() const;
@ -168,7 +170,7 @@ private:
static void preventDialogOnCrash(); static void preventDialogOnCrash();
private: private:
using Factories = std::deque<TestCaseFactory>; typedef std::deque<TestCaseFactory> Factories;
Factories tests_; Factories tests_;
}; };
@ -251,8 +253,10 @@ TestResult& checkStringEqual(TestResult& result, const Json::String& expected,
} \ } \
\ \
public: /* overridden from TestCase */ \ public: /* overridden from TestCase */ \
const char* testName() const override { return #FixtureType "/" #name; } \ const char* testName() const JSONCPP_OVERRIDE { \
void runTestCase() override; \ return #FixtureType "/" #name; \
} \
void runTestCase() JSONCPP_OVERRIDE; \
}; \ }; \
\ \
void Test##FixtureType##name::runTestCase() void Test##FixtureType##name::runTestCase()
@ -276,8 +280,10 @@ TestResult& checkStringEqual(TestResult& result, const Json::String& expected,
} \ } \
\ \
public: /* overridden from TestCase */ \ public: /* overridden from TestCase */ \
const char* testName() const override { return #FixtureType "/" #name; } \ const char* testName() const JSONCPP_OVERRIDE { \
void runTestCase() override; \ return #FixtureType "/" #name; \
} \
void runTestCase() JSONCPP_OVERRIDE; \
}; \ }; \
\ \
static bool test##FixtureType##name##collect = \ static bool test##FixtureType##name##collect = \

View File

@ -25,7 +25,7 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
using CharReaderPtr = std::unique_ptr<Json::CharReader>; typedef Json::CharReader* CharReaderPtr;
// Make numeric limits more convenient to talk about. // Make numeric limits more convenient to talk about.
// Assumes int type in 32 bits. // Assumes int type in 32 bits.
@ -65,22 +65,27 @@ static std::deque<JsonTest::TestCaseFactory> local_;
struct ValueTest : JsonTest::TestCase { struct ValueTest : JsonTest::TestCase {
Json::Value null_; Json::Value null_;
Json::Value emptyArray_{Json::arrayValue}; Json::Value emptyArray_;
Json::Value emptyObject_{Json::objectValue}; Json::Value emptyObject_;
Json::Value integer_{123456789}; Json::Value integer_;
Json::Value unsignedInteger_{34567890}; Json::Value unsignedInteger_;
Json::Value smallUnsignedInteger_{Json::Value::UInt(Json::Value::maxInt)}; Json::Value smallUnsignedInteger_;
Json::Value real_{1234.56789}; Json::Value real_;
Json::Value float_{0.00390625f}; Json::Value float_;
Json::Value array1_; Json::Value array1_;
Json::Value object1_; Json::Value object1_;
Json::Value emptyString_{""}; Json::Value emptyString_;
Json::Value string1_{"a"}; Json::Value string1_;
Json::Value string_{"sometext with space"}; Json::Value string_;
Json::Value true_{true}; Json::Value true_;
Json::Value false_{false}; Json::Value false_;
ValueTest() { 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) {
array1_.append(1234); array1_.append(1234);
object1_["id"] = 1234; object1_["id"] = 1234;
} }
@ -89,19 +94,19 @@ struct ValueTest : JsonTest::TestCase {
/// Initialize all checks to \c false by default. /// Initialize all checks to \c false by default.
IsCheck(); IsCheck();
bool isObject_{false}; bool isObject_;
bool isArray_{false}; bool isArray_;
bool isBool_{false}; bool isBool_;
bool isString_{false}; bool isString_;
bool isNull_{false}; bool isNull_;
bool isInt_{false}; bool isInt_;
bool isInt64_{false}; bool isInt64_;
bool isUInt_{false}; bool isUInt_;
bool isUInt64_{false}; bool isUInt64_;
bool isIntegral_{false}; bool isIntegral_;
bool isDouble_{false}; bool isDouble_;
bool isNumeric_{false}; bool isNumeric_;
}; };
void checkConstMemberCount(const Json::Value& value, void checkConstMemberCount(const Json::Value& value,
@ -121,13 +126,14 @@ struct ValueTest : JsonTest::TestCase {
}; };
Json::String ValueTest::normalizeFloatingPointStr(const Json::String& s) { Json::String ValueTest::normalizeFloatingPointStr(const Json::String& s) {
auto index = s.find_last_of("eE"); std::string::size_type index = s.find_last_of("eE");
if (index == s.npos) if (index == s.npos)
return s; return s;
std::size_t signWidth = (s[index + 1] == '+' || s[index + 1] == '-') ? 1 : 0; std::size_t signWidth = (s[index + 1] == '+' || s[index + 1] == '-') ? 1 : 0;
auto exponentStartIndex = index + 1 + signWidth; std::string::size_type exponentStartIndex = index + 1 + signWidth;
Json::String normalized = s.substr(0, exponentStartIndex); Json::String normalized = s.substr(0, exponentStartIndex);
auto indexDigit = s.find_first_not_of('0', exponentStartIndex); std::string::size_type indexDigit =
s.find_first_not_of('0', exponentStartIndex);
Json::String exponent = "0"; Json::String exponent = "0";
if (indexDigit != s.npos) { // nonzero exponent if (indexDigit != s.npos) { // nonzero exponent
exponent = s.substr(indexDigit); exponent = s.substr(indexDigit);
@ -157,7 +163,9 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, checkNormalizeFloatingPointStr) {
{"1234e+100", "1234e+100"}, {"1234e+100", "1234e+100"},
{"1234e-100", "1234e-100"}, {"1234e-100", "1234e-100"},
}; };
for (const auto& td : testData) { for (unsigned int index = 0; index < sizeof(testData) / sizeof(testData[0]);
++index) {
const struct TestData td = testData[index];
JSONTEST_ASSERT_STRING_EQUAL(normalizeFloatingPointStr(td.in), td.out); JSONTEST_ASSERT_STRING_EQUAL(normalizeFloatingPointStr(td.in), td.out);
} }
} }
@ -215,22 +223,22 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, objects) {
// Access through find() // Access through find()
const char idKey[] = "id"; const char idKey[] = "id";
const Json::Value* foundId = object1_.find(idKey, idKey + strlen(idKey)); const Json::Value* foundId = object1_.find(idKey, idKey + strlen(idKey));
JSONTEST_ASSERT(foundId != nullptr); JSONTEST_ASSERT(foundId != JSONCPP_NULL);
JSONTEST_ASSERT_EQUAL(Json::Value(1234), *foundId); JSONTEST_ASSERT_EQUAL(Json::Value(1234), *foundId);
const char unknownIdKey[] = "unknown id"; const char unknownIdKey[] = "unknown id";
const Json::Value* foundUnknownId = const Json::Value* foundUnknownId =
object1_.find(unknownIdKey, unknownIdKey + strlen(unknownIdKey)); object1_.find(unknownIdKey, unknownIdKey + strlen(unknownIdKey));
JSONTEST_ASSERT_EQUAL(nullptr, foundUnknownId); JSONTEST_ASSERT(JSONCPP_NULL == foundUnknownId);
// Access through demand() // Access through demand()
const char yetAnotherIdKey[] = "yet another id"; const char yetAnotherIdKey[] = "yet another id";
const Json::Value* foundYetAnotherId = const Json::Value* foundYetAnotherId =
object1_.find(yetAnotherIdKey, yetAnotherIdKey + strlen(yetAnotherIdKey)); object1_.find(yetAnotherIdKey, yetAnotherIdKey + strlen(yetAnotherIdKey));
JSONTEST_ASSERT_EQUAL(nullptr, foundYetAnotherId); JSONTEST_ASSERT(JSONCPP_NULL == foundYetAnotherId);
Json::Value* demandedYetAnotherId = object1_.demand( Json::Value* demandedYetAnotherId = object1_.demand(
yetAnotherIdKey, yetAnotherIdKey + strlen(yetAnotherIdKey)); yetAnotherIdKey, yetAnotherIdKey + strlen(yetAnotherIdKey));
JSONTEST_ASSERT(demandedYetAnotherId != nullptr); JSONTEST_ASSERT(demandedYetAnotherId != JSONCPP_NULL);
*demandedYetAnotherId = "baz"; *demandedYetAnotherId = "baz";
JSONTEST_ASSERT_EQUAL(Json::Value("baz"), object1_["yet another id"]); JSONTEST_ASSERT_EQUAL(Json::Value("baz"), object1_["yet another id"]);
@ -255,9 +263,9 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, objects) {
JSONTEST_ASSERT_EQUAL(false, did); JSONTEST_ASSERT_EQUAL(false, did);
object1_["some other id"] = "foo"; object1_["some other id"] = "foo";
Json::Value* gotPtr = nullptr; Json::Value* gotPtr = JSONCPP_NULL;
did = object1_.removeMember("some other id", gotPtr); did = object1_.removeMember("some other id", gotPtr);
JSONTEST_ASSERT_EQUAL(nullptr, gotPtr); JSONTEST_ASSERT(JSONCPP_NULL == gotPtr);
JSONTEST_ASSERT_EQUAL(true, did); JSONTEST_ASSERT_EQUAL(true, did);
// Using other removeMember interfaces, the test idea is the same as above. // Using other removeMember interfaces, the test idea is the same as above.
@ -1182,7 +1190,7 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, integers) {
normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString()))); normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString())));
// 10^19 // 10^19
const auto ten_to_19 = static_cast<Json::UInt64>(1e19); const Json::UInt64 ten_to_19 = static_cast<Json::UInt64>(1e19);
val = Json::Value(Json::UInt64(ten_to_19)); val = Json::Value(Json::UInt64(ten_to_19));
JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type()); JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type());
@ -1476,7 +1484,11 @@ void ValueTest::checkMemberCount(Json::Value& value,
JSONTEST_ASSERT_PRED(checkConstMemberCount(value, expectedCount)); JSONTEST_ASSERT_PRED(checkConstMemberCount(value, expectedCount));
} }
ValueTest::IsCheck::IsCheck() = default; 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) {}
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.isObject_, value.isObject());
@ -1661,19 +1673,19 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, CopyObject) {
Json::Value srcObject, objectCopy, otherObject; Json::Value srcObject, objectCopy, otherObject;
srcObject["key0"] = 10; srcObject["key0"] = 10;
objectCopy.copy(srcObject); objectCopy.copy(srcObject);
JSONTEST_ASSERT(srcObject["key0"] == 10); JSONTEST_ASSERT(srcObject["key0"].asInt() == 10);
JSONTEST_ASSERT(objectCopy["key0"] == 10); JSONTEST_ASSERT(objectCopy["key0"].asInt() == 10);
JSONTEST_ASSERT(srcObject.getMemberNames().size() == 1); JSONTEST_ASSERT(srcObject.getMemberNames().size() == 1);
JSONTEST_ASSERT(objectCopy.getMemberNames().size() == 1); JSONTEST_ASSERT(objectCopy.getMemberNames().size() == 1);
otherObject["key1"] = 15; otherObject["key1"] = 15;
otherObject["key2"] = 16; otherObject["key2"] = 16;
JSONTEST_ASSERT(otherObject.getMemberNames().size() == 2); JSONTEST_ASSERT(otherObject.getMemberNames().size() == 2);
objectCopy.copy(otherObject); objectCopy.copy(otherObject);
JSONTEST_ASSERT(objectCopy["key1"] == 15); JSONTEST_ASSERT(objectCopy["key1"].asInt() == 15);
JSONTEST_ASSERT(objectCopy["key2"] == 16); JSONTEST_ASSERT(objectCopy["key2"].asInt() == 16);
JSONTEST_ASSERT(objectCopy.getMemberNames().size() == 2); JSONTEST_ASSERT(objectCopy.getMemberNames().size() == 2);
otherObject["key1"] = 20; otherObject["key1"] = 20;
JSONTEST_ASSERT(objectCopy["key1"] == 15); JSONTEST_ASSERT(objectCopy["key1"].asInt() == 15);
} }
} }
@ -1817,7 +1829,7 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, StaticString) {
JSONTEST_FIXTURE_LOCAL(ValueTest, WideString) { JSONTEST_FIXTURE_LOCAL(ValueTest, WideString) {
// https://github.com/open-source-parsers/jsoncpp/issues/756 // https://github.com/open-source-parsers/jsoncpp/issues/756
const std::string uni = u8"\u5f0f\uff0c\u8fdb"; // "式,进" const std::string uni = "\u5f0f\uff0c\u8fdb"; // "式,进"
std::string styled; std::string styled;
{ {
Json::Value v; Json::Value v;
@ -2592,7 +2604,7 @@ JSONTEST_FIXTURE_LOCAL(StreamWriterTest, indentation) {
JSONTEST_FIXTURE_LOCAL(StreamWriterTest, writeZeroes) { JSONTEST_FIXTURE_LOCAL(StreamWriterTest, writeZeroes) {
Json::String binary("hi", 3); // include trailing 0 Json::String binary("hi", 3); // include trailing 0
JSONTEST_ASSERT_EQUAL(3, binary.length()); JSONTEST_ASSERT_EQUAL(3, binary.length());
Json::String expected(R"("hi\u0000")"); // unicoded zero Json::String expected("\"hi\\u0000\""); // unicoded zero
Json::StreamWriterBuilder b; Json::StreamWriterBuilder b;
{ {
Json::Value root; Json::Value root;
@ -2639,7 +2651,7 @@ JSONTEST_FIXTURE_LOCAL(StreamWriterTest, unicode) {
"{\n\t\"test\" : " "{\n\t\"test\" : "
"\"\\t\\n\\ud806\\udca1=\\u0133\\ud82c\\udd1b\\uff67\"\n}"); "\"\\t\\n\\ud806\\udca1=\\u0133\\ud82c\\udd1b\\uff67\"\n}");
} }
#if JSONCPP_CXX_STD_11
struct ReaderTest : JsonTest::TestCase { struct ReaderTest : JsonTest::TestCase {
void setStrictMode() { void setStrictMode() {
reader = std::unique_ptr<Json::Reader>( reader = std::unique_ptr<Json::Reader>(
@ -2688,43 +2700,43 @@ struct ReaderTest : JsonTest::TestCase {
}; };
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrors) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrors) {
checkParse(R"({ "property" : "value" })"); checkParse("{ \"property\" : \"value\" }");
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseObject) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseObject) {
checkParse(R"({"property"})", checkParse("{\"property\"}",
{{11, 12, "Missing ':' after object member name"}}, {{11, 12, "Missing ':' after object member name"}},
"* Line 1, Column 12\n Missing ':' after object member name\n"); "* Line 1, Column 12\n Missing ':' after object member name\n");
checkParse( checkParse(
R"({"property" : "value" )", "{\"property\" : \"value\" ",
{{22, 22, "Missing ',' or '}' in object declaration"}}, {{22, 22, "Missing ',' or '}' in object declaration"}},
"* Line 1, Column 23\n Missing ',' or '}' in object declaration\n"); "* Line 1, Column 23\n Missing ',' or '}' in object declaration\n");
checkParse(R"({"property" : "value", )", checkParse("{\"property\" : \"value\", ",
{{23, 23, "Missing '}' or object member name"}}, {{23, 23, "Missing '}' or object member name"}},
"* Line 1, Column 24\n Missing '}' or object member name\n"); "* Line 1, Column 24\n Missing '}' or object member name\n");
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseArray) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseArray) {
checkParse( checkParse(
R"([ "value" )", {{10, 10, "Missing ',' or ']' in array declaration"}}, "[ \"value\" ", {{10, 10, "Missing ',' or ']' in array declaration"}},
"* Line 1, Column 11\n Missing ',' or ']' in array declaration\n"); "* Line 1, Column 11\n Missing ',' or ']' in array declaration\n");
checkParse( checkParse(
R"([ "value1" "value2" ] )", "[ \"value1\" \"value2\" ] ",
{{11, 19, "Missing ',' or ']' in array declaration"}}, {{11, 19, "Missing ',' or ']' in array declaration"}},
"* Line 1, Column 12\n Missing ',' or ']' in array declaration\n"); "* Line 1, Column 12\n Missing ',' or ']' in array declaration\n");
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseString) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseString) {
checkParse(R"([ "\u8a2a" ])"); checkParse("[ \"\u8a2a\" ]");
checkParse( checkParse(
R"([ "\ud801" ])", "[ \"\\ud801\" ]",
{{2, 10, {{2, 10,
"additional six characters expected to parse unicode surrogate " "additional six characters expected to parse unicode surrogate "
"pair."}}, "pair."}},
"* Line 1, Column 3\n" "* Line 1, Column 3\n"
" additional six characters expected to parse unicode surrogate pair.\n" " additional six characters expected to parse unicode surrogate pair.\n"
"See Line 1, Column 10 for detail.\n"); "See Line 1, Column 10 for detail.\n");
checkParse(R"([ "\ud801\d1234" ])", checkParse("[ \"\\ud801\\d1234\" ]",
{{2, 16, {{2, 16,
"expecting another \\u token to begin the " "expecting another \\u token to begin the "
"second half of a unicode surrogate pair"}}, "second half of a unicode surrogate pair"}},
@ -2732,7 +2744,7 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseString) {
" expecting another \\u token to begin the " " expecting another \\u token to begin the "
"second half of a unicode surrogate pair\n" "second half of a unicode surrogate pair\n"
"See Line 1, Column 12 for detail.\n"); "See Line 1, Column 12 for detail.\n");
checkParse(R"([ "\ua3t@" ])", checkParse("[ \"\\ua3t@\" ]",
{{2, 10, {{2, 10,
"Bad unicode escape sequence in string: " "Bad unicode escape sequence in string: "
"hexadecimal digit expected."}}, "hexadecimal digit expected."}},
@ -2741,7 +2753,7 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseString) {
"hexadecimal digit expected.\n" "hexadecimal digit expected.\n"
"See Line 1, Column 9 for detail.\n"); "See Line 1, Column 9 for detail.\n");
checkParse( checkParse(
R"([ "\ua3t" ])", "[ \"\\ua3t\" ]",
{{2, 9, "Bad unicode escape sequence in string: four digits expected."}}, {{2, 9, "Bad unicode escape sequence in string: four digits expected."}},
"* Line 1, Column 3\n" "* Line 1, Column 3\n"
" Bad unicode escape sequence in string: four digits expected.\n" " Bad unicode escape sequence in string: four digits expected.\n"
@ -2750,29 +2762,29 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseString) {
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseComment) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseComment) {
checkParse( checkParse(
R"({ /*commentBeforeValue*/ "property" : "value" }//commentAfterValue)" "{ /*commentBeforeValue*/ \"property\" : \"value\" }//commentAfterValue"
"\n"); "\n");
checkParse(" true //comment1\n//comment2\r//comment3\r\n"); checkParse(" true //comment1\n//comment2\r//comment3\r\n");
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, streamParseWithNoErrors) { JSONTEST_FIXTURE_LOCAL(ReaderTest, streamParseWithNoErrors) {
std::string styled = R"({ "property" : "value" })"; std::string styled = "{ \"property\" : \"value\" }";
std::istringstream iss(styled); std::istringstream iss(styled);
checkParse(iss); checkParse(iss);
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrorsTestingOffsets) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrorsTestingOffsets) {
checkParse(R"({)" checkParse("{"
R"( "property" : ["value", "value2"],)" " \"property\" : [\"value\", \"value2\"],"
R"( "obj" : { "nested" : -6.2e+15, "bool" : true},)" " \"obj\" : { \"nested\" : -6.2e+15, \"bool\" : true},"
R"( "null" : null,)" " \"null\" : null,"
R"( "false" : false)" " \"false\" : false"
R"( })"); "}");
auto checkOffsets = [&](const Json::Value& v, int start, int limit) { auto checkOffsets = [&](const Json::Value& v, int start, int limit) {
JSONTEST_ASSERT_EQUAL(start, v.getOffsetStart()); JSONTEST_ASSERT_EQUAL(start, v.getOffsetStart());
JSONTEST_ASSERT_EQUAL(limit, v.getOffsetLimit()); JSONTEST_ASSERT_EQUAL(limit, v.getOffsetLimit());
}; };
checkOffsets(root, 0, 115); checkOffsets(root, 0, 114);
checkOffsets(root["property"], 15, 34); checkOffsets(root["property"], 15, 34);
checkOffsets(root["property"][0], 16, 23); checkOffsets(root["property"][0], 16, 23);
checkOffsets(root["property"][1], 25, 33); checkOffsets(root["property"][1], 25, 33);
@ -2784,7 +2796,7 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrorsTestingOffsets) {
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithOneError) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithOneError) {
checkParse(R"({ "property" :: "value" })", checkParse("{ \"property\" :: \"value\" }",
{{14, 15, "Syntax error: value, object or array expected."}}, {{14, 15, "Syntax error: value, object or array expected."}},
"* Line 1, Column 15\n Syntax error: value, object or array " "* Line 1, Column 15\n Syntax error: value, object or array "
"expected.\n"); "expected.\n");
@ -2794,11 +2806,11 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithOneError) {
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseSpecialFloat) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseSpecialFloat) {
checkParse(R"({ "a" : Infi })", checkParse("{ \"a\" : Infi }",
{{8, 9, "Syntax error: value, object or array expected."}}, {{8, 9, "Syntax error: value, object or array expected."}},
"* Line 1, Column 9\n Syntax error: value, object or array " "* Line 1, Column 9\n Syntax error: value, object or array "
"expected.\n"); "expected.\n");
checkParse(R"({ "a" : Infiniaa })", checkParse("{ \"a\" : Infiniaa }",
{{8, 9, "Syntax error: value, object or array expected."}}, {{8, 9, "Syntax error: value, object or array expected."}},
"* Line 1, Column 9\n Syntax error: value, object or array " "* Line 1, Column 9\n Syntax error: value, object or array "
"expected.\n"); "expected.\n");
@ -2815,16 +2827,20 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, strictModeParseNumber) {
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseChineseWithOneError) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseChineseWithOneError) {
checkParse(R"({ "pr)" checkParse("{ \"pr"
#if JSONCPP_CXX_STD_11
u8"\u4f50\u85e4" // 佐藤 u8"\u4f50\u85e4" // 佐藤
R"(erty" :: "value" })", #else
"\u4f50\u85e4" // 佐藤
#endif
"erty\" :: \"value\" }",
{{18, 19, "Syntax error: value, object or array expected."}}, {{18, 19, "Syntax error: value, object or array expected."}},
"* Line 1, Column 19\n Syntax error: value, object or array " "* Line 1, Column 19\n Syntax error: value, object or array "
"expected.\n"); "expected.\n");
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithDetailError) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithDetailError) {
checkParse(R"({ "property" : "v\alue" })", checkParse("{ \"property\" : \"v\\alue\" }",
{{15, 23, "Bad escape sequence in string"}}, {{15, 23, "Bad escape sequence in string"}},
"* Line 1, Column 16\n" "* Line 1, Column 16\n"
" Bad escape sequence in string\n" " Bad escape sequence in string\n"
@ -2832,7 +2848,7 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithDetailError) {
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, pushErrorTest) { JSONTEST_FIXTURE_LOCAL(ReaderTest, pushErrorTest) {
checkParse(R"({ "AUTHOR" : 123 })"); checkParse("{ \"AUTHOR\" : 123 }");
if (!root["AUTHOR"].isString()) { if (!root["AUTHOR"].isString()) {
JSONTEST_ASSERT( JSONTEST_ASSERT(
reader->pushError(root["AUTHOR"], "AUTHOR must be a string")); reader->pushError(root["AUTHOR"], "AUTHOR must be a string"));
@ -2841,7 +2857,7 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, pushErrorTest) {
"* Line 1, Column 14\n" "* Line 1, Column 14\n"
" AUTHOR must be a string\n"); " AUTHOR must be a string\n");
checkParse(R"({ "AUTHOR" : 123 })"); checkParse("{ \"AUTHOR\" : 123 }");
if (!root["AUTHOR"].isString()) { if (!root["AUTHOR"].isString()) {
JSONTEST_ASSERT(reader->pushError(root["AUTHOR"], "AUTHOR must be a string", JSONTEST_ASSERT(reader->pushError(root["AUTHOR"], "AUTHOR must be a string",
root["AUTHOR"])); root["AUTHOR"]));
@ -2856,9 +2872,9 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, allowNumericKeysTest) {
Json::Features features; Json::Features features;
features.allowNumericKeys_ = true; features.allowNumericKeys_ = true;
setFeatures(features); setFeatures(features);
checkParse(R"({ 123 : "abc" })"); checkParse("{ 123 : \"abc\" }");
} }
#endif // JSONCPP_CXX_STD_11
struct CharReaderTest : JsonTest::TestCase {}; struct CharReaderTest : JsonTest::TestCase {};
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrors) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrors) {
@ -2866,10 +2882,11 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrors) {
CharReaderPtr reader(b.newCharReader()); CharReaderPtr reader(b.newCharReader());
Json::String errs; Json::String errs;
Json::Value root; Json::Value root;
char const doc[] = R"({ "property" : "value" })"; char const doc[] = "{ \"property\" : \"value\" }";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT(errs.empty());
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrorsTestingOffsets) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrorsTestingOffsets) {
@ -2883,6 +2900,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrorsTestingOffsets) {
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT(errs.empty());
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseNumber) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseNumber) {
@ -2899,6 +2917,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseNumber) {
JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT(errs.empty());
JSONTEST_ASSERT_EQUAL(1.1111111111111111e+020, root[0]); JSONTEST_ASSERT_EQUAL(1.1111111111111111e+020, root[0]);
} }
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) {
@ -2914,14 +2933,18 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) {
JSONTEST_ASSERT_EQUAL("", root[0]); JSONTEST_ASSERT_EQUAL("", root[0]);
} }
{ {
char const doc[] = R"(["\u8A2a"])"; char const doc[] = "[\"\\u8A2a\"]";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT(errs.empty());
#if JSONCPP_CXX_STD_11
JSONTEST_ASSERT_EQUAL(u8"\u8A2a", root[0].asString()); // "訪" JSONTEST_ASSERT_EQUAL(u8"\u8A2a", root[0].asString()); // "訪"
#else
JSONTEST_ASSERT_EQUAL("\u8A2a", root[0].asString()); // "訪"
#endif // JSONCPP_CXX_STD_11
} }
{ {
char const doc[] = R"([ "\uD801" ])"; char const doc[] = "[ \"\\uD801\" ]";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs == "* Line 1, Column 3\n" JSONTEST_ASSERT(errs == "* Line 1, Column 3\n"
@ -2930,7 +2953,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) {
"See Line 1, Column 10 for detail.\n"); "See Line 1, Column 10 for detail.\n");
} }
{ {
char const doc[] = R"([ "\uD801\d1234" ])"; char const doc[] = "[ \"\\uD801\\d1234\" ]";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs == "* Line 1, Column 3\n" JSONTEST_ASSERT(errs == "* Line 1, Column 3\n"
@ -2939,7 +2962,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) {
"See Line 1, Column 12 for detail.\n"); "See Line 1, Column 12 for detail.\n");
} }
{ {
char const doc[] = R"([ "\ua3t@" ])"; char const doc[] = "[ \"\\ua3t@\" ]";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs == "* Line 1, Column 3\n" JSONTEST_ASSERT(errs == "* Line 1, Column 3\n"
@ -2948,7 +2971,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) {
"See Line 1, Column 9 for detail.\n"); "See Line 1, Column 9 for detail.\n");
} }
{ {
char const doc[] = R"([ "\ua3t" ])"; char const doc[] = "[ \"\\ua3t\" ]";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT( JSONTEST_ASSERT(
@ -2957,16 +2980,18 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) {
" Bad unicode escape sequence in string: four digits expected.\n" " Bad unicode escape sequence in string: four digits expected.\n"
"See Line 1, Column 6 for detail.\n"); "See Line 1, Column 6 for detail.\n");
} }
delete reader;
{ {
b.settings_["allowSingleQuotes"] = true; b.settings_["allowSingleQuotes"] = true;
CharReaderPtr charreader(b.newCharReader()); CharReaderPtr charReader(b.newCharReader());
char const doc[] = R"({'a': 'x\ty', "b":'x\\y'})"; char const doc[] = "{'a': 'x\\ty', \"b\":'x\\\\y'}";
bool ok = charreader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = charReader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs); JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL(2u, root.size()); JSONTEST_ASSERT_EQUAL(2u, root.size());
JSONTEST_ASSERT_STRING_EQUAL("x\ty", root["a"].asString()); JSONTEST_ASSERT_STRING_EQUAL("x\ty", root["a"].asString());
JSONTEST_ASSERT_STRING_EQUAL("x\\y", root["b"].asString()); JSONTEST_ASSERT_STRING_EQUAL("x\\y", root["b"].asString());
delete charReader;
} }
} }
@ -2999,6 +3024,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseComment) {
JSONTEST_ASSERT_EQUAL("value", root[0]); JSONTEST_ASSERT_EQUAL("value", root[0]);
JSONTEST_ASSERT_EQUAL(true, root[1]); JSONTEST_ASSERT_EQUAL(true, root[1]);
} }
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseObjectWithErrors) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseObjectWithErrors) {
@ -3007,7 +3033,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseObjectWithErrors) {
Json::Value root; Json::Value root;
Json::String errs; Json::String errs;
{ {
char const doc[] = R"({ "property" : "value" )"; char const doc[] = "{ \"property\" : \"value\" ";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs == "* Line 1, Column 24\n" JSONTEST_ASSERT(errs == "* Line 1, Column 24\n"
@ -3015,13 +3041,14 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseObjectWithErrors) {
JSONTEST_ASSERT_EQUAL("value", root["property"]); JSONTEST_ASSERT_EQUAL("value", root["property"]);
} }
{ {
char const doc[] = R"({ "property" : "value" ,)"; char const doc[] = "{ \"property\" : \"value\" ,";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs == "* Line 1, Column 25\n" JSONTEST_ASSERT(errs == "* Line 1, Column 25\n"
" Missing '}' or object member name\n"); " Missing '}' or object member name\n");
JSONTEST_ASSERT_EQUAL("value", root["property"]); JSONTEST_ASSERT_EQUAL("value", root["property"]);
} }
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseArrayWithErrors) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseArrayWithErrors) {
@ -3038,13 +3065,14 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseArrayWithErrors) {
JSONTEST_ASSERT_EQUAL("value", root[0]); JSONTEST_ASSERT_EQUAL("value", root[0]);
} }
{ {
char const doc[] = R"([ "value1" "value2" ])"; char const doc[] = "[ \"value1\" \"value2\" ]";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs == "* Line 1, Column 12\n" JSONTEST_ASSERT(errs == "* Line 1, Column 12\n"
" Missing ',' or ']' in array declaration\n"); " Missing ',' or ']' in array declaration\n");
JSONTEST_ASSERT_EQUAL("value1", root[0]); JSONTEST_ASSERT_EQUAL("value1", root[0]);
} }
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithOneError) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithOneError) {
@ -3052,12 +3080,13 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithOneError) {
CharReaderPtr reader(b.newCharReader()); CharReaderPtr reader(b.newCharReader());
Json::String errs; Json::String errs;
Json::Value root; Json::Value root;
char const doc[] = R"({ "property" :: "value" })"; char const doc[] = "{ \"property\" :: \"value\" }";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs == JSONTEST_ASSERT(errs ==
"* Line 1, Column 15\n Syntax error: value, object or array " "* Line 1, Column 15\n Syntax error: value, object or array "
"expected.\n"); "expected.\n");
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseChineseWithOneError) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseChineseWithOneError) {
@ -3071,6 +3100,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseChineseWithOneError) {
JSONTEST_ASSERT(errs == JSONTEST_ASSERT(errs ==
"* Line 1, Column 19\n Syntax error: value, object or array " "* Line 1, Column 19\n Syntax error: value, object or array "
"expected.\n"); "expected.\n");
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithDetailError) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithDetailError) {
@ -3078,18 +3108,19 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithDetailError) {
CharReaderPtr reader(b.newCharReader()); CharReaderPtr reader(b.newCharReader());
Json::String errs; Json::String errs;
Json::Value root; Json::Value root;
char const doc[] = R"({ "property" : "v\alue" })"; char const doc[] = "{ \"property\" : \"v\\alue\" }";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs == JSONTEST_ASSERT(errs ==
"* Line 1, Column 16\n Bad escape sequence in string\nSee " "* Line 1, Column 16\n Bad escape sequence in string\nSee "
"Line 1, Column 20 for detail.\n"); "Line 1, Column 20 for detail.\n");
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) {
Json::CharReaderBuilder b; Json::CharReaderBuilder b;
Json::Value root; Json::Value root;
char const doc[] = R"({ "property" : "value" })"; char const doc[] = "{ \"property\" : \"value\" }";
{ {
b.settings_["stackLimit"] = 2; b.settings_["stackLimit"] = 2;
CharReaderPtr reader(b.newCharReader()); CharReaderPtr reader(b.newCharReader());
@ -3098,6 +3129,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) {
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT(errs.empty());
JSONTEST_ASSERT_EQUAL("value", root["property"]); JSONTEST_ASSERT_EQUAL("value", root["property"]);
delete reader;
} }
{ {
b.settings_["stackLimit"] = 1; b.settings_["stackLimit"] = 1;
@ -3105,11 +3137,12 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) {
Json::String errs; Json::String errs;
JSONTEST_ASSERT_THROWS( JSONTEST_ASSERT_THROWS(
reader->parse(doc, doc + std::strlen(doc), &root, &errs)); reader->parse(doc, doc + std::strlen(doc), &root, &errs));
delete reader;
} }
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, testOperator) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, testOperator) {
const std::string styled = R"({ "property" : "value" })"; const std::string styled = "{ \"property\" : \"value\" }";
std::istringstream iss(styled); std::istringstream iss(styled);
Json::Value root; Json::Value root;
iss >> root; iss >> root;
@ -3122,7 +3155,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderStrictModeTest, dupKeys) {
Json::CharReaderBuilder b; Json::CharReaderBuilder b;
Json::Value root; Json::Value root;
char const doc[] = char const doc[] =
R"({ "property" : "value", "key" : "val1", "key" : "val2" })"; "{ \"property\" : \"value\", \"key\" : \"val1\", \"key\" : \"val2\" }";
{ {
b.strictMode(&b.settings_); b.strictMode(&b.settings_);
CharReaderPtr reader(b.newCharReader()); CharReaderPtr reader(b.newCharReader());
@ -3133,6 +3166,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderStrictModeTest, dupKeys) {
" Duplicate key: 'key'\n", " Duplicate key: 'key'\n",
errs); errs);
JSONTEST_ASSERT_EQUAL("val1", root["key"]); // so far JSONTEST_ASSERT_EQUAL("val1", root["key"]); // so far
delete reader;
} }
} }
struct CharReaderFailIfExtraTest : JsonTest::TestCase {}; struct CharReaderFailIfExtraTest : JsonTest::TestCase {};
@ -3141,7 +3175,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue164) {
// This is interpreted as a string value followed by a colon. // This is interpreted as a string value followed by a colon.
Json::CharReaderBuilder b; Json::CharReaderBuilder b;
Json::Value root; Json::Value root;
char const doc[] = R"( "property" : "value" })"; char const doc[] = " \"property\" : \"value\" }";
{ {
b.settings_["failIfExtra"] = false; b.settings_["failIfExtra"] = false;
CharReaderPtr reader(b.newCharReader()); CharReaderPtr reader(b.newCharReader());
@ -3150,6 +3184,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue164) {
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT(errs.empty());
JSONTEST_ASSERT_EQUAL("property", root); JSONTEST_ASSERT_EQUAL("property", root);
delete reader;
} }
{ {
b.settings_["failIfExtra"] = true; b.settings_["failIfExtra"] = true;
@ -3161,6 +3196,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue164) {
" Extra non-whitespace after JSON value.\n", " Extra non-whitespace after JSON value.\n",
errs); errs);
JSONTEST_ASSERT_EQUAL("property", root); JSONTEST_ASSERT_EQUAL("property", root);
delete reader;
} }
{ {
b.strictMode(&b.settings_); b.strictMode(&b.settings_);
@ -3172,6 +3208,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue164) {
" Extra non-whitespace after JSON value.\n", " Extra non-whitespace after JSON value.\n",
errs); errs);
JSONTEST_ASSERT_EQUAL("property", root); JSONTEST_ASSERT_EQUAL("property", root);
delete reader;
} }
{ {
b.strictMode(&b.settings_); b.strictMode(&b.settings_);
@ -3185,6 +3222,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue164) {
" A valid JSON document must be either an array or an object value.\n", " A valid JSON document must be either an array or an object value.\n",
errs); errs);
JSONTEST_ASSERT_EQUAL("property", root); JSONTEST_ASSERT_EQUAL("property", root);
delete reader;
} }
} }
@ -3202,6 +3240,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue107) {
" Extra non-whitespace after JSON value.\n", " Extra non-whitespace after JSON value.\n",
errs); errs);
JSONTEST_ASSERT_EQUAL(1, root.asInt()); JSONTEST_ASSERT_EQUAL(1, root.asInt());
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterObject) { JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterObject) {
Json::CharReaderBuilder b; Json::CharReaderBuilder b;
@ -3215,6 +3254,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterObject) {
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs); JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL("value", root["property"]); JSONTEST_ASSERT_EQUAL("value", root["property"]);
delete reader;
} }
} }
JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterArray) { JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterArray) {
@ -3228,6 +3268,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterArray) {
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs); JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL("value", root[1u]); JSONTEST_ASSERT_EQUAL("value", root[1u]);
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterBool) { JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterBool) {
Json::CharReaderBuilder b; Json::CharReaderBuilder b;
@ -3240,6 +3281,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterBool) {
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs); JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL(true, root.asBool()); JSONTEST_ASSERT_EQUAL(true, root.asBool());
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, parseComment) { JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, parseComment) {
@ -3273,11 +3315,12 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, parseComment) {
errs); errs);
JSONTEST_ASSERT_EQUAL(true, root.asBool()); JSONTEST_ASSERT_EQUAL(true, root.asBool());
} }
delete reader;
} }
#if JSONCPP_CXX_STD_11
struct CharReaderAllowDropNullTest : JsonTest::TestCase { struct CharReaderAllowDropNullTest : JsonTest::TestCase {
using Value = Json::Value; typedef Json::Value Value;
using ValueCheck = std::function<void(const Value&)>; typedef std::function<void(const Value&)> ValueCheck;
Value nullValue = Value{Json::nullValue}; Value nullValue = Value{Json::nullValue};
Value emptyArray = Value{Json::arrayValue}; Value emptyArray = Value{Json::arrayValue};
@ -3303,19 +3346,19 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowDropNullTest, issue178) {
ValueCheck onRoot; ValueCheck onRoot;
}; };
const TestSpec specs[] = { const TestSpec specs[] = {
{__LINE__, R"({"a":,"b":true})", 2, objGetAnd("a", checkEq(nullValue))}, {__LINE__, "{\"a\":,\"b\":true}", 2, objGetAnd("a", checkEq(nullValue))},
{__LINE__, R"({"a":,"b":true})", 2, objGetAnd("a", checkEq(nullValue))}, {__LINE__, "{\"a\":,\"b\":true}", 2, objGetAnd("a", checkEq(nullValue))},
{__LINE__, R"({"a":})", 1, objGetAnd("a", checkEq(nullValue))}, {__LINE__, "{\"a\":}", 1, objGetAnd("a", checkEq(nullValue))},
{__LINE__, "[]", 0, checkEq(emptyArray)}, {__LINE__, "[]", 0, checkEq(emptyArray)},
{__LINE__, "[null]", 1, nullptr}, {__LINE__, "[null]", 1, JSONCPP_NULL},
{__LINE__, "[,]", 2, nullptr}, {__LINE__, "[,]", 2, JSONCPP_NULL},
{__LINE__, "[,,,]", 4, nullptr}, {__LINE__, "[,,,]", 4, JSONCPP_NULL},
{__LINE__, "[null,]", 2, nullptr}, {__LINE__, "[null,]", 2, JSONCPP_NULL},
{__LINE__, "[,null]", 2, nullptr}, {__LINE__, "[,null]", 2, JSONCPP_NULL},
{__LINE__, "[,,]", 3, nullptr}, {__LINE__, "[,,]", 3, JSONCPP_NULL},
{__LINE__, "[null,,]", 3, nullptr}, {__LINE__, "[null,,]", 3, JSONCPP_NULL},
{__LINE__, "[,null,]", 3, nullptr}, {__LINE__, "[,null,]", 3, JSONCPP_NULL},
{__LINE__, "[,,null]", 3, nullptr}, {__LINE__, "[,,null]", 3, JSONCPP_NULL},
{__LINE__, "[[],,,]", 4, arrGetAnd(0, checkEq(emptyArray))}, {__LINE__, "[[],,,]", 4, arrGetAnd(0, checkEq(emptyArray))},
{__LINE__, "[,[],,]", 4, arrGetAnd(1, checkEq(emptyArray))}, {__LINE__, "[,[],,]", 4, arrGetAnd(1, checkEq(emptyArray))},
{__LINE__, "[,,,[]]", 4, arrGetAnd(3, checkEq(emptyArray))}, {__LINE__, "[,,,[]]", 4, arrGetAnd(3, checkEq(emptyArray))},
@ -3336,7 +3379,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowDropNullTest, issue178) {
} }
} }
} }
#endif // JSONCPP_CXX_STD_11
struct CharReaderAllowNumericKeysTest : JsonTest::TestCase {}; struct CharReaderAllowNumericKeysTest : JsonTest::TestCase {};
JSONTEST_FIXTURE_LOCAL(CharReaderAllowNumericKeysTest, allowNumericKeys) { JSONTEST_FIXTURE_LOCAL(CharReaderAllowNumericKeysTest, allowNumericKeys) {
@ -3353,6 +3396,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowNumericKeysTest, allowNumericKeys) {
JSONTEST_ASSERT_EQUAL(true, root.get("15", false)); JSONTEST_ASSERT_EQUAL(true, root.get("15", false));
JSONTEST_ASSERT_EQUAL(true, root.get("-16", false)); JSONTEST_ASSERT_EQUAL(true, root.get("-16", false));
JSONTEST_ASSERT_EQUAL(true, root.get("12.01", false)); JSONTEST_ASSERT_EQUAL(true, root.get("12.01", false));
delete reader;
} }
struct CharReaderAllowSingleQuotesTest : JsonTest::TestCase {}; struct CharReaderAllowSingleQuotesTest : JsonTest::TestCase {};
@ -3381,6 +3425,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSingleQuotesTest, issue182) {
JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString()); JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString());
JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString()); JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString());
} }
delete reader;
} }
struct CharReaderAllowZeroesTest : JsonTest::TestCase {}; struct CharReaderAllowZeroesTest : JsonTest::TestCase {};
@ -3409,6 +3454,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowZeroesTest, issue176) {
JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString()); JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString());
JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString()); JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString());
} }
delete reader;
} }
struct CharReaderAllowSpecialFloatsTest : JsonTest::TestCase {}; struct CharReaderAllowSpecialFloatsTest : JsonTest::TestCase {};
@ -3436,6 +3482,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, specialFloat) {
" Syntax error: value, object or array expected.\n", " Syntax error: value, object or array expected.\n",
errs); errs);
} }
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) { JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) {
@ -3445,7 +3492,8 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) {
Json::String errs; Json::String errs;
CharReaderPtr reader(b.newCharReader()); CharReaderPtr reader(b.newCharReader());
{ {
char const doc[] = R"({"a":NaN,"b":Infinity,"c":-Infinity,"d":+Infinity})"; char const doc[] =
"{\"a\":NaN,\"b\":Infinity,\"c\":-Infinity,\"d\":+Infinity}";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs); JSONTEST_ASSERT_STRING_EQUAL("", errs);
@ -3484,7 +3532,9 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) {
{__LINE__, true, "{\"a\":-Infinity}"}, // {__LINE__, true, "{\"a\":-Infinity}"}, //
{__LINE__, true, "{\"a\":+Infinity}"} // {__LINE__, true, "{\"a\":+Infinity}"} //
}; };
for (const auto& td : test_data) { for (unsigned int index = 0; index < sizeof(test_data) / sizeof(test_data[0]);
++index) {
const struct TestData td = test_data[index];
bool ok = reader->parse(&*td.in.begin(), &*td.in.begin() + td.in.size(), bool ok = reader->parse(&*td.in.begin(), &*td.in.begin() + td.in.size(),
&root, &errs); &root, &errs);
JSONTEST_ASSERT(td.ok == ok) << "line:" << td.line << "\n" JSONTEST_ASSERT(td.ok == ok) << "line:" << td.line << "\n"
@ -3496,7 +3546,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) {
} }
{ {
char const doc[] = R"({"posInf": +Infinity, "NegInf": -Infinity})"; char const doc[] = "{\"posInf\": +Infinity, \"NegInf\": -Infinity}";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs); JSONTEST_ASSERT_STRING_EQUAL("", errs);
@ -3506,6 +3556,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) {
JSONTEST_ASSERT_EQUAL(-std::numeric_limits<double>::infinity(), JSONTEST_ASSERT_EQUAL(-std::numeric_limits<double>::infinity(),
root["NegInf"].asDouble()); root["NegInf"].asDouble());
} }
delete reader;
} }
struct EscapeSequenceTest : JsonTest::TestCase {}; struct EscapeSequenceTest : JsonTest::TestCase {};
@ -3533,6 +3584,7 @@ JSONTEST_FIXTURE_LOCAL(EscapeSequenceTest, charReaderParseEscapeSequence) {
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT(errs.empty());
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(EscapeSequenceTest, writeEscapeSequence) { JSONTEST_FIXTURE_LOCAL(EscapeSequenceTest, writeEscapeSequence) {
@ -3608,7 +3660,7 @@ struct IteratorTest : JsonTest::TestCase {};
JSONTEST_FIXTURE_LOCAL(IteratorTest, convert) { JSONTEST_FIXTURE_LOCAL(IteratorTest, convert) {
Json::Value j; Json::Value j;
const Json::Value& cj = j; const Json::Value& cj = j;
auto it = j.begin(); Json::Value::const_iterator it = j.begin();
Json::Value::const_iterator cit; Json::Value::const_iterator cit;
cit = it; cit = it;
JSONTEST_ASSERT(cit == cj.begin()); JSONTEST_ASSERT(cit == cj.begin());
@ -3619,11 +3671,17 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, decrement) {
json["k1"] = "a"; json["k1"] = "a";
json["k2"] = "b"; json["k2"] = "b";
std::vector<std::string> values; std::vector<std::string> values;
for (auto it = json.end(); it != json.begin();) { std::vector<std::string> expected;
expected.push_back("b");
expected.push_back("a");
for (Json::Value::const_iterator it = json.end(); it != json.begin();) {
--it; --it;
values.push_back(it->asString()); values.push_back(it->asString());
} }
JSONTEST_ASSERT((values == std::vector<std::string>{"b", "a"})); JSONTEST_ASSERT(values.size() == expected.size());
for (unsigned int i = 0; i < expected.size(); i++) {
JSONTEST_ASSERT(values.at(i) == expected.at(i));
}
} }
JSONTEST_FIXTURE_LOCAL(IteratorTest, reverseIterator) { JSONTEST_FIXTURE_LOCAL(IteratorTest, reverseIterator) {
@ -3631,12 +3689,19 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, reverseIterator) {
json["k1"] = "a"; json["k1"] = "a";
json["k2"] = "b"; json["k2"] = "b";
std::vector<std::string> values; std::vector<std::string> values;
using Iter = decltype(json.begin()); typedef Json::Value::const_iterator Iter;
auto re = std::reverse_iterator<Iter>(json.begin()); std::reverse_iterator<Iter> re = std::reverse_iterator<Iter>(json.begin());
for (auto it = std::reverse_iterator<Iter>(json.end()); it != re; ++it) { for (std::reverse_iterator<Iter> it = std::reverse_iterator<Iter>(json.end());
it != re; ++it) {
values.push_back(it->asString()); values.push_back(it->asString());
} }
JSONTEST_ASSERT((values == std::vector<std::string>{"b", "a"})); std::vector<std::string> expected;
expected.push_back("b");
expected.push_back("a");
JSONTEST_ASSERT(values.size() == expected.size());
for (unsigned int i = 0; i < expected.size(); i++) {
JSONTEST_ASSERT(values.at(i) == expected.at(i));
}
} }
JSONTEST_FIXTURE_LOCAL(IteratorTest, distance) { JSONTEST_FIXTURE_LOCAL(IteratorTest, distance) {
@ -3645,9 +3710,9 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, distance) {
json["k1"] = "a"; json["k1"] = "a";
json["k2"] = "b"; json["k2"] = "b";
int i = 0; int i = 0;
auto it = json.begin(); Json::Value::const_iterator it = json.begin();
for (;; ++it, ++i) { for (;; ++it, ++i) {
auto dist = it - json.begin(); Json::ValueIteratorBase::difference_type dist = it - json.begin();
JSONTEST_ASSERT_EQUAL(i, dist); JSONTEST_ASSERT_EQUAL(i, dist);
if (it == json.end()) if (it == json.end())
break; break;
@ -3663,8 +3728,8 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, distance) {
JSONTEST_FIXTURE_LOCAL(IteratorTest, nullValues) { JSONTEST_FIXTURE_LOCAL(IteratorTest, nullValues) {
{ {
Json::Value json; Json::Value json;
auto end = json.end(); Json::Value::const_iterator end = json.end();
auto endCopy = end; Json::Value::const_iterator endCopy = end;
JSONTEST_ASSERT(endCopy == end); JSONTEST_ASSERT(endCopy == end);
endCopy = end; endCopy = end;
JSONTEST_ASSERT(endCopy == end); JSONTEST_ASSERT(endCopy == end);
@ -3672,8 +3737,8 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, nullValues) {
{ {
// Same test, now with const Value. // Same test, now with const Value.
const Json::Value json; const Json::Value json;
auto end = json.end(); Json::Value::const_iterator end = json.end();
auto endCopy = end; Json::Value::const_iterator endCopy = end;
JSONTEST_ASSERT(endCopy == end); JSONTEST_ASSERT(endCopy == end);
endCopy = end; endCopy = end;
JSONTEST_ASSERT(endCopy == end); JSONTEST_ASSERT(endCopy == end);
@ -3744,10 +3809,10 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, constness) {
for (; iter != value.end(); ++iter) { for (; iter != value.end(); ++iter) {
out << *iter << ','; out << *iter << ',';
} }
Json::String expected = R"(" 9","10","11",)"; Json::String expected = "\" 9\",\"10\",\"11\",";
JSONTEST_ASSERT_STRING_EQUAL(expected, out.str()); JSONTEST_ASSERT_STRING_EQUAL(expected, out.str());
} }
#if JSONCPP_CXX_STD_11
struct RValueTest : JsonTest::TestCase {}; struct RValueTest : JsonTest::TestCase {};
JSONTEST_FIXTURE_LOCAL(RValueTest, moveConstruction) { JSONTEST_FIXTURE_LOCAL(RValueTest, moveConstruction) {
@ -3759,7 +3824,7 @@ JSONTEST_FIXTURE_LOCAL(RValueTest, moveConstruction) {
JSONTEST_ASSERT_EQUAL(Json::objectValue, moved.type()); JSONTEST_ASSERT_EQUAL(Json::objectValue, moved.type());
JSONTEST_ASSERT_EQUAL(Json::stringValue, moved["key"].type()); JSONTEST_ASSERT_EQUAL(Json::stringValue, moved["key"].type());
} }
#endif // JSONCPP_CXX_STD_11
struct FuzzTest : JsonTest::TestCase {}; struct FuzzTest : JsonTest::TestCase {};
// Build and run the fuzz test without any fuzzer, so that it's guaranteed not // Build and run the fuzz test without any fuzzer, so that it's guaranteed not
@ -3775,13 +3840,14 @@ JSONTEST_FIXTURE_LOCAL(FuzzTest, fuzzDoesntCrash) {
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
JsonTest::Runner runner; JsonTest::Runner runner;
for (auto& local : local_) { for (unsigned int index = 0; index < local_.size(); ++index) {
JsonTest::TestCaseFactory local = local_[index];
runner.add(local); runner.add(local);
} }
return runner.runCommandLine(argc, argv); return runner.runCommandLine(argc, argv);
} }
#if JSONCPP_CXX_STD_11
struct MemberTemplateAs : JsonTest::TestCase { struct MemberTemplateAs : JsonTest::TestCase {
template <typename T, typename F> template <typename T, typename F>
JsonTest::TestResult& EqEval(T v, F f) const { JsonTest::TestResult& EqEval(T v, F f) const {
@ -3810,12 +3876,13 @@ JSONTEST_FIXTURE_LOCAL(MemberTemplateAs, BehavesSameAsNamedAs) {
EqEval(false, [](const Json::Value& j) { return j.asBool(); }); EqEval(false, [](const Json::Value& j) { return j.asBool(); });
EqEval(true, [](const Json::Value& j) { return j.asBool(); }); EqEval(true, [](const Json::Value& j) { return j.asBool(); });
} }
#endif // JSONCPP_CXX_STD_11
class MemberTemplateIs : public JsonTest::TestCase {}; class MemberTemplateIs : public JsonTest::TestCase {};
JSONTEST_FIXTURE_LOCAL(MemberTemplateIs, BehavesSameAsNamedIs) { JSONTEST_FIXTURE_LOCAL(MemberTemplateIs, BehavesSameAsNamedIs) {
const Json::Value values[] = {true, 142, 40.63, "hello world"}; const Json::Value values[] = {true, 142, 40.63, "hello world"};
for (const Json::Value& j : values) { for (size_t index = 0; index < sizeof(values) / sizeof(values[0]); index++) {
const Json::Value& j = values[index];
JSONTEST_ASSERT_EQUAL(j.is<bool>(), j.isBool()); JSONTEST_ASSERT_EQUAL(j.is<bool>(), j.isBool());
JSONTEST_ASSERT_EQUAL(j.is<Json::Int>(), j.isInt()); JSONTEST_ASSERT_EQUAL(j.is<Json::Int>(), j.isInt());
JSONTEST_ASSERT_EQUAL(j.is<Json::Int64>(), j.isInt64()); JSONTEST_ASSERT_EQUAL(j.is<Json::Int64>(), j.isInt64());