// 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>// 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) {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// staticValue 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!// staticValue const& Value::null = Value::nullSingleton();// staticValue 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. ~cdunnreturn d >= static_cast<double>(min) && d <= static_cast<double>(max);}#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)static inline double integerToDouble(Json::UInt64 value) {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);}#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.*/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 laterreturn 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_USING_SECURE_MEMORYstatic 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 memorysize_t size = (length == 0) ? strlen(value) : length;memset(value, 0, size);free(value);}#else // !JSONCPP_USING_SECURE_MEMORYstatic inline void releasePrefixedStringValue(char* value) { free(value); }static inline void releaseStringValue(char* value, unsigned) { free(value); }#endif // JSONCPP_USING_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_EXCEPTIONException::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_EXCEPTIONJSONCPP_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.Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {}Value::CZString::CZString(char const* str, unsigned length,DuplicationPolicy allocate): cstr_(str) {// allocate != duplicatestorage_.policy_ = allocate & 0x3;storage_.length_ = length & 0x3FFFFFFF;}Value::CZString::CZString(const CZString& 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) {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;}bool Value::CZString::operator<(const CZString& other) const {if (!cstr_)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_)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(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)));}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()));}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;}void Value::swapPayload(Value& other) {std::swap(bits_, other.bits_);std::swap(value_, other.value_);}void Value::copyPayload(const Value& other) {releasePayload();dupPayload(other);}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);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); }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_USING_SECURE_MEMORYunsigned 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;}#endifbool 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;}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);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");}}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.");}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_, 0, 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: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_, 0, 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();#elsereturn asInt64();#endif}LargestUInt Value::asLargestUInt() const {#if defined(JSON_NO_INT64)return asUInt();#elsereturn 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;case booleanValue:return value_.bool_ ? 1.0 : 0.0;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.");}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 falseconst 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.");}bool Value::isConvertibleTo(ValueType other) const {switch (other) {case nullValue:return (isNumeric() && asDouble() == 0.0) ||(type() == booleanValue && !value_.bool_) ||(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_, 0, 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 objectArrayIndex 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 + 1if (!value_.map_->empty()) {ObjectValues::const_iterator itLast = value_.map_->end();--itLast;return (*itLast).first.index() + 1;}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;}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);}}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);auto it = value_.map_->lower_bound(key);if (it != value_.map_->end() && (*it).first == key)return (*it).second;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)];}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_;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); // NOTE!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* 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);}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.data(), key.data() + key.length());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());}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;}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;}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);}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;}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);}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()); }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 = 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;}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());}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;}static bool IsIntegral(double d) {double integral_part;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;#elsereturn true;#endifcase 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);#elsereturn value_.int_ >= 0;#endifcase uintValue:#if defined(JSON_HAS_INT64)return value_.uint_ <= maxUInt;#elsereturn true;#endifcase 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.return value_.real_ >= double(minInt64) &&value_.real_ < double(maxInt64) && IsIntegral(value_.real_);default:break;}#endif // JSON_HAS_INT64return 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_INT64return 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.return value_.real_ >= double(minInt64) &&value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);#elsereturn value_.real_ >= minInt && value_.real_ <= maxUInt &&IsIntegral(value_.real_);#endif // JSON_HAS_INT64default:break;}return false;}bool Value::isDouble() const {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(!comment.empty());JSON_ASSERT_MESSAGE(comment[0] == '0円' || 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
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。