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, ×tamp ); 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 }