#include <iostream> #include <json/value.h> #include <json/writer.h> #include <utility> #include <stdexcept> #include <cstring> #include <cassert> #ifdef JSON_USE_CPPTL # include <cpptl/conststring.h> #endif #include <cstddef> // size_t #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR # include "json_batchallocator.h" #endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR #define JSON_ASSERT_UNREACHABLE assert( false ) #define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw #define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) throw std::runtime_error( message ); namespace Json { // QNX is strict about declaring C symbols in the std namespace. #ifdef __QNXNTO__ using std::memcpy; using std::strchr; using std::strcmp; using std::strlen; #endif 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<char *>( 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<char *>( 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<char *>( 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 DefaultValueAllocator defaultAllocator; static ValueAllocator *valueAllocator = &defaultAllocator; 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<char *>( 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( const StaticString &value ) : type_( stringValue ) , allocated_( false ) , comments_( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_( 0 ) #endif { value_.string_ = const_cast<char *>( 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: 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: 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: 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<const CZString &>() ), // MemberNamesTransform() ) ); // } // return EnumMemberNames(); //} // // //EnumValues //Value::enumValues() const //{ // if ( type_ == objectValue || type_ == arrayValue ) // return CppTL::Enum::anyValues( *(value_.map_), // CppTL::Type<const Value &>() ); // 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