587 lines
11 KiB
C++
587 lines
11 KiB
C++
|
// Interpreted Block Stream Functions
|
||
|
//
|
||
|
// -- jweier
|
||
|
|
||
|
// this include must remain at the top of every Icarus CPP file
|
||
|
#include "stdafx.h"
|
||
|
|
||
|
#include "IcarusInterface.h"
|
||
|
#include "IcarusImplementation.h"
|
||
|
|
||
|
#include "BlockStream.h"
|
||
|
|
||
|
/*
|
||
|
===================================================================================================
|
||
|
|
||
|
CBlockMember
|
||
|
|
||
|
===================================================================================================
|
||
|
*/
|
||
|
|
||
|
inline CBlockMember::CBlockMember( void )
|
||
|
{
|
||
|
m_id = -1;
|
||
|
m_size = -1;
|
||
|
m_data = NULL;
|
||
|
}
|
||
|
|
||
|
inline CBlockMember::~CBlockMember( void )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
Free
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
void CBlockMember::Free(IGameInterface* game)
|
||
|
{
|
||
|
if ( m_data != NULL )
|
||
|
{
|
||
|
game->Free ( m_data );
|
||
|
m_data = NULL;
|
||
|
|
||
|
m_id = m_size = -1;
|
||
|
}
|
||
|
delete this;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
GetInfo
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
void CBlockMember::GetInfo( int *id, int *size, void **data )
|
||
|
{
|
||
|
*id = m_id;
|
||
|
*size = m_size;
|
||
|
*data = m_data;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
SetData overloads
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
void CBlockMember::SetData( const char *data , CIcarus* icarus)
|
||
|
{
|
||
|
WriteDataPointer( data, strlen(data)+1, icarus );
|
||
|
}
|
||
|
|
||
|
void CBlockMember::SetData( vec3_t data , CIcarus* icarus)
|
||
|
{
|
||
|
WriteDataPointer( data, 3 , icarus);
|
||
|
}
|
||
|
|
||
|
void CBlockMember::SetData( void *data, int size, CIcarus* icarus)
|
||
|
{
|
||
|
IGameInterface* game = icarus->GetGame();
|
||
|
if ( m_data )
|
||
|
game->Free( m_data );
|
||
|
|
||
|
m_data = game->Malloc( size );
|
||
|
memcpy( m_data, data, size );
|
||
|
m_size = size;
|
||
|
}
|
||
|
|
||
|
// Member I/O functions
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
ReadMember
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int CBlockMember::ReadMember( char **stream, long *streamPos, CIcarus* icarus )
|
||
|
{
|
||
|
IGameInterface* game = icarus->GetGame();
|
||
|
m_id = *(int *) (*stream + *streamPos);
|
||
|
*streamPos += sizeof( int );
|
||
|
|
||
|
if ( m_id == CIcarus::ID_RANDOM )
|
||
|
{//special case, need to initialize this member's data to Q3_INFINITE so we can randomize the number only the first time random is checked when inside a wait
|
||
|
m_size = sizeof( float );
|
||
|
*streamPos += sizeof( long );
|
||
|
m_data = game->Malloc( m_size );
|
||
|
float infinite = game->MaxFloat();
|
||
|
memcpy( m_data, &infinite, m_size );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_size = *(long *) (*stream + *streamPos);
|
||
|
*streamPos += sizeof( long );
|
||
|
m_data = game->Malloc( m_size );
|
||
|
memcpy( m_data, (*stream + *streamPos), m_size );
|
||
|
}
|
||
|
*streamPos += m_size;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
WriteMember
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int CBlockMember::WriteMember( FILE *m_fileHandle )
|
||
|
{
|
||
|
fwrite( &m_id, sizeof(m_id), 1, m_fileHandle );
|
||
|
fwrite( &m_size, sizeof(m_size), 1, m_fileHandle );
|
||
|
fwrite( m_data, m_size, 1, m_fileHandle );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
Duplicate
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
CBlockMember *CBlockMember::Duplicate( CIcarus* icarus )
|
||
|
{
|
||
|
CBlockMember *newblock = new CBlockMember;
|
||
|
|
||
|
if ( newblock == NULL )
|
||
|
return NULL;
|
||
|
|
||
|
newblock->SetData( m_data, m_size, icarus );
|
||
|
newblock->SetSize( m_size );
|
||
|
newblock->SetID( m_id );
|
||
|
|
||
|
return newblock;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===================================================================================================
|
||
|
|
||
|
CBlock
|
||
|
|
||
|
===================================================================================================
|
||
|
*/
|
||
|
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
Init
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int CBlock::Init( void )
|
||
|
{
|
||
|
m_flags = 0;
|
||
|
m_id = 0;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
Create
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int CBlock::Create( int block_id )
|
||
|
{
|
||
|
Init();
|
||
|
|
||
|
m_id = block_id;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
Free
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int CBlock::Free( CIcarus* icarus )
|
||
|
{
|
||
|
IGameInterface* game = icarus->GetGame();
|
||
|
int numMembers = GetNumMembers();
|
||
|
CBlockMember *bMember;
|
||
|
|
||
|
while ( numMembers-- )
|
||
|
{
|
||
|
bMember = GetMember( numMembers );
|
||
|
|
||
|
if (!bMember)
|
||
|
return false;
|
||
|
|
||
|
bMember->Free(game);
|
||
|
}
|
||
|
|
||
|
m_members.clear(); //List of all CBlockMembers owned by this list
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Write overloads
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
Write
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int CBlock::Write( int member_id, const char *member_data, CIcarus* icarus )
|
||
|
{
|
||
|
CBlockMember *bMember = new CBlockMember;
|
||
|
|
||
|
bMember->SetID( member_id );
|
||
|
|
||
|
bMember->SetData( member_data, icarus );
|
||
|
bMember->SetSize( strlen(member_data) + 1 );
|
||
|
|
||
|
AddMember( bMember );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int CBlock::Write( int member_id, vec3_t member_data, CIcarus* icarus )
|
||
|
{
|
||
|
CBlockMember *bMember;
|
||
|
|
||
|
bMember = new CBlockMember;
|
||
|
|
||
|
bMember->SetID( member_id );
|
||
|
bMember->SetData( member_data, icarus );
|
||
|
bMember->SetSize( sizeof(vec3_t) );
|
||
|
|
||
|
AddMember( bMember );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int CBlock::Write( int member_id, float member_data, CIcarus* icarus )
|
||
|
{
|
||
|
CBlockMember *bMember = new CBlockMember;
|
||
|
|
||
|
bMember->SetID( member_id );
|
||
|
bMember->WriteData( member_data, icarus );
|
||
|
bMember->SetSize( sizeof(member_data) );
|
||
|
|
||
|
AddMember( bMember );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int CBlock::Write( int member_id, int member_data, CIcarus* icarus )
|
||
|
{
|
||
|
CBlockMember *bMember = new CBlockMember;
|
||
|
|
||
|
bMember->SetID( member_id );
|
||
|
bMember->WriteData( member_data , icarus);
|
||
|
bMember->SetSize( sizeof(member_data) );
|
||
|
|
||
|
AddMember( bMember );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
int CBlock::Write( CBlockMember *bMember, CIcarus* )
|
||
|
{
|
||
|
// findme: this is wrong: bMember->SetSize( sizeof(bMember->GetData()) );
|
||
|
|
||
|
AddMember( bMember );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Member list functions
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
AddMember
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int CBlock::AddMember( CBlockMember *member )
|
||
|
{
|
||
|
m_members.insert( m_members.end(), member );
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
GetMember
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
CBlockMember *CBlock::GetMember( int memberNum )
|
||
|
{
|
||
|
if ( memberNum > GetNumMembers()-1 )
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
return m_members[ memberNum ];
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
GetMemberData
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
void *CBlock::GetMemberData( int memberNum )
|
||
|
{
|
||
|
if ( memberNum > GetNumMembers()-1 )
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
return (void *) ((GetMember( memberNum ))->GetData());
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
Duplicate
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
CBlock *CBlock::Duplicate( CIcarus* icarus )
|
||
|
{
|
||
|
blockMember_v::iterator mi;
|
||
|
CBlock *newblock;
|
||
|
|
||
|
newblock = new CBlock;
|
||
|
|
||
|
if ( newblock == NULL )
|
||
|
return false;
|
||
|
|
||
|
newblock->Create( m_id );
|
||
|
|
||
|
//Duplicate entire block and return the cc
|
||
|
for ( mi = m_members.begin(); mi != m_members.end(); mi++ )
|
||
|
{
|
||
|
newblock->AddMember( (*mi)->Duplicate(icarus) );
|
||
|
}
|
||
|
|
||
|
return newblock;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===================================================================================================
|
||
|
|
||
|
CBlockStream
|
||
|
|
||
|
===================================================================================================
|
||
|
*/
|
||
|
|
||
|
char* CBlockStream::s_IBI_EXT = ".IBI"; //(I)nterpreted (B)lock (I)nstructions
|
||
|
char* CBlockStream::s_IBI_HEADER_ID = "IBI";
|
||
|
const float CBlockStream::s_IBI_VERSION = 1.57f;
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
Free
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int CBlockStream::Free( void )
|
||
|
{
|
||
|
//NOTENOTE: It is assumed that the user will free the passed memory block (m_stream) immediately after the run call
|
||
|
// That's why this doesn't free the memory, it only clears its internal pointer
|
||
|
|
||
|
m_stream = NULL;
|
||
|
m_streamPos = 0;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
Create
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int CBlockStream::Create( char *filename )
|
||
|
{
|
||
|
// strip extension
|
||
|
int extensionloc = strlen(filename);
|
||
|
while ( (filename[extensionloc] != '.') && (extensionloc >= 0) )
|
||
|
{
|
||
|
extensionloc--;
|
||
|
}
|
||
|
if ( extensionloc < 0 )
|
||
|
{
|
||
|
strcpy(m_fileName, filename);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
strncpy(m_fileName, filename, extensionloc);
|
||
|
m_fileName[extensionloc] = '\0';
|
||
|
}
|
||
|
// add extension
|
||
|
strcat((char *) m_fileName, s_IBI_EXT);
|
||
|
|
||
|
if ( ((m_fileHandle = fopen(m_fileName, "wb")) == NULL) )
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
fwrite( s_IBI_HEADER_ID, 1, sizeof(s_IBI_HEADER_ID), m_fileHandle );
|
||
|
fwrite( &s_IBI_VERSION, 1, sizeof(s_IBI_VERSION), m_fileHandle );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
Init
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int CBlockStream::Init( void )
|
||
|
{
|
||
|
m_fileHandle = NULL;
|
||
|
memset(m_fileName, 0, sizeof(m_fileName));
|
||
|
|
||
|
m_stream = NULL;
|
||
|
m_streamPos = 0;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Block I/O functions
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
WriteBlock
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int CBlockStream::WriteBlock( CBlock *block, CIcarus* icarus )
|
||
|
{
|
||
|
CBlockMember *bMember;
|
||
|
int id = block->GetBlockID();
|
||
|
int numMembers = block->GetNumMembers();
|
||
|
unsigned char flags = block->GetFlags();
|
||
|
|
||
|
fwrite ( &id, sizeof(id), 1, m_fileHandle );
|
||
|
fwrite ( &numMembers, sizeof(numMembers), 1, m_fileHandle );
|
||
|
fwrite ( &flags, sizeof( flags ), 1, m_fileHandle );
|
||
|
|
||
|
for ( int i = 0; i < numMembers; i++ )
|
||
|
{
|
||
|
bMember = block->GetMember( i );
|
||
|
bMember->WriteMember( m_fileHandle );
|
||
|
}
|
||
|
|
||
|
block->Free(icarus);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
BlockAvailable
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int CBlockStream::BlockAvailable( void )
|
||
|
{
|
||
|
if ( m_streamPos >= m_fileSize )
|
||
|
return false;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
ReadBlock
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int CBlockStream::ReadBlock( CBlock *get, CIcarus* icarus )
|
||
|
{
|
||
|
CBlockMember *bMember;
|
||
|
int b_id, numMembers;
|
||
|
unsigned char flags;
|
||
|
|
||
|
if (!BlockAvailable())
|
||
|
return false;
|
||
|
|
||
|
b_id = *(int *) (m_stream + m_streamPos);
|
||
|
m_streamPos += sizeof( b_id );
|
||
|
|
||
|
numMembers = *(int *) (m_stream + m_streamPos);
|
||
|
m_streamPos += sizeof( numMembers );
|
||
|
|
||
|
flags = *(unsigned char*) (m_stream + m_streamPos);
|
||
|
m_streamPos += sizeof( flags );
|
||
|
|
||
|
if (numMembers < 0)
|
||
|
return false;
|
||
|
|
||
|
get->Create( b_id );
|
||
|
get->SetFlags( flags );
|
||
|
|
||
|
// Stream blocks are generally temporary as they
|
||
|
// are just used in an initial parsing phase...
|
||
|
#ifdef _XBOX
|
||
|
extern void Z_SetNewDeleteTemporary(bool bTemp);
|
||
|
Z_SetNewDeleteTemporary(true);
|
||
|
#endif
|
||
|
|
||
|
while ( numMembers-- > 0)
|
||
|
{
|
||
|
bMember = new CBlockMember;
|
||
|
bMember->ReadMember( &m_stream, &m_streamPos, icarus );
|
||
|
get->AddMember( bMember );
|
||
|
}
|
||
|
|
||
|
#ifdef _XBOX
|
||
|
Z_SetNewDeleteTemporary(false);
|
||
|
#endif
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
Open
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int CBlockStream::Open( char *buffer, long size )
|
||
|
{
|
||
|
char id_header[sizeof(s_IBI_HEADER_ID)];
|
||
|
float version;
|
||
|
|
||
|
Init();
|
||
|
|
||
|
m_fileSize = size;
|
||
|
|
||
|
m_stream = buffer;
|
||
|
|
||
|
for ( int i = 0; i < sizeof( id_header ); i++ )
|
||
|
{
|
||
|
id_header[i] = *(m_stream + m_streamPos++);
|
||
|
}
|
||
|
|
||
|
version = *(float *) (m_stream + m_streamPos);
|
||
|
m_streamPos += sizeof( version );
|
||
|
|
||
|
//Check for valid header
|
||
|
if ( strcmp( id_header, s_IBI_HEADER_ID ) )
|
||
|
{
|
||
|
Free();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//Check for valid version
|
||
|
if ( version != s_IBI_VERSION )
|
||
|
{
|
||
|
Free();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|