w_wad.cpp (9973B)
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 "Precompiled.h" 30 #include "globaldata.h" 31 32 33 #include <ctype.h> 34 #include <sys/types.h> 35 #include <string.h> 36 #include <fcntl.h> 37 #include <sys/stat.h> 38 #include <vector> 39 40 #include "doomtype.h" 41 #include "m_swap.h" 42 #include "i_system.h" 43 #include "z_zone.h" 44 45 #include "idlib/precompiled.h" 46 47 #ifdef __GNUG__ 48 #pragma implementation "w_wad.h" 49 #endif 50 #include "w_wad.h" 51 52 53 54 // 55 // GLOBALS 56 // 57 58 lumpinfo_t* lumpinfo = NULL; 59 int numlumps; 60 void** lumpcache; 61 62 63 64 int filelength (FILE* handle) 65 { 66 // DHM - not used :: development tool (loading single lump not in a WAD file) 67 return 0; 68 } 69 70 71 void 72 ExtractFileBase 73 ( const char* path, 74 char* dest ) 75 { 76 const char* src; 77 int length; 78 79 src = path + strlen(path) - 1; 80 81 // back up until a \ or the start 82 while (src != path 83 && *(src-1) != '\\' 84 && *(src-1) != '/') 85 { 86 src--; 87 } 88 89 // copy up to eight characters 90 memset (dest,0,8); 91 length = 0; 92 93 while (*src && *src != '.') 94 { 95 if (++length == 9) 96 I_Error ("Filename base of %s >8 chars",path); 97 98 *dest++ = toupper((int)*src++); 99 } 100 } 101 102 103 104 105 106 // 107 // LUMP BASED ROUTINES. 108 // 109 110 // 111 // W_AddFile 112 // All files are optional, but at least one file must be 113 // found (PWAD, if all required lumps are present). 114 // Files with a .wad extension are wadlink files 115 // with multiple lumps. 116 // Other files are single lumps with the base filename 117 // for the lump name. 118 // 119 // If filename starts with a tilde, the file is handled 120 // specially to allow map reloads. 121 // But: the reload feature is a fragile hack... 122 123 const char* reloadname; 124 125 126 void W_AddFile ( const char *filename) 127 { 128 wadinfo_t header; 129 lumpinfo_t* lump_p; 130 int i; 131 idFile * handle; 132 int length; 133 int startlump; 134 std::vector<filelump_t> fileinfo( 1 ); 135 136 // open the file and add to directory 137 if ( (handle = fileSystem->OpenFileRead(filename)) == 0) 138 { 139 I_Printf (" couldn't open %s\n",filename); 140 return; 141 } 142 143 I_Printf (" adding %s\n",filename); 144 startlump = numlumps; 145 146 if ( idStr::Icmp( filename+strlen(filename)-3 , "wad" ) ) 147 { 148 // single lump file 149 fileinfo[0].filepos = 0; 150 fileinfo[0].size = 0; 151 ExtractFileBase (filename, fileinfo[0].name); 152 numlumps++; 153 } 154 else 155 { 156 // WAD file 157 handle->Read( &header, sizeof( header ) ); 158 if ( idStr::Cmpn( header.identification,"IWAD",4 ) ) 159 { 160 // Homebrew levels? 161 if ( idStr::Cmpn( header.identification, "PWAD", 4 ) ) 162 { 163 I_Error ("Wad file %s doesn't have IWAD " 164 "or PWAD id\n", filename); 165 } 166 167 // ???modifiedgame = true; 168 } 169 header.numlumps = LONG(header.numlumps); 170 header.infotableofs = LONG(header.infotableofs); 171 length = header.numlumps*sizeof(filelump_t); 172 fileinfo.resize(header.numlumps); 173 handle->Seek( header.infotableofs, FS_SEEK_SET ); 174 handle->Read( &fileinfo[0], length ); 175 numlumps += header.numlumps; 176 } 177 178 179 // Fill in lumpinfo 180 if (lumpinfo == NULL) { 181 lumpinfo = (lumpinfo_t*)malloc( numlumps*sizeof(lumpinfo_t) ); 182 } else { 183 lumpinfo = (lumpinfo_t*)realloc( lumpinfo, numlumps*sizeof(lumpinfo_t) ); 184 } 185 186 if (!lumpinfo) 187 I_Error ("Couldn't realloc lumpinfo"); 188 189 lump_p = &lumpinfo[startlump]; 190 191 ::g->wadFileHandles[ ::g->numWadFiles++ ] = handle; 192 193 filelump_t * filelumpPointer = &fileinfo[0]; 194 for (i=startlump ; i<numlumps ; i++,lump_p++, filelumpPointer++) 195 { 196 lump_p->handle = handle; 197 lump_p->position = LONG(filelumpPointer->filepos); 198 lump_p->size = LONG(filelumpPointer->size); 199 strncpy (lump_p->name, filelumpPointer->name, 8); 200 } 201 } 202 203 204 205 206 // 207 // W_Reload 208 // Flushes any of the reloadable lumps in memory 209 // and reloads the directory. 210 // 211 void W_Reload (void) 212 { 213 // DHM - unused development tool 214 } 215 216 // 217 // W_FreeLumps 218 // Frees all lump data 219 // 220 void W_FreeLumps() { 221 if ( lumpcache != NULL ) { 222 for ( int i = 0; i < numlumps; i++ ) { 223 if ( lumpcache[i] ) { 224 Z_Free( lumpcache[i] ); 225 } 226 } 227 228 Z_Free( lumpcache ); 229 lumpcache = NULL; 230 } 231 232 if ( lumpinfo != NULL ) { 233 free( lumpinfo ); 234 lumpinfo = NULL; 235 numlumps = 0; 236 } 237 } 238 239 // 240 // W_FreeWadFiles 241 // Free this list of wad files so that a new list can be created 242 // 243 void W_FreeWadFiles() { 244 for (int i = 0 ; i < MAXWADFILES ; i++) { 245 wadfiles[i] = NULL; 246 if ( ::g->wadFileHandles[i] ) { 247 delete ::g->wadFileHandles[i]; 248 } 249 ::g->wadFileHandles[i] = NULL; 250 } 251 ::g->numWadFiles = 0; 252 extraWad = 0; 253 } 254 255 256 257 // 258 // W_InitMultipleFiles 259 // Pass a null terminated list of files to use. 260 // All files are optional, but at least one file 261 // must be found. 262 // Files with a .wad extension are idlink files 263 // with multiple lumps. 264 // Other files are single lumps with the base filename 265 // for the lump name. 266 // Lump names can appear multiple times. 267 // The name searcher looks backwards, so a later file 268 // does override all earlier ones. 269 // 270 void W_InitMultipleFiles (const char** filenames) 271 { 272 int size; 273 274 if (lumpinfo == NULL) 275 { 276 // open all the files, load headers, and count lumps 277 numlumps = 0; 278 279 // will be realloced as lumps are added 280 lumpinfo = NULL; 281 282 for ( ; *filenames ; filenames++) 283 { 284 W_AddFile (*filenames); 285 } 286 287 if (!numlumps) 288 I_Error ("W_InitMultipleFiles: no files found"); 289 290 // set up caching 291 size = numlumps * sizeof(*lumpcache); 292 lumpcache = (void**)DoomLib::Z_Malloc(size, PU_STATIC_SHARED, 0 ); 293 294 if (!lumpcache) 295 I_Error ("Couldn't allocate lumpcache"); 296 297 memset (lumpcache,0, size); 298 } else { 299 // set up caching 300 size = numlumps * sizeof(*lumpcache); 301 lumpcache = (void**)DoomLib::Z_Malloc(size, PU_STATIC_SHARED, 0 ); 302 303 if (!lumpcache) 304 I_Error ("Couldn't allocate lumpcache"); 305 306 memset (lumpcache,0, size); 307 } 308 } 309 310 311 void W_Shutdown( void ) { 312 /* 313 for (int i = 0 ; i < MAXWADFILES ; i++) { 314 if ( ::g->wadFileHandles[i] ) { 315 doomFiles->FClose( ::g->wadFileHandles[i] ); 316 } 317 } 318 319 if ( lumpinfo != NULL ) { 320 free( lumpinfo ); 321 lumpinfo = NULL; 322 } 323 */ 324 W_FreeLumps(); 325 W_FreeWadFiles(); 326 } 327 328 // 329 // W_NumLumps 330 // 331 int W_NumLumps (void) 332 { 333 return numlumps; 334 } 335 336 337 338 // 339 // W_CheckNumForName 340 // Returns -1 if name not found. 341 // 342 343 int W_CheckNumForName (const char* name) 344 { 345 const int NameLength = 9; 346 347 union { 348 char s[NameLength]; 349 int x[2]; 350 351 } name8; 352 353 int v1; 354 int v2; 355 lumpinfo_t* lump_p; 356 357 // make the name into two integers for easy compares 358 strncpy (name8.s,name, NameLength - 1); 359 360 // in case the name was a fill 8 chars 361 name8.s[NameLength - 1] = 0; 362 363 // case insensitive 364 for ( int i = 0; i < NameLength; ++i ) { 365 name8.s[i] = toupper( name8.s[i] ); 366 } 367 368 v1 = name8.x[0]; 369 v2 = name8.x[1]; 370 371 372 // scan backwards so patch lump files take precedence 373 lump_p = lumpinfo + numlumps; 374 375 while (lump_p-- != lumpinfo) 376 { 377 if ( *(int *)lump_p->name == v1 378 && *(int *)&lump_p->name[4] == v2) 379 { 380 return lump_p - lumpinfo; 381 } 382 } 383 384 // TFB. Not found. 385 return -1; 386 } 387 388 389 390 391 // 392 // W_GetNumForName 393 // Calls W_CheckNumForName, but bombs out if not found. 394 // 395 int W_GetNumForName ( const char* name) 396 { 397 int i; 398 399 i = W_CheckNumForName ( name); 400 401 if (i == -1) 402 I_Error ("W_GetNumForName: %s not found!", name); 403 404 return i; 405 } 406 407 408 // 409 // W_LumpLength 410 // Returns the buffer size needed to load the given lump. 411 // 412 int W_LumpLength (int lump) 413 { 414 if (lump >= numlumps) 415 I_Error ("W_LumpLength: %i >= numlumps",lump); 416 417 return lumpinfo[lump].size; 418 } 419 420 421 422 // 423 // W_ReadLump 424 // Loads the lump into the given buffer, 425 // which must be >= W_LumpLength(). 426 // 427 void 428 W_ReadLump 429 ( int lump, 430 void* dest ) 431 { 432 int c; 433 lumpinfo_t* l; 434 idFile * handle; 435 436 if (lump >= numlumps) 437 I_Error ("W_ReadLump: %i >= numlumps",lump); 438 439 l = lumpinfo+lump; 440 441 handle = l->handle; 442 443 handle->Seek( l->position, FS_SEEK_SET ); 444 c = handle->Read( dest, l->size ); 445 446 if (c < l->size) 447 I_Error ("W_ReadLump: only read %i of %i on lump %i", c,l->size,lump); 448 } 449 450 451 452 453 // 454 // W_CacheLumpNum 455 // 456 void* 457 W_CacheLumpNum 458 ( int lump, 459 int tag ) 460 { 461 #ifdef RANGECHECK 462 if (lump >= numlumps) 463 I_Error ("W_CacheLumpNum: %i >= numlumps",lump); 464 #endif 465 466 if (!lumpcache[lump]) 467 { 468 byte* ptr; 469 // read the lump in 470 //I_Printf ("cache miss on lump %i\n",lump); 471 ptr = (byte*)DoomLib::Z_Malloc(W_LumpLength (lump), tag, &lumpcache[lump]); 472 W_ReadLump (lump, lumpcache[lump]); 473 } 474 475 return lumpcache[lump]; 476 } 477 478 479 480 // 481 // W_CacheLumpName 482 // 483 void* 484 W_CacheLumpName 485 ( const char* name, 486 int tag ) 487 { 488 return W_CacheLumpNum (W_GetNumForName(name), tag); 489 } 490 491 492 void W_Profile (void) 493 { 494 } 495 496 497