// Copyright 2011 Baptiste Lepilleur // 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 #include #include #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR #include "json_batchallocator.h" #endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR #endif // if !defined(JSON_IS_AMALGAMATION) #include #include #include #include #include #ifdef JSON_USE_CPPTL #include #endif #include // size_t #define JSON_ASSERT_UNREACHABLE assert(false) namespace Json { // 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 const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; const unsigned char& kNullRef = kNull[0]; const Value& Value::null = reinterpret_cast(kNullRef); const Int Value::minInt = Int(~(UInt(-1) / 2)); const Int Value::maxInt = Int(UInt(-1) / 2); const UInt Value::maxUInt = UInt(-1); #if defined(JSON_HAS_INT64) const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2)); const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2); const UInt64 Value::maxUInt64 = UInt64(-1); // 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 const double maxUInt64AsDouble = 18446744073709551615.0; #endif // defined(JSON_HAS_INT64) const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); const LargestUInt Value::maxLargestUInt = LargestUInt(-1); /// Unknown size marker static const unsigned int unknown = (unsigned)-1; #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) template static inline bool InRange(double d, T min, U max) { return d >= min && d <= max; } #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) static inline double integerToDouble(Json::UInt64 value) { return static_cast(Int64(value / 2)) * 2.0 + Int64(value & 1); } template static inline double integerToDouble(T value) { return static_cast(value); } template 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, unsigned int length = unknown) { if (length == unknown) length = (unsigned int)strlen(value); // Avoid an integer overflow in the call to malloc below by limiting length // to a sane value. if (length >= (unsigned)Value::maxInt) length = Value::maxInt - 1; char* newString = static_cast(malloc(length + 1)); JSON_ASSERT_MESSAGE(newString != 0, "in Json::Value::duplicateStringValue(): " "Failed to allocate string value buffer"); memcpy(newString, value, length); newString[length] = 0; return newString; } /** Free the string duplicated by duplicateStringValue(). */ static inline void releaseStringValue(char* value) { free(value); } } // namespace Json // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ValueInternals... // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// #if !defined(JSON_IS_AMALGAMATION) #ifdef JSON_VALUE_USE_INTERNAL_MAP #include "json_internalarray.inl" #include "json_internalmap.inl" #endif // JSON_VALUE_USE_INTERNAL_MAP #include "json_valueiterator.inl" #endif // if !defined(JSON_IS_AMALGAMATION) namespace Json { // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class Value::CommentInfo // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// Value::CommentInfo::CommentInfo() : comment_(0) {} Value::CommentInfo::~CommentInfo() { if (comment_) releaseStringValue(comment_); } void Value::CommentInfo::setComment(const char* text) { if (comment_) releaseStringValue(comment_); JSON_ASSERT(text != 0); JSON_ASSERT_MESSAGE( text[0] == '\0' || text[0] == '/', "in Json::Value::setComment(): Comments must start with /"); // It seems that /**/ style comments are acceptable as well. comment_ = duplicateStringValue(text); } // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class Value::CZString // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// #ifndef JSON_VALUE_USE_INTERNAL_MAP // Notes: index_ indicates if the string was allocated when // a string is stored. Value::CZString::CZString(ArrayIndex index) : cstr_(0), index_(index) {} Value::CZString::CZString(const char* cstr, DuplicationPolicy allocate) : cstr_(allocate == duplicate ? duplicateStringValue(cstr) : cstr), index_(allocate) {} Value::CZString::CZString(const CZString& other) : cstr_(other.index_ != noDuplication && other.cstr_ != 0 ? duplicateStringValue(other.cstr_) : other.cstr_), index_(other.cstr_ ? static_cast(other.index_ == noDuplication ? noDuplication : duplicate) : other.index_) {} Value::CZString::~CZString() { if (cstr_ && index_ == duplicate) releaseStringValue(const_cast(cstr_)); } void Value::CZString::swap(CZString& other) { std::swap(cstr_, other.cstr_); std::swap(index_, other.index_); } Value::CZString& Value::CZString::operator=(CZString other) { swap(other); return *this; } bool Value::CZString::operator<(const CZString& other) const { if (cstr_) return strcmp(cstr_, other.cstr_) < 0; return index_ < other.index_; } bool Value::CZString::operator==(const CZString& other) const { if (cstr_) return strcmp(cstr_, other.cstr_) == 0; return index_ == other.index_; } ArrayIndex Value::CZString::index() const { return index_; } const char* Value::CZString::c_str() const { return cstr_; } bool Value::CZString::isStaticString() const { return index_ == noDuplication; } #endif // ifndef JSON_VALUE_USE_INTERNAL_MAP // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // 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) { initBasic(type); switch (type) { case nullValue: break; case intValue: case uintValue: value_.int_ = 0; break; case realValue: value_.real_ = 0.0; break; case stringValue: value_.string_ = 0; break; #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: value_.map_ = new ObjectValues(); break; #else case arrayValue: value_.array_ = arrayAllocator()->newArray(); break; case objectValue: value_.map_ = mapAllocator()->newMap(); break; #endif 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); value_.string_ = duplicateStringValue(value); } Value::Value(const char* beginValue, const char* endValue) { initBasic(stringValue, true); value_.string_ = duplicateStringValue(beginValue, (unsigned int)(endValue - beginValue)); } Value::Value(const std::string& value) { initBasic(stringValue, true); value_.string_ = duplicateStringValue(value.c_str(), (unsigned int)value.length()); } Value::Value(const StaticString& value) { initBasic(stringValue); value_.string_ = const_cast(value.c_str()); } #ifdef JSON_USE_CPPTL Value::Value(const CppTL::ConstString& value) { initBasic(stringValue, true); value_.string_ = duplicateStringValue(value, value.length()); } #endif Value::Value(bool value) { initBasic(booleanValue); value_.bool_ = value; } Value::Value(const Value& other) : type_(other.type_), allocated_(false) #ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_(0) #endif , comments_(0), start_(other.start_), limit_(other.limit_) { switch (type_) { case nullValue: case intValue: case uintValue: case realValue: case booleanValue: value_ = other.value_; break; case stringValue: if (other.value_.string_) { value_.string_ = duplicateStringValue(other.value_.string_); allocated_ = true; } else { value_.string_ = 0; allocated_ = false; } break; #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: value_.map_ = new ObjectValues(*other.value_.map_); break; #else case arrayValue: value_.array_ = arrayAllocator()->newArrayCopy(*other.value_.array_); break; case objectValue: value_.map_ = mapAllocator()->newMapCopy(*other.value_.map_); break; #endif default: JSON_ASSERT_UNREACHABLE; } if (other.comments_) { comments_ = new CommentInfo[numberOfCommentPlacement]; for (int comment = 0; comment < numberOfCommentPlacement; ++comment) { const CommentInfo& otherComment = other.comments_[comment]; if (otherComment.comment_) comments_[comment].setComment(otherComment.comment_); } } } Value::~Value() { switch (type_) { case nullValue: case intValue: case uintValue: case realValue: case booleanValue: break; case stringValue: if (allocated_) releaseStringValue(value_.string_); break; #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: delete value_.map_; break; #else case arrayValue: arrayAllocator()->destructArray(value_.array_); break; case objectValue: mapAllocator()->destructMap(value_.map_); break; #endif default: JSON_ASSERT_UNREACHABLE; } if (comments_) delete[] comments_; } Value& Value::operator=(Value other) { swap(other); return *this; } void Value::swap(Value& other) { ValueType temp = type_; type_ = other.type_; other.type_ = temp; std::swap(value_, other.value_); int temp2 = allocated_; allocated_ = other.allocated_; other.allocated_ = temp2; std::swap(start_, other.start_); std::swap(limit_, other.limit_); } ValueType Value::type() const { return 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 ? true : false; 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: return (value_.string_ == 0 && other.value_.string_) || (other.value_.string_ && value_.string_ && strcmp(value_.string_, other.value_.string_) < 0); #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: { int delta = int(value_.map_->size() - other.value_.map_->size()); if (delta) return delta < 0; return (*value_.map_) < (*other.value_.map_); } #else case arrayValue: return value_.array_->compare(*(other.value_.array_)) < 0; case objectValue: return value_.map_->compare(*(other.value_.map_)) < 0; #endif 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_ ) // GCC 2.95.3 says: // attempt to take address of bit-field structure member `Json::Value::type_' // Beats me, but a temp solves the problem. int temp = other.type_; if (type_ != temp) 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: return (value_.string_ == other.value_.string_) || (other.value_.string_ && value_.string_ && strcmp(value_.string_, other.value_.string_) == 0); #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: return value_.map_->size() == other.value_.map_->size() && (*value_.map_) == (*other.value_.map_); #else case arrayValue: return value_.array_->compare(*(other.value_.array_)) == 0; case objectValue: return value_.map_->compare(*(other.value_.map_)) == 0; #endif 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"); return value_.string_; } std::string Value::asString() const { switch (type_) { case nullValue: return ""; case stringValue: return value_.string_ ? value_.string_ : ""; 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"); } } #ifdef JSON_USE_CPPTL CppTL::ConstString Value::asConstString() const { return CppTL::ConstString(asString().c_str()); } #endif 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(); #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(value_.int_); case uintValue: #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) return static_cast(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(value_.int_); case uintValue: #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) return static_cast(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 static_cast(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_ ? true : false; case uintValue: return value_.uint_ ? true : false; case realValue: return value_.real_ ? true : false; 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_ == false) || (type_ == stringValue && asString() == "") || (type_ == arrayValue && value_.map_->size() == 0) || (type_ == objectValue && value_.map_->size() == 0) || 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 object ArrayIndex Value::size() const { switch (type_) { case nullValue: case intValue: case uintValue: case realValue: case booleanValue: case stringValue: return 0; #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: // size of the array is highest index + 1 if (!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()); #else case arrayValue: return Int(value_.array_->size()); case objectValue: return Int(value_.map_->size()); #endif } JSON_ASSERT_UNREACHABLE; return 0; // unreachable; } bool Value::empty() const { if (isNull() || isArray() || isObject()) return size() == 0u; else return false; } bool Value::operator!() 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_) { #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: value_.map_->clear(); break; #else case arrayValue: value_.array_->clear(); break; case objectValue: value_.map_->clear(); break; #endif 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); #ifndef JSON_VALUE_USE_INTERNAL_MAP ArrayIndex oldSize = size(); if (newSize == 0) clear(); else if (newSize > oldSize) (*this)[newSize - 1]; else { for (ArrayIndex index = newSize; index < oldSize; ++index) { value_.map_->erase(index); } assert(size() == newSize); } #else value_.array_->resize(newSize); #endif } 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); #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString key(index); ObjectValues::iterator it = value_.map_->lower_bound(key); if (it != value_.map_->end() && (*it).first == key) return (*it).second; ObjectValues::value_type defaultValue(key, null); it = value_.map_->insert(it, defaultValue); return (*it).second; #else return value_.array_->resolveReference(index); #endif } 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 null; #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString key(index); ObjectValues::const_iterator it = value_.map_->find(key); if (it == value_.map_->end()) return null; return (*it).second; #else Value* value = value_.array_->find(index); return value ? *value : null; #endif } 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)]; } Value& Value::operator[](const char* key) { return resolveReference(key, false); } void Value::initBasic(ValueType type, bool allocated) { type_ = type; allocated_ = allocated; #ifdef JSON_VALUE_USE_INTERNAL_MAP itemIsUsed_ = 0; #endif comments_ = 0; start_ = 0; limit_ = 0; } Value& Value::resolveReference(const char* key, bool isStatic) { JSON_ASSERT_MESSAGE( type_ == nullValue || type_ == objectValue, "in Json::Value::resolveReference(): requires objectValue"); if (type_ == nullValue) *this = Value(objectValue); #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString actualKey( key, isStatic ? CZString::noDuplication : CZString::duplicateOnCopy); ObjectValues::iterator it = value_.map_->lower_bound(actualKey); if (it != value_.map_->end() && (*it).first == actualKey) return (*it).second; ObjectValues::value_type defaultValue(actualKey, null); it = value_.map_->insert(it, defaultValue); Value& value = (*it).second; return value; #else return value_.map_->resolveReference(key, isStatic); #endif } Value Value::get(ArrayIndex index, const Value& defaultValue) const { const Value* value = &((*this)[index]); return value == &null ? defaultValue : *value; } bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } const Value& Value::operator[](const char* key) const { JSON_ASSERT_MESSAGE( type_ == nullValue || type_ == objectValue, "in Json::Value::operator[](char const*)const: requires objectValue"); if (type_ == nullValue) return null; #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString actualKey(key, CZString::noDuplication); ObjectValues::const_iterator it = value_.map_->find(actualKey); if (it == value_.map_->end()) return null; return (*it).second; #else const Value* value = value_.map_->find(key); return value ? *value : null; #endif } Value& Value::operator[](const std::string& key) { return (*this)[key.c_str()]; } const Value& Value::operator[](const std::string& key) const { return (*this)[key.c_str()]; } Value& Value::operator[](const StaticString& key) { return resolveReference(key, true); } #ifdef JSON_USE_CPPTL Value& Value::operator[](const CppTL::ConstString& key) { return (*this)[key.c_str()]; } const Value& Value::operator[](const CppTL::ConstString& key) const { return (*this)[key.c_str()]; } #endif Value& Value::append(const Value& value) { return (*this)[size()] = value; } Value Value::get(const char* key, const Value& defaultValue) const { const Value* value = &((*this)[key]); return value == &null ? defaultValue : *value; } Value Value::get(const std::string& key, const Value& defaultValue) const { return get(key.c_str(), defaultValue); } Value Value::removeMember(const char* key) { JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, "in Json::Value::removeMember(): requires objectValue"); if (type_ == nullValue) return null; #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString actualKey(key, CZString::noDuplication); ObjectValues::iterator it = value_.map_->find(actualKey); if (it == value_.map_->end()) return null; Value old(it->second); value_.map_->erase(it); return old; #else Value* value = value_.map_->find(key); if (value) { Value old(*value); value_.map_.remove(key); return old; } else { return null; } #endif } Value Value::removeMember(const std::string& key) { return removeMember(key.c_str()); } #ifdef JSON_USE_CPPTL Value Value::get(const CppTL::ConstString& key, const Value& defaultValue) const { return get(key.c_str(), defaultValue); } #endif bool Value::isMember(const char* key) const { const Value* value = &((*this)[key]); return value != &null; } bool Value::isMember(const std::string& key) const { return isMember(key.c_str()); } #ifdef JSON_USE_CPPTL bool Value::isMember(const CppTL::ConstString& key) const { return isMember(key.c_str()); } #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()); #ifndef JSON_VALUE_USE_INTERNAL_MAP ObjectValues::const_iterator it = value_.map_->begin(); ObjectValues::const_iterator itEnd = value_.map_->end(); for (; it != itEnd; ++it) members.push_back(std::string((*it).first.c_str())); #else ValueInternalMap::IteratorState it; ValueInternalMap::IteratorState itEnd; value_.map_->makeBeginIterator(it); value_.map_->makeEndIterator(itEnd); for (; !ValueInternalMap::equals(it, itEnd); ValueInternalMap::increment(it)) members.push_back(std::string(ValueInternalMap::key(it))); #endif return members; } // //# ifdef JSON_USE_CPPTL // EnumMemberNames // Value::enumMemberNames() const //{ // if ( type_ == objectValue ) // { // return CppTL::Enum::any( CppTL::Enum::transform( // CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), // MemberNamesTransform() ) ); // } // return EnumMemberNames(); //} // // // EnumValues // Value::enumValues() const //{ // if ( type_ == objectValue || type_ == arrayValue ) // return CppTL::Enum::anyValues( *(value_.map_), // CppTL::Type() ); // return EnumValues(); //} // //# endif 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: return value_.int_ >= minInt && value_.int_ <= maxInt; 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: return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); case uintValue: return value_.uint_ <= maxUInt; 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. 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 { #if defined(JSON_HAS_INT64) return isInt64() || isUInt64(); #else return isInt() || isUInt(); #endif } bool Value::isDouble() const { return type_ == realValue || isIntegral(); } bool Value::isNumeric() const { return isIntegral() || isDouble(); } bool Value::isString() const { return type_ == stringValue; } bool Value::isArray() const { return type_ == arrayValue; } bool Value::isObject() const { return type_ == objectValue; } void Value::setComment(const char* comment, CommentPlacement placement) { if (!comments_) comments_ = new CommentInfo[numberOfCommentPlacement]; comments_[placement].setComment(comment); } void Value::setComment(const std::string& comment, CommentPlacement placement) { setComment(comment.c_str(), placement); } bool Value::hasComment(CommentPlacement placement) const { return comments_ != 0 && comments_[placement].comment_ != 0; } std::string Value::getComment(CommentPlacement placement) const { if (hasComment(placement)) return comments_[placement].comment_; return ""; } void Value::setOffsetStart(size_t start) { start_ = start; } void Value::setOffsetLimit(size_t limit) { limit_ = limit; } size_t Value::getOffsetStart() const { return start_; } size_t Value::getOffsetLimit() const { return limit_; } std::string Value::toStyledString() const { StyledWriter writer; return writer.write(*this); } Value::const_iterator Value::begin() const { switch (type_) { #ifdef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: if (value_.array_) { ValueInternalArray::IteratorState it; value_.array_->makeBeginIterator(it); return const_iterator(it); } break; case objectValue: if (value_.map_) { ValueInternalMap::IteratorState it; value_.map_->makeBeginIterator(it); return const_iterator(it); } break; #else case arrayValue: case objectValue: if (value_.map_) return const_iterator(value_.map_->begin()); break; #endif default: break; } return const_iterator(); } Value::const_iterator Value::end() const { switch (type_) { #ifdef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: if (value_.array_) { ValueInternalArray::IteratorState it; value_.array_->makeEndIterator(it); return const_iterator(it); } break; case objectValue: if (value_.map_) { ValueInternalMap::IteratorState it; value_.map_->makeEndIterator(it); return const_iterator(it); } break; #else case arrayValue: case objectValue: if (value_.map_) return const_iterator(value_.map_->end()); break; #endif default: break; } return const_iterator(); } Value::iterator Value::begin() { switch (type_) { #ifdef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: if (value_.array_) { ValueInternalArray::IteratorState it; value_.array_->makeBeginIterator(it); return iterator(it); } break; case objectValue: if (value_.map_) { ValueInternalMap::IteratorState it; value_.map_->makeBeginIterator(it); return iterator(it); } break; #else case arrayValue: case objectValue: if (value_.map_) return iterator(value_.map_->begin()); break; #endif default: break; } return iterator(); } Value::iterator Value::end() { switch (type_) { #ifdef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: if (value_.array_) { ValueInternalArray::IteratorState it; value_.array_->makeEndIterator(it); return iterator(it); } break; case objectValue: if (value_.map_) { ValueInternalMap::IteratorState it; value_.map_->makeEndIterator(it); return iterator(it); } break; #else case arrayValue: case objectValue: if (value_.map_) return iterator(value_.map_->end()); break; #endif default: break; } return iterator(); } // class PathArgument // ////////////////////////////////////////////////////////////////// PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {} PathArgument::PathArgument(ArrayIndex index) : key_(), index_(index), kind_(kindIndex) {} PathArgument::PathArgument(const char* key) : key_(key), index_(), kind_(kindKey) {} PathArgument::PathArgument(const std::string& key) : key_(key.c_str()), index_(), kind_(kindKey) {} // class Path // ////////////////////////////////////////////////////////////////// Path::Path(const std::string& path, const PathArgument& a1, const PathArgument& a2, const PathArgument& a3, const PathArgument& a4, const PathArgument& a5) { InArgs in; 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 std::string& path, const InArgs& in) { const char* current = path.c_str(); const char* end = current + path.length(); InArgs::const_iterator 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; } else { const char* beginName = current; while (current != end && !strchr("[.", *current)) ++current; args_.push_back(std::string(beginName, current)); } } } void Path::addPathInArg(const std::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 std::string& /*path*/, int /*location*/) { // Error: invalid path. } const Value& Path::resolve(const Value& root) const { const Value* node = &root; for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { const PathArgument& arg = *it; if (arg.kind_ == PathArgument::kindIndex) { if (!node->isArray() || !node->isValidIndex(arg.index_)) { // Error: unable to resolve path (array value expected at position... } node = &((*node)[arg.index_]); } else if (arg.kind_ == PathArgument::kindKey) { if (!node->isObject()) { // Error: unable to resolve path (object value expected at position...) } node = &((*node)[arg.key_]); if (node == &Value::null) { // Error: unable to resolve path (object has no member named '' at // position...) } } } return *node; } Value Path::resolve(const Value& root, const Value& defaultValue) const { const Value* node = &root; for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { const PathArgument& arg = *it; 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::null) return defaultValue; } } return *node; } Value& Path::make(Value& root) const { Value* node = &root; for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { const PathArgument& arg = *it; 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