DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

DemoFile.cpp (7829B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #include "../idlib/precompiled.h"
     30 #pragma hdrstop
     31 
     32 idCVar idDemoFile::com_logDemos( "com_logDemos", "0", CVAR_SYSTEM | CVAR_BOOL, "Write demo.log with debug information in it" );
     33 idCVar idDemoFile::com_compressDemos( "com_compressDemos", "1", CVAR_SYSTEM | CVAR_INTEGER | CVAR_ARCHIVE, "Compression scheme for demo files\n0: None    (Fast, large files)\n1: LZW     (Fast to compress, Fast to decompress, medium/small files)\n2: LZSS    (Slow to compress, Fast to decompress, small files)\n3: Huffman (Fast to compress, Slow to decompress, medium files)\nSee also: The 'CompressDemo' command" );
     34 idCVar idDemoFile::com_preloadDemos( "com_preloadDemos", "0", CVAR_SYSTEM | CVAR_BOOL | CVAR_ARCHIVE, "Load the whole demo in to RAM before running it" );
     35 
     36 #define DEMO_MAGIC GAME_NAME " RDEMO"
     37 
     38 /*
     39 ================
     40 idDemoFile::idDemoFile
     41 ================
     42 */
     43 idDemoFile::idDemoFile() {
     44 	f = NULL;
     45 	fLog = NULL;
     46 	log = false;
     47 	fileImage = NULL;
     48 	compressor = NULL;
     49 	writing = false;
     50 }
     51 
     52 /*
     53 ================
     54 idDemoFile::~idDemoFile
     55 ================
     56 */
     57 idDemoFile::~idDemoFile() {
     58 	Close();
     59 }
     60 
     61 /*
     62 ================
     63 idDemoFile::AllocCompressor
     64 ================
     65 */
     66 idCompressor *idDemoFile::AllocCompressor( int type ) {
     67 	switch ( type ) {
     68 	case 0: return idCompressor::AllocNoCompression();
     69 	default:
     70 	case 1: return idCompressor::AllocLZW();
     71 	case 2: return idCompressor::AllocLZSS();
     72 	case 3: return idCompressor::AllocHuffman();
     73 	}
     74 }
     75 
     76 /*
     77 ================
     78 idDemoFile::OpenForReading
     79 ================
     80 */
     81 bool idDemoFile::OpenForReading( const char *fileName ) {
     82 	static const int magicLen = sizeof(DEMO_MAGIC) / sizeof(DEMO_MAGIC[0]);
     83 	char magicBuffer[magicLen];
     84 	int compression;
     85 	int fileLength;
     86 
     87 	Close();
     88 
     89 	f = fileSystem->OpenFileRead( fileName );
     90 	if ( !f ) {
     91 		return false;
     92 	}
     93 
     94 	fileLength = f->Length();
     95 
     96 	if ( com_preloadDemos.GetBool() ) {
     97 		fileImage = (byte *)Mem_Alloc( fileLength, TAG_CRAP );
     98 		f->Read( fileImage, fileLength );
     99 		fileSystem->CloseFile( f );
    100 		f = new (TAG_SYSTEM) idFile_Memory( va( "preloaded(%s)", fileName ), (const char *)fileImage, fileLength );
    101 	}
    102 
    103 	if ( com_logDemos.GetBool() ) {
    104 		fLog = fileSystem->OpenFileWrite( "demoread.log" );
    105 	}
    106 
    107 	writing = false;
    108 
    109 	f->Read(magicBuffer, magicLen);
    110 	if ( memcmp(magicBuffer, DEMO_MAGIC, magicLen) == 0 ) {
    111 		f->ReadInt( compression );
    112 	} else {
    113 		// Ideally we would error out if the magic string isn't there,
    114 		// but for backwards compatibility we are going to assume it's just an uncompressed demo file
    115 		compression = 0;
    116 		f->Rewind();
    117 	}
    118 
    119 	compressor = AllocCompressor( compression );
    120 	compressor->Init( f, false, 8 );
    121 
    122 	return true;
    123 }
    124 
    125 /*
    126 ================
    127 idDemoFile::SetLog
    128 ================
    129 */
    130 void idDemoFile::SetLog(bool b, const char *p) {
    131 	log = b;
    132 	if (p) {
    133 		logStr = p;
    134 	}
    135 }
    136 
    137 /*
    138 ================
    139 idDemoFile::Log
    140 ================
    141 */
    142 void idDemoFile::Log(const char *p) {
    143 	if ( fLog && p && *p ) {
    144 		fLog->Write( p, strlen(p) );
    145 	}
    146 }
    147 
    148 /*
    149 ================
    150 idDemoFile::OpenForWriting
    151 ================
    152 */
    153 bool idDemoFile::OpenForWriting( const char *fileName ) {
    154 	Close();
    155 
    156 	f = fileSystem->OpenFileWrite( fileName );
    157 	if ( f == NULL ) {
    158 		return false;
    159 	}
    160 
    161 	if ( com_logDemos.GetBool() ) {
    162 		fLog = fileSystem->OpenFileWrite( "demowrite.log" );
    163 	}
    164 
    165 	writing = true;
    166 
    167 	f->Write(DEMO_MAGIC, sizeof(DEMO_MAGIC));
    168 	f->WriteInt( com_compressDemos.GetInteger() );
    169 	f->Flush();
    170 
    171 	compressor = AllocCompressor( com_compressDemos.GetInteger() );
    172 	compressor->Init( f, true, 8 );
    173 
    174 	return true;
    175 }
    176 
    177 /*
    178 ================
    179 idDemoFile::Close
    180 ================
    181 */
    182 void idDemoFile::Close() {
    183 	if ( writing && compressor ) {
    184 		compressor->FinishCompress();
    185 	}
    186 
    187 	if ( f ) {
    188 		fileSystem->CloseFile( f );
    189 		f = NULL;
    190 	}
    191 	if ( fLog ) {
    192 		fileSystem->CloseFile( fLog );
    193 		fLog = NULL;
    194 	}
    195 	if ( fileImage ) {
    196 		Mem_Free( fileImage );
    197 		fileImage = NULL;
    198 	}
    199 	if ( compressor ) {
    200 		delete compressor;
    201 		compressor = NULL;
    202 	}
    203 
    204 	demoStrings.DeleteContents( true );
    205 }
    206 
    207 /*
    208 ================
    209 idDemoFile::ReadHashString
    210 ================
    211 */
    212 const char *idDemoFile::ReadHashString() {
    213 	int		index;
    214 
    215 	if ( log && fLog ) {
    216 		const char *text = va( "%s > Reading hash string\n", logStr.c_str() );
    217 		fLog->Write( text, strlen( text ) );
    218 	} 
    219 
    220 	ReadInt( index );
    221 
    222 	if ( index == -1 ) {
    223 		// read a new string for the table
    224 		idStr	*str = new (TAG_SYSTEM) idStr;
    225 		
    226 		idStr data;
    227 		ReadString( data );
    228 		*str = data;
    229 		
    230 		demoStrings.Append( str );
    231 
    232 		return *str;
    233 	}
    234 
    235 	if ( index < -1 || index >= demoStrings.Num() ) {
    236 		Close();
    237 		common->Error( "demo hash index out of range" );
    238 	}
    239 
    240 	return demoStrings[index]->c_str();
    241 }
    242 
    243 /*
    244 ================
    245 idDemoFile::WriteHashString
    246 ================
    247 */
    248 void idDemoFile::WriteHashString( const char *str ) {
    249 	if ( log && fLog ) {
    250 		const char *text = va( "%s > Writing hash string\n", logStr.c_str() );
    251 		fLog->Write( text, strlen( text ) );
    252 	}
    253 	// see if it is already in the has table
    254 	for ( int i = 0 ; i < demoStrings.Num() ; i++ ) {
    255 		if ( !strcmp( demoStrings[i]->c_str(), str ) ) {
    256 			WriteInt( i );
    257 			return;
    258 		}
    259 	}
    260 
    261 	// add it to our table and the demo table
    262 	idStr	*copy = new (TAG_SYSTEM) idStr( str );
    263 //common->Printf( "hash:%i = %s\n", demoStrings.Num(), str );
    264 	demoStrings.Append( copy );
    265 	int cmd = -1;	
    266 	WriteInt( cmd );
    267 	WriteString( str );
    268 }
    269 
    270 /*
    271 ================
    272 idDemoFile::ReadDict
    273 ================
    274 */
    275 void idDemoFile::ReadDict( idDict &dict ) {
    276 	int i, c;
    277 	idStr key, val;
    278 
    279 	dict.Clear();
    280 	ReadInt( c );
    281 	for ( i = 0; i < c; i++ ) {
    282 		key = ReadHashString();
    283 		val = ReadHashString();
    284 		dict.Set( key, val );
    285 	}
    286 }
    287 
    288 /*
    289 ================
    290 idDemoFile::WriteDict
    291 ================
    292 */
    293 void idDemoFile::WriteDict( const idDict &dict ) {
    294 	int i, c;
    295 
    296 	c = dict.GetNumKeyVals();
    297 	WriteInt( c );
    298 	for ( i = 0; i < c; i++ ) {
    299 		WriteHashString( dict.GetKeyVal( i )->GetKey() );
    300 		WriteHashString( dict.GetKeyVal( i )->GetValue() );
    301 	}
    302 }
    303 
    304 /*
    305  ================
    306  idDemoFile::Read
    307  ================
    308  */
    309 int idDemoFile::Read( void *buffer, int len ) {
    310 	int read = compressor->Read( buffer, len );
    311 	if ( read == 0 && len >= 4 ) {
    312 		*(demoSystem_t *)buffer = DS_FINISHED;
    313 	}
    314 	return read;
    315 }
    316 
    317 /*
    318  ================
    319  idDemoFile::Write
    320  ================
    321  */
    322 int idDemoFile::Write( const void *buffer, int len ) {
    323 	return compressor->Write( buffer, len );
    324 }
    325 
    326 
    327 
    328