doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
DeclManager.cpp
Go to the documentation of this file.
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 /*
33 
34 GUIs and script remain separately parsed
35 
36 Following a parse, all referenced media (and other decls) will have been touched.
37 
38 sinTable and cosTable are required for the rotate material keyword to function
39 
40 A new FindType on a purged decl will cause it to be reloaded, but a stale pointer to a purged
41 decl will look like a defaulted decl.
42 
43 Moving a decl from one file to another will not be handled correctly by a reload, the material
44 will be defaulted.
45 
46 NULL or empty decl names will always return NULL
47  Should probably make a default decl for this
48 
49 Decls are initially created without a textSource
50 A parse without textSource set should always just call MakeDefault()
51 A parse that has an error should internally call MakeDefault()
52 A purge does nothing to a defaulted decl
53 
54 Should we have a "purged" media state separate from the "defaulted" media state?
55 
56 reloading over a decl name that was defaulted
57 
58 reloading over a decl name that was valid
59 
60 missing reload over a previously explicit definition
61 
62 */
63 
64 #define USE_COMPRESSED_DECLS
65 //#define GET_HUFFMAN_FREQUENCIES
66 
67 class idDeclType {
68 public:
71  idDecl * (*allocator)( void );
72 };
73 
74 class idDeclFolder {
75 public:
79 };
80 
81 class idDeclFile;
82 
83 class idDeclLocal : public idDeclBase {
84  friend class idDeclFile;
85  friend class idDeclManagerLocal;
86 
87 public:
88  idDeclLocal();
89  virtual ~idDeclLocal() {};
90  virtual const char * GetName( void ) const;
91  virtual declType_t GetType( void ) const;
92  virtual declState_t GetState( void ) const;
93  virtual bool IsImplicit( void ) const;
94  virtual bool IsValid( void ) const;
95  virtual void Invalidate( void );
96  virtual void Reload( void );
97  virtual void EnsureNotPurged( void );
98  virtual int Index( void ) const;
99  virtual int GetLineNum( void ) const;
100  virtual const char * GetFileName( void ) const;
101  virtual size_t Size( void ) const;
102  virtual void GetText( char *text ) const;
103  virtual int GetTextLength( void ) const;
104  virtual void SetText( const char *text );
105  virtual bool ReplaceSourceFileText( void );
106  virtual bool SourceFileChanged( void ) const;
107  virtual void MakeDefault( void );
108  virtual bool EverReferenced( void ) const;
109 
110 protected:
111  virtual bool SetDefaultText( void );
112  virtual const char * DefaultDefinition( void ) const;
113  virtual bool Parse( const char *text, const int textLength );
114  virtual void FreeData( void );
115  virtual void List( void ) const;
116  virtual void Print( void ) const;
117 
118 protected:
119  void AllocateSelf( void );
120 
121  // Parses the decl definition.
122  // After calling parse, a decl will be guaranteed usable.
123  void ParseLocal( void );
124 
125  // Does a MakeDefualt, but flags the decl so that it
126  // will Parse() the next time the decl is found.
127  void Purge( void );
128 
129  // Set textSource possible with compression.
130  void SetTextLocal( const char *text, const int length );
131 
132 private:
133  idDecl * self;
134 
135  idStr name; // name of the decl
136  char * textSource; // decl text definition
137  int textLength; // length of textSource
138  int compressedLength; // compressed length
139  idDeclFile * sourceFile; // source file in which the decl was defined
140  int sourceTextOffset; // offset in source file to decl text
141  int sourceTextLength; // length of decl text in source file
142  int sourceLine; // this is where the actual declaration token starts
143  int checksum; // checksum of the decl text
144  declType_t type; // decl type
145  declState_t declState; // decl state
146  int index; // index in the per-type list
147 
148  bool parsedOutsideLevelLoad; // these decls will never be purged
149  bool everReferenced; // set to true if the decl was ever used
150  bool referencedThisLevel; // set to true when the decl is used for the current level
151  bool redefinedInReload; // used during file reloading to make sure a decl that has
152  // its source removed will be defaulted
153  idDeclLocal * nextInFile; // next decl in the decl file
154 };
155 
156 class idDeclFile {
157 public:
158  idDeclFile();
159  idDeclFile( const char *fileName, declType_t defaultType );
160 
161  void Reload( bool force );
162  int LoadAndParse();
163 
164 public:
167 
168  ID_TIME_T timestamp;
169  int checksum;
170  int fileSize;
171  int numLines;
172 
174 };
175 
177  friend class idDeclLocal;
178 
179 public:
180  virtual void Init( void );
181  virtual void Shutdown( void );
182  virtual void Reload( bool force );
183  virtual void BeginLevelLoad();
184  virtual void EndLevelLoad();
185  virtual void RegisterDeclType( const char *typeName, declType_t type, idDecl *(*allocator)( void ) );
186  virtual void RegisterDeclFolder( const char *folder, const char *extension, declType_t defaultType );
187  virtual int GetChecksum( void ) const;
188  virtual int GetNumDeclTypes( void ) const;
189  virtual int GetNumDecls( declType_t type );
190  virtual const char * GetDeclNameFromType( declType_t type ) const;
191  virtual declType_t GetDeclTypeFromName( const char *typeName ) const;
192  virtual const idDecl * FindType( declType_t type, const char *name, bool makeDefault = true );
193  virtual const idDecl * DeclByIndex( declType_t type, int index, bool forceParse = true );
194 
195  virtual const idDecl* FindDeclWithoutParsing( declType_t type, const char *name, bool makeDefault = true );
196  virtual void ReloadFile( const char* filename, bool force );
197 
198  virtual void ListType( const idCmdArgs &args, declType_t type );
199  virtual void PrintType( const idCmdArgs &args, declType_t type );
200 
201  virtual idDecl * CreateNewDecl( declType_t type, const char *name, const char *fileName );
202 
203  //BSM Added for the material editors rename capabilities
204  virtual bool RenameDecl( declType_t type, const char* oldName, const char* newName );
205 
206  virtual void MediaPrint( const char *fmt, ... ) id_attribute((format(printf,2,3)));
207  virtual void WritePrecacheCommands( idFile *f );
208 
209  virtual const idMaterial * FindMaterial( const char *name, bool makeDefault = true );
210  virtual const idDeclSkin * FindSkin( const char *name, bool makeDefault = true );
211  virtual const idSoundShader * FindSound( const char *name, bool makeDefault = true );
212 
213  virtual const idMaterial * MaterialByIndex( int index, bool forceParse = true );
214  virtual const idDeclSkin * SkinByIndex( int index, bool forceParse = true );
215  virtual const idSoundShader * SoundByIndex( int index, bool forceParse = true );
216 
217 public:
218  static void MakeNameCanonical( const char *name, char *result, int maxLength );
219  idDeclLocal * FindTypeWithoutParsing( declType_t type, const char *name, bool makeDefault = true );
220 
221  idDeclType * GetDeclType( int type ) const { return declTypes[type]; }
222  const idDeclFile * GetImplicitDeclFile( void ) const { return &implicitDecls; }
223 
224 private:
227 
231  idDeclFile implicitDecls; // this holds all the decls that were created because explicit
232  // text definitions were not found. Decls that became default
233  // because of a parse error are not in this list.
234  int checksum; // checksum of all loaded decl text
235  int indent; // for MediaPrint
237 
239 
240 private:
241  static void ListDecls_f( const idCmdArgs &args );
242  static void ReloadDecls_f( const idCmdArgs &args );
243  static void TouchDecl_f( const idCmdArgs &args );
244 };
245 
246 idCVar idDeclManagerLocal::decl_show( "decl_show", "0", CVAR_SYSTEM, "set to 1 to print parses, 2 to also print references", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
247 
250 
251 /*
252 ====================================================================================
253 
254  decl text huffman compression
255 
256 ====================================================================================
257 */
258 
259 const int MAX_HUFFMAN_SYMBOLS = 256;
260 
261 typedef struct huffmanNode_s {
262  int symbol;
264  struct huffmanNode_s * next;
265  struct huffmanNode_s * children[2];
266 } huffmanNode_t;
267 
268 typedef struct huffmanCode_s {
269  unsigned long bits[8];
270  int numBits;
271 } huffmanCode_t;
272 
273 // compression ratio = 64%
274 static int huffmanFrequencies[] = {
275  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
276  0x00000001, 0x00078fb6, 0x000352a7, 0x00000002, 0x00000001, 0x0002795e, 0x00000001, 0x00000001,
277  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
278  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
279  0x00049600, 0x000000dd, 0x00018732, 0x0000005a, 0x00000007, 0x00000092, 0x0000000a, 0x00000919,
280  0x00002dcf, 0x00002dda, 0x00004dfc, 0x0000039a, 0x000058be, 0x00002d13, 0x00014d8c, 0x00023c60,
281  0x0002ddb0, 0x0000d1fc, 0x000078c4, 0x00003ec7, 0x00003113, 0x00006b59, 0x00002499, 0x0000184a,
282  0x0000250b, 0x00004e38, 0x000001ca, 0x00000011, 0x00000020, 0x000023da, 0x00000012, 0x00000091,
283  0x0000000b, 0x00000b14, 0x0000035d, 0x0000137e, 0x000020c9, 0x00000e11, 0x000004b4, 0x00000737,
284  0x000006b8, 0x00001110, 0x000006b3, 0x000000fe, 0x00000f02, 0x00000d73, 0x000005f6, 0x00000be4,
285  0x00000d86, 0x0000014d, 0x00000d89, 0x0000129b, 0x00000db3, 0x0000015a, 0x00000167, 0x00000375,
286  0x00000028, 0x00000112, 0x00000018, 0x00000678, 0x0000081a, 0x00000677, 0x00000003, 0x00018112,
287  0x00000001, 0x000441ee, 0x000124b0, 0x0001fa3f, 0x00026125, 0x0005a411, 0x0000e50f, 0x00011820,
288  0x00010f13, 0x0002e723, 0x00003518, 0x00005738, 0x0002cc26, 0x0002a9b7, 0x0002db81, 0x0003b5fa,
289  0x000185d2, 0x00001299, 0x00030773, 0x0003920d, 0x000411cd, 0x00018751, 0x00005fbd, 0x000099b0,
290  0x00009242, 0x00007cf2, 0x00002809, 0x00005a1d, 0x00000001, 0x00005a1d, 0x00000001, 0x00000001,
291 
292  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
293  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
294  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
295  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
296  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
297  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
298  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
299  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
300  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
301  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
302  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
303  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
304  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
305  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
306  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
307  0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
308 };
309 
310 static huffmanCode_t huffmanCodes[MAX_HUFFMAN_SYMBOLS];
311 static huffmanNode_t *huffmanTree = NULL;
312 static int totalUncompressedLength = 0;
313 static int totalCompressedLength = 0;
314 static int maxHuffmanBits = 0;
315 
316 
317 /*
318 ================
319 ClearHuffmanFrequencies
320 ================
321 */
323  int i;
324 
325  for( i = 0; i < MAX_HUFFMAN_SYMBOLS; i++ ) {
326  huffmanFrequencies[i] = 1;
327  }
328 }
329 
330 /*
331 ================
332 InsertHuffmanNode
333 ================
334 */
336  huffmanNode_t *n, *lastNode;
337 
338  lastNode = NULL;
339  for ( n = firstNode; n; n = n->next ) {
340  if ( node->frequency <= n->frequency ) {
341  break;
342  }
343  lastNode = n;
344  }
345  if ( lastNode ) {
346  node->next = lastNode->next;
347  lastNode->next = node;
348  } else {
349  node->next = firstNode;
350  firstNode = node;
351  }
352  return firstNode;
353 }
354 
355 /*
356 ================
357 BuildHuffmanCode_r
358 ================
359 */
360 void BuildHuffmanCode_r( huffmanNode_t *node, huffmanCode_t code, huffmanCode_t codes[MAX_HUFFMAN_SYMBOLS] ) {
361  if ( node->symbol == -1 ) {
362  huffmanCode_t newCode = code;
363  assert( code.numBits < sizeof( codes[0].bits ) * 8 );
364  newCode.numBits++;
365  if ( code.numBits > maxHuffmanBits ) {
366  maxHuffmanBits = newCode.numBits;
367  }
368  BuildHuffmanCode_r( node->children[0], newCode, codes );
369  newCode.bits[code.numBits >> 5] |= 1 << ( code.numBits & 31 );
370  BuildHuffmanCode_r( node->children[1], newCode, codes );
371  } else {
372  assert( code.numBits <= sizeof( codes[0].bits ) * 8 );
373  codes[node->symbol] = code;
374  }
375 }
376 
377 /*
378 ================
379 FreeHuffmanTree_r
380 ================
381 */
383  if ( node->symbol == -1 ) {
384  FreeHuffmanTree_r( node->children[0] );
385  FreeHuffmanTree_r( node->children[1] );
386  }
387  delete node;
388 }
389 
390 /*
391 ================
392 HuffmanHeight_r
393 ================
394 */
396  if ( node == NULL ) {
397  return -1;
398  }
399  int left = HuffmanHeight_r( node->children[0] );
400  int right = HuffmanHeight_r( node->children[1] );
401  if ( left > right ) {
402  return left + 1;
403  }
404  return right + 1;
405 }
406 
407 /*
408 ================
409 SetupHuffman
410 ================
411 */
412 void SetupHuffman( void ) {
413  int i, height;
414  huffmanNode_t *firstNode, *node;
415  huffmanCode_t code;
416 
417  firstNode = NULL;
418  for( i = 0; i < MAX_HUFFMAN_SYMBOLS; i++ ) {
419  node = new huffmanNode_t;
420  node->symbol = i;
421  node->frequency = huffmanFrequencies[i];
422  node->next = NULL;
423  node->children[0] = NULL;
424  node->children[1] = NULL;
425  firstNode = InsertHuffmanNode( firstNode, node );
426  }
427 
428  for( i = 1; i < MAX_HUFFMAN_SYMBOLS; i++ ) {
429  node = new huffmanNode_t;
430  node->symbol = -1;
431  node->frequency = firstNode->frequency + firstNode->next->frequency;
432  node->next = NULL;
433  node->children[0] = firstNode;
434  node->children[1] = firstNode->next;
435  firstNode = InsertHuffmanNode( firstNode->next->next, node );
436  }
437 
438  maxHuffmanBits = 0;
439  memset( &code, 0, sizeof( code ) );
440  BuildHuffmanCode_r( firstNode, code, huffmanCodes );
441 
442  huffmanTree = firstNode;
443 
444  height = HuffmanHeight_r( firstNode );
445  assert( maxHuffmanBits == height );
446 }
447 
448 /*
449 ================
450 ShutdownHuffman
451 ================
452 */
453 void ShutdownHuffman( void ) {
454  if ( huffmanTree ) {
455  FreeHuffmanTree_r( huffmanTree );
456  }
457 }
458 
459 /*
460 ================
461 HuffmanCompressText
462 ================
463 */
464 int HuffmanCompressText( const char *text, int textLength, byte *compressed, int maxCompressedSize ) {
465  int i, j;
466  idBitMsg msg;
467 
468  totalUncompressedLength += textLength;
469 
470  msg.Init( compressed, maxCompressedSize );
471  msg.BeginWriting();
472  for ( i = 0; i < textLength; i++ ) {
473  const huffmanCode_t &code = huffmanCodes[(unsigned char)text[i]];
474  for ( j = 0; j < ( code.numBits >> 5 ); j++ ) {
475  msg.WriteBits( code.bits[j], 32 );
476  }
477  if ( code.numBits & 31 ) {
478  msg.WriteBits( code.bits[j], code.numBits & 31 );
479  }
480  }
481 
482  totalCompressedLength += msg.GetSize();
483 
484  return msg.GetSize();
485 }
486 
487 /*
488 ================
489 HuffmanDecompressText
490 ================
491 */
492 int HuffmanDecompressText( char *text, int textLength, const byte *compressed, int compressedSize ) {
493  int i, bit;
494  idBitMsg msg;
495  huffmanNode_t *node;
496 
497  msg.Init( compressed, compressedSize );
498  msg.SetSize( compressedSize );
499  msg.BeginReading();
500  for ( i = 0; i < textLength; i++ ) {
501  node = huffmanTree;
502  do {
503  bit = msg.ReadBits( 1 );
504  node = node->children[bit];
505  } while( node->symbol == -1 );
506  text[i] = node->symbol;
507  }
508  text[i] = '\0';
509  return msg.GetReadCount();
510 }
511 
512 /*
513 ================
514 ListHuffmanFrequencies_f
515 ================
516 */
517 void ListHuffmanFrequencies_f( const idCmdArgs &args ) {
518  int i;
519  float compression;
520  compression = !totalUncompressedLength ? 100 : 100 * totalCompressedLength / totalUncompressedLength;
521  common->Printf( "// compression ratio = %d%%\n", (int)compression );
522  common->Printf( "static int huffmanFrequencies[] = {\n" );
523  for( i = 0; i < MAX_HUFFMAN_SYMBOLS; i += 8 ) {
524  common->Printf( "\t0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x,\n",
525  huffmanFrequencies[i+0], huffmanFrequencies[i+1],
526  huffmanFrequencies[i+2], huffmanFrequencies[i+3],
527  huffmanFrequencies[i+4], huffmanFrequencies[i+5],
528  huffmanFrequencies[i+6], huffmanFrequencies[i+7]);
529  }
530  common->Printf( "}\n" );
531 }
532 
533 /*
534 ====================================================================================
535 
536  idDeclFile
537 
538 ====================================================================================
539 */
540 
541 /*
542 ================
543 idDeclFile::idDeclFile
544 ================
545 */
546 idDeclFile::idDeclFile( const char *fileName, declType_t defaultType ) {
547  this->fileName = fileName;
548  this->defaultType = defaultType;
549  this->timestamp = 0;
550  this->checksum = 0;
551  this->fileSize = 0;
552  this->numLines = 0;
553  this->decls = NULL;
554 }
555 
556 /*
557 ================
558 idDeclFile::idDeclFile
559 ================
560 */
562  this->fileName = "<implicit file>";
563  this->defaultType = DECL_MAX_TYPES;
564  this->timestamp = 0;
565  this->checksum = 0;
566  this->fileSize = 0;
567  this->numLines = 0;
568  this->decls = NULL;
569 }
570 
571 /*
572 ================
573 idDeclFile::Reload
574 
575 ForceReload will cause it to reload even if the timestamp hasn't changed
576 ================
577 */
578 void idDeclFile::Reload( bool force ) {
579  // check for an unchanged timestamp
580  if ( !force && timestamp != 0 ) {
581  ID_TIME_T testTimeStamp;
582  fileSystem->ReadFile( fileName, NULL, &testTimeStamp );
583 
584  if ( testTimeStamp == timestamp ) {
585  return;
586  }
587  }
588 
589  // parse the text
590  LoadAndParse();
591 }
592 
593 /*
594 ================
595 idDeclFile::LoadAndParse
596 
597 This is used during both the initial load, and any reloads
598 ================
599 */
601 
603  int i, numTypes;
604  idLexer src;
605  idToken token;
606  int startMarker;
607  char * buffer;
608  int length, size;
609  int sourceLine;
610  idStr name;
611  idDeclLocal *newDecl;
612  bool reparse;
613 
614  // load the text
615  common->DPrintf( "...loading '%s'\n", fileName.c_str() );
616  length = fileSystem->ReadFile( fileName, (void **)&buffer, &timestamp );
617  if ( length == -1 ) {
618  common->FatalError( "couldn't load %s", fileName.c_str() );
619  return 0;
620  }
621 
622  if ( !src.LoadMemory( buffer, length, fileName ) ) {
623  common->Error( "Couldn't parse %s", fileName.c_str() );
624  Mem_Free( buffer );
625  return 0;
626  }
627 
628  // mark all the defs that were from the last reload of this file
629  for ( idDeclLocal *decl = decls; decl; decl = decl->nextInFile ) {
630  decl->redefinedInReload = false;
631  }
632 
633  src.SetFlags( DECL_LEXER_FLAGS );
634 
635  checksum = MD5_BlockChecksum( buffer, length );
636 
637  fileSize = length;
638 
639  // scan through, identifying each individual declaration
640  while( 1 ) {
641 
642  startMarker = src.GetFileOffset();
643  sourceLine = src.GetLineNum();
644 
645  // parse the decl type name
646  if ( !src.ReadToken( &token ) ) {
647  break;
648  }
649 
650  declType_t identifiedType = DECL_MAX_TYPES;
651 
652  // get the decl type from the type name
653  numTypes = declManagerLocal.GetNumDeclTypes();
654  for ( i = 0; i < numTypes; i++ ) {
655  idDeclType *typeInfo = declManagerLocal.GetDeclType( i );
656  if ( typeInfo && typeInfo->typeName.Icmp( token ) == 0 ) {
657  identifiedType = (declType_t) typeInfo->type;
658  break;
659  }
660  }
661 
662  if ( i >= numTypes ) {
663 
664  if ( token.Icmp( "{" ) == 0 ) {
665 
666  // if we ever see an open brace, we somehow missed the [type] <name> prefix
667  src.Warning( "Missing decl name" );
668  src.SkipBracedSection( false );
669  continue;
670 
671  } else {
672 
673  if ( defaultType == DECL_MAX_TYPES ) {
674  src.Warning( "No type" );
675  continue;
676  }
677  src.UnreadToken( &token );
678  // use the default type
679  identifiedType = defaultType;
680  }
681  }
682 
683  // now parse the name
684  if ( !src.ReadToken( &token ) ) {
685  src.Warning( "Type without definition at end of file" );
686  break;
687  }
688 
689  if ( !token.Icmp( "{" ) ) {
690  // if we ever see an open brace, we somehow missed the [type] <name> prefix
691  src.Warning( "Missing decl name" );
692  src.SkipBracedSection( false );
693  continue;
694  }
695 
696  // FIXME: export decls are only used by the model exporter, they are skipped here for now
697  if ( identifiedType == DECL_MODELEXPORT ) {
698  src.SkipBracedSection();
699  continue;
700  }
701 
702  name = token;
703 
704  // make sure there's a '{'
705  if ( !src.ReadToken( &token ) ) {
706  src.Warning( "Type without definition at end of file" );
707  break;
708  }
709  if ( token != "{" ) {
710  src.Warning( "Expecting '{' but found '%s'", token.c_str() );
711  continue;
712  }
713  src.UnreadToken( &token );
714 
715  // now take everything until a matched closing brace
716  src.SkipBracedSection();
717  size = src.GetFileOffset() - startMarker;
718 
719  // look it up, possibly getting a newly created default decl
720  reparse = false;
721  newDecl = declManagerLocal.FindTypeWithoutParsing( identifiedType, name, false );
722  if ( newDecl ) {
723  // update the existing copy
724  if ( newDecl->sourceFile != this || newDecl->redefinedInReload ) {
725  src.Warning( "%s '%s' previously defined at %s:%i", declManagerLocal.GetDeclNameFromType( identifiedType ),
726  name.c_str(), newDecl->sourceFile->fileName.c_str(), newDecl->sourceLine );
727  continue;
728  }
729  if ( newDecl->declState != DS_UNPARSED ) {
730  reparse = true;
731  }
732  } else {
733  // allow it to be created as a default, then add it to the per-file list
734  newDecl = declManagerLocal.FindTypeWithoutParsing( identifiedType, name, true );
735  newDecl->nextInFile = this->decls;
736  this->decls = newDecl;
737  }
738 
739  newDecl->redefinedInReload = true;
740 
741  if ( newDecl->textSource ) {
742  Mem_Free( newDecl->textSource );
743  newDecl->textSource = NULL;
744  }
745 
746  newDecl->SetTextLocal( buffer + startMarker, size );
747  newDecl->sourceFile = this;
748  newDecl->sourceTextOffset = startMarker;
749  newDecl->sourceTextLength = size;
750  newDecl->sourceLine = sourceLine;
751  newDecl->declState = DS_UNPARSED;
752 
753  // if it is currently in use, reparse it immedaitely
754  if ( reparse ) {
755  newDecl->ParseLocal();
756  }
757  }
758 
759  numLines = src.GetLineNum();
760 
761  Mem_Free( buffer );
762 
763  // any defs that weren't redefinedInReload should now be defaulted
764  for ( idDeclLocal *decl = decls ; decl ; decl = decl->nextInFile ) {
765  if ( decl->redefinedInReload == false ) {
766  decl->MakeDefault();
767  decl->sourceTextOffset = decl->sourceFile->fileSize;
768  decl->sourceTextLength = 0;
769  decl->sourceLine = decl->sourceFile->numLines;
770  }
771  }
772 
773  return checksum;
774 }
775 
776 /*
777 ====================================================================================
778 
779  idDeclManagerLocal
780 
781 ====================================================================================
782 */
783 
784 const char *listDeclStrings[] = { "current", "all", "ever", NULL };
785 
786 /*
787 ===================
788 idDeclManagerLocal::Init
789 ===================
790 */
792 
793  common->Printf( "----- Initializing Decls -----\n" );
794 
795  checksum = 0;
796 
797 #ifdef USE_COMPRESSED_DECLS
798  SetupHuffman();
799 #endif
800 
801 #ifdef GET_HUFFMAN_FREQUENCIES
803 #endif
804 
805  // decls used throughout the engine
806  RegisterDeclType( "table", DECL_TABLE, idDeclAllocator<idDeclTable> );
807  RegisterDeclType( "material", DECL_MATERIAL, idDeclAllocator<idMaterial> );
808  RegisterDeclType( "skin", DECL_SKIN, idDeclAllocator<idDeclSkin> );
809  RegisterDeclType( "sound", DECL_SOUND, idDeclAllocator<idSoundShader> );
810 
811  RegisterDeclType( "entityDef", DECL_ENTITYDEF, idDeclAllocator<idDeclEntityDef> );
812  RegisterDeclType( "mapDef", DECL_MAPDEF, idDeclAllocator<idDeclEntityDef> );
813  RegisterDeclType( "fx", DECL_FX, idDeclAllocator<idDeclFX> );
814  RegisterDeclType( "particle", DECL_PARTICLE, idDeclAllocator<idDeclParticle> );
815  RegisterDeclType( "articulatedFigure", DECL_AF, idDeclAllocator<idDeclAF> );
816  RegisterDeclType( "pda", DECL_PDA, idDeclAllocator<idDeclPDA> );
817  RegisterDeclType( "email", DECL_EMAIL, idDeclAllocator<idDeclEmail> );
818  RegisterDeclType( "video", DECL_VIDEO, idDeclAllocator<idDeclVideo> );
819  RegisterDeclType( "audio", DECL_AUDIO, idDeclAllocator<idDeclAudio> );
820 
821  RegisterDeclFolder( "materials", ".mtr", DECL_MATERIAL );
822  RegisterDeclFolder( "skins", ".skin", DECL_SKIN );
823  RegisterDeclFolder( "sound", ".sndshd", DECL_SOUND );
824 
825  // add console commands
826  cmdSystem->AddCommand( "listDecls", ListDecls_f, CMD_FL_SYSTEM, "lists all decls" );
827 
828  cmdSystem->AddCommand( "reloadDecls", ReloadDecls_f, CMD_FL_SYSTEM, "reloads decls" );
829  cmdSystem->AddCommand( "touch", TouchDecl_f, CMD_FL_SYSTEM, "touches a decl" );
830 
831  cmdSystem->AddCommand( "listTables", idListDecls_f<DECL_TABLE>, CMD_FL_SYSTEM, "lists tables", idCmdSystem::ArgCompletion_String<listDeclStrings> );
832  cmdSystem->AddCommand( "listMaterials", idListDecls_f<DECL_MATERIAL>, CMD_FL_SYSTEM, "lists materials", idCmdSystem::ArgCompletion_String<listDeclStrings> );
833  cmdSystem->AddCommand( "listSkins", idListDecls_f<DECL_SKIN>, CMD_FL_SYSTEM, "lists skins", idCmdSystem::ArgCompletion_String<listDeclStrings> );
834  cmdSystem->AddCommand( "listSoundShaders", idListDecls_f<DECL_SOUND>, CMD_FL_SYSTEM, "lists sound shaders", idCmdSystem::ArgCompletion_String<listDeclStrings> );
835 
836  cmdSystem->AddCommand( "listEntityDefs", idListDecls_f<DECL_ENTITYDEF>, CMD_FL_SYSTEM, "lists entity defs", idCmdSystem::ArgCompletion_String<listDeclStrings> );
837  cmdSystem->AddCommand( "listFX", idListDecls_f<DECL_FX>, CMD_FL_SYSTEM, "lists FX systems", idCmdSystem::ArgCompletion_String<listDeclStrings> );
838  cmdSystem->AddCommand( "listParticles", idListDecls_f<DECL_PARTICLE>, CMD_FL_SYSTEM, "lists particle systems", idCmdSystem::ArgCompletion_String<listDeclStrings> );
839  cmdSystem->AddCommand( "listAF", idListDecls_f<DECL_AF>, CMD_FL_SYSTEM, "lists articulated figures", idCmdSystem::ArgCompletion_String<listDeclStrings>);
840 
841  cmdSystem->AddCommand( "listPDAs", idListDecls_f<DECL_PDA>, CMD_FL_SYSTEM, "lists PDAs", idCmdSystem::ArgCompletion_String<listDeclStrings> );
842  cmdSystem->AddCommand( "listEmails", idListDecls_f<DECL_EMAIL>, CMD_FL_SYSTEM, "lists Emails", idCmdSystem::ArgCompletion_String<listDeclStrings> );
843  cmdSystem->AddCommand( "listVideos", idListDecls_f<DECL_VIDEO>, CMD_FL_SYSTEM, "lists Videos", idCmdSystem::ArgCompletion_String<listDeclStrings> );
844  cmdSystem->AddCommand( "listAudios", idListDecls_f<DECL_AUDIO>, CMD_FL_SYSTEM, "lists Audios", idCmdSystem::ArgCompletion_String<listDeclStrings> );
845 
846  cmdSystem->AddCommand( "printTable", idPrintDecls_f<DECL_TABLE>, CMD_FL_SYSTEM, "prints a table", idCmdSystem::ArgCompletion_Decl<DECL_TABLE> );
847  cmdSystem->AddCommand( "printMaterial", idPrintDecls_f<DECL_MATERIAL>, CMD_FL_SYSTEM, "prints a material", idCmdSystem::ArgCompletion_Decl<DECL_MATERIAL> );
848  cmdSystem->AddCommand( "printSkin", idPrintDecls_f<DECL_SKIN>, CMD_FL_SYSTEM, "prints a skin", idCmdSystem::ArgCompletion_Decl<DECL_SKIN> );
849  cmdSystem->AddCommand( "printSoundShader", idPrintDecls_f<DECL_SOUND>, CMD_FL_SYSTEM, "prints a sound shader", idCmdSystem::ArgCompletion_Decl<DECL_SOUND> );
850 
851  cmdSystem->AddCommand( "printEntityDef", idPrintDecls_f<DECL_ENTITYDEF>, CMD_FL_SYSTEM, "prints an entity def", idCmdSystem::ArgCompletion_Decl<DECL_ENTITYDEF> );
852  cmdSystem->AddCommand( "printFX", idPrintDecls_f<DECL_FX>, CMD_FL_SYSTEM, "prints an FX system", idCmdSystem::ArgCompletion_Decl<DECL_FX> );
853  cmdSystem->AddCommand( "printParticle", idPrintDecls_f<DECL_PARTICLE>, CMD_FL_SYSTEM, "prints a particle system", idCmdSystem::ArgCompletion_Decl<DECL_PARTICLE> );
854  cmdSystem->AddCommand( "printAF", idPrintDecls_f<DECL_AF>, CMD_FL_SYSTEM, "prints an articulated figure", idCmdSystem::ArgCompletion_Decl<DECL_AF> );
855 
856  cmdSystem->AddCommand( "printPDA", idPrintDecls_f<DECL_PDA>, CMD_FL_SYSTEM, "prints an PDA", idCmdSystem::ArgCompletion_Decl<DECL_PDA> );
857  cmdSystem->AddCommand( "printEmail", idPrintDecls_f<DECL_EMAIL>, CMD_FL_SYSTEM, "prints an Email", idCmdSystem::ArgCompletion_Decl<DECL_EMAIL> );
858  cmdSystem->AddCommand( "printVideo", idPrintDecls_f<DECL_VIDEO>, CMD_FL_SYSTEM, "prints a Audio", idCmdSystem::ArgCompletion_Decl<DECL_VIDEO> );
859  cmdSystem->AddCommand( "printAudio", idPrintDecls_f<DECL_AUDIO>, CMD_FL_SYSTEM, "prints an Video", idCmdSystem::ArgCompletion_Decl<DECL_AUDIO> );
860 
861  cmdSystem->AddCommand( "listHuffmanFrequencies", ListHuffmanFrequencies_f, CMD_FL_SYSTEM, "lists decl text character frequencies" );
862 
863  common->Printf( "------------------------------\n" );
864 }
865 
866 /*
867 ===================
868 idDeclManagerLocal::Shutdown
869 ===================
870 */
872  int i, j;
873  idDeclLocal *decl;
874 
875  // free decls
876  for ( i = 0; i < DECL_MAX_TYPES; i++ ) {
877  for ( j = 0; j < linearLists[i].Num(); j++ ) {
878  decl = linearLists[i][j];
879  if ( decl->self != NULL ) {
880  decl->self->FreeData();
881  delete decl->self;
882  }
883  if ( decl->textSource ) {
884  Mem_Free( decl->textSource );
885  decl->textSource = NULL;
886  }
887  delete decl;
888  }
889  linearLists[i].Clear();
890  hashTables[i].Free();
891  }
892 
893  // free decl files
894  loadedFiles.DeleteContents( true );
895 
896  // free the decl types and folders
897  declTypes.DeleteContents( true );
898  declFolders.DeleteContents( true );
899 
900 #ifdef USE_COMPRESSED_DECLS
901  ShutdownHuffman();
902 #endif
903 }
904 
905 /*
906 ===================
907 idDeclManagerLocal::Reload
908 ===================
909 */
910 void idDeclManagerLocal::Reload( bool force ) {
911  for ( int i = 0; i < loadedFiles.Num(); i++ ) {
912  loadedFiles[i]->Reload( force );
913  }
914 }
915 
916 /*
917 ===================
918 idDeclManagerLocal::BeginLevelLoad
919 ===================
920 */
922  insideLevelLoad = true;
923 
924  // clear all the referencedThisLevel flags and purge all the data
925  // so the next reference will cause a reparse
926  for ( int i = 0; i < DECL_MAX_TYPES; i++ ) {
927  int num = linearLists[i].Num();
928  for ( int j = 0 ; j < num ; j++ ) {
929  idDeclLocal *decl = linearLists[i][j];
930  decl->Purge();
931  }
932  }
933 }
934 
935 /*
936 ===================
937 idDeclManagerLocal::EndLevelLoad
938 ===================
939 */
941  insideLevelLoad = false;
942 
943  // we don't need to do anything here, but the image manager, model manager,
944  // and sound sample manager will need to free media that was not referenced
945 }
946 
947 /*
948 ===================
949 idDeclManagerLocal::RegisterDeclType
950 ===================
951 */
952 void idDeclManagerLocal::RegisterDeclType( const char *typeName, declType_t type, idDecl *(*allocator)( void ) ) {
953  idDeclType *declType;
954 
955  if ( type < declTypes.Num() && declTypes[(int)type] ) {
956  common->Warning( "idDeclManager::RegisterDeclType: type '%s' already exists", typeName );
957  return;
958  }
959 
960  declType = new idDeclType;
961  declType->typeName = typeName;
962  declType->type = type;
963  declType->allocator = allocator;
964 
965  if ( (int)type + 1 > declTypes.Num() ) {
966  declTypes.AssureSize( (int)type + 1, NULL );
967  }
968  declTypes[type] = declType;
969 }
970 
971 /*
972 ===================
973 idDeclManagerLocal::RegisterDeclFolder
974 ===================
975 */
976 void idDeclManagerLocal::RegisterDeclFolder( const char *folder, const char *extension, declType_t defaultType ) {
977  int i, j;
978  idStr fileName;
979  idDeclFolder *declFolder;
980  idFileList *fileList;
981  idDeclFile *df;
982 
983  // check whether this folder / extension combination already exists
984  for ( i = 0; i < declFolders.Num(); i++ ) {
985  if ( declFolders[i]->folder.Icmp( folder ) == 0 && declFolders[i]->extension.Icmp( extension ) == 0 ) {
986  break;
987  }
988  }
989  if ( i < declFolders.Num() ) {
990  declFolder = declFolders[i];
991  } else {
992  declFolder = new idDeclFolder;
993  declFolder->folder = folder;
994  declFolder->extension = extension;
995  declFolder->defaultType = defaultType;
996  declFolders.Append( declFolder );
997  }
998 
999  // scan for decl files
1000  fileList = fileSystem->ListFiles( declFolder->folder, declFolder->extension, true );
1001 
1002  // load and parse decl files
1003  for ( i = 0; i < fileList->GetNumFiles(); i++ ) {
1004  fileName = declFolder->folder + "/" + fileList->GetFile( i );
1005 
1006  // check whether this file has already been loaded
1007  for ( j = 0; j < loadedFiles.Num(); j++ ) {
1008  if ( fileName.Icmp( loadedFiles[j]->fileName ) == 0 ) {
1009  break;
1010  }
1011  }
1012  if ( j < loadedFiles.Num() ) {
1013  df = loadedFiles[j];
1014  } else {
1015  df = new idDeclFile( fileName, defaultType );
1016  loadedFiles.Append( df );
1017  }
1018  df->LoadAndParse();
1019  }
1020 
1021  fileSystem->FreeFileList( fileList );
1022 }
1023 
1024 /*
1025 ===================
1026 idDeclManagerLocal::GetChecksum
1027 ===================
1028 */
1030  int i, j, total, num;
1031  int *checksumData;
1032 
1033  // get the total number of decls
1034  total = 0;
1035  for ( i = 0; i < DECL_MAX_TYPES; i++ ) {
1036  total += linearLists[i].Num();
1037  }
1038 
1039  checksumData = (int *) _alloca16( total * 2 * sizeof( int ) );
1040 
1041  total = 0;
1042  for ( i = 0; i < DECL_MAX_TYPES; i++ ) {
1043  declType_t type = (declType_t) i;
1044 
1045  // FIXME: not particularly pretty but PDAs and associated decls are localized and should not be checksummed
1046  if ( type == DECL_PDA || type == DECL_VIDEO || type == DECL_AUDIO || type == DECL_EMAIL ) {
1047  continue;
1048  }
1049 
1050  num = linearLists[i].Num();
1051  for ( j = 0; j < num; j++ ) {
1052  idDeclLocal *decl = linearLists[i][j];
1053 
1054  if ( decl->sourceFile == &implicitDecls ) {
1055  continue;
1056  }
1057 
1058  checksumData[total*2+0] = total;
1059  checksumData[total*2+1] = decl->checksum;
1060  total++;
1061  }
1062  }
1063 
1064  LittleRevBytes( checksumData, sizeof(int), total * 2 );
1065  return MD5_BlockChecksum( checksumData, total * 2 * sizeof( int ) );
1066 }
1067 
1068 /*
1069 ===================
1070 idDeclManagerLocal::GetNumDeclTypes
1071 ===================
1072 */
1074  return declTypes.Num();
1075 }
1076 
1077 /*
1078 ===================
1079 idDeclManagerLocal::GetDeclNameFromType
1080 ===================
1081 */
1083  int typeIndex = (int)type;
1084 
1085  if ( typeIndex < 0 || typeIndex >= declTypes.Num() || declTypes[typeIndex] == NULL ) {
1086  common->FatalError( "idDeclManager::GetDeclNameFromType: bad type: %i", typeIndex );
1087  }
1088  return declTypes[typeIndex]->typeName;
1089 }
1090 
1091 /*
1092 ===================
1093 idDeclManagerLocal::GetDeclTypeFromName
1094 ===================
1095 */
1097  int i;
1098 
1099  for ( i = 0; i < declTypes.Num(); i++ ) {
1100  if ( declTypes[i] && declTypes[i]->typeName.Icmp( typeName ) == 0 ) {
1101  return (declType_t)declTypes[i]->type;
1102  }
1103  }
1104  return DECL_MAX_TYPES;
1105 }
1106 
1107 /*
1108 =================
1109 idDeclManagerLocal::FindType
1110 
1111 External users will always cause the decl to be parsed before returning
1112 =================
1113 */
1114 const idDecl *idDeclManagerLocal::FindType( declType_t type, const char *name, bool makeDefault ) {
1115  idDeclLocal *decl;
1116 
1117  if ( !name || !name[0] ) {
1118  name = "_emptyName";
1119  //common->Warning( "idDeclManager::FindType: empty %s name", GetDeclType( (int)type )->typeName.c_str() );
1120  }
1121 
1122  decl = FindTypeWithoutParsing( type, name, makeDefault );
1123  if ( !decl ) {
1124  return NULL;
1125  }
1126 
1127  decl->AllocateSelf();
1128 
1129  // if it hasn't been parsed yet, parse it now
1130  if ( decl->declState == DS_UNPARSED ) {
1131  decl->ParseLocal();
1132  }
1133 
1134  // mark it as referenced
1135  decl->referencedThisLevel = true;
1136  decl->everReferenced = true;
1137  if ( insideLevelLoad ) {
1138  decl->parsedOutsideLevelLoad = false;
1139  }
1140 
1141  return decl->self;
1142 }
1143 
1144 /*
1145 ===============
1146 idDeclManagerLocal::FindDeclWithoutParsing
1147 ===============
1148 */
1149 const idDecl* idDeclManagerLocal::FindDeclWithoutParsing( declType_t type, const char *name, bool makeDefault) {
1150  idDeclLocal* decl;
1151  decl = FindTypeWithoutParsing(type, name, makeDefault);
1152  if(decl) {
1153  return decl->self;
1154  }
1155  return NULL;
1156 }
1157 
1158 /*
1159 ===============
1160 idDeclManagerLocal::ReloadFile
1161 ===============
1162 */
1163 void idDeclManagerLocal::ReloadFile( const char* filename, bool force ) {
1164  for ( int i = 0; i < loadedFiles.Num(); i++ ) {
1165  if(!loadedFiles[i]->fileName.Icmp(filename)) {
1166  checksum ^= loadedFiles[i]->checksum;
1167  loadedFiles[i]->Reload( force );
1168  checksum ^= loadedFiles[i]->checksum;
1169  }
1170  }
1171 }
1172 
1173 /*
1174 ===================
1175 idDeclManagerLocal::GetNumDecls
1176 ===================
1177 */
1179  int typeIndex = (int)type;
1180 
1181  if ( typeIndex < 0 || typeIndex >= declTypes.Num() || declTypes[typeIndex] == NULL ) {
1182  common->FatalError( "idDeclManager::GetNumDecls: bad type: %i", typeIndex );
1183  }
1184  return linearLists[ typeIndex ].Num();
1185 }
1186 
1187 /*
1188 ===================
1189 idDeclManagerLocal::DeclByIndex
1190 ===================
1191 */
1192 const idDecl *idDeclManagerLocal::DeclByIndex( declType_t type, int index, bool forceParse ) {
1193  int typeIndex = (int)type;
1194 
1195  if ( typeIndex < 0 || typeIndex >= declTypes.Num() || declTypes[typeIndex] == NULL ) {
1196  common->FatalError( "idDeclManager::DeclByIndex: bad type: %i", typeIndex );
1197  }
1198  if ( index < 0 || index >= linearLists[ typeIndex ].Num() ) {
1199  common->Error( "idDeclManager::DeclByIndex: out of range" );
1200  }
1201  idDeclLocal *decl = linearLists[ typeIndex ][ index ];
1202 
1203  decl->AllocateSelf();
1204 
1205  if ( forceParse && decl->declState == DS_UNPARSED ) {
1206  decl->ParseLocal();
1207  }
1208 
1209  return decl->self;
1210 }
1211 
1212 /*
1213 ===================
1214 idDeclManagerLocal::ListType
1215 
1216 list*
1217 Lists decls currently referenced
1218 
1219 list* ever
1220 Lists decls that have been referenced at least once since app launched
1221 
1222 list* all
1223 Lists every decl declared, even if it hasn't been referenced or parsed
1224 
1225 FIXME: alphabetized, wildcards?
1226 ===================
1227 */
1229  bool all, ever;
1230 
1231  if ( !idStr::Icmp( args.Argv( 1 ), "all" ) ) {
1232  all = true;
1233  } else {
1234  all = false;
1235  }
1236  if ( !idStr::Icmp( args.Argv( 1 ), "ever" ) ) {
1237  ever = true;
1238  } else {
1239  ever = false;
1240  }
1241 
1242  common->Printf( "--------------------\n" );
1243  int printed = 0;
1244  int count = linearLists[ (int)type ].Num();
1245  for ( int i = 0 ; i < count ; i++ ) {
1246  idDeclLocal *decl = linearLists[ (int)type ][ i ];
1247 
1248  if ( !all && decl->declState == DS_UNPARSED ) {
1249  continue;
1250  }
1251 
1252  if ( !all && !ever && !decl->referencedThisLevel ) {
1253  continue;
1254  }
1255 
1256  if ( decl->referencedThisLevel ) {
1257  common->Printf( "*" );
1258  } else if ( decl->everReferenced ) {
1259  common->Printf( "." );
1260  } else {
1261  common->Printf( " " );
1262  }
1263  if ( decl->declState == DS_DEFAULTED ) {
1264  common->Printf( "D" );
1265  } else {
1266  common->Printf( " " );
1267  }
1268  common->Printf( "%4i: ", decl->index );
1269  printed++;
1270  if ( decl->declState == DS_UNPARSED ) {
1271  // doesn't have any type specific data yet
1272  common->Printf( "%s\n", decl->GetName() );
1273  } else {
1274  decl->self->List();
1275  }
1276  }
1277 
1278  common->Printf( "--------------------\n" );
1279  common->Printf( "%i of %i %s\n", printed, count, declTypes[type]->typeName.c_str() );
1280 }
1281 
1282 /*
1283 ===================
1284 idDeclManagerLocal::PrintType
1285 ===================
1286 */
1288  // individual decl types may use additional command parameters
1289  if ( args.Argc() < 2 ) {
1290  common->Printf( "USAGE: Print<decl type> <decl name> [type specific parms]\n" );
1291  return;
1292  }
1293 
1294  // look it up, skipping the public path so it won't parse or reference
1295  idDeclLocal *decl = FindTypeWithoutParsing( type, args.Argv( 1 ), false );
1296  if ( !decl ) {
1297  common->Printf( "%s '%s' not found.\n", declTypes[ type ]->typeName.c_str(), args.Argv( 1 ) );
1298  return;
1299  }
1300 
1301  // print information common to all decls
1302  common->Printf( "%s %s:\n", declTypes[ type ]->typeName.c_str(), decl->name.c_str() );
1303  common->Printf( "source: %s:%i\n", decl->sourceFile->fileName.c_str(), decl->sourceLine );
1304  common->Printf( "----------\n" );
1305  if ( decl->textSource != NULL ) {
1306  char *declText = (char *)_alloca( decl->textLength + 1 );
1307  decl->GetText( declText );
1308  common->Printf( "%s\n", declText );
1309  } else {
1310  common->Printf( "NO SOURCE\n" );
1311  }
1312  common->Printf( "----------\n" );
1313  switch( decl->declState ) {
1314  case DS_UNPARSED:
1315  common->Printf( "Unparsed.\n" );
1316  break;
1317  case DS_DEFAULTED:
1318  common->Printf( "<DEFAULTED>\n" );
1319  break;
1320  case DS_PARSED:
1321  common->Printf( "Parsed.\n" );
1322  break;
1323  }
1324 
1325  if ( decl->referencedThisLevel ) {
1326  common->Printf( "Currently referenced this level.\n" );
1327  } else if ( decl->everReferenced ) {
1328  common->Printf( "Referenced in a previous level.\n" );
1329  } else {
1330  common->Printf( "Never referenced.\n" );
1331  }
1332 
1333  // allow type-specific data to be printed
1334  if ( decl->self != NULL ) {
1335  decl->self->Print();
1336  }
1337 }
1338 
1339 /*
1340 ===================
1341 idDeclManagerLocal::CreateNewDecl
1342 ===================
1343 */
1344 idDecl *idDeclManagerLocal::CreateNewDecl( declType_t type, const char *name, const char *_fileName ) {
1345  int typeIndex = (int)type;
1346  int i, hash;
1347 
1348  if ( typeIndex < 0 || typeIndex >= declTypes.Num() || declTypes[typeIndex] == NULL ) {
1349  common->FatalError( "idDeclManager::CreateNewDecl: bad type: %i", typeIndex );
1350  }
1351 
1352  char canonicalName[MAX_STRING_CHARS];
1353 
1354  MakeNameCanonical( name, canonicalName, sizeof( canonicalName ) );
1355 
1356  idStr fileName = _fileName;
1357  fileName.BackSlashesToSlashes();
1358 
1359  // see if it already exists
1360  hash = hashTables[typeIndex].GenerateKey( canonicalName, false );
1361  for ( i = hashTables[typeIndex].First( hash ); i >= 0; i = hashTables[typeIndex].Next( i ) ) {
1362  if ( linearLists[typeIndex][i]->name.Icmp( canonicalName ) == 0 ) {
1363  linearLists[typeIndex][i]->AllocateSelf();
1364  return linearLists[typeIndex][i]->self;
1365  }
1366  }
1367 
1368  idDeclFile *sourceFile;
1369 
1370  // find existing source file or create a new one
1371  for ( i = 0; i < loadedFiles.Num(); i++ ) {
1372  if ( loadedFiles[i]->fileName.Icmp( fileName ) == 0 ) {
1373  break;
1374  }
1375  }
1376  if ( i < loadedFiles.Num() ) {
1377  sourceFile = loadedFiles[i];
1378  } else {
1379  sourceFile = new idDeclFile( fileName, type );
1380  loadedFiles.Append( sourceFile );
1381  }
1382 
1383  idDeclLocal *decl = new idDeclLocal;
1384  decl->name = canonicalName;
1385  decl->type = type;
1386  decl->declState = DS_UNPARSED;
1387  decl->AllocateSelf();
1388  idStr header = declTypes[typeIndex]->typeName;
1389  idStr defaultText = decl->self->DefaultDefinition();
1390 
1391 
1392  int size = header.Length() + 1 + idStr::Length( canonicalName ) + 1 + defaultText.Length();
1393  char *declText = ( char * ) _alloca( size + 1 );
1394 
1395  memcpy( declText, header, header.Length() );
1396  declText[header.Length()] = ' ';
1397  memcpy( declText + header.Length() + 1, canonicalName, idStr::Length( canonicalName ) );
1398  declText[header.Length() + 1 + idStr::Length( canonicalName )] = ' ';
1399  memcpy( declText + header.Length() + 1 + idStr::Length( canonicalName ) + 1, defaultText, defaultText.Length() + 1 );
1400 
1401  decl->SetTextLocal( declText, size );
1402  decl->sourceFile = sourceFile;
1403  decl->sourceTextOffset = sourceFile->fileSize;
1404  decl->sourceTextLength = 0;
1405  decl->sourceLine = sourceFile->numLines;
1406 
1407  decl->ParseLocal();
1408 
1409  // add this decl to the source file list
1410  decl->nextInFile = sourceFile->decls;
1411  sourceFile->decls = decl;
1412 
1413  // add it to the hash table and linear list
1414  decl->index = linearLists[typeIndex].Num();
1415  hashTables[typeIndex].Add( hash, linearLists[typeIndex].Append( decl ) );
1416 
1417  return decl->self;
1418 }
1419 
1420 /*
1421 ===============
1422 idDeclManagerLocal::RenameDecl
1423 ===============
1424 */
1425 bool idDeclManagerLocal::RenameDecl( declType_t type, const char* oldName, const char* newName ) {
1426 
1427  char canonicalOldName[MAX_STRING_CHARS];
1428  MakeNameCanonical( oldName, canonicalOldName, sizeof( canonicalOldName ));
1429 
1430  char canonicalNewName[MAX_STRING_CHARS];
1431  MakeNameCanonical( newName, canonicalNewName, sizeof( canonicalNewName ) );
1432 
1433  idDeclLocal *decl = NULL;
1434 
1435  // make sure it already exists
1436  int typeIndex = (int)type;
1437  int i, hash;
1438  hash = hashTables[typeIndex].GenerateKey( canonicalOldName, false );
1439  for ( i = hashTables[typeIndex].First( hash ); i >= 0; i = hashTables[typeIndex].Next( i ) ) {
1440  if ( linearLists[typeIndex][i]->name.Icmp( canonicalOldName ) == 0 ) {
1441  decl = linearLists[typeIndex][i];
1442  break;
1443  }
1444  }
1445  if(!decl)
1446  return false;
1447 
1448  //if ( !hashTables[(int)type].Get( canonicalOldName, &declPtr ) )
1449  // return false;
1450 
1451  //decl = *declPtr;
1452 
1453  //Change the name
1454  decl->name = canonicalNewName;
1455 
1456 
1457  // add it to the hash table
1458  //hashTables[(int)decl->type].Set( decl->name, decl );
1459  int newhash = hashTables[typeIndex].GenerateKey( canonicalNewName, false );
1460  hashTables[typeIndex].Add( newhash, decl->index );
1461 
1462  //Remove the old hash item
1463  hashTables[typeIndex].Remove(hash, decl->index);
1464 
1465  return true;
1466 }
1467 
1468 /*
1469 ===================
1470 idDeclManagerLocal::MediaPrint
1471 
1472 This is just used to nicely indent media caching prints
1473 ===================
1474 */
1475 void idDeclManagerLocal::MediaPrint( const char *fmt, ... ) {
1476  if ( !decl_show.GetInteger() ) {
1477  return;
1478  }
1479  for ( int i = 0 ; i < indent ; i++ ) {
1480  common->Printf( " " );
1481  }
1482  va_list argptr;
1483  char buffer[1024];
1484  va_start (argptr,fmt);
1485  idStr::vsnPrintf( buffer, sizeof(buffer), fmt, argptr );
1486  va_end (argptr);
1487  buffer[sizeof(buffer)-1] = '\0';
1488 
1489  common->Printf( "%s", buffer );
1490 }
1491 
1492 /*
1493 ===================
1494 idDeclManagerLocal::WritePrecacheCommands
1495 ===================
1496 */
1498  for ( int i = 0; i < declTypes.Num(); i++ ) {
1499  int num;
1500 
1501  if ( declTypes[i] == NULL ) {
1502  continue;
1503  }
1504 
1505  num = linearLists[i].Num();
1506 
1507  for ( int j = 0 ; j < num ; j++ ) {
1508  idDeclLocal *decl = linearLists[i][j];
1509 
1510  if ( !decl->referencedThisLevel ) {
1511  continue;
1512  }
1513 
1514  char str[1024];
1515  sprintf( str, "touch %s %s\n", declTypes[i]->typeName.c_str(), decl->GetName() );
1516  common->Printf( "%s", str );
1517  f->Printf( "%s", str );
1518  }
1519  }
1520 }
1521 
1522 /********************************************************************/
1523 
1524 const idMaterial *idDeclManagerLocal::FindMaterial( const char *name, bool makeDefault ) {
1525  return static_cast<const idMaterial *>( FindType( DECL_MATERIAL, name, makeDefault ) );
1526 }
1527 
1528 const idMaterial *idDeclManagerLocal::MaterialByIndex( int index, bool forceParse ) {
1529  return static_cast<const idMaterial *>( DeclByIndex( DECL_MATERIAL, index, forceParse ) );
1530 }
1531 
1532 /********************************************************************/
1533 
1534 const idDeclSkin *idDeclManagerLocal::FindSkin( const char *name, bool makeDefault ) {
1535  return static_cast<const idDeclSkin *>( FindType( DECL_SKIN, name, makeDefault ) );
1536 }
1537 
1538 const idDeclSkin *idDeclManagerLocal::SkinByIndex( int index, bool forceParse ) {
1539  return static_cast<const idDeclSkin *>( DeclByIndex( DECL_SKIN, index, forceParse ) );
1540 }
1541 
1542 /********************************************************************/
1543 
1544 const idSoundShader *idDeclManagerLocal::FindSound( const char *name, bool makeDefault ) {
1545  return static_cast<const idSoundShader *>( FindType( DECL_SOUND, name, makeDefault ) );
1546 }
1547 
1548 const idSoundShader *idDeclManagerLocal::SoundByIndex( int index, bool forceParse ) {
1549  return static_cast<const idSoundShader *>( DeclByIndex( DECL_SOUND, index, forceParse ) );
1550 }
1551 
1552 /*
1553 ===================
1554 idDeclManagerLocal::MakeNameCanonical
1555 ===================
1556 */
1558  int i, lastDot;
1559 
1560  lastDot = -1;
1561  for ( i = 0; i < maxLength && name[i] != '\0'; i++ ) {
1562  int c = name[i];
1563  if ( c == '\\' ) {
1564  result[i] = '/';
1565  } else if ( c == '.' ) {
1566  lastDot = i;
1567  result[i] = c;
1568  } else {
1569  result[i] = idStr::ToLower( c );
1570  }
1571  }
1572  if ( lastDot != -1 ) {
1573  result[lastDot] = '\0';
1574  } else {
1575  result[i] = '\0';
1576  }
1577 }
1578 
1579 /*
1580 ================
1581 idDeclManagerLocal::ListDecls_f
1582 ================
1583 */
1585  int i, j;
1586  int totalDecls = 0;
1587  int totalText = 0;
1588  int totalStructs = 0;
1589 
1590  for ( i = 0; i < declManagerLocal.declTypes.Num(); i++ ) {
1591  int size, num;
1592 
1593  if ( declManagerLocal.declTypes[i] == NULL ) {
1594  continue;
1595  }
1596 
1597  num = declManagerLocal.linearLists[i].Num();
1598  totalDecls += num;
1599 
1600  size = 0;
1601  for ( j = 0; j < num; j++ ) {
1602  size += declManagerLocal.linearLists[i][j]->Size();
1603  if ( declManagerLocal.linearLists[i][j]->self != NULL ) {
1604  size += declManagerLocal.linearLists[i][j]->self->Size();
1605  }
1606  }
1607  totalStructs += size;
1608 
1609  common->Printf( "%4ik %4i %s\n", size >> 10, num, declManagerLocal.declTypes[i]->typeName.c_str() );
1610  }
1611 
1612  for ( i = 0 ; i < declManagerLocal.loadedFiles.Num() ; i++ ) {
1613  idDeclFile *df = declManagerLocal.loadedFiles[i];
1614  totalText += df->fileSize;
1615  }
1616 
1617  common->Printf( "%i total decls is %i decl files\n", totalDecls, declManagerLocal.loadedFiles.Num() );
1618  common->Printf( "%iKB in text, %iKB in structures\n", totalText >> 10, totalStructs >> 10 );
1619 }
1620 
1621 /*
1622 ===================
1623 idDeclManagerLocal::ReloadDecls_f
1624 
1625 Reload will not find any new files created in the directories, it
1626 will only reload existing files.
1627 
1628 A reload will never cause anything to be purged.
1629 ===================
1630 */
1632  bool force;
1633 
1634  if ( !idStr::Icmp( args.Argv( 1 ), "all" ) ) {
1635  force = true;
1636  common->Printf( "reloading all decl files:\n" );
1637  } else {
1638  force = false;
1639  common->Printf( "reloading changed decl files:\n" );
1640  }
1641 
1642  soundSystem->SetMute( true );
1643 
1644  declManagerLocal.Reload( force );
1645 
1646  soundSystem->SetMute( false );
1647 }
1648 
1649 /*
1650 ===================
1651 idDeclManagerLocal::TouchDecl_f
1652 ===================
1653 */
1655  int i;
1656 
1657  if ( args.Argc() != 3 ) {
1658  common->Printf( "usage: touch <type> <name>\n" );
1659  common->Printf( "valid types: " );
1660  for ( int i = 0 ; i < declManagerLocal.declTypes.Num() ; i++ ) {
1661  if ( declManagerLocal.declTypes[i] ) {
1662  common->Printf( "%s ", declManagerLocal.declTypes[i]->typeName.c_str() );
1663  }
1664  }
1665  common->Printf( "\n" );
1666  return;
1667  }
1668 
1669  for ( i = 0; i < declManagerLocal.declTypes.Num(); i++ ) {
1670  if ( declManagerLocal.declTypes[i] && declManagerLocal.declTypes[i]->typeName.Icmp( args.Argv( 1 ) ) == 0 ) {
1671  break;
1672  }
1673  }
1674  if ( i >= declManagerLocal.declTypes.Num() ) {
1675  common->Printf( "unknown decl type '%s'\n", args.Argv( 1 ) );
1676  return;
1677  }
1678 
1679  const idDecl *decl = declManagerLocal.FindType( (declType_t)i, args.Argv( 2 ), false );
1680  if ( !decl ) {
1681  common->Printf( "%s '%s' not found\n", declManagerLocal.declTypes[i]->typeName.c_str(), args.Argv( 2 ) );
1682  }
1683 }
1684 
1685 /*
1686 ===================
1687 idDeclManagerLocal::FindTypeWithoutParsing
1688 
1689 This finds or creats the decl, but does not cause a parse. This is only used internally.
1690 ===================
1691 */
1693  int typeIndex = (int)type;
1694  int i, hash;
1695 
1696  if ( typeIndex < 0 || typeIndex >= declTypes.Num() || declTypes[typeIndex] == NULL ) {
1697  common->FatalError( "idDeclManager::FindTypeWithoutParsing: bad type: %i", typeIndex );
1698  }
1699 
1700  char canonicalName[MAX_STRING_CHARS];
1701 
1702  MakeNameCanonical( name, canonicalName, sizeof( canonicalName ) );
1703 
1704  // see if it already exists
1705  hash = hashTables[typeIndex].GenerateKey( canonicalName, false );
1706  for ( i = hashTables[typeIndex].First( hash ); i >= 0; i = hashTables[typeIndex].Next( i ) ) {
1707  if ( linearLists[typeIndex][i]->name.Icmp( canonicalName ) == 0 ) {
1708  // only print these when decl_show is set to 2, because it can be a lot of clutter
1709  if ( decl_show.GetInteger() > 1 ) {
1710  MediaPrint( "referencing %s %s\n", declTypes[ type ]->typeName.c_str(), name );
1711  }
1712  return linearLists[typeIndex][i];
1713  }
1714  }
1715 
1716  if ( !makeDefault ) {
1717  return NULL;
1718  }
1719 
1720  idDeclLocal *decl = new idDeclLocal;
1721  decl->self = NULL;
1722  decl->name = canonicalName;
1723  decl->type = type;
1724  decl->declState = DS_UNPARSED;
1725  decl->textSource = NULL;
1726  decl->textLength = 0;
1727  decl->sourceFile = &implicitDecls;
1728  decl->referencedThisLevel = false;
1729  decl->everReferenced = false;
1731 
1732  // add it to the linear list and hash table
1733  decl->index = linearLists[typeIndex].Num();
1734  hashTables[typeIndex].Add( hash, linearLists[typeIndex].Append( decl ) );
1735 
1736  return decl;
1737 }
1738 
1739 
1740 /*
1741 ====================================================================================
1742 
1743  idDeclLocal
1744 
1745 ====================================================================================
1746 */
1747 
1748 /*
1749 =================
1750 idDeclLocal::idDeclLocal
1751 =================
1752 */
1754  name = "unnamed";
1755  textSource = NULL;
1756  textLength = 0;
1757  compressedLength = 0;
1758  sourceFile = NULL;
1759  sourceTextOffset = 0;
1760  sourceTextLength = 0;
1761  sourceLine = 0;
1762  checksum = 0;
1763  type = DECL_ENTITYDEF;
1764  index = 0;
1766  parsedOutsideLevelLoad = false;
1767  referencedThisLevel = false;
1768  everReferenced = false;
1769  redefinedInReload = false;
1770  nextInFile = NULL;
1771 }
1772 
1773 /*
1774 =================
1775 idDeclLocal::GetName
1776 =================
1777 */
1778 const char *idDeclLocal::GetName( void ) const {
1779  return name.c_str();
1780 }
1781 
1782 /*
1783 =================
1784 idDeclLocal::GetType
1785 =================
1786 */
1788  return type;
1789 }
1790 
1791 /*
1792 =================
1793 idDeclLocal::GetState
1794 =================
1795 */
1797  return declState;
1798 }
1799 
1800 /*
1801 =================
1802 idDeclLocal::IsImplicit
1803 =================
1804 */
1805 bool idDeclLocal::IsImplicit( void ) const {
1806  return ( sourceFile == declManagerLocal.GetImplicitDeclFile() );
1807 }
1808 
1809 /*
1810 =================
1811 idDeclLocal::IsValid
1812 =================
1813 */
1814 bool idDeclLocal::IsValid( void ) const {
1815  return ( declState != DS_UNPARSED );
1816 }
1817 
1818 /*
1819 =================
1820 idDeclLocal::Invalidate
1821 =================
1822 */
1825 }
1826 
1827 /*
1828 =================
1829 idDeclLocal::EnsureNotPurged
1830 =================
1831 */
1833  if ( declState == DS_UNPARSED ) {
1834  ParseLocal();
1835  }
1836 }
1837 
1838 /*
1839 =================
1840 idDeclLocal::Index
1841 =================
1842 */
1843 int idDeclLocal::Index( void ) const {
1844  return index;
1845 }
1846 
1847 /*
1848 =================
1849 idDeclLocal::GetLineNum
1850 =================
1851 */
1852 int idDeclLocal::GetLineNum( void ) const {
1853  return sourceLine;
1854 }
1855 
1856 /*
1857 =================
1858 idDeclLocal::GetFileName
1859 =================
1860 */
1861 const char *idDeclLocal::GetFileName( void ) const {
1862  return ( sourceFile ) ? sourceFile->fileName.c_str() : "*invalid*";
1863 }
1864 
1865 /*
1866 =================
1867 idDeclLocal::Size
1868 =================
1869 */
1870 size_t idDeclLocal::Size( void ) const {
1871  return sizeof( idDecl ) + name.Allocated();
1872 }
1873 
1874 /*
1875 =================
1876 idDeclLocal::GetText
1877 =================
1878 */
1879 void idDeclLocal::GetText( char *text ) const {
1880 #ifdef USE_COMPRESSED_DECLS
1882 #else
1883  memcpy( text, textSource, textLength+1 );
1884 #endif
1885 }
1886 
1887 /*
1888 =================
1889 idDeclLocal::GetTextLength
1890 =================
1891 */
1892 int idDeclLocal::GetTextLength( void ) const {
1893  return textLength;
1894 }
1895 
1896 /*
1897 =================
1898 idDeclLocal::SetText
1899 =================
1900 */
1901 void idDeclLocal::SetText( const char *text ) {
1902  SetTextLocal( text, idStr::Length( text ) );
1903 }
1904 
1905 /*
1906 =================
1907 idDeclLocal::SetTextLocal
1908 =================
1909 */
1910 void idDeclLocal::SetTextLocal( const char *text, const int length ) {
1911 
1912  Mem_Free( textSource );
1913 
1914  checksum = MD5_BlockChecksum( text, length );
1915 
1916 #ifdef GET_HUFFMAN_FREQUENCIES
1917  for( int i = 0; i < length; i++ ) {
1918  huffmanFrequencies[((const unsigned char *)text)[i]]++;
1919  }
1920 #endif
1921 
1922 #ifdef USE_COMPRESSED_DECLS
1923  int maxBytesPerCode = ( maxHuffmanBits + 7 ) >> 3;
1924  byte *compressed = (byte *)_alloca( length * maxBytesPerCode );
1925  compressedLength = HuffmanCompressText( text, length, compressed, length * maxBytesPerCode );
1926  textSource = (char *)Mem_Alloc( compressedLength );
1927  memcpy( textSource, compressed, compressedLength );
1928 #else
1930  textSource = (char *) Mem_Alloc( length + 1 );
1931  memcpy( textSource, text, length );
1932  textSource[length] = '\0';
1933 #endif
1934  textLength = length;
1935 }
1936 
1937 /*
1938 =================
1939 idDeclLocal::ReplaceSourceFileText
1940 =================
1941 */
1943  int oldFileLength, newFileLength;
1944  char *buffer;
1945  idFile *file;
1946 
1947  common->Printf( "Writing \'%s\' to \'%s\'...\n", GetName(), GetFileName() );
1948 
1949  if ( sourceFile == &declManagerLocal.implicitDecls ) {
1950  common->Warning( "Can't save implicit declaration %s.", GetName() );
1951  return false;
1952  }
1953 
1954  // get length and allocate buffer to hold the file
1955  oldFileLength = sourceFile->fileSize;
1956  newFileLength = oldFileLength - sourceTextLength + textLength;
1957  buffer = (char *) Mem_Alloc( Max( newFileLength, oldFileLength ) );
1958 
1959  // read original file
1960  if ( sourceFile->fileSize ) {
1961 
1962  file = fileSystem->OpenFileRead( GetFileName() );
1963  if ( !file ) {
1964  Mem_Free( buffer );
1965  common->Warning( "Couldn't open %s for reading.", GetFileName() );
1966  return false;
1967  }
1968 
1969  if ( file->Length() != sourceFile->fileSize || file->Timestamp() != sourceFile->timestamp ) {
1970  Mem_Free( buffer );
1971  common->Warning( "The file %s has been modified outside of the engine.", GetFileName() );
1972  return false;
1973  }
1974 
1975  file->Read( buffer, oldFileLength );
1976  fileSystem->CloseFile( file );
1977 
1978  if ( MD5_BlockChecksum( buffer, oldFileLength ) != sourceFile->checksum ) {
1979  Mem_Free( buffer );
1980  common->Warning( "The file %s has been modified outside of the engine.", GetFileName() );
1981  return false;
1982  }
1983  }
1984 
1985  // insert new text
1986  char *declText = (char *) _alloca( textLength + 1 );
1987  GetText( declText );
1988  memmove( buffer + sourceTextOffset + textLength, buffer + sourceTextOffset + sourceTextLength, oldFileLength - sourceTextOffset - sourceTextLength );
1989  memcpy( buffer + sourceTextOffset, declText, textLength );
1990 
1991  // write out new file
1992  file = fileSystem->OpenFileWrite( GetFileName(), "fs_devpath" );
1993  if ( !file ) {
1994  Mem_Free( buffer );
1995  common->Warning( "Couldn't open %s for writing.", GetFileName() );
1996  return false;
1997  }
1998  file->Write( buffer, newFileLength );
1999  fileSystem->CloseFile( file );
2000 
2001  // set new file size, checksum and timestamp
2002  sourceFile->fileSize = newFileLength;
2003  sourceFile->checksum = MD5_BlockChecksum( buffer, newFileLength );
2005 
2006  // free buffer
2007  Mem_Free( buffer );
2008 
2009  // move all decls in the same file
2010  for ( idDeclLocal *decl = sourceFile->decls; decl; decl = decl->nextInFile ) {
2011  if (decl->sourceTextOffset > sourceTextOffset) {
2012  decl->sourceTextOffset += textLength - sourceTextLength;
2013  }
2014  }
2015 
2016  // set new size of text in source file
2018 
2019  return true;
2020 }
2021 
2022 /*
2023 =================
2024 idDeclLocal::SourceFileChanged
2025 =================
2026 */
2028  int newLength;
2029  ID_TIME_T newTimestamp;
2030 
2031  if ( sourceFile->fileSize <= 0 ) {
2032  return false;
2033  }
2034 
2035  newLength = fileSystem->ReadFile( GetFileName(), NULL, &newTimestamp );
2036 
2037  if ( newLength != sourceFile->fileSize || newTimestamp != sourceFile->timestamp ) {
2038  return true;
2039  }
2040 
2041  return false;
2042 }
2043 
2044 /*
2045 =================
2046 idDeclLocal::MakeDefault
2047 =================
2048 */
2050  static int recursionLevel;
2051  const char *defaultText;
2052 
2053  declManagerLocal.MediaPrint( "DEFAULTED\n" );
2055 
2056  AllocateSelf();
2057 
2058  defaultText = self->DefaultDefinition();
2059 
2060  // a parse error inside a DefaultDefinition() string could
2061  // cause an infinite loop, but normal default definitions could
2062  // still reference other default definitions, so we can't
2063  // just dump out on the first recursion
2064  if ( ++recursionLevel > 100 ) {
2065  common->FatalError( "idDecl::MakeDefault: bad DefaultDefinition(): %s", defaultText );
2066  }
2067 
2068  // always free data before parsing
2069  self->FreeData();
2070 
2071  // parse
2072  self->Parse( defaultText, strlen( defaultText ) );
2073 
2074  // we could still eventually hit the recursion if we have enough Error() calls inside Parse...
2075  --recursionLevel;
2076 }
2077 
2078 /*
2079 =================
2080 idDeclLocal::SetDefaultText
2081 =================
2082 */
2084  return false;
2085 }
2086 
2087 /*
2088 =================
2089 idDeclLocal::DefaultDefinition
2090 =================
2091 */
2092 const char *idDeclLocal::DefaultDefinition() const {
2093  return "{ }";
2094 }
2095 
2096 /*
2097 =================
2098 idDeclLocal::Parse
2099 =================
2100 */
2101 bool idDeclLocal::Parse( const char *text, const int textLength ) {
2102  idLexer src;
2103 
2104  src.LoadMemory( text, textLength, GetFileName(), GetLineNum() );
2105  src.SetFlags( DECL_LEXER_FLAGS );
2106  src.SkipUntilString( "{" );
2107  src.SkipBracedSection( false );
2108  return true;
2109 }
2110 
2111 /*
2112 =================
2113 idDeclLocal::FreeData
2114 =================
2115 */
2117 }
2118 
2119 /*
2120 =================
2121 idDeclLocal::List
2122 =================
2123 */
2124 void idDeclLocal::List() const {
2125  common->Printf( "%s\n", GetName() );
2126 }
2127 
2128 /*
2129 =================
2130 idDeclLocal::Print
2131 =================
2132 */
2133 void idDeclLocal::Print() const {
2134 }
2135 
2136 /*
2137 =================
2138 idDeclLocal::Reload
2139 =================
2140 */
2141 void idDeclLocal::Reload( void ) {
2142  this->sourceFile->Reload( false );
2143 }
2144 
2145 /*
2146 =================
2147 idDeclLocal::AllocateSelf
2148 =================
2149 */
2151  if ( self == NULL ) {
2152  self = declManagerLocal.GetDeclType( (int)type )->allocator();
2153  self->base = this;
2154  }
2155 }
2156 
2157 /*
2158 =================
2159 idDeclLocal::ParseLocal
2160 =================
2161 */
2163  bool generatedDefaultText = false;
2164 
2165  AllocateSelf();
2166 
2167  // always free data before parsing
2168  self->FreeData();
2169 
2170  declManagerLocal.MediaPrint( "parsing %s %s\n", declManagerLocal.declTypes[type]->typeName.c_str(), name.c_str() );
2171 
2172  // if no text source try to generate default text
2173  if ( textSource == NULL ) {
2174  generatedDefaultText = self->SetDefaultText();
2175  }
2176 
2177  // indent for DEFAULTED or media file references
2178  declManagerLocal.indent++;
2179 
2180  // no text immediately causes a MakeDefault()
2181  if ( textSource == NULL ) {
2182  MakeDefault();
2183  declManagerLocal.indent--;
2184  return;
2185  }
2186 
2187  declState = DS_PARSED;
2188 
2189  // parse
2190  char *declText = (char *) _alloca( ( GetTextLength() + 1 ) * sizeof( char ) );
2191  GetText( declText );
2192  self->Parse( declText, GetTextLength() );
2193 
2194  // free generated text
2195  if ( generatedDefaultText ) {
2196  Mem_Free( textSource );
2197  textSource = 0;
2198  textLength = 0;
2199  }
2200 
2201  declManagerLocal.indent--;
2202 }
2203 
2204 /*
2205 =================
2206 idDeclLocal::Purge
2207 =================
2208 */
2209 void idDeclLocal::Purge( void ) {
2210  // never purge things that were referenced outside level load,
2211  // like the console and menu graphics
2212  if ( parsedOutsideLevelLoad ) {
2213  return;
2214  }
2215 
2216  referencedThisLevel = false;
2217  MakeDefault();
2218 
2219  // the next Find() for this will re-parse the real data
2221 }
2222 
2223 /*
2224 =================
2225 idDeclLocal::EverReferenced
2226 =================
2227 */
2228 bool idDeclLocal::EverReferenced( void ) const {
2229  return everReferenced;
2230 }
virtual void Init(void)
idDeclFile * sourceFile
void BeginWriting(void)
Definition: BitMsg.h:265
struct huffmanNode_s * children[2]
virtual idFile * OpenFileRead(const char *relativePath, bool allowCopyFiles=true, const char *gamedir=NULL)=0
virtual void GetText(char *text) const
int GetReadCount(void) const
Definition: BitMsg.h:231
static idCVar decl_show
idList< idDeclFile * > loadedFiles
int LoadAndParse()
virtual idFileList * ListFiles(const char *relativePath, const char *extension, bool sort=false, bool fullRelativePath=false, const char *gamedir=NULL)=0
assert(prefInfo.fullscreenBtn)
idDeclLocal * FindTypeWithoutParsing(declType_t type, const char *name, bool makeDefault=true)
declState_t declState
virtual bool SourceFileChanged(void) const
int Next(const int index) const
Definition: HashIndex.h:247
void ToLower(void)
Definition: Str.h:817
bool redefinedInReload
const int DECL_LEXER_FLAGS
Definition: DeclManager.h:93
void SetTextLocal(const char *text, const int length)
virtual void SetText(const char *text)
void Remove(const int key, const int index)
Definition: HashIndex.h:213
GLenum GLsizei GLenum format
Definition: glext.h:2846
virtual int Index(void) const
virtual void virtual void WritePrecacheCommands(idFile *f)
virtual const idDecl * DeclByIndex(declType_t type, int index, bool forceParse=true)
int sourceTextLength
virtual bool RenameDecl(declType_t type, const char *oldName, const char *newName)
idDeclManagerLocal declManagerLocal
void Purge(void)
ID_INLINE T Max(T x, T y)
Definition: Lib.h:158
#define const
Definition: getdate.c:251
virtual int ReadFile(const char *relativePath, void **buffer, ID_TIME_T *timestamp=NULL)=0
int Length(void) const
Definition: Str.h:702
int GetNumFiles(void) const
Definition: FileSystem.h:126
void AssureSize(int newSize)
Definition: List.h:445
GLenum GLsizei n
Definition: glext.h:3705
case const int
Definition: Callbacks.cpp:52
virtual void Reload(bool force)
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
declType_t
Definition: DeclManager.h:65
int SkipBracedSection(bool parseFirstBrace=true)
Definition: Lexer.cpp:1134
static void TouchDecl_f(const idCmdArgs &args)
ID_TIME_T timestamp
declType_t defaultType
Definition: DeclManager.cpp:78
virtual const char * GetFileName(void) const
virtual const idDeclSkin * SkinByIndex(int index, bool forceParse=true)
virtual void BeginLevelLoad()
bool everReferenced
static void ListDecls_f(const idCmdArgs &args)
huffmanNode_t * InsertHuffmanNode(huffmanNode_t *firstNode, huffmanNode_t *node)
declType_t type
Definition: DeclManager.cpp:70
GLuint GLuint GLsizei GLenum type
Definition: glext.h:2845
idCmdSystem * cmdSystem
Definition: CmdSystem.cpp:116
Definition: Token.h:71
void SetFlags(int flags)
Definition: Lexer.h:298
virtual const idDecl * FindType(declType_t type, const char *name, bool makeDefault=true)
GLuint src
Definition: glext.h:5390
GLdouble right
Definition: qgl.h:273
void BuildHuffmanCode_r(huffmanNode_t *node, huffmanCode_t code, huffmanCode_t codes[MAX_HUFFMAN_SYMBOLS])
void AllocateSelf(void)
idList< idDeclFolder * > declFolders
virtual declState_t GetState(void) const
char * textSource
int compressedLength
virtual int GetLineNum(void) const
int i
Definition: process.py:33
void SetupHuffman(void)
struct nodetype * next
Definition: Compressor.cpp:813
GLuint GLuint num
Definition: glext.h:5390
Boolean result
void Free(void)
Definition: HashIndex.cpp:75
virtual size_t Size(void) const
int Icmp(const char *text) const
Definition: Str.h:667
idDecl * self
void ListHuffmanFrequencies_f(const idCmdArgs &args)
virtual bool Parse(const char *text, const int textLength)
idStr & BackSlashesToSlashes(void)
Definition: Str.cpp:727
void Init(byte *data, int length)
Definition: BitMsg.h:155
virtual void EndLevelLoad()
const int GetFileOffset(void)
Definition: Lexer.h:286
virtual const idDeclSkin * FindSkin(const char *name, bool makeDefault=true)
virtual const char * DefaultDefinition(void) const
Definition: File.h:50
const int GetLineNum(void)
Definition: Lexer.h:294
Definition: Lexer.h:137
declType_t type
bool parsedOutsideLevelLoad
virtual void MediaPrint(const char *fmt,...) id_attribute((format(printf
GLuint GLuint GLsizei count
Definition: glext.h:2845
virtual void FreeData(void)
virtual const idMaterial * FindMaterial(const char *name, bool makeDefault=true)
idDeclType * GetDeclType(int type) const
virtual idDecl * CreateNewDecl(declType_t type, const char *name, const char *fileName)
GLuint index
Definition: glext.h:3476
const GLubyte * c
Definition: glext.h:4677
unsigned long bits[8]
virtual void EnsureNotPurged(void)
#define MAX_STRING_CHARS
Definition: Lib.h:95
virtual void FreeData(void)
Definition: DeclManager.h:220
bool referencedThisLevel
virtual bool IsValid(void) const
idCommon * common
Definition: Common.cpp:206
int GetSize(void) const
Definition: BitMsg.h:187
#define NULL
Definition: Lib.h:88
void BeginReading(void) const
Definition: BitMsg.h:346
virtual int GetNumDecls(declType_t type)
void LittleRevBytes(void *bp, int elsize, int elcount)
Definition: Lib.cpp:285
declState_t
Definition: DeclManager.h:87
GLuint buffer
Definition: glext.h:3108
virtual void MakeDefault(void)
int GetInteger(void) const
Definition: CVarSystem.h:143
void FreeHuffmanTree_r(huffmanNode_t *node)
idDeclLocal * nextInFile
struct huffmanNode_s * next
size_t Size(void) const
Definition: List.h:242
virtual void virtual void FatalError(const char *fmt,...) id_attribute((format(printf
virtual idFile * OpenFileWrite(const char *relativePath, const char *basePath="fs_savepath")=0
const char * GetFile(int index) const
Definition: FileSystem.h:127
struct huffmanNode_s huffmanNode_t
virtual int Read(void *buffer, int len)
Definition: File.cpp:179
virtual const char * GetName(void) const
virtual void Print(void) const
Definition: DeclManager.h:233
int Argc(void) const
Definition: CmdArgs.h:48
void DeleteContents(bool clear)
Definition: List.h:207
void SetSize(int size)
Definition: BitMsg.h:191
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
virtual const idDecl * FindDeclWithoutParsing(declType_t type, const char *name, bool makeDefault=true)
int HuffmanDecompressText(char *text, int textLength, const byte *compressed, int compressedSize)
virtual void FreeFileList(idFileList *fileList)=0
void UnreadToken(const idToken *token)
Definition: Lexer.cpp:1159
virtual declType_t GetType(void) const
virtual void Printf(const char *fmt,...) id_attribute((format(printf
int LoadMemory(const char *ptr, int length, const char *name, int startLine=1)
Definition: Lexer.cpp:1646
unsigned long MD5_BlockChecksum(const void *data, int length)
Definition: MD5.cpp:260
virtual void ListType(const idCmdArgs &args, declType_t type)
virtual ID_TIME_T Timestamp(void)
Definition: File.cpp:208
GLenum GLsizei GLsizei height
Definition: glext.h:2856
idDeclManager * declManager
int GenerateKey(const char *string, bool caseSensitive=true) const
Definition: HashIndex.h:379
void ParseLocal(void)
virtual void Print(void) const
int HuffmanHeight_r(huffmanNode_t *node)
virtual void List(void) const
virtual void SetMute(bool mute)=0
virtual const idSoundShader * SoundByIndex(int index, bool forceParse=true)
idList< idDeclType * > declTypes
int Append(const type &obj)
Definition: List.h:646
void void Warning(const char *str,...) id_attribute((format(printf
Definition: Lexer.cpp:241
idList< idDeclLocal * > linearLists[DECL_MAX_TYPES]
int HuffmanCompressText(const char *text, int textLength, byte *compressed, int maxCompressedSize)
int c_savedMemory
#define id_attribute(x)
Definition: sys_public.h:139
virtual void RegisterDeclFolder(const char *folder, const char *extension, declType_t defaultType)
virtual void Reload(void)
static int static int vsnPrintf(char *dest, int size, const char *fmt, va_list argptr)
Definition: Str.cpp:1502
tuple f
Definition: idal.py:89
int Num(void) const
Definition: List.h:265
declType_t defaultType
unsigned char byte
Definition: Lib.h:75
const int MAX_HUFFMAN_SYMBOLS
const GLcharARB * name
Definition: glext.h:3629
GLsizeiptr size
Definition: glext.h:3112
idSoundSystem * soundSystem
Definition: snd_system.cpp:92
virtual void Invalidate(void)
virtual const idMaterial * MaterialByIndex(int index, bool forceParse=true)
virtual int Write(const void *buffer, int len)
Definition: File.cpp:189
virtual void PrintType(const idCmdArgs &args, declType_t type)
Definition: Str.h:116
GLsizei const GLcharARB const GLint * length
Definition: glext.h:3599
idDeclLocal * decls
friend class idDeclLocal
virtual ~idDeclLocal()
Definition: DeclManager.cpp:89
const char * listDeclStrings[]
virtual bool SetDefaultText(void)
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
const char * c_str(void) const
Definition: Str.h:487
int SkipUntilString(const char *string)
Definition: Lexer.cpp:1097
GLsizei maxLength
Definition: glext.h:3627
void Reload(bool force)
idDeclBase * base
Definition: DeclManager.h:236
virtual bool EverReferenced(void) const
idStr typeName
Definition: DeclManager.cpp:69
const char * Argv(int arg) const
Definition: CmdArgs.h:50
idHashIndex hashTables[DECL_MAX_TYPES]
virtual bool ReplaceSourceFileText(void)
void Add(const int key, const int index)
Definition: HashIndex.h:193
void * Mem_Alloc(const int size)
Definition: Heap.cpp:1067
virtual const char * GetDeclNameFromType(declType_t type) const
GLint j
Definition: qgl.h:264
const idDeclFile * GetImplicitDeclFile(void) const
virtual void ReloadFile(const char *filename, bool force)
virtual bool IsImplicit(void) const
void WriteBits(int value, int numBits)
Definition: BitMsg.cpp:110
virtual void CloseFile(idFile *f)=0
virtual int GetNumDeclTypes(void) const
virtual void DPrintf(const char *fmt,...) id_attribute((format(printf
virtual void RegisterDeclType(const char *typeName, declType_t type, idDecl *(*allocator)(void))
virtual void Error(const char *fmt,...) id_attribute((format(printf
idDeclFile implicitDecls
idStr fileName
virtual const idSoundShader * FindSound(const char *name, bool makeDefault=true)
virtual int GetTextLength(void) const
virtual void virtual void Warning(const char *fmt,...) id_attribute((format(printf
static void MakeNameCanonical(const char *name, char *result, int maxLength)
virtual const char * DefaultDefinition(void) const
Definition: DeclManager.h:207
int ReadToken(idToken *token)
Definition: Lexer.cpp:820
virtual void List(void) const
Definition: DeclManager.h:228
int ReadBits(int numBits) const
Definition: BitMsg.cpp:362
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
void ClearHuffmanFrequencies(void)
virtual declType_t GetDeclTypeFromName(const char *typeName) const
int sourceTextOffset
virtual int Printf(const char *fmt,...) id_attribute((format(printf
Definition: File.cpp:260
virtual int Length(void)
Definition: File.cpp:199
virtual void Shutdown(void)
void ShutdownHuffman(void)
virtual void AddCommand(const char *cmdName, cmdFunction_t function, int flags, const char *description, argCompletion_t argCompletion=NULL)=0
virtual int GetChecksum(void) const
struct huffmanCode_s huffmanCode_t
idDecl *(* allocator)(void)
Definition: DeclManager.cpp:71
static void ReloadDecls_f(const idCmdArgs &args)
void Clear(void)
Definition: List.h:184