1 //----------------------------------------------------------------------------
2 //  EDGE WAD Support Code
3 //----------------------------------------------------------------------------
4 //
5 //  Copyright (c) 1999-2009  The EDGE Team.
6 //
7 //  This program is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU General Public License
9 //  as published by the Free Software Foundation; either version 2
10 //  of the License, or (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //  GNU General Public License for more details.
16 //
17 //----------------------------------------------------------------------------
18 //
19 //  Based on the DOOM source code, released by Id Software under the
20 //  following copyright:
21 //
22 //    Copyright (C) 1993-1996 by id Software, Inc.
23 //
24 //----------------------------------------------------------------------------
25 //
26 // This file contains various levels of support for using sprites and
27 // flats directly from a PWAD as well as some minor optimisations for
28 // patches. Because there are some PWADs that do arcane things with
29 // sprites, it is possible that this feature may not always work (at
30 // least, not until I become aware of them and support them) and so
31 // this feature can be turned off from the command line if necessary.
32 //
33 // -MH- 1998/03/04
34 //
35 
36 #include "i_defs.h"
37 
38 #include <limits.h>
39 
40 #include <list>
41 
42 #include "epi/endianess.h"
43 #include "epi/file.h"
44 #include "epi/file_sub.h"
45 #include "epi/filesystem.h"
46 #include "epi/math_md5.h"
47 #include "epi/path.h"
48 #include "epi/str_format.h"
49 #include "epi/utility.h"
50 
51 #include "ddf/main.h"
52 #include "ddf/anim.h"
53 #include "ddf/colormap.h"
54 #include "ddf/font.h"
55 #include "ddf/image.h"
56 #include "ddf/style.h"
57 #include "ddf/switch.h"
58 
59 #include "dm_data.h"
60 #include "dm_defs.h"
61 #include "dm_state.h"
62 #include "dm_structs.h"
63 #include "dstrings.h"
64 #include "e_main.h"
65 #include "e_search.h"
66 #include "l_deh.h"
67 #include "l_glbsp.h"
68 #include "m_misc.h"
69 #include "r_image.h"
70 #include "rad_trig.h"
71 #include "vm_coal.h"
72 #include "w_wad.h"
73 #include "z_zone.h"
74 
75 // -KM- 1999/01/31 Order is important, Languages are loaded before sfx, etc...
76 typedef struct ddf_reader_s
77 {
78 	const char *name;
79 	const char *print_name;
80 	bool (* func)(void *data, int size);
81 }
82 ddf_reader_t;
83 
84 static ddf_reader_t DDF_Readers[] =
85 {
86 	{ "DDFLANG", "Languages",  DDF_ReadLangs },
87 	{ "DDFSFX",  "Sounds",     DDF_ReadSFX },
88 	{ "DDFCOLM", "ColourMaps", DDF_ReadColourMaps },  // -AJA- 1999/07/09.
89 	{ "DDFIMAGE","Images",     DDF_ReadImages },      // -AJA- 2004/11/18
90 	{ "DDFFONT", "Fonts",      DDF_ReadFonts },       // -AJA- 2004/11/13
91 	{ "DDFSTYLE","Styles",     DDF_ReadStyles },      // -AJA- 2004/11/14
92 	{ "DDFATK",  "Attacks",    DDF_ReadAtks },
93 	{ "DDFWEAP", "Weapons",    DDF_ReadWeapons },
94 	{ "DDFTHING","Things",     DDF_ReadThings },
95 	{ "DDFPLAY", "Playlists",  DDF_ReadMusicPlaylist },
96 	{ "DDFLINE", "Lines",      DDF_ReadLines },
97 	{ "DDFSECT", "Sectors",    DDF_ReadSectors },
98 	{ "DDFSWTH", "Switches",   DDF_ReadSwitch },
99 	{ "DDFANIM", "Anims",      DDF_ReadAnims },
100 	{ "DDFGAME", "Games",      DDF_ReadGames },
101 	{ "DDFLEVL", "Levels",     DDF_ReadLevels },
102 	{ "RSCRIPT", "RadTrig",    RAD_ReadScript }       // -AJA- 2000/04/21.
103 };
104 
105 #define NUM_DDF_READERS  (int)(sizeof(DDF_Readers) / sizeof(ddf_reader_t))
106 
107 #define LANG_READER  0
108 #define COLM_READER  2
109 #define SWTH_READER  12
110 #define ANIM_READER  13
111 #define RTS_READER   16
112 
113 class data_file_c
114 {
115 public:
116 	const char *file_name;
117 
118 	// type of file (FLKIND_XXX)
119 	int kind;
120 
121 	// file object
122     epi::file_c *file;
123 
124 	// lists for sprites, flats, patches (stuff between markers)
125 	epi::u32array_c sprite_lumps;
126 	epi::u32array_c flat_lumps;
127 	epi::u32array_c patch_lumps;
128 	epi::u32array_c colmap_lumps;
129 	epi::u32array_c tx_lumps;
130 	epi::u32array_c hires_lumps;
131 
132 	// level markers and skin markers
133 	epi::u32array_c level_markers;
134 	epi::u32array_c skin_markers;
135 
136 	// ddf lump list
137 	int ddf_lumps[NUM_DDF_READERS];
138 
139 	// texture information
140 	wadtex_resource_c wadtex;
141 
142 	// DeHackEd support
143 	int deh_lump;
144 
145 	// COAL scripts
146 	int coal_huds;
147 
148 	// BOOM stuff
149 	int animated, switches;
150 
151 	// file containing the GL nodes for the levels in this WAD.
152 	// -1 when none (usually when this WAD has no levels, but also
153 	// temporarily before a new GWA files has been built and added).
154 	int companion_gwa;
155 
156 	// MD5 hash of the contents of the WAD directory.
157 	// This is used to disambiguate cached GWA/HWA filenames.
158 	epi::md5hash_c dir_hash;
159 
160 public:
data_file_c(const char * _fname,int _kind,epi::file_c * _file)161 	data_file_c(const char *_fname, int _kind, epi::file_c* _file) :
162 		file_name(_fname), kind(_kind), file(_file),
163 		sprite_lumps(), flat_lumps(), patch_lumps(),
164 		colmap_lumps(), tx_lumps(), hires_lumps(),
165 		level_markers(), skin_markers(),
166 		wadtex(), deh_lump(-1), coal_huds(-1),
167 		animated(-1), switches(-1),
168 		companion_gwa(-1), dir_hash()
169 	{
170 		file_name = strdup(_fname);
171 
172 		for (int d = 0; d < NUM_DDF_READERS; d++)
173 			ddf_lumps[d] = -1;
174 	}
175 
~data_file_c()176 	~data_file_c()
177 	{
178 		free((void*)file_name);
179 	}
180 };
181 
182 static std::vector<data_file_c *> data_files;
183 
184 
185 // Raw filenames
186 class raw_filename_c
187 {
188 public:
189 	std::string filename;
190 	int kind;
191 
192 public:
raw_filename_c(const char * _name,int _kind)193 	raw_filename_c(const char *_name, int _kind) :
194 			 filename(_name), kind(_kind)
195 	{ }
196 
~raw_filename_c()197 	~raw_filename_c()
198 	{ }
199 };
200 
201 static std::list<raw_filename_c *> wadfiles;
202 
203 
204 typedef enum
205 {
206 	LMKIND_Normal = 0,  // fallback value
207 	LMKIND_Marker = 3,  // X_START, X_END, S_SKIN, level name
208 	LMKIND_WadTex = 6,  // palette, pnames, texture1/2
209 	LMKIND_DDFRTS = 10, // DDF, RTS, DEHACKED lump
210 	LMKIND_TX     = 14,
211 	LMKIND_Colmap = 15,
212 	LMKIND_Flat   = 16,
213 	LMKIND_Sprite = 17,
214 	LMKIND_Patch  = 18,
215 	LMKIND_HiRes  = 19
216 }
217 lump_kind_e;
218 
219 typedef struct
220 {
221 	char name[10];
222 	int position;
223 	int size;
224 
225 	// file number (an index into data_files[]).
226 	short file;
227 
228 	// value used when sorting.  When lumps have the same name, the one
229 	// with the highest sort_index is used (W_CheckNumForName).  This is
230 	// closely related to the `file' field, with some tweaks for
231 	// handling GWA files (especially dynamic ones).
232 	short sort_index;
233 
234 	// one of the LMKIND values.  For sorting, this is the least
235 	// significant aspect (but still necessary).
236 	short kind;
237 }
238 lumpinfo_t;
239 
240 // Create the start and end markers
241 
242 //
243 //  GLOBALS
244 //
245 
246 // Location of each lump on disk.
247 lumpinfo_t *lumpinfo;
248 static int *lumpmap = NULL;
249 int numlumps;
250 
251 #define LUMP_MAP_CMP(a) (strncmp(lumpinfo[lumpmap[a]].name, buf, 8))
252 
253 
254 typedef struct lumpheader_s
255 {
256 #ifdef DEVELOPERS
257 	static const int LUMPID = (int)0xAC45197e;
258 
259 	int id;  // Should be LUMPID
260 #endif
261 
262 	// number of users.
263 	int users;
264 
265 	// index in lumplookup
266 	int lumpindex;
267 	struct lumpheader_s *next, *prev;
268 }
269 lumpheader_t;
270 
271 static lumpheader_t **lumplookup;
272 static lumpheader_t lumphead;
273 
274 // number of freeable bytes in cache (excluding headers).
275 // Used to decide how many bytes we should flush.
276 static int cache_size = 0;
277 
278 // the first datafile which contains a PLAYPAL lump
279 static int palette_datafile = -1;
280 
281 // Sprites & Flats
282 static bool within_sprite_list;
283 static bool within_flat_list;
284 static bool within_patch_list;
285 static bool within_colmap_list;
286 static bool within_tex_list;
287 static bool within_hires_list;
288 
289 byte *W_ReadLumpAlloc(int lump, int *length);
290 
291 //
292 // Is the name a sprite list start flag?
293 // If lax syntax match, fix up to standard syntax.
294 //
IsS_START(char * name)295 static bool IsS_START(char *name)
296 {
297 	if (strncmp(name, "SS_START", 8) == 0)
298 	{
299 		// fix up flag to standard syntax
300 		// Note: strncpy will pad will nulls
301 		strncpy(name, "S_START", 8);
302 		return 1;
303 	}
304 
305 	return (strncmp(name, "S_START", 8) == 0);
306 }
307 
308 //
309 // Is the name a sprite list end flag?
310 // If lax syntax match, fix up to standard syntax.
311 //
IsS_END(char * name)312 static bool IsS_END(char *name)
313 {
314 	if (strncmp(name, "SS_END", 8) == 0)
315 	{
316 		// fix up flag to standard syntax
317 		strncpy(name, "S_END", 8);
318 		return 1;
319 	}
320 
321 	return (strncmp(name, "S_END", 8) == 0);
322 }
323 
324 //
325 // Is the name a flat list start flag?
326 // If lax syntax match, fix up to standard syntax.
327 //
IsF_START(char * name)328 static bool IsF_START(char *name)
329 {
330 	if (strncmp(name, "FF_START", 8) == 0)
331 	{
332 		// fix up flag to standard syntax
333 		strncpy(name, "F_START", 8);
334 		return 1;
335 	}
336 
337 	return (strncmp(name, "F_START", 8) == 0);
338 }
339 
340 //
341 // Is the name a flat list end flag?
342 // If lax syntax match, fix up to standard syntax.
343 //
IsF_END(char * name)344 static bool IsF_END(char *name)
345 {
346 	if (strncmp(name, "FF_END", 8) == 0)
347 	{
348 		// fix up flag to standard syntax
349 		strncpy(name, "F_END", 8);
350 		return 1;
351 	}
352 
353 	return (strncmp(name, "F_END", 8) == 0);
354 }
355 
356 //
357 // Is the name a patch list start flag?
358 // If lax syntax match, fix up to standard syntax.
359 //
IsP_START(char * name)360 static bool IsP_START(char *name)
361 {
362 	if (strncmp(name, "PP_START", 8) == 0)
363 	{
364 		// fix up flag to standard syntax
365 		strncpy(name, "P_START", 8);
366 		return 1;
367 	}
368 
369 	return (strncmp(name, "P_START", 8) == 0);
370 }
371 
372 //
373 // Is the name a patch list end flag?
374 // If lax syntax match, fix up to standard syntax.
375 //
IsP_END(char * name)376 static bool IsP_END(char *name)
377 {
378 	if (strncmp(name, "PP_END", 8) == 0)
379 	{
380 		// fix up flag to standard syntax
381 		strncpy(name, "P_END", 8);
382 		return 1;
383 	}
384 
385 	return (strncmp(name, "P_END", 8) == 0);
386 }
387 
388 //
389 // Is the name a colourmap list start/end flag?
390 //
IsC_START(char * name)391 static bool IsC_START(char *name)
392 {
393 	return (strncmp(name, "C_START", 8) == 0);
394 }
395 
IsC_END(char * name)396 static bool IsC_END(char *name)
397 {
398 	return (strncmp(name, "C_END", 8) == 0);
399 }
400 
401 //
402 // Is the name a texture list start/end flag?
403 //
IsTX_START(char * name)404 static bool IsTX_START(char *name)
405 {
406 	return (strncmp(name, "TX_START", 8) == 0);
407 }
408 
IsTX_END(char * name)409 static bool IsTX_END(char *name)
410 {
411 	return (strncmp(name, "TX_END", 8) == 0);
412 }
413 
414 //
415 // Is the name a high-resolution start/end flag?
416 //
IsHI_START(char * name)417 static bool IsHI_START(char *name)
418 {
419 	return (strncmp(name, "HI_START", 8) == 0);
420 }
421 
IsHI_END(char * name)422 static bool IsHI_END(char *name)
423 {
424 	return (strncmp(name, "HI_END", 8) == 0);
425 }
426 
427 //
428 // Is the name a dummy sprite/flat/patch marker ?
429 //
IsDummySF(const char * name)430 static bool IsDummySF(const char *name)
431 {
432 	return (strncmp(name, "S1_START", 8) == 0 ||
433 			strncmp(name, "S2_START", 8) == 0 ||
434 			strncmp(name, "S3_START", 8) == 0 ||
435 			strncmp(name, "F1_START", 8) == 0 ||
436 			strncmp(name, "F2_START", 8) == 0 ||
437 			strncmp(name, "F3_START", 8) == 0 ||
438 			strncmp(name, "P1_START", 8) == 0 ||
439 			strncmp(name, "P2_START", 8) == 0 ||
440 			strncmp(name, "P3_START", 8) == 0);
441 }
442 
443 //
444 // Is the name a skin specifier ?
445 //
IsSkin(const char * name)446 static bool IsSkin(const char *name)
447 {
448 	return (strncmp(name, "S_SKIN", 6) == 0);
449 }
450 
IsGL_Prefix(const char * name)451 static inline bool IsGL_Prefix(const char *name)
452 {
453 	return name[0] == 'G' && name[1] == 'L' && name[2] == '_';
454 }
455 
456 //
457 // W_GetTextureLumps
458 //
W_GetTextureLumps(int file,wadtex_resource_c * res)459 void W_GetTextureLumps(int file, wadtex_resource_c *res)
460 {
461 	SYS_ASSERT(0 <= file && file < (int)data_files.size());
462 	SYS_ASSERT(res);
463 
464 	data_file_c *df = data_files[file];
465 
466 	res->palette  = df->wadtex.palette;
467 	res->pnames   = df->wadtex.pnames;
468 	res->texture1 = df->wadtex.texture1;
469 	res->texture2 = df->wadtex.texture2;
470 
471 	// find an earlier PNAMES lump when missing.
472 	// Ditto for palette.
473 
474 	if (res->texture1 >= 0 || res->texture2 >= 0)
475 	{
476 		int cur;
477 
478 		for (cur=file; res->pnames == -1 && cur > 0; cur--)
479 			res->pnames = data_files[cur]->wadtex.pnames;
480 
481 		for (cur=file; res->palette == -1 && cur > 0; cur--)
482 			res->palette = data_files[cur]->wadtex.palette;
483 	}
484 }
485 
486 //
487 // SortLumps
488 //
489 // Create the lumpmap[] array, which is sorted by name for fast
490 // searching.  It also makes sure that entries with the same name all
491 // refer to the same lump (prefering lumps in later WADs over those in
492 // earlier ones).
493 //
494 // -AJA- 2000/10/14: simplified.
495 //
SortLumps(void)496 static void SortLumps(void)
497 {
498 	int i;
499 
500 	Z_Resize(lumpmap, int, numlumps);
501 
502 	for (i = 0; i < numlumps; i++)
503 		lumpmap[i] = i;
504 
505 	// sort it, primarily by increasing name, secondly by decreasing
506 	// file number, thirdly by the lump type.
507 
508 #define CMP(a, b)  \
509     (strncmp(lumpinfo[a].name, lumpinfo[b].name, 8) < 0 ||    \
510      (strncmp(lumpinfo[a].name, lumpinfo[b].name, 8) == 0 &&  \
511       (lumpinfo[a].sort_index > lumpinfo[b].sort_index ||     \
512 	   (lumpinfo[a].sort_index == lumpinfo[b].sort_index &&   \
513         lumpinfo[a].kind > lumpinfo[b].kind))))
514 	QSORT(int, lumpmap, numlumps, CUTOFF);
515 #undef CMP
516 
517 #if 0
518 	for (i=1; i < numlumps; i++)
519 	{
520 		int a = lumpmap[i - 1];
521 		int b = lumpmap[i];
522 
523 		if (strncmp(lumpinfo[a].name, lumpinfo[b].name, 8) == 0)
524 			lumpmap[i] = lumpmap[i - 1];
525 	}
526 #endif
527 }
528 
529 //
530 // SortSpriteLumps
531 //
532 // Put the sprite list in sorted order (of name), required by
533 // R_InitSprites (speed optimisation).
534 //
SortSpriteLumps(data_file_c * df)535 static void SortSpriteLumps(data_file_c *df)
536 {
537 	if (df->sprite_lumps.GetSize() < 2)
538 		return;
539 
540 #define CMP(a, b) (strncmp(lumpinfo[a].name, lumpinfo[b].name, 8) < 0)
541 	QSORT(int, df->sprite_lumps, df->sprite_lumps.GetSize(), CUTOFF);
542 #undef CMP
543 
544 #if 0  // DEBUGGING
545 	{
546 		int i, lump;
547 
548 		for (i=0; i < f->sprite_num; i++)
549 		{
550 			lump = f->sprite_lumps[i];
551 
552 			I_Debugf("Sorted sprite %d = lump %d [%s]\n", i, lump,
553 						 lumpinfo[lump].name);
554 		}
555 	}
556 #endif
557 }
558 
559 
560 //
561 // LUMP BASED ROUTINES.
562 //
563 
564 //
565 // W_AddFile
566 //
567 // All files are optional, but at least one file must be
568 //  found (PWAD, if all required lumps are present).
569 // Files with a .wad extension are wadlink files
570 //  with multiple lumps.
571 // Other files are single lumps with the base filename
572 //  for the lump name.
573 //
574 
575 #if 0  // UNUSED ??
576 static void FreeLump(lumpheader_t *h)
577 {
578 	int lumpnum = h->lumpindex;
579 
580 	cache_size -= W_LumpLength(lumpnum);
581 #ifdef DEVELOPERS
582 	if (h->id != lumpheader_s::LUMPID)
583 		I_Error("FreeLump: id != LUMPID");
584 	h->id = 0;
585 	if (h == NULL)
586 		I_Error("FreeLump: NULL lump");
587 	if (h->users)
588 		I_Error("FreeLump: lump %d has %d users!", lumpnum, h->users);
589 	if (lumplookup[lumpnum] != h)
590 		I_Error("FreeLump: Internal error, lump %d", lumpnum);
591 #endif
592 	lumplookup[lumpnum] = NULL;
593 	h->prev->next = h->next;
594 	h->next->prev = h->prev;
595 	Z_Free(h);
596 }
597 #endif
598 
599 //
600 // MarkAsCached
601 //
MarkAsCached(lumpheader_t * item)602 static void MarkAsCached(lumpheader_t *item)
603 {
604 #ifdef DEVELOPERS
605 	if (item->id != lumpheader_s::LUMPID)
606 		I_Error("MarkAsCached: id != LUMPID");
607 	if (!item)
608 		I_Error("MarkAsCached: lump %d is NULL", item->lumpindex);
609 	if (item->users)
610 		I_Error("MarkAsCached: lump %d has %d users!", item->lumpindex, item->users);
611 	if (lumplookup[item->lumpindex] != item)
612 		I_Error("MarkAsCached: Internal error, lump %d", item->lumpindex);
613 #endif
614 
615 	cache_size += W_LumpLength(item->lumpindex);
616 }
617 
618 //
619 // AddLump
620 //
AddLump(data_file_c * df,int lump,int pos,int size,int file,int sort_index,const char * name,bool allow_ddf)621 static void AddLump(data_file_c *df, int lump, int pos, int size, int file,
622 					int sort_index, const char *name, bool allow_ddf)
623 {
624 	int j;
625 	lumpinfo_t *lump_p = lumpinfo + lump;
626 
627 	lump_p->position = pos;
628 	lump_p->size = size;
629 	lump_p->file = file;
630 	lump_p->sort_index = sort_index;
631 	lump_p->kind = LMKIND_Normal;
632 
633 	Z_StrNCpy(lump_p->name, name, 8);
634 	strupr(lump_p->name);
635 
636 	// -- handle special names --
637 
638 	if (strncmp(name, "PLAYPAL", 8) == 0)
639 	{
640 		lump_p->kind = LMKIND_WadTex;
641 		df->wadtex.palette = lump;
642 		if (palette_datafile < 0)
643 			palette_datafile = file;
644 		return;
645 	}
646 	else if (strncmp(name, "PNAMES", 8) == 0)
647 	{
648 		lump_p->kind = LMKIND_WadTex;
649 		df->wadtex.pnames = lump;
650 		return;
651 	}
652 	else if (strncmp(name, "TEXTURE1", 8) == 0)
653 	{
654 		lump_p->kind = LMKIND_WadTex;
655 		df->wadtex.texture1 = lump;
656 		return;
657 	}
658 	else if (strncmp(name, "TEXTURE2", 8) == 0)
659 	{
660 		lump_p->kind = LMKIND_WadTex;
661 		df->wadtex.texture2 = lump;
662 		return;
663 	}
664 	else if (strncmp(name, "DEHACKED", 8) == 0)
665 	{
666 		lump_p->kind = LMKIND_DDFRTS;
667 		df->deh_lump = lump;
668 		return;
669 	}
670 	else if (strncmp(name, "COALHUDS", 8) == 0)
671 	{
672 		lump_p->kind = LMKIND_DDFRTS;
673 		df->coal_huds = lump;
674 		return;
675 	}
676 	else if (strncmp(name, "ANIMATED", 8) == 0)
677 	{
678 		lump_p->kind = LMKIND_DDFRTS;
679 		df->animated = lump;
680 		return;
681 	}
682 	else if (strncmp(name, "SWITCHES", 8) == 0)
683 	{
684 		lump_p->kind = LMKIND_DDFRTS;
685 		df->switches = lump;
686 		return;
687 	}
688 
689 	// -KM- 1998/12/16 Load DDF/RSCRIPT file from wad.
690 	if (allow_ddf)
691 	{
692 		for (j=0; j < NUM_DDF_READERS; j++)
693 		{
694 			if (strncmp(name, DDF_Readers[j].name, 8) == 0)
695 			{
696 				lump_p->kind = LMKIND_DDFRTS;
697 				df->ddf_lumps[j] = lump;
698 				return;
699 			}
700 		}
701 	}
702 
703 	if (IsSkin(lump_p->name))
704 	{
705 		lump_p->kind = LMKIND_Marker;
706 		df->skin_markers.Insert(lump);
707 		return;
708 	}
709 
710 	// -- handle sprite, flat & patch lists --
711 
712 	if (IsS_START(lump_p->name))
713 	{
714 		lump_p->kind = LMKIND_Marker;
715 		within_sprite_list = true;
716 		return;
717 	}
718 	else if (IsS_END(lump_p->name))
719 	{
720 	  	if (!within_sprite_list)
721 			I_Warning("Unexpected S_END marker in wad.\n");
722 
723 		lump_p->kind = LMKIND_Marker;
724 		within_sprite_list = false;
725 		return;
726 	}
727 	else if (IsF_START(lump_p->name))
728 	{
729 		lump_p->kind = LMKIND_Marker;
730 		within_flat_list = true;
731 		return;
732 	}
733 	else if (IsF_END(lump_p->name))
734 	{
735 		if (!within_flat_list)
736 			I_Warning("Unexpected F_END marker in wad.\n");
737 
738 		lump_p->kind = LMKIND_Marker;
739 		within_flat_list = false;
740 		return;
741 	}
742 	else if (IsP_START(lump_p->name))
743 	{
744 		lump_p->kind = LMKIND_Marker;
745 		within_patch_list = true;
746 		return;
747 	}
748 	else if (IsP_END(lump_p->name))
749 	{
750 		if (!within_patch_list)
751 			I_Warning("Unexpected P_END marker in wad.\n");
752 
753 		lump_p->kind = LMKIND_Marker;
754 		within_patch_list = false;
755 		return;
756 	}
757 	else if (IsC_START(lump_p->name))
758 	{
759 		lump_p->kind = LMKIND_Marker;
760 		within_colmap_list = true;
761 		return;
762 	}
763 	else if (IsC_END(lump_p->name))
764 	{
765 		if (!within_colmap_list)
766 			I_Warning("Unexpected C_END marker in wad.\n");
767 
768 		lump_p->kind = LMKIND_Marker;
769 		within_colmap_list = false;
770 		return;
771 	}
772 	else if (IsTX_START(lump_p->name))
773 	{
774 		lump_p->kind = LMKIND_Marker;
775 		within_tex_list = true;
776 		return;
777 	}
778 	else if (IsTX_END(lump_p->name))
779 	{
780 		if (!within_tex_list)
781 			I_Warning("Unexpected TX_END marker in wad.\n");
782 
783 		lump_p->kind = LMKIND_Marker;
784 		within_tex_list = false;
785 		return;
786 	}
787 	else if (IsHI_START(lump_p->name))
788 	{
789 		lump_p->kind = LMKIND_Marker;
790 		within_hires_list = true;
791 		return;
792 	}
793 	else if (IsHI_END(lump_p->name))
794 	{
795 		if (!within_hires_list)
796 			I_Warning("Unexpected HI_END marker in wad.\n");
797 
798 		lump_p->kind = LMKIND_Marker;
799 		within_hires_list = false;
800 		return;
801 	}
802 
803 	// ignore zero size lumps or dummy markers
804 	if (lump_p->size > 0 && !IsDummySF(lump_p->name))
805 	{
806 		if (within_sprite_list)
807 		{
808 			lump_p->kind = LMKIND_Sprite;
809 			df->sprite_lumps.Insert(lump);
810 		}
811 
812 		if (within_flat_list)
813 		{
814 			lump_p->kind = LMKIND_Flat;
815 			df->flat_lumps.Insert(lump);
816 		}
817 
818 		if (within_patch_list)
819 		{
820 			lump_p->kind = LMKIND_Patch;
821 			df->patch_lumps.Insert(lump);
822 		}
823 
824 		if (within_colmap_list)
825 		{
826 			lump_p->kind = LMKIND_Colmap;
827 			df->colmap_lumps.Insert(lump);
828 		}
829 
830 		if (within_tex_list)
831 		{
832 			lump_p->kind = LMKIND_TX;
833 			df->tx_lumps.Insert(lump);
834 		}
835 
836 		if (within_hires_list)
837 		{
838 			lump_p->kind = LMKIND_HiRes;
839 			df->hires_lumps.Insert(lump);
840 		}
841 	}
842 }
843 
844 //
845 // CheckForLevel
846 //
847 // Tests whether the current lump is a level marker (MAP03, E1M7, etc).
848 // Because EDGE supports arbitrary names (via DDF), we look at the
849 // sequence of lumps _after_ this one, which works well since their
850 // order is fixed (e.g. THINGS is always first).
851 //
CheckForLevel(data_file_c * df,int lump,const char * name,const raw_wad_entry_t * raw,int remaining)852 static void CheckForLevel(data_file_c *df, int lump, const char *name,
853 	const raw_wad_entry_t *raw, int remaining)
854 {
855 	// we only test four lumps (it is enough), but fewer definitely
856 	// means this is not a level marker.
857 	if (remaining < 4)
858 		return;
859 
860 	if (strncmp(raw[1].name, "THINGS",   8) == 0 &&
861 	    strncmp(raw[2].name, "LINEDEFS", 8) == 0 &&
862 	    strncmp(raw[3].name, "SIDEDEFS", 8) == 0 &&
863 	    strncmp(raw[4].name, "VERTEXES", 8) == 0)
864 	{
865 		if (strlen(name) > 5)
866 		{
867 			I_Warning("Level name '%s' is too long !!\n", name);
868 			return;
869 		}
870 
871 		// check for duplicates (Slige sometimes does this)
872 		for (int L = 0; L < df->level_markers.GetSize(); L++)
873 		{
874 			if (strcmp(lumpinfo[df->level_markers[L]].name, name) == 0)
875 			{
876 				I_Warning("Duplicate level '%s' ignored.\n", name);
877 				return;
878 			}
879 		}
880 
881 		df->level_markers.Insert(lump);
882 		return;
883 	}
884 
885 	// handle GL nodes here too
886 
887 	if (strncmp(raw[1].name, "GL_VERT",  8) == 0 &&
888 	    strncmp(raw[2].name, "GL_SEGS",  8) == 0 &&
889 	    strncmp(raw[3].name, "GL_SSECT", 8) == 0 &&
890 	    strncmp(raw[4].name, "GL_NODES", 8) == 0)
891 	{
892 		df->level_markers.Insert(lump);
893 		return;
894 	}
895 }
896 
897 //
898 // HasInternalGLNodes
899 //
900 // Determine if WAD file contains GL nodes for every level.
901 //
HasInternalGLNodes(data_file_c * df,int datafile)902 static bool HasInternalGLNodes(data_file_c *df, int datafile)
903 {
904 	int levels  = 0;
905 	int glnodes = 0;
906 
907 	for (int L = 0; L < df->level_markers.GetSize(); L++)
908 	{
909 		int lump = df->level_markers[L];
910 
911 		if (IsGL_Prefix(lumpinfo[lump].name))
912 			continue;
913 
914 		levels++;
915 
916 		char gl_marker[10];
917 
918 		sprintf(gl_marker, "GL_%s", lumpinfo[lump].name);
919 
920 		for (int M = L+1; M < df->level_markers.GetSize(); M++)
921 		{
922 			int lump2 = df->level_markers[M];
923 
924 			if (strcmp(lumpinfo[lump2].name, gl_marker) == 0)
925 			{
926 				glnodes++;
927 				break;
928 			}
929 		}
930 	}
931 
932 	I_Debugf("Levels %d, Internal GL nodes %d\n", levels, glnodes);
933 
934 	return levels == glnodes;
935 }
936 
ComputeFileMD5hash(epi::md5hash_c & hash,epi::file_c * file)937 static void ComputeFileMD5hash(epi::md5hash_c& hash, epi::file_c *file)
938 {
939 	int length = file->GetLength();
940 
941 	if (length <= 0)
942 		return;
943 
944 	byte *buffer = new byte[length];
945 
946 	// TODO: handle Read failure
947 	file->Read(buffer, length);
948 
949 	hash.Compute(buffer, length);
950 
951 	delete[] buffer;
952 }
953 
FindCacheFilename(std::string & out_name,const char * filename,data_file_c * df,const char * extension)954 static bool FindCacheFilename (std::string& out_name,
955 		const char *filename, data_file_c *df,
956 		const char *extension)
957 {
958 	std::string wad_dir;
959 	std::string hash_string;
960 	std::string local_name;
961 	std::string cache_name;
962 
963 	// Get the directory which the wad is currently stored
964 	wad_dir = epi::PATH_GetDir(filename);
965 
966 	// Hash string used for files in the cache directory
967 	hash_string = epi::STR_Format("-%02X%02X%02X-%02X%02X%02X",
968 		df->dir_hash.hash[0], df->dir_hash.hash[1],
969 		df->dir_hash.hash[2], df->dir_hash.hash[3],
970 		df->dir_hash.hash[4], df->dir_hash.hash[5]);
971 
972 	// Determine the full path filename for "local" (same-directory) version
973 	local_name = epi::PATH_GetBasename(filename);
974 	local_name += (".");
975 	local_name += (extension);
976 
977 	local_name = epi::PATH_Join(wad_dir.c_str(), local_name.c_str());
978 
979 	// Determine the full path filename for the cached version
980 	cache_name = epi::PATH_GetBasename(filename);
981 	cache_name += (hash_string);
982 	cache_name += (".");
983 	cache_name += (extension);
984 
985 	cache_name = epi::PATH_Join(cache_dir.c_str(), cache_name.c_str());
986 
987 	I_Debugf("FindCacheFilename: local_name = '%s'\n", local_name.c_str());
988 	I_Debugf("FindCacheFilename: cache_name = '%s'\n", cache_name.c_str());
989 
990 	// Check for the existance of the local and cached dir files
991 	bool has_local = epi::FS_Access(local_name.c_str(), epi::file_c::ACCESS_READ);
992 	bool has_cache = epi::FS_Access(cache_name.c_str(), epi::file_c::ACCESS_READ);
993 
994 	// If both exist, use the local one.
995 	// If neither exist, create one in the cache directory.
996 
997 	// Check whether the waddir gwa is out of date
998 	if (has_local)
999 		has_local = (L_CompareFileTimes(filename, local_name.c_str()) <= 0);
1000 
1001 	// Check whether the cached gwa is out of date
1002 	if (has_cache)
1003 		has_cache = (L_CompareFileTimes(filename, cache_name.c_str()) <= 0);
1004 
1005 	I_Debugf("FindCacheFilename: has_local=%s  has_cache=%s\n",
1006 		has_local ? "YES" : "NO", has_cache ? "YES" : "NO");
1007 
1008 
1009 	if (has_local)
1010 	{
1011 		out_name = local_name;
1012 		return true;
1013 	}
1014 	else if (has_cache)
1015 	{
1016 		out_name = cache_name;
1017 		return true;
1018 	}
1019 
1020 	// Neither is valid so create one in the cached directory
1021 	out_name = cache_name;
1022 	return false;
1023 }
1024 
1025 //
1026 // AddFile
1027 //
1028 // -AJA- New `dyn_index' parameter -- this is for adding GWA files
1029 //       which have been built by the GLBSP plugin.  Nothing else is
1030 //       supported, e.g. wads with textures/sprites/DDF/RTS.
1031 //
1032 //       The dyn_index value is -1 for normal (non-dynamic) files,
1033 //       otherwise it is the sort_index for the lumps (typically the
1034 //       file number of the wad which the GWA is a companion for).
1035 //
AddFile(const char * filename,int kind,int dyn_index)1036 static void AddFile(const char *filename, int kind, int dyn_index)
1037 {
1038 	int j;
1039 	int length;
1040 	int startlump;
1041 
1042 	raw_wad_header_t header;
1043 	raw_wad_entry_t *curinfo;
1044 
1045 	// reset the sprite/flat/patch list stuff
1046 	within_sprite_list = within_flat_list   = false;
1047 	within_patch_list  = within_colmap_list = false;
1048 	within_tex_list    = within_hires_list  = false;
1049 
1050 	// open the file and add to directory
1051     epi::file_c *file = epi::FS_Open(filename, epi::file_c::ACCESS_READ | epi::file_c::ACCESS_BINARY);
1052 	if (file == NULL)
1053 	{
1054 		I_Error("Couldn't open file %s\n", filename);
1055 		return;
1056 	}
1057 
1058 	I_Printf("  Adding %s\n", filename);
1059 
1060 	startlump = numlumps;
1061 
1062 	int datafile = (int)data_files.size();
1063 
1064 	data_file_c *df = new data_file_c(filename, kind, file);
1065 	data_files.push_back(df);
1066 
1067 	// for RTS scripts, adding the data_file is enough
1068 	if (kind == FLKIND_RTS)
1069 		return;
1070 
1071 	if (kind <= FLKIND_HWad)
1072 	{
1073 		// WAD file
1074 		// TODO: handle Read failure
1075         file->Read(&header, sizeof(raw_wad_header_t));
1076 
1077 		if (strncmp(header.identification, "IWAD", 4) != 0)
1078 		{
1079 			// Homebrew levels?
1080 			if (strncmp(header.identification, "PWAD", 4) != 0)
1081 			{
1082 				I_Error("Wad file %s doesn't have IWAD or PWAD id\n", filename);
1083 			}
1084 		}
1085 
1086 		header.num_entries = EPI_LE_S32(header.num_entries);
1087 		header.dir_start = EPI_LE_S32(header.dir_start);
1088 
1089 		length = header.num_entries * sizeof(raw_wad_entry_t);
1090 
1091         raw_wad_entry_t *fileinfo = new raw_wad_entry_t[header.num_entries];
1092 
1093         file->Seek(header.dir_start, epi::file_c::SEEKPOINT_START);
1094 		// TODO: handle Read failure
1095         file->Read(fileinfo, length);
1096 
1097 		// compute MD5 hash over wad directory
1098 		df->dir_hash.Compute((const byte *)fileinfo, length);
1099 
1100 		// Fill in lumpinfo
1101 		numlumps += header.num_entries;
1102 		Z_Resize(lumpinfo, lumpinfo_t, numlumps);
1103 
1104 		for (j=startlump, curinfo=fileinfo; j < numlumps; j++,curinfo++)
1105 		{
1106 			AddLump(df, j, EPI_LE_S32(curinfo->pos), EPI_LE_S32(curinfo->size),
1107 					datafile,
1108                     (dyn_index >= 0) ? dyn_index : datafile,
1109 					curinfo->name,
1110 					(kind == FLKIND_PWad) || (kind == FLKIND_HWad) );
1111 
1112 			if (kind != FLKIND_HWad)
1113 				CheckForLevel(df, j, lumpinfo[j].name, curinfo, numlumps-1 - j);
1114 		}
1115 
1116 		delete[] fileinfo;
1117 	}
1118 	else  /* single lump file */
1119 	{
1120 		char lump_name[32];
1121 
1122 		SYS_ASSERT(dyn_index < 0);
1123 
1124 		if (kind == FLKIND_DDF)
1125         {
1126 			DDF_GetLumpNameForFile(filename, lump_name);
1127         }
1128         else
1129         {
1130             std::string base = epi::PATH_GetBasename(filename);
1131             if (base.size() > 8)
1132                 I_Error("Filename base of %s >8 chars", filename);
1133 
1134             strcpy(lump_name, base.c_str());
1135 			strupr(lump_name);    // Required to be uppercase
1136         }
1137 
1138 		// calculate MD5 hash over whole file
1139 		ComputeFileMD5hash(df->dir_hash, file);
1140 
1141 		// Fill in lumpinfo
1142 		numlumps++;
1143 		Z_Resize(lumpinfo, lumpinfo_t, numlumps);
1144 
1145 		AddLump(df, startlump, 0,
1146                 file->GetLength(), datafile, datafile,
1147 				lump_name, true);
1148 	}
1149 
1150 	I_Debugf("   md5hash = %02x%02x%02x%02x...%02x%02x%02x%02x\n",
1151 			df->dir_hash.hash[0], df->dir_hash.hash[1],
1152 			df->dir_hash.hash[2], df->dir_hash.hash[3],
1153 			df->dir_hash.hash[12], df->dir_hash.hash[13],
1154 			df->dir_hash.hash[14], df->dir_hash.hash[15]);
1155 
1156 	SortLumps();
1157 	SortSpriteLumps(df);
1158 
1159 	// set up caching
1160 	Z_Resize(lumplookup, lumpheader_t *, numlumps);
1161 
1162 	for (j=startlump; j < numlumps; j++)
1163 		lumplookup[j] = NULL;
1164 
1165 	// check for unclosed sprite/flat/patch lists
1166 	if (within_sprite_list)
1167 		I_Warning("Missing S_END marker in %s.\n", filename);
1168 
1169 	if (within_flat_list)
1170 		I_Warning("Missing F_END marker in %s.\n", filename);
1171 
1172 	if (within_patch_list)
1173 		I_Warning("Missing P_END marker in %s.\n", filename);
1174 
1175 	if (within_colmap_list)
1176 		I_Warning("Missing C_END marker in %s.\n", filename);
1177 
1178 	if (within_tex_list)
1179 		I_Warning("Missing TX_END marker in %s.\n", filename);
1180 
1181 	if (within_hires_list)
1182 		I_Warning("Missing HI_END marker in %s.\n", filename);
1183 
1184 	// -AJA- 1999/12/25: What did Santa bring EDGE ?  Just some support
1185 	//       for "GWA" files (part of the "GL-Friendly Nodes" specs).
1186 
1187 	if (kind <= FLKIND_EWad && df->level_markers.GetSize() > 0)
1188 	{
1189 		if (HasInternalGLNodes(df, datafile))
1190 		{
1191 		    df->companion_gwa = datafile;
1192 		}
1193 		else
1194 		{
1195 			SYS_ASSERT(dyn_index < 0);
1196 
1197 			std::string gwa_filename;
1198 
1199 			bool exists = FindCacheFilename(gwa_filename, filename, df, EDGEGWAEXT);
1200 
1201 			I_Debugf("Actual_GWA_filename: %s\n", gwa_filename.c_str());
1202 
1203 			if (! exists)
1204 			{
1205 				I_Printf("Building GL Nodes for: %s\n", filename);
1206 
1207 				if (! GB_BuildNodes(filename, gwa_filename.c_str()))
1208 					I_Error("Failed to build GL nodes for: %s\n", filename);
1209             }
1210 
1211 			// Load it.  This recursion bit is rather sneaky,
1212 			// hopefully it doesn't break anything...
1213 			AddFile(gwa_filename.c_str(), FLKIND_GWad, datafile);
1214 
1215 			df->companion_gwa = datafile + 1;
1216 		}
1217 	}
1218 
1219 	// handle DeHackEd patch files
1220 	if (kind == FLKIND_Deh || df->deh_lump >= 0)
1221 	{
1222 		std::string hwa_filename;
1223 
1224 		char base_name[64];
1225 		sprintf(base_name, "DEH_%04d.%s", datafile, EDGEHWAEXT);
1226 
1227 		hwa_filename = epi::PATH_Join(cache_dir.c_str(), base_name);
1228 
1229 		I_Debugf("Actual_HWA_filename: %s\n", hwa_filename.c_str());
1230 
1231 			if (kind == FLKIND_Deh)
1232 			{
1233                 I_Printf("Converting DEH file: %s\n", filename);
1234 
1235 				if (! DH_ConvertFile(filename, hwa_filename.c_str()))
1236 					I_Error("Failed to convert DeHackEd patch: %s\n", filename);
1237 			}
1238 			else
1239 			{
1240 				const char *lump_name = lumpinfo[df->deh_lump].name;
1241 
1242 				I_Printf("Converting [%s] lump in: %s\n", lump_name, filename);
1243 
1244 				const byte *data = (const byte *)W_CacheLumpNum(df->deh_lump);
1245 				int length = W_LumpLength(df->deh_lump);
1246 
1247 				if (! DH_ConvertLump(data, length, lump_name, hwa_filename.c_str()))
1248 					I_Error("Failed to convert DeHackEd LUMP in: %s\n", filename);
1249 
1250 				W_DoneWithLump(data);
1251 			}
1252 
1253 		// Load it (using good ol' recursion again).
1254 		AddFile(hwa_filename.c_str(), FLKIND_HWad, -1);
1255 	}
1256 }
1257 
InitCaches(void)1258 static void InitCaches(void)
1259 {
1260 	lumphead.next = lumphead.prev = &lumphead;
1261 }
1262 
1263 //
1264 // W_AddRawFilename
1265 //
W_AddRawFilename(const char * file,int kind)1266 void W_AddRawFilename(const char *file, int kind)
1267 {
1268 	I_Debugf("Added filename: %s\n", file);
1269 
1270     wadfiles.push_back(new raw_filename_c(file, kind));
1271 }
1272 
1273 //
1274 // W_InitMultipleFiles
1275 //
1276 // Pass a null terminated list of files to use.
1277 // Files with a .wad extension are idlink files with multiple lumps.
1278 // Other files are single lumps with the base filename for the lump name.
1279 // Lump names can appear multiple times.
1280 // The name searcher looks backwards, so a later file
1281 //   does override all earlier ones.
1282 //
W_InitMultipleFiles(void)1283 void W_InitMultipleFiles(void)
1284 {
1285 	InitCaches();
1286 
1287 	// open all the files, load headers, and count lumps
1288 	numlumps = 0;
1289 
1290 	// will be realloced as lumps are added
1291 	lumpinfo = NULL;
1292 
1293 	std::list<raw_filename_c *>::iterator it;
1294 
1295 	for (it = wadfiles.begin(); it != wadfiles.end(); it++)
1296     {
1297         raw_filename_c *rf = *it;
1298 		AddFile(rf->filename.c_str(), rf->kind, -1);
1299     }
1300 
1301 	if (numlumps == 0)
1302 		I_Error("W_InitMultipleFiles: no files found!\n");
1303 }
1304 
TryLoadExtraLanguage(const char * name)1305 static bool TryLoadExtraLanguage(const char *name)
1306 {
1307 	int lumpnum = W_CheckNumForName(name);
1308 
1309 	if (lumpnum < 0)
1310 		return false;
1311 
1312 	I_Printf("Loading Languages from %s\n", name);
1313 
1314 	int length;
1315 	char *data = (char *) W_ReadLumpAlloc(lumpnum, &length);
1316 
1317 	DDF_ReadLangs(data, length);
1318 	delete[] data;
1319 
1320 	return true;
1321 }
1322 
1323 // MUNDO HACK, but if only fixable by a new wad structure...
LoadTntPlutStrings(void)1324 static void LoadTntPlutStrings(void)
1325 {
1326 	if (DDF_CompareName(iwad_base.c_str(), "TNT") == 0)
1327 		TryLoadExtraLanguage("TNTLANG");
1328 
1329 	if (DDF_CompareName(iwad_base.c_str(), "PLUTONIA") == 0)
1330 		TryLoadExtraLanguage("PLUTLANG");
1331 }
1332 
1333 
W_ReadDDF(void)1334 void W_ReadDDF(void)
1335 {
1336 	// -AJA- the order here may look strange.  Since DDF files
1337 	// have dependencies between them, it makes more sense to
1338 	// load all lumps of a certain type together (e.g. all
1339 	// DDFSFX lumps before all the DDFTHING lumps).
1340 
1341 	for (int d = 0; d < NUM_DDF_READERS; d++)
1342 	{
1343 		if (true)
1344 		{
1345 			I_Printf("Loading external %s\n", DDF_Readers[d].print_name);
1346 
1347 			// call read function
1348 			(* DDF_Readers[d].func)(NULL, 0);
1349 		}
1350 
1351 		for (int f = 0; f < (int)data_files.size(); f++)
1352 		{
1353 			data_file_c *df = data_files[f];
1354 
1355 			// all script files get parsed here
1356 			if (d == RTS_READER && df->kind == FLKIND_RTS)
1357 			{
1358 				I_Printf("Loading RTS script: %s\n", df->file_name);
1359 
1360 				RAD_LoadFile(df->file_name);
1361 				continue;
1362 			}
1363 
1364 			if (df->kind >= FLKIND_Demo)
1365 				continue;
1366 
1367 			if (df->kind == FLKIND_EWad)
1368 			{
1369 				// special handling for TNT and Plutonia
1370 				if (d == LANG_READER)
1371 					LoadTntPlutStrings();
1372 
1373 				continue;
1374 			}
1375 
1376 			int lump = df->ddf_lumps[d];
1377 
1378 			if (lump >= 0)
1379 			{
1380 				I_Printf("Loading %s from: %s\n", DDF_Readers[d].name, df->file_name);
1381 
1382 				int length;
1383 				char *data = (char *) W_ReadLumpAlloc(lump, &length);
1384 
1385 				// call read function
1386 				(* DDF_Readers[d].func)(data, length);
1387 				delete[] data;
1388 			}
1389 
1390 			// handle Boom's ANIMATED and SWITCHES lumps
1391 			if (d == ANIM_READER && df->animated >= 0)
1392 			{
1393 				I_Printf("Loading ANIMATED from: %s\n", df->file_name);
1394 
1395 				int length;
1396 				byte *data = W_ReadLumpAlloc(df->animated, &length);
1397 
1398 				DDF_ParseANIMATED(data, length);
1399 				delete[] data;
1400 			}
1401 			if (d == SWTH_READER && df->switches >= 0)
1402 			{
1403 				I_Printf("Loading SWITCHES from: %s\n", df->file_name);
1404 
1405 				int length;
1406 				byte *data = W_ReadLumpAlloc(df->switches, &length);
1407 
1408 				DDF_ParseSWITCHES(data, length);
1409 				delete[] data;
1410 			}
1411 
1412 			// handle BOOM Colourmaps (between C_START and C_END)
1413 			if (d == COLM_READER && df->colmap_lumps.GetSize() > 0)
1414 			{
1415 				for (int i=0; i < df->colmap_lumps.GetSize(); i++)
1416 				{
1417 					int lump = df->colmap_lumps[i];
1418 
1419 					DDF_ColourmapAddRaw(W_GetLumpName(lump), W_LumpLength(lump));
1420 				}
1421 			}
1422 		}
1423 
1424 ///		std::string msg_buf(epi::STR_Format(
1425 ///			"Loaded %s %s\n", (d == NUM_DDF_READERS-1) ? "RTS" : "DDF",
1426 ///				DDF_Readers[d].print_name));
1427 ///
1428 ///		E_ProgressMessage(msg_buf.c_str());
1429 
1430 		E_LocalProgress(d, NUM_DDF_READERS);
1431 	}
1432 }
1433 
W_ReadCoalLumps(void)1434 void W_ReadCoalLumps(void)
1435 {
1436 	for (int f = 0; f < (int)data_files.size(); f++)
1437 	{
1438 		data_file_c *df = data_files[f];
1439 
1440 		if (df->kind > FLKIND_Lump)
1441 			continue;
1442 
1443 		if (df->coal_huds < 0)
1444 			continue;
1445 
1446 		VM_LoadLumpOfCoal(df->coal_huds);
1447 	}
1448 }
1449 
W_OpenLump(int lump)1450 epi::file_c *W_OpenLump(int lump)
1451 {
1452 	SYS_ASSERT(0 <= lump && lump < numlumps);
1453 
1454 	lumpinfo_t *l = lumpinfo + lump;
1455 
1456 	data_file_c *df = data_files[l->file];
1457 
1458 	SYS_ASSERT(df->file);
1459 
1460 	return new epi::sub_file_c(df->file, l->position, l->size);
1461 }
1462 
W_OpenLump(const char * name)1463 epi::file_c *W_OpenLump(const char *name)
1464 {
1465 	return W_OpenLump(W_GetNumForName(name));
1466 }
1467 
1468 //
1469 // W_GetFileName
1470 //
1471 // Returns the filename of the WAD file containing the given lump, or
1472 // NULL if it wasn't a WAD file (e.g. a pure lump).
1473 //
W_GetFileName(int lump)1474 const char *W_GetFileName(int lump)
1475 {
1476 	SYS_ASSERT(0 <= lump && lump < numlumps);
1477 
1478 	lumpinfo_t *l = lumpinfo + lump;
1479 
1480 	data_file_c *df = data_files[l->file];
1481 
1482 	if (df->kind >= FLKIND_Lump)
1483 		return NULL;
1484 
1485 	return df->file_name;
1486 }
1487 
1488 //
1489 // W_GetPaletteForLump
1490 //
1491 // Returns the palette lump that should be used for the given lump
1492 // (presumably an image), otherwise -1 (indicating that the global
1493 // palette should be used).
1494 //
1495 // NOTE: when the same WAD as the lump does not contain a palette,
1496 // there are two possibilities: search backwards for the "closest"
1497 // palette, or simply return -1.  Neither one is ideal, though I tend
1498 // to think that searching backwards is more intuitive.
1499 //
1500 // NOTE 2: the palette_datafile stuff is there so we always return -1
1501 // for the "GLOBAL" palette.
1502 //
W_GetPaletteForLump(int lump)1503 int W_GetPaletteForLump(int lump)
1504 {
1505 	SYS_ASSERT(0 <= lump && lump < numlumps);
1506 
1507 	int f = lumpinfo[lump].file;
1508 
1509 	for (; f > palette_datafile; f--)
1510 	{
1511 		data_file_c *df = data_files[f];
1512 
1513 		if (df->kind >= FLKIND_Lump)
1514 			continue;
1515 
1516 		if (df->wadtex.palette >= 0)
1517 			return df->wadtex.palette;
1518 	}
1519 
1520 	// none found
1521 	return -1;
1522 }
1523 
1524 
QuickFindLumpMap(char * buf)1525 static inline int QuickFindLumpMap(char *buf)
1526 {
1527 	int i;
1528 
1529 #define CMP(a)  (LUMP_MAP_CMP(a) < 0)
1530 	BSEARCH(numlumps, i);
1531 #undef CMP
1532 
1533 	if (i < 0 || i >= numlumps || LUMP_MAP_CMP(i) != 0)
1534 	{
1535 		// not found (nothing has that name)
1536 		return -1;
1537 	}
1538 
1539 	// jump to first matching name
1540 	while (i > 0 && LUMP_MAP_CMP(i-1) == 0)
1541 		i--;
1542 
1543 	return i;
1544 }
1545 
1546 
1547 //
1548 // W_CheckNumForName
1549 //
1550 // Returns -1 if name not found.
1551 //
1552 // -ACB- 1999/09/18 Added name to error message
1553 //
W_CheckNumForName2(const char * name)1554 int W_CheckNumForName2(const char *name)
1555 {
1556 	int i;
1557 	char buf[9];
1558 
1559 	for (i = 0; name[i]; i++)
1560 	{
1561 		if (i > 8)
1562 		{
1563 			I_Warning("W_CheckNumForName: Name '%s' longer than 8 chars!\n", name);
1564 			return -1;
1565 		}
1566 		buf[i] = toupper(name[i]);
1567 	}
1568 	buf[i] = 0;
1569 
1570 	i = QuickFindLumpMap(buf);
1571 
1572 	if (i < 0)
1573 		return -1; // not found
1574 
1575 	return lumpmap[i];
1576 }
1577 
1578 
W_CheckNumForName_GFX(const char * name)1579 int W_CheckNumForName_GFX(const char *name)
1580 {
1581 	// this looks for a graphic lump, skipping anything which would
1582 	// not be suitable (especially flats and HIRES replacements).
1583 
1584 	int i;
1585 	char buf[9];
1586 
1587 	for (i = 0; name[i]; i++)
1588 	{
1589 		if (i > 8)
1590 		{
1591 			I_Warning("W_CheckNumForName: Name '%s' longer than 8 chars!\n", name);
1592 			return -1;
1593 		}
1594 		buf[i] = toupper(name[i]);
1595 	}
1596 	buf[i] = 0;
1597 
1598 	// search backwards
1599 	for (i = numlumps-1; i >= 0; i--)
1600 	{
1601 		if (lumpinfo[i].kind == LMKIND_Normal ||
1602 		    lumpinfo[i].kind == LMKIND_Sprite ||
1603 		    lumpinfo[i].kind == LMKIND_Patch)
1604 		{
1605 			if (strncmp(lumpinfo[i].name, buf, 8) == 0)
1606 				return i;
1607 		}
1608 	}
1609 
1610 	return -1; // not found
1611 }
1612 
1613 //
1614 // W_GetNumForName
1615 //
1616 // Calls W_CheckNumForName, but bombs out if not found.
1617 //
W_GetNumForName2(const char * name)1618 int W_GetNumForName2(const char *name)
1619 {
1620 	int i;
1621 
1622 	if ((i = W_CheckNumForName2(name)) == -1)
1623 		I_Error("W_GetNumForName: \'%.8s\' not found!", name);
1624 
1625 	return i;
1626 }
1627 
1628 //
1629 // W_CheckNumForTexPatch
1630 //
1631 // Returns -1 if name not found.
1632 //
1633 // -AJA- 2004/06/24: Patches should be within the P_START/P_END markers,
1634 //       so we should look there first.  Also we should never return a
1635 //       flat as a tex-patch.
1636 //
W_CheckNumForTexPatch(const char * name)1637 int W_CheckNumForTexPatch(const char *name)
1638 {
1639 	int i;
1640 	char buf[10];
1641 
1642 	for (i = 0; name[i]; i++)
1643 	{
1644 #ifdef DEVELOPERS
1645 		if (i > 8)
1646 			I_Error("W_CheckNumForTexPatch: '%s' longer than 8 chars!", name);
1647 #endif
1648 		buf[i] = toupper(name[i]);
1649 	}
1650 	buf[i] = 0;
1651 
1652 	i = QuickFindLumpMap(buf);
1653 
1654 	if (i < 0)
1655 		return -1;  // not found
1656 
1657 	for (; i < numlumps && LUMP_MAP_CMP(i) == 0; i++)
1658 	{
1659 		lumpinfo_t *L = lumpinfo + lumpmap[i];
1660 
1661 		if (L->kind == LMKIND_Patch || L->kind == LMKIND_Sprite ||
1662 			L->kind == LMKIND_Normal)
1663 		{
1664 			// allow LMKIND_Normal to support patches outside of the
1665 			// P_START/END markers.  We especially want to disallow
1666 			// flat and colourmap lumps.
1667 			return lumpmap[i];
1668 		}
1669 	}
1670 
1671 	return -1;  // nothing suitable
1672 }
1673 
1674 //
1675 // W_VerifyLumpName
1676 //
1677 // Verifies that the given lump number is valid and has the given
1678 // name.
1679 //
1680 // -AJA- 1999/11/26: written.
1681 //
W_VerifyLumpName(int lump,const char * name)1682 bool W_VerifyLumpName(int lump, const char *name)
1683 {
1684 	if (lump >= numlumps)
1685 		return false;
1686 
1687 	return (strncmp(lumpinfo[lump].name, name, 8) == 0);
1688 }
1689 
1690 //
1691 // W_LumpLength
1692 //
1693 // Returns the buffer size needed to load the given lump.
1694 //
W_LumpLength(int lump)1695 int W_LumpLength(int lump)
1696 {
1697 	if (lump >= numlumps)
1698 		I_Error("W_LumpLength: %i >= numlumps", lump);
1699 
1700 	return lumpinfo[lump].size;
1701 }
1702 
1703 //
1704 // W_FindFlatSequence
1705 //
1706 // Returns the file number containing the sequence, or -1 if not
1707 // found.  Search is from newest wad file to oldest wad file.
1708 //
W_FindFlatSequence(const char * start,const char * end,int * s_offset,int * e_offset)1709 int W_FindFlatSequence(const char *start, const char *end,
1710 					   int *s_offset, int *e_offset)
1711 {
1712 	for (int file = (int)data_files.size()-1; file >= 0; file--)
1713 	{
1714 		data_file_c *df = data_files[file];
1715 
1716 		// look for start name
1717 		int i;
1718 		for (i=0; i < df->flat_lumps.GetSize(); i++)
1719 		{
1720 			if (strncmp(start, W_GetLumpName(df->flat_lumps[i]), 8) == 0)
1721 				break;
1722 		}
1723 
1724 		if (i >= df->flat_lumps.GetSize())
1725 			continue;
1726 
1727 		(*s_offset) = i;
1728 
1729 		// look for end name
1730 		for (i++; i < df->flat_lumps.GetSize(); i++)
1731 		{
1732 			if (strncmp(end, W_GetLumpName(df->flat_lumps[i]), 8) == 0)
1733 			{
1734 				(*e_offset) = i;
1735 				return file;
1736 			}
1737 		}
1738 	}
1739 
1740 	// not found
1741 	return -1;
1742 }
1743 
1744 
1745 //
1746 // Returns NULL for an empty list.
1747 //
W_GetListLumps(int file,lumplist_e which)1748 epi::u32array_c& W_GetListLumps(int file, lumplist_e which)
1749 {
1750 	SYS_ASSERT(0 <= file && file < (int)data_files.size());
1751 
1752 	data_file_c *df = data_files[file];
1753 
1754 	switch (which)
1755 	{
1756 		case LMPLST_Sprites: return df->sprite_lumps;
1757 		case LMPLST_Flats:   return df->flat_lumps;
1758 		case LMPLST_Patches: return df->patch_lumps;
1759 
1760 		default: break;
1761 	}
1762 
1763 	I_Error("W_GetListLumps: bad `which' (%d)\n", which);
1764 	return df->sprite_lumps; /* NOT REACHED */
1765 }
1766 
1767 
W_GetNumFiles(void)1768 int W_GetNumFiles(void)
1769 {
1770 	return (int)data_files.size();
1771 }
1772 
1773 
W_GetFileForLump(int lump)1774 int W_GetFileForLump(int lump)
1775 {
1776 	SYS_ASSERT(lump >= 0 && lump < numlumps);
1777 
1778 	return lumpinfo[lump].file;
1779 }
1780 
1781 
1782 //
1783 // Loads the lump into the given buffer,
1784 // which must be >= W_LumpLength().
1785 //
W_ReadLump(int lump,void * dest)1786 static void W_ReadLump(int lump, void *dest)
1787 {
1788 	if (lump >= numlumps)
1789 		I_Error("W_ReadLump: %i >= numlumps", lump);
1790 
1791 	lumpinfo_t *L = lumpinfo + lump;
1792 	data_file_c *df = data_files[L->file];
1793 
1794 	// -KM- 1998/07/31 This puts the loading icon in the corner of the screen :-)
1795 	display_disk = true;
1796 
1797     df->file->Seek(L->position, epi::file_c::SEEKPOINT_START);
1798 
1799     int c = df->file->Read(dest, L->size);
1800 
1801 	if (c < L->size)
1802 		I_Error("W_ReadLump: only read %i of %i on lump %i", c, L->size, lump);
1803 }
1804 
1805 // FIXME !!! merge W_ReadLumpAlloc and W_LoadLumpNum into one good function
W_ReadLumpAlloc(int lump,int * length)1806 byte *W_ReadLumpAlloc(int lump, int *length)
1807 {
1808 	*length = W_LumpLength(lump);
1809 
1810 	byte *data = new byte[*length + 1];
1811 
1812 	W_ReadLump(lump, data);
1813 
1814 	data[*length] = 0;
1815 
1816 	return data;
1817 }
1818 
1819 //
1820 // W_DoneWithLump
1821 //
W_DoneWithLump(const void * ptr)1822 void W_DoneWithLump(const void *ptr)
1823 {
1824 	lumpheader_t *h = ((lumpheader_t *)ptr); // Intentional Const Override
1825 
1826 #ifdef DEVELOPERS
1827 	if (h == NULL)
1828 		I_Error("W_DoneWithLump: NULL pointer");
1829 	if (h[-1].id != lumpheader_s::LUMPID)
1830 		I_Error("W_DoneWithLump: id != LUMPID");
1831 	if (h[-1].users == 0)
1832 		I_Error("W_DoneWithLump: lump %d has no users!", h[-1].lumpindex);
1833 #endif
1834 	h--;
1835 	h->users--;
1836 	if (h->users == 0)
1837 	{
1838 		// Move the item to the tail.
1839 		h->prev->next = h->next;
1840 		h->next->prev = h->prev;
1841 		h->prev = lumphead.prev;
1842 		h->next = &lumphead;
1843 		h->prev->next = h;
1844 		h->next->prev = h;
1845 		MarkAsCached(h);
1846 	}
1847 }
1848 
1849 //
1850 // W_DoneWithLump_Flushable
1851 //
1852 // Call this if the lump probably won't be used for a while, to hint the
1853 // system to flush it early.
1854 //
1855 // Useful if you are creating a cache for e.g. some kind of lump
1856 // conversions (like the sound cache).
1857 //
W_DoneWithLump_Flushable(const void * ptr)1858 void W_DoneWithLump_Flushable(const void *ptr)
1859 {
1860 	lumpheader_t *h = ((lumpheader_t *)ptr); // Intentional Const Override
1861 
1862 #ifdef DEVELOPERS
1863 	if (h == NULL)
1864 		I_Error("W_DoneWithLump: NULL pointer");
1865 	h--;
1866 	if (h->id != lumpheader_s::LUMPID)
1867 		I_Error("W_DoneWithLump: id != LUMPID");
1868 	if (h->users == 0)
1869 		I_Error("W_DoneWithLump: lump %d has no users!", h->lumpindex);
1870 #endif
1871 	h->users--;
1872 	if (h->users == 0)
1873 	{
1874 		// Move the item to the head of the list.
1875 		h->prev->next = h->next;
1876 		h->next->prev = h->prev;
1877 		h->next = lumphead.next;
1878 		h->prev = &lumphead;
1879 		h->prev->next = h;
1880 		h->next->prev = h;
1881 		MarkAsCached(h);
1882 	}
1883 }
1884 
1885 //
1886 // W_CacheLumpNum
1887 //
W_CacheLumpNum2(int lump)1888 const void *W_CacheLumpNum2 (int lump)
1889 {
1890 	lumpheader_t *h;
1891 
1892 #ifdef DEVELOPERS
1893 	if ((unsigned int)lump >= (unsigned int)numlumps)
1894 		I_Error("W_CacheLumpNum: %i >= numlumps", lump);
1895 #endif
1896 
1897 	h = lumplookup[lump];
1898 
1899 	if (h)
1900 	{
1901 		// cache hit
1902 		if (h->users == 0)
1903 			cache_size -= W_LumpLength(h->lumpindex);
1904 		h->users++;
1905 	}
1906 	else
1907 	{
1908 		// cache miss. load the new item.
1909 		h = (lumpheader_t *) Z_Malloc(sizeof(lumpheader_t) + W_LumpLength(lump));
1910 		lumplookup[lump] = h;
1911 #ifdef DEVELOPERS
1912 		h->id = lumpheader_s::LUMPID;
1913 #endif
1914 		h->lumpindex = lump;
1915 		h->users = 1;
1916 		h->prev = lumphead.prev;
1917 		h->next = &lumphead;
1918 		h->prev->next = h;
1919 		lumphead.prev = h;
1920 
1921 		W_ReadLump(lump, (void *)(h + 1));
1922 	}
1923 
1924 	return (void *)(h + 1);
1925 }
1926 
1927 //
1928 // W_CacheLumpName
1929 //
W_CacheLumpName2(const char * name)1930 const void *W_CacheLumpName2(const char *name)
1931 {
1932 	return W_CacheLumpNum2(W_GetNumForName2(name));
1933 }
1934 
1935 //
1936 // W_PreCacheLumpNum
1937 //
1938 // Attempts to load lump into the cache, if it isn't already there
1939 //
W_PreCacheLumpNum(int lump)1940 void W_PreCacheLumpNum(int lump)
1941 {
1942 	W_DoneWithLump(W_CacheLumpNum(lump));
1943 }
1944 
1945 //
1946 // W_PreCacheLumpName
1947 //
W_PreCacheLumpName(const char * name)1948 void W_PreCacheLumpName(const char *name)
1949 {
1950 	W_DoneWithLump(W_CacheLumpName(name));
1951 }
1952 
1953 //
1954 // W_CacheInfo
1955 //
W_CacheInfo(int level)1956 int W_CacheInfo(int level)
1957 {
1958 	lumpheader_t *h;
1959 	int value = 0;
1960 
1961 	for (h = lumphead.next; h != &lumphead; h = h->next)
1962 	{
1963 		if ((level & 1) && h->users)
1964 			value += W_LumpLength(h->lumpindex);
1965 		if ((level & 2) && !h->users)
1966 			value += W_LumpLength(h->lumpindex);
1967 	}
1968 	return value;
1969 }
1970 
1971 //
1972 // W_LoadLumpNum
1973 //
1974 // Returns a copy of the lump (it is your responsibility to free it)
1975 //
W_LoadLumpNum(int lump)1976 void *W_LoadLumpNum(int lump)
1977 {
1978 	void *p;
1979 	const void *cached;
1980 	int length = W_LumpLength(lump);
1981 	p = (void *) Z_Malloc(length);
1982 	cached = W_CacheLumpNum2(lump);
1983 	memcpy(p, cached, length);
1984 	W_DoneWithLump(cached);
1985 	return p;
1986 }
1987 
1988 //
1989 // W_LoadLumpName
1990 //
W_LoadLumpName(const char * name)1991 void *W_LoadLumpName(const char *name)
1992 {
1993 	return W_LoadLumpNum(W_GetNumForName2(name));
1994 }
1995 
1996 //
1997 // W_GetLumpName
1998 //
W_GetLumpName(int lump)1999 const char *W_GetLumpName(int lump)
2000 {
2001 	return lumpinfo[lump].name;
2002 }
2003 
2004 
W_ProcessTX_HI(void)2005 void W_ProcessTX_HI(void)
2006 {
2007 	// Add the textures that occur in between TX_START/TX_END markers
2008 
2009 	// TODO: collect names, remove duplicates
2010 
2011 	for (int file = 0; file < (int)data_files.size(); file++)
2012 	{
2013 		data_file_c *df = data_files[file];
2014 
2015 		for (int i = 0; i < (int)df->tx_lumps.GetSize(); i++)
2016 		{
2017 			int lump = df->tx_lumps[i];
2018 			W_ImageAddTX(lump, W_GetLumpName(lump), false);
2019 		}
2020 	}
2021 
2022 	// Add the textures that occur in between HI_START/HI_END markers
2023 
2024 	for (int file = 0; file < (int)data_files.size(); file++)
2025 	{
2026 		data_file_c *df = data_files[file];
2027 
2028 		for (int i = 0; i < (int)df->hires_lumps.GetSize(); i++)
2029 		{
2030 			int lump = df->hires_lumps[i];
2031 			W_ImageAddTX(lump, W_GetLumpName(lump), true);
2032 		}
2033 	}
2034 }
2035 
2036 
2037 static const char *FileKind_Strings[] =
2038 {
2039 	"iwad", "pwad", "edge", "gwa", "hwa",
2040 	"lump", "ddf",  "demo", "rts", "deh",
2041 	"???",  "???",  "???",  "???"
2042 };
2043 
2044 static const char *LumpKind_Strings[] =
2045 {
2046 	"normal", "???", "???",
2047 	"marker", "???", "???",
2048 	"wadtex", "???", "???", "???",
2049 	"ddf",    "???", "???", "???",
2050 
2051 	"tx", "colmap", "flat", "sprite", "patch",
2052 	"???", "???", "???", "???"
2053 };
2054 
2055 
W_ShowLumps(int for_file,const char * match)2056 void W_ShowLumps(int for_file, const char *match)
2057 {
2058 	I_Printf("Lump list:\n");
2059 
2060 	int total = 0;
2061 
2062 	for (int i = 0; i < numlumps; i++)
2063 	{
2064 		lumpinfo_t *L = &lumpinfo[i];
2065 
2066 		if (for_file >= 1 && L->file != for_file-1)
2067 			continue;
2068 
2069 		if (match && *match)
2070 			if (! strstr(L->name, match))
2071 				continue;
2072 
2073 		I_Printf(" %4d %-9s %2d %-6s %7d @ 0x%08x\n",
2074 		         i+1, L->name,
2075 				 L->file+1, LumpKind_Strings[L->kind],
2076 				 L->size, L->position);
2077 		total++;
2078 	}
2079 
2080 	I_Printf("Total: %d\n", total);
2081 }
2082 
W_ShowFiles(void)2083 void W_ShowFiles(void)
2084 {
2085 	I_Printf("File list:\n");
2086 
2087 	for (int i = 0; i < (int)data_files.size(); i++)
2088 	{
2089 		data_file_c *df = data_files[i];
2090 
2091 		I_Printf(" %2d %-4s \"%s\"\n", i+1, FileKind_Strings[df->kind], df->file_name);
2092 	}
2093 }
2094 
2095 
2096 //--- editor settings ---
2097 // vi:ts=4:sw=4:noexpandtab
2098