#include "pch.h"
#include <iostream>
#include <utility>
#include <stdexcept>
#include <cstring>
#include <cassert>
#include "value.h"
#include "writer.h"
#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 {
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_.arra