DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

DeclManager.cpp (70756B)


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