JsonCpp 是一个C++库,用于解析和生成 JSON 数据。它具有以下特点:
- 轻量级且易于集成
- 支持 STL 容器
- 提供 DOM 风格的 API
- 支持 JSON 指针和 JSON 补丁(部分版本)
主要功能
- 解析JSON字符串为 C++ 对象
- 将 C++ 对象序列化为 JSON 字符串
- 访问和修改 JSON 数据
- 支持 JSON 数组和对象
1、下载jsonCPP
源码下载:git clone https://github.com/open-source-parsers/jsoncpp.git
源码编译:
cd jsoncpp
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=release -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=OFF ../
make
成功编译出 libjsoncpp.a库文件。
2、jsonCPP的使用
下面用一段代码说明jsonCPP的使用
#include <iostream>
#include <string>
#include <memory>
#include "json.h"
using namespace std;
/*如何使用jsoncpp库文件*/
string jsonStr = R"(
{
"name": "John Doe",
"age": 30,
"is_student": false,
"courses": ["Math", "Physics"],
"address": {
"street": "123 Main St",
"city": "New York"
}
}
)";
int main()
{
Json::Value root;
Json::CharReaderBuilder readerBuilder;
unique_ptr<Json::CharReader> reader(readerBuilder.newCharReader());
string errs;
bool parsingSuccessful = reader->parse(jsonStr.c_str(),jsonStr.c_str()+jsonStr.size(),
&root,&errs);
if(!parsingSuccessful)
cout << "failed to parse JSON:" << errs << endl;
/*获取字符串值*/
string name = root["name"].asString();
cout << "name:" << name << endl;
/*获取数值*/
int age = root["age"].asInt();
cout << "age:" << age << endl;
/*获取布尔值*/
bool isStudent = root["is_student"].asBool();
cout << "is_student:" << isStudent << endl;
/*获取数组*/
const Json::Value& courses = root["courses"];
for(Json::ArrayIndex i = 0; i<courses.size(); i++)
cout << courses[i].asString() << endl;
/*获取嵌套对象*/
const Json::Value& address = root["address"];
string street = address["street"].asString();
string city = address["city"].asString();
cout << "address:" << street << ',' << city << endl;
/*修改内容*/
root["age"] = 31;
root["email"] = "john.doe@example.com";
root["courses"].append("chemistry");
root["address"]["city"] = "Boston";
/*生成JSON字符串*/
Json::StreamWriterBuilder writerBuilder;
unique_ptr<Json::StreamWriter> writer(writerBuilder.newStreamWriter());
ostringstream oss;
writer->write(root,&oss);
string outputJson = oss.str();
/*
{
"address" :
{
"city" : "Boston",
"street" : "123 Main St"
},
"age" : 31,
"courses" :
[
"Math",
"Physics",
"chemistry"
],
"email" : "john.doe@example.com",
"is_student" : false,
"name" : "John Doe"
}
*/
cout << outputJson << endl;
//可以直接使用ostream代替ostringstream类型
cout << "直接输出JSON数据内容:" << endl;
writer->write(root,&cout);
cout << endl;
//代码中针对Json::Value类重载了输出运算符<<,所以我们可以直接使用cout输出json内容
cout << "cout的方式输出JSON数据:" << endl;
cout << root << endl;
return 1;
}
编译时记得链接 libjsoncpp.a 库文件以及-I 指定josn.h头文件的位置。
3、jsonCPP源码详解
jsonCPP源码主要完成两个功能:
一是解析json数据并且将解析后的数据通过map进行存储。其中作者非常巧妙的对Value类重载了好几个版本的下标运算符[]使得我们可以通过下标运算符来获取对应的值,如下所示:
string name = root["name"].asString();
bool isStudent = root["is_student"].asBool();
二是打印json数据,我们可以随意的修改json中的数据并将最终的结果打印出来。如下所示:
root["age"] = 31;
root["email"] = "john.doe@example.com";
由于jsonCPP的源码内容不是很长,阅读的难度也不是很大,鼓励大家去进行阅读。大家阅读时可以从Value类开始,因为这个类是核心重点。最后我将jsonCPP注释过的源码放在文章中,需要的同学自行阅读。
value.h内容如下:
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_VALUE_H_INCLUDED
#define JSON_VALUE_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include "forwards.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
// Conditional NORETURN attribute on the throw functions would:
// a) suppress false positives from static code analysis
// b) possibly improve optimization opportunities.
#if !defined(JSONCPP_NORETURN)
#if defined(_MSC_VER) && _MSC_VER == 1800
#define JSONCPP_NORETURN __declspec(noreturn)
#else
#define JSONCPP_NORETURN [[noreturn]]
#endif
#endif
// 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
// even though these declare themselves to be c++11 compilers.
#if !defined(JSONCPP_TEMPLATE_DELETE)
#if defined(__clang__) && defined(__apple_build_version__)
#if __apple_build_version__ <= 8000042
#define JSONCPP_TEMPLATE_DELETE
#endif
#elif defined(__clang__)
#if __clang_major__ == 3 && __clang_minor__ <= 8
#define JSONCPP_TEMPLATE_DELETE
#endif
#endif
#if !defined(JSONCPP_TEMPLATE_DELETE)
#define JSONCPP_TEMPLATE_DELETE = delete
#endif
#endif
#if __cplusplus >= 201703L
#define JSONCPP_HAS_STRING_VIEW 1
#endif
#include <array>
#include <exception>
#include <map>
#include <memory>
#include <string>
#include <vector>
#ifdef JSONCPP_HAS_STRING_VIEW
#include <string_view>
#endif
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(push)
#pragma warning(disable : 4251 4275)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma pack(push)
#pragma pack()
/** \brief JSON (JavaScript Object Notation).
*/
namespace Json {
#if JSON_USE_EXCEPTION
/** Base class for all exceptions we throw.
*
* We use nothing but these internally. Of course, STL can throw others.
*/
class JSON_API Exception : public std::exception {
public:
Exception(String msg);
~Exception() noexcept override;
char const* what() const noexcept override;
protected:
String msg_;
};
/** Exceptions which the user cannot easily avoid.
*
* E.g. out-of-memory (when we use malloc), stack-overflow, malicious input
*
* \remark derived from Json::Exception
*/
class JSON_API RuntimeError : public Exception {
public:
RuntimeError(String const& msg);
};
/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros.
*
* These are precondition-violations (user bugs) and internal errors (our bugs).
*
* \remark derived from Json::Exception
*/
class JSON_API LogicError : public Exception {
public:
LogicError(String const& msg);
};
#endif
/// used internally
JSONCPP_NORETURN void throwRuntimeError(String const& msg);
/// used internally
JSONCPP_NORETURN void throwLogicError(String const& msg);
/** \brief Type of the value held by a Value object.
*/
/*Value能够存放的数据类型*/
enum ValueType {
nullValue = 0, ///< 'null' value
intValue, ///< signed integer value
uintValue, ///< unsigned integer value
realValue, ///< double value
stringValue, ///< UTF-8 string value
booleanValue, ///< bool value
arrayValue, ///< array value (ordered list)
objectValue ///< object value (collection of name/value pairs).
};
enum CommentPlacement {
// /*注释*/
// a = 5;
commentBefore = 0, ///< a comment placed on the line before a value
// a = 5; /*注释*/
commentAfterOnSameLine, ///< a comment just after a value on the same line
// a = 5;
// /*注释*/
commentAfter, ///< a comment on the line after a value (only make sense for
/// root value)
numberOfCommentPlacement
};
/** \brief Type of precision for formatting of real values.
*/
enum PrecisionType {
significantDigits = 0, ///< we set max number of significant digits in string
decimalPlaces ///< we set max number of digits after "." in string
};
/** \brief Lightweight wrapper to tag static string.
*
* Value constructor and objectValue member assignment takes advantage of the
* StaticString and avoid the cost of string duplication when storing the
* string or the member name.
*
* Example of usage:
* \code
* Json::Value aValue( StaticString("some text") );
* Json::Value object;
* static const StaticString code("code");
* object[code] = 1234;
* \endcode
*/
class JSON_API StaticString {
public:
explicit StaticString(const char* czstring) : c_str_(czstring) {}
/*定义了一个类型转换运算符,将对象转换为 const char* 类型*/
operator const char*() const { return c_str_; }
const char* c_str() const { return c_str_; }
private:
const char* c_str_;
};
/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
*
* This class is a discriminated union wrapper that can represents a:
* - signed integer [range: Value::minInt - Value::maxInt]
* - unsigned integer (range: 0 - Value::maxUInt)
* - double
* - UTF-8 string
* - boolean
* - 'null'
* - an ordered list of Value
* - collection of name/value pairs (javascript object)
*
* The type of the held value is represented by a #ValueType and
* can be obtained using type().
*
* Values of an #objectValue or #arrayValue can be accessed using operator[]()
* methods.
* Non-const methods will automatically create the a #nullValue element
* if it does not exist.
* The sequence of an #arrayValue will be automatically resized and initialized
* with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
*
* The get() methods can be used to obtain default value in the case the
* required element does not exist.
*
* It is possible to iterate over the list of member keys of an object using
* the getMemberNames() method.
*
* \note #Value string-length fit in size_t, but keys must be < 2^30.
* (The reason is an implementation detail.) A #CharReader will raise an
* exception if a bound is exceeded to avoid security holes in your app,
* but the Value API does *not* check bounds. That is the responsibility
* of the caller.
*/
/*
Value类
JSON 数据由以下两种基本结构组成:
键值对集合(对象):用花括号 {} 包裹,键值对之间用逗号 , 分隔,键和值用冒号 : 分隔。
键:必须是字符串(用双引号 "" 包裹)。
值:可以是字符串、数字、布尔值、null、对象或数组。
值的有序列表(数组):用方括号 [] 包裹,元素之间用逗号 , 分隔。
元素类型可以是字符串、数字、布尔值、null、对象或数组。
*/
class JSON_API Value {
/*友元类*/
friend class ValueIteratorBase;
public:
/*打印JSON时使用*/
using Members = std::vector<String>;
using iterator = ValueIterator;
using const_iterator = ValueConstIterator;
using UInt = Json::UInt;
using Int = Json::Int;
#if defined(JSON_HAS_INT64)
using UInt64 = Json::UInt64;
using Int64 = Json::Int64;
#endif // defined(JSON_HAS_INT64)
using LargestInt = Json::LargestInt;
using LargestUInt = Json::LargestUInt;
using ArrayIndex = Json::ArrayIndex;
// Required for boost integration, e. g. BOOST_TEST
using value_type = std::string;
/*静态成员*/
#if JSON_USE_NULLREF
// Binary compatibility kludges, do not use.
/*null和nullRef的类型是const Value&而非指针*/
static const Value& null;
static const Value& nullRef;
#endif
// null and nullRef are deprecated, use this instead.
static Value const& nullSingleton();
/// Minimum signed integer value that can be stored in a Json::Value.
/*能够存储的最小有符号整数,/2可以视为右移一位*/
static constexpr LargestInt minLargestInt =
LargestInt(~(LargestUInt(-1) / 2));
/// Maximum signed integer value that can be stored in a Json::Value.
static constexpr LargestInt maxLargestInt = LargestInt(LargestUInt(-1) / 2);
/// Maximum unsigned integer value that can be stored in a Json::Value.
static constexpr LargestUInt maxLargestUInt = LargestUInt(-1);
/// Minimum signed int value that can be stored in a Json::Value.
static constexpr Int minInt = Int(~(UInt(-1) / 2));
/// Maximum signed int value that can be stored in a Json::Value.
static constexpr Int maxInt = Int(UInt(-1) / 2);
/// Maximum unsigned int value that can be stored in a Json::Value.
static constexpr UInt maxUInt = UInt(-1);
#if defined(JSON_HAS_INT64)
/// Minimum signed 64 bits int value that can be stored in a Json::Value.
static constexpr Int64 minInt64 = Int64(~(UInt64(-1) / 2));
/// Maximum signed 64 bits int value that can be stored in a Json::Value.
static constexpr Int64 maxInt64 = Int64(UInt64(-1) / 2);
/// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
static constexpr UInt64 maxUInt64 = UInt64(-1);
#endif // defined(JSON_HAS_INT64)
/// Default precision for real value for string representation.
static constexpr UInt defaultRealPrecision = 17;
// The constant is hard-coded because some compiler have trouble
// converting Value::maxUInt64 to a double correctly (AIX/xlC).
// Assumes that UInt64 is a 64 bits integer.
static constexpr double maxUInt64AsDouble = 18446744073709551615.0;
// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler
// when using gcc and clang backend compilers. CZString
// cannot be defined as private. See issue #486
#ifdef __NVCC__
public:
#else
private:
#endif
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
/*Value类里面包含了CZString类*/
class CZString {
public:
/*复制策略*/
enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy };
CZString(ArrayIndex index);
CZString(char const* str, unsigned length, DuplicationPolicy allocate);
/*拷贝构造函数*/
CZString(CZString const& other);
/*移动构造函数*/
CZString(CZString&& other) noexcept;
/*析构函数*/
~CZString();
/*拷贝赋值运算符*/
CZString& operator=(const CZString& other);
/*移动赋值运算符*/
CZString& operator=(CZString&& other) noexcept;
/*实现为成员函数*/
bool operator<(CZString const& other) const;
bool operator==(CZString const& other) const;
ArrayIndex index() const;
// const char* c_str() const; ///< \deprecated
char const* data() const;
unsigned length() const;
bool isStaticString() const;
private:
void swap(CZString& other);
struct StringStorage {
unsigned policy_ : 2;
unsigned length_ : 30; // 1GB max
};
char const* cstr_; // actually, a prefixed string, unless policy is noDup
union {
ArrayIndex index_;
StringStorage storage_;
};
};
public:
/*使用map key-value对来存储*/
typedef std::map<CZString, Value> ObjectValues;
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
public:
/**
* \brief Create a default Value of the given type.
*
* This is a very useful constructor.
* To create an empty array, pass arrayValue.
* To create an empty object, pass objectValue.
* Another Value can then be set to this one by assignment.
* This is useful since clear() and resize() will not alter types.
*
* Examples:
* \code
* Json::Value null_value; // null
* Json::Value arr_value(Json::arrayValue); // []
* Json::Value obj_value(Json::objectValue); // {}
* \endcode
*/
/*Value类的构造函数,支持整形,浮点数,布尔类型,字符串*/
Value(ValueType type = nullValue);
Value(Int value);
Value(UInt value);
#if defined(JSON_HAS_INT64)
Value(Int64 value);
Value(UInt64 value);
#endif // if defined(JSON_HAS_INT64)
Value(double value);
Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.)
Value(const char* begin, const char* end); ///< Copy all, incl zeroes.
/**
* \brief Constructs a value from a static string.
*
* Like other value string constructor but do not duplicate the string for
* internal storage. The given string must remain alive after the call to
* this constructor.
*
* \note This works only for null-terminated strings. (We cannot change the
* size of this class, so we have nowhere to store the length, which might be
* computed later for various operations.)
*
* Example of usage:
* \code
* static StaticString foo("some text");
* Json::Value aValue(foo);
* \endcode
*/
Value(const StaticString& value);
Value(const String& value);
#ifdef JSONCPP_HAS_STRING_VIEW
Value(std::string_view value);
#endif
Value(bool value);
Value(std::nullptr_t ptr) = delete;
/*拷贝构造函数*/
Value(const Value& other);
/*移动构造函数*/
Value(Value&& other) noexcept;
~Value();
/// \note Overwrite existing comments. To preserve comments, use
/// #swapPayload().
/*赋值运算符*/
Value& operator=(const Value& other);
/*移动运算符*/
Value& operator=(Value&& other) noexcept;
/// Swap everything.
void swap(Value& other);
/// Swap values but leave comments and source offsets in place.
void swapPayload(Value& other);
/// copy everything.
void copy(const Value& other);
/// copy values but leave comments and source offsets in place.
void copyPayload(const Value& other);
ValueType type() const;
/// Compare payload only, not comments etc.
bool operator<(const Value& other) const;
bool operator<=(const Value& other) const;
bool operator>=(const Value& other) const;
bool operator>(const Value& other) const;
bool operator==(const Value& other) const;
bool operator!=(const Value& other) const;
int compare(const Value& other) const;
const char* asCString() const; ///< Embedded zeroes could cause you trouble!
#if JSONCPP_USE_SECURE_MEMORY
unsigned getCStringLength() const; // Allows you to understand the length of
// the CString
#endif
String asString() const; ///< Embedded zeroes are possible.
/** Get raw char* of string-value.
* \return false if !string. (Seg-fault if str or end are NULL.)
*/
bool getString(char const** begin, char const** end) const;
#ifdef JSONCPP_HAS_STRING_VIEW
/** Get string_view of string-value.
* \return false if !string. (Seg-fault if str is NULL.)
*/
bool getString(std::string_view* str) const;
#endif
Int asInt() const;
UInt asUInt() const;
#if defined(JSON_HAS_INT64)
Int64 asInt64() const;
UInt64 asUInt64() const;
#endif // if defined(JSON_HAS_INT64)
LargestInt asLargestInt() const;
LargestUInt asLargestUInt() const;
float asFloat() const;
double asDouble() const;
bool asBool() const;
bool isNull() const;
bool isBool() const;
bool isInt() const;
bool isInt64() const;
bool isUInt() const;
bool isUInt64() const;
bool isIntegral() const;
bool isDouble() const;
bool isNumeric() const;
bool isString() const;
bool isArray() const;
bool isObject() const;
/// The `as<T>` and `is<T>` member function templates and specializations.
template <typename T> T as() const JSONCPP_TEMPLATE_DELETE;
template <typename T> bool is() const JSONCPP_TEMPLATE_DELETE;
bool isConvertibleTo(ValueType other) const;
/// Number of values in array or object
ArrayIndex size() const;
/// \brief Return true if empty array, empty object, or null;
/// otherwise, false.
bool empty() const;
/// Return !isNull()
explicit operator bool() const;
/// Remove all object members and array elements.
/// \pre type() is arrayValue, objectValue, or nullValue
/// \post type() is unchanged
void clear();
/// Resize the array to newSize elements.
/// New elements are initialized to null.
/// May only be called on nullValue or arrayValue.
/// \pre type() is arrayValue or nullValue
/// \post type() is arrayValue
void resize(ArrayIndex newSize);
///@{
/// 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
/// its size is index+1.
/// (You may need to say 'value[0u]' to get your compiler to distinguish
/// this from the operator[] which takes a string.)
Value& operator[](ArrayIndex index);
Value& operator[](int index);
///@}
///@{
/// Access an array element (zero based index).
/// (You may need to say 'value[0u]' to get your compiler to distinguish
/// this from the operator[] which takes a string.)
const Value& operator[](ArrayIndex index) const;
const Value& operator[](int index) const;
///@}
/// If the array contains at least index+1 elements, returns the element
/// value, otherwise returns defaultValue.
Value get(ArrayIndex index, const Value& defaultValue) const;
/// Return true if index < size().
bool isValidIndex(ArrayIndex index) const;
/// \brief Append value to array at the end.
///
/// Equivalent to jsonvalue[jsonvalue.size()] = value;
Value& append(const Value& value);
Value& append(Value&& value);
/// \brief Insert value in array at specific index
bool insert(ArrayIndex index, const Value& newValue);
bool insert(ArrayIndex index, Value&& newValue);
#ifdef JSONCPP_HAS_STRING_VIEW
/// Access an object value by name, create a null member if it does not exist.
/// \param key may contain embedded nulls.
Value& operator[](std::string_view key);
/// Access an object value by name, returns null if there is no member with
/// that name.
/// \param key may contain embedded nulls.
const Value& operator[](std::string_view key) const;
#else
/// 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.
/// Exceeding that will cause an exception.
Value& operator[](const char* key);
/// Access an object value by name, returns null if there is no member with
/// that name.
const Value& operator[](const char* key) const;
/// Access an object value by name, create a null member if it does not exist.
/// \param key may contain embedded nulls.
Value& operator[](const String& key);
/// Access an object value by name, returns null if there is no member with
/// that name.
/// \param key may contain embedded nulls.
const Value& operator[](const String& key) const;
#endif
/** \brief Access an object value by name, create a null member if it does not
* exist.
*
* If the object has no entry for that name, then the member name used to
* store the new entry is not duplicated.
* Example of use:
* \code
* Json::Value object;
* static const StaticString code("code");
* object[code] = 1234;
* \endcode
*/
Value& operator[](const StaticString& key);
#ifdef JSONCPP_HAS_STRING_VIEW
/// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy
Value get(std::string_view key, const Value& defaultValue) const;
#else
/// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy
Value get(const char* key, const Value& defaultValue) const;
/// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy
/// \param key may contain embedded nulls.
Value get(const String& key, const Value& defaultValue) const;
#endif
/// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy
/// \note key may contain embedded nulls.
Value get(const char* begin, const char* end,
const Value& defaultValue) const;
/// Most general and efficient version of isMember()const, get()const,
/// and operator[]const
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
Value const* find(char const* begin, char const* end) const;
/// Most general and efficient version of isMember()const, get()const,
/// and operator[]const
Value const* find(const String& key) const;
/// Calls find and only returns a valid pointer if the type is found
template <typename T, bool (T::*TMemFn)() const>
Value const* findValue(const String& key) const {
Value const* found = find(key);
if (!found || !(found->*TMemFn)())
return nullptr;
return found;
}
Value const* findNull(const String& key) const;
Value const* findBool(const String& key) const;
Value const* findInt(const String& key) const;
Value const* findInt64(const String& key) const;
Value const* findUInt(const String& key) const;
Value const* findUInt64(const String& key) const;
Value const* findIntegral(const String& key) const;
Value const* findDouble(const String& key) const;
Value const* findNumeric(const String& key) const;
Value const* findString(const String& key) const;
Value const* findArray(const String& key) const;
Value const* findObject(const String& key) const;
/// Most general and efficient version of object-mutators.
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
/// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
Value* demand(char const* begin, char const* end);
/// \brief Remove and return the named member.
///
/// Do nothing if it did not exist.
/// \pre type() is objectValue or nullValue
/// \post type() is unchanged
#if JSONCPP_HAS_STRING_VIEW
void removeMember(std::string_view key);
#else
void removeMember(const char* key);
/// Same as removeMember(const char*)
/// \param key may contain embedded nulls.
void removeMember(const String& key);
#endif
/** \brief Remove the named map member.
*
* Update 'removed' iff removed.
* \param key may contain embedded nulls.
* \return true iff removed (no exceptions)
*/
#if JSONCPP_HAS_STRING_VIEW
bool removeMember(std::string_view key, Value* removed);
#else
bool removeMember(String const& key, Value* removed);
/// Same as removeMember(const char* begin, const char* end, Value* removed),
/// but 'key' is null-terminated.
bool removeMember(const char* key, Value* removed);
#endif
/// Same as removeMember(String const& key, Value* removed)
bool removeMember(const char* begin, const char* end, Value* removed);
/** \brief Remove the indexed array element.
*
* O(n) expensive operations.
* Update 'removed' iff removed.
* \return true if removed (no exceptions)
*/
bool removeIndex(ArrayIndex index, Value* removed);
#ifdef JSONCPP_HAS_STRING_VIEW
/// Return true if the object has a member named key.
/// \param key may contain embedded nulls.
bool isMember(std::string_view key) const;
#else
/// Return true if the object has a member named key.
/// \note 'key' must be null-terminated.
bool isMember(const char* key) const;
/// Return true if the object has a member named key.
/// \param key may contain embedded nulls.
bool isMember(const String& key) const;
#endif
/// Same as isMember(String const& key)const
bool isMember(const char* begin, const char* end) const;
/// \brief Return a list of the member names.
///
/// If null, return an empty list.
/// \pre type() is objectValue or nullValue
/// \post if type() was nullValue, it remains nullValue
Members getMemberNames() const;
/// \deprecated Always pass len.
JSONCPP_DEPRECATED("Use setComment(String const&) instead.")
void setComment(const char* comment, CommentPlacement placement) {
setComment(String(comment, strlen(comment)), placement);
}
/// Comments must be //... or /* ... */
void setComment(const char* comment, size_t len, CommentPlacement placement) {
setComment(String(comment, len), placement);
}
/// Comments must be //... or /* ... */
void setComment(String comment, CommentPlacement placement);
bool hasComment(CommentPlacement placement) const;
/// Include delimiters and embedded newlines.
String getComment(CommentPlacement placement) const;
String toStyledString() const;
const_iterator begin() const;
const_iterator end() const;
iterator begin();
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
// which this value was parsed, if any.
void setOffsetStart(ptrdiff_t start);
void setOffsetLimit(ptrdiff_t limit);
ptrdiff_t getOffsetStart() const;
ptrdiff_t getOffsetLimit() const;
private:
void setType(ValueType v) {
bits_.value_type_ = static_cast<unsigned char>(v);
}
bool isAllocated() const { return bits_.allocated_; }
void setIsAllocated(bool v) { bits_.allocated_ = v; }
/*initBasic在声明时参数allocated存在默认参数*/
void initBasic(ValueType type, bool allocated = false);
void dupPayload(const Value& other);
void releasePayload();
void dupMeta(const Value& other);
Value& resolveReference(const char* key);
Value& resolveReference(const char* key, const char* end);
// struct MemberNamesTransform
//{
// typedef const char *result_type;
// const char *operator()( const CZString &name ) const
// {
// return name.c_str();
// }
//};
/*存放值,因为需要各种类型的json数据,使用联合类型来存放*/
union ValueHolder {
LargestInt int_;
LargestUInt uint_;
double real_;
bool bool_;
/*只有bits_.allocated为1时,string中的内容才有效*/
char* string_; // if allocated_, ptr to { unsigned, char[] }.
ObjectValues* map_;
} value_;
struct {
// Really a ValueType, but types should agree for bitfield packing.
/*表明数据类型,int bool,double,char *,map<>*/
unsigned int value_type_ : 8;
// Unless allocated_, string_ must be null-terminated.
unsigned int allocated_ : 1;
} bits_;
class Comments {
public:
/*使用编译器生成的无参构造函数*/
Comments() = default;
Comments(const Comments& that);
Comments(Comments&& that) noexcept;
Comments& operator=(const Comments& that);
Comments& operator=(Comments&& that) noexcept;
bool has(CommentPlacement slot) const;
String get(CommentPlacement slot) const;
void set(CommentPlacement slot, String comment);
private:
using Array = std::array<String, numberOfCommentPlacement>;
std::unique_ptr<Array> ptr_; /*ptr_存放注释内容??*/
};
Comments comments_;
// [start, limit) byte offsets in the source JSON text from which this Value
// was extracted.
ptrdiff_t start_;
ptrdiff_t limit_;
}; //Value类结束
template <> inline bool Value::as<bool>() const { return asBool(); }
template <> inline bool Value::is<bool>() const { return isBool(); }
template <> inline Int Value::as<Int>() const { return asInt(); }
template <> inline bool Value::is<Int>() const { return isInt(); }
template <> inline UInt Value::as<UInt>() const { return asUInt(); }
template <> inline bool Value::is<UInt>() const { return isUInt(); }
#if defined(JSON_HAS_INT64)
template <> inline Int64 Value::as<Int64>() const { return asInt64(); }
template <> inline bool Value::is<Int64>() const { return isInt64(); }
template <> inline UInt64 Value::as<UInt64>() const { return asUInt64(); }
template <> inline bool Value::is<UInt64>() const { return isUInt64(); }
#endif
template <> inline double Value::as<double>() const { return asDouble(); }
template <> inline bool Value::is<double>() const { return isDouble(); }
template <> inline String Value::as<String>() const { return asString(); }
template <> inline bool Value::is<String>() const { return isString(); }
/// These `as` specializations are type conversions, and do not have a
/// corresponding `is`.
template <> inline float Value::as<float>() const { return asFloat(); }
template <> inline const char* Value::as<const char*>() const {
return asCString();
}
/** \brief Experimental and untested: represents an element of the "path" to
* access a node.
*/
class JSON_API PathArgument {
public:
friend class Path;
PathArgument();
PathArgument(ArrayIndex index);
PathArgument(const char* key);
PathArgument(String key);
private:
enum Kind { kindNone = 0, kindIndex, kindKey };
String key_;
ArrayIndex index_{};
Kind kind_{kindNone};
};
/** \brief Experimental and untested: represents a "path" to access a node.
*
* Syntax:
* - "." => root node
* - ".[n]" => elements at index 'n' of root node (an array value)
* - ".name" => member named 'name' of root node (an object value)
* - ".name1.name2.name3"
* - ".[0][1][2].name1[3]"
* - ".%" => member name is provided as parameter
* - ".[%]" => index is provided as parameter
*/
class JSON_API Path {
public:
Path(const String& path, const PathArgument& a1 = PathArgument(),
const PathArgument& a2 = PathArgument(),
const PathArgument& a3 = PathArgument(),
const PathArgument& a4 = PathArgument(),
const PathArgument& a5 = PathArgument());
const Value& resolve(const Value& root) const;
Value resolve(const Value& root, const Value& defaultValue) const;
/// Creates the "path" to access the specified node and returns a reference on
/// the node.
Value& make(Value& root) const;
private:
using InArgs = std::vector<const PathArgument*>;
using Args = std::vector<PathArgument>;
void makePath(const String& path, const InArgs& in);
void addPathInArg(const String& path, const InArgs& in,
InArgs::const_iterator& itInArg, PathArgument::Kind kind);
static void invalidPath(const String& path, int location);
Args args_;
};
/** \brief base class for Value iterators.
*
*/
class JSON_API ValueIteratorBase {
public:
using iterator_category = std::bidirectional_iterator_tag;
using size_t = unsigned int;
using difference_type = int;
using SelfType = ValueIteratorBase;
bool operator==(const SelfType& other) const { return isEqual(other); }
bool operator!=(const SelfType& other) const { return !isEqual(other); }
difference_type operator-(const SelfType& other) const {
return other.computeDistance(*this);
}
/// Return either the index or the member name of the referenced value as a
/// Value.
Value key() const;
/// Return the index of the referenced Value, or -1 if it is not an
/// arrayValue.
UInt index() const;
/// Return the member name of the referenced Value, or "" if it is not an
/// objectValue.
/// \note Avoid `c_str()` on result, as embedded zeroes are possible.
String name() const;
/// Return the member name of the referenced Value. "" if it is not an
/// objectValue.
/// \deprecated This cannot be used for UTF-8 strings, since there can be
/// embedded nulls.
JSONCPP_DEPRECATED("Use `key = name();` instead.")
char const* memberName() const;
/// Return the member name of the referenced Value, or NULL if it is not an
/// objectValue.
/// \note Better version than memberName(). Allows embedded nulls.
char const* memberName(char const** end) const;
protected:
/*! Internal utility functions to assist with implementing
* other iterator functions. The const and non-const versions
* of the "deref" protected methods expose the protected
* current_ member variable in a way that can often be
* optimized away by the compiler.
*/
const Value& deref() const;
Value& deref();
void increment();
void decrement();
difference_type computeDistance(const SelfType& other) const;
bool isEqual(const SelfType& other) const;
void copy(const SelfType& other);
private:
Value::ObjectValues::iterator current_;
// Indicates that iterator is for a null value.
bool isNull_{true};
public:
// For some reason, BORLAND needs these at the end, rather
// than earlier. No idea why.
ValueIteratorBase();
explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
};
/** \brief const iterator for object and array value.
*
*/
class JSON_API ValueConstIterator : public ValueIteratorBase {
friend class Value;
public:
using value_type = const Value;
// typedef unsigned int size_t;
// typedef int difference_type;
using reference = const Value&;
using pointer = const Value*;
using SelfType = ValueConstIterator;
ValueConstIterator();
ValueConstIterator(ValueIterator const& other);
private:
/*! \internal Use by Value to create an iterator.
*/
explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
public:
SelfType& operator=(const ValueIteratorBase& other);
SelfType operator++(int) {
SelfType temp(*this);
++*this;
return temp;
}
SelfType operator--(int) {
SelfType temp(*this);
--*this;
return temp;
}
SelfType& operator--() {
decrement();
return *this;
}
SelfType& operator++() {
increment();
return *this;
}
reference operator*() const { return deref(); }
pointer operator->() const { return &deref(); }
};
/** \brief Iterator for object and array value.
*/
class JSON_API ValueIterator : public ValueIteratorBase {
friend class Value;
public:
using value_type = Value;
using size_t = unsigned int;
using difference_type = int;
using reference = Value&;
using pointer = Value*;
using SelfType = ValueIterator;
ValueIterator();
explicit ValueIterator(const ValueConstIterator& other);
ValueIterator(const ValueIterator& other);
private:
/*! \internal Use by Value to create an iterator.
*/
explicit ValueIterator(const Value::ObjectValues::iterator& current);
public:
SelfType& operator=(const SelfType& other);
SelfType operator++(int) {
SelfType temp(*this);
++*this;
return temp;
}
SelfType operator--(int) {
SelfType temp(*this);
--*this;
return temp;
}
SelfType& operator--() {
decrement();
return *this;
}
SelfType& operator++() {
increment();
return *this;
}
/*! The return value of non-const iterators can be
* changed, so the these functions are not const
* because the returned references/pointers can be used
* to change state of the base class.
*/
reference operator*() const { return const_cast<reference>(deref()); }
pointer operator->() const { return const_cast<pointer>(&deref()); }
};
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
#pragma pack(pop)
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(pop)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#endif // JSON_H_INCLUDED
json_value.cpp内容如下:
// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#if !defined(JSON_IS_AMALGAMATION)
#include <json/assertions.h>
#include <json/value.h>
#include <json/writer.h>
#endif // if !defined(JSON_IS_AMALGAMATION)
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstddef>
#include <cstring>
#include <iostream>
#include <sstream>
#include <utility>
#ifdef JSONCPP_HAS_STRING_VIEW
#include <string_view>
#endif
// Provide implementation equivalent of std::snprintf for older _MSC compilers
#if defined(_MSC_VER) && _MSC_VER < 1900
#include <stdarg.h>
static int msvc_pre1900_c99_vsnprintf(char* outBuf, size_t size,
const char* format, va_list ap) {
int count = -1;
if (size != 0)
count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
if (count == -1)
count = _vscprintf(format, ap);
return count;
}
int JSON_API msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
const char* format, ...) {
va_list ap;
va_start(ap, format);
const int count = msvc_pre1900_c99_vsnprintf(outBuf, size, format, ap);
va_end(ap);
return count;
}
#endif
// Disable warning C4702 : unreachable code
#if defined(_MSC_VER)
#pragma warning(disable : 4702)
#endif
#define JSON_ASSERT_UNREACHABLE assert(false)
namespace Json {
template <typename T>
static std::unique_ptr<T> cloneUnique(const std::unique_ptr<T>& p) {
std::unique_ptr<T> r; /*临时对象*/
if (p) {
/*unique_ptr不支持赋值运算符,这里只能是移动赋值运算符*/
r = std::unique_ptr<T>(new T(*p));
}
return r;
}
// 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
// 8 (instead of 4) as a bit of future-proofing.
#if defined(__ARMEL__)
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
#else
#define ALIGNAS(byte_alignment)
#endif
// static
Value const& Value::nullSingleton() {
static Value const nullStatic;
return nullStatic;
}
#if JSON_USE_NULLREF
// for backwards compatibility, we'll leave these global references around, but
// DO NOT use them in JSONCPP library code any more!
// static
Value const& Value::null = Value::nullSingleton();
// static
Value const& Value::nullRef = Value::nullSingleton();
#endif
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
template <typename T, typename U>
static inline bool InRange(double d, T min, U max) {
// The casts can lose precision, but we are looking only for
// an approximate range. Might fail on edge cases though. ~cdunn
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)
static inline double integerToDouble(Json::UInt64 value) {
/*
double是64位浮点数,遵循IEEE 754标准,其有效数字约为15-17位十进制数。
Json::UInt64是64位无符号整数,范围是0到18446744073709551615(约20位十进制数)。
结论:当value超过2^52 时,直接转换为double会丢失精度(因为 double的尾数部分只能精确表示52位二进制数)。
这个代码写的很隐晦,将value拆分为整数部分和余数部分来处理,value / 2 ,value % 2(value & 1)
但是还是不能避免精度丢失的情况
*/
return static_cast<double>(Int64(value / 2)) * 2.0 +
static_cast<double>(Int64(value & 1));
}
/*函数模板*/
template <typename T> static inline double integerToDouble(T value) {
return static_cast<double>(value);
}
/*函数模板*/
template <typename T, typename U>
static inline bool InRange(double d, T min, U max) {
return d >= integerToDouble(min) && d <= integerToDouble(max)/*d在将min和max转换为double的范围内*/ &&
!(static_cast<U>(d) == min/*将d转为min的类型*/ && d != integerToDouble(min)/*将min转换为d的double类型*/);
}
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
/** Duplicates the specified string value.
* @param value Pointer to the string to duplicate. Must be zero-terminated if
* length is "unknown".
* @param length Length of the value. if equals to unknown, then it will be
* computed using strlen(value).
* @return Pointer on the duplicate instance of string.
*/
/*将value所指内存中的数据拷贝到新内存中,并返回新内存空间地址*/
static inline char* duplicateStringValue(const char* value, size_t length) {
// Avoid an integer overflow in the call to malloc below by limiting length
// to a sane value.
if (length >= static_cast<size_t>(Value::maxInt))
length = Value::maxInt - 1;
auto newString = static_cast<char*>(malloc(length + 1));
if (newString == nullptr) {
throwRuntimeError("in Json::Value::duplicateStringValue(): "
"Failed to allocate string value buffer");
}
memcpy(newString, value, length);
newString[length] = 0;
return newString;
}
/* Record the length as a prefix.
*/
static inline char* duplicateAndPrefixStringValue(const char* value,
unsigned int length) {
// Avoid an integer overflow in the call to malloc below by limiting length
// to a sane value.
JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) -
sizeof(unsigned) - 1U,
"in Json::Value::duplicateAndPrefixStringValue(): "
"length too big for prefixing");
size_t actualLength = sizeof(length) + length + 1;
auto newString = static_cast<char*>(malloc(actualLength));
if (newString == nullptr) {
throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "
"Failed to allocate string value buffer");
}
/*先存放字符长度再存放字符串数据*/
*reinterpret_cast<unsigned*>(newString) = length;
memcpy(newString + sizeof(unsigned), value, length);
newString[actualLength - 1U] =
0; // to avoid buffer over-run accidents by users later
return newString;
}
inline static void decodePrefixedString(bool isPrefixed, char const* prefixed,
unsigned* length, char const** value) {
if (!isPrefixed) { /*不存在前缀长度字段*/
*length = static_cast<unsigned>(strlen(prefixed));
*value = prefixed;
} else { /*存在前缀长度字段*/
*length = *reinterpret_cast<unsigned const*>(prefixed); /*获取前缀长度*/
*value = prefixed + sizeof(unsigned);
}
}
/** Free the string duplicated by
* duplicateStringValue()/duplicateAndPrefixStringValue().
*/
#if JSONCPP_USE_SECURE_MEMORY
/*释放内存空间*/
static inline void releasePrefixedStringValue(char* value) {
unsigned length = 0;
char const* valueDecoded;
decodePrefixedString(true, value, &length, &valueDecoded);
size_t const size = sizeof(unsigned) + length + 1U;
memset(value, 0, size);
free(value);
}
static inline void releaseStringValue(char* value, unsigned length) {
// length==0 => we allocated the strings memory
size_t size = (length == 0) ? strlen(value) : length;
memset(value, 0, size);
free(value);
}
#else // !JSONCPP_USE_SECURE_MEMORY
static inline void releasePrefixedStringValue(char* value) { free(value); }
static inline void releaseStringValue(char* value, unsigned) { free(value); }
#endif // JSONCPP_USE_SECURE_MEMORY
} // namespace Json
// //
// //
// //
// ValueInternals...
// //
// //
// //
#if !defined(JSON_IS_AMALGAMATION)
#include "json_valueiterator.inl"
#endif // if !defined(JSON_IS_AMALGAMATION)
namespace Json {
#if JSON_USE_EXCEPTION
Exception::Exception(String msg) : msg_(std::move(msg)) {}
Exception::~Exception() noexcept = default;
char const* Exception::what() const noexcept { return msg_.c_str(); }
RuntimeError::RuntimeError(String const& msg) : Exception(msg) {}
LogicError::LogicError(String const& msg) : Exception(msg) {}
JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
throw RuntimeError(msg);
}
JSONCPP_NORETURN void throwLogicError(String const& msg) {
throw LogicError(msg);
}
#else // !JSON_USE_EXCEPTION
JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
std::cerr << msg << std::endl;
abort();
}
JSONCPP_NORETURN void throwLogicError(String const& msg) {
std::cerr << msg << std::endl;
abort();
}
#endif
// //
// //
// //
// class Value::CZString
// //
// //
// //
// Notes: policy_ indicates if the string was allocated when
// a string is stored.
/*CZString类构造函数实现*/
Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {}
Value::CZString::CZString(char const* str, unsigned length,
DuplicationPolicy allocate)
: cstr_(str) {
// allocate != duplicate
storage_.policy_ = allocate & 0x3;
storage_.length_ = length & 0x3FFFFFFF;
}
/*拷贝构造函数*/
Value::CZString::CZString(const CZString& other) {
/*如果other的存储策略为不允许复制的化,则使用同一片存储空间,如果申请一块新的内存空间将other的值拷贝到该空间并返回空间地址*/
cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr
? duplicateStringValue(other.cstr_, other.storage_.length_)
: other.cstr_);
storage_.policy_ =
static_cast<unsigned>(
other.cstr_
? (static_cast<DuplicationPolicy>(other.storage_.policy_) ==
noDuplication
? noDuplication
: duplicate)
: static_cast<DuplicationPolicy>(other.storage_.policy_)) &
3U;
storage_.length_ = other.storage_.length_;
}
/*移动构造函数*/
Value::CZString::CZString(CZString&& other) noexcept
: cstr_(other.cstr_), index_(other.index_) {
other.cstr_ = nullptr;
}
/*析构函数*/
Value::CZString::~CZString() {
if (cstr_ && storage_.policy_ == duplicate) { /*析构函数中只有policy为duplicate时才能释放分配的内存空间*/
releaseStringValue(const_cast<char*>(cstr_),
storage_.length_ + 1U); // +1 for null terminating
// character for sake of
// completeness but not actually
// necessary
}
}
void Value::CZString::swap(CZString& other) {
std::swap(cstr_, other.cstr_);
std::swap(index_, other.index_);
}
/*赋值运算符*/
Value::CZString& Value::CZString::operator=(const CZString& other) {
cstr_ = other.cstr_;
index_ = other.index_;
return *this;
}
/*移动赋值运算符*/
Value::CZString& Value::CZString::operator=(CZString&& other) noexcept {
cstr_ = other.cstr_;
index_ = other.index_;
other.cstr_ = nullptr;
return *this;
}
/*因为Value类的map中的键值为CZString类,所以CZString类必须实现比较运算符*/
/*<运算符*/
bool Value::CZString::operator<(const CZString& other) const {
if (!cstr_) /*如果cstr_无效则直接比较index*/
return index_ < other.index_;
// return strcmp(cstr_, other.cstr_) < 0;
// Assume both are strings.
unsigned this_len = this->storage_.length_;
unsigned other_len = other.storage_.length_;
/*取两者之间长度最小的长度作为比较长度*/
unsigned min_len = std::min<unsigned>(this_len, other_len);
JSON_ASSERT(this->cstr_ && other.cstr_);
int comp = memcmp(this->cstr_, other.cstr_, min_len);
if (comp < 0)
return true;
if (comp > 0)
return false;
return (this_len < other_len);
}
/*==运算符*/
bool Value::CZString::operator==(const CZString& other) const {
if (!cstr_) /*如果cstr_无效则直接比较index*/
return index_ == other.index_;
// return strcmp(cstr_, other.cstr_) == 0;
// Assume both are strings.
unsigned this_len = this->storage_.length_;
unsigned other_len = other.storage_.length_;
if (this_len != other_len)
return false;
JSON_ASSERT(this->cstr_ && other.cstr_);
int comp = memcmp(this->cstr_, other.cstr_, this_len);
return comp == 0;
}
ArrayIndex Value::CZString::index() const { return index_; }
// const char* Value::CZString::c_str() const { return cstr_; }
const char* Value::CZString::data() const { return cstr_; }
unsigned Value::CZString::length() const { return storage_.length_; }
bool Value::CZString::isStaticString() const {
return storage_.policy_ == noDuplication;
}
// //
// //
// //
// class Value::Value
// //
// //
// //
/*! \internal Default constructor initialization must be equivalent to:
* memset( this, 0, sizeof(Value) )
* This optimization is used in ValueInternalMap fast allocator.
*/
/*Value类构造函数实现*/
Value::Value(ValueType type) {
static char const emptyString[] = "";
initBasic(type);
switch (type) {
case nullValue:
break;
case intValue:
case uintValue:
value_.int_ = 0;
break;
case realValue:
value_.real_ = 0.0;
break;
case stringValue:
// allocated_ == false, so this is safe.
value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString));
break;
case arrayValue:
case objectValue:
value_.map_ = new ObjectValues();
break;
case booleanValue:
value_.bool_ = false;
break;
default:
JSON_ASSERT_UNREACHABLE;
}
}
Value::Value(Int value) {
initBasic(intValue);
value_.int_ = value;
}
Value::Value(UInt value) {
initBasic(uintValue);
value_.uint_ = value;
}
#if defined(JSON_HAS_INT64)
Value::Value(Int64 value) {
initBasic(intValue);
value_.int_ = value;
}
Value::Value(UInt64 value) {
initBasic(uintValue);
value_.uint_ = value;
}
#endif // defined(JSON_HAS_INT64)
Value::Value(double value) {
initBasic(realValue);
value_.real_ = value;
}
Value::Value(const char* value) {
initBasic(stringValue, true);
JSON_ASSERT_MESSAGE(value != nullptr,
"Null Value Passed to Value Constructor");
/*存在前缀即字符串的长度*/
value_.string_ = duplicateAndPrefixStringValue(
value, static_cast<unsigned>(strlen(value))/*使用C++的强制类型转换*/);
}
Value::Value(const char* begin, const char* end) {
initBasic(stringValue, true);
value_.string_ =
duplicateAndPrefixStringValue(begin, static_cast<unsigned>(end - begin));
}
Value::Value(const String& value) {
initBasic(stringValue, true);
value_.string_ = duplicateAndPrefixStringValue(
value.data(), static_cast<unsigned>(value.length()));
}
#ifdef JSONCPP_HAS_STRING_VIEW
Value::Value(std::string_view value) {
initBasic(stringValue, true);
value_.string_ = duplicateAndPrefixStringValue(
value.data(), static_cast<unsigned>(value.length()));
}
#endif
Value::Value(const StaticString& value) {
initBasic(stringValue);
value_.string_ = const_cast<char*>(value.c_str());
}
Value::Value(bool value) {
initBasic(booleanValue);
value_.bool_ = value;
}
/*拷贝构造函数*/
Value::Value(const Value& other) {
dupPayload(other);
dupMeta(other);
}
/*移动构造函数*/
Value::Value(Value&& other) noexcept {
initBasic(nullValue);
swap(other);
}
/*析构函数*/
Value::~Value() {
releasePayload();
value_.uint_ = 0;
}
/*赋值运算符*/
Value& Value::operator=(const Value& other) {
Value(other).swap(*this);
return *this;
}
/*移动赋值运算符*/
Value& Value::operator=(Value&& other) noexcept {
other.swap(*this);
return *this;
}
/*交换bits和value数据成员*/
void Value::swapPayload(Value& other) {
std::swap(bits_, other.bits_);
std::swap(value_, other.value_);
}
void Value::copyPayload(const Value& other) {
/*释放this中存放的数据*/
releasePayload();
dupPayload(other);
}
/*实现Value类的swap函数*/
void Value::swap(Value& other) {
swapPayload(other);
std::swap(comments_, other.comments_);
std::swap(start_, other.start_);
std::swap(limit_, other.limit_);
}
void Value::copy(const Value& other) {
copyPayload(other);
dupMeta(other);
}
ValueType Value::type() const {
return static_cast<ValueType>(bits_.value_type_);
}
int Value::compare(const Value& other) const {
if (*this < other)
return -1;
if (*this > other)
return 1;
return 0;
}
/*<运算符*/
bool Value::operator<(const Value& other) const {
int typeDelta = type() - other.type();
if (typeDelta) /*类型不同原则上不能进行比较*/
return typeDelta < 0;
switch (type()) {
case nullValue:
return false;
case intValue:
return value_.int_ < other.value_.int_;
case uintValue:
return value_.uint_ < other.value_.uint_;
case realValue:
return value_.real_ < other.value_.real_;
case booleanValue:
return value_.bool_ < other.value_.bool_;
case stringValue: {
if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
return other.value_.string_ != nullptr;
}
unsigned this_len;
unsigned other_len;
char const* this_str;
char const* other_str;
decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
&this_str);
decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
&other_str);
/*感觉具有一定的意义,先比较min长度部分的字符,再根据长度来判断*/
unsigned min_len = std::min<unsigned>(this_len, other_len);
JSON_ASSERT(this_str && other_str);
int comp = memcmp(this_str, other_str, min_len);
if (comp < 0)
return true;
if (comp > 0)
return false;
return (this_len < other_len);
}
case arrayValue:
case objectValue: {
auto thisSize = value_.map_->size();
auto otherSize = other.value_.map_->size();
if (thisSize != otherSize)
return thisSize < otherSize;
return (*value_.map_) < (*other.value_.map_);
}
default:
JSON_ASSERT_UNREACHABLE;
}
return false; // unreachable
}
/*下面运算符的实现基于前面的<小于运算符*/
bool Value::operator<=(const Value& other) const { return !(other < *this); }
bool Value::operator>=(const Value& other) const { return !(*this < other); }
bool Value::operator>(const Value& other) const { return other < *this; }
bool Value::operator==(const Value& other) const {
if (type() != other.type())
return false; /*原则上类型相同才能进行比较*/
switch (type()) {
case nullValue:
return true;
case intValue:
return value_.int_ == other.value_.int_;
case uintValue:
return value_.uint_ == other.value_.uint_;
case realValue:
return value_.real_ == other.value_.real_;
case booleanValue:
return value_.bool_ == other.value_.bool_;
case stringValue: {
if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
return (value_.string_ == other.value_.string_);
}
unsigned this_len;
unsigned other_len;
char const* this_str;
char const* other_str;
decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
&this_str);
decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
&other_str);
if (this_len != other_len)
return false;
JSON_ASSERT(this_str && other_str);
int comp = memcmp(this_str, other_str, this_len);
return comp == 0;
}
case arrayValue:
case objectValue:
return value_.map_->size() == other.value_.map_->size() &&
(*value_.map_) == (*other.value_.map_);
default:
JSON_ASSERT_UNREACHABLE;
}
return false; // unreachable
}
bool Value::operator!=(const Value& other) const { return !(*this == other); }
/*返回Value中的字符串类型的数据*/
const char* Value::asCString() const {
JSON_ASSERT_MESSAGE(type() == stringValue,
"in Json::Value::asCString(): requires stringValue");
if (value_.string_ == nullptr)
return nullptr;
unsigned this_len;
char const* this_str;
/*返回解码出有效字符串的位置*/
decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
&this_str);
return this_str;
}
#if JSONCPP_USE_SECURE_MEMORY
unsigned Value::getCStringLength() const {
JSON_ASSERT_MESSAGE(type() == stringValue,
"in Json::Value::asCString(): requires stringValue");
if (value_.string_ == 0)
return 0;
unsigned this_len;
char const* this_str;
decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
&this_str);
return this_len;
}
#endif
/*
返回Value中字符串类型数据的起始和结束位置
注意:begin和end为二级指针
*/
bool Value::getString(char const** begin, char const** end) const {
if (type() != stringValue)
return false;
if (value_.string_ == nullptr)
return false;
unsigned length;
decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
begin);
*end = *begin + length;
return true;
}
#ifdef JSONCPP_HAS_STRING_VIEW
bool Value::getString(std::string_view* str) const {
if (type() != stringValue)
return false;
if (value_.string_ == nullptr)
return false;
const char* begin;
unsigned length;
decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
&begin);
*str = std::string_view(begin, length);
return true;
}
#endif
/*返回的类型为String*/
String Value::asString() const {
switch (type()) {
case nullValue:
return "";
case stringValue: {
if (value_.string_ == nullptr)
return "";
unsigned this_len;
char const* this_str;
decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
&this_str);
/*返回匿名对象String*/
return String(this_str, this_len);
}
case booleanValue:
return value_.bool_ ? "true" : "false";
case intValue:
return valueToString(value_.int_);
case uintValue:
return valueToString(value_.uint_);
case realValue:
return valueToString(value_.real_);
default:
JSON_FAIL_MESSAGE("Type is not convertible to string");
}
}
/*返回的类型为int*/
Value::Int Value::asInt() const {
switch (type()) {
case intValue:
JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
return Int(value_.int_);
case uintValue:
JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
return Int(value_.uint_);
case realValue:
JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
"double out of Int range");
return Int(value_.real_);
case nullValue:
return 0;
case booleanValue:
return value_.bool_ ? 1 : 0;
default:
break;
}
JSON_FAIL_MESSAGE("Value is not convertible to Int.");
}
/*返回的类型为uint*/
Value::UInt Value::asUInt() const {
switch (type()) {
case intValue:
JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
return UInt(value_.int_);
case uintValue:
JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
return UInt(value_.uint_);
case realValue:
JSON_ASSERT_MESSAGE(InRange(value_.real_, 0u, maxUInt),
"double out of UInt range");
return UInt(value_.real_);
case nullValue:
return 0;
case booleanValue:
return value_.bool_ ? 1 : 0;
default:
break;
}
JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
}
#if defined(JSON_HAS_INT64)
Value::Int64 Value::asInt64() const {
switch (type()) {
case intValue:
return Int64(value_.int_);
case uintValue:
JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
return Int64(value_.uint_);
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),
"double out of Int64 range");
return Int64(value_.real_);
case nullValue:
return 0;
case booleanValue:
return value_.bool_ ? 1 : 0;
default:
break;
}
JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
}
Value::UInt64 Value::asUInt64() const {
switch (type()) {
case intValue:
JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
return UInt64(value_.int_);
case uintValue:
return UInt64(value_.uint_);
case realValue:
JSON_ASSERT_MESSAGE(InRange(value_.real_, 0u, maxUInt64),
"double out of UInt64 range");
return UInt64(value_.real_);
case nullValue:
return 0;
case booleanValue:
return value_.bool_ ? 1 : 0;
default:
break;
}
JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
}
#endif // if defined(JSON_HAS_INT64)
LargestInt Value::asLargestInt() const {
#if defined(JSON_NO_INT64)
return asInt();
#else
return asInt64();
#endif
}
LargestUInt Value::asLargestUInt() const {
#if defined(JSON_NO_INT64)
return asUInt();
#else
return asUInt64();
#endif
}
double Value::asDouble() const {
switch (type()) {
case intValue:
return static_cast<double>(value_.int_);
case uintValue:
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
return static_cast<double>(value_.uint_);
#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
return integerToDouble(value_.uint_);
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
case realValue:
return value_.real_;
case nullValue:
return 0.0; /*空指针返回0.0*/
case booleanValue:
return value_.bool_ ? 1.0 : 0.0; /*bool类型*/
default:
break;
}
JSON_FAIL_MESSAGE("Value is not convertible to double.");
}
float Value::asFloat() const {
switch (type()) {
case intValue:
return static_cast<float>(value_.int_);
case uintValue:
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
return static_cast<float>(value_.uint_);
#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
// This can fail (silently?) if the value is bigger than MAX_FLOAT.
return static_cast<float>(integerToDouble(value_.uint_));
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
case realValue:
return static_cast<float>(value_.real_);
case nullValue:
return 0.0;
case booleanValue:
return value_.bool_ ? 1.0F : 0.0F;
default:
break;
}
JSON_FAIL_MESSAGE("Value is not convertible to float.");
}
/*将value的值返回为bool类型*/
bool Value::asBool() const {
switch (type()) {
case booleanValue:
return value_.bool_;
case nullValue:
return false;
case intValue:
return value_.int_ != 0;
case uintValue:
return value_.uint_ != 0;
case realValue: {
// According to JavaScript language zero or NaN is regarded as false
/*
NaN(Not a Number)是浮点数的特殊值,表示“未定义或不可表示的数值”(如 0/0、sqrt(-1))。
在布尔上下文中,NaN会被隐式转换为false,但这是通过operator bool()的隐式转换规则实现的,而非直接比较。
std::fpclassify是C++标准库(<cmath>)中的一个函数,用于对浮点数进行分类,判断其属于哪一类特殊值(如正常数、零、无穷大、NaN 等)。
它是处理浮点数状态检测的核心工具之一。
*/
/*浮点数是否为bool的判断方法*/
const auto value_classification = std::fpclassify(value_.real_);
return value_classification != FP_ZERO && value_classification != FP_NAN;
}
default:
break;
}
JSON_FAIL_MESSAGE("Value is not convertible to bool.");
}
/*Value的值能够转换为other的类型*/
bool Value::isConvertibleTo(ValueType other) const {
switch (other) {
case nullValue:
return (isNumeric() && asDouble() == 0.0) ||
(type() == booleanValue && !value_.bool_)/*bool类型,值为false*/ ||
(type() == stringValue && asString().empty())/*字符串类型,为空*/ ||
(type() == arrayValue && value_.map_->empty()) ||
(type() == objectValue && value_.map_->empty()) ||
type() == nullValue;
case intValue:
return isInt() ||
(type() == realValue && InRange(value_.real_, minInt, maxInt)) ||
type() == booleanValue || type() == nullValue;
case uintValue:
return isUInt() ||
(type() == realValue && InRange(value_.real_, 0u, maxUInt)) ||
type() == booleanValue || type() == nullValue;
case realValue:
return isNumeric() || type() == booleanValue || type() == nullValue;
case booleanValue:
return isNumeric() || type() == booleanValue || type() == nullValue;
case stringValue:
return isNumeric() || type() == booleanValue || type() == stringValue ||
type() == nullValue;
case arrayValue:
return type() == arrayValue || type() == nullValue;
case objectValue:
return type() == objectValue || type() == nullValue;
}
JSON_ASSERT_UNREACHABLE;
return false;
}
/// Number of values in array or object
ArrayIndex Value::size() const {
switch (type()) {
case nullValue:
case intValue:
case uintValue:
case realValue:
case booleanValue:
case stringValue:
return 0;
case arrayValue: // size of the array is highest index + 1
if (!value_.map_->empty()) { /*map中存在数据*/
ObjectValues::const_iterator itLast = value_.map_->end();
--itLast;
return (*itLast).first.index() + 1; /*+1?? index是从0开始计数*/
}
return 0;
case objectValue:
return ArrayIndex(value_.map_->size());
}
JSON_ASSERT_UNREACHABLE;
return 0; // unreachable;
}
bool Value::empty() const {
if (isNull() || isArray() || isObject())
return size() == 0U;
return false;
}
/*强制类型转换操作符bool*/
Value::operator bool() const { return !isNull(); }
void Value::clear() {
JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue ||
type() == objectValue,
"in Json::Value::clear(): requires complex value");
start_ = 0;
limit_ = 0;
switch (type()) {
case arrayValue:
case objectValue:
value_.map_->clear();
break;
default:
break;
}
}
void Value::resize(ArrayIndex newSize) {
JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
"in Json::Value::resize(): requires arrayValue");
if (type() == nullValue)
*this = Value(arrayValue);
ArrayIndex oldSize = size();
if (newSize == 0)
clear();
else if (newSize > oldSize)
for (ArrayIndex i = oldSize; i < newSize; ++i)
(*this)[i]; /*下标运算符的操作*/
else {
for (ArrayIndex index = newSize; index < oldSize; ++index) {
value_.map_->erase(index);
}
JSON_ASSERT(size() == newSize);
}
}
/*
[]下标运算符,通过index来查找对应
下面四个函数构成下标运算符[]的重载
*/
Value& Value::operator[](ArrayIndex index) {
JSON_ASSERT_MESSAGE(
type() == nullValue || type() == arrayValue,
"in Json::Value::operator[](ArrayIndex): requires arrayValue");
if (type() == nullValue)
*this = Value(arrayValue);
CZString key(index); /*使用index初始化CZString key*/
auto it = value_.map_->lower_bound(key); /*再从map中查找key,那么类需要实现<等比较运算符*/
if (it != value_.map_->end() && (*it).first == key)
return (*it).second; /*返回key对应的Value值*/
/*没有找到则构造一个默认初始化的pair<key,value>到map中*/
ObjectValues::value_type defaultValue(key, nullSingleton());
it = value_.map_->insert(it, defaultValue);
return (*it).second;
}
/*[]下标运算符重载,这个[]调用前面实现的[]运算符*/
Value& Value::operator[](int index) {
JSON_ASSERT_MESSAGE(
index >= 0,
"in Json::Value::operator[](int index): index cannot be negative");
return (*this)[ArrayIndex(index)]; /*将index强转为ArrayIndex来调用前面实现的下标运算符[]*/
}
const Value& Value::operator[](ArrayIndex index) const {
JSON_ASSERT_MESSAGE(
type() == nullValue || type() == arrayValue,
"in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
if (type() == nullValue)
return nullSingleton();
CZString key(index);
ObjectValues::const_iterator it = value_.map_->find(key);
if (it == value_.map_->end())
return nullSingleton();
return (*it).second;
}
const Value& Value::operator[](int index) const {
JSON_ASSERT_MESSAGE(
index >= 0,
"in Json::Value::operator[](int index) const: index cannot be negative");
return (*this)[ArrayIndex(index)];
}
void Value::initBasic(ValueType type, bool allocated) {
setType(type);
setIsAllocated(allocated);
comments_ = Comments{}; /*匿名对象*/
start_ = 0;
limit_ = 0;
}
void Value::dupPayload(const Value& other) {
setType(other.type());
setIsAllocated(false);
switch (type()) {
case nullValue:
case intValue:
case uintValue:
case realValue:
case booleanValue:
value_ = other.value_;
break;
case stringValue:
if (other.value_.string_ && other.isAllocated()) {
unsigned len;
char const* str;
decodePrefixedString(other.isAllocated(), other.value_.string_, &len,
&str);
value_.string_ = duplicateAndPrefixStringValue(str, len);
setIsAllocated(true);
} else {
value_.string_ = other.value_.string_;
}
break;
case arrayValue:
case objectValue:
value_.map_ = new ObjectValues(*other.value_.map_);
break;
default:
JSON_ASSERT_UNREACHABLE;
}
}
void Value::releasePayload() {
switch (type()) {
case nullValue:
case intValue:
case uintValue:
case realValue:
case booleanValue:
break;
case stringValue:
if (isAllocated())
releasePrefixedStringValue(value_.string_);
break;
case arrayValue:
case objectValue:
delete value_.map_; //使用new分配的空间,这里使用delete进行释放
break;
default:
JSON_ASSERT_UNREACHABLE;
}
}
void Value::dupMeta(const Value& other) {
comments_ = other.comments_;
start_ = other.start_;
limit_ = other.limit_;
}
// Access an object value by name, create a null member if it does not exist.
// @pre Type of '*this' is object or null.
// @param key is null-terminated.
Value& Value::resolveReference(const char* key) {
JSON_ASSERT_MESSAGE(
type() == nullValue || type() == objectValue,
"in Json::Value::resolveReference(): requires objectValue");
if (type() == nullValue)
*this = Value(objectValue);
CZString actualKey(key, static_cast<unsigned>(strlen(key)),
CZString::noDuplication); /*policy为noDuplication,不进行空间分配*/
auto it = value_.map_->lower_bound(actualKey);
if (it != value_.map_->end() && (*it).first == actualKey)
return (*it).second;
ObjectValues::value_type defaultValue(actualKey, nullSingleton());
it = value_.map_->insert(it, defaultValue);
Value& value = (*it).second;
return value;
}
// @param key is not null-terminated.
Value& Value::resolveReference(char const* key, char const* end) {
JSON_ASSERT_MESSAGE(
type() == nullValue || type() == objectValue,
"in Json::Value::resolveReference(key, end): requires objectValue");
if (type() == nullValue)
*this = Value(objectValue);
CZString actualKey(key, static_cast<unsigned>(end - key),
CZString::duplicateOnCopy);
auto it = value_.map_->lower_bound(actualKey);
if (it != value_.map_->end() && (*it).first == actualKey)
return (*it).second;
ObjectValues::value_type defaultValue(actualKey, nullSingleton());
it = value_.map_->insert(it, defaultValue);
Value& value = (*it).second;
return value;
}
Value Value::get(ArrayIndex index, const Value& defaultValue) const {
const Value* value = &((*this)[index]);
return value == &nullSingleton() ? defaultValue : *value;
}
bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
Value const* Value::find(char const* begin, char const* end) const {
JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
"in Json::Value::find(begin, end): requires "
"objectValue or nullValue");
if (type() == nullValue)
return nullptr;
CZString actualKey(begin, static_cast<unsigned>(end - begin),
CZString::noDuplication);
ObjectValues::const_iterator it = value_.map_->find(actualKey);
if (it == value_.map_->end())
return nullptr;
return &(*it).second;
}
Value const* Value::find(const String& key) const {
return find(key.data(), key.data() + key.length());
}
Value const* Value::findNull(const String& key) const {
return findValue<Value, &Value::isNull>(key);
}
Value const* Value::findBool(const String& key) const {
return findValue<Value, &Value::isBool>(key);
}
Value const* Value::findInt(const String& key) const {
return findValue<Value, &Value::isInt>(key);
}
Value const* Value::findInt64(const String& key) const {
return findValue<Value, &Value::isInt64>(key);
}
Value const* Value::findUInt(const String& key) const {
return findValue<Value, &Value::isUInt>(key);
}
Value const* Value::findUInt64(const String& key) const {
return findValue<Value, &Value::isUInt64>(key);
}
Value const* Value::findIntegral(const String& key) const {
return findValue<Value, &Value::isIntegral>(key);
}
Value const* Value::findDouble(const String& key) const {
return findValue<Value, &Value::isDouble>(key);
}
Value const* Value::findNumeric(const String& key) const {
return findValue<Value, &Value::isNumeric>(key);
}
Value const* Value::findString(const String& key) const {
return findValue<Value, &Value::isString>(key);
}
Value const* Value::findArray(const String& key) const {
return findValue<Value, &Value::isArray>(key);
}
Value const* Value::findObject(const String& key) const {
return findValue<Value, &Value::isObject>(key);
}
Value* Value::demand(char const* begin, char const* end) {
JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
"in Json::Value::demand(begin, end): requires "
"objectValue or nullValue");
return &resolveReference(begin, end);
}
#ifdef JSONCPP_HAS_STRING_VIEW
const Value& Value::operator[](std::string_view key) const {
Value const* found = find(key.data(), key.data() + key.length());
if (!found)
return nullSingleton();
return *found;
}
Value& Value::operator[](std::string_view key) {
return resolveReference(key.data(), key.data() + key.length());
}
#else
/*
const Value& 和 Value const& 写法上是等价的表示两者都表示一个对Value类型对象的常量引用
*/
const Value& Value::operator[](const char* key) const {
Value const* found = find(key, key + strlen(key));
if (!found)
return nullSingleton();
return *found;
}
Value const& Value::operator[](const String& key) const {
Value const* found = find(key);
if (!found)
return nullSingleton();
return *found;
}
Value& Value::operator[](const char* key) {
return resolveReference(key, key + strlen(key));
}
Value& Value::operator[](const String& key) {
return resolveReference(key.data(), key.data() + key.length());
}
#endif
Value& Value::operator[](const StaticString& key) {
return resolveReference(key.c_str());
}
Value& Value::append(const Value& value) { return append(Value(value)); }
Value& Value::append(Value&& value) {
JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
"in Json::Value::append: requires arrayValue");
if (type() == nullValue) {
*this = Value(arrayValue);
}
return this->value_.map_->emplace(size(), std::move(value)).first->second;
}
bool Value::insert(ArrayIndex index, const Value& newValue) {
return insert(index, Value(newValue));
}
bool Value::insert(ArrayIndex index, Value&& newValue) {
JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
"in Json::Value::insert: requires arrayValue");
ArrayIndex length = size();
if (index > length) { /*越界判断*/
return false;
}
/*length处的数据是不是丢失了????*/
for (ArrayIndex i = length; i > index; i--) {
(*this)[i] = std::move((*this)[i - 1]);
}
(*this)[index] = std::move(newValue);
return true;
}
Value Value::get(char const* begin, char const* end,
Value const& defaultValue) const {
Value const* found = find(begin, end);
return !found ? defaultValue : *found;
}
#ifdef JSONCPP_HAS_STRING_VIEW
Value Value::get(std::string_view key, const Value& defaultValue) const {
return get(key.data(), key.data() + key.length(), defaultValue);
}
#else
Value Value::get(char const* key, Value const& defaultValue) const {
return get(key, key + strlen(key), defaultValue);
}
Value Value::get(String const& key, Value const& defaultValue) const {
return get(key.data(), key.data() + key.length(), defaultValue);
}
#endif
bool Value::removeMember(const char* begin, const char* end, Value* removed) {
if (type() != objectValue) {
return false;
}
CZString actualKey(begin, static_cast<unsigned>(end - begin),
CZString::noDuplication);
auto it = value_.map_->find(actualKey);
if (it == value_.map_->end())
return false;
if (removed)
*removed = std::move(it->second);
value_.map_->erase(it);
return true;
}
#ifdef JSONCPP_HAS_STRING_VIEW
bool Value::removeMember(std::string_view key, Value* removed) {
return removeMember(key.data(), key.data() + key.length(), removed);
}
#else
bool Value::removeMember(const char* key, Value* removed) {
return removeMember(key, key + strlen(key), removed);
}
bool Value::removeMember(String const& key, Value* removed) {
return removeMember(key.data(), key.data() + key.length(), removed);
}
#endif
#ifdef JSONCPP_HAS_STRING_VIEW
void Value::removeMember(std::string_view key) {
JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
"in Json::Value::removeMember(): requires objectValue");
if (type() == nullValue)
return;
CZString actualKey(key.data(), unsigned(key.length()),
CZString::noDuplication);
value_.map_->erase(actualKey);
}
#else
void Value::removeMember(const char* key) {
JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
"in Json::Value::removeMember(): requires objectValue");
if (type() == nullValue)
return;
CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication);
value_.map_->erase(actualKey);
}
void Value::removeMember(const String& key) { removeMember(key.c_str()); }
#endif
bool Value::removeIndex(ArrayIndex index, Value* removed) {
if (type() != arrayValue) {
return false;
}
CZString key(index);
auto it = value_.map_->find(key);
if (it == value_.map_->end()) {
return false;
}
if (removed)
*removed = std::move(it->second);
ArrayIndex oldSize = size();
// shift left all items left, into the place of the "removed"
for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
CZString keey(i);
(*value_.map_)[keey] = (*this)[i + 1];
}
// erase the last one ("leftover")
CZString keyLast(oldSize - 1);
auto itLast = value_.map_->find(keyLast);
value_.map_->erase(itLast);
return true;
}
bool Value::isMember(char const* begin, char const* end) const {
Value const* value = find(begin, end);
return nullptr != value;
}
#ifdef JSONCPP_HAS_STRING_VIEW
bool Value::isMember(std::string_view key) const {
return isMember(key.data(), key.data() + key.length());
}
#else
bool Value::isMember(char const* key) const {
return isMember(key, key + strlen(key));
}
bool Value::isMember(String const& key) const {
return isMember(key.data(), key.data() + key.length());
}
#endif
Value::Members Value::getMemberNames() const {
JSON_ASSERT_MESSAGE(
type() == nullValue || type() == objectValue,
"in Json::Value::getMemberNames(), value must be objectValue");
if (type() == nullValue)
return Value::Members();
Members members;
members.reserve(value_.map_->size());
ObjectValues::const_iterator it = value_.map_->begin();
ObjectValues::const_iterator itEnd = value_.map_->end();
for (; it != itEnd; ++it) {
members.push_back(String((*it).first.data(), (*it).first.length()));
}
return members;
}
/*
modf是C/C++标准库中的一个数学函数,用于分解浮点数为整数部分和小数部分,两部分的符号与原浮点数相同。
double modf(double x, double* intpart);
float modff(float x, float* intpart);
long double modfl(long double x, long double* intpart);
*/
static bool IsIntegral(double d) {
double integral_part;
/*将浮点数d的整数部分和小数部分进行拆分后来判断小数部分是不是等于0.0*/
return modf(d, &integral_part) == 0.0;
}
bool Value::isNull() const { return type() == nullValue; }
bool Value::isBool() const { return type() == booleanValue; }
bool Value::isInt() const {
switch (type()) {
case intValue:
#if defined(JSON_HAS_INT64)
return value_.int_ >= minInt && value_.int_ <= maxInt;
#else
return true;
#endif
case uintValue:
return value_.uint_ <= UInt(maxInt);
case realValue:
return value_.real_ >= minInt && value_.real_ <= maxInt &&
IsIntegral(value_.real_); /*整数*/
default:
break;
}
return false;
}
bool Value::isUInt() const {
switch (type()) {
case intValue:
#if defined(JSON_HAS_INT64)
return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
#else
return value_.int_ >= 0;
#endif
case uintValue:
#if defined(JSON_HAS_INT64)
return value_.uint_ <= maxUInt;
#else
return true;
#endif
case realValue:
return value_.real_ >= 0 && value_.real_ <= maxUInt &&
IsIntegral(value_.real_);
default:
break;
}
return false;
}
bool Value::isInt64() const {
#if defined(JSON_HAS_INT64)
switch (type()) {
case intValue:
return true;
case uintValue:
return value_.uint_ <= UInt64(maxInt64);
case realValue:
// 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
// require the value to be strictly less than the limit.
// 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_ < double(maxInt64) &&
IsIntegral(value_.real_);
default:
break;
}
#endif // JSON_HAS_INT64
return false;
}
bool Value::isUInt64() const {
#if defined(JSON_HAS_INT64)
switch (type()) {
case intValue:
return value_.int_ >= 0;
case uintValue:
return true;
case realValue:
// 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
// require the value to be strictly less than the limit.
return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
IsIntegral(value_.real_);
default:
break;
}
#endif // JSON_HAS_INT64
return false;
}
bool Value::isIntegral() const {
switch (type()) {
case intValue:
case uintValue:
return true;
case realValue:
#if defined(JSON_HAS_INT64)
// 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
// require the value to be strictly less than the limit.
// 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_);
#else
return value_.real_ >= minInt && value_.real_ <= maxUInt &&
IsIntegral(value_.real_);
#endif // JSON_HAS_INT64
default:
break;
}
return false;
}
bool Value::isDouble() const {
/*整数也算double*/
return type() == intValue || type() == uintValue || type() == realValue;
}
bool Value::isNumeric() const { return isDouble(); }
bool Value::isString() const { return type() == stringValue; }
bool Value::isArray() const { return type() == arrayValue; }
bool Value::isObject() const { return type() == objectValue; }
Value::Comments::Comments(const Comments& that)
: ptr_{cloneUnique(that.ptr_)} {}
Value::Comments::Comments(Comments&& that) noexcept
: ptr_{std::move(that.ptr_)} {}
Value::Comments& Value::Comments::operator=(const Comments& that) {
ptr_ = cloneUnique(that.ptr_);
return *this;
}
Value::Comments& Value::Comments::operator=(Comments&& that) noexcept {
ptr_ = std::move(that.ptr_);
return *this;
}
bool Value::Comments::has(CommentPlacement slot) const {
return ptr_ && !(*ptr_)[slot].empty();
}
String Value::Comments::get(CommentPlacement slot) const {
if (!ptr_)
return {};
return (*ptr_)[slot];
}
void Value::Comments::set(CommentPlacement slot, String comment) {
if (slot >= CommentPlacement::numberOfCommentPlacement)
return;
if (!ptr_)
ptr_ = std::unique_ptr<Array>(new Array());
(*ptr_)[slot] = std::move(comment);
}
void Value::setComment(String comment, CommentPlacement placement) {
if (!comment.empty() && (comment.back() == '\n')) {
// Always discard trailing newline, to aid indentation.
comment.pop_back();
}
JSON_ASSERT_MESSAGE(
comment.empty() || comment[0] == '/',
"in Json::Value::setComment(): Comments must start with /");
comments_.set(placement, std::move(comment));
}
bool Value::hasComment(CommentPlacement placement) const {
return comments_.has(placement);
}
String Value::getComment(CommentPlacement placement) const {
return comments_.get(placement);
}
void Value::setOffsetStart(ptrdiff_t start) { start_ = start; }
void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; }
ptrdiff_t Value::getOffsetStart() const { return start_; }
ptrdiff_t Value::getOffsetLimit() const { return limit_; }
String Value::toStyledString() const {
StreamWriterBuilder builder;
String out = this->hasComment(commentBefore) ? "\n" : "";
out += Json::writeString(builder, *this);
out += '\n';
return out;
}
Value::const_iterator Value::begin() const {
switch (type()) {
case arrayValue:
case objectValue:
if (value_.map_)
return const_iterator(value_.map_->begin());
break;
default:
break;
}
return {};
}
Value::const_iterator Value::end() const {
switch (type()) {
case arrayValue:
case objectValue:
if (value_.map_)
return const_iterator(value_.map_->end());
break;
default:
break;
}
return {};
}
Value::iterator Value::begin() {
switch (type()) {
case arrayValue:
case objectValue:
if (value_.map_)
return iterator(value_.map_->begin());
break;
default:
break;
}
return iterator();
}
Value::iterator Value::end() {
switch (type()) {
case arrayValue:
case objectValue:
if (value_.map_)
return iterator(value_.map_->end());
break;
default:
break;
}
return iterator();
}
// class PathArgument
// //
PathArgument::PathArgument() = default;
PathArgument::PathArgument(ArrayIndex index)
: index_(index), kind_(kindIndex) {}
PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {}
PathArgument::PathArgument(String key) : key_(std::move(key)), kind_(kindKey) {}
// class Path
// //
Path::Path(const String& path, const PathArgument& a1, const PathArgument& a2,
const PathArgument& a3, const PathArgument& a4,
const PathArgument& a5) {
InArgs in;
in.reserve(5);
in.push_back(&a1);
in.push_back(&a2);
in.push_back(&a3);
in.push_back(&a4);
in.push_back(&a5);
makePath(path, in);
}
void Path::makePath(const String& path, const InArgs& in) {
const char* current = path.c_str();
const char* end = current + path.length();
auto itInArg = in.begin();
while (current != end) {
if (*current == '[') {
++current;
if (*current == '%')
addPathInArg(path, in, itInArg, PathArgument::kindIndex);
else {
ArrayIndex index = 0;
for (; current != end && *current >= '0' && *current <= '9'; ++current)
index = index * 10 + ArrayIndex(*current - '0');
args_.push_back(index);
}
if (current == end || *++current != ']')
invalidPath(path, int(current - path.c_str()));
} else if (*current == '%') {
addPathInArg(path, in, itInArg, PathArgument::kindKey);
++current;
} else if (*current == '.' || *current == ']') {
++current;
} else {
const char* beginName = current;
while (current != end && !strchr("[.", *current))
++current;
args_.push_back(String(beginName, current));
}
}
}
void Path::addPathInArg(const String& /*path*/, const InArgs& in,
InArgs::const_iterator& itInArg,
PathArgument::Kind kind) {
if (itInArg == in.end()) {
// Error: missing argument %d
} else if ((*itInArg)->kind_ != kind) {
// Error: bad argument type
} else {
args_.push_back(**itInArg++);
}
}
void Path::invalidPath(const String& /*path*/, int /*location*/) {
// Error: invalid path.
}
const Value& Path::resolve(const Value& root) const {
const Value* node = &root;
for (const auto& arg : args_) {
if (arg.kind_ == PathArgument::kindIndex) {
if (!node->isArray() || !node->isValidIndex(arg.index_)) {
// Error: unable to resolve path (array value expected at position... )
return Value::nullSingleton();
}
node = &((*node)[arg.index_]);
} else if (arg.kind_ == PathArgument::kindKey) {
if (!node->isObject()) {
// Error: unable to resolve path (object value expected at position...)
return Value::nullSingleton();
}
node = &((*node)[arg.key_]);
if (node == &Value::nullSingleton()) {
// Error: unable to resolve path (object has no member named '' at
// position...)
return Value::nullSingleton();
}
}
}
return *node;
}
Value Path::resolve(const Value& root, const Value& defaultValue) const {
const Value* node = &root;
for (const auto& arg : args_) {
if (arg.kind_ == PathArgument::kindIndex) {
if (!node->isArray() || !node->isValidIndex(arg.index_))
return defaultValue;
node = &((*node)[arg.index_]);
} else if (arg.kind_ == PathArgument::kindKey) {
if (!node->isObject())
return defaultValue;
node = &((*node)[arg.key_]);
if (node == &Value::nullSingleton())
return defaultValue;
}
}
return *node;
}
Value& Path::make(Value& root) const {
Value* node = &root;
for (const auto& arg : args_) {
if (arg.kind_ == PathArgument::kindIndex) {
if (!node->isArray()) {
// Error: node is not an array at position ...
}
node = &((*node)[arg.index_]);
} else if (arg.kind_ == PathArgument::kindKey) {
if (!node->isObject()) {
// Error: node is not an object at position...
}
node = &((*node)[arg.key_]);
}
}
return *node;
}
} // namespace Json
json_reader.cpp内容如下:
// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors
// Copyright (C) 2016 InfoTeCS JSC. All rights reserved.
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#if !defined(JSON_IS_AMALGAMATION)
#include "json_tool.h"
#include <json/assertions.h>
#include <json/reader.h>
#include <json/value.h>
#endif // if !defined(JSON_IS_AMALGAMATION)
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstring>
#include <iostream>
#include <istream>
#include <limits>
#include <memory>
#include <set>
#include <sstream>
#include <utility>
#include <cstdio>
#if defined(_MSC_VER)
#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
#endif //_MSC_VER
#if defined(_MSC_VER)
// Disable warning about strdup being deprecated.
#pragma warning(disable : 4996)
#endif
// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile
// time to change the stack limit
#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
#define JSONCPP_DEPRECATED_STACK_LIMIT 1000
#endif
static size_t const stackLimit_g =
JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()
namespace Json {
using CharReaderPtr = std::unique_ptr<CharReader>;
// Implementation of class Features
//
Features::Features() = default;
Features Features::all() { return {}; }
Features Features::strictMode() {
Features features;
features.allowComments_ = false;
features.strictRoot_ = true;
features.allowDroppedNullPlaceholders_ = false;
features.allowNumericKeys_ = false;
return features;
}
// Implementation of class Reader
//
/*内部使用了lambda表达式*/
bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
}
// Class Reader
// //
Reader::Reader() : features_(Features::all()) {}
Reader::Reader(const Features& features) : features_(features) {}
/*parse函数重载*/
bool Reader::parse(const std::string& document, Value& root,
bool collectComments) {
document_.assign(document.begin(), document.end());
const char* begin = document_.c_str();
const char* end = begin + document_.length();
return parse(begin, end, root, collectComments);
}
bool Reader::parse(std::istream& is, Value& root, bool collectComments) {
// std::istream_iterator<char> begin(is);
// std::istream_iterator<char> end;
// Those would allow streamed input from a file, if parse() were a
// template function.
// Since String is reference-counted, this at least does not
// create an extra copy.
String doc(std::istreambuf_iterator<char>(is), {});
return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
}
/*JSON数据解析*/
bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root,
bool collectComments) {
if (!features_.allowComments_) {
collectComments = false;
}
begin_ = beginDoc;
end_ = endDoc;
collectComments_ = collectComments;
current_ = begin_;
lastValueEnd_ = nullptr;
lastValue_ = nullptr;
commentsBefore_.clear();
errors_.clear();
while (!nodes_.empty()) /*nodes不为空,这将nodes中数据pop()出去*/
nodes_.pop();
nodes_.push(&root); /*将root入栈*/
/*readValue中进行递归的解析*/
bool successful = readValue();
Token token;
readTokenSkippingComments(token);
if (collectComments_ && !commentsBefore_.empty())
root.setComment(commentsBefore_, commentAfter);
if (features_.strictRoot_) {
/*有效的JSON数据必须是对象或者数字值*/
if (!root.isArray() && !root.isObject()) {
// Set error location to start of doc, ideally should be first token found
// in doc
token.type_ = tokenError;
token.start_ = beginDoc;
token.end_ = endDoc;
addError(
"A valid JSON document must be either an array or an object value.",
token);
return false;
}
}
return successful;
}
bool Reader::readValue() {
// readValue() may call itself only if it calls readObject() or ReadArray().
// These methods execute nodes_.push() just before and nodes_.pop)() just
// after calling readValue(). parse() executes one nodes_.push(), so > instead
// of >=.
if (nodes_.size() > stackLimit_g)
throwRuntimeError("Exceeded stackLimit in readValue().");
Token token;
/*读取JSON数据中的token,跳过其中的注释内容,即不获取注释内容*/
readTokenSkippingComments(token);
bool successful = true;
if (collectComments_ && !commentsBefore_.empty()) {
currentValue().setComment(commentsBefore_, commentBefore);
commentsBefore_.clear();
}
/*识别出JSON token类型*/
switch (token.type_) {
case tokenObjectBegin: /*{*/
successful = readObject(token);
currentValue().setOffsetLimit(current_ - begin_);
break;
case tokenArrayBegin: /*[*/
successful = readArray(token);
currentValue().setOffsetLimit(current_ - begin_);
break;
case tokenNumber: /*数值*/
successful = decodeNumber(token);
break;
case tokenString: /*字符串*/
successful = decodeString(token);
break;
case tokenTrue: { /*bool类型*/
Value v(true); /*直接使用true初始化*/
currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} break;
case tokenFalse: {
Value v(false); /*直接使用false初始化*/
currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} break;
case tokenNull: {
Value v;
currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} break;
case tokenArraySeparator: /*,*/
case tokenObjectEnd: /*}*/
case tokenArrayEnd: /*]*/
if (features_.allowDroppedNullPlaceholders_) {
// "Un-read" the current token and mark the current value as a null
// token.
current_--;
Value v;
currentValue().swapPayload(v);
currentValue().setOffsetStart(current_ - begin_ - 1);
currentValue().setOffsetLimit(current_ - begin_);
break;
} // Else, fall through...
default:
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return addError("Syntax error: value, object or array expected.", token);
}
if (collectComments_) {
lastValueEnd_ = current_;
lastValue_ = ¤tValue();
}
return successful;
}
/*读取JSON数据中的token,跳过其中的注释内容,即不获取注释内容*/
bool Reader::readTokenSkippingComments(Token& token) {
/*JSON token读取,token内容存放在参数token中*/
bool success = readToken(token);
if (features_.allowComments_) {
/*判断读到的token是否为注释内容,如果为注释内容的话继续读token直到不为注释内容*/
while (success && token.type_ == tokenComment) {
success = readToken(token);
}
}
return success;
}
/*将JSON数据每个单元数据解析出来*/
bool Reader::readToken(Token& token) {
/*跳过开头的空白符*/
skipSpaces();
token.start_ = current_;
Char c = getNextChar(); /*获取下一个字符内容*/
bool ok = true;
switch (c) {
case '{':
token.type_ = tokenObjectBegin;
break;
case '}':
token.type_ = tokenObjectEnd;
break;
case '[':
token.type_ = tokenArrayBegin;
break;
case ']':
token.type_ = tokenArrayEnd;
break;
case '"':
token.type_ = tokenString;
ok = readString(); /*直到遇到"符号才退出*/
break;
case '/':
token.type_ = tokenComment;
ok = readComment();
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
token.type_ = tokenNumber;
/*解析整数,小数,指数形式的数据*/
readNumber();
break;
case 't':
token.type_ = tokenTrue;
ok = match("rue", 3);
break;
case 'f':
token.type_ = tokenFalse;
ok = match("alse", 4);
break;
case 'n':
token.type_ = tokenNull;
ok = match("ull", 3);
break;
case ',':
token.type_ = tokenArraySeparator; /*分割符*/
break;
case ':':
token.type_ = tokenMemberSeparator; /*age": 30,*/
break;
case 0:
token.type_ = tokenEndOfStream;
break;
default:
ok = false;
break;
}
if (!ok)
token.type_ = tokenError;
token.end_ = current_;
return ok;
}
/*跳过开头的空白符*/
void Reader::skipSpaces() {
while (current_ != end_) {
Char c = *current_;
if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
++current_;
else
break;
}
}
/*匹配比较*/
bool Reader::match(const Char* pattern, int patternLength) {
if (end_ - current_ < patternLength)
return false;
int index = patternLength;
while (index--)
if (current_[index] != pattern[index])
return false;
current_ += patternLength;
return true;
}
/*读取注释内容*/
bool Reader::readComment() {
Location commentBegin = current_ - 1; /*commentBegin指向/*/
Char c = getNextChar();
bool successful = false;
if (c == '*') // /**/风格的注释内容
successful = readCStyleComment();
else if (c == '/') /* //风格的注释内容 */
successful = readCppStyleComment();
if (!successful)
return false;
if (collectComments_) {
CommentPlacement placement = commentBefore;
if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
if (c != '*' || !containsNewLine(commentBegin, current_))
placement = commentAfterOnSameLine;
}
/*记录注释部分的内容*/
addComment(commentBegin, current_, placement);
}
return true;
}
/*这里体现了C++ string操作的便捷*/
String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {
String normalized;
normalized.reserve(static_cast<size_t>(end - begin));
Reader::Location current = begin;
while (current != end) {
char c = *current++;
if (c == '\r') {
if (current != end && *current == '\n')
// convert dos EOL
++current;
// convert Mac EOL
normalized += '\n';
} else {
normalized += c;
}
}
return normalized;
}
void Reader::addComment(Location begin, Location end,
CommentPlacement placement) {
assert(collectComments_);
/*将注释内容存放到normalized string中*/
const String& normalized = normalizeEOL(begin, end);
if (placement == commentAfterOnSameLine) {
assert(lastValue_ != nullptr);
lastValue_->setComment(normalized, placement);
} else {
commentsBefore_ += normalized;
}
}
// /**/风格的注释内容
bool Reader::readCStyleComment() {
while ((current_ + 1) < end_) { /*这里判断current_+1 < end是因为最后的判断是判断的两个字符*和/ */
Char c = getNextChar();
if (c == '*' && *current_ == '/') //直到遇到注释的后半部分 */ 才退出
break;
}
return getNextChar() == '/';
}
/* //风格的注释内容 */
bool Reader::readCppStyleComment() {
while (current_ != end_) {
Char c = getNextChar(); /*以回车换行作为结束判断依据*/
if (c == '\n')
break;
if (c == '\r') {
// Consume DOS EOL. It will be normalized in addComment.
if (current_ != end_ && *current_ == '\n') /*\r\n*/
getNextChar();
// Break on Moc OS 9 EOL.
break;
}
}
return true;
}
/*解析整数,小数,指数形式的数据*/
void Reader::readNumber() {
Location p = current_;
char c = '0'; // stopgap for already consumed character
// integral part
/*整数部分*/
while (c >= '0' && c <= '9')
c = (current_ = p) < end_ ? *p++ : '\0';
// fractional part
/*小数部分*/
if (c == '.') {
c = (current_ = p) < end_ ? *p++ : '\0';
while (c >= '0' && c <= '9')
c = (current_ = p) < end_ ? *p++ : '\0';
}
// exponential part
/*指数部分*/
if (c == 'e' || c == 'E') {
c = (current_ = p) < end_ ? *p++ : '\0';
if (c == '+' || c == '-')
c = (current_ = p) < end_ ? *p++ : '\0';
while (c >= '0' && c <= '9')
c = (current_ = p) < end_ ? *p++ : '\0';
}
}
/*获取"..."中的数据*/
bool Reader::readString() {
Char c = '\0';
while (current_ != end_) {
c = getNextChar();
if (c == '\\') /*\符号后面一般情况下后面接转义字符*/
getNextChar(); /*没有获取字符数据,说明转义字符不处理*/
else if (c == '"')
break; /*直到"才退出*/
}
return c == '"';
}
/*读对象数据*/
bool Reader::readObject(Token& token) {
Token tokenName;
String name;
Value init(objectValue);
currentValue().swapPayload(init);
/*token起始位置相对于begin_的偏移量*/
currentValue().setOffsetStart(token.start_ - begin_);
/*读取JSON中的token 键值对集合(对象)数据,跳过注释内容*/
while (readTokenSkippingComments(tokenName)) {
if (tokenName.type_ == tokenObjectEnd && name.empty()) // { } 空obj
return true;
name.clear();
if (tokenName.type_ == tokenString) {
if (!decodeString(tokenName, name)) /*对string中的数据进行解码,注意:需要对其中的转义字符进行处理*/
return recoverFromError(tokenObjectEnd);
} else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
Value numberName;
if (!decodeNumber(tokenName, numberName)) /*解码数据*/
return recoverFromError(tokenObjectEnd);
name = numberName.asString();
} else {
break; /*退出循环*/
}
Token colon; /*colon 冒号 :*/
if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
return addErrorAndRecover("Missing ':' after object member name", colon,
tokenObjectEnd);
}
/*
Value类的下标运算符,如果[]中的数据不存在则默认初始化插入数据到map中,并返回插入的数据的引用,便于修改操作
上面部分将json中键值对集合(对象){"key":value}中键值数据name解析出来,其作为Value的下标[name]插入到map中
name数据其实已经保存到的map中,下面需要解析value的值并将其存入map中即可
*/
Value& value = currentValue()[name];
nodes_.push(&value); /*需要设置哪个Value的内容就需要先将其放入到nodes_栈中*/
bool ok = readValue(); /*获取其数据,递归获取JSON中的数据*/
nodes_.pop(); /*弹出nodes_栈*/
if (!ok) // error already set
return recoverFromError(tokenObjectEnd);
Token comma; /*comma 逗号 ,*/
if (!readTokenSkippingComments(comma) ||
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) {
return addErrorAndRecover("Missing ',' or '}' in object declaration",
comma, tokenObjectEnd);
}
if (comma.type_ == tokenObjectEnd)
return true;
}
return addErrorAndRecover("Missing '}' or object member name", tokenName,
tokenObjectEnd);
}
/*读数组数据*/
bool Reader::readArray(Token& token) {
Value init(arrayValue); /*变量init初始化*/
currentValue().swapPayload(init);
currentValue().setOffsetStart(token.start_ - begin_);
skipSpaces();
if (current_ != end_ && *current_ == ']') // empty array
{
Token endArray;
readToken(endArray);
return true;
}
int index = 0;
for (;;) {
Value& value = currentValue()[index++]; /*Value类的下标运算符[]*/
nodes_.push(&value);
bool ok = readValue();
nodes_.pop();
if (!ok) // error already set
return recoverFromError(tokenArrayEnd);
Token currentToken;
// Accept Comment after last item in the array.
ok = readTokenSkippingComments(currentToken);
bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
currentToken.type_ != tokenArrayEnd);
if (!ok || badTokenType) {
return addErrorAndRecover("Missing ',' or ']' in array declaration",
currentToken, tokenArrayEnd);
}
if (currentToken.type_ == tokenArrayEnd)
break;
}
return true;
}
bool Reader::decodeNumber(Token& token) {
Value decoded;
if (!decodeNumber(token, decoded))
return false;
currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_); /*Value开始相对于JSON数据开始位置的偏移*/
currentValue().setOffsetLimit(token.end_ - begin_); /*Value结束相对于JSON数据结束位置的偏移*/
return true;
}
bool Reader::decodeNumber(Token& token, Value& decoded) {
// Attempts to parse the number as an integer. If the number is
// larger than the maximum supported value of an integer then
// we decode the number as a double.
/*尝试将解析数据为整数,如果数据比整数的最大值还大则解码为浮点数,此时存在精度的丢失但是总比溢出好*/
Location current = token.start_;
bool isNegative = *current == '-';
if (isNegative)
++current;
// TODO: Help the compiler do the div and mod at compile time or get rid of
// them.
Value::LargestUInt maxIntegerValue =
isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 /*有符号数的最大值*/
: Value::maxLargestUInt; /*无符号数的最大值*/
/*设置一个门限值,超过门限值*/
Value::LargestUInt threshold = maxIntegerValue / 10; /*丢弃个数上的数值*/
Value::LargestUInt value = 0;
while (current < token.end_) {
Char c = *current++;
/*JSON整数或浮点数,不支持八进制或十六进制前缀(如 0x)*/
if (c < '0' || c > '9') /*视为浮点数处理*/
return decodeDouble(token, decoded);
auto digit(static_cast<Value::UInt>(c - '0')); /*这是一个变量的定义,C++ 非常让人无解的地方*/
if (value >= threshold) { /*累积的value超过门限值*/
// We've hit or exceeded the max value divided by 10 (rounded down). If
// a) we've only just touched the limit, b) this is the last digit, and
// c) it's small enough to fit in that rounding delta, we're okay.
// Otherwise treat this number as a double to avoid overflow.
if (value > threshold || current != token.end_ ||
digit > maxIntegerValue % 10 /*digit比最大值个位上数据还大,必然溢出*/) {
return decodeDouble(token, decoded); /*视为浮点数处理,会丢失精度*/
}
}
value = value * 10 + digit;
}
if (isNegative && value == maxIntegerValue)
decoded = Value::minLargestInt;
else if (isNegative)
decoded = -Value::LargestInt(value);
else if (value <= Value::LargestUInt(Value::maxInt))
decoded = Value::LargestInt(value);
else
decoded = value;
return true;
}
bool Reader::decodeDouble(Token& token) {
Value decoded;
if (!decodeDouble(token, decoded))
return false;
currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true;
}
bool Reader::decodeDouble(Token& token, Value& decoded) {
double value = 0;
IStringStream is(String(token.start_, token.end_));
if (!(is >> value)) { /*double时出错*/
if (value == std::numeric_limits<double>::max())
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)) /*std::isinf 是 C++ 标准库 <cmath> 中提供的函数,用于检测一个浮点数是否为无穷大(Infinity)。*/
return addError(
"'" + String(token.start_, token.end_) + "' is not a number.", token);
}
decoded = value; /*隐式类型转换*/
return true;
}
bool Reader::decodeString(Token& token) {
String decoded_string;
if (!decodeString(token, decoded_string))
return false;
Value decoded(decoded_string);
currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true;
}
/*注意:需要对其中的转义字符进行处理*/
bool Reader::decodeString(Token& token, String& decoded) {
/*-2,"..."去除开始和结束的两个"符号*/
decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
Location current = token.start_ + 1; // skip '"'
Location end = token.end_ - 1; // do not include '"'
while (current != end) {
Char c = *current++;
if (c == '"')
break;
if (c == '\\') { /*转义字符的处理*/
if (current == end)
return addError("Empty escape sequence in string", token, current);
Char escape = *current++;
switch (escape) { /*解析字符串中的转义字符*/
case '"': // \"
decoded += '"';
break;
case '/': // \/
decoded += '/';
break;
case '\\': // \\
decoded += '\\';
break;
case 'b':
decoded += '\b';
break;
case 'f':
decoded += '\f';
break;
case 'n':
decoded += '\n';
break;
case 'r':
decoded += '\r';
break;
case 't':
decoded += '\t';
break;
/*
在JSON(JavaScript Object Notation)中,\u是一种转义序列,用于表示Unicode字符。
它的作用是将Unicode码点(以十六进制表示)转换为对应的字符,
确保JSON数据可以包含各种语言的字符(如中文、表情符号等),同时保持纯文本格式的兼容性。
*/
case 'u': { // \u:unicode编码
unsigned int unicode;
/*解码JSON中的unicode码*/
if (!decodeUnicodeCodePoint(token, current, end, unicode))
return false;
decoded += codePointToUTF8(unicode); /*unicode码点转换为UTF-8*/
} break;
default:
return addError("Bad escape sequence in string", token, current);
}
} else {
decoded += c;
}
}
return true;
}
/*解码JSON中的unicode码*/
bool Reader::decodeUnicodeCodePoint(Token& token, Location& current,
Location end, unsigned int& unicode) {
if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) /*解码4位16进制 unicode码*/
return false;
if (unicode >= 0xD800 && unicode <= 0xDBFF) {
// surrogate pairs 代理对
if (end - current < 6)
return addError(
"additional six characters expected to parse unicode surrogate pair.",
token, current);
if (*(current++) == '\\' && *(current++) == 'u') {
unsigned int surrogatePair;
if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
} else
return false;
} else
return addError("expecting another \\u token to begin the second half of "
"a unicode surrogate pair",
token, current);
}
return true;
}
/*解码16进制 unicode码*/
bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current,
Location end,
unsigned int& ret_unicode) {
if (end - current < 4) /*非4位16进制则报错*/
return addError(
"Bad unicode escape sequence in string: four digits expected.", token,
current);
int unicode = 0;
for (int index = 0; index < 4; ++index) {
Char c = *current++;
unicode *= 16;
if (c >= '0' && c <= '9')
unicode += c - '0';
else if (c >= 'a' && c <= 'f')
unicode += c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
unicode += c - 'A' + 10;
else
return addError(
"Bad unicode escape sequence in string: hexadecimal digit expected.",
token, current);
}
ret_unicode = static_cast<unsigned int>(unicode);
return true;
}
bool Reader::addError(const String& message, Token& token, Location extra) {
ErrorInfo info;
info.token_ = token;
info.message_ = message;
info.extra_ = extra;
errors_.push_back(info);
return false;
}
bool Reader::recoverFromError(TokenType skipUntilToken) {
size_t const errorCount = errors_.size();
Token skip;
for (;;) {
if (!readToken(skip))
errors_.resize(errorCount); // discard errors caused by recovery
if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
break;
}
errors_.resize(errorCount);
return false;
}
bool Reader::addErrorAndRecover(const String& message, Token& token,
TokenType skipUntilToken) {
addError(message, token);
return recoverFromError(skipUntilToken);
}
Value& Reader::currentValue() { return *(nodes_.top()); }
Reader::Char Reader::getNextChar() {
if (current_ == end_)
return 0;
return *current_++;
}
void Reader::getLocationLineAndColumn(Location location, int& line,
int& column) const {
Location current = begin_;
Location lastLineStart = current;
line = 0;
while (current < location && current != end_) {
Char c = *current++;
if (c == '\r') {
if (current != end_ && *current == '\n')
++current;
lastLineStart = current;
++line;
} else if (c == '\n') {
lastLineStart = current;
++line;
}
}
// column & line start at 1
column = int(location - lastLineStart) + 1;
++line;
}
String Reader::getLocationLineAndColumn(Location location) const {
int line, column;
getLocationLineAndColumn(location, line, column);
char buffer[18 + 16 + 16 + 1];
jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
return buffer;
}
// Deprecated. Preserved for backward compatibility
String Reader::getFormatedErrorMessages() const {
return getFormattedErrorMessages();
}
String Reader::getFormattedErrorMessages() const {
String formattedMessage;
for (const auto& error : errors_) {
formattedMessage +=
"* " + getLocationLineAndColumn(error.token_.start_) + "\n";
formattedMessage += " " + error.message_ + "\n";
if (error.extra_)
formattedMessage +=
"See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
}
return formattedMessage;
}
std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
std::vector<Reader::StructuredError> allErrors;
for (const auto& error : errors_) {
Reader::StructuredError structured;
structured.offset_start = error.token_.start_ - begin_;
structured.offset_limit = error.token_.end_ - begin_;
structured.message = error.message_;
allErrors.push_back(structured);
}
return allErrors;
}
bool Reader::pushError(const Value& value, const String& message) {
ptrdiff_t const length = end_ - begin_;
if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
return false;
Token token;
token.type_ = tokenError;
token.start_ = begin_ + value.getOffsetStart();
token.end_ = begin_ + value.getOffsetLimit();
ErrorInfo info;
info.token_ = token;
info.message_ = message;
info.extra_ = nullptr;
errors_.push_back(info);
return true;
}
bool Reader::pushError(const Value& value, const String& message,
const Value& extra) {
ptrdiff_t const length = end_ - begin_;
if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
extra.getOffsetLimit() > length)
return false;
Token token;
token.type_ = tokenError;
token.start_ = begin_ + value.getOffsetStart();
token.end_ = begin_ + value.getOffsetLimit();
ErrorInfo info;
info.token_ = token;
info.message_ = message;
info.extra_ = begin_ + extra.getOffsetStart();
errors_.push_back(info);
return true;
}
bool Reader::good() const { return errors_.empty(); }
// Originally copied from the Features class (now deprecated), used internally
// for features implementation.
class OurFeatures {
public:
static OurFeatures all();
bool allowComments_;
bool allowTrailingCommas_;
bool strictRoot_;
bool allowDroppedNullPlaceholders_;
bool allowNumericKeys_;
bool allowSingleQuotes_;
bool failIfExtra_;
bool rejectDupKeys_;
bool allowSpecialFloats_;
bool skipBom_;
size_t stackLimit_;
}; // OurFeatures
OurFeatures OurFeatures::all() { return {}; }
// Implementation of class Reader
//
// Originally copied from the Reader class (now deprecated), used internally
// for implementing JSON reading.
/*最初是从Reader类(现已弃用)复制的,目前仅用于内部实现JSON读取功能。*/
class OurReader {
public:
using Char = char;
using Location = const Char*;
explicit OurReader(OurFeatures const& features);
bool parse(const char* beginDoc, const char* endDoc, Value& root,
bool collectComments = true);
String getFormattedErrorMessages() const;
std::vector<CharReader::StructuredError> getStructuredErrors() const;
private:
OurReader(OurReader const&); // no impl
void operator=(OurReader const&); // no impl
enum TokenType {
tokenEndOfStream = 0,
tokenObjectBegin,
tokenObjectEnd,
tokenArrayBegin,
tokenArrayEnd,
tokenString,
tokenNumber,
tokenTrue,
tokenFalse,
tokenNull,
tokenNaN,
tokenPosInf,
tokenNegInf,
tokenArraySeparator,
tokenMemberSeparator,
tokenComment,
tokenError
};
class Token {
public:
TokenType type_;
Location start_;
Location end_;
};
class ErrorInfo {
public:
Token token_;
String message_;
Location extra_;
};
using Errors = std::deque<ErrorInfo>;
bool readToken(Token& token);
bool readTokenSkippingComments(Token& token);
void skipSpaces();
void skipBom(bool skipBom);
bool match(const Char* pattern, int patternLength);
bool readComment();
bool readCStyleComment(bool* containsNewLineResult);
bool readCppStyleComment();
bool readString();
bool readStringSingleQuote();
bool readNumber(bool checkInf);
bool readValue();
bool readObject(Token& token);
bool readArray(Token& token);
bool decodeNumber(Token& token);
bool decodeNumber(Token& token, Value& decoded);
bool decodeString(Token& token);
bool decodeString(Token& token, String& decoded);
bool decodeDouble(Token& token);
bool decodeDouble(Token& token, Value& decoded);
bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
unsigned int& unicode);
bool decodeUnicodeEscapeSequence(Token& token, Location& current,
Location end, unsigned int& unicode);
bool addError(const String& message, Token& token, Location extra = nullptr);
bool recoverFromError(TokenType skipUntilToken);
bool addErrorAndRecover(const String& message, Token& token,
TokenType skipUntilToken);
void skipUntilSpace();
Value& currentValue();
Char getNextChar();
void getLocationLineAndColumn(Location location, int& line,
int& column) const;
String getLocationLineAndColumn(Location location) const;
void addComment(Location begin, Location end, CommentPlacement placement);
static String normalizeEOL(Location begin, Location end);
static bool containsNewLine(Location begin, Location end);
using Nodes = std::stack<Value*>;
Nodes nodes_{};
Errors errors_{};
String document_{};
Location begin_ = nullptr;
Location end_ = nullptr;
Location current_ = nullptr;
Location lastValueEnd_ = nullptr;
Value* lastValue_ = nullptr;
bool lastValueHasAComment_ = false;
String commentsBefore_{};
OurFeatures const features_;
bool collectComments_ = false;
}; // OurReader
// complete copy of Read impl, for OurReader
bool OurReader::containsNewLine(OurReader::Location begin,
OurReader::Location end) {
return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
}
OurReader::OurReader(OurFeatures const& features) : features_(features) {}
bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
bool collectComments) {
if (!features_.allowComments_) {
collectComments = false;
}
begin_ = beginDoc;
end_ = endDoc;
collectComments_ = collectComments;
current_ = begin_;
lastValueEnd_ = nullptr;
lastValue_ = nullptr;
commentsBefore_.clear();
errors_.clear();
while (!nodes_.empty())
nodes_.pop();
nodes_.push(&root);
// skip byte order mark if it exists at the beginning of the UTF-8 text.
skipBom(features_.skipBom_);
bool successful = readValue();
nodes_.pop();
Token token;
readTokenSkippingComments(token);
if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) {
addError("Extra non-whitespace after JSON value.", token);
return false;
}
if (collectComments_ && !commentsBefore_.empty())
root.setComment(commentsBefore_, commentAfter);
if (features_.strictRoot_) {
if (!root.isArray() && !root.isObject()) {
// Set error location to start of doc, ideally should be first token found
// in doc
token.type_ = tokenError;
token.start_ = beginDoc;
token.end_ = endDoc;
addError(
"A valid JSON document must be either an array or an object value.",
token);
return false;
}
}
return successful;
}
bool OurReader::readValue() {
// To preserve the old behaviour we cast size_t to int.
if (nodes_.size() > features_.stackLimit_)
throwRuntimeError("Exceeded stackLimit in readValue().");
Token token;
readTokenSkippingComments(token);
bool successful = true;
if (collectComments_ && !commentsBefore_.empty()) {
currentValue().setComment(commentsBefore_, commentBefore);
commentsBefore_.clear();
}
switch (token.type_) {
case tokenObjectBegin:
successful = readObject(token);
currentValue().setOffsetLimit(current_ - begin_);
break;
case tokenArrayBegin:
successful = readArray(token);
currentValue().setOffsetLimit(current_ - begin_);
break;
case tokenNumber:
successful = decodeNumber(token);
break;
case tokenString:
successful = decodeString(token);
break;
case tokenTrue: {
Value v(true);
currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} break;
case tokenFalse: {
Value v(false);
currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} break;
case tokenNull: {
Value v;
currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} break;
case tokenNaN: {
Value v(std::numeric_limits<double>::quiet_NaN());
currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} break;
case tokenPosInf: {
Value v(std::numeric_limits<double>::infinity());
currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} break;
case tokenNegInf: {
Value v(-std::numeric_limits<double>::infinity());
currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} break;
case tokenArraySeparator:
case tokenObjectEnd:
case tokenArrayEnd:
if (features_.allowDroppedNullPlaceholders_) {
// "Un-read" the current token and mark the current value as a null
// token.
current_--;
Value v;
currentValue().swapPayload(v);
currentValue().setOffsetStart(current_ - begin_ - 1);
currentValue().setOffsetLimit(current_ - begin_);
break;
} // else, fall through ...
default:
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return addError("Syntax error: value, object or array expected.", token);
}
if (collectComments_) {
lastValueEnd_ = current_;
lastValueHasAComment_ = false;
lastValue_ = ¤tValue();
}
return successful;
}
bool OurReader::readTokenSkippingComments(Token& token) {
bool success = readToken(token);
if (features_.allowComments_) {
while (success && token.type_ == tokenComment) {
success = readToken(token);
}
}
return success;
}
bool OurReader::readToken(Token& token) {
skipSpaces();
token.start_ = current_;
Char c = getNextChar();
bool ok = true;
switch (c) {
case '{':
token.type_ = tokenObjectBegin;
break;
case '}':
token.type_ = tokenObjectEnd;
break;
case '[':
token.type_ = tokenArrayBegin;
break;
case ']':
token.type_ = tokenArrayEnd;
break;
case '"':
token.type_ = tokenString;
ok = readString();
break;
case '\'':
if (features_.allowSingleQuotes_) {
token.type_ = tokenString;
ok = readStringSingleQuote();
} else {
// If we don't allow single quotes, this is a failure case.
ok = false;
}
break;
case '/':
token.type_ = tokenComment;
ok = readComment();
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
token.type_ = tokenNumber;
readNumber(false);
break;
case '-':
if (readNumber(true)) {
token.type_ = tokenNumber;
} else {
token.type_ = tokenNegInf;
ok = features_.allowSpecialFloats_ && match("nfinity", 7);
}
break;
case '+':
if (readNumber(true)) {
token.type_ = tokenNumber;
} else {
token.type_ = tokenPosInf;
ok = features_.allowSpecialFloats_ && match("nfinity", 7);
}
break;
case 't':
token.type_ = tokenTrue;
ok = match("rue", 3);
break;
case 'f':
token.type_ = tokenFalse;
ok = match("alse", 4);
break;
case 'n':
token.type_ = tokenNull;
ok = match("ull", 3);
break;
case 'N':
if (features_.allowSpecialFloats_) {
token.type_ = tokenNaN;
ok = match("aN", 2);
} else {
ok = false;
}
break;
case 'I':
if (features_.allowSpecialFloats_) {
token.type_ = tokenPosInf;
ok = match("nfinity", 7);
} else {
ok = false;
}
break;
case ',':
token.type_ = tokenArraySeparator;
break;
case ':':
token.type_ = tokenMemberSeparator;
break;
case 0:
token.type_ = tokenEndOfStream;
break;
default:
ok = false;
break;
}
if (!ok)
token.type_ = tokenError;
token.end_ = current_;
return ok;
}
void OurReader::skipSpaces() {
while (current_ != end_) {
Char c = *current_;
if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
++current_;
else
break;
}
}
void OurReader::skipBom(bool skipBom) {
// The default behavior is to skip BOM.
if (skipBom) {
if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) {
begin_ += 3;
current_ = begin_;
}
}
}
bool OurReader::match(const Char* pattern, int patternLength) {
if (end_ - current_ < patternLength)
return false;
int index = patternLength;
while (index--)
if (current_[index] != pattern[index])
return false;
current_ += patternLength;
return true;
}
bool OurReader::readComment() {
const Location commentBegin = current_ - 1;
const Char c = getNextChar();
bool successful = false;
bool cStyleWithEmbeddedNewline = false;
const bool isCStyleComment = (c == '*');
const bool isCppStyleComment = (c == '/');
if (isCStyleComment) {
successful = readCStyleComment(&cStyleWithEmbeddedNewline);
} else if (isCppStyleComment) {
successful = readCppStyleComment();
}
if (!successful)
return false;
if (collectComments_) {
CommentPlacement placement = commentBefore;
if (!lastValueHasAComment_) {
if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
if (isCppStyleComment || !cStyleWithEmbeddedNewline) {
placement = commentAfterOnSameLine;
lastValueHasAComment_ = true;
}
}
}
addComment(commentBegin, current_, placement);
}
return true;
}
String OurReader::normalizeEOL(OurReader::Location begin,
OurReader::Location end) {
String normalized;
normalized.reserve(static_cast<size_t>(end - begin));
OurReader::Location current = begin;
while (current != end) {
char c = *current++;
if (c == '\r') {
if (current != end && *current == '\n')
// convert dos EOL
++current;
// convert Mac EOL
normalized += '\n';
} else {
normalized += c;
}
}
return normalized;
}
void OurReader::addComment(Location begin, Location end,
CommentPlacement placement) {
assert(collectComments_);
const String& normalized = normalizeEOL(begin, end);
if (placement == commentAfterOnSameLine) {
assert(lastValue_ != nullptr);
lastValue_->setComment(normalized, placement);
} else {
commentsBefore_ += normalized;
}
}
bool OurReader::readCStyleComment(bool* containsNewLineResult) {
*containsNewLineResult = false;
while ((current_ + 1) < end_) {
Char c = getNextChar();
if (c == '*' && *current_ == '/')
break;
if (c == '\n')
*containsNewLineResult = true;
}
return getNextChar() == '/';
}
bool OurReader::readCppStyleComment() {
while (current_ != end_) {
Char c = getNextChar();
if (c == '\n')
break;
if (c == '\r') {
// Consume DOS EOL. It will be normalized in addComment.
if (current_ != end_ && *current_ == '\n')
getNextChar();
// Break on Moc OS 9 EOL.
break;
}
}
return true;
}
bool OurReader::readNumber(bool checkInf) {
Location p = current_;
if (checkInf && p != end_ && *p == 'I') {
current_ = ++p;
return false;
}
char c = '0'; // stopgap for already consumed character
// integral part
while (c >= '0' && c <= '9')
c = (current_ = p) < end_ ? *p++ : '\0';
// fractional part
if (c == '.') {
c = (current_ = p) < end_ ? *p++ : '\0';
while (c >= '0' && c <= '9')
c = (current_ = p) < end_ ? *p++ : '\0';
}
// exponential part
if (c == 'e' || c == 'E') {
c = (current_ = p) < end_ ? *p++ : '\0';
if (c == '+' || c == '-')
c = (current_ = p) < end_ ? *p++ : '\0';
while (c >= '0' && c <= '9')
c = (current_ = p) < end_ ? *p++ : '\0';
}
return true;
}
bool OurReader::readString() {
Char c = 0;
while (current_ != end_) {
c = getNextChar();
if (c == '\\')
getNextChar();
else if (c == '"')
break;
}
return c == '"';
}
bool OurReader::readStringSingleQuote() {
Char c = 0;
while (current_ != end_) {
c = getNextChar();
if (c == '\\')
getNextChar();
else if (c == '\'')
break;
}
return c == '\'';
}
bool OurReader::readObject(Token& token) {
Token tokenName;
String name;
Value init(objectValue);
currentValue().swapPayload(init);
currentValue().setOffsetStart(token.start_ - begin_);
while (readTokenSkippingComments(tokenName)) {
if (tokenName.type_ == tokenObjectEnd &&
(name.empty() ||
features_.allowTrailingCommas_)) // empty object or trailing comma
return true;
name.clear();
if (tokenName.type_ == tokenString) {
if (!decodeString(tokenName, name))
return recoverFromError(tokenObjectEnd);
} else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
Value numberName;
if (!decodeNumber(tokenName, numberName))
return recoverFromError(tokenObjectEnd);
name = numberName.asString();
} else {
break;
}
if (name.length() >= (1U << 30))
throwRuntimeError("keylength >= 2^30");
if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
String msg = "Duplicate key: '" + name + "'";
return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
}
Token colon;
if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
return addErrorAndRecover("Missing ':' after object member name", colon,
tokenObjectEnd);
}
Value& value = currentValue()[name];
nodes_.push(&value);
bool ok = readValue();
nodes_.pop();
if (!ok) // error already set
return recoverFromError(tokenObjectEnd);
Token comma;
if (!readTokenSkippingComments(comma) ||
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) {
return addErrorAndRecover("Missing ',' or '}' in object declaration",
comma, tokenObjectEnd);
}
if (comma.type_ == tokenObjectEnd)
return true;
}
return addErrorAndRecover("Missing '}' or object member name", tokenName,
tokenObjectEnd);
}
bool OurReader::readArray(Token& token) {
Value init(arrayValue);
currentValue().swapPayload(init);
currentValue().setOffsetStart(token.start_ - begin_);
int index = 0;
for (;;) {
skipSpaces();
if (current_ != end_ && *current_ == ']' &&
(index == 0 ||
(features_.allowTrailingCommas_ &&
!features_.allowDroppedNullPlaceholders_))) // empty array or trailing
// comma
{
Token endArray;
readToken(endArray);
return true;
}
Value& value = currentValue()[index++];
nodes_.push(&value);
bool ok = readValue();
nodes_.pop();
if (!ok) // error already set
return recoverFromError(tokenArrayEnd);
Token currentToken;
// Accept Comment after last item in the array.
ok = readTokenSkippingComments(currentToken);
bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
currentToken.type_ != tokenArrayEnd);
if (!ok || badTokenType) {
return addErrorAndRecover("Missing ',' or ']' in array declaration",
currentToken, tokenArrayEnd);
}
if (currentToken.type_ == tokenArrayEnd)
break;
}
return true;
}
bool OurReader::decodeNumber(Token& token) {
Value decoded;
if (!decodeNumber(token, decoded))
return false;
currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true;
}
bool OurReader::decodeNumber(Token& token, Value& decoded) {
// Attempts to parse the number as an integer. If the number is
// larger than the maximum supported value of an integer then
// we decode the number as a double.
Location current = token.start_;
const bool isNegative = *current == '-';
if (isNegative) {
++current;
}
// 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
// into an unsigned integer.
static_assert(Value::maxLargestInt <= Value::maxLargestUInt,
"Int must be smaller than UInt");
// We need to convert minLargestInt into a positive number. The easiest way
// to do this conversion is to assume our "threshold" value of minLargestInt
// divided by 10 can fit in maxLargestInt when absolute valued. This should
// be a safe assumption.
static_assert(Value::minLargestInt <= -Value::maxLargestInt,
"The absolute value of minLargestInt must be greater than or "
"equal to maxLargestInt");
static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt,
"The absolute value of minLargestInt must be only 1 magnitude "
"larger than maxLargest Int");
static constexpr Value::LargestUInt positive_threshold =
Value::maxLargestUInt / 10;
static constexpr Value::UInt positive_last_digit = Value::maxLargestUInt % 10;
// For the negative values, we have to be more careful. Since typically
// -Value::minLargestInt will cause an overflow, we first divide by 10 and
// 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
// digit, we take the modulus before negating for the same reason.
static constexpr auto negative_threshold =
Value::LargestUInt(-(Value::minLargestInt / 10));
static constexpr auto negative_last_digit =
Value::UInt(-(Value::minLargestInt % 10));
const Value::LargestUInt threshold =
isNegative ? negative_threshold : positive_threshold;
const Value::UInt max_last_digit =
isNegative ? negative_last_digit : positive_last_digit;
Value::LargestUInt value = 0;
while (current < token.end_) {
Char c = *current++;
if (c < '0' || c > '9')
return decodeDouble(token, decoded);
const auto digit(static_cast<Value::UInt>(c - '0'));
if (value >= threshold) {
// We've hit or exceeded the max value divided by 10 (rounded down). If
// a) we've only just touched the limit, meaning value == threshold,
// b) this is the last digit, or
// c) it's small enough to fit in that rounding delta, we're okay.
// Otherwise treat this number as a double to avoid overflow.
if (value > threshold || current != token.end_ ||
digit > max_last_digit) {
return decodeDouble(token, decoded);
}
}
value = value * 10 + digit;
}
if (isNegative) {
// We use the same magnitude assumption here, just in case.
const auto last_digit = static_cast<Value::UInt>(value % 10);
decoded = -Value::LargestInt(value / 10) * 10 - last_digit;
} else if (value <= Value::LargestUInt(Value::maxLargestInt)) {
decoded = Value::LargestInt(value);
} else {
decoded = value;
}
return true;
}
bool OurReader::decodeDouble(Token& token) {
Value decoded;
if (!decodeDouble(token, decoded))
return false;
currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true;
}
bool OurReader::decodeDouble(Token& token, Value& decoded) {
double value = 0;
IStringStream is(String(token.start_, token.end_));
if (!(is >> value)) {
if (value == std::numeric_limits<double>::max())
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;
return true;
}
bool OurReader::decodeString(Token& token) {
String decoded_string;
if (!decodeString(token, decoded_string))
return false;
Value decoded(decoded_string);
currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true;
}
bool OurReader::decodeString(Token& token, String& decoded) {
decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
Location current = token.start_ + 1; // skip '"'
Location end = token.end_ - 1; // do not include '"'
while (current != end) {
Char c = *current++;
if (c == '"')
break;
if (c == '\\') {
if (current == end)
return addError("Empty escape sequence in string", token, current);
Char escape = *current++;
switch (escape) {
case '"':
decoded += '"';
break;
case '/':
decoded += '/';
break;
case '\\':
decoded += '\\';
break;
case 'b':
decoded += '\b';
break;
case 'f':
decoded += '\f';
break;
case 'n':
decoded += '\n';
break;
case 'r':
decoded += '\r';
break;
case 't':
decoded += '\t';
break;
case 'u': {
unsigned int unicode;
if (!decodeUnicodeCodePoint(token, current, end, unicode))
return false;
decoded += codePointToUTF8(unicode);
} break;
default:
return addError("Bad escape sequence in string", token, current);
}
} else {
decoded += c;
}
}
return true;
}
bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current,
Location end, unsigned int& unicode) {
if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
return false;
if (unicode >= 0xD800 && unicode <= 0xDBFF) {
// surrogate pairs
if (end - current < 6)
return addError(
"additional six characters expected to parse unicode surrogate pair.",
token, current);
if (*(current++) == '\\' && *(current++) == 'u') {
unsigned int surrogatePair;
if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
} else
return false;
} else
return addError("expecting another \\u token to begin the second half of "
"a unicode surrogate pair",
token, current);
}
return true;
}
bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current,
Location end,
unsigned int& ret_unicode) {
if (end - current < 4)
return addError(
"Bad unicode escape sequence in string: four digits expected.", token,
current);
int unicode = 0;
for (int index = 0; index < 4; ++index) {
Char c = *current++;
unicode *= 16;
if (c >= '0' && c <= '9')
unicode += c - '0';
else if (c >= 'a' && c <= 'f')
unicode += c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
unicode += c - 'A' + 10;
else
return addError(
"Bad unicode escape sequence in string: hexadecimal digit expected.",
token, current);
}
ret_unicode = static_cast<unsigned int>(unicode);
return true;
}
bool OurReader::addError(const String& message, Token& token, Location extra) {
ErrorInfo info;
info.token_ = token;
info.message_ = message;
info.extra_ = extra;
errors_.push_back(info);
return false;
}
bool OurReader::recoverFromError(TokenType skipUntilToken) {
size_t errorCount = errors_.size();
Token skip;
for (;;) {
if (!readToken(skip))
errors_.resize(errorCount); // discard errors caused by recovery
if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
break;
}
errors_.resize(errorCount);
return false;
}
bool OurReader::addErrorAndRecover(const String& message, Token& token,
TokenType skipUntilToken) {
addError(message, token);
return recoverFromError(skipUntilToken);
}
Value& OurReader::currentValue() { return *(nodes_.top()); }
OurReader::Char OurReader::getNextChar() {
if (current_ == end_)
return 0;
return *current_++;
}
void OurReader::getLocationLineAndColumn(Location location, int& line,
int& column) const {
Location current = begin_;
Location lastLineStart = current;
line = 0;
while (current < location && current != end_) {
Char c = *current++;
if (c == '\r') {
if (current != end_ && *current == '\n')
++current;
lastLineStart = current;
++line;
} else if (c == '\n') {
lastLineStart = current;
++line;
}
}
// column & line start at 1
column = int(location - lastLineStart) + 1;
++line;
}
String OurReader::getLocationLineAndColumn(Location location) const {
int line, column;
getLocationLineAndColumn(location, line, column);
char buffer[18 + 16 + 16 + 1];
jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
return buffer;
}
String OurReader::getFormattedErrorMessages() const {
String formattedMessage;
for (const auto& error : errors_) {
formattedMessage +=
"* " + getLocationLineAndColumn(error.token_.start_) + "\n";
formattedMessage += " " + error.message_ + "\n";
if (error.extra_)
formattedMessage +=
"See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
}
return formattedMessage;
}
std::vector<CharReader::StructuredError>
OurReader::getStructuredErrors() const {
std::vector<CharReader::StructuredError> allErrors;
for (const auto& error : errors_) {
CharReader::StructuredError structured;
structured.offset_start = error.token_.start_ - begin_;
structured.offset_limit = error.token_.end_ - begin_;
structured.message = error.message_;
allErrors.push_back(structured);
}
return allErrors;
}
/*OurCharReader公开继承CharReader*/
class OurCharReader : public CharReader {
public:
OurCharReader(bool collectComments, OurFeatures const& features)
: CharReader( /*使用派生类OurImpl*/
std::unique_ptr<OurImpl>(new OurImpl(collectComments, features))) {}
protected:
/*OurImpl类公开继承于Impl类*/
class OurImpl : public Impl {
public:
OurImpl(bool collectComments, OurFeatures const& features)
: collectComments_(collectComments), reader_(features) {}
bool parse(char const* beginDoc, char const* endDoc, Value* root,
String* errs) override {
/*内部调用OurReader的parse*/
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
if (errs) {
*errs = reader_.getFormattedErrorMessages();
}
return ok;
}
std::vector<CharReader::StructuredError>
getStructuredErrors() const override {
return reader_.getStructuredErrors();
}
private:
bool const collectComments_;
/*OurReader拷贝自Reader,其是实现JSON解析的关键*/
OurReader reader_;
};
};
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
CharReaderBuilder::~CharReaderBuilder() = default;
/*返回的是CharReader类型的地址*/
CharReader* CharReaderBuilder::newCharReader() const {
/*通过settings_来对features进行赋值*/
bool collectComments = settings_["collectComments"].asBool();
OurFeatures features = OurFeatures::all();
features.allowComments_ = settings_["allowComments"].asBool();
features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool();
features.strictRoot_ = settings_["strictRoot"].asBool();
features.allowDroppedNullPlaceholders_ =
settings_["allowDroppedNullPlaceholders"].asBool();
features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
// Stack limit is always a size_t, so we get this as an unsigned int
// regardless of it we have 64-bit integer support enabled.
features.stackLimit_ = static_cast<size_t>(settings_["stackLimit"].asUInt());
features.failIfExtra_ = settings_["failIfExtra"].asBool();
features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
features.skipBom_ = settings_["skipBom"].asBool();
/*返回派生类OurCharReader*/
return new OurCharReader(collectComments, features);
}
bool CharReaderBuilder::validate(Json::Value* invalid) const {
static const auto& valid_keys = *new std::set<String>{
"collectComments",
"allowComments",
"allowTrailingCommas",
"strictRoot",
"allowDroppedNullPlaceholders",
"allowNumericKeys",
"allowSingleQuotes",
"stackLimit",
"failIfExtra",
"rejectDupKeys",
"allowSpecialFloats",
"skipBom",
};
for (auto si = settings_.begin(); si != settings_.end(); ++si) {
auto key = si.name();
if (valid_keys.count(key))
continue;
if (invalid)
(*invalid)[key] = *si;
else
return false;
}
return invalid ? invalid->empty() : true;
}
Value& CharReaderBuilder::operator[](const String& key) {
return settings_[key];
}
// static
void CharReaderBuilder::strictMode(Json::Value* settings) {
//! [CharReaderBuilderStrictMode]
(*settings)["allowComments"] = false;
(*settings)["allowTrailingCommas"] = false;
(*settings)["strictRoot"] = true;
(*settings)["allowDroppedNullPlaceholders"] = false;
(*settings)["allowNumericKeys"] = false;
(*settings)["allowSingleQuotes"] = false;
(*settings)["stackLimit"] = 1000;
(*settings)["failIfExtra"] = true;
(*settings)["rejectDupKeys"] = true;
(*settings)["allowSpecialFloats"] = false;
(*settings)["skipBom"] = true;
//! [CharReaderBuilderStrictMode]
}
// static
void CharReaderBuilder::setDefaults(Json::Value* settings) {
//! [CharReaderBuilderDefaults]
(*settings)["collectComments"] = true;
(*settings)["allowComments"] = true;
(*settings)["allowTrailingCommas"] = true;
(*settings)["strictRoot"] = false;
(*settings)["allowDroppedNullPlaceholders"] = false;
(*settings)["allowNumericKeys"] = false;
(*settings)["allowSingleQuotes"] = false;
(*settings)["stackLimit"] = 1000;
(*settings)["failIfExtra"] = false;
(*settings)["rejectDupKeys"] = false;
(*settings)["allowSpecialFloats"] = false;
(*settings)["skipBom"] = true;
//! [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();
}
/*CharReader的解析函数*/
bool CharReader::parse(char const* beginDoc, char const* endDoc, Value* root,
String* errs) {
/*调用内部Impl类的parse*/
return _impl->parse(beginDoc, endDoc, root, errs);
}
//
// global functions
bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root,
String* errs) {
OStringStream ssin;
ssin << sin.rdbuf();
String doc = std::move(ssin).str();
char const* begin = doc.data();
char const* end = begin + doc.size();
// Note that we do not actually need a null-terminator.
CharReaderPtr const reader(fact.newCharReader());
return reader->parse(begin, end, root, errs);
}
IStream& operator>>(IStream& sin, Value& root) {
CharReaderBuilder b;
String errs;
bool ok = parseFromStream(b, sin, &root, &errs);
if (!ok) {
throwRuntimeError(errs);
}
return sin;
}
} // namespace Json