aboutsummaryrefslogtreecommitdiff
path: root/src/w_wad.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/w_wad.c')
-rw-r--r--src/w_wad.c476
1 files changed, 476 insertions, 0 deletions
diff --git a/src/w_wad.c b/src/w_wad.c
new file mode 100644
index 0000000..753a227
--- /dev/null
+++ b/src/w_wad.c
@@ -0,0 +1,476 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2001 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Handles WAD file header, directory, lump I/O.
31 *
32 *-----------------------------------------------------------------------------
33 */
34
35// use config.h if autoconf made one -- josh
36#ifdef HAVE_CONFIG_H
37#include "config.h"
38#endif
39#ifdef HAVE_UNISTD_H
40#include <unistd.h>
41#endif
42#ifdef _MSC_VER
43#include <stddef.h>
44#include <io.h>
45#endif
46#include <fcntl.h>
47
48#include "doomstat.h"
49#include "d_net.h"
50#include "doomtype.h"
51#include "i_system.h"
52
53#ifdef __GNUG__
54#pragma implementation "w_wad.h"
55#endif
56#include "w_wad.h"
57#include "lprintf.h"
58
59//
60// GLOBALS
61//
62
63// Location of each lump on disk.
64lumpinfo_t *lumpinfo;
65int numlumps; // killough
66
67void ExtractFileBase (const char *path, char *dest)
68{
69 const char *src = path + strlen(path) - 1;
70 int length;
71
72 // back up until a \ or the start
73 while (src != path && src[-1] != ':' // killough 3/22/98: allow c:filename
74 && *(src-1) != '\\'
75 && *(src-1) != '/')
76 {
77 src--;
78 }
79
80 // copy up to eight characters
81 memset(dest,0,8);
82 length = 0;
83
84 while ((*src) && (*src != '.') && (++length<9))
85 {
86 *dest++ = toupper(*src);
87 *src++;
88 }
89 /* cph - length check removed, just truncate at 8 chars.
90 * If there are 8 or more chars, we'll copy 8, and no zero termination
91 */
92}
93
94//
95// 1/18/98 killough: adds a default extension to a path
96// Note: Backslashes are treated specially, for MS-DOS.
97//
98
99char *AddDefaultExtension(char *path, const char *ext)
100{
101 char *p = path;
102 while (*p++);
103 while (p-->path && *p!='/' && *p!='\\')
104 if (*p=='.')
105 return path;
106 if (*ext!='.')
107 strcat(path,".");
108 return strcat(path,ext);
109}
110
111//
112// LUMP BASED ROUTINES.
113//
114
115//
116// W_AddFile
117// All files are optional, but at least one file must be
118// found (PWAD, if all required lumps are present).
119// Files with a .wad extension are wadlink files
120// with multiple lumps.
121// Other files are single lumps with the base filename
122// for the lump name.
123//
124// Reload hack removed by Lee Killough
125// CPhipps - source is an enum
126//
127// proff - changed using pointer to wadfile_info_t
128static void W_AddFile(wadfile_info_t *wadfile)
129// killough 1/31/98: static, const
130{
131 wadinfo_t header;
132 lumpinfo_t* lump_p;
133 unsigned i;
134 int length;
135 int startlump;
136 filelump_t *fileinfo, *fileinfo2free=NULL; //killough
137 filelump_t singleinfo;
138
139 // open the file and add to directory
140
141 wadfile->handle = open(wadfile->name,O_RDONLY | O_BINARY);
142
143#ifdef HAVE_NET
144 if (wadfile->handle == -1 && D_NetGetWad(wadfile->name)) // CPhipps
145 wadfile->handle = open(wadfile->name,O_RDONLY | O_BINARY);
146#endif
147
148 if (wadfile->handle == -1)
149 {
150 if ( strlen(wadfile->name)<=4 || // add error check -- killough
151 (strcasecmp(wadfile->name+strlen(wadfile->name)-4 , ".lmp" ) &&
152 strcasecmp(wadfile->name+strlen(wadfile->name)-4 , ".gwa" ) )
153 )
154 I_Error("W_AddFile: couldn't open %s",wadfile->name);
155 return;
156 }
157
158 //jff 8/3/98 use logical output routine
159 lprintf (LO_INFO," adding %s\n",wadfile->name);
160 startlump = numlumps;
161
162 if ( strlen(wadfile->name)<=4 ||
163 (
164 strcasecmp(wadfile->name+strlen(wadfile->name)-4,".wad") &&
165 strcasecmp(wadfile->name+strlen(wadfile->name)-4,".gwa")
166 )
167 )
168 {
169 // single lump file
170 fileinfo = &singleinfo;
171 singleinfo.filepos = 0;
172 singleinfo.size = LONG(I_Filelength(wadfile->handle));
173 ExtractFileBase(wadfile->name, singleinfo.name);
174 numlumps++;
175 }
176 else
177 {
178 // WAD file
179 I_Read(wadfile->handle, &header, sizeof(header));
180 if (strncmp(header.identification,"IWAD",4) &&
181 strncmp(header.identification,"PWAD",4))
182 I_Error("W_AddFile: Wad file %s doesn't have IWAD or PWAD id", wadfile->name);
183 header.numlumps = LONG(header.numlumps);
184 header.infotableofs = LONG(header.infotableofs);
185 length = header.numlumps*sizeof(filelump_t);
186 fileinfo2free = fileinfo = malloc(length); // killough
187 lseek(wadfile->handle, header.infotableofs, SEEK_SET);
188 I_Read(wadfile->handle, fileinfo, length);
189 numlumps += header.numlumps;
190 }
191
192 // Fill in lumpinfo
193 lumpinfo = realloc(lumpinfo, numlumps*sizeof(lumpinfo_t));
194
195 lump_p = &lumpinfo[startlump];
196
197 for (i=startlump ; (int)i<numlumps ; i++,lump_p++, fileinfo++)
198 {
199 lump_p->wadfile = wadfile; // killough 4/25/98
200 lump_p->position = LONG(fileinfo->filepos);
201 lump_p->size = LONG(fileinfo->size);
202 lump_p->li_namespace = ns_global; // killough 4/17/98
203 strncpy (lump_p->name, fileinfo->name, 8);
204 lump_p->source = wadfile->src; // Ty 08/29/98
205 }
206
207 free(fileinfo2free); // killough
208}
209
210// jff 1/23/98 Create routines to reorder the master directory
211// putting all flats into one marked block, and all sprites into another.
212// This will allow loading of sprites and flats from a PWAD with no
213// other changes to code, particularly fast hashes of the lumps.
214//
215// killough 1/24/98 modified routines to be a little faster and smaller
216
217static int IsMarker(const char *marker, const char *name)
218{
219 return !strncasecmp(name, marker, 8) ||
220 (*name == *marker && !strncasecmp(name+1, marker, 7));
221}
222
223// killough 4/17/98: add namespace tags
224
225static void W_CoalesceMarkedResource(const char *start_marker,
226 const char *end_marker, int li_namespace)
227{
228 lumpinfo_t *marked = malloc(sizeof(*marked) * numlumps);
229 size_t i, num_marked = 0, num_unmarked = 0;
230 int is_marked = 0, mark_end = 0;
231 lumpinfo_t *lump = lumpinfo;
232
233 for (i=numlumps; i--; lump++)
234 if (IsMarker(start_marker, lump->name)) // start marker found
235 { // If this is the first start marker, add start marker to marked lumps
236 if (!num_marked)
237 {
238 strncpy(marked->name, start_marker, 8);
239 marked->size = 0; // killough 3/20/98: force size to be 0
240 marked->li_namespace = ns_global; // killough 4/17/98
241 marked->wadfile = NULL;
242 num_marked = 1;
243 }
244 is_marked = 1; // start marking lumps
245 }
246 else
247 if (IsMarker(end_marker, lump->name)) // end marker found
248 {
249 mark_end = 1; // add end marker below
250 is_marked = 0; // stop marking lumps
251 }
252 else
253 if (is_marked) // if we are marking lumps,
254 { // move lump to marked list
255 marked[num_marked] = *lump;
256 marked[num_marked++].li_namespace = li_namespace; // killough 4/17/98
257 }
258 else
259 lumpinfo[num_unmarked++] = *lump; // else move down THIS list
260
261 // Append marked list to end of unmarked list
262 memcpy(lumpinfo + num_unmarked, marked, num_marked * sizeof(*marked));
263
264 free(marked); // free marked list
265
266 numlumps = num_unmarked + num_marked; // new total number of lumps
267
268 if (mark_end) // add end marker
269 {
270 lumpinfo[numlumps].size = 0; // killough 3/20/98: force size to be 0
271 lumpinfo[numlumps].wadfile = NULL;
272 lumpinfo[numlumps].li_namespace = ns_global; // killough 4/17/98
273 strncpy(lumpinfo[numlumps++].name, end_marker, 8);
274 }
275}
276
277// Hash function used for lump names.
278// Must be mod'ed with table size.
279// Can be used for any 8-character names.
280// by Lee Killough
281
282unsigned W_LumpNameHash(const char *s)
283{
284 unsigned hash;
285 (void) ((hash = toupper(s[0]), s[1]) &&
286 (hash = hash*3+toupper(s[1]), s[2]) &&
287 (hash = hash*2+toupper(s[2]), s[3]) &&
288 (hash = hash*2+toupper(s[3]), s[4]) &&
289 (hash = hash*2+toupper(s[4]), s[5]) &&
290 (hash = hash*2+toupper(s[5]), s[6]) &&
291 (hash = hash*2+toupper(s[6]),
292 hash = hash*2+toupper(s[7]))
293 );
294 return hash;
295}
296
297//
298// W_CheckNumForName
299// Returns -1 if name not found.
300//
301// Rewritten by Lee Killough to use hash table for performance. Significantly
302// cuts down on time -- increases Doom performance over 300%. This is the
303// single most important optimization of the original Doom sources, because
304// lump name lookup is used so often, and the original Doom used a sequential
305// search. For large wads with > 1000 lumps this meant an average of over
306// 500 were probed during every search. Now the average is under 2 probes per
307// search. There is no significant benefit to packing the names into longwords
308// with this new hashing algorithm, because the work to do the packing is
309// just as much work as simply doing the string comparisons with the new
310// algorithm, which minimizes the expected number of comparisons to under 2.
311//
312// killough 4/17/98: add namespace parameter to prevent collisions
313// between different resources such as flats, sprites, colormaps
314//
315
316int (W_CheckNumForName)(register const char *name, register int li_namespace)
317{
318 // Hash function maps the name to one of possibly numlump chains.
319 // It has been tuned so that the average chain length never exceeds 2.
320
321 // proff 2001/09/07 - check numlumps==0, this happens when called before WAD loaded
322 register int i = (numlumps==0)?(-1):(lumpinfo[W_LumpNameHash(name) % (unsigned) numlumps].index);
323
324 // We search along the chain until end, looking for case-insensitive
325 // matches which also match a namespace tag. Separate hash tables are
326 // not used for each namespace, because the performance benefit is not
327 // worth the overhead, considering namespace collisions are rare in
328 // Doom wads.
329
330 while (i >= 0 && (strncasecmp(lumpinfo[i].name, name, 8) ||
331 lumpinfo[i].li_namespace != li_namespace))
332 i = lumpinfo[i].next;
333
334 // Return the matching lump, or -1 if none found.
335
336 return i;
337}
338
339//
340// killough 1/31/98: Initialize lump hash table
341//
342
343void W_HashLumps(void)
344{
345 int i;
346
347 for (i=0; i<numlumps; i++)
348 lumpinfo[i].index = -1; // mark slots empty
349
350 // Insert nodes to the beginning of each chain, in first-to-last
351 // lump order, so that the last lump of a given name appears first
352 // in any chain, observing pwad ordering rules. killough
353
354 for (i=0; i<numlumps; i++)
355 { // hash function:
356 int j = W_LumpNameHash(lumpinfo[i].name) % (unsigned) numlumps;
357 lumpinfo[i].next = lumpinfo[j].index; // Prepend to list
358 lumpinfo[j].index = i;
359 }
360}
361
362// End of lump hashing -- killough 1/31/98
363
364
365
366// W_GetNumForName
367// Calls W_CheckNumForName, but bombs out if not found.
368//
369int W_GetNumForName (const char* name) // killough -- const added
370{
371 int i = W_CheckNumForName (name);
372 if (i == -1)
373 I_Error("W_GetNumForName: %.8s not found", name);
374 return i;
375}
376
377
378
379// W_Init
380// Loads each of the files in the wadfiles array.
381// All files are optional, but at least one file
382// must be found.
383// Files with a .wad extension are idlink files
384// with multiple lumps.
385// Other files are single lumps with the base filename
386// for the lump name.
387// Lump names can appear multiple times.
388// The name searcher looks backwards, so a later file
389// does override all earlier ones.
390//
391// CPhipps - modified to use the new wadfiles array
392//
393wadfile_info_t *wadfiles=NULL;
394
395size_t numwadfiles = 0; // CPhipps - size of the wadfiles array (dynamic, no limit)
396
397void W_Init(void)
398{
399 // CPhipps - start with nothing
400
401 numlumps = 0; lumpinfo = NULL;
402
403 { // CPhipps - new wadfiles array used
404 // open all the files, load headers, and count lumps
405 int i;
406 for (i=0; (size_t)i<numwadfiles; i++)
407 W_AddFile(&wadfiles[i]);
408 }
409
410 if (!numlumps)
411 I_Error ("W_Init: No files found");
412
413 //jff 1/23/98
414 // get all the sprites and flats into one marked block each
415 // killough 1/24/98: change interface to use M_START/M_END explicitly
416 // killough 4/17/98: Add namespace tags to each entry
417 // killough 4/4/98: add colormap markers
418 W_CoalesceMarkedResource("S_START", "S_END", ns_sprites);
419 W_CoalesceMarkedResource("F_START", "F_END", ns_flats);
420 W_CoalesceMarkedResource("C_START", "C_END", ns_colormaps);
421 W_CoalesceMarkedResource("B_START", "B_END", ns_prboom);
422
423 // killough 1/31/98: initialize lump hash table
424 W_HashLumps();
425
426 /* cph 2001/07/07 - separated cache setup */
427 lprintf(LO_INFO,"W_InitCache\n");
428 W_InitCache();
429}
430
431void W_ReleaseAllWads(void)
432{
433 W_DoneCache();
434 numwadfiles = 0;
435 free(wadfiles);
436 wadfiles = NULL;
437 numlumps = 0;
438 free(lumpinfo);
439 lumpinfo = NULL;
440}
441
442//
443// W_LumpLength
444// Returns the buffer size needed to load the given lump.
445//
446int W_LumpLength (int lump)
447{
448 if (lump >= numlumps)
449 I_Error ("W_LumpLength: %i >= numlumps",lump);
450 return lumpinfo[lump].size;
451}
452
453//
454// W_ReadLump
455// Loads the lump into the given buffer,
456// which must be >= W_LumpLength().
457//
458
459void W_ReadLump(int lump, void *dest)
460{
461 lumpinfo_t *l = lumpinfo + lump;
462
463#ifdef RANGECHECK
464 if (lump >= numlumps)
465 I_Error ("W_ReadLump: %i >= numlumps",lump);
466#endif
467
468 {
469 if (l->wadfile)
470 {
471 lseek(l->wadfile->handle, l->position, SEEK_SET);
472 I_Read(l->wadfile->handle, dest, l->size);
473 }
474 }
475}
476