]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/framework/DemoFile.cpp
hello world
[icculus/iodoom3.git] / neo / framework / DemoFile.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
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.
13
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.
18
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/>.
21
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.
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 );
98                 f->Read( fileImage, fileLength );
99                 fileSystem->CloseFile( f );
100                 f = new 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 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 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