DemoFile.cpp 7.6 KB

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