482 lines
11 KiB
C++
482 lines
11 KiB
C++
#include "../../include/kfile/TrfMapper.h"
|
|
|
|
|
|
namespace trf {
|
|
|
|
// =================================================================================================================
|
|
|
|
void MTemplate::init( Mapper* pParent, const TemplateInfo* pInfo, const char* pBuf, bool bID )
|
|
{
|
|
m_pParent = pParent;
|
|
m_pInfo = pInfo;
|
|
m_pATI = pInfo ? m_pParent->getATI( m_pInfo->id() ) : NULL;
|
|
|
|
if ( m_pATI == NULL || fixedSize() < 0 )
|
|
{
|
|
unsigned int size = *reinterpret_cast< const unsigned int* >( pBuf );
|
|
pBuf += sizeof(size);
|
|
if ( size < 0 || pBuf + size > m_pParent->m_pBufEnd )
|
|
throw Exception( 1 );
|
|
}
|
|
|
|
if ( bID )
|
|
{
|
|
short nId = *reinterpret_cast< const short* >( pBuf );
|
|
pBuf += sizeof(nId);
|
|
|
|
m_pATI = m_pParent->getATI( nId );
|
|
m_pInfo = m_pATI->pInfo;
|
|
|
|
if ( m_pInfo == NULL || (pInfo != NULL && m_pInfo != pInfo) )
|
|
throw Exception( 2 );
|
|
}
|
|
|
|
// mapper 는 filer 와 달리 내부적으로도 field limit 를 존중한다
|
|
|
|
m_fields.resize( count() );
|
|
memset( &m_fields.front(), 0, count() * sizeof(Field) );
|
|
|
|
for ( int i = 0, n = count(); i < n; i++ )
|
|
{
|
|
m_fields[ i ].ptr = pBuf;
|
|
int size = fixedSizeAt( i );
|
|
if ( size > 0 )
|
|
pBuf += size;
|
|
else
|
|
pBuf += *reinterpret_cast< const unsigned int* >( pBuf ) + sizeof(unsigned int);
|
|
}
|
|
}
|
|
|
|
void MTemplate::close()
|
|
{
|
|
for ( int i = 0, n = count(); i < n; i++ )
|
|
{
|
|
int type = typeAt( i );
|
|
if ( Type::isSimpleArrayType( type ) )
|
|
m_pParent->deleteArray( m_fields[ i ].asArray );
|
|
else if ( type == Type::TEMPLATE )
|
|
m_pParent->deleteTemplate( m_fields[ i ].asTemplate );
|
|
else if ( type == Type::TEMPLATE_ARRAY )
|
|
m_pParent->deleteTemplateArray( m_fields[ i ].asTemplateArray );
|
|
else if ( type == Type::DICT )
|
|
m_pParent->deleteDict( m_fields[ i ].asDict );
|
|
}
|
|
}
|
|
|
|
void MTemplateArray::init( Mapper* pParent, const TemplateInfo* pInfo, int fixedCount, const char* pBuf )
|
|
{
|
|
// fixed array
|
|
|
|
m_pInfo = pInfo;
|
|
m_pParent = pParent;
|
|
m_pATI = pParent->getATI( pInfo->id() );
|
|
|
|
m_fields.resize( fixedCount );
|
|
memset( &m_fields.front(), 0, fixedCount * sizeof(Field) );
|
|
|
|
if ( m_pInfo->fixedSize() < 0 )
|
|
{
|
|
unsigned int size = *reinterpret_cast< const unsigned int* >( pBuf );
|
|
pBuf += sizeof(size);
|
|
if ( size < 0 || pBuf + size > m_pParent->m_pBufEnd )
|
|
throw Exception( 3 );
|
|
}
|
|
|
|
int fixSize = fixedSize();
|
|
if ( fixSize > 0 )
|
|
for ( int i = 0; i < fixedCount; i++ )
|
|
{
|
|
m_fields[ i ].ptr = pBuf;
|
|
pBuf += fixSize;
|
|
}
|
|
else
|
|
for ( int i = 0; i < fixedCount; i++ )
|
|
{
|
|
m_fields[ i ].ptr = pBuf;
|
|
pBuf += *reinterpret_cast< const unsigned int* >( pBuf ) + sizeof(unsigned int);
|
|
}
|
|
}
|
|
|
|
void MTemplateArray::init( Mapper* pParent, const TemplateInfo* pInfo, const char* pBuf )
|
|
{
|
|
// variable array
|
|
|
|
m_pInfo = pInfo;
|
|
m_pParent = pParent;
|
|
|
|
unsigned int size = *reinterpret_cast< const unsigned int* >( pBuf );
|
|
pBuf += sizeof(size);
|
|
|
|
if ( size < 0 || pBuf + size > m_pParent->m_pBufEnd )
|
|
throw Exception( 4 );
|
|
|
|
short nId = *reinterpret_cast< const short* >( pBuf );
|
|
pBuf += sizeof(nId);
|
|
|
|
m_pATI = pParent->getATI( nId );
|
|
m_pInfo = m_pATI->pInfo;
|
|
|
|
if ( m_pInfo == NULL || (pInfo != NULL && m_pInfo != pInfo) )
|
|
throw Exception( 5 );
|
|
|
|
int n = *reinterpret_cast< const int* >( pBuf );
|
|
pBuf += sizeof(n);
|
|
|
|
if ( n < 0 )
|
|
throw Exception( 6 );
|
|
|
|
m_fields.resize( n );
|
|
if ( n > 0 )
|
|
memset( &m_fields.front(), 0, n * sizeof(Field) );
|
|
|
|
int fixSize = fixedSize();
|
|
if ( fixSize > 0 )
|
|
for ( int i = 0, n = count(); i < n; i++ )
|
|
{
|
|
m_fields[ i ].ptr = pBuf;
|
|
pBuf += fixSize;
|
|
}
|
|
else
|
|
for ( int i = 0, n = count(); i < n; i++ )
|
|
{
|
|
m_fields[ i ].ptr = pBuf;
|
|
pBuf += *reinterpret_cast< const unsigned int* >( pBuf ) + sizeof(unsigned int);
|
|
}
|
|
}
|
|
|
|
void MTemplateArray::close()
|
|
{
|
|
for ( int i = 0, n = m_fields.size(); i < n; i++ )
|
|
m_pParent->deleteTemplate( m_fields[ i ].asTemplate );
|
|
}
|
|
|
|
void MArray::init( Mapper* pParent, int type, int fixedCount, const char* pBuf )
|
|
{
|
|
// fixed array
|
|
|
|
m_pParent = pParent;
|
|
m_type = type;
|
|
|
|
m_pBuf = pBuf;
|
|
m_count = fixedCount;
|
|
}
|
|
|
|
void MArray::init( Mapper* pParent, int type, const char* pBuf )
|
|
{
|
|
// variable array
|
|
|
|
m_pParent = pParent;
|
|
m_type = type;
|
|
|
|
unsigned int size = *reinterpret_cast< const unsigned int* >( pBuf );
|
|
pBuf += sizeof( size );
|
|
|
|
if ( size < 0 || pBuf + size > m_pParent->m_pBufEnd )
|
|
throw Exception( 7 );
|
|
|
|
m_type = *(pBuf++);
|
|
int elemSize = Type::getTypeSize( m_type );
|
|
|
|
m_pBuf = pBuf;
|
|
m_count = (size - 1) / elemSize;
|
|
}
|
|
|
|
void MDict::init( Mapper* pParent, const char* pBuf )
|
|
{
|
|
m_pParent = pParent;
|
|
|
|
unsigned int size = *reinterpret_cast< const unsigned int* >( pBuf );
|
|
pBuf += sizeof(size);
|
|
|
|
if ( size < 0 || pBuf + size > m_pParent->m_pBufEnd )
|
|
throw Exception( 8 );
|
|
|
|
int n = *reinterpret_cast< const int* >( pBuf );
|
|
pBuf += sizeof( n );
|
|
|
|
if ( n < 0 )
|
|
throw Exception( 9 );
|
|
|
|
m_fields.resize( n );
|
|
if ( n > 0 )
|
|
memset( &m_fields.front(), 0, n * sizeof(Field) );
|
|
|
|
unsigned int fieldHdrSize = m_pParent->m_bUnpackedDict ? sizeof(UnpackedFieldHdr) : sizeof(FieldHdr);
|
|
|
|
for ( int i = 0; i < n; i++ )
|
|
{
|
|
Field& field = m_fields[ i ];
|
|
field.ptr = reinterpret_cast< const FieldHdr* >( pBuf );
|
|
pBuf += fieldHdrSize;
|
|
|
|
int type = _getFieldType( field.ptr );
|
|
|
|
if ( Type::isSimpleType( type ) )
|
|
{
|
|
pBuf += Type::getTypeSize( type );
|
|
}
|
|
else
|
|
{
|
|
unsigned int blockLen = *reinterpret_cast< const unsigned int* >( pBuf );
|
|
if ( blockLen < 0 )
|
|
throw Exception( 10 );
|
|
pBuf += blockLen + sizeof(blockLen);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MDict::close()
|
|
{
|
|
for ( int i = 0, n = m_fields.size(); i < n; i++ )
|
|
{
|
|
int type = typeAt( i );
|
|
if ( Type::isSimpleArrayType( type ) )
|
|
m_pParent->deleteArray( m_fields[ i ].asArray );
|
|
else if ( type == Type::TEMPLATE )
|
|
m_pParent->deleteTemplate( m_fields[ i ].asTemplate );
|
|
else if ( type == Type::TEMPLATE_ARRAY )
|
|
m_pParent->deleteTemplateArray( m_fields[ i ].asTemplateArray );
|
|
else if ( type == Type::DICT )
|
|
m_pParent->deleteDict( m_fields[ i ].asDict );
|
|
}
|
|
}
|
|
|
|
|
|
// =================================================================================================================
|
|
|
|
static const char g_idStr[4] = { 'B','T','R','F' };
|
|
|
|
Mapper::Mapper( const MetaData* pMetaData, const void* pBuf, int bufSize )
|
|
{
|
|
m_pMetaData = pMetaData;
|
|
m_pBuf = reinterpret_cast< const char* >( pBuf );
|
|
m_pBufEnd = m_pBuf + bufSize;
|
|
m_pRoot = NULL;
|
|
|
|
if ( m_pMetaData )
|
|
m_pMetaData->addRef();
|
|
|
|
try
|
|
{
|
|
const char* p = m_pBuf;
|
|
|
|
const FileHeader* pFileHeader = reinterpret_cast< const FileHeader* >( p );
|
|
if ( memcmp( pFileHeader->idstr, g_idStr, 4 ) )
|
|
throw Exception( 11 );
|
|
|
|
p += sizeof( FileHeader );
|
|
bufSize -= sizeof( FileHeader );
|
|
|
|
const HeaderInfo* pHeaderInfo = reinterpret_cast< const HeaderInfo* >( p );
|
|
|
|
m_bUnpackedDict = pHeaderInfo->majorVersion == 1 && pHeaderInfo->minorVersion == 0;
|
|
|
|
p += pFileHeader->headerInfoSize;
|
|
bufSize -= pFileHeader->headerInfoSize;
|
|
|
|
p = initIdTable( p );
|
|
p = initStringTable( p );
|
|
|
|
m_pRoot = createDict( p );
|
|
}
|
|
catch ( Exception& )
|
|
{
|
|
if ( m_pMetaData )
|
|
m_pMetaData->subRef();
|
|
m_pMetaData = NULL;
|
|
throw;
|
|
}
|
|
}
|
|
|
|
Mapper::~Mapper()
|
|
{
|
|
if ( m_pRoot )
|
|
m_pRoot->close();
|
|
delete m_pRoot;
|
|
|
|
if ( m_pMetaData ) {
|
|
m_pMetaData->subRef();
|
|
}
|
|
}
|
|
|
|
const char* Mapper::initIdTable( const char* pBuf )
|
|
{
|
|
int size = *reinterpret_cast< const int* >( pBuf );
|
|
pBuf += sizeof(size);
|
|
const char* pBufEnd = pBuf + size;
|
|
|
|
if ( size < 0 )
|
|
throw Exception( size, "idtable size error!" );
|
|
|
|
// map GUID pointer
|
|
|
|
m_idCount = size / (sizeof(GUID) + sizeof(unsigned short));
|
|
m_pId = reinterpret_cast< const GUID* >( pBuf );
|
|
|
|
// set template field limits
|
|
|
|
pBuf += m_idCount * sizeof(GUID);
|
|
const unsigned short* pATInfos = reinterpret_cast< const unsigned short* >( pBuf );
|
|
|
|
m_TInfoIndexTable.resize( m_pMetaData->getTemplateInfoCount() );
|
|
memset( m_TInfoIndexTable, 0xff, m_pMetaData->getTemplateInfoCount() * sizeof(short) );
|
|
|
|
m_ATIs.resize( m_idCount );
|
|
for ( int i = 0; i < m_idCount; i++ )
|
|
{
|
|
const TemplateInfo* pInfo = m_pMetaData->getTemplateInfo( m_pId[ i ] );
|
|
if ( pInfo == NULL )
|
|
throw Exception( 0, "unknown template GUID" );
|
|
|
|
ATInfo& fl = m_ATIs[ i ];
|
|
fl.fieldLimit = pATInfos[ i ];
|
|
fl.fixedSize = pInfo->calcFixedSize( fl.fieldLimit );
|
|
fl.pInfo = pInfo;
|
|
m_TInfoIndexTable[ pInfo->getMetaDataIndex() ] = static_cast< short >( i );
|
|
}
|
|
|
|
if ( pBuf + m_idCount * sizeof(unsigned short) > pBufEnd )
|
|
throw Exception( size, "idtable error!" );
|
|
|
|
return pBufEnd;
|
|
}
|
|
|
|
template< typename CHAR >
|
|
inline static int strnlen_( const CHAR* pStr, int limit )
|
|
{
|
|
if ( pStr == NULL )
|
|
return 0;
|
|
|
|
for ( int i = 0; i < limit; i++, pStr++ )
|
|
{
|
|
if ( *pStr == 0 )
|
|
return i;
|
|
}
|
|
return limit;
|
|
}
|
|
|
|
const char* Mapper::initStringTable( const char* pBuf )
|
|
{
|
|
int size = *reinterpret_cast< const int* >( pBuf );
|
|
pBuf += sizeof(size);
|
|
const char* pBufEnd = pBuf + size;
|
|
|
|
if ( size < 0 )
|
|
throw Exception( size, "stringtable size error!" );
|
|
|
|
int i;
|
|
int n;
|
|
|
|
// map string table
|
|
|
|
n = *reinterpret_cast< const int* >( pBuf );
|
|
pBuf += sizeof( n );
|
|
size -= sizeof( n );
|
|
|
|
if ( n < 0 )
|
|
throw Exception( n, "str table count error" );
|
|
|
|
m_stringTable.resize( n );
|
|
for ( i = 0; i < n; i++ )
|
|
{
|
|
int len = strnlen_( pBuf, size );
|
|
m_stringTable[ i ] = pBuf;
|
|
|
|
pBuf += len+1;
|
|
size -= len+1;
|
|
}
|
|
|
|
// map wstring table
|
|
|
|
n = *reinterpret_cast< const int* >( pBuf );
|
|
pBuf += sizeof( n );
|
|
size -= sizeof( n );
|
|
|
|
if ( n < 0 )
|
|
throw Exception( n, "wstr table count error" );
|
|
|
|
m_wstringTable.resize( n );
|
|
for ( i = 0; i < n; i++ )
|
|
{
|
|
int len = strnlen_( reinterpret_cast< const wchar_t* >( pBuf ), size / sizeof(wchar_t) );
|
|
m_wstringTable[ i ] = reinterpret_cast< const wchar_t* >( pBuf );
|
|
|
|
pBuf += (len+1) * sizeof(wchar_t);
|
|
size -= (len+1) * sizeof(wchar_t);
|
|
}
|
|
|
|
if ( pBuf > pBufEnd )
|
|
throw Exception( size, "stringtable error!" );
|
|
|
|
return pBufEnd;
|
|
}
|
|
|
|
MTemplate* Mapper::createTemplate( const TemplateInfo* pInfo, const char* pBuf, bool bID )
|
|
{
|
|
MTemplate* p = new MTemplate;
|
|
p->init( this, pInfo, pBuf, bID );
|
|
return p;
|
|
}
|
|
|
|
MTemplateArray* Mapper::createTemplateArray( const TemplateInfo* pInfo, int fixedCount, const char* pBuf )
|
|
{
|
|
MTemplateArray* p = new MTemplateArray;
|
|
p->init( this, pInfo, fixedCount, pBuf );
|
|
return p;
|
|
}
|
|
|
|
MTemplateArray* Mapper::createTemplateArray( const TemplateInfo* pInfo, const char* pBuf )
|
|
{
|
|
MTemplateArray* p = new MTemplateArray;
|
|
p->init( this, pInfo, pBuf );
|
|
return p;
|
|
}
|
|
|
|
MArray* Mapper::createArray( int type, int fixedCount, const char* pBuf )
|
|
{
|
|
MArray* p = new MArray;
|
|
p->init( this, type, fixedCount, pBuf );
|
|
return p;
|
|
}
|
|
|
|
MArray* Mapper::createArray( int type, const char* pBuf )
|
|
{
|
|
MArray* p = new MArray;
|
|
p->init( this, type, pBuf );
|
|
return p;
|
|
}
|
|
|
|
MDict* Mapper::createDict( const char* pBuf )
|
|
{
|
|
MDict* p = new MDict;
|
|
p->init( this, pBuf );
|
|
return p;
|
|
}
|
|
|
|
void Mapper::deleteTemplate( MTemplate* pTemplate )
|
|
{
|
|
if ( pTemplate )
|
|
pTemplate->close();
|
|
delete pTemplate;
|
|
}
|
|
|
|
void Mapper::deleteTemplateArray( MTemplateArray* pTemplateArray )
|
|
{
|
|
if ( pTemplateArray )
|
|
pTemplateArray->close();
|
|
delete pTemplateArray;
|
|
}
|
|
|
|
void Mapper::deleteArray( MArray* pArray )
|
|
{
|
|
delete pArray;
|
|
}
|
|
|
|
void Mapper::deleteDict( MDict* pDict )
|
|
{
|
|
if ( pDict )
|
|
pDict->close();
|
|
delete pDict;
|
|
}
|
|
|
|
} // namespace trf
|