]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/framework/DeclManager.cpp
hello world
[icculus/iodoom3.git] / neo / framework / DeclManager.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 /*
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:
69         idStr                                           typeName;
70         declType_t                                      type;
71         idDecl *                                        (*allocator)( void );
72 };
73
74 class idDeclFolder {
75 public:
76         idStr                                           folder;
77         idStr                                           extension;
78         declType_t                                      defaultType;
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:
165         idStr                                           fileName;
166         declType_t                                      defaultType;
167
168         ID_TIME_T                                               timestamp;
169         int                                                     checksum;
170         int                                                     fileSize;
171         int                                                     numLines;
172
173         idDeclLocal *                           decls;
174 };
175
176 class idDeclManagerLocal : public idDeclManager {
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:
225         idList<idDeclType *>            declTypes;
226         idList<idDeclFolder *>          declFolders;
227
228         idList<idDeclFile *>            loadedFiles;
229         idHashIndex                                     hashTables[DECL_MAX_TYPES];
230         idList<idDeclLocal *>           linearLists[DECL_MAX_TYPES];
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
236         bool                                            insideLevelLoad;
237
238         static idCVar                           decl_show;
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
248 idDeclManagerLocal      declManagerLocal;
249 idDeclManager *         declManager = &declManagerLocal;
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;
263         int                                             frequency;
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 */
322 void ClearHuffmanFrequencies( void ) {
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 */
335 huffmanNode_t *InsertHuffmanNode( huffmanNode_t *firstNode, huffmanNode_t *node ) {
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 */
382 void FreeHuffmanTree_r( huffmanNode_t *node ) {
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 */
395 int HuffmanHeight_r( huffmanNode_t *node ) {
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 */
561 idDeclFile::idDeclFile() {
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 */
600 int c_savedMemory = 0;
601
602 int idDeclFile::LoadAndParse() {
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 */
791 void idDeclManagerLocal::Init( void ) {
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
802         ClearHuffmanFrequencies();
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 */
871 void idDeclManagerLocal::Shutdown( void ) {
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 */
921 void idDeclManagerLocal::BeginLevelLoad() {
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 */
940 void idDeclManagerLocal::EndLevelLoad() {
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 */
1029 int idDeclManagerLocal::GetChecksum( void ) const {
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 */
1073 int idDeclManagerLocal::GetNumDeclTypes( void ) const {
1074         return declTypes.Num();
1075 }
1076
1077 /*
1078 ===================
1079 idDeclManagerLocal::GetDeclNameFromType
1080 ===================
1081 */
1082 const char * idDeclManagerLocal::GetDeclNameFromType( declType_t type ) const {
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 */
1096 declType_t idDeclManagerLocal::GetDeclTypeFromName( const char *typeName ) const {
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 */
1178 int idDeclManagerLocal::GetNumDecls( declType_t type ) {
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 */
1228 void idDeclManagerLocal::ListType( const idCmdArgs &args, declType_t type ) {
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 */
1287 void idDeclManagerLocal::PrintType( const idCmdArgs &args, declType_t type ) {
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 */
1497 void idDeclManagerLocal::WritePrecacheCommands( idFile *f ) {
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 */
1557 void idDeclManagerLocal::MakeNameCanonical( const char *name, char *result, int maxLength ) {
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 */
1584 void idDeclManagerLocal::ListDecls_f( const idCmdArgs &args ) {
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 */
1631 void idDeclManagerLocal::ReloadDecls_f( const idCmdArgs &args ) {
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 */
1654 void idDeclManagerLocal::TouchDecl_f( const idCmdArgs &args ) {
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 */
1692 idDeclLocal *idDeclManagerLocal::FindTypeWithoutParsing( declType_t type, const char *name, bool makeDefault ) {
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;
1730         decl->parsedOutsideLevelLoad = !insideLevelLoad;
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 */
1753 idDeclLocal::idDeclLocal( void ) {
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;
1765         declState = DS_UNPARSED;
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 */
1787 declType_t idDeclLocal::GetType( void ) const {
1788         return type;
1789 }
1790
1791 /*
1792 =================
1793 idDeclLocal::GetState
1794 =================
1795 */
1796 declState_t idDeclLocal::GetState( void ) const {
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 */
1823 void idDeclLocal::Invalidate( void ) {
1824         declState = DS_UNPARSED;
1825 }
1826
1827 /*
1828 =================
1829 idDeclLocal::EnsureNotPurged
1830 =================
1831 */
1832 void idDeclLocal::EnsureNotPurged( void ) {
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
1881         HuffmanDecompressText( text, textLength, (byte *)textSource, compressedLength );
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
1929         compressedLength = length;
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 */
1942 bool idDeclLocal::ReplaceSourceFileText( void ) {
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 );
2004         fileSystem->ReadFile( GetFileName(), NULL, &sourceFile->timestamp );
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
2017         sourceTextLength = textLength;
2018
2019         return true;
2020 }
2021
2022 /*
2023 =================
2024 idDeclLocal::SourceFileChanged
2025 =================
2026 */
2027 bool idDeclLocal::SourceFileChanged( void ) const {
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 */
2049 void idDeclLocal::MakeDefault() {
2050         static int recursionLevel;
2051         const char *defaultText;
2052
2053         declManagerLocal.MediaPrint( "DEFAULTED\n" );
2054         declState = DS_DEFAULTED;
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 */
2083 bool idDeclLocal::SetDefaultText( void ) {
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 */
2116 void idDeclLocal::FreeData() {
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 */
2150 void idDeclLocal::AllocateSelf( void ) {
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 */
2162 void idDeclLocal::ParseLocal( void ) {
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
2220         declState = DS_UNPARSED;
2221 }
2222
2223 /*
2224 =================
2225 idDeclLocal::EverReferenced
2226 =================
2227 */
2228 bool idDeclLocal::EverReferenced( void ) const {
2229         return everReferenced;
2230 }