ian@0: // Copyright 2011 Baptiste Lepilleur ian@0: // Distributed under MIT license, or public domain if desired and ian@0: // recognized in your jurisdiction. ian@0: // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE ian@0: ian@0: #if !defined(JSON_IS_AMALGAMATION) ian@0: # include ian@0: # include ian@0: # include ian@0: # ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR ian@0: # include "json_batchallocator.h" ian@0: # endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR ian@0: #endif // if !defined(JSON_IS_AMALGAMATION) ian@0: #include ian@0: #include ian@0: #include ian@0: #include ian@0: #include ian@0: #include ian@0: #include ian@0: #ifdef JSON_USE_CPPTL ian@0: # include ian@0: #endif ian@0: #include // size_t ian@0: ian@0: #define JSON_ASSERT_UNREACHABLE assert( false ) ian@0: ian@0: namespace Json { ian@0: ian@0: const Value Value::null; ian@0: const Int Value::minInt = Int( ~(UInt(-1)/2) ); ian@0: const Int Value::maxInt = Int( UInt(-1)/2 ); ian@0: const UInt Value::maxUInt = UInt(-1); ian@0: # if defined(JSON_HAS_INT64) ian@0: const Int64 Value::minInt64 = Int64( ~(UInt64(-1)/2) ); ian@0: const Int64 Value::maxInt64 = Int64( UInt64(-1)/2 ); ian@0: const UInt64 Value::maxUInt64 = UInt64(-1); ian@0: // The constant is hard-coded because some compiler have trouble ian@0: // converting Value::maxUInt64 to a double correctly (AIX/xlC). ian@0: // Assumes that UInt64 is a 64 bits integer. ian@0: static const double maxUInt64AsDouble = 18446744073709551615.0; ian@0: #endif // defined(JSON_HAS_INT64) ian@0: const LargestInt Value::minLargestInt = LargestInt( ~(LargestUInt(-1)/2) ); ian@0: const LargestInt Value::maxLargestInt = LargestInt( LargestUInt(-1)/2 ); ian@0: const LargestUInt Value::maxLargestUInt = LargestUInt(-1); ian@0: ian@0: ian@0: /// Unknown size marker ian@0: static const unsigned int unknown = (unsigned)-1; ian@0: ian@0: #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) ian@0: template ian@0: static inline bool InRange(double d, T min, U max) { ian@0: return d >= min && d <= max; ian@0: } ian@0: #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) ian@0: static inline double integerToDouble( Json::UInt64 value ) ian@0: { ian@0: return static_cast( Int64(value/2) ) * 2.0 + Int64(value & 1); ian@0: } ian@0: ian@0: template ian@0: static inline double integerToDouble( T value ) ian@0: { ian@0: return static_cast( value ); ian@0: } ian@0: ian@0: template ian@0: static inline bool InRange(double d, T min, U max) { ian@0: return d >= integerToDouble(min) && d <= integerToDouble(max); ian@0: } ian@0: #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) ian@0: ian@0: ian@0: /** Duplicates the specified string value. ian@0: * @param value Pointer to the string to duplicate. Must be zero-terminated if ian@0: * length is "unknown". ian@0: * @param length Length of the value. if equals to unknown, then it will be ian@0: * computed using strlen(value). ian@0: * @return Pointer on the duplicate instance of string. ian@0: */ ian@0: static inline char * ian@0: duplicateStringValue( const char *value, ian@0: unsigned int length = unknown ) ian@0: { ian@0: if ( length == unknown ) ian@0: length = (unsigned int)strlen(value); ian@0: ian@0: // Avoid an integer overflow in the call to malloc below by limiting length ian@0: // to a sane value. ian@0: if (length >= (unsigned)Value::maxInt) ian@0: length = Value::maxInt - 1; ian@0: ian@0: char *newString = static_cast( malloc( length + 1 ) ); ian@0: JSON_ASSERT_MESSAGE( newString != 0, "Failed to allocate string value buffer" ); ian@0: memcpy( newString, value, length ); ian@0: newString[length] = 0; ian@0: return newString; ian@0: } ian@0: ian@0: ian@0: /** Free the string duplicated by duplicateStringValue(). ian@0: */ ian@0: static inline void ian@0: releaseStringValue( char *value ) ian@0: { ian@0: if ( value ) ian@0: free( value ); ian@0: } ian@0: ian@0: } // namespace Json ian@0: ian@0: ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // ValueInternals... ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // ////////////////////////////////////////////////////////////////// ian@0: #if !defined(JSON_IS_AMALGAMATION) ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: # include "json_internalarray.inl" ian@0: # include "json_internalmap.inl" ian@0: # endif // JSON_VALUE_USE_INTERNAL_MAP ian@0: ian@0: # include "json_valueiterator.inl" ian@0: #endif // if !defined(JSON_IS_AMALGAMATION) ian@0: ian@0: namespace Json { ian@0: ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // class Value::CommentInfo ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // ////////////////////////////////////////////////////////////////// ian@0: ian@0: ian@0: Value::CommentInfo::CommentInfo() ian@0: : comment_( 0 ) ian@0: { ian@0: } ian@0: ian@0: Value::CommentInfo::~CommentInfo() ian@0: { ian@0: if ( comment_ ) ian@0: releaseStringValue( comment_ ); ian@0: } ian@0: ian@0: ian@0: void ian@0: Value::CommentInfo::setComment( const char *text ) ian@0: { ian@0: if ( comment_ ) ian@0: releaseStringValue( comment_ ); ian@0: JSON_ASSERT( text != 0 ); ian@0: JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /"); ian@0: // It seems that /**/ style comments are acceptable as well. ian@0: comment_ = duplicateStringValue( text ); ian@0: } ian@0: ian@0: ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // class Value::CZString ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // ////////////////////////////////////////////////////////////////// ian@0: # ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: ian@0: // Notes: index_ indicates if the string was allocated when ian@0: // a string is stored. ian@0: ian@0: Value::CZString::CZString( ArrayIndex index ) ian@0: : cstr_( 0 ) ian@0: , index_( index ) ian@0: { ian@0: } ian@0: ian@0: Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate ) ian@0: : cstr_( allocate == duplicate ? duplicateStringValue(cstr) ian@0: : cstr ) ian@0: , index_( allocate ) ian@0: { ian@0: } ian@0: ian@0: Value::CZString::CZString( const CZString &other ) ian@0: : cstr_( other.index_ != noDuplication && other.cstr_ != 0 ian@0: ? duplicateStringValue( other.cstr_ ) ian@0: : other.cstr_ ) ian@0: , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) ian@0: : other.index_ ) ian@0: { ian@0: } ian@0: ian@0: Value::CZString::~CZString() ian@0: { ian@0: if ( cstr_ && index_ == duplicate ) ian@0: releaseStringValue( const_cast( cstr_ ) ); ian@0: } ian@0: ian@0: void ian@0: Value::CZString::swap( CZString &other ) ian@0: { ian@0: std::swap( cstr_, other.cstr_ ); ian@0: std::swap( index_, other.index_ ); ian@0: } ian@0: ian@0: Value::CZString & ian@0: Value::CZString::operator =( const CZString &other ) ian@0: { ian@0: CZString temp( other ); ian@0: swap( temp ); ian@0: return *this; ian@0: } ian@0: ian@0: bool ian@0: Value::CZString::operator<( const CZString &other ) const ian@0: { ian@0: if ( cstr_ ) ian@0: return strcmp( cstr_, other.cstr_ ) < 0; ian@0: return index_ < other.index_; ian@0: } ian@0: ian@0: bool ian@0: Value::CZString::operator==( const CZString &other ) const ian@0: { ian@0: if ( cstr_ ) ian@0: return strcmp( cstr_, other.cstr_ ) == 0; ian@0: return index_ == other.index_; ian@0: } ian@0: ian@0: ian@0: ArrayIndex ian@0: Value::CZString::index() const ian@0: { ian@0: return index_; ian@0: } ian@0: ian@0: ian@0: const char * ian@0: Value::CZString::c_str() const ian@0: { ian@0: return cstr_; ian@0: } ian@0: ian@0: bool ian@0: Value::CZString::isStaticString() const ian@0: { ian@0: return index_ == noDuplication; ian@0: } ian@0: ian@0: #endif // ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: ian@0: ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // class Value::Value ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // ////////////////////////////////////////////////////////////////// ian@0: // ////////////////////////////////////////////////////////////////// ian@0: ian@0: /*! \internal Default constructor initialization must be equivalent to: ian@0: * memset( this, 0, sizeof(Value) ) ian@0: * This optimization is used in ValueInternalMap fast allocator. ian@0: */ ian@0: Value::Value( ValueType type ) ian@0: : type_( type ) ian@0: , allocated_( false ) ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: , itemIsUsed_( 0 ) ian@0: #endif ian@0: , comments_( 0 ) ian@0: { ian@0: switch ( type ) ian@0: { ian@0: case nullValue: ian@0: break; ian@0: case intValue: ian@0: case uintValue: ian@0: value_.int_ = 0; ian@0: break; ian@0: case realValue: ian@0: value_.real_ = 0.0; ian@0: break; ian@0: case stringValue: ian@0: value_.string_ = 0; ian@0: break; ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: case arrayValue: ian@0: case objectValue: ian@0: value_.map_ = new ObjectValues(); ian@0: break; ian@0: #else ian@0: case arrayValue: ian@0: value_.array_ = arrayAllocator()->newArray(); ian@0: break; ian@0: case objectValue: ian@0: value_.map_ = mapAllocator()->newMap(); ian@0: break; ian@0: #endif ian@0: case booleanValue: ian@0: value_.bool_ = false; ian@0: break; ian@0: default: ian@0: JSON_ASSERT_UNREACHABLE; ian@0: } ian@0: } ian@0: ian@0: ian@0: Value::Value( UInt value ) ian@0: : type_( uintValue ) ian@0: , allocated_( false ) ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: , itemIsUsed_( 0 ) ian@0: #endif ian@0: , comments_( 0 ) ian@0: { ian@0: value_.uint_ = value; ian@0: } ian@0: ian@0: Value::Value( Int value ) ian@0: : type_( intValue ) ian@0: , allocated_( false ) ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: , itemIsUsed_( 0 ) ian@0: #endif ian@0: , comments_( 0 ) ian@0: { ian@0: value_.int_ = value; ian@0: } ian@0: ian@0: ian@0: # if defined(JSON_HAS_INT64) ian@0: Value::Value( Int64 value ) ian@0: : type_( intValue ) ian@0: , allocated_( false ) ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: , itemIsUsed_( 0 ) ian@0: #endif ian@0: , comments_( 0 ) ian@0: { ian@0: value_.int_ = value; ian@0: } ian@0: ian@0: ian@0: Value::Value( UInt64 value ) ian@0: : type_( uintValue ) ian@0: , allocated_( false ) ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: , itemIsUsed_( 0 ) ian@0: #endif ian@0: , comments_( 0 ) ian@0: { ian@0: value_.uint_ = value; ian@0: } ian@0: #endif // defined(JSON_HAS_INT64) ian@0: ian@0: Value::Value( double value ) ian@0: : type_( realValue ) ian@0: , allocated_( false ) ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: , itemIsUsed_( 0 ) ian@0: #endif ian@0: , comments_( 0 ) ian@0: { ian@0: value_.real_ = value; ian@0: } ian@0: ian@0: Value::Value( const char *value ) ian@0: : type_( stringValue ) ian@0: , allocated_( true ) ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: , itemIsUsed_( 0 ) ian@0: #endif ian@0: , comments_( 0 ) ian@0: { ian@0: value_.string_ = duplicateStringValue( value ); ian@0: } ian@0: ian@0: ian@0: Value::Value( const char *beginValue, ian@0: const char *endValue ) ian@0: : type_( stringValue ) ian@0: , allocated_( true ) ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: , itemIsUsed_( 0 ) ian@0: #endif ian@0: , comments_( 0 ) ian@0: { ian@0: value_.string_ = duplicateStringValue( beginValue, ian@0: (unsigned int)(endValue - beginValue) ); ian@0: } ian@0: ian@0: ian@0: Value::Value( const std::string &value ) ian@0: : type_( stringValue ) ian@0: , allocated_( true ) ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: , itemIsUsed_( 0 ) ian@0: #endif ian@0: , comments_( 0 ) ian@0: { ian@0: value_.string_ = duplicateStringValue( value.c_str(), ian@0: (unsigned int)value.length() ); ian@0: ian@0: } ian@0: ian@0: Value::Value( const StaticString &value ) ian@0: : type_( stringValue ) ian@0: , allocated_( false ) ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: , itemIsUsed_( 0 ) ian@0: #endif ian@0: , comments_( 0 ) ian@0: { ian@0: value_.string_ = const_cast( value.c_str() ); ian@0: } ian@0: ian@0: ian@0: # ifdef JSON_USE_CPPTL ian@0: Value::Value( const CppTL::ConstString &value ) ian@0: : type_( stringValue ) ian@0: , allocated_( true ) ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: , itemIsUsed_( 0 ) ian@0: #endif ian@0: , comments_( 0 ) ian@0: { ian@0: value_.string_ = duplicateStringValue( value, value.length() ); ian@0: } ian@0: # endif ian@0: ian@0: Value::Value( bool value ) ian@0: : type_( booleanValue ) ian@0: , allocated_( false ) ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: , itemIsUsed_( 0 ) ian@0: #endif ian@0: , comments_( 0 ) ian@0: { ian@0: value_.bool_ = value; ian@0: } ian@0: ian@0: ian@0: Value::Value( const Value &other ) ian@0: : type_( other.type_ ) ian@0: , allocated_( false ) ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: , itemIsUsed_( 0 ) ian@0: #endif ian@0: , comments_( 0 ) ian@0: { ian@0: switch ( type_ ) ian@0: { ian@0: case nullValue: ian@0: case intValue: ian@0: case uintValue: ian@0: case realValue: ian@0: case booleanValue: ian@0: value_ = other.value_; ian@0: break; ian@0: case stringValue: ian@0: if ( other.value_.string_ ) ian@0: { ian@0: value_.string_ = duplicateStringValue( other.value_.string_ ); ian@0: allocated_ = true; ian@0: } ian@0: else ian@0: value_.string_ = 0; ian@0: break; ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: case arrayValue: ian@0: case objectValue: ian@0: value_.map_ = new ObjectValues( *other.value_.map_ ); ian@0: break; ian@0: #else ian@0: case arrayValue: ian@0: value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ ); ian@0: break; ian@0: case objectValue: ian@0: value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ ); ian@0: break; ian@0: #endif ian@0: default: ian@0: JSON_ASSERT_UNREACHABLE; ian@0: } ian@0: if ( other.comments_ ) ian@0: { ian@0: comments_ = new CommentInfo[numberOfCommentPlacement]; ian@0: for ( int comment =0; comment < numberOfCommentPlacement; ++comment ) ian@0: { ian@0: const CommentInfo &otherComment = other.comments_[comment]; ian@0: if ( otherComment.comment_ ) ian@0: comments_[comment].setComment( otherComment.comment_ ); ian@0: } ian@0: } ian@0: } ian@0: ian@0: ian@0: Value::~Value() ian@0: { ian@0: switch ( type_ ) ian@0: { ian@0: case nullValue: ian@0: case intValue: ian@0: case uintValue: ian@0: case realValue: ian@0: case booleanValue: ian@0: break; ian@0: case stringValue: ian@0: if ( allocated_ ) ian@0: releaseStringValue( value_.string_ ); ian@0: break; ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: case arrayValue: ian@0: case objectValue: ian@0: delete value_.map_; ian@0: break; ian@0: #else ian@0: case arrayValue: ian@0: arrayAllocator()->destructArray( value_.array_ ); ian@0: break; ian@0: case objectValue: ian@0: mapAllocator()->destructMap( value_.map_ ); ian@0: break; ian@0: #endif ian@0: default: ian@0: JSON_ASSERT_UNREACHABLE; ian@0: } ian@0: ian@0: if ( comments_ ) ian@0: delete[] comments_; ian@0: } ian@0: ian@0: Value & ian@0: Value::operator=( const Value &other ) ian@0: { ian@0: Value temp( other ); ian@0: swap( temp ); ian@0: return *this; ian@0: } ian@0: ian@0: void ian@0: Value::swap( Value &other ) ian@0: { ian@0: ValueType temp = type_; ian@0: type_ = other.type_; ian@0: other.type_ = temp; ian@0: std::swap( value_, other.value_ ); ian@0: int temp2 = allocated_; ian@0: allocated_ = other.allocated_; ian@0: other.allocated_ = temp2; ian@0: } ian@0: ian@0: ValueType ian@0: Value::type() const ian@0: { ian@0: return type_; ian@0: } ian@0: ian@0: ian@0: int ian@0: Value::compare( const Value &other ) const ian@0: { ian@0: if ( *this < other ) ian@0: return -1; ian@0: if ( *this > other ) ian@0: return 1; ian@0: return 0; ian@0: } ian@0: ian@0: ian@0: bool ian@0: Value::operator <( const Value &other ) const ian@0: { ian@0: int typeDelta = type_ - other.type_; ian@0: if ( typeDelta ) ian@0: return typeDelta < 0 ? true : false; ian@0: switch ( type_ ) ian@0: { ian@0: case nullValue: ian@0: return false; ian@0: case intValue: ian@0: return value_.int_ < other.value_.int_; ian@0: case uintValue: ian@0: return value_.uint_ < other.value_.uint_; ian@0: case realValue: ian@0: return value_.real_ < other.value_.real_; ian@0: case booleanValue: ian@0: return value_.bool_ < other.value_.bool_; ian@0: case stringValue: ian@0: return ( value_.string_ == 0 && other.value_.string_ ) ian@0: || ( other.value_.string_ ian@0: && value_.string_ ian@0: && strcmp( value_.string_, other.value_.string_ ) < 0 ); ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: case arrayValue: ian@0: case objectValue: ian@0: { ian@0: int delta = int( value_.map_->size() - other.value_.map_->size() ); ian@0: if ( delta ) ian@0: return delta < 0; ian@0: return (*value_.map_) < (*other.value_.map_); ian@0: } ian@0: #else ian@0: case arrayValue: ian@0: return value_.array_->compare( *(other.value_.array_) ) < 0; ian@0: case objectValue: ian@0: return value_.map_->compare( *(other.value_.map_) ) < 0; ian@0: #endif ian@0: default: ian@0: JSON_ASSERT_UNREACHABLE; ian@0: } ian@0: return false; // unreachable ian@0: } ian@0: ian@0: bool ian@0: Value::operator <=( const Value &other ) const ian@0: { ian@0: return !(other < *this); ian@0: } ian@0: ian@0: bool ian@0: Value::operator >=( const Value &other ) const ian@0: { ian@0: return !(*this < other); ian@0: } ian@0: ian@0: bool ian@0: Value::operator >( const Value &other ) const ian@0: { ian@0: return other < *this; ian@0: } ian@0: ian@0: bool ian@0: Value::operator ==( const Value &other ) const ian@0: { ian@0: //if ( type_ != other.type_ ) ian@0: // GCC 2.95.3 says: ian@0: // attempt to take address of bit-field structure member `Json::Value::type_' ian@0: // Beats me, but a temp solves the problem. ian@0: int temp = other.type_; ian@0: if ( type_ != temp ) ian@0: return false; ian@0: switch ( type_ ) ian@0: { ian@0: case nullValue: ian@0: return true; ian@0: case intValue: ian@0: return value_.int_ == other.value_.int_; ian@0: case uintValue: ian@0: return value_.uint_ == other.value_.uint_; ian@0: case realValue: ian@0: return value_.real_ == other.value_.real_; ian@0: case booleanValue: ian@0: return value_.bool_ == other.value_.bool_; ian@0: case stringValue: ian@0: return ( value_.string_ == other.value_.string_ ) ian@0: || ( other.value_.string_ ian@0: && value_.string_ ian@0: && strcmp( value_.string_, other.value_.string_ ) == 0 ); ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: case arrayValue: ian@0: case objectValue: ian@0: return value_.map_->size() == other.value_.map_->size() ian@0: && (*value_.map_) == (*other.value_.map_); ian@0: #else ian@0: case arrayValue: ian@0: return value_.array_->compare( *(other.value_.array_) ) == 0; ian@0: case objectValue: ian@0: return value_.map_->compare( *(other.value_.map_) ) == 0; ian@0: #endif ian@0: default: ian@0: JSON_ASSERT_UNREACHABLE; ian@0: } ian@0: return false; // unreachable ian@0: } ian@0: ian@0: bool ian@0: Value::operator !=( const Value &other ) const ian@0: { ian@0: return !( *this == other ); ian@0: } ian@0: ian@0: const char * ian@0: Value::asCString() const ian@0: { ian@0: JSON_ASSERT( type_ == stringValue ); ian@0: return value_.string_; ian@0: } ian@0: ian@0: ian@0: std::string ian@0: Value::asString() const ian@0: { ian@0: switch ( type_ ) ian@0: { ian@0: case nullValue: ian@0: return ""; ian@0: case stringValue: ian@0: return value_.string_ ? value_.string_ : ""; ian@0: case booleanValue: ian@0: return value_.bool_ ? "true" : "false"; ian@0: case intValue: ian@0: return valueToString( value_.int_ ); ian@0: case uintValue: ian@0: return valueToString( value_.uint_ ); ian@0: case realValue: ian@0: return valueToString( value_.real_ ); ian@0: default: ian@0: JSON_FAIL_MESSAGE( "Type is not convertible to string" ); ian@0: } ian@0: } ian@0: ian@0: # ifdef JSON_USE_CPPTL ian@0: CppTL::ConstString ian@0: Value::asConstString() const ian@0: { ian@0: return CppTL::ConstString( asString().c_str() ); ian@0: } ian@0: # endif ian@0: ian@0: ian@0: Value::Int ian@0: Value::asInt() const ian@0: { ian@0: switch ( type_ ) ian@0: { ian@0: case intValue: ian@0: JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); ian@0: return Int(value_.int_); ian@0: case uintValue: ian@0: JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); ian@0: return Int(value_.uint_); ian@0: case realValue: ian@0: JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), "double out of Int range"); ian@0: return Int(value_.real_); ian@0: case nullValue: ian@0: return 0; ian@0: case booleanValue: ian@0: return value_.bool_ ? 1 : 0; ian@0: default: ian@0: break; ian@0: } ian@0: JSON_FAIL_MESSAGE("Value is not convertible to Int."); ian@0: } ian@0: ian@0: ian@0: Value::UInt ian@0: Value::asUInt() const ian@0: { ian@0: switch ( type_ ) ian@0: { ian@0: case intValue: ian@0: JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); ian@0: return UInt(value_.int_); ian@0: case uintValue: ian@0: JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); ian@0: return UInt(value_.uint_); ian@0: case realValue: ian@0: JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), "double out of UInt range"); ian@0: return UInt( value_.real_ ); ian@0: case nullValue: ian@0: return 0; ian@0: case booleanValue: ian@0: return value_.bool_ ? 1 : 0; ian@0: default: ian@0: break; ian@0: } ian@0: JSON_FAIL_MESSAGE("Value is not convertible to UInt."); ian@0: } ian@0: ian@0: ian@0: # if defined(JSON_HAS_INT64) ian@0: ian@0: Value::Int64 ian@0: Value::asInt64() const ian@0: { ian@0: switch ( type_ ) ian@0: { ian@0: case intValue: ian@0: return Int64(value_.int_); ian@0: case uintValue: ian@0: JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); ian@0: return Int64(value_.uint_); ian@0: case realValue: ian@0: JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), "double out of Int64 range"); ian@0: return Int64(value_.real_); ian@0: case nullValue: ian@0: return 0; ian@0: case booleanValue: ian@0: return value_.bool_ ? 1 : 0; ian@0: default: ian@0: break; ian@0: } ian@0: JSON_FAIL_MESSAGE("Value is not convertible to Int64."); ian@0: } ian@0: ian@0: ian@0: Value::UInt64 ian@0: Value::asUInt64() const ian@0: { ian@0: switch ( type_ ) ian@0: { ian@0: case intValue: ian@0: JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); ian@0: return UInt64(value_.int_); ian@0: case uintValue: ian@0: return UInt64(value_.uint_); ian@0: case realValue: ian@0: JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), "double out of UInt64 range"); ian@0: return UInt64( value_.real_ ); ian@0: case nullValue: ian@0: return 0; ian@0: case booleanValue: ian@0: return value_.bool_ ? 1 : 0; ian@0: default: ian@0: break; ian@0: } ian@0: JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); ian@0: } ian@0: # endif // if defined(JSON_HAS_INT64) ian@0: ian@0: ian@0: LargestInt ian@0: Value::asLargestInt() const ian@0: { ian@0: #if defined(JSON_NO_INT64) ian@0: return asInt(); ian@0: #else ian@0: return asInt64(); ian@0: #endif ian@0: } ian@0: ian@0: ian@0: LargestUInt ian@0: Value::asLargestUInt() const ian@0: { ian@0: #if defined(JSON_NO_INT64) ian@0: return asUInt(); ian@0: #else ian@0: return asUInt64(); ian@0: #endif ian@0: } ian@0: ian@0: ian@0: double ian@0: Value::asDouble() const ian@0: { ian@0: switch ( type_ ) ian@0: { ian@0: case intValue: ian@0: return static_cast( value_.int_ ); ian@0: case uintValue: ian@0: #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) ian@0: return static_cast( value_.uint_ ); ian@0: #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) ian@0: return integerToDouble( value_.uint_ ); ian@0: #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) ian@0: case realValue: ian@0: return value_.real_; ian@0: case nullValue: ian@0: return 0.0; ian@0: case booleanValue: ian@0: return value_.bool_ ? 1.0 : 0.0; ian@0: default: ian@0: break; ian@0: } ian@0: JSON_FAIL_MESSAGE("Value is not convertible to double."); ian@0: } ian@0: ian@0: float ian@0: Value::asFloat() const ian@0: { ian@0: switch ( type_ ) ian@0: { ian@0: case intValue: ian@0: return static_cast( value_.int_ ); ian@0: case uintValue: ian@0: #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) ian@0: return static_cast( value_.uint_ ); ian@0: #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) ian@0: return integerToDouble( value_.uint_ ); ian@0: #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) ian@0: case realValue: ian@0: return static_cast( value_.real_ ); ian@0: case nullValue: ian@0: return 0.0; ian@0: case booleanValue: ian@0: return value_.bool_ ? 1.0f : 0.0f; ian@0: default: ian@0: break; ian@0: } ian@0: JSON_FAIL_MESSAGE("Value is not convertible to float."); ian@0: } ian@0: ian@0: bool ian@0: Value::asBool() const ian@0: { ian@0: switch ( type_ ) ian@0: { ian@0: case booleanValue: ian@0: return value_.bool_; ian@0: case nullValue: ian@0: return false; ian@0: case intValue: ian@0: return value_.int_ ? true : false; ian@0: case uintValue: ian@0: return value_.uint_ ? true : false; ian@0: case realValue: ian@0: return value_.real_ ? true : false; ian@0: default: ian@0: break; ian@0: } ian@0: JSON_FAIL_MESSAGE("Value is not convertible to bool."); ian@0: } ian@0: ian@0: ian@0: bool ian@0: Value::isConvertibleTo( ValueType other ) const ian@0: { ian@0: switch ( other ) ian@0: { ian@0: case nullValue: ian@0: return ( isNumeric() && asDouble() == 0.0 ) ian@0: || ( type_ == booleanValue && value_.bool_ == false ) ian@0: || ( type_ == stringValue && asString() == "" ) ian@0: || ( type_ == arrayValue && value_.map_->size() == 0 ) ian@0: || ( type_ == objectValue && value_.map_->size() == 0 ) ian@0: || type_ == nullValue; ian@0: case intValue: ian@0: return isInt() ian@0: || (type_ == realValue && InRange(value_.real_, minInt, maxInt)) ian@0: || type_ == booleanValue ian@0: || type_ == nullValue; ian@0: case uintValue: ian@0: return isUInt() ian@0: || (type_ == realValue && InRange(value_.real_, 0, maxUInt)) ian@0: || type_ == booleanValue ian@0: || type_ == nullValue; ian@0: case realValue: ian@0: return isNumeric() ian@0: || type_ == booleanValue ian@0: || type_ == nullValue; ian@0: case booleanValue: ian@0: return isNumeric() ian@0: || type_ == booleanValue ian@0: || type_ == nullValue; ian@0: case stringValue: ian@0: return isNumeric() ian@0: || type_ == booleanValue ian@0: || type_ == stringValue ian@0: || type_ == nullValue; ian@0: case arrayValue: ian@0: return type_ == arrayValue ian@0: || type_ == nullValue; ian@0: case objectValue: ian@0: return type_ == objectValue ian@0: || type_ == nullValue; ian@0: } ian@0: JSON_ASSERT_UNREACHABLE; ian@0: return false; ian@0: } ian@0: ian@0: ian@0: /// Number of values in array or object ian@0: ArrayIndex ian@0: Value::size() const ian@0: { ian@0: switch ( type_ ) ian@0: { ian@0: case nullValue: ian@0: case intValue: ian@0: case uintValue: ian@0: case realValue: ian@0: case booleanValue: ian@0: case stringValue: ian@0: return 0; ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: case arrayValue: // size of the array is highest index + 1 ian@0: if ( !value_.map_->empty() ) ian@0: { ian@0: ObjectValues::const_iterator itLast = value_.map_->end(); ian@0: --itLast; ian@0: return (*itLast).first.index()+1; ian@0: } ian@0: return 0; ian@0: case objectValue: ian@0: return ArrayIndex( value_.map_->size() ); ian@0: #else ian@0: case arrayValue: ian@0: return Int( value_.array_->size() ); ian@0: case objectValue: ian@0: return Int( value_.map_->size() ); ian@0: #endif ian@0: } ian@0: JSON_ASSERT_UNREACHABLE; ian@0: return 0; // unreachable; ian@0: } ian@0: ian@0: ian@0: bool ian@0: Value::empty() const ian@0: { ian@0: if ( isNull() || isArray() || isObject() ) ian@0: return size() == 0u; ian@0: else ian@0: return false; ian@0: } ian@0: ian@0: ian@0: bool ian@0: Value::operator!() const ian@0: { ian@0: return isNull(); ian@0: } ian@0: ian@0: ian@0: void ian@0: Value::clear() ian@0: { ian@0: JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue ); ian@0: ian@0: switch ( type_ ) ian@0: { ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: case arrayValue: ian@0: case objectValue: ian@0: value_.map_->clear(); ian@0: break; ian@0: #else ian@0: case arrayValue: ian@0: value_.array_->clear(); ian@0: break; ian@0: case objectValue: ian@0: value_.map_->clear(); ian@0: break; ian@0: #endif ian@0: default: ian@0: break; ian@0: } ian@0: } ian@0: ian@0: void ian@0: Value::resize( ArrayIndex newSize ) ian@0: { ian@0: JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); ian@0: if ( type_ == nullValue ) ian@0: *this = Value( arrayValue ); ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: ArrayIndex oldSize = size(); ian@0: if ( newSize == 0 ) ian@0: clear(); ian@0: else if ( newSize > oldSize ) ian@0: (*this)[ newSize - 1 ]; ian@0: else ian@0: { ian@0: for ( ArrayIndex index = newSize; index < oldSize; ++index ) ian@0: { ian@0: value_.map_->erase( index ); ian@0: } ian@0: assert( size() == newSize ); ian@0: } ian@0: #else ian@0: value_.array_->resize( newSize ); ian@0: #endif ian@0: } ian@0: ian@0: ian@0: Value & ian@0: Value::operator[]( ArrayIndex index ) ian@0: { ian@0: JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); ian@0: if ( type_ == nullValue ) ian@0: *this = Value( arrayValue ); ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: CZString key( index ); ian@0: ObjectValues::iterator it = value_.map_->lower_bound( key ); ian@0: if ( it != value_.map_->end() && (*it).first == key ) ian@0: return (*it).second; ian@0: ian@0: ObjectValues::value_type defaultValue( key, null ); ian@0: it = value_.map_->insert( it, defaultValue ); ian@0: return (*it).second; ian@0: #else ian@0: return value_.array_->resolveReference( index ); ian@0: #endif ian@0: } ian@0: ian@0: ian@0: Value & ian@0: Value::operator[]( int index ) ian@0: { ian@0: JSON_ASSERT( index >= 0 ); ian@0: return (*this)[ ArrayIndex(index) ]; ian@0: } ian@0: ian@0: ian@0: const Value & ian@0: Value::operator[]( ArrayIndex index ) const ian@0: { ian@0: JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); ian@0: if ( type_ == nullValue ) ian@0: return null; ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: CZString key( index ); ian@0: ObjectValues::const_iterator it = value_.map_->find( key ); ian@0: if ( it == value_.map_->end() ) ian@0: return null; ian@0: return (*it).second; ian@0: #else ian@0: Value *value = value_.array_->find( index ); ian@0: return value ? *value : null; ian@0: #endif ian@0: } ian@0: ian@0: ian@0: const Value & ian@0: Value::operator[]( int index ) const ian@0: { ian@0: JSON_ASSERT( index >= 0 ); ian@0: return (*this)[ ArrayIndex(index) ]; ian@0: } ian@0: ian@0: ian@0: Value & ian@0: Value::operator[]( const char *key ) ian@0: { ian@0: return resolveReference( key, false ); ian@0: } ian@0: ian@0: ian@0: Value & ian@0: Value::resolveReference( const char *key, ian@0: bool isStatic ) ian@0: { ian@0: JSON_ASSERT( type_ == nullValue || type_ == objectValue ); ian@0: if ( type_ == nullValue ) ian@0: *this = Value( objectValue ); ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: CZString actualKey( key, isStatic ? CZString::noDuplication ian@0: : CZString::duplicateOnCopy ); ian@0: ObjectValues::iterator it = value_.map_->lower_bound( actualKey ); ian@0: if ( it != value_.map_->end() && (*it).first == actualKey ) ian@0: return (*it).second; ian@0: ian@0: ObjectValues::value_type defaultValue( actualKey, null ); ian@0: it = value_.map_->insert( it, defaultValue ); ian@0: Value &value = (*it).second; ian@0: return value; ian@0: #else ian@0: return value_.map_->resolveReference( key, isStatic ); ian@0: #endif ian@0: } ian@0: ian@0: ian@0: Value ian@0: Value::get( ArrayIndex index, ian@0: const Value &defaultValue ) const ian@0: { ian@0: const Value *value = &((*this)[index]); ian@0: return value == &null ? defaultValue : *value; ian@0: } ian@0: ian@0: ian@0: bool ian@0: Value::isValidIndex( ArrayIndex index ) const ian@0: { ian@0: return index < size(); ian@0: } ian@0: ian@0: ian@0: ian@0: const Value & ian@0: Value::operator[]( const char *key ) const ian@0: { ian@0: JSON_ASSERT( type_ == nullValue || type_ == objectValue ); ian@0: if ( type_ == nullValue ) ian@0: return null; ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: CZString actualKey( key, CZString::noDuplication ); ian@0: ObjectValues::const_iterator it = value_.map_->find( actualKey ); ian@0: if ( it == value_.map_->end() ) ian@0: return null; ian@0: return (*it).second; ian@0: #else ian@0: const Value *value = value_.map_->find( key ); ian@0: return value ? *value : null; ian@0: #endif ian@0: } ian@0: ian@0: ian@0: Value & ian@0: Value::operator[]( const std::string &key ) ian@0: { ian@0: return (*this)[ key.c_str() ]; ian@0: } ian@0: ian@0: ian@0: const Value & ian@0: Value::operator[]( const std::string &key ) const ian@0: { ian@0: return (*this)[ key.c_str() ]; ian@0: } ian@0: ian@0: Value & ian@0: Value::operator[]( const StaticString &key ) ian@0: { ian@0: return resolveReference( key, true ); ian@0: } ian@0: ian@0: ian@0: # ifdef JSON_USE_CPPTL ian@0: Value & ian@0: Value::operator[]( const CppTL::ConstString &key ) ian@0: { ian@0: return (*this)[ key.c_str() ]; ian@0: } ian@0: ian@0: ian@0: const Value & ian@0: Value::operator[]( const CppTL::ConstString &key ) const ian@0: { ian@0: return (*this)[ key.c_str() ]; ian@0: } ian@0: # endif ian@0: ian@0: ian@0: Value & ian@0: Value::append( const Value &value ) ian@0: { ian@0: return (*this)[size()] = value; ian@0: } ian@0: ian@0: ian@0: Value ian@0: Value::get( const char *key, ian@0: const Value &defaultValue ) const ian@0: { ian@0: const Value *value = &((*this)[key]); ian@0: return value == &null ? defaultValue : *value; ian@0: } ian@0: ian@0: ian@0: Value ian@0: Value::get( const std::string &key, ian@0: const Value &defaultValue ) const ian@0: { ian@0: return get( key.c_str(), defaultValue ); ian@0: } ian@0: ian@0: Value ian@0: Value::removeMember( const char* key ) ian@0: { ian@0: JSON_ASSERT( type_ == nullValue || type_ == objectValue ); ian@0: if ( type_ == nullValue ) ian@0: return null; ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: CZString actualKey( key, CZString::noDuplication ); ian@0: ObjectValues::iterator it = value_.map_->find( actualKey ); ian@0: if ( it == value_.map_->end() ) ian@0: return null; ian@0: Value old(it->second); ian@0: value_.map_->erase(it); ian@0: return old; ian@0: #else ian@0: Value *value = value_.map_->find( key ); ian@0: if (value){ ian@0: Value old(*value); ian@0: value_.map_.remove( key ); ian@0: return old; ian@0: } else { ian@0: return null; ian@0: } ian@0: #endif ian@0: } ian@0: ian@0: Value ian@0: Value::removeMember( const std::string &key ) ian@0: { ian@0: return removeMember( key.c_str() ); ian@0: } ian@0: ian@0: # ifdef JSON_USE_CPPTL ian@0: Value ian@0: Value::get( const CppTL::ConstString &key, ian@0: const Value &defaultValue ) const ian@0: { ian@0: return get( key.c_str(), defaultValue ); ian@0: } ian@0: # endif ian@0: ian@0: bool ian@0: Value::isMember( const char *key ) const ian@0: { ian@0: const Value *value = &((*this)[key]); ian@0: return value != &null; ian@0: } ian@0: ian@0: ian@0: bool ian@0: Value::isMember( const std::string &key ) const ian@0: { ian@0: return isMember( key.c_str() ); ian@0: } ian@0: ian@0: ian@0: # ifdef JSON_USE_CPPTL ian@0: bool ian@0: Value::isMember( const CppTL::ConstString &key ) const ian@0: { ian@0: return isMember( key.c_str() ); ian@0: } ian@0: #endif ian@0: ian@0: Value::Members ian@0: Value::getMemberNames() const ian@0: { ian@0: JSON_ASSERT( type_ == nullValue || type_ == objectValue ); ian@0: if ( type_ == nullValue ) ian@0: return Value::Members(); ian@0: Members members; ian@0: members.reserve( value_.map_->size() ); ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: ObjectValues::const_iterator it = value_.map_->begin(); ian@0: ObjectValues::const_iterator itEnd = value_.map_->end(); ian@0: for ( ; it != itEnd; ++it ) ian@0: members.push_back( std::string( (*it).first.c_str() ) ); ian@0: #else ian@0: ValueInternalMap::IteratorState it; ian@0: ValueInternalMap::IteratorState itEnd; ian@0: value_.map_->makeBeginIterator( it ); ian@0: value_.map_->makeEndIterator( itEnd ); ian@0: for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) ) ian@0: members.push_back( std::string( ValueInternalMap::key( it ) ) ); ian@0: #endif ian@0: return members; ian@0: } ian@0: // ian@0: //# ifdef JSON_USE_CPPTL ian@0: //EnumMemberNames ian@0: //Value::enumMemberNames() const ian@0: //{ ian@0: // if ( type_ == objectValue ) ian@0: // { ian@0: // return CppTL::Enum::any( CppTL::Enum::transform( ian@0: // CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), ian@0: // MemberNamesTransform() ) ); ian@0: // } ian@0: // return EnumMemberNames(); ian@0: //} ian@0: // ian@0: // ian@0: //EnumValues ian@0: //Value::enumValues() const ian@0: //{ ian@0: // if ( type_ == objectValue || type_ == arrayValue ) ian@0: // return CppTL::Enum::anyValues( *(value_.map_), ian@0: // CppTL::Type() ); ian@0: // return EnumValues(); ian@0: //} ian@0: // ian@0: //# endif ian@0: ian@0: static bool IsIntegral(double d) { ian@0: double integral_part; ian@0: return modf(d, &integral_part) == 0.0; ian@0: } ian@0: ian@0: ian@0: bool ian@0: Value::isNull() const ian@0: { ian@0: return type_ == nullValue; ian@0: } ian@0: ian@0: ian@0: bool ian@0: Value::isBool() const ian@0: { ian@0: return type_ == booleanValue; ian@0: } ian@0: ian@0: ian@0: bool ian@0: Value::isInt() const ian@0: { ian@0: switch ( type_ ) ian@0: { ian@0: case intValue: ian@0: return value_.int_ >= minInt && value_.int_ <= maxInt; ian@0: case uintValue: ian@0: return value_.uint_ <= UInt(maxInt); ian@0: case realValue: ian@0: return value_.real_ >= minInt && ian@0: value_.real_ <= maxInt && ian@0: IsIntegral(value_.real_); ian@0: default: ian@0: break; ian@0: } ian@0: return false; ian@0: } ian@0: ian@0: ian@0: bool ian@0: Value::isUInt() const ian@0: { ian@0: switch ( type_ ) ian@0: { ian@0: case intValue: ian@0: return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); ian@0: case uintValue: ian@0: return value_.uint_ <= maxUInt; ian@0: case realValue: ian@0: return value_.real_ >= 0 && ian@0: value_.real_ <= maxUInt && ian@0: IsIntegral(value_.real_); ian@0: default: ian@0: break; ian@0: } ian@0: return false; ian@0: } ian@0: ian@0: bool ian@0: Value::isInt64() const ian@0: { ian@0: # if defined(JSON_HAS_INT64) ian@0: switch ( type_ ) ian@0: { ian@0: case intValue: ian@0: return true; ian@0: case uintValue: ian@0: return value_.uint_ <= UInt64(maxInt64); ian@0: case realValue: ian@0: // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a ian@0: // double, so double(maxInt64) will be rounded up to 2^63. Therefore we ian@0: // require the value to be strictly less than the limit. ian@0: return value_.real_ >= double(minInt64) && ian@0: value_.real_ < double(maxInt64) && ian@0: IsIntegral(value_.real_); ian@0: default: ian@0: break; ian@0: } ian@0: # endif // JSON_HAS_INT64 ian@0: return false; ian@0: } ian@0: ian@0: bool ian@0: Value::isUInt64() const ian@0: { ian@0: # if defined(JSON_HAS_INT64) ian@0: switch ( type_ ) ian@0: { ian@0: case intValue: ian@0: return value_.int_ >= 0; ian@0: case uintValue: ian@0: return true; ian@0: case realValue: ian@0: // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a ian@0: // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we ian@0: // require the value to be strictly less than the limit. ian@0: return value_.real_ >= 0 && ian@0: value_.real_ < maxUInt64AsDouble && ian@0: IsIntegral(value_.real_); ian@0: default: ian@0: break; ian@0: } ian@0: # endif // JSON_HAS_INT64 ian@0: return false; ian@0: } ian@0: ian@0: ian@0: bool ian@0: Value::isIntegral() const ian@0: { ian@0: #if defined(JSON_HAS_INT64) ian@0: return isInt64() || isUInt64(); ian@0: #else ian@0: return isInt() || isUInt(); ian@0: #endif ian@0: } ian@0: ian@0: ian@0: bool ian@0: Value::isDouble() const ian@0: { ian@0: return type_ == realValue || isIntegral(); ian@0: } ian@0: ian@0: ian@0: bool ian@0: Value::isNumeric() const ian@0: { ian@0: return isIntegral() || isDouble(); ian@0: } ian@0: ian@0: ian@0: bool ian@0: Value::isString() const ian@0: { ian@0: return type_ == stringValue; ian@0: } ian@0: ian@0: ian@0: bool ian@0: Value::isArray() const ian@0: { ian@0: return type_ == arrayValue; ian@0: } ian@0: ian@0: ian@0: bool ian@0: Value::isObject() const ian@0: { ian@0: return type_ == objectValue; ian@0: } ian@0: ian@0: ian@0: void ian@0: Value::setComment( const char *comment, ian@0: CommentPlacement placement ) ian@0: { ian@0: if ( !comments_ ) ian@0: comments_ = new CommentInfo[numberOfCommentPlacement]; ian@0: comments_[placement].setComment( comment ); ian@0: } ian@0: ian@0: ian@0: void ian@0: Value::setComment( const std::string &comment, ian@0: CommentPlacement placement ) ian@0: { ian@0: setComment( comment.c_str(), placement ); ian@0: } ian@0: ian@0: ian@0: bool ian@0: Value::hasComment( CommentPlacement placement ) const ian@0: { ian@0: return comments_ != 0 && comments_[placement].comment_ != 0; ian@0: } ian@0: ian@0: std::string ian@0: Value::getComment( CommentPlacement placement ) const ian@0: { ian@0: if ( hasComment(placement) ) ian@0: return comments_[placement].comment_; ian@0: return ""; ian@0: } ian@0: ian@0: ian@0: std::string ian@0: Value::toStyledString() const ian@0: { ian@0: StyledWriter writer; ian@0: return writer.write( *this ); ian@0: } ian@0: ian@0: ian@0: Value::const_iterator ian@0: Value::begin() const ian@0: { ian@0: switch ( type_ ) ian@0: { ian@0: #ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: case arrayValue: ian@0: if ( value_.array_ ) ian@0: { ian@0: ValueInternalArray::IteratorState it; ian@0: value_.array_->makeBeginIterator( it ); ian@0: return const_iterator( it ); ian@0: } ian@0: break; ian@0: case objectValue: ian@0: if ( value_.map_ ) ian@0: { ian@0: ValueInternalMap::IteratorState it; ian@0: value_.map_->makeBeginIterator( it ); ian@0: return const_iterator( it ); ian@0: } ian@0: break; ian@0: #else ian@0: case arrayValue: ian@0: case objectValue: ian@0: if ( value_.map_ ) ian@0: return const_iterator( value_.map_->begin() ); ian@0: break; ian@0: #endif ian@0: default: ian@0: break; ian@0: } ian@0: return const_iterator(); ian@0: } ian@0: ian@0: Value::const_iterator ian@0: Value::end() const ian@0: { ian@0: switch ( type_ ) ian@0: { ian@0: #ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: case arrayValue: ian@0: if ( value_.array_ ) ian@0: { ian@0: ValueInternalArray::IteratorState it; ian@0: value_.array_->makeEndIterator( it ); ian@0: return const_iterator( it ); ian@0: } ian@0: break; ian@0: case objectValue: ian@0: if ( value_.map_ ) ian@0: { ian@0: ValueInternalMap::IteratorState it; ian@0: value_.map_->makeEndIterator( it ); ian@0: return const_iterator( it ); ian@0: } ian@0: break; ian@0: #else ian@0: case arrayValue: ian@0: case objectValue: ian@0: if ( value_.map_ ) ian@0: return const_iterator( value_.map_->end() ); ian@0: break; ian@0: #endif ian@0: default: ian@0: break; ian@0: } ian@0: return const_iterator(); ian@0: } ian@0: ian@0: ian@0: Value::iterator ian@0: Value::begin() ian@0: { ian@0: switch ( type_ ) ian@0: { ian@0: #ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: case arrayValue: ian@0: if ( value_.array_ ) ian@0: { ian@0: ValueInternalArray::IteratorState it; ian@0: value_.array_->makeBeginIterator( it ); ian@0: return iterator( it ); ian@0: } ian@0: break; ian@0: case objectValue: ian@0: if ( value_.map_ ) ian@0: { ian@0: ValueInternalMap::IteratorState it; ian@0: value_.map_->makeBeginIterator( it ); ian@0: return iterator( it ); ian@0: } ian@0: break; ian@0: #else ian@0: case arrayValue: ian@0: case objectValue: ian@0: if ( value_.map_ ) ian@0: return iterator( value_.map_->begin() ); ian@0: break; ian@0: #endif ian@0: default: ian@0: break; ian@0: } ian@0: return iterator(); ian@0: } ian@0: ian@0: Value::iterator ian@0: Value::end() ian@0: { ian@0: switch ( type_ ) ian@0: { ian@0: #ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: case arrayValue: ian@0: if ( value_.array_ ) ian@0: { ian@0: ValueInternalArray::IteratorState it; ian@0: value_.array_->makeEndIterator( it ); ian@0: return iterator( it ); ian@0: } ian@0: break; ian@0: case objectValue: ian@0: if ( value_.map_ ) ian@0: { ian@0: ValueInternalMap::IteratorState it; ian@0: value_.map_->makeEndIterator( it ); ian@0: return iterator( it ); ian@0: } ian@0: break; ian@0: #else ian@0: case arrayValue: ian@0: case objectValue: ian@0: if ( value_.map_ ) ian@0: return iterator( value_.map_->end() ); ian@0: break; ian@0: #endif ian@0: default: ian@0: break; ian@0: } ian@0: return iterator(); ian@0: } ian@0: ian@0: ian@0: // class PathArgument ian@0: // ////////////////////////////////////////////////////////////////// ian@0: ian@0: PathArgument::PathArgument() ian@0: : key_() ian@0: , index_() ian@0: , kind_( kindNone ) ian@0: { ian@0: } ian@0: ian@0: ian@0: PathArgument::PathArgument( ArrayIndex index ) ian@0: : key_() ian@0: , index_( index ) ian@0: , kind_( kindIndex ) ian@0: { ian@0: } ian@0: ian@0: ian@0: PathArgument::PathArgument( const char *key ) ian@0: : key_( key ) ian@0: , index_() ian@0: , kind_( kindKey ) ian@0: { ian@0: } ian@0: ian@0: ian@0: PathArgument::PathArgument( const std::string &key ) ian@0: : key_( key.c_str() ) ian@0: , index_() ian@0: , kind_( kindKey ) ian@0: { ian@0: } ian@0: ian@0: // class Path ian@0: // ////////////////////////////////////////////////////////////////// ian@0: ian@0: Path::Path( const std::string &path, ian@0: const PathArgument &a1, ian@0: const PathArgument &a2, ian@0: const PathArgument &a3, ian@0: const PathArgument &a4, ian@0: const PathArgument &a5 ) ian@0: { ian@0: InArgs in; ian@0: in.push_back( &a1 ); ian@0: in.push_back( &a2 ); ian@0: in.push_back( &a3 ); ian@0: in.push_back( &a4 ); ian@0: in.push_back( &a5 ); ian@0: makePath( path, in ); ian@0: } ian@0: ian@0: ian@0: void ian@0: Path::makePath( const std::string &path, ian@0: const InArgs &in ) ian@0: { ian@0: const char *current = path.c_str(); ian@0: const char *end = current + path.length(); ian@0: InArgs::const_iterator itInArg = in.begin(); ian@0: while ( current != end ) ian@0: { ian@0: if ( *current == '[' ) ian@0: { ian@0: ++current; ian@0: if ( *current == '%' ) ian@0: addPathInArg( path, in, itInArg, PathArgument::kindIndex ); ian@0: else ian@0: { ian@0: ArrayIndex index = 0; ian@0: for ( ; current != end && *current >= '0' && *current <= '9'; ++current ) ian@0: index = index * 10 + ArrayIndex(*current - '0'); ian@0: args_.push_back( index ); ian@0: } ian@0: if ( current == end || *current++ != ']' ) ian@0: invalidPath( path, int(current - path.c_str()) ); ian@0: } ian@0: else if ( *current == '%' ) ian@0: { ian@0: addPathInArg( path, in, itInArg, PathArgument::kindKey ); ian@0: ++current; ian@0: } ian@0: else if ( *current == '.' ) ian@0: { ian@0: ++current; ian@0: } ian@0: else ian@0: { ian@0: const char *beginName = current; ian@0: while ( current != end && !strchr( "[.", *current ) ) ian@0: ++current; ian@0: args_.push_back( std::string( beginName, current ) ); ian@0: } ian@0: } ian@0: } ian@0: ian@0: ian@0: void ian@0: Path::addPathInArg( const std::string &path, ian@0: const InArgs &in, ian@0: InArgs::const_iterator &itInArg, ian@0: PathArgument::Kind kind ) ian@0: { ian@0: if ( itInArg == in.end() ) ian@0: { ian@0: // Error: missing argument %d ian@0: } ian@0: else if ( (*itInArg)->kind_ != kind ) ian@0: { ian@0: // Error: bad argument type ian@0: } ian@0: else ian@0: { ian@0: args_.push_back( **itInArg ); ian@0: } ian@0: } ian@0: ian@0: ian@0: void ian@0: Path::invalidPath( const std::string &path, ian@0: int location ) ian@0: { ian@0: // Error: invalid path. ian@0: } ian@0: ian@0: ian@0: const Value & ian@0: Path::resolve( const Value &root ) const ian@0: { ian@0: const Value *node = &root; ian@0: for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) ian@0: { ian@0: const PathArgument &arg = *it; ian@0: if ( arg.kind_ == PathArgument::kindIndex ) ian@0: { ian@0: if ( !node->isArray() || !node->isValidIndex( arg.index_ ) ) ian@0: { ian@0: // Error: unable to resolve path (array value expected at position... ian@0: } ian@0: node = &((*node)[arg.index_]); ian@0: } ian@0: else if ( arg.kind_ == PathArgument::kindKey ) ian@0: { ian@0: if ( !node->isObject() ) ian@0: { ian@0: // Error: unable to resolve path (object value expected at position...) ian@0: } ian@0: node = &((*node)[arg.key_]); ian@0: if ( node == &Value::null ) ian@0: { ian@0: // Error: unable to resolve path (object has no member named '' at position...) ian@0: } ian@0: } ian@0: } ian@0: return *node; ian@0: } ian@0: ian@0: ian@0: Value ian@0: Path::resolve( const Value &root, ian@0: const Value &defaultValue ) const ian@0: { ian@0: const Value *node = &root; ian@0: for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) ian@0: { ian@0: const PathArgument &arg = *it; ian@0: if ( arg.kind_ == PathArgument::kindIndex ) ian@0: { ian@0: if ( !node->isArray() || !node->isValidIndex( arg.index_ ) ) ian@0: return defaultValue; ian@0: node = &((*node)[arg.index_]); ian@0: } ian@0: else if ( arg.kind_ == PathArgument::kindKey ) ian@0: { ian@0: if ( !node->isObject() ) ian@0: return defaultValue; ian@0: node = &((*node)[arg.key_]); ian@0: if ( node == &Value::null ) ian@0: return defaultValue; ian@0: } ian@0: } ian@0: return *node; ian@0: } ian@0: ian@0: ian@0: Value & ian@0: Path::make( Value &root ) const ian@0: { ian@0: Value *node = &root; ian@0: for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) ian@0: { ian@0: const PathArgument &arg = *it; ian@0: if ( arg.kind_ == PathArgument::kindIndex ) ian@0: { ian@0: if ( !node->isArray() ) ian@0: { ian@0: // Error: node is not an array at position ... ian@0: } ian@0: node = &((*node)[arg.index_]); ian@0: } ian@0: else if ( arg.kind_ == PathArgument::kindKey ) ian@0: { ian@0: if ( !node->isObject() ) ian@0: { ian@0: // Error: node is not an object at position... ian@0: } ian@0: node = &((*node)[arg.key_]); ian@0: } ian@0: } ian@0: return *node; ian@0: } ian@0: ian@0: ian@0: } // namespace Json