//------------------------------------------------------------------------------ /* Copyright (c) 2011-2013, OpenCoin, Inc. */ //============================================================================== namespace Json { const Value Value::null; const Int Value::minInt = Int ( ~ (UInt (-1) / 2) ); const Int Value::maxInt = Int ( UInt (-1) / 2 ); const UInt Value::maxUInt = UInt (-1); // A "safe" implementation of strdup. Allow null pointer to be passed. // Also avoid warning on msvc80. // //inline char *safeStringDup( const char *czstring ) //{ // if ( czstring ) // { // const size_t length = (unsigned int)( strlen(czstring) + 1 ); // char *newString = static_cast( malloc( length ) ); // memcpy( newString, czstring, length ); // return newString; // } // return 0; //} // //inline char *safeStringDup( const std::string &str ) //{ // if ( !str.empty() ) // { // const size_t length = str.length(); // char *newString = static_cast( malloc( length + 1 ) ); // memcpy( newString, str.c_str(), length ); // newString[length] = 0; // return newString; // } // return 0; //} ValueAllocator::~ValueAllocator () { } class DefaultValueAllocator : public ValueAllocator { public: virtual ~DefaultValueAllocator () { } virtual char* makeMemberName ( const char* memberName ) { return duplicateStringValue ( memberName ); } virtual void releaseMemberName ( char* memberName ) { releaseStringValue ( memberName ); } virtual char* duplicateStringValue ( const char* value, unsigned int length = unknown ) { //@todo invesgate this old optimization //if ( !value || value[0] == 0 ) // return 0; if ( length == unknown ) length = (unsigned int)strlen (value); char* newString = static_cast ( malloc ( length + 1 ) ); memcpy ( newString, value, length ); newString[length] = 0; return newString; } virtual void releaseStringValue ( char* value ) { if ( value ) free ( value ); } }; static ValueAllocator*& valueAllocator () { static ValueAllocator* valueAllocator = new DefaultValueAllocator; return valueAllocator; } static struct DummyValueAllocatorInitializer { DummyValueAllocatorInitializer () { valueAllocator (); // ensure valueAllocator() statics are initialized before main(). } } dummyValueAllocatorInitializer; // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ValueInternals... // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// #ifdef JSON_VALUE_USE_INTERNAL_MAP # include "json_internalarray.inl" # include "json_internalmap.inl" #endif // JSON_VALUE_USE_INTERNAL_MAP # include "json_valueiterator.inl" // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class Value::CommentInfo // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// Value::CommentInfo::CommentInfo () : comment_ ( 0 ) { } Value::CommentInfo::~CommentInfo () { if ( comment_ ) valueAllocator ()->releaseStringValue ( comment_ ); } void Value::CommentInfo::setComment ( const char* text ) { if ( comment_ ) valueAllocator ()->releaseStringValue ( comment_ ); JSON_ASSERT ( text ); JSON_ASSERT_MESSAGE ( text[0] == '\0' || text[0] == '/', "Comments must start with /"); // It seems that /**/ style comments are acceptable as well. comment_ = valueAllocator ()->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 ( int index ) : cstr_ ( 0 ) , index_ ( index ) { } Value::CZString::CZString ( const char* cstr, DuplicationPolicy allocate ) : cstr_ ( allocate == duplicate ? valueAllocator ()->makeMemberName (cstr) : cstr ) , index_ ( allocate ) { } Value::CZString::CZString ( const CZString& other ) : cstr_ ( other.index_ != noDuplication&& other.cstr_ != 0 ? valueAllocator ()->makeMemberName ( other.cstr_ ) : other.cstr_ ) , index_ ( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) : other.index_ ) { } Value::CZString::~CZString () { if ( cstr_ && index_ == duplicate ) valueAllocator ()->releaseMemberName ( const_cast ( cstr_ ) ); } void Value::CZString::swap ( CZString& other ) { std::swap ( cstr_, other.cstr_ ); std::swap ( index_, other.index_ ); } Value::CZString& Value::CZString::operator = ( const CZString& other ) { CZString temp ( other ); swap ( temp ); 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_; } int 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 ) : type_ ( type ) , allocated_ ( 0 ) , comments_ ( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_ ( 0 ) #endif { 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 ) : type_ ( intValue ) , comments_ ( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_ ( 0 ) #endif { value_.int_ = value; } Value::Value ( UInt value ) : type_ ( uintValue ) , comments_ ( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_ ( 0 ) #endif { value_.uint_ = value; } Value::Value ( double value ) : type_ ( realValue ) , comments_ ( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_ ( 0 ) #endif { value_.real_ = value; } Value::Value ( const char* value ) : type_ ( stringValue ) , allocated_ ( true ) , comments_ ( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_ ( 0 ) #endif { value_.string_ = valueAllocator ()->duplicateStringValue ( value ); } Value::Value ( const char* beginValue, const char* endValue ) : type_ ( stringValue ) , allocated_ ( true ) , comments_ ( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_ ( 0 ) #endif { value_.string_ = valueAllocator ()->duplicateStringValue ( beginValue, UInt (endValue - beginValue) ); } Value::Value ( const std::string& value ) : type_ ( stringValue ) , allocated_ ( true ) , comments_ ( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_ ( 0 ) #endif { value_.string_ = valueAllocator ()->duplicateStringValue ( value.c_str (), (unsigned int)value.length () ); } Value::Value (beast::String const& beastString) : type_ ( stringValue ) , allocated_ ( true ) , comments_ ( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_ ( 0 ) #endif { value_.string_ = valueAllocator ()->duplicateStringValue ( beastString.toStdString ().c_str (), (unsigned int)beastString.length () ); } Value::Value ( const StaticString& value ) : type_ ( stringValue ) , allocated_ ( false ) , comments_ ( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_ ( 0 ) #endif { value_.string_ = const_cast ( value.c_str () ); } # ifdef JSON_USE_CPPTL Value::Value ( const CppTL::ConstString& value ) : type_ ( stringValue ) , allocated_ ( true ) , comments_ ( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_ ( 0 ) #endif { value_.string_ = valueAllocator ()->duplicateStringValue ( value, value.length () ); } # endif Value::Value ( bool value ) : type_ ( booleanValue ) , comments_ ( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_ ( 0 ) #endif { value_.bool_ = value; } Value::Value ( const Value& other ) : type_ ( other.type_ ) , comments_ ( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_ ( 0 ) #endif { switch ( type_ ) { case nullValue: case intValue: case uintValue: case realValue: case booleanValue: value_ = other.value_; break; case stringValue: if ( other.value_.string_ ) { value_.string_ = valueAllocator ()->duplicateStringValue ( other.value_.string_ ); allocated_ = true; } else value_.string_ = 0; 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_ ) valueAllocator ()->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= ( const Value& other ) { Value temp ( other ); swap ( temp ); 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; } ValueType Value::type () const { return type_; } int Value::compare ( const Value& other ) { /* int typeDelta = other.type_ - type_; switch ( type_ ) { case nullValue: return other.type_ == type_; case intValue: if ( other.type_.isNumeric() case uintValue: case realValue: case booleanValue: break; case stringValue, break; case arrayValue: delete value_.array_; break; case objectValue: delete value_.map_; default: JSON_ASSERT_UNREACHABLE; } */ return 0; // unreachable } 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 0; // 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 0; // unreachable } bool Value::operator != ( const Value& other ) const { return ! ( *this == other ); } const char* Value::asCString () const { JSON_ASSERT ( type_ == 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 lexicalCastThrow (value_.int_); case uintValue: case realValue: case arrayValue: case objectValue: JSON_ASSERT_MESSAGE ( false, "Type is not convertible to string" ); default: JSON_ASSERT_UNREACHABLE; } return ""; // unreachable } # ifdef JSON_USE_CPPTL CppTL::ConstString Value::asConstString () const { return CppTL::ConstString ( asString ().c_str () ); } # endif Value::Int Value::asInt () const { switch ( type_ ) { case nullValue: return 0; case intValue: return value_.int_; case uintValue: JSON_ASSERT_MESSAGE ( value_.uint_ < (unsigned)maxInt, "integer out of signed integer range" ); return value_.uint_; case realValue: JSON_ASSERT_MESSAGE ( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); return Int ( value_.real_ ); case booleanValue: return value_.bool_ ? 1 : 0; case stringValue: return lexicalCastThrow (value_.string_); case arrayValue: case objectValue: JSON_ASSERT_MESSAGE ( false, "Type is not convertible to int" ); default: JSON_ASSERT_UNREACHABLE; } return 0; // unreachable; } Value::UInt Value::asUInt () const { switch ( type_ ) { case nullValue: return 0; case intValue: JSON_ASSERT_MESSAGE ( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); return value_.int_; case uintValue: return value_.uint_; case realValue: JSON_ASSERT_MESSAGE ( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); return UInt ( value_.real_ ); case booleanValue: return value_.bool_ ? 1 : 0; case stringValue: return lexicalCastThrow (value_.string_); case arrayValue: case objectValue: JSON_ASSERT_MESSAGE ( false, "Type is not convertible to uint" ); default: JSON_ASSERT_UNREACHABLE; } return 0; // unreachable; } double Value::asDouble () const { switch ( type_ ) { case nullValue: return 0.0; case intValue: return value_.int_; case uintValue: return value_.uint_; case realValue: return value_.real_; case booleanValue: return value_.bool_ ? 1.0 : 0.0; case stringValue: case arrayValue: case objectValue: JSON_ASSERT_MESSAGE ( false, "Type is not convertible to double" ); default: JSON_ASSERT_UNREACHABLE; } return 0; // unreachable; } bool Value::asBool () const { switch ( type_ ) { case nullValue: return false; case intValue: case uintValue: return value_.int_ != 0; case realValue: return value_.real_ != 0.0; case booleanValue: return value_.bool_; case stringValue: return value_.string_ && value_.string_[0] != 0; case arrayValue: case objectValue: return value_.map_->size () != 0; default: JSON_ASSERT_UNREACHABLE; } return false; // unreachable; } bool Value::isConvertibleTo ( ValueType other ) const { switch ( type_ ) { case nullValue: return true; case intValue: return ( other == nullValue && value_.int_ == 0 ) || other == intValue || ( other == uintValue && value_.int_ >= 0 ) || other == realValue || other == stringValue || other == booleanValue; case uintValue: return ( other == nullValue && value_.uint_ == 0 ) || ( other == intValue && value_.uint_ <= (unsigned)maxInt ) || other == uintValue || other == realValue || other == stringValue || other == booleanValue; case realValue: return ( other == nullValue && value_.real_ == 0.0 ) || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt ) || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt ) || other == realValue || other == stringValue || other == booleanValue; case booleanValue: return ( other == nullValue && value_.bool_ == false ) || other == intValue || other == uintValue || other == realValue || other == stringValue || other == booleanValue; case stringValue: return other == stringValue || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) ); case arrayValue: return other == arrayValue || ( other == nullValue && value_.map_->size () == 0 ); case objectValue: return other == objectValue || ( other == nullValue && value_.map_->size () == 0 ); default: JSON_ASSERT_UNREACHABLE; } return false; // unreachable; } /// Number of values in array or object Value::UInt 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 Int ( value_.map_->size () ); #else case arrayValue: return Int ( value_.array_->size () ); case objectValue: return Int ( value_.map_->size () ); #endif default: 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 ( type_ == nullValue || type_ == arrayValue || type_ == objectValue ); 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 ( UInt newSize ) { JSON_ASSERT ( type_ == nullValue || type_ == arrayValue ); if ( type_ == nullValue ) *this = Value ( arrayValue ); #ifndef JSON_VALUE_USE_INTERNAL_MAP UInt oldSize = size (); if ( newSize == 0 ) clear (); else if ( newSize > oldSize ) (*this)[ newSize - 1 ]; else { for ( UInt index = newSize; index < oldSize; ++index ) value_.map_->erase ( index ); assert ( size () == newSize ); } #else value_.array_->resize ( newSize ); #endif } Value& Value::operator[] ( UInt index ) { JSON_ASSERT ( type_ == nullValue || type_ == 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 } const Value& Value::operator[] ( UInt index ) const { JSON_ASSERT ( type_ == nullValue || type_ == 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 } Value& Value::operator[] ( const char* key ) { return resolveReference ( key, false ); } Value& Value::resolveReference ( const char* key, bool isStatic ) { JSON_ASSERT ( type_ == nullValue || type_ == 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 ( UInt index, const Value& defaultValue ) const { const Value* value = & ((*this)[index]); return value == &null ? defaultValue : *value; } bool Value::isValidIndex ( UInt index ) const { return index < size (); } const Value& Value::operator[] ( const char* key ) const { JSON_ASSERT ( type_ == nullValue || type_ == 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 ( type_ == nullValue || type_ == 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 ( type_ == nullValue || type_ == 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 bool Value::isNull () const { return type_ == nullValue; } bool Value::isBool () const { return type_ == booleanValue; } bool Value::isInt () const { return type_ == intValue; } bool Value::isUInt () const { return type_ == uintValue; } bool Value::isIntegral () const { return type_ == intValue || type_ == uintValue || type_ == booleanValue; } bool Value::isDouble () const { return type_ == realValue; } bool Value::isNumeric () const { return isIntegral () || isDouble (); } bool Value::isString () const { return type_ == stringValue; } bool Value::isArray () const { return type_ == nullValue || type_ == arrayValue; } bool Value::isObject () const { return type_ == nullValue || 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 ""; } 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 () : kind_ ( kindNone ) { } PathArgument::PathArgument ( Value::UInt index ) : index_ ( index ) , kind_ ( kindIndex ) { } PathArgument::PathArgument ( const char* key ) : key_ ( key ) , kind_ ( kindKey ) { } PathArgument::PathArgument ( const std::string& key ) : key_ ( key.c_str () ) , 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 { Value::UInt index = 0; for ( ; current != end && *current >= '0' && *current <= '9'; ++current ) index = index * 10 + Value::UInt (*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