2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 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.
14 Doom 3 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.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 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 Source Code. If not, please request a copy in writing from id Software at the address below.
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.
26 ===========================================================================
29 #include "../idlib/precompiled.h"
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" );
36 #define DEMO_MAGIC GAME_NAME " RDEMO"
40 idDemoFile::idDemoFile
43 idDemoFile::idDemoFile() {
54 idDemoFile::~idDemoFile
57 idDemoFile::~idDemoFile() {
63 idDemoFile::AllocCompressor
66 idCompressor *idDemoFile::AllocCompressor( int type ) {
68 case 0: return idCompressor::AllocNoCompression();
70 case 1: return idCompressor::AllocLZW();
71 case 2: return idCompressor::AllocLZSS();
72 case 3: return idCompressor::AllocHuffman();
78 idDemoFile::OpenForReading
81 bool idDemoFile::OpenForReading( const char *fileName ) {
82 static const int magicLen = sizeof(DEMO_MAGIC) / sizeof(DEMO_MAGIC[0]);
83 char magicBuffer[magicLen];
89 f = fileSystem->OpenFileRead( fileName );
94 fileLength = f->Length();
96 if ( com_preloadDemos.GetBool() ) {
97 fileImage = (byte *)Mem_Alloc( fileLength );
98 f->Read( fileImage, fileLength );
99 fileSystem->CloseFile( f );
100 f = new idFile_Memory( va( "preloaded(%s)", fileName ), (const char *)fileImage, fileLength );
103 if ( com_logDemos.GetBool() ) {
104 fLog = fileSystem->OpenFileWrite( "demoread.log" );
109 f->Read(magicBuffer, magicLen);
110 if ( memcmp(magicBuffer, DEMO_MAGIC, magicLen) == 0 ) {
111 f->ReadInt( compression );
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
119 compressor = AllocCompressor( compression );
120 compressor->Init( f, false, 8 );
130 void idDemoFile::SetLog(bool b, const char *p) {
142 void idDemoFile::Log(const char *p) {
143 if ( fLog && p && *p ) {
144 fLog->Write( p, strlen(p) );
150 idDemoFile::OpenForWriting
153 bool idDemoFile::OpenForWriting( const char *fileName ) {
156 f = fileSystem->OpenFileWrite( fileName );
161 if ( com_logDemos.GetBool() ) {
162 fLog = fileSystem->OpenFileWrite( "demowrite.log" );
167 f->Write(DEMO_MAGIC, sizeof(DEMO_MAGIC));
168 f->WriteInt( com_compressDemos.GetInteger() );
171 compressor = AllocCompressor( com_compressDemos.GetInteger() );
172 compressor->Init( f, true, 8 );
182 void idDemoFile::Close() {
183 if ( writing && compressor ) {
184 compressor->FinishCompress();
188 fileSystem->CloseFile( f );
192 fileSystem->CloseFile( fLog );
196 Mem_Free( fileImage );
204 demoStrings.DeleteContents( true );
209 idDemoFile::ReadHashString
212 const char *idDemoFile::ReadHashString() {
216 const char *text = va( "%s > Reading hash string\n", logStr.c_str() );
217 fLog->Write( text, strlen( text ) );
223 // read a new string for the table
224 idStr *str = new idStr;
230 demoStrings.Append( str );
235 if ( index < -1 || index >= demoStrings.Num() ) {
237 common->Error( "demo hash index out of range" );
240 return demoStrings[index]->c_str();
245 idDemoFile::WriteHashString
248 void idDemoFile::WriteHashString( const char *str ) {
250 const char *text = va( "%s > Writing hash string\n", logStr.c_str() );
251 fLog->Write( text, strlen( text ) );
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 ) ) {
261 // add it to our table and the demo table
262 idStr *copy = new idStr( str );
263 //common->Printf( "hash:%i = %s\n", demoStrings.Num(), str );
264 demoStrings.Append( copy );
275 void idDemoFile::ReadDict( idDict &dict ) {
281 for ( i = 0; i < c; i++ ) {
282 key = ReadHashString();
283 val = ReadHashString();
284 dict.Set( key, val );
290 idDemoFile::WriteDict
293 void idDemoFile::WriteDict( const idDict &dict ) {
296 c = dict.GetNumKeyVals();
298 for ( i = 0; i < c; i++ ) {
299 WriteHashString( dict.GetKeyVal( i )->GetKey() );
300 WriteHashString( dict.GetKeyVal( i )->GetValue() );
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;
322 int idDemoFile::Write( const void *buffer, int len ) {
323 return compressor->Write( buffer, len );