//
//	Copyright © 2005 Nemetschek North America 
//	All Rights Reserved.
//
// Created by Vladislav Stanev

#include "StdAfx.h"
//#include "DataSerializer.h"

using namespace VWFC::Tools;

static int		g_bByteSwapEnsure		= -1;
template<class T> T EnsureSwappedBytes(const T& value)
{
	// this is kind of stupid, but it's the only way
	// to be able to work with broken not equal byte order of existing documents
	// This should not be problem for current use of the DataSerializer
	// since nobody currenly stores monster data
	T	swappedValue	= VWFC::Tools::SwapBytes( value );
	if ( swappedValue == value )
		return value;
	if ( g_bByteSwapEnsure == -1 ) {
		g_bByteSwapEnsure	= swappedValue < value ? 0 : 1;
	}

	return g_bByteSwapEnsure == 0 ?swappedValue : value;
}


// ----------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------
VWDataSerializerValue::VWDataSerializerValue(void* pData, size_t size)
{
	this->SetValue( pData, size );
}

VWDataSerializerValue::VWDataSerializerValue(SInt8 data)
{
	this->SetValue( data );
}

VWDataSerializerValue::VWDataSerializerValue(UInt8 data)
{
	this->SetValue( data );
}

VWDataSerializerValue::VWDataSerializerValue(SInt16 data)
{
	this->SetValue( data );
}

VWDataSerializerValue::VWDataSerializerValue(UInt16 data)
{
	this->SetValue( data );
}

VWDataSerializerValue::VWDataSerializerValue(SInt32 data)
{
	this->SetValue( data );
}

VWDataSerializerValue::VWDataSerializerValue(UInt32 data)
{
	this->SetValue( data );
}

VWDataSerializerValue::VWDataSerializerValue(double data)
{
	this->SetValue( data );
}

VWDataSerializerValue::VWDataSerializerValue(const TXString& str)
{
	this->SetValue( str );
}

VWDataSerializerValue::VWDataSerializerValue(UInt32 data, const char* szEnum1, ...)
{
	va_list marker;
	va_start( marker, szEnum1 );
	const char*		szThisEnum		= szEnum1;
	while( szThisEnum ) {
		TXString	enumValue	= szThisEnum;
		m_arrEnumValues.push_back( enumValue );
		
		szThisEnum = va_arg( marker, const char* );
	}
	va_end( marker );

	size_t		len		= m_arrEnumValues.size();
	VWFC_ASSERT( data < len );
	if ( data < len )
		this->SetValue( m_arrEnumValues[ data ] );
	else
		this->SetValue( data );
}

VWDataSerializerValue::VWDataSerializerValue(const VWDataSerializerValue& src)
{
	m_nBytesCnt		= src.m_nBytesCnt;
	m_pBytes		= (UInt8*) NEW_DATA( m_nBytesCnt );
	for(size_t i=0; i<m_nBytesCnt; i++) {
		m_pBytes[i]	= src.m_pBytes[i];
	}
	m_valueAsString	= src.m_valueAsString;
}

VWDataSerializerValue::~VWDataSerializerValue()
{
	DELETE_DATA( m_pBytes );
	m_nBytesCnt			= 0;
}

VWDataSerializerValue& VWDataSerializerValue::SetEnumValues(const char* szEnum1, ...)
{
	va_list marker;
	va_start( marker, szEnum1 );
	const char*		szThisEnum		= szEnum1;
	while( szThisEnum ) {
		TXString	enumValue	= szThisEnum;
		m_arrEnumValues.push_back( enumValue );
		
		szThisEnum = va_arg( marker, const char* );
	}
	va_end( marker );

	return *this;
}

VWDataSerializerValue& VWDataSerializerValue::operator=(const VWDataSerializerValue& src)
{
	DELETE_DATA( m_pBytes );

	m_nBytesCnt		= src.m_nBytesCnt;
	m_pBytes		= (UInt8*) NEW_DATA( m_nBytesCnt );
	for(size_t i=0; i<m_nBytesCnt; i++) {
		m_pBytes[i]	= src.m_pBytes[i];
	}
	m_valueAsString	= src.m_valueAsString;

	return *this;
}

void VWDataSerializerValue::SetValue(SInt8 data)
{
	// make the string before altering the byte order
	m_valueAsString.Format( "%d", data );

	data	= /*static*/ ::EnsureSwappedBytes( data );
	this->SetData( & data, sizeof(SInt8) );
}

void VWDataSerializerValue::SetValue(UInt8 data)
{
	// make the string before altering the byte order
	m_valueAsString.Format( "%d", data );

	data	= /*static*/ ::EnsureSwappedBytes( data );
	this->SetData( & data, sizeof(UInt8) );
}

void VWDataSerializerValue::SetValue(SInt16 data)
{
	// make the string before altering the byte order
	m_valueAsString.Format( "%d", data );

	data	= /*static*/ ::EnsureSwappedBytes( data );
	this->SetData( & data, sizeof(SInt16) );
}

void VWDataSerializerValue::SetValue(UInt16 data)
{
	// make the string before altering the byte order
	m_valueAsString.Format( "%d", data );

	data	= /*static*/ ::EnsureSwappedBytes( data );
	this->SetData( & data, sizeof(UInt16) );
}

void VWDataSerializerValue::SetValue(SInt32 data)
{
	// make the string before altering the byte order
	m_valueAsString.Format( "%d", data );

	data	= /*static*/ ::EnsureSwappedBytes( data );
	this->SetData( & data, sizeof(SInt32) );
}

void VWDataSerializerValue::SetValue(UInt32 data)
{
	// make the string before altering the byte order
	m_valueAsString.Format( "%d", data );

	data	= /*static*/ ::EnsureSwappedBytes( data );
	this->SetData( & data, sizeof(UInt32) );
}

void VWDataSerializerValue::SetValue(double data)
{
	// make the string before altering the byte order
	m_valueAsString.Format( "%f", data );

	VWFC_ASSERT( sizeof(double) == sizeof(Uint64) );
	Uint64	bitValue;
	memcpy( & bitValue, & data, sizeof(double) );

	bitValue	= /*static*/ ::EnsureSwappedBytes( bitValue );
	this->SetData( & bitValue, sizeof(Uint64) );
}

void VWDataSerializerValue::SetValue(void* pData, size_t size)
{
	this->SetData( pData, size );

	m_valueAsString		= "0x";
	UInt8*	pBuffer		= (UInt8*) pData;
	for(size_t i=0; i<size; i++) {
		TXString	thisValue;
		thisValue.Format( "%X", pBuffer[i] );
		m_valueAsString	+= thisValue;
	}
}

void VWDataSerializerValue::SetValue(const TXString& str)
{
	size_t	len		= str.GetLength();
	m_nBytesCnt		= len + 1;
	m_pBytes		= (UInt8*) NEW_DATA( m_nBytesCnt );
	for(size_t i=0; i<len; i++) {
		m_pBytes[i]	= (UInt8) str.GetAt( i );
	}
	m_pBytes[len]	= 0x00;

	m_valueAsString	= str;
}

VWDataSerializerValue::operator SInt8() const
{
	SInt32	commonValue	= this->GetSIntValue();
	SInt8	value		= ::DemoteTo<SInt8>( kVStanev, commonValue );
	return value;
}

VWDataSerializerValue::operator UInt8() const
{
	UInt32	commonValue	= this->GetUIntValue();
	UInt8	value		= ::DemoteTo<UInt8>( kVStanev, commonValue );
	return value;
}

VWDataSerializerValue::operator SInt16() const
{
	SInt32	commonValue	= this->GetSIntValue();
	SInt16	value		= ::DemoteTo<SInt16>( kVStanev, commonValue );
	return value;
}

VWDataSerializerValue::operator UInt16() const
{
	UInt32	commonValue	= this->GetUIntValue();
	UInt16	value		= ::DemoteTo<UInt16>( kVStanev, commonValue );
	return value;
}

VWDataSerializerValue::operator SInt32() const
{
	SInt32	commonValue	= this->GetSIntValue();
	return commonValue;
}

VWDataSerializerValue::operator UInt32() const
{
	UInt32	commonValue	= this->GetUIntValue();
	return commonValue;
}

VWDataSerializerValue::operator double() const
{
	VWFC_ASSERT( sizeof(double) == m_nBytesCnt );
	if ( sizeof(double) != m_nBytesCnt )
		return 0;

	VWFC_ASSERT( sizeof(double) == sizeof(Uint64) );
	Uint64	bitValue;
	memcpy( & bitValue, m_pBytes, sizeof(double) );
	bitValue		= /*static*/ ::EnsureSwappedBytes( bitValue );

	double	value;
	memcpy( & value, & bitValue, sizeof(double) );
	return value;
}

VWDataSerializerValue::operator TXString() const
{
	return TXString( (char*) m_pBytes, m_nBytesCnt-1 );
}

size_t VWDataSerializerValue::GetBytesCount() const
{
	return m_nBytesCnt;
}

SInt32 VWDataSerializerValue::GetSIntValue() const
{
	SInt32	value	= 0;
	if ( sizeof(SInt8) == m_nBytesCnt ) {
		SInt8*	pValue	= (SInt8*) m_pBytes;
		value			= (SInt32) /*static*/ ::EnsureSwappedBytes( *pValue );
	}
	else if ( sizeof(SInt16) == m_nBytesCnt ) {
		SInt16*	pValue	= (SInt16*) m_pBytes;
		value			= (SInt32) /*static*/ ::EnsureSwappedBytes( *pValue );
	}
	else if ( sizeof(SInt32) == m_nBytesCnt ) {
		SInt32*	pValue	= (SInt32*) m_pBytes;
		value			= (SInt32) /*static*/ ::EnsureSwappedBytes( *pValue );
	}
	else if ( m_arrEnumValues.size() > 0 ) {
		// check for enum
		const char*	szValue	= (const char*) m_pBytes;
		size_t		len		= m_arrEnumValues.size();
		bool		bFound	= false;
		for(size_t i=0; i<len; i++) {
			const TXString&		enumValue	= m_arrEnumValues[ i ];
			if ( enumValue == szValue ) {
				bFound		= true;
				value		= i;
				break;
			}
		}
		// we have to find enum -- otherwise it's bad data
		VWFC_ASSERT( bFound );
	}
	else {
		// not an integer type
		VWFC_ASSERT( false );
	}

	return value;
}

UInt32 VWDataSerializerValue::GetUIntValue() const
{
	UInt32	value	= 0;
	if ( sizeof(UInt8) == m_nBytesCnt ) {
		UInt8*	pValue	= (UInt8*) m_pBytes;
		value			= (UInt32) /*static*/ ::EnsureSwappedBytes( *pValue );
	}
	else if ( sizeof(UInt16) == m_nBytesCnt ) {
		UInt16*	pValue	= (UInt16*) m_pBytes;
		value			= (UInt32) /*static*/ ::EnsureSwappedBytes( *pValue );
	}
	else if ( sizeof(UInt32) == m_nBytesCnt ) {
		UInt32*	pValue	= (UInt32*) m_pBytes;
		value			= (UInt32) /*static*/ ::EnsureSwappedBytes( *pValue );
	}
	else if ( m_arrEnumValues.size() > 0 ) {
		// check for enum
		const char*	szValue	= (const char*) m_pBytes;
		size_t		len		= m_arrEnumValues.size();
		bool		bFound	= false;
		for(size_t i=0; i<len; i++) {
			const TXString&		enumValue	= m_arrEnumValues[ i ];
			if ( enumValue == szValue ) {
				bFound		= true;
				value		= i;
				break;
			}
		}
		// we have to find enum -- otherwise it's bad data
		VWFC_ASSERT( bFound );
	}
	else {
		// not an integer type
		VWFC_ASSERT( false );
	}

	return value;
}

void VWDataSerializerValue::CopyInto(void* pData, size_t size) const
{
	VWFC_ASSERT( m_nBytesCnt <= size );
	if ( m_nBytesCnt > size )
		return;

	memcpy( pData, m_pBytes, size );
}

TXString VWDataSerializerValue::GetValueAsString()
{
	return m_valueAsString;
}

void VWDataSerializerValue::SetValueAsString(const TXString& str)
{
	DELETE_DATA( m_pBytes );
	m_nBytesCnt				= 0;

	const char*	szString	= str;
	size_t		len			= str.GetLength();

	bool		bDigits		= false;
	bool		bHasDot		= false;
	for(size_t i=0; i<len; i++) {
		if ( i == 0 )					bDigits	= TXStringExt::IsDigit( szString[i] ) || szString[i] == '-' || szString[i] == '+';
		else if ( szString[i] != '.' )	bDigits	= bDigits && TXStringExt::IsDigit( szString[i] );
		if ( ! bHasDot )				bHasDot	= szString[i] == '.';
	}

	if ( len >= 1 && szString[0] == '0' && szString[1] == 'x' ) {
		VWFC_ASSERT( false );	// NOT TESTED!!!!
		// we have binary data
		bool	switc		= false;
		size_t	dataIndex	= 0;
		UInt8*	arrBytes	= (UInt8*) NEW_DATA( len );	// make a little bit more
		for(size_t i=2; i<len; i++) {
			UInt8	data	= 0;
			if ( szString[i] >= '0' && szString[i] <= '9' )			data	= szString[i] - '0';
			else if ( szString[i] >= 'A' && szString[i] <= 'F' )	data	= szString[i] - 'A' + 0x0A;
			else													VWFC_ASSERT( false );

			if ( switc == false ) {
				switc					= true;
				arrBytes[ dataIndex ]	= data;
			}
			else {
				switc					= false;
				arrBytes[ dataIndex ]	= (data << 4) & arrBytes[ dataIndex ];
				dataIndex++;
			}
		}
		// set the data
		this->SetValue( arrBytes, dataIndex );
	}
	else if ( bDigits  ) {
		// we have integer or real
		if ( bHasDot ) {
			double		value	= str.atof();
			this->SetValue( value );
		}
		else {
			SInt32		value	= str.atoi();
			this->SetValue( value );
		}
	}
	else {
		// we have string
		this->SetValue( str );
	}
}

TXString VWDataSerializerValue::GetName() const
{
	return m_name;
}

void VWDataSerializerValue::SetName(const TXString& name)
{
	m_name		= name;
}

void VWDataSerializerValue::SetData(void* pData, size_t size)
{
	m_nBytesCnt		= size;
	m_pBytes		= (UInt8*) NEW_DATA( m_nBytesCnt );
	UInt8*	pSource	= (UInt8*) pData;
	for(size_t i=0; i<m_nBytesCnt; i++) {
		m_pBytes[i]	= pSource[i];
	}
}

// ----------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------
VWDataSerializerGroup::VWDataSerializerGroup(TDataIdentifier id, const char* szName)
{
	m_identifier		= id;
	if ( szName )	m_szName		= szName;
	else			m_szName.Format( "Gr%X", id );
}

VWDataSerializerGroup::~VWDataSerializerGroup()
{
	this->ClearChildGroups();
}

void VWDataSerializerGroup::ClearChildGroups()
{
	size_t		vlen		= m_arrValues.size();
	for(size_t i=0; i<vlen; i++) {
		DELETE_OBJECT( VWDataSerializerValue, m_arrValues[i] );
	}
	m_arrValues.clear();

	size_t		glen		= m_arrChildGroups.size();
	for(size_t i=0; i<glen; i++) {
		DELETE_OBJECT( VWDataSerializerGroup, m_arrChildGroups[i] );
	}
	m_arrChildGroups.clear();
}

VWDataSerializerGroup* VWDataSerializerGroup::CreateChildDataGroup(TDataIdentifier id, const char* szGroupName)
{
	VWDataSerializerGroup*		pNewGroup	= NEW_OBJECT( VWDataSerializerGroup )( id, szGroupName );

	m_arrChildGroups.push_back( pNewGroup );

	return pNewGroup;
}

VWDataSerializerGroup* VWDataSerializerGroup::FindChildDataGroup(TDataIdentifier id, const char* szGroupName) const
{
	VWDataSerializerGroup*	pFound		= NULL;
	size_t					len			= m_arrChildGroups.size();
	for(size_t i=0; i<len; i++) {
		VWDataSerializerGroup*	pGroup	= m_arrChildGroups[ i ];
		if ( pGroup->m_identifier == id ) {
			pFound		= pGroup;
			break;
		}
	}
	return pFound;
}

void VWDataSerializerGroup::FindChildDataGroups(TDataSerializerGroupsArray& outArray, TDataIdentifier id, const char* szGroupName) const
{
	outArray.clear();
	size_t		len		= m_arrChildGroups.size();
	for(size_t i=0; i<len; i++) {
		VWDataSerializerGroup*	pGroup	= m_arrChildGroups[ i ];
		if ( pGroup->m_identifier == id ) {
			outArray.push_back( pGroup );
		}
	}
}

TXString VWDataSerializerGroup::GetName() const
{
	return m_szName;
}

TDataIdentifier VWDataSerializerGroup::GetIdentifier() const
{
	return m_identifier;
}

void VWDataSerializerGroup::AddValue(const VWDataSerializerValue& value, size_t index, const char* szValueName)
{
	VWDataSerializerValue*	pValue	= NEW_OBJECT( VWDataSerializerValue )( value );

	TXString		valueName;
	if ( szValueName )		valueName	= szValueName;
	else					valueName.Format( "Value%d", m_arrValues.size() );

	pValue->SetName( valueName );

	size_t	len		= m_arrValues.size();
	for(size_t i=len; i<=index; i++)
		m_arrValues.push_back( NULL );
	m_arrValues[ index ]	= pValue;
}

VWDataSerializerValue VWDataSerializerGroup::GetValue(size_t index, const char* szValueName) const
{
	size_t	len		= m_arrValues.size();

	// first search for the name
	for(size_t i=0; i<len; i++) {
		const VWDataSerializerValue*	pValue	= m_arrValues[ i ];
		TXString						name	= pValue->GetName();
		if ( ! name.IsEmpty() && szValueName && name == szValueName ) {
			// STOP!
			return * pValue;
		}
	}

	if ( index < len )
		return * m_arrValues[ index ];
	
	return VWDataSerializerValue( (SInt32) 0 );
}

bool VWDataSerializerGroup::IsGroupIdentifier(TDataIdentifier id)
{
	return m_identifier == id;
}

VWDataSerializerGroup* VWDataSerializerGroup::GetChildGroup(TDataIdentifier id, const char* szGroupName)
{
	VWDataSerializerGroup*	pFound		= NULL;
	size_t					len			= m_arrChildGroups.size();
	for(size_t i=0; i<len; i++) {
		VWDataSerializerGroup*	pChild	= m_arrChildGroups[ i ];
		if ( pChild->GetIdentifier() == id || ( szGroupName && pChild->GetName() == szGroupName ) ) {
			pFound		= pChild;
			break;
		}
	}
	
	return pFound;
}

// ----------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------
VWDataSerializer::VWDataSerializer(const char* szSerializerName)
{
	m_pMainGroup		= NEW_OBJECT(VWDataSerializerGroup)( 0, szSerializerName ? szSerializerName : "MainGroup" );
}

VWDataSerializer::~VWDataSerializer()
{
	this->ClearChildGroups();
	DELETE_OBJECT( VWDataSerializerGroup, m_pMainGroup );
}

void VWDataSerializer::ClearChildGroups()
{
	m_pMainGroup->ClearChildGroups();
}

VWDataSerializerGroup* VWDataSerializer::CreateChildDataGroup(TDataIdentifier id, const char* szGroupName)
{
	return m_pMainGroup->CreateChildDataGroup( id, szGroupName );
}

VWDataSerializerGroup* VWDataSerializer::FindChildDataGroup(TDataIdentifier id, const char* szGroupName) const
{
	return m_pMainGroup->FindChildDataGroup( id, szGroupName );
}

void VWDataSerializer::FindChildDataGroups(TDataSerializerGroupsArray& outArray, TDataIdentifier id, const char* szGroupName) const
{
	m_pMainGroup->FindChildDataGroups( outArray, id, szGroupName );
}

size_t VWDataSerializer::SaveDataInMemoryReq(VWDataSerializerGroup* pGroup, UInt8* pData) const
{
	UInt8*			pDataID		= pData;
	UInt8*			pChunkSize	= pDataID + sizeof(TDataIdentifier);
	UInt8*			pValueData	= pChunkSize + sizeof(UInt32);

	size_t	valueCnt		= pGroup->m_arrValues.size();
	for(size_t i=0; i<valueCnt; i++) {
		VWDataSerializerValue*	pValue	= pGroup->m_arrValues[i];
		if ( pValue ) {
			UInt8*			pThisValueSize	= pValueData;
			pValueData						+= sizeof(UInt32);

			if ( pData ) {
				UInt32	bytesCnt	= pValue->m_nBytesCnt;
				bytesCnt			= /*static*/ ::EnsureSwappedBytes( bytesCnt );

				memcpy( pThisValueSize, & bytesCnt, sizeof(UInt32) );
				memcpy( pValueData, pValue->m_pBytes, pValue->m_nBytesCnt );
			}

			pValueData		+= pValue->m_nBytesCnt;
		}
	}
	if ( pData ) {
		UInt32	bytesEnd	= 0;
		memcpy( pValueData, & bytesEnd, sizeof(UInt32) );
	}
	pValueData		+= sizeof(UInt32);

	size_t	groupCnt		= pGroup->m_arrChildGroups.size();
	for(size_t i=0; i<groupCnt; i++) {
		size_t	size	= this->SaveDataInMemoryReq( pGroup->m_arrChildGroups[i], pData ? pValueData : NULL );

		pValueData		+=  size;
	}

	UInt32	chunkSize		= pValueData - pData;

	if ( pData ) {
		TDataIdentifier	id			= pGroup->m_identifier;
		id							= /*static*/ ::EnsureSwappedBytes( id );
		memcpy( pDataID, & id, sizeof(TDataIdentifier) );

		UInt32			size		= chunkSize;
		size						= /*static*/ ::EnsureSwappedBytes( size );
		memcpy( pChunkSize, & size, sizeof(UInt32) );
	}

	return chunkSize;
}

bool VWDataSerializer::ReadDataFromMemoryReq(VWDataSerializerGroup* pGroup, UInt8* pData, size_t size)
{
#define CHECK_CAN_READ_BYTES(bytes)	if ( size_t(pReadData - pData + bytes) > size ) return false;

	TDataIdentifier		id;
	UInt32				chunkSize		= 0;

	UInt8*				pReadData		= pData;

	CHECK_CAN_READ_BYTES( sizeof(TDataIdentifier) );
	memcpy( & id, pReadData, sizeof(TDataIdentifier) );
	id				= /*static*/ ::EnsureSwappedBytes( id );
	pReadData		+= sizeof(TDataIdentifier);

	CHECK_CAN_READ_BYTES( sizeof(UInt32) );
	memcpy( & chunkSize, pReadData, sizeof(UInt32) );
	chunkSize		= /*static*/ ::EnsureSwappedBytes( chunkSize );
	pReadData		+= sizeof(UInt32);

	VWDataSerializerGroup*	pNewGroup	= m_pMainGroup;
	if ( pGroup )
		pNewGroup		= pGroup->CreateChildDataGroup( id, NULL );

	size_t	valuesCnt	= 0;
	while( true ) {
		UInt32		bytesCnt	= 0;

		CHECK_CAN_READ_BYTES( sizeof(UInt32) );
		memcpy( & bytesCnt, pReadData, sizeof(UInt32) );
		bytesCnt		= /*static*/ ::EnsureSwappedBytes( bytesCnt );
		pReadData		+= sizeof(UInt32);
		if ( bytesCnt == 0 )
			break;

		CHECK_CAN_READ_BYTES( bytesCnt );
		VWDataSerializerValue	value( (void*) pReadData, bytesCnt );
		pNewGroup->AddValue( value, valuesCnt, NULL );
		valuesCnt++;

		pReadData		+= bytesCnt;
	}

	UInt32		currSize		= pReadData - pData;
	if ( currSize > chunkSize )		return false;

	UInt32		childChunksSize	= chunkSize - currSize;
	while( childChunksSize > 0 ) {
		UInt32	childChunkSize	= 0;
		CHECK_CAN_READ_BYTES( sizeof(TDataIdentifier) );
		memcpy( & childChunkSize, pReadData + sizeof(TDataIdentifier), sizeof(UInt32) );
		childChunkSize		= /*static*/ ::EnsureSwappedBytes( childChunkSize );

		if ( ! this->ReadDataFromMemoryReq( pNewGroup, pReadData, childChunkSize ) )
			return false;

		if ( childChunksSize < childChunkSize )	return false;
		childChunksSize	-= childChunkSize;

		pReadData		+= childChunkSize;
	}
#undef CHECK_CAN_READ_BYTES

	return true;
}

void VWDataSerializer::SaveDataInVWSettingsReq(VWDataSerializerGroup* pGroup, const TXString& category) const
{
	size_t	valueCnt		= pGroup->m_arrValues.size();
	for(size_t i=0; i<valueCnt; i++) {
		VWDataSerializerValue*	pValue	= pGroup->m_arrValues[i];

		TXString		valueName		= pValue->GetName();
		TXString		valueContent	= pValue->GetValueAsString();

		::GS_SetSavedSetting( gCBP, category, valueName, valueContent );
	}

	size_t	groupCnt		= pGroup->m_arrChildGroups.size();
	for(size_t i=0; i<groupCnt; i++) {
		VWDataSerializerGroup*	pChildGroup	= pGroup->m_arrChildGroups[i];

		TXString	childCategory	= category;
		childCategory				+= "/";
		childCategory				+= pChildGroup->GetName();
		this->SaveDataInVWSettingsReq( pChildGroup, childCategory );
	}
}

bool VWDataSerializer::ReadDataFromVWSettingsReq(VWDataSerializerGroup* pGroup, const TXString& category)
{
	size_t	valueCnt		= pGroup->m_arrValues.size();
	for(size_t i=0; i<valueCnt; i++) {
		VWDataSerializerValue*	pValue	= pGroup->m_arrValues[i];
		if ( pValue ) {
			TXString		valueName		= pValue->GetName();

			Str255			value;
			if ( ::GS_GetSavedSetting( gCBP, category, valueName, value ) ) {
				pValue->SetValueAsString( value );
			}
		}
	}

	size_t	groupCnt		= pGroup->m_arrChildGroups.size();
	for(size_t i=0; i<groupCnt; i++) {
		VWDataSerializerGroup*	pChildGroup	= pGroup->m_arrChildGroups[i];

		TXString	childCategory	= category;
		childCategory				+= "/";
		childCategory				+= pChildGroup->GetName();
		this->ReadDataFromVWSettingsReq( pChildGroup, childCategory );
	}

	return true;
}

size_t VWDataSerializer::GetDataBytesCount() const
{
	return this->SaveDataInMemoryReq( m_pMainGroup, NULL );
}

void VWDataSerializer::SaveDataInMemory(void* pData) const
{
	this->SaveDataInMemoryReq( m_pMainGroup, (UInt8*) pData );
}

bool VWDataSerializer::ReadDataFromMemory(void* pData, size_t size)
{
	// reset byte swap flag
	// this is to ensure correct byte swap
	// and we will determine it each time when we read from the memory
	g_bByteSwapEnsure		= -1;

	this->ClearChildGroups();

	bool		ok = true;
	if ( ! this->ReadDataFromMemoryReq( NULL, (UInt8*) pData, size ) ) {
		ok		= false;
		m_pMainGroup->ClearChildGroups();
	}

	return ok;
}

void VWDataSerializer::SaveDataInVWSettings() const
{
	this->SaveDataInVWSettingsReq( m_pMainGroup, m_pMainGroup->GetName() );
}

bool VWDataSerializer::ReadDataFromVWSettings()
{
	bool		ok = true;
	if ( ! this->ReadDataFromVWSettingsReq( m_pMainGroup, m_pMainGroup->GetName() ) ) {
		ok		= false;
		m_pMainGroup->ClearChildGroups();
	}

	return ok;
}
