w_wad.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. // Emacs style mode select -*- C++ -*-
  2. //-----------------------------------------------------------------------------
  3. //
  4. // $Id:$
  5. //
  6. // Copyright (C) 1993-1996 by id Software, Inc.
  7. //
  8. // This source is available for distribution and/or modification
  9. // only under the terms of the DOOM Source Code License as
  10. // published by id Software. All rights reserved.
  11. //
  12. // The source is distributed in the hope that it will be useful,
  13. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
  15. // for more details.
  16. //
  17. // $Log:$
  18. //
  19. // DESCRIPTION:
  20. // Handles WAD file header, directory, lump I/O.
  21. //
  22. //-----------------------------------------------------------------------------
  23. static const char
  24. rcsid[] = "$Id: w_wad.c,v 1.5 1997/02/03 16:47:57 b1 Exp $";
  25. #ifdef NORMALUNIX
  26. #include <ctype.h>
  27. #include <sys/types.h>
  28. #include <string.h>
  29. #include <unistd.h>
  30. #include <malloc.h>
  31. #include <fcntl.h>
  32. #include <sys/stat.h>
  33. #include <alloca.h>
  34. #define O_BINARY 0
  35. #endif
  36. #include "doomtype.h"
  37. #include "m_swap.h"
  38. #include "i_system.h"
  39. #include "z_zone.h"
  40. #ifdef __GNUG__
  41. #pragma implementation "w_wad.h"
  42. #endif
  43. #include "w_wad.h"
  44. //
  45. // GLOBALS
  46. //
  47. // Location of each lump on disk.
  48. lumpinfo_t* lumpinfo;
  49. int numlumps;
  50. void** lumpcache;
  51. #define strcmpi strcasecmp
  52. void strupr (char* s)
  53. {
  54. while (*s) { *s = toupper(*s); s++; }
  55. }
  56. int filelength (int handle)
  57. {
  58. struct stat fileinfo;
  59. if (fstat (handle,&fileinfo) == -1)
  60. I_Error ("Error fstating");
  61. return fileinfo.st_size;
  62. }
  63. void
  64. ExtractFileBase
  65. ( char* path,
  66. char* dest )
  67. {
  68. char* src;
  69. int length;
  70. src = path + strlen(path) - 1;
  71. // back up until a \ or the start
  72. while (src != path
  73. && *(src-1) != '\\'
  74. && *(src-1) != '/')
  75. {
  76. src--;
  77. }
  78. // copy up to eight characters
  79. memset (dest,0,8);
  80. length = 0;
  81. while (*src && *src != '.')
  82. {
  83. if (++length == 9)
  84. I_Error ("Filename base of %s >8 chars",path);
  85. *dest++ = toupper((int)*src++);
  86. }
  87. }
  88. //
  89. // LUMP BASED ROUTINES.
  90. //
  91. //
  92. // W_AddFile
  93. // All files are optional, but at least one file must be
  94. // found (PWAD, if all required lumps are present).
  95. // Files with a .wad extension are wadlink files
  96. // with multiple lumps.
  97. // Other files are single lumps with the base filename
  98. // for the lump name.
  99. //
  100. // If filename starts with a tilde, the file is handled
  101. // specially to allow map reloads.
  102. // But: the reload feature is a fragile hack...
  103. int reloadlump;
  104. char* reloadname;
  105. void W_AddFile (char *filename)
  106. {
  107. wadinfo_t header;
  108. lumpinfo_t* lump_p;
  109. unsigned i;
  110. int handle;
  111. int length;
  112. int startlump;
  113. filelump_t* fileinfo;
  114. filelump_t singleinfo;
  115. int storehandle;
  116. // open the file and add to directory
  117. // handle reload indicator.
  118. if (filename[0] == '~')
  119. {
  120. filename++;
  121. reloadname = filename;
  122. reloadlump = numlumps;
  123. }
  124. if ( (handle = open (filename,O_RDONLY | O_BINARY)) == -1)
  125. {
  126. printf (" couldn't open %s\n",filename);
  127. return;
  128. }
  129. printf (" adding %s\n",filename);
  130. startlump = numlumps;
  131. if (strcmpi (filename+strlen(filename)-3 , "wad" ) )
  132. {
  133. // single lump file
  134. fileinfo = &singleinfo;
  135. singleinfo.filepos = 0;
  136. singleinfo.size = LONG(filelength(handle));
  137. ExtractFileBase (filename, singleinfo.name);
  138. numlumps++;
  139. }
  140. else
  141. {
  142. // WAD file
  143. read (handle, &header, sizeof(header));
  144. if (strncmp(header.identification,"IWAD",4))
  145. {
  146. // Homebrew levels?
  147. if (strncmp(header.identification,"PWAD",4))
  148. {
  149. I_Error ("Wad file %s doesn't have IWAD "
  150. "or PWAD id\n", filename);
  151. }
  152. // ???modifiedgame = true;
  153. }
  154. header.numlumps = LONG(header.numlumps);
  155. header.infotableofs = LONG(header.infotableofs);
  156. length = header.numlumps*sizeof(filelump_t);
  157. fileinfo = alloca (length);
  158. lseek (handle, header.infotableofs, SEEK_SET);
  159. read (handle, fileinfo, length);
  160. numlumps += header.numlumps;
  161. }
  162. // Fill in lumpinfo
  163. lumpinfo = realloc (lumpinfo, numlumps*sizeof(lumpinfo_t));
  164. if (!lumpinfo)
  165. I_Error ("Couldn't realloc lumpinfo");
  166. lump_p = &lumpinfo[startlump];
  167. storehandle = reloadname ? -1 : handle;
  168. for (i=startlump ; i<numlumps ; i++,lump_p++, fileinfo++)
  169. {
  170. lump_p->handle = storehandle;
  171. lump_p->position = LONG(fileinfo->filepos);
  172. lump_p->size = LONG(fileinfo->size);
  173. strncpy (lump_p->name, fileinfo->name, 8);
  174. }
  175. if (reloadname)
  176. close (handle);
  177. }
  178. //
  179. // W_Reload
  180. // Flushes any of the reloadable lumps in memory
  181. // and reloads the directory.
  182. //
  183. void W_Reload (void)
  184. {
  185. wadinfo_t header;
  186. int lumpcount;
  187. lumpinfo_t* lump_p;
  188. unsigned i;
  189. int handle;
  190. int length;
  191. filelump_t* fileinfo;
  192. if (!reloadname)
  193. return;
  194. if ( (handle = open (reloadname,O_RDONLY | O_BINARY)) == -1)
  195. I_Error ("W_Reload: couldn't open %s",reloadname);
  196. read (handle, &header, sizeof(header));
  197. lumpcount = LONG(header.numlumps);
  198. header.infotableofs = LONG(header.infotableofs);
  199. length = lumpcount*sizeof(filelump_t);
  200. fileinfo = alloca (length);
  201. lseek (handle, header.infotableofs, SEEK_SET);
  202. read (handle, fileinfo, length);
  203. // Fill in lumpinfo
  204. lump_p = &lumpinfo[reloadlump];
  205. for (i=reloadlump ;
  206. i<reloadlump+lumpcount ;
  207. i++,lump_p++, fileinfo++)
  208. {
  209. if (lumpcache[i])
  210. Z_Free (lumpcache[i]);
  211. lump_p->position = LONG(fileinfo->filepos);
  212. lump_p->size = LONG(fileinfo->size);
  213. }
  214. close (handle);
  215. }
  216. //
  217. // W_InitMultipleFiles
  218. // Pass a null terminated list of files to use.
  219. // All files are optional, but at least one file
  220. // must be found.
  221. // Files with a .wad extension are idlink files
  222. // with multiple lumps.
  223. // Other files are single lumps with the base filename
  224. // for the lump name.
  225. // Lump names can appear multiple times.
  226. // The name searcher looks backwards, so a later file
  227. // does override all earlier ones.
  228. //
  229. void W_InitMultipleFiles (char** filenames)
  230. {
  231. int size;
  232. // open all the files, load headers, and count lumps
  233. numlumps = 0;
  234. // will be realloced as lumps are added
  235. lumpinfo = malloc(1);
  236. for ( ; *filenames ; filenames++)
  237. W_AddFile (*filenames);
  238. if (!numlumps)
  239. I_Error ("W_InitFiles: no files found");
  240. // set up caching
  241. size = numlumps * sizeof(*lumpcache);
  242. lumpcache = malloc (size);
  243. if (!lumpcache)
  244. I_Error ("Couldn't allocate lumpcache");
  245. memset (lumpcache,0, size);
  246. }
  247. //
  248. // W_InitFile
  249. // Just initialize from a single file.
  250. //
  251. void W_InitFile (char* filename)
  252. {
  253. char* names[2];
  254. names[0] = filename;
  255. names[1] = NULL;
  256. W_InitMultipleFiles (names);
  257. }
  258. //
  259. // W_NumLumps
  260. //
  261. int W_NumLumps (void)
  262. {
  263. return numlumps;
  264. }
  265. //
  266. // W_CheckNumForName
  267. // Returns -1 if name not found.
  268. //
  269. int W_CheckNumForName (char* name)
  270. {
  271. union {
  272. char s[9];
  273. int x[2];
  274. } name8;
  275. int v1;
  276. int v2;
  277. lumpinfo_t* lump_p;
  278. // make the name into two integers for easy compares
  279. strncpy (name8.s,name,8);
  280. // in case the name was a fill 8 chars
  281. name8.s[8] = 0;
  282. // case insensitive
  283. strupr (name8.s);
  284. v1 = name8.x[0];
  285. v2 = name8.x[1];
  286. // scan backwards so patch lump files take precedence
  287. lump_p = lumpinfo + numlumps;
  288. while (lump_p-- != lumpinfo)
  289. {
  290. if ( *(int *)lump_p->name == v1
  291. && *(int *)&lump_p->name[4] == v2)
  292. {
  293. return lump_p - lumpinfo;
  294. }
  295. }
  296. // TFB. Not found.
  297. return -1;
  298. }
  299. //
  300. // W_GetNumForName
  301. // Calls W_CheckNumForName, but bombs out if not found.
  302. //
  303. int W_GetNumForName (char* name)
  304. {
  305. int i;
  306. i = W_CheckNumForName (name);
  307. if (i == -1)
  308. I_Error ("W_GetNumForName: %s not found!", name);
  309. return i;
  310. }
  311. //
  312. // W_LumpLength
  313. // Returns the buffer size needed to load the given lump.
  314. //
  315. int W_LumpLength (int lump)
  316. {
  317. if (lump >= numlumps)
  318. I_Error ("W_LumpLength: %i >= numlumps",lump);
  319. return lumpinfo[lump].size;
  320. }
  321. //
  322. // W_ReadLump
  323. // Loads the lump into the given buffer,
  324. // which must be >= W_LumpLength().
  325. //
  326. void
  327. W_ReadLump
  328. ( int lump,
  329. void* dest )
  330. {
  331. int c;
  332. lumpinfo_t* l;
  333. int handle;
  334. if (lump >= numlumps)
  335. I_Error ("W_ReadLump: %i >= numlumps",lump);
  336. l = lumpinfo+lump;
  337. // ??? I_BeginRead ();
  338. if (l->handle == -1)
  339. {
  340. // reloadable file, so use open / read / close
  341. if ( (handle = open (reloadname,O_RDONLY | O_BINARY)) == -1)
  342. I_Error ("W_ReadLump: couldn't open %s",reloadname);
  343. }
  344. else
  345. handle = l->handle;
  346. lseek (handle, l->position, SEEK_SET);
  347. c = read (handle, dest, l->size);
  348. if (c < l->size)
  349. I_Error ("W_ReadLump: only read %i of %i on lump %i",
  350. c,l->size,lump);
  351. if (l->handle == -1)
  352. close (handle);
  353. // ??? I_EndRead ();
  354. }
  355. //
  356. // W_CacheLumpNum
  357. //
  358. void*
  359. W_CacheLumpNum
  360. ( int lump,
  361. int tag )
  362. {
  363. byte* ptr;
  364. if ((unsigned)lump >= numlumps)
  365. I_Error ("W_CacheLumpNum: %i >= numlumps",lump);
  366. if (!lumpcache[lump])
  367. {
  368. // read the lump in
  369. //printf ("cache miss on lump %i\n",lump);
  370. ptr = Z_Malloc (W_LumpLength (lump), tag, &lumpcache[lump]);
  371. W_ReadLump (lump, lumpcache[lump]);
  372. }
  373. else
  374. {
  375. //printf ("cache hit on lump %i\n",lump);
  376. Z_ChangeTag (lumpcache[lump],tag);
  377. }
  378. return lumpcache[lump];
  379. }
  380. //
  381. // W_CacheLumpName
  382. //
  383. void*
  384. W_CacheLumpName
  385. ( char* name,
  386. int tag )
  387. {
  388. return W_CacheLumpNum (W_GetNumForName(name), tag);
  389. }
  390. //
  391. // W_Profile
  392. //
  393. int info[2500][10];
  394. int profilecount;
  395. void W_Profile (void)
  396. {
  397. int i;
  398. memblock_t* block;
  399. void* ptr;
  400. char ch;
  401. FILE* f;
  402. int j;
  403. char name[9];
  404. for (i=0 ; i<numlumps ; i++)
  405. {
  406. ptr = lumpcache[i];
  407. if (!ptr)
  408. {
  409. ch = ' ';
  410. continue;
  411. }
  412. else
  413. {
  414. block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
  415. if (block->tag < PU_PURGELEVEL)
  416. ch = 'S';
  417. else
  418. ch = 'P';
  419. }
  420. info[i][profilecount] = ch;
  421. }
  422. profilecount++;
  423. f = fopen ("waddump.txt","w");
  424. name[8] = 0;
  425. for (i=0 ; i<numlumps ; i++)
  426. {
  427. memcpy (name,lumpinfo[i].name,8);
  428. for (j=0 ; j<8 ; j++)
  429. if (!name[j])
  430. break;
  431. for ( ; j<8 ; j++)
  432. name[j] = ' ';
  433. fprintf (f,"%s ",name);
  434. for (j=0 ; j<profilecount ; j++)
  435. fprintf (f," %c",info[i][j]);
  436. fprintf (f,"\n");
  437. }
  438. fclose (f);
  439. }