//------------------------------------------------------------------------------ /* This file is part of rippled: https://github.com/ripple/rippled Copyright (c) 2012, 2013 Ripple Labs Inc. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== #include "../../beast/modules/beast_core/text/LexicalCast.h" 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 beast::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 beast::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 beast::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