mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
Update jsoncpp copy to 1.9.6
note: the version number is different due to https://github.com/open-source-parsers/jsoncpp/issues/1571
This commit is contained in:
parent
cbc741f464
commit
dbbe0ca065
4 changed files with 278 additions and 146 deletions
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
cd ..
|
cd ..
|
||||||
git clone https://github.com/open-source-parsers/jsoncpp -b 1.9.5 --depth 1
|
git clone https://github.com/open-source-parsers/jsoncpp -b 1.9.6 --depth 1
|
||||||
cd jsoncpp
|
cd jsoncpp
|
||||||
./amalgamate.py
|
./amalgamate.py
|
||||||
cp -R dist/json ../json
|
cp -R dist/json ../json
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/// Json-cpp amalgamated forward header (http://jsoncpp.sourceforge.net/).
|
/// Json-cpp amalgamated forward header (https://github.com/open-source-parsers/jsoncpp/).
|
||||||
/// It is intended to be used with #include "json/json-forwards.h"
|
/// It is intended to be used with #include "json/json-forwards.h"
|
||||||
/// This header provides forward declaration for all JsonCpp types.
|
/// This header provides forward declaration for all JsonCpp types.
|
||||||
|
|
||||||
|
@ -94,19 +94,18 @@ license you like.
|
||||||
// 3. /CMakeLists.txt
|
// 3. /CMakeLists.txt
|
||||||
// IMPORTANT: also update the SOVERSION!!
|
// IMPORTANT: also update the SOVERSION!!
|
||||||
|
|
||||||
#define JSONCPP_VERSION_STRING "1.9.5"
|
#define JSONCPP_VERSION_STRING "1.9.7"
|
||||||
#define JSONCPP_VERSION_MAJOR 1
|
#define JSONCPP_VERSION_MAJOR 1
|
||||||
#define JSONCPP_VERSION_MINOR 9
|
#define JSONCPP_VERSION_MINOR 9
|
||||||
#define JSONCPP_VERSION_PATCH 5
|
#define JSONCPP_VERSION_PATCH 7
|
||||||
#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) | \
|
||||||
(JSONCPP_VERSION_PATCH << 8))
|
(JSONCPP_VERSION_PATCH << 8))
|
||||||
|
|
||||||
#ifdef JSONCPP_USING_SECURE_MEMORY
|
#if !defined(JSONCPP_USE_SECURE_MEMORY)
|
||||||
#undef JSONCPP_USING_SECURE_MEMORY
|
#define JSONCPP_USE_SECURE_MEMORY 0
|
||||||
#endif
|
#endif
|
||||||
#define JSONCPP_USING_SECURE_MEMORY 0
|
|
||||||
// If non-zero, the library zeroes any memory that it has allocated before
|
// If non-zero, the library zeroes any memory that it has allocated before
|
||||||
// it frees its memory.
|
// it frees its memory.
|
||||||
|
|
||||||
|
@ -133,10 +132,12 @@ license you like.
|
||||||
#ifndef JSON_ALLOCATOR_H_INCLUDED
|
#ifndef JSON_ALLOCATOR_H_INCLUDED
|
||||||
#define JSON_ALLOCATOR_H_INCLUDED
|
#define JSON_ALLOCATOR_H_INCLUDED
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#pragma pack(push, 8)
|
#pragma pack(push)
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
template <typename T> class SecureAllocator {
|
template <typename T> class SecureAllocator {
|
||||||
|
@ -164,8 +165,16 @@ public:
|
||||||
* The memory block is filled with zeroes before being released.
|
* The memory block is filled with zeroes before being released.
|
||||||
*/
|
*/
|
||||||
void deallocate(pointer p, size_type n) {
|
void deallocate(pointer p, size_type n) {
|
||||||
// memset_s is used because memset may be optimized away by the compiler
|
// These constructs will not be removed by the compiler during optimization,
|
||||||
|
// unlike memset.
|
||||||
|
#if defined(HAVE_MEMSET_S)
|
||||||
memset_s(p, n * sizeof(T), 0, n * sizeof(T));
|
memset_s(p, n * sizeof(T), 0, n * sizeof(T));
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
RtlSecureZeroMemory(p, n * sizeof(T));
|
||||||
|
#else
|
||||||
|
std::fill_n(reinterpret_cast<volatile unsigned char*>(p), n, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
// free using "global operator delete"
|
// free using "global operator delete"
|
||||||
::operator delete(p);
|
::operator delete(p);
|
||||||
}
|
}
|
||||||
|
@ -195,7 +204,9 @@ public:
|
||||||
// Boilerplate
|
// Boilerplate
|
||||||
SecureAllocator() {}
|
SecureAllocator() {}
|
||||||
template <typename U> SecureAllocator(const SecureAllocator<U>&) {}
|
template <typename U> SecureAllocator(const SecureAllocator<U>&) {}
|
||||||
template <typename U> struct rebind { using other = SecureAllocator<U>; };
|
template <typename U> struct rebind {
|
||||||
|
using other = SecureAllocator<U>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
|
@ -356,7 +367,7 @@ using LargestUInt = UInt64;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using Allocator =
|
using Allocator =
|
||||||
typename std::conditional<JSONCPP_USING_SECURE_MEMORY, SecureAllocator<T>,
|
typename std::conditional<JSONCPP_USE_SECURE_MEMORY, SecureAllocator<T>,
|
||||||
std::allocator<T>>::type;
|
std::allocator<T>>::type;
|
||||||
using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
|
using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
|
||||||
using IStringStream =
|
using IStringStream =
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/// Json-cpp amalgamated header (http://jsoncpp.sourceforge.net/).
|
/// Json-cpp amalgamated header (https://github.com/open-source-parsers/jsoncpp/).
|
||||||
/// It is intended to be used with #include "json/json.h"
|
/// It is intended to be used with #include "json/json.h"
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////////
|
||||||
|
@ -93,19 +93,18 @@ license you like.
|
||||||
// 3. /CMakeLists.txt
|
// 3. /CMakeLists.txt
|
||||||
// IMPORTANT: also update the SOVERSION!!
|
// IMPORTANT: also update the SOVERSION!!
|
||||||
|
|
||||||
#define JSONCPP_VERSION_STRING "1.9.5"
|
#define JSONCPP_VERSION_STRING "1.9.7"
|
||||||
#define JSONCPP_VERSION_MAJOR 1
|
#define JSONCPP_VERSION_MAJOR 1
|
||||||
#define JSONCPP_VERSION_MINOR 9
|
#define JSONCPP_VERSION_MINOR 9
|
||||||
#define JSONCPP_VERSION_PATCH 5
|
#define JSONCPP_VERSION_PATCH 7
|
||||||
#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) | \
|
||||||
(JSONCPP_VERSION_PATCH << 8))
|
(JSONCPP_VERSION_PATCH << 8))
|
||||||
|
|
||||||
#ifdef JSONCPP_USING_SECURE_MEMORY
|
#if !defined(JSONCPP_USE_SECURE_MEMORY)
|
||||||
#undef JSONCPP_USING_SECURE_MEMORY
|
#define JSONCPP_USE_SECURE_MEMORY 0
|
||||||
#endif
|
#endif
|
||||||
#define JSONCPP_USING_SECURE_MEMORY 0
|
|
||||||
// If non-zero, the library zeroes any memory that it has allocated before
|
// If non-zero, the library zeroes any memory that it has allocated before
|
||||||
// it frees its memory.
|
// it frees its memory.
|
||||||
|
|
||||||
|
@ -132,10 +131,12 @@ license you like.
|
||||||
#ifndef JSON_ALLOCATOR_H_INCLUDED
|
#ifndef JSON_ALLOCATOR_H_INCLUDED
|
||||||
#define JSON_ALLOCATOR_H_INCLUDED
|
#define JSON_ALLOCATOR_H_INCLUDED
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#pragma pack(push, 8)
|
#pragma pack(push)
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
template <typename T> class SecureAllocator {
|
template <typename T> class SecureAllocator {
|
||||||
|
@ -163,8 +164,16 @@ public:
|
||||||
* The memory block is filled with zeroes before being released.
|
* The memory block is filled with zeroes before being released.
|
||||||
*/
|
*/
|
||||||
void deallocate(pointer p, size_type n) {
|
void deallocate(pointer p, size_type n) {
|
||||||
// memset_s is used because memset may be optimized away by the compiler
|
// These constructs will not be removed by the compiler during optimization,
|
||||||
|
// unlike memset.
|
||||||
|
#if defined(HAVE_MEMSET_S)
|
||||||
memset_s(p, n * sizeof(T), 0, n * sizeof(T));
|
memset_s(p, n * sizeof(T), 0, n * sizeof(T));
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
RtlSecureZeroMemory(p, n * sizeof(T));
|
||||||
|
#else
|
||||||
|
std::fill_n(reinterpret_cast<volatile unsigned char*>(p), n, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
// free using "global operator delete"
|
// free using "global operator delete"
|
||||||
::operator delete(p);
|
::operator delete(p);
|
||||||
}
|
}
|
||||||
|
@ -194,7 +203,9 @@ public:
|
||||||
// Boilerplate
|
// Boilerplate
|
||||||
SecureAllocator() {}
|
SecureAllocator() {}
|
||||||
template <typename U> SecureAllocator(const SecureAllocator<U>&) {}
|
template <typename U> SecureAllocator(const SecureAllocator<U>&) {}
|
||||||
template <typename U> struct rebind { using other = SecureAllocator<U>; };
|
template <typename U> struct rebind {
|
||||||
|
using other = SecureAllocator<U>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
|
@ -355,7 +366,7 @@ using LargestUInt = UInt64;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using Allocator =
|
using Allocator =
|
||||||
typename std::conditional<JSONCPP_USING_SECURE_MEMORY, SecureAllocator<T>,
|
typename std::conditional<JSONCPP_USE_SECURE_MEMORY, SecureAllocator<T>,
|
||||||
std::allocator<T>>::type;
|
std::allocator<T>>::type;
|
||||||
using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
|
using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
|
||||||
using IStringStream =
|
using IStringStream =
|
||||||
|
@ -459,7 +470,8 @@ class ValueConstIterator;
|
||||||
#include "forwards.h"
|
#include "forwards.h"
|
||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
|
||||||
#pragma pack(push, 8)
|
#pragma pack(push)
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
|
@ -527,8 +539,8 @@ public:
|
||||||
// recognized in your jurisdiction.
|
// recognized in your jurisdiction.
|
||||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
#ifndef JSON_H_INCLUDED
|
#ifndef JSON_VALUE_H_INCLUDED
|
||||||
#define JSON_H_INCLUDED
|
#define JSON_VALUE_H_INCLUDED
|
||||||
|
|
||||||
#if !defined(JSON_IS_AMALGAMATION)
|
#if !defined(JSON_IS_AMALGAMATION)
|
||||||
#include "forwards.h"
|
#include "forwards.h"
|
||||||
|
@ -577,7 +589,8 @@ public:
|
||||||
#pragma warning(disable : 4251 4275)
|
#pragma warning(disable : 4251 4275)
|
||||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
|
|
||||||
#pragma pack(push, 8)
|
#pragma pack(push)
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
/** \brief JSON (JavaScript Object Notation).
|
/** \brief JSON (JavaScript Object Notation).
|
||||||
*/
|
*/
|
||||||
|
@ -898,7 +911,7 @@ public:
|
||||||
int compare(const Value& other) const;
|
int compare(const Value& other) const;
|
||||||
|
|
||||||
const char* asCString() const; ///< Embedded zeroes could cause you trouble!
|
const char* asCString() const; ///< Embedded zeroes could cause you trouble!
|
||||||
#if JSONCPP_USING_SECURE_MEMORY
|
#if JSONCPP_USE_SECURE_MEMORY
|
||||||
unsigned getCStringLength() const; // Allows you to understand the length of
|
unsigned getCStringLength() const; // Allows you to understand the length of
|
||||||
// the CString
|
// the CString
|
||||||
#endif
|
#endif
|
||||||
|
@ -960,7 +973,7 @@ public:
|
||||||
/// \post type() is arrayValue
|
/// \post type() is arrayValue
|
||||||
void resize(ArrayIndex newSize);
|
void resize(ArrayIndex newSize);
|
||||||
|
|
||||||
//@{
|
///@{
|
||||||
/// Access an array element (zero based index). If the array contains less
|
/// Access an array element (zero based index). If the array contains less
|
||||||
/// than index element, then null value are inserted in the array so that
|
/// than index element, then null value are inserted in the array so that
|
||||||
/// its size is index+1.
|
/// its size is index+1.
|
||||||
|
@ -968,15 +981,15 @@ public:
|
||||||
/// this from the operator[] which takes a string.)
|
/// this from the operator[] which takes a string.)
|
||||||
Value& operator[](ArrayIndex index);
|
Value& operator[](ArrayIndex index);
|
||||||
Value& operator[](int index);
|
Value& operator[](int index);
|
||||||
//@}
|
///@}
|
||||||
|
|
||||||
//@{
|
///@{
|
||||||
/// Access an array element (zero based index).
|
/// Access an array element (zero based index).
|
||||||
/// (You may need to say 'value[0u]' to get your compiler to distinguish
|
/// (You may need to say 'value[0u]' to get your compiler to distinguish
|
||||||
/// this from the operator[] which takes a string.)
|
/// this from the operator[] which takes a string.)
|
||||||
const Value& operator[](ArrayIndex index) const;
|
const Value& operator[](ArrayIndex index) const;
|
||||||
const Value& operator[](int index) const;
|
const Value& operator[](int index) const;
|
||||||
//@}
|
///@}
|
||||||
|
|
||||||
/// If the array contains at least index+1 elements, returns the element
|
/// If the array contains at least index+1 elements, returns the element
|
||||||
/// value, otherwise returns defaultValue.
|
/// value, otherwise returns defaultValue.
|
||||||
|
@ -1036,6 +1049,9 @@ public:
|
||||||
/// and operator[]const
|
/// and operator[]const
|
||||||
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
|
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
|
||||||
Value const* find(char const* begin, char const* end) const;
|
Value const* find(char const* begin, char const* end) const;
|
||||||
|
/// Most general and efficient version of isMember()const, get()const,
|
||||||
|
/// and operator[]const
|
||||||
|
Value const* find(const String& key) const;
|
||||||
/// Most general and efficient version of object-mutators.
|
/// Most general and efficient version of object-mutators.
|
||||||
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
|
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
|
||||||
/// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
|
/// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
|
||||||
|
@ -1108,6 +1124,26 @@ public:
|
||||||
iterator begin();
|
iterator begin();
|
||||||
iterator end();
|
iterator end();
|
||||||
|
|
||||||
|
/// \brief Returns a reference to the first element in the `Value`.
|
||||||
|
/// Requires that this value holds an array or json object, with at least one
|
||||||
|
/// element.
|
||||||
|
const Value& front() const;
|
||||||
|
|
||||||
|
/// \brief Returns a reference to the first element in the `Value`.
|
||||||
|
/// Requires that this value holds an array or json object, with at least one
|
||||||
|
/// element.
|
||||||
|
Value& front();
|
||||||
|
|
||||||
|
/// \brief Returns a reference to the last element in the `Value`.
|
||||||
|
/// Requires that value holds an array or json object, with at least one
|
||||||
|
/// element.
|
||||||
|
const Value& back() const;
|
||||||
|
|
||||||
|
/// \brief Returns a reference to the last element in the `Value`.
|
||||||
|
/// Requires that this value holds an array or json object, with at least one
|
||||||
|
/// element.
|
||||||
|
Value& back();
|
||||||
|
|
||||||
// Accessors for the [start, limit) range of bytes within the JSON text from
|
// Accessors for the [start, limit) range of bytes within the JSON text from
|
||||||
// which this value was parsed, if any.
|
// which this value was parsed, if any.
|
||||||
void setOffsetStart(ptrdiff_t start);
|
void setOffsetStart(ptrdiff_t start);
|
||||||
|
@ -1448,6 +1484,14 @@ public:
|
||||||
|
|
||||||
inline void swap(Value& a, Value& b) { a.swap(b); }
|
inline void swap(Value& a, Value& b) { a.swap(b); }
|
||||||
|
|
||||||
|
inline const Value& Value::front() const { return *begin(); }
|
||||||
|
|
||||||
|
inline Value& Value::front() { return *begin(); }
|
||||||
|
|
||||||
|
inline const Value& Value::back() const { return *(--end()); }
|
||||||
|
|
||||||
|
inline Value& Value::back() { return *(--end()); }
|
||||||
|
|
||||||
} // namespace Json
|
} // namespace Json
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
@ -1496,7 +1540,8 @@ inline void swap(Value& a, Value& b) { a.swap(b); }
|
||||||
#pragma warning(disable : 4251)
|
#pragma warning(disable : 4251)
|
||||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
|
|
||||||
#pragma pack(push, 8)
|
#pragma pack(push)
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
|
@ -1523,12 +1568,12 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \brief Constructs a Reader allowing all features for parsing.
|
/** \brief Constructs a Reader allowing all features for parsing.
|
||||||
* \deprecated Use CharReader and CharReaderBuilder.
|
* \deprecated Use CharReader and CharReaderBuilder.
|
||||||
*/
|
*/
|
||||||
Reader();
|
Reader();
|
||||||
|
|
||||||
/** \brief Constructs a Reader allowing the specified feature set for parsing.
|
/** \brief Constructs a Reader allowing the specified feature set for parsing.
|
||||||
* \deprecated Use CharReader and CharReaderBuilder.
|
* \deprecated Use CharReader and CharReaderBuilder.
|
||||||
*/
|
*/
|
||||||
Reader(const Features& features);
|
Reader(const Features& features);
|
||||||
|
|
||||||
|
@ -1662,6 +1707,7 @@ private:
|
||||||
using Errors = std::deque<ErrorInfo>;
|
using Errors = std::deque<ErrorInfo>;
|
||||||
|
|
||||||
bool readToken(Token& token);
|
bool readToken(Token& token);
|
||||||
|
bool readTokenSkippingComments(Token& token);
|
||||||
void skipSpaces();
|
void skipSpaces();
|
||||||
bool match(const Char* pattern, int patternLength);
|
bool match(const Char* pattern, int patternLength);
|
||||||
bool readComment();
|
bool readComment();
|
||||||
|
@ -1693,7 +1739,6 @@ private:
|
||||||
int& column) const;
|
int& column) const;
|
||||||
String getLocationLineAndColumn(Location location) const;
|
String getLocationLineAndColumn(Location location) const;
|
||||||
void addComment(Location begin, Location end, CommentPlacement placement);
|
void addComment(Location begin, Location end, CommentPlacement placement);
|
||||||
void skipCommentTokens(Token& token);
|
|
||||||
|
|
||||||
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);
|
||||||
|
@ -1716,6 +1761,12 @@ private:
|
||||||
*/
|
*/
|
||||||
class JSON_API CharReader {
|
class JSON_API CharReader {
|
||||||
public:
|
public:
|
||||||
|
struct JSON_API StructuredError {
|
||||||
|
ptrdiff_t offset_start;
|
||||||
|
ptrdiff_t offset_limit;
|
||||||
|
String message;
|
||||||
|
};
|
||||||
|
|
||||||
virtual ~CharReader() = default;
|
virtual ~CharReader() = default;
|
||||||
/** \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
|
||||||
|
@ -1734,7 +1785,12 @@ public:
|
||||||
* error occurred.
|
* error occurred.
|
||||||
*/
|
*/
|
||||||
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
|
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
|
||||||
String* errs) = 0;
|
String* errs);
|
||||||
|
|
||||||
|
/** \brief Returns a vector of structured errors encountered while parsing.
|
||||||
|
* Each parse call resets the stored list of errors.
|
||||||
|
*/
|
||||||
|
std::vector<StructuredError> getStructuredErrors() const;
|
||||||
|
|
||||||
class JSON_API Factory {
|
class JSON_API Factory {
|
||||||
public:
|
public:
|
||||||
|
@ -1744,7 +1800,21 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual CharReader* newCharReader() const = 0;
|
virtual CharReader* newCharReader() const = 0;
|
||||||
}; // Factory
|
}; // Factory
|
||||||
}; // CharReader
|
|
||||||
|
protected:
|
||||||
|
class Impl {
|
||||||
|
public:
|
||||||
|
virtual ~Impl() = default;
|
||||||
|
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
|
||||||
|
String* errs) = 0;
|
||||||
|
virtual std::vector<StructuredError> getStructuredErrors() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit CharReader(std::unique_ptr<Impl> impl) : _impl(std::move(impl)) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Impl> _impl;
|
||||||
|
}; // CharReader
|
||||||
|
|
||||||
/** \brief Build a CharReader implementation.
|
/** \brief Build a CharReader implementation.
|
||||||
*
|
*
|
||||||
|
@ -1832,6 +1902,12 @@ public:
|
||||||
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode
|
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode
|
||||||
*/
|
*/
|
||||||
static void strictMode(Json::Value* settings);
|
static void strictMode(Json::Value* settings);
|
||||||
|
/** ECMA-404 mode.
|
||||||
|
* \pre 'settings' != NULL (but Json::null is fine)
|
||||||
|
* \remark Defaults:
|
||||||
|
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderECMA404Mode
|
||||||
|
*/
|
||||||
|
static void ecma404Mode(Json::Value* settings);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Consume entire stream and use its begin/end.
|
/** Consume entire stream and use its begin/end.
|
||||||
|
@ -1912,7 +1988,8 @@ JSON_API IStream& operator>>(IStream&, Value&);
|
||||||
#pragma warning(disable : 4251)
|
#pragma warning(disable : 4251)
|
||||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
|
|
||||||
#pragma pack(push, 8)
|
#pragma pack(push)
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
|
@ -1955,7 +2032,7 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual StreamWriter* newStreamWriter() const = 0;
|
virtual StreamWriter* newStreamWriter() const = 0;
|
||||||
}; // Factory
|
}; // Factory
|
||||||
}; // StreamWriter
|
}; // StreamWriter
|
||||||
|
|
||||||
/** \brief Write into stringstream, then return string, for convenience.
|
/** \brief Write into stringstream, then return string, for convenience.
|
||||||
* A StreamWriter will be created from the factory, used, and then deleted.
|
* A StreamWriter will be created from the factory, used, and then deleted.
|
||||||
|
@ -2059,8 +2136,7 @@ public:
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||||
#endif
|
#endif
|
||||||
class JSON_API FastWriter
|
class JSON_API FastWriter : public Writer {
|
||||||
: public Writer {
|
|
||||||
public:
|
public:
|
||||||
FastWriter();
|
FastWriter();
|
||||||
~FastWriter() override = default;
|
~FastWriter() override = default;
|
||||||
|
@ -2109,7 +2185,7 @@ private:
|
||||||
* - otherwise, it the values do not fit on one line, or the array contains
|
* - otherwise, it the values do not fit on one line, or the array contains
|
||||||
* object or non empty array, then print one value per line.
|
* object or non empty array, then print one value per line.
|
||||||
*
|
*
|
||||||
* If the Value have comments then they are outputed according to their
|
* If the Value have comments then they are outputted according to their
|
||||||
*#CommentPlacement.
|
*#CommentPlacement.
|
||||||
*
|
*
|
||||||
* \sa Reader, Value, Value::setComment()
|
* \sa Reader, Value, Value::setComment()
|
||||||
|
@ -2119,8 +2195,7 @@ private:
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||||
#endif
|
#endif
|
||||||
class JSON_API
|
class JSON_API StyledWriter : public Writer {
|
||||||
StyledWriter : public Writer {
|
|
||||||
public:
|
public:
|
||||||
StyledWriter();
|
StyledWriter();
|
||||||
~StyledWriter() override = default;
|
~StyledWriter() override = default;
|
||||||
|
@ -2178,7 +2253,7 @@ private:
|
||||||
* - otherwise, it the values do not fit on one line, or the array contains
|
* - otherwise, it the values do not fit on one line, or the array contains
|
||||||
* object or non empty array, then print one value per line.
|
* object or non empty array, then print one value per line.
|
||||||
*
|
*
|
||||||
* If the Value have comments then they are outputed according to their
|
* If the Value have comments then they are outputted according to their
|
||||||
#CommentPlacement.
|
#CommentPlacement.
|
||||||
*
|
*
|
||||||
* \sa Reader, Value, Value::setComment()
|
* \sa Reader, Value, Value::setComment()
|
||||||
|
@ -2188,8 +2263,7 @@ private:
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||||
#endif
|
#endif
|
||||||
class JSON_API
|
class JSON_API StyledStreamWriter {
|
||||||
StyledStreamWriter {
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* \param indentation Each level will be indented by this amount extra.
|
* \param indentation Each level will be indented by this amount extra.
|
||||||
|
@ -2245,6 +2319,7 @@ String JSON_API valueToString(
|
||||||
PrecisionType precisionType = PrecisionType::significantDigits);
|
PrecisionType 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);
|
||||||
|
String JSON_API valueToQuotedString(const char* value, size_t length);
|
||||||
|
|
||||||
/// \brief Output using the StyledStreamWriter.
|
/// \brief Output using the StyledStreamWriter.
|
||||||
/// \see Json::operator>>()
|
/// \see Json::operator>>()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/).
|
/// Json-cpp amalgamated source (https://github.com/open-source-parsers/jsoncpp/).
|
||||||
/// It is intended to be used with #include "json/json.h"
|
/// It is intended to be used with #include "json/json.h"
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////////
|
||||||
|
@ -250,6 +250,7 @@ Iter fixZerosInTheEnd(Iter begin, Iter end, unsigned int precision) {
|
||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <istream>
|
#include <istream>
|
||||||
|
@ -366,7 +367,7 @@ bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root,
|
||||||
|
|
||||||
bool successful = readValue();
|
bool successful = readValue();
|
||||||
Token token;
|
Token token;
|
||||||
skipCommentTokens(token);
|
readTokenSkippingComments(token);
|
||||||
if (collectComments_ && !commentsBefore_.empty())
|
if (collectComments_ && !commentsBefore_.empty())
|
||||||
root.setComment(commentsBefore_, commentAfter);
|
root.setComment(commentsBefore_, commentAfter);
|
||||||
if (features_.strictRoot_) {
|
if (features_.strictRoot_) {
|
||||||
|
@ -394,7 +395,7 @@ bool Reader::readValue() {
|
||||||
throwRuntimeError("Exceeded stackLimit in readValue().");
|
throwRuntimeError("Exceeded stackLimit in readValue().");
|
||||||
|
|
||||||
Token token;
|
Token token;
|
||||||
skipCommentTokens(token);
|
readTokenSkippingComments(token);
|
||||||
bool successful = true;
|
bool successful = true;
|
||||||
|
|
||||||
if (collectComments_ && !commentsBefore_.empty()) {
|
if (collectComments_ && !commentsBefore_.empty()) {
|
||||||
|
@ -462,14 +463,14 @@ bool Reader::readValue() {
|
||||||
return successful;
|
return successful;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reader::skipCommentTokens(Token& token) {
|
bool Reader::readTokenSkippingComments(Token& token) {
|
||||||
|
bool success = readToken(token);
|
||||||
if (features_.allowComments_) {
|
if (features_.allowComments_) {
|
||||||
do {
|
while (success && token.type_ == tokenComment) {
|
||||||
readToken(token);
|
success = readToken(token);
|
||||||
} while (token.type_ == tokenComment);
|
}
|
||||||
} else {
|
|
||||||
readToken(token);
|
|
||||||
}
|
}
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Reader::readToken(Token& token) {
|
bool Reader::readToken(Token& token) {
|
||||||
|
@ -683,12 +684,7 @@ bool Reader::readObject(Token& token) {
|
||||||
Value init(objectValue);
|
Value init(objectValue);
|
||||||
currentValue().swapPayload(init);
|
currentValue().swapPayload(init);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
currentValue().setOffsetStart(token.start_ - begin_);
|
||||||
while (readToken(tokenName)) {
|
while (readTokenSkippingComments(tokenName)) {
|
||||||
bool initialTokenOk = true;
|
|
||||||
while (tokenName.type_ == tokenComment && initialTokenOk)
|
|
||||||
initialTokenOk = readToken(tokenName);
|
|
||||||
if (!initialTokenOk)
|
|
||||||
break;
|
|
||||||
if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
|
if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
|
||||||
return true;
|
return true;
|
||||||
name.clear();
|
name.clear();
|
||||||
|
@ -717,15 +713,11 @@ bool Reader::readObject(Token& token) {
|
||||||
return recoverFromError(tokenObjectEnd);
|
return recoverFromError(tokenObjectEnd);
|
||||||
|
|
||||||
Token comma;
|
Token comma;
|
||||||
if (!readToken(comma) ||
|
if (!readTokenSkippingComments(comma) ||
|
||||||
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
|
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) {
|
||||||
comma.type_ != tokenComment)) {
|
|
||||||
return addErrorAndRecover("Missing ',' or '}' in object declaration",
|
return addErrorAndRecover("Missing ',' or '}' in object declaration",
|
||||||
comma, tokenObjectEnd);
|
comma, tokenObjectEnd);
|
||||||
}
|
}
|
||||||
bool finalizeTokenOk = true;
|
|
||||||
while (comma.type_ == tokenComment && finalizeTokenOk)
|
|
||||||
finalizeTokenOk = readToken(comma);
|
|
||||||
if (comma.type_ == tokenObjectEnd)
|
if (comma.type_ == tokenObjectEnd)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -755,10 +747,7 @@ bool Reader::readArray(Token& token) {
|
||||||
|
|
||||||
Token currentToken;
|
Token currentToken;
|
||||||
// Accept Comment after last item in the array.
|
// Accept Comment after last item in the array.
|
||||||
ok = readToken(currentToken);
|
ok = readTokenSkippingComments(currentToken);
|
||||||
while (currentToken.type_ == tokenComment && ok) {
|
|
||||||
ok = readToken(currentToken);
|
|
||||||
}
|
|
||||||
bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
|
bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
|
||||||
currentToken.type_ != tokenArrayEnd);
|
currentToken.type_ != tokenArrayEnd);
|
||||||
if (!ok || badTokenType) {
|
if (!ok || badTokenType) {
|
||||||
|
@ -836,11 +825,16 @@ bool Reader::decodeDouble(Token& token) {
|
||||||
|
|
||||||
bool Reader::decodeDouble(Token& token, Value& decoded) {
|
bool Reader::decodeDouble(Token& token, Value& decoded) {
|
||||||
double value = 0;
|
double value = 0;
|
||||||
String buffer(token.start_, token.end_);
|
IStringStream is(String(token.start_, token.end_));
|
||||||
IStringStream is(buffer);
|
if (!(is >> value)) {
|
||||||
if (!(is >> value))
|
if (value == std::numeric_limits<double>::max())
|
||||||
return addError(
|
value = std::numeric_limits<double>::infinity();
|
||||||
"'" + String(token.start_, token.end_) + "' is not a number.", token);
|
else if (value == std::numeric_limits<double>::lowest())
|
||||||
|
value = -std::numeric_limits<double>::infinity();
|
||||||
|
else if (!std::isinf(value))
|
||||||
|
return addError(
|
||||||
|
"'" + String(token.start_, token.end_) + "' is not a number.", token);
|
||||||
|
}
|
||||||
decoded = value;
|
decoded = value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1004,7 +998,7 @@ void Reader::getLocationLineAndColumn(Location location, int& line,
|
||||||
while (current < location && current != end_) {
|
while (current < location && current != end_) {
|
||||||
Char c = *current++;
|
Char c = *current++;
|
||||||
if (c == '\r') {
|
if (c == '\r') {
|
||||||
if (*current == '\n')
|
if (current != end_ && *current == '\n')
|
||||||
++current;
|
++current;
|
||||||
lastLineStart = current;
|
lastLineStart = current;
|
||||||
++line;
|
++line;
|
||||||
|
@ -1121,17 +1115,12 @@ class OurReader {
|
||||||
public:
|
public:
|
||||||
using Char = char;
|
using Char = char;
|
||||||
using Location = const Char*;
|
using Location = const Char*;
|
||||||
struct StructuredError {
|
|
||||||
ptrdiff_t offset_start;
|
|
||||||
ptrdiff_t offset_limit;
|
|
||||||
String message;
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit OurReader(OurFeatures const& features);
|
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;
|
||||||
std::vector<StructuredError> getStructuredErrors() const;
|
std::vector<CharReader::StructuredError> getStructuredErrors() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OurReader(OurReader const&); // no impl
|
OurReader(OurReader const&); // no impl
|
||||||
|
@ -1174,6 +1163,7 @@ private:
|
||||||
using Errors = std::deque<ErrorInfo>;
|
using Errors = std::deque<ErrorInfo>;
|
||||||
|
|
||||||
bool readToken(Token& token);
|
bool readToken(Token& token);
|
||||||
|
bool readTokenSkippingComments(Token& token);
|
||||||
void skipSpaces();
|
void skipSpaces();
|
||||||
void skipBom(bool skipBom);
|
void skipBom(bool skipBom);
|
||||||
bool match(const Char* pattern, int patternLength);
|
bool match(const Char* pattern, int patternLength);
|
||||||
|
@ -1207,7 +1197,6 @@ private:
|
||||||
int& column) const;
|
int& column) const;
|
||||||
String getLocationLineAndColumn(Location location) const;
|
String getLocationLineAndColumn(Location location) const;
|
||||||
void addComment(Location begin, Location end, CommentPlacement placement);
|
void addComment(Location begin, Location end, CommentPlacement placement);
|
||||||
void skipCommentTokens(Token& token);
|
|
||||||
|
|
||||||
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);
|
||||||
|
@ -1261,7 +1250,7 @@ bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
|
||||||
bool successful = readValue();
|
bool successful = readValue();
|
||||||
nodes_.pop();
|
nodes_.pop();
|
||||||
Token token;
|
Token token;
|
||||||
skipCommentTokens(token);
|
readTokenSkippingComments(token);
|
||||||
if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) {
|
if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) {
|
||||||
addError("Extra non-whitespace after JSON value.", token);
|
addError("Extra non-whitespace after JSON value.", token);
|
||||||
return false;
|
return false;
|
||||||
|
@ -1289,7 +1278,7 @@ bool OurReader::readValue() {
|
||||||
if (nodes_.size() > features_.stackLimit_)
|
if (nodes_.size() > features_.stackLimit_)
|
||||||
throwRuntimeError("Exceeded stackLimit in readValue().");
|
throwRuntimeError("Exceeded stackLimit in readValue().");
|
||||||
Token token;
|
Token token;
|
||||||
skipCommentTokens(token);
|
readTokenSkippingComments(token);
|
||||||
bool successful = true;
|
bool successful = true;
|
||||||
|
|
||||||
if (collectComments_ && !commentsBefore_.empty()) {
|
if (collectComments_ && !commentsBefore_.empty()) {
|
||||||
|
@ -1376,14 +1365,14 @@ bool OurReader::readValue() {
|
||||||
return successful;
|
return successful;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OurReader::skipCommentTokens(Token& token) {
|
bool OurReader::readTokenSkippingComments(Token& token) {
|
||||||
|
bool success = readToken(token);
|
||||||
if (features_.allowComments_) {
|
if (features_.allowComments_) {
|
||||||
do {
|
while (success && token.type_ == tokenComment) {
|
||||||
readToken(token);
|
success = readToken(token);
|
||||||
} while (token.type_ == tokenComment);
|
}
|
||||||
} else {
|
|
||||||
readToken(token);
|
|
||||||
}
|
}
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OurReader::readToken(Token& token) {
|
bool OurReader::readToken(Token& token) {
|
||||||
|
@ -1680,12 +1669,7 @@ bool OurReader::readObject(Token& token) {
|
||||||
Value init(objectValue);
|
Value init(objectValue);
|
||||||
currentValue().swapPayload(init);
|
currentValue().swapPayload(init);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
currentValue().setOffsetStart(token.start_ - begin_);
|
||||||
while (readToken(tokenName)) {
|
while (readTokenSkippingComments(tokenName)) {
|
||||||
bool initialTokenOk = true;
|
|
||||||
while (tokenName.type_ == tokenComment && initialTokenOk)
|
|
||||||
initialTokenOk = readToken(tokenName);
|
|
||||||
if (!initialTokenOk)
|
|
||||||
break;
|
|
||||||
if (tokenName.type_ == tokenObjectEnd &&
|
if (tokenName.type_ == tokenObjectEnd &&
|
||||||
(name.empty() ||
|
(name.empty() ||
|
||||||
features_.allowTrailingCommas_)) // empty object or trailing comma
|
features_.allowTrailingCommas_)) // empty object or trailing comma
|
||||||
|
@ -1722,15 +1706,11 @@ bool OurReader::readObject(Token& token) {
|
||||||
return recoverFromError(tokenObjectEnd);
|
return recoverFromError(tokenObjectEnd);
|
||||||
|
|
||||||
Token comma;
|
Token comma;
|
||||||
if (!readToken(comma) ||
|
if (!readTokenSkippingComments(comma) ||
|
||||||
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
|
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) {
|
||||||
comma.type_ != tokenComment)) {
|
|
||||||
return addErrorAndRecover("Missing ',' or '}' in object declaration",
|
return addErrorAndRecover("Missing ',' or '}' in object declaration",
|
||||||
comma, tokenObjectEnd);
|
comma, tokenObjectEnd);
|
||||||
}
|
}
|
||||||
bool finalizeTokenOk = true;
|
|
||||||
while (comma.type_ == tokenComment && finalizeTokenOk)
|
|
||||||
finalizeTokenOk = readToken(comma);
|
|
||||||
if (comma.type_ == tokenObjectEnd)
|
if (comma.type_ == tokenObjectEnd)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1764,10 +1744,7 @@ bool OurReader::readArray(Token& token) {
|
||||||
|
|
||||||
Token currentToken;
|
Token currentToken;
|
||||||
// Accept Comment after last item in the array.
|
// Accept Comment after last item in the array.
|
||||||
ok = readToken(currentToken);
|
ok = readTokenSkippingComments(currentToken);
|
||||||
while (currentToken.type_ == tokenComment && ok) {
|
|
||||||
ok = readToken(currentToken);
|
|
||||||
}
|
|
||||||
bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
|
bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
|
||||||
currentToken.type_ != tokenArrayEnd);
|
currentToken.type_ != tokenArrayEnd);
|
||||||
if (!ok || badTokenType) {
|
if (!ok || badTokenType) {
|
||||||
|
@ -1845,7 +1822,7 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) {
|
||||||
const auto digit(static_cast<Value::UInt>(c - '0'));
|
const auto 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, meaning value == threshold,
|
||||||
// b) this is the last digit, or
|
// b) this is the last digit, or
|
||||||
// c) it's small enough to fit in that rounding delta, we're okay.
|
// c) it's small enough to fit in that rounding delta, we're okay.
|
||||||
// Otherwise treat this number as a double to avoid overflow.
|
// Otherwise treat this number as a double to avoid overflow.
|
||||||
|
@ -1882,11 +1859,15 @@ bool OurReader::decodeDouble(Token& token) {
|
||||||
|
|
||||||
bool OurReader::decodeDouble(Token& token, Value& decoded) {
|
bool OurReader::decodeDouble(Token& token, Value& decoded) {
|
||||||
double value = 0;
|
double value = 0;
|
||||||
const String buffer(token.start_, token.end_);
|
IStringStream is(String(token.start_, token.end_));
|
||||||
IStringStream is(buffer);
|
|
||||||
if (!(is >> value)) {
|
if (!(is >> value)) {
|
||||||
return addError(
|
if (value == std::numeric_limits<double>::max())
|
||||||
"'" + String(token.start_, token.end_) + "' is not a number.", token);
|
value = std::numeric_limits<double>::infinity();
|
||||||
|
else if (value == std::numeric_limits<double>::lowest())
|
||||||
|
value = -std::numeric_limits<double>::infinity();
|
||||||
|
else if (!std::isinf(value))
|
||||||
|
return addError(
|
||||||
|
"'" + String(token.start_, token.end_) + "' is not a number.", token);
|
||||||
}
|
}
|
||||||
decoded = value;
|
decoded = value;
|
||||||
return true;
|
return true;
|
||||||
|
@ -2051,7 +2032,7 @@ void OurReader::getLocationLineAndColumn(Location location, int& line,
|
||||||
while (current < location && current != end_) {
|
while (current < location && current != end_) {
|
||||||
Char c = *current++;
|
Char c = *current++;
|
||||||
if (c == '\r') {
|
if (c == '\r') {
|
||||||
if (*current == '\n')
|
if (current != end_ && *current == '\n')
|
||||||
++current;
|
++current;
|
||||||
lastLineStart = current;
|
lastLineStart = current;
|
||||||
++line;
|
++line;
|
||||||
|
@ -2086,10 +2067,11 @@ String OurReader::getFormattedErrorMessages() const {
|
||||||
return formattedMessage;
|
return formattedMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
|
std::vector<CharReader::StructuredError>
|
||||||
std::vector<OurReader::StructuredError> allErrors;
|
OurReader::getStructuredErrors() const {
|
||||||
|
std::vector<CharReader::StructuredError> allErrors;
|
||||||
for (const auto& error : errors_) {
|
for (const auto& error : errors_) {
|
||||||
OurReader::StructuredError structured;
|
CharReader::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_;
|
||||||
structured.message = error.message_;
|
structured.message = error.message_;
|
||||||
|
@ -2099,20 +2081,36 @@ std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
class OurCharReader : public CharReader {
|
class OurCharReader : public CharReader {
|
||||||
bool const collectComments_;
|
|
||||||
OurReader reader_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OurCharReader(bool collectComments, OurFeatures const& features)
|
OurCharReader(bool collectComments, OurFeatures const& features)
|
||||||
: collectComments_(collectComments), reader_(features) {}
|
: CharReader(
|
||||||
bool parse(char const* beginDoc, char const* endDoc, Value* root,
|
std::unique_ptr<OurImpl>(new OurImpl(collectComments, features))) {}
|
||||||
String* errs) override {
|
|
||||||
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
|
protected:
|
||||||
if (errs) {
|
class OurImpl : public Impl {
|
||||||
*errs = reader_.getFormattedErrorMessages();
|
public:
|
||||||
|
OurImpl(bool collectComments, OurFeatures const& features)
|
||||||
|
: collectComments_(collectComments), reader_(features) {}
|
||||||
|
|
||||||
|
bool parse(char const* beginDoc, char const* endDoc, Value* root,
|
||||||
|
String* errs) override {
|
||||||
|
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
|
||||||
|
if (errs) {
|
||||||
|
*errs = reader_.getFormattedErrorMessages();
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
return ok;
|
|
||||||
}
|
std::vector<CharReader::StructuredError>
|
||||||
|
getStructuredErrors() const override {
|
||||||
|
return reader_.getStructuredErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool const collectComments_;
|
||||||
|
OurReader reader_;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
|
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
|
||||||
|
@ -2201,6 +2199,32 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) {
|
||||||
(*settings)["skipBom"] = true;
|
(*settings)["skipBom"] = true;
|
||||||
//! [CharReaderBuilderDefaults]
|
//! [CharReaderBuilderDefaults]
|
||||||
}
|
}
|
||||||
|
// static
|
||||||
|
void CharReaderBuilder::ecma404Mode(Json::Value* settings) {
|
||||||
|
//! [CharReaderBuilderECMA404Mode]
|
||||||
|
(*settings)["allowComments"] = false;
|
||||||
|
(*settings)["allowTrailingCommas"] = false;
|
||||||
|
(*settings)["strictRoot"] = false;
|
||||||
|
(*settings)["allowDroppedNullPlaceholders"] = false;
|
||||||
|
(*settings)["allowNumericKeys"] = false;
|
||||||
|
(*settings)["allowSingleQuotes"] = false;
|
||||||
|
(*settings)["stackLimit"] = 1000;
|
||||||
|
(*settings)["failIfExtra"] = true;
|
||||||
|
(*settings)["rejectDupKeys"] = false;
|
||||||
|
(*settings)["allowSpecialFloats"] = false;
|
||||||
|
(*settings)["skipBom"] = false;
|
||||||
|
//! [CharReaderBuilderECMA404Mode]
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<CharReader::StructuredError>
|
||||||
|
CharReader::getStructuredErrors() const {
|
||||||
|
return _impl->getStructuredErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CharReader::parse(char const* beginDoc, char const* endDoc, Value* root,
|
||||||
|
String* errs) {
|
||||||
|
return _impl->parse(beginDoc, endDoc, root, errs);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
// global functions
|
// global functions
|
||||||
|
@ -2209,7 +2233,7 @@ bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root,
|
||||||
String* errs) {
|
String* errs) {
|
||||||
OStringStream ssin;
|
OStringStream ssin;
|
||||||
ssin << sin.rdbuf();
|
ssin << sin.rdbuf();
|
||||||
String doc = ssin.str();
|
String doc = std::move(ssin).str();
|
||||||
char const* begin = doc.data();
|
char const* begin = doc.data();
|
||||||
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.
|
||||||
|
@ -2501,7 +2525,8 @@ template <typename T, typename U>
|
||||||
static inline bool InRange(double d, T min, U max) {
|
static inline bool InRange(double d, T min, U max) {
|
||||||
// The casts can lose precision, but we are looking only for
|
// The casts can lose precision, but we are looking only for
|
||||||
// an approximate range. Might fail on edge cases though. ~cdunn
|
// an approximate range. Might fail on edge cases though. ~cdunn
|
||||||
return d >= static_cast<double>(min) && d <= static_cast<double>(max);
|
return d >= static_cast<double>(min) && d <= static_cast<double>(max) &&
|
||||||
|
!(static_cast<U>(d) == min && d != static_cast<double>(min));
|
||||||
}
|
}
|
||||||
#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
||||||
static inline double integerToDouble(Json::UInt64 value) {
|
static inline double integerToDouble(Json::UInt64 value) {
|
||||||
|
@ -2515,7 +2540,8 @@ template <typename T> static inline double integerToDouble(T value) {
|
||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
static inline bool InRange(double d, T min, U max) {
|
static inline bool InRange(double d, T min, U max) {
|
||||||
return d >= integerToDouble(min) && d <= integerToDouble(max);
|
return d >= integerToDouble(min) && d <= integerToDouble(max) &&
|
||||||
|
!(static_cast<U>(d) == min && d != integerToDouble(min));
|
||||||
}
|
}
|
||||||
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
||||||
|
|
||||||
|
@ -2577,7 +2603,7 @@ inline static void decodePrefixedString(bool isPrefixed, char const* prefixed,
|
||||||
/** Free the string duplicated by
|
/** Free the string duplicated by
|
||||||
* duplicateStringValue()/duplicateAndPrefixStringValue().
|
* duplicateStringValue()/duplicateAndPrefixStringValue().
|
||||||
*/
|
*/
|
||||||
#if JSONCPP_USING_SECURE_MEMORY
|
#if JSONCPP_USE_SECURE_MEMORY
|
||||||
static inline void releasePrefixedStringValue(char* value) {
|
static inline void releasePrefixedStringValue(char* value) {
|
||||||
unsigned length = 0;
|
unsigned length = 0;
|
||||||
char const* valueDecoded;
|
char const* valueDecoded;
|
||||||
|
@ -2592,10 +2618,10 @@ static inline void releaseStringValue(char* value, unsigned length) {
|
||||||
memset(value, 0, size);
|
memset(value, 0, size);
|
||||||
free(value);
|
free(value);
|
||||||
}
|
}
|
||||||
#else // !JSONCPP_USING_SECURE_MEMORY
|
#else // !JSONCPP_USE_SECURE_MEMORY
|
||||||
static inline void releasePrefixedStringValue(char* value) { free(value); }
|
static inline void releasePrefixedStringValue(char* value) { free(value); }
|
||||||
static inline void releaseStringValue(char* value, unsigned) { free(value); }
|
static inline void releaseStringValue(char* value, unsigned) { free(value); }
|
||||||
#endif // JSONCPP_USING_SECURE_MEMORY
|
#endif // JSONCPP_USE_SECURE_MEMORY
|
||||||
|
|
||||||
} // namespace Json
|
} // namespace Json
|
||||||
|
|
||||||
|
@ -3013,7 +3039,7 @@ const char* Value::asCString() const {
|
||||||
return this_str;
|
return this_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if JSONCPP_USING_SECURE_MEMORY
|
#if JSONCPP_USE_SECURE_MEMORY
|
||||||
unsigned Value::getCStringLength() const {
|
unsigned Value::getCStringLength() const {
|
||||||
JSON_ASSERT_MESSAGE(type() == stringValue,
|
JSON_ASSERT_MESSAGE(type() == stringValue,
|
||||||
"in Json::Value::asCString(): requires stringValue");
|
"in Json::Value::asCString(): requires stringValue");
|
||||||
|
@ -3119,6 +3145,11 @@ Value::Int64 Value::asInt64() const {
|
||||||
JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
|
JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
|
||||||
return Int64(value_.uint_);
|
return Int64(value_.uint_);
|
||||||
case realValue:
|
case realValue:
|
||||||
|
// If the double value is in proximity to minInt64, it will be rounded to
|
||||||
|
// minInt64. The correct value in this scenario is indeterminable
|
||||||
|
JSON_ASSERT_MESSAGE(
|
||||||
|
value_.real_ != minInt64,
|
||||||
|
"Double value is minInt64, precise value cannot be determined");
|
||||||
JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
|
JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
|
||||||
"double out of Int64 range");
|
"double out of Int64 range");
|
||||||
return Int64(value_.real_);
|
return Int64(value_.real_);
|
||||||
|
@ -3506,6 +3537,9 @@ Value const* Value::find(char const* begin, char const* end) const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return &(*it).second;
|
return &(*it).second;
|
||||||
}
|
}
|
||||||
|
Value const* Value::find(const String& key) const {
|
||||||
|
return find(key.data(), key.data() + key.length());
|
||||||
|
}
|
||||||
Value* Value::demand(char const* begin, char const* end) {
|
Value* Value::demand(char const* begin, char const* end) {
|
||||||
JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
|
JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
|
||||||
"in Json::Value::demand(begin, end): requires "
|
"in Json::Value::demand(begin, end): requires "
|
||||||
|
@ -3519,7 +3553,7 @@ const Value& Value::operator[](const char* key) const {
|
||||||
return *found;
|
return *found;
|
||||||
}
|
}
|
||||||
Value const& Value::operator[](const String& key) const {
|
Value const& Value::operator[](const String& key) const {
|
||||||
Value const* found = find(key.data(), key.data() + key.length());
|
Value const* found = find(key);
|
||||||
if (!found)
|
if (!found)
|
||||||
return nullSingleton();
|
return nullSingleton();
|
||||||
return *found;
|
return *found;
|
||||||
|
@ -3619,7 +3653,7 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (removed)
|
if (removed)
|
||||||
*removed = it->second;
|
*removed = std::move(it->second);
|
||||||
ArrayIndex oldSize = size();
|
ArrayIndex oldSize = size();
|
||||||
// shift left all items left, into the place of the "removed"
|
// shift left all items left, into the place of the "removed"
|
||||||
for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
|
for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
|
||||||
|
@ -3722,8 +3756,12 @@ bool Value::isInt64() const {
|
||||||
// Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
|
// Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
|
||||||
// double, so double(maxInt64) will be rounded up to 2^63. Therefore we
|
// double, so double(maxInt64) will be rounded up to 2^63. Therefore we
|
||||||
// require the value to be strictly less than the limit.
|
// require the value to be strictly less than the limit.
|
||||||
return value_.real_ >= double(minInt64) &&
|
// minInt64 is -2^63 which can be represented as a double, but since double
|
||||||
value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
|
// values in its proximity are also rounded to -2^63, we require the value
|
||||||
|
// to be strictly greater than the limit to avoid returning 'true' for
|
||||||
|
// values that are not in the range
|
||||||
|
return value_.real_ > double(minInt64) && value_.real_ < double(maxInt64) &&
|
||||||
|
IsIntegral(value_.real_);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3761,7 +3799,11 @@ bool Value::isIntegral() const {
|
||||||
// Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
|
// Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
|
||||||
// double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
|
// double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
|
||||||
// require the value to be strictly less than the limit.
|
// require the value to be strictly less than the limit.
|
||||||
return value_.real_ >= double(minInt64) &&
|
// minInt64 is -2^63 which can be represented as a double, but since double
|
||||||
|
// values in its proximity are also rounded to -2^63, we require the value
|
||||||
|
// to be strictly greater than the limit to avoid returning 'true' for
|
||||||
|
// values that are not in the range
|
||||||
|
return value_.real_ > double(minInt64) &&
|
||||||
value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
|
value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
|
||||||
#else
|
#else
|
||||||
return value_.real_ >= minInt && value_.real_ <= maxUInt &&
|
return value_.real_ >= minInt && value_.real_ <= maxUInt &&
|
||||||
|
@ -3824,9 +3866,8 @@ void Value::setComment(String comment, CommentPlacement placement) {
|
||||||
// Always discard trailing newline, to aid indentation.
|
// Always discard trailing newline, to aid indentation.
|
||||||
comment.pop_back();
|
comment.pop_back();
|
||||||
}
|
}
|
||||||
JSON_ASSERT(!comment.empty());
|
|
||||||
JSON_ASSERT_MESSAGE(
|
JSON_ASSERT_MESSAGE(
|
||||||
comment[0] == '\0' || comment[0] == '/',
|
comment.empty() || comment[0] == '/',
|
||||||
"in Json::Value::setComment(): Comments must start with /");
|
"in Json::Value::setComment(): Comments must start with /");
|
||||||
comments_.set(placement, std::move(comment));
|
comments_.set(placement, std::move(comment));
|
||||||
}
|
}
|
||||||
|
@ -4194,8 +4235,9 @@ String valueToString(double value, bool useSpecialFloats,
|
||||||
if (!isfinite(value)) {
|
if (!isfinite(value)) {
|
||||||
static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"},
|
static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"},
|
||||||
{"null", "-1e+9999", "1e+9999"}};
|
{"null", "-1e+9999", "1e+9999"}};
|
||||||
return reps[useSpecialFloats ? 0 : 1]
|
return reps[useSpecialFloats ? 0 : 1][isnan(value) ? 0
|
||||||
[isnan(value) ? 0 : (value < 0) ? 1 : 2];
|
: (value < 0) ? 1
|
||||||
|
: 2];
|
||||||
}
|
}
|
||||||
|
|
||||||
String buffer(size_t(36), '\0');
|
String buffer(size_t(36), '\0');
|
||||||
|
@ -4415,6 +4457,10 @@ String valueToQuotedString(const char* value) {
|
||||||
return valueToQuotedStringN(value, strlen(value));
|
return valueToQuotedStringN(value, strlen(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String valueToQuotedString(const char* value, size_t length) {
|
||||||
|
return valueToQuotedStringN(value, length);
|
||||||
|
}
|
||||||
|
|
||||||
// Class Writer
|
// Class Writer
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
Writer::~Writer() = default;
|
Writer::~Writer() = default;
|
||||||
|
@ -4552,7 +4598,7 @@ void StyledWriter::writeValue(const Value& value) {
|
||||||
const String& name = *it;
|
const String& name = *it;
|
||||||
const Value& childValue = value[name];
|
const Value& childValue = value[name];
|
||||||
writeCommentBeforeValue(childValue);
|
writeCommentBeforeValue(childValue);
|
||||||
writeWithIndent(valueToQuotedString(name.c_str()));
|
writeWithIndent(valueToQuotedString(name.c_str(), name.size()));
|
||||||
document_ += " : ";
|
document_ += " : ";
|
||||||
writeValue(childValue);
|
writeValue(childValue);
|
||||||
if (++it == members.end()) {
|
if (++it == members.end()) {
|
||||||
|
@ -4770,7 +4816,7 @@ void StyledStreamWriter::writeValue(const Value& value) {
|
||||||
const String& name = *it;
|
const String& name = *it;
|
||||||
const Value& childValue = value[name];
|
const Value& childValue = value[name];
|
||||||
writeCommentBeforeValue(childValue);
|
writeCommentBeforeValue(childValue);
|
||||||
writeWithIndent(valueToQuotedString(name.c_str()));
|
writeWithIndent(valueToQuotedString(name.c_str(), name.size()));
|
||||||
*document_ << " : ";
|
*document_ << " : ";
|
||||||
writeValue(childValue);
|
writeValue(childValue);
|
||||||
if (++it == members.end()) {
|
if (++it == members.end()) {
|
||||||
|
@ -5308,7 +5354,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);
|
||||||
return sout.str();
|
return std::move(sout).str();
|
||||||
}
|
}
|
||||||
|
|
||||||
OStream& operator<<(OStream& sout, Value const& root) {
|
OStream& operator<<(OStream& sout, Value const& root) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue