diff options
Diffstat (limited to 'src/w_wad.c')
-rw-r--r-- | src/w_wad.c | 476 |
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. | ||
64 | lumpinfo_t *lumpinfo; | ||
65 | int numlumps; // killough | ||
66 | |||
67 | void 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 | |||
99 | char *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 | ||
128 | static 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 | |||
217 | static 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 | |||
225 | static 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 | |||
282 | unsigned 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 | |||
316 | int (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 | |||
343 | void 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 | // | ||
369 | int 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 | // | ||
393 | wadfile_info_t *wadfiles=NULL; | ||
394 | |||
395 | size_t numwadfiles = 0; // CPhipps - size of the wadfiles array (dynamic, no limit) | ||
396 | |||
397 | void 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 | |||
431 | void 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 | // | ||
446 | int 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 | |||
459 | void 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 | |||