/* =========================================================================== Copyright (C) 2000 - 2013, Raven Software, Inc. Copyright (C) 2001 - 2013, Activision, Inc. Copyright (C) 2013 - 2015, OpenJK contributors This file is part of the OpenJK source code. OpenJK is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . =========================================================================== */ // Interpreted Block Stream Functions // // -- jweier // this include must remain at the top of every Icarus CPP file #include "icarus.h" #include #include "blockstream.h" #include "g_local.h" /* =================================================================================================== CBlockMember =================================================================================================== */ CBlockMember::CBlockMember( void ) { m_id = -1; m_size = -1; m_data = NULL; } CBlockMember::~CBlockMember( void ) { Free(); } /* ------------------------- Free ------------------------- */ void CBlockMember::Free( void ) { if ( m_data != NULL ) { ICARUS_Free ( m_data ); m_data = NULL; m_id = m_size = -1; } } /* ------------------------- 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 ) { WriteDataPointer( data, strlen(data)+1 ); } void CBlockMember::SetData( vector_t data ) { WriteDataPointer( data, 3 ); } void CBlockMember::SetData( void *data, int size ) { if ( m_data ) ICARUS_Free( m_data ); m_data = ICARUS_Malloc( size ); memcpy( m_data, data, size ); m_size = size; } // Member I/O functions /* ------------------------- ReadMember ------------------------- */ int CBlockMember::ReadMember( char **stream, int *streamPos ) { m_id = LittleLong(*(int *) (*stream + *((int *)streamPos))); *streamPos += sizeof( int ); if ( m_id == 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( int ); m_data = ICARUS_Malloc( m_size ); float infinite = Q3_INFINITE; memcpy( m_data, &infinite, m_size ); } else { m_size = LittleLong(*(int *) (*stream + *streamPos)); *streamPos += sizeof( int ); m_data = ICARUS_Malloc( m_size ); memcpy( m_data, (*stream + *streamPos), m_size ); #ifdef Q3_BIG_ENDIAN // only TK_INT, TK_VECTOR and TK_FLOAT has to be swapped, but just in case if (m_size == 4 && m_id != TK_STRING && m_id != TK_IDENTIFIER && m_id != TK_CHAR) *(int *)m_data = LittleLong(*(int *)m_data); #endif } *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( void ) { CBlockMember *newblock = new CBlockMember; if ( newblock == NULL ) return NULL; newblock->SetData( m_data, m_size ); newblock->SetSize( m_size ); newblock->SetID( m_id ); return newblock; } /* =================================================================================================== CBlock =================================================================================================== */ CBlock::CBlock( void ) { m_flags = 0; m_id = 0; } CBlock::~CBlock( void ) { Free(); } /* ------------------------- 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( void ) { int numMembers = GetNumMembers(); CBlockMember *bMember; while ( numMembers-- ) { bMember = GetMember( numMembers ); if (!bMember) return false; delete bMember; } 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 ) { CBlockMember *bMember = new CBlockMember; bMember->SetID( member_id ); bMember->SetData( member_data ); bMember->SetSize( strlen(member_data) + 1 ); AddMember( bMember ); return true; } int CBlock::Write( int member_id, vector_t member_data ) { CBlockMember *bMember; bMember = new CBlockMember; bMember->SetID( member_id ); bMember->SetData( member_data ); bMember->SetSize( sizeof(vector_t) ); AddMember( bMember ); return true; } int CBlock::Write( int member_id, float member_data ) { CBlockMember *bMember = new CBlockMember; bMember->SetID( member_id ); bMember->WriteData( member_data ); bMember->SetSize( sizeof(member_data) ); AddMember( bMember ); return true; } int CBlock::Write( int member_id, int member_data ) { CBlockMember *bMember = new CBlockMember; bMember->SetID( member_id ); bMember->WriteData( member_data ); bMember->SetSize( sizeof(member_data) ); AddMember( bMember ); return true; } int CBlock::Write( CBlockMember *bMember ) { // 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() ) { return NULL; } return m_members[ memberNum ]; } /* ------------------------- GetMemberData ------------------------- */ void *CBlock::GetMemberData( int memberNum ) { if ( memberNum >= GetNumMembers() ) { return NULL; } return (void *) ((GetMember( memberNum ))->GetData()); } /* ------------------------- Duplicate ------------------------- */ CBlock *CBlock::Duplicate( void ) { blockMember_v::iterator mi; CBlock *newblock; newblock = new CBlock; if ( newblock == NULL ) return NULL; 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() ); } return newblock; } /* =================================================================================================== CBlockStream =================================================================================================== */ CBlockStream::CBlockStream( void ) { m_stream = NULL; m_streamPos = 0; } CBlockStream::~CBlockStream( void ) { } /* ------------------------- GetChar ------------------------- */ char CBlockStream::GetChar( void ) { char data; data = *(char*) (m_stream + m_streamPos); m_streamPos += sizeof( data ); return data; } /* ------------------------- GetUnsignedInteger ------------------------- */ unsigned CBlockStream::GetUnsignedInteger( void ) { unsigned data; data = *(unsigned *) (m_stream + m_streamPos); m_streamPos += sizeof( data ); return data; } /* ------------------------- GetInteger ------------------------- */ int CBlockStream::GetInteger( void ) { int data; data = *(int *) (m_stream + m_streamPos); m_streamPos += sizeof( data ); return data; } /* ------------------------- GetLong ------------------------- */ long CBlockStream::GetLong( void ) { long data; data = *(int *) (m_stream + m_streamPos); m_streamPos += sizeof( data ); return data; } /* ------------------------- GetFloat ------------------------- */ float CBlockStream::GetFloat( void ) { float data; data = *(float *) (m_stream + m_streamPos); m_streamPos += sizeof( data ); return data; } /* ------------------------- 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 ) { char *id_header = IBI_HEADER_ID; float version = IBI_VERSION; //Strip the extension and add the BLOCK_EXT extension COM_StripExtension( filename, m_fileName, sizeof(m_fileName) ); COM_DefaultExtension( m_fileName, sizeof(m_fileName), IBI_EXT ); if ( (m_fileHandle = fopen(m_fileName, "wb")) == NULL ) { return false; } fwrite( id_header, IBI_HEADER_ID_LENGTH, 1, m_fileHandle ); fwrite( &version, sizeof(version), 1, 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 ) { 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(); return true; } /* ------------------------- BlockAvailable ------------------------- */ int CBlockStream::BlockAvailable( void ) { if ( m_streamPos >= m_fileSize ) return false; return true; } /* ------------------------- ReadBlock ------------------------- */ int CBlockStream::ReadBlock( CBlock *get ) { CBlockMember *bMember; int b_id, numMembers; unsigned char flags; if (!BlockAvailable()) return false; b_id = LittleLong(GetInteger()); numMembers = LittleLong(GetInteger()); flags = (unsigned char) GetChar(); if (numMembers < 0) return false; get->Create( b_id ); get->SetFlags( flags ); while ( numMembers-- > 0) { bMember = new CBlockMember; bMember->ReadMember( &m_stream, &m_streamPos ); get->AddMember( bMember ); } return true; } /* ------------------------- Open ------------------------- */ int CBlockStream::Open( char *buffer, long size ) { char id_header[IBI_HEADER_ID_LENGTH]; float version; Init(); m_fileSize = size; m_stream = buffer; for ( size_t i = 0; i < sizeof( id_header ); i++ ) { id_header[i] = GetChar(); } version = GetFloat(); version = LittleFloat(version); //Check for valid header if ( strcmp( id_header, IBI_HEADER_ID ) ) { Free(); return false; } //Check for valid version if ( version != IBI_VERSION ) { Free(); return false; } return true; }