1 //**************************************************************************
2 //**
3 //**    ##   ##    ##    ##   ##   ####     ####   ###     ###
4 //**    ##   ##  ##  ##  ##   ##  ##  ##   ##  ##  ####   ####
5 //**     ## ##  ##    ##  ## ##  ##    ## ##    ## ## ## ## ##
6 //**     ## ##  ########  ## ##  ##    ## ##    ## ##  ###  ##
7 //**      ###   ##    ##   ###    ##  ##   ##  ##  ##       ##
8 //**       #    ##    ##    #      ####     ####   ##       ##
9 //**
10 //**    $Id: wad.cpp 4297 2010-06-03 22:49:00Z firebrand_kh $
11 //**
12 //**    Copyright (C) 1999-2006 Jānis Legzdiņš
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 //**************************************************************************
25 //**
26 //**    Handles WAD file header, directory, lump I/O.
27 //**
28 //**************************************************************************
29 
30 // HEADER FILES ------------------------------------------------------------
31 
32 #include "gamedefs.h"
33 #include "fs_local.h"
34 
35 // MACROS ------------------------------------------------------------------
36 
37 #define GET_LUMP_FILE(num)		SearchPaths[num >> 16]
38 #define FILE_INDEX(num)			(num >> 16)
39 #define LUMP_INDEX(num)			(num & 0xffff)
40 #define MAKE_HANDLE(wi, num)	((wi << 16) + num)
41 
42 // TYPES -------------------------------------------------------------------
43 
44 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
45 
46 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
47 
48 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
49 
50 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
51 
52 extern TArray<VStr>			wadfiles;
53 
54 // PUBLIC DATA DEFINITIONS -------------------------------------------------
55 
56 // PRIVATE DATA DEFINITIONS ------------------------------------------------
57 
58 static int					AuxiliaryIndex;
59 
60 // CODE --------------------------------------------------------------------
61 
~VSearchPath()62 VSearchPath::~VSearchPath()
63 {
64 }
65 
66 //==========================================================================
67 //
68 //  W_AddFile
69 //
70 //  All files are optional, but at least one file must be found (PWAD, if
71 // all required lumps are present). Files with a .wad extension are wadlink
72 // files with multiple lumps. Other files are single lumps with the base
73 // filename for the lump name.
74 //
75 //==========================================================================
76 
W_AddFile(const VStr & FileName,const VStr & GwaDir,bool FixVoices)77 void W_AddFile(const VStr& FileName, const VStr& GwaDir, bool FixVoices)
78 {
79 	guard(W_AddFile);
80 	int wadtime;
81 
82 	wadtime = Sys_FileTime(FileName);
83 	if (wadtime == -1)
84 	{
85 		Sys_Error("Required file %s doesn't exist", *FileName);
86 	}
87 
88 	wadfiles.Append(FileName);
89 
90 	VStr ext = FileName.ExtractFileExtension().ToLower();
91 	VWadFile* Wad = new VWadFile;
92 	if (ext != "wad" && ext != "gwa")
93 	{
94 		Wad->OpenSingleLump(FileName);
95 	}
96 	else
97 	{
98 		Wad->Open(FileName, GwaDir, FixVoices, NULL);
99 	}
100 	SearchPaths.Append(Wad);
101 
102 	if (ext == "wad")
103 	{
104 		VStr gl_name;
105 
106 		bool FoundGwa = false;
107 		if (GwaDir.IsNotEmpty())
108 		{
109 			gl_name = GwaDir + "/" +
110 				FileName.ExtractFileName().StripExtension() + ".gwa";
111 			if (Sys_FileTime(gl_name) >= wadtime)
112 			{
113 				W_AddFile(gl_name, VStr(), false);
114 				FoundGwa = true;
115 			}
116 		}
117 
118 		if (!FoundGwa)
119 		{
120 			gl_name = FileName.StripExtension() + ".gwa";
121 			if (Sys_FileTime(gl_name) >= wadtime)
122 			{
123 				W_AddFile(gl_name, VStr(), false);
124 			}
125 			else
126 			{
127 				//	Leave empty slot for GWA file
128 				SearchPaths.Append(new VWadFile);
129 			}
130 		}
131 	}
132 	unguard;
133 }
134 
135 //==========================================================================
136 //
137 //  W_AddFileFromZip
138 //
139 //==========================================================================
140 
W_AddFileFromZip(const VStr & WadName,VStream * WadStrm,const VStr & GwaName,VStream * GwaStrm)141 void W_AddFileFromZip(const VStr& WadName, VStream* WadStrm,
142 	const VStr& GwaName, VStream* GwaStrm)
143 {
144 	guard(W_AddFileFromZip);
145 	//	Add WAD file.
146 	wadfiles.Append(WadName);
147 	VWadFile* Wad = new VWadFile;
148 	Wad->Open(WadName, VStr(), false, WadStrm);
149 	SearchPaths.Append(Wad);
150 
151 	if (GwaStrm)
152 	{
153 		//	Add GWA file
154 		wadfiles.Append(GwaName);
155 		VWadFile* Gwa = new VWadFile;
156 		Gwa->Open(GwaName, VStr(), false, GwaStrm);
157 		SearchPaths.Append(Gwa);
158 	}
159 	else
160 	{
161 		//	Leave empty slot for GWA file
162 		SearchPaths.Append(new VWadFile);
163 	}
164 	unguard;
165 }
166 
167 //==========================================================================
168 //
169 //  W_OpenAuxiliary
170 //
171 //==========================================================================
172 
W_OpenAuxiliary(const VStr & FileName)173 int W_OpenAuxiliary(const VStr& FileName)
174 {
175 	guard(W_OpenAuxiliary);
176 	W_CloseAuxiliary();
177 
178 	AuxiliaryIndex = SearchPaths.Num();
179 
180 	VStr GwaName = FileName.StripExtension() + ".gwa";
181 	VStream* WadStrm = FL_OpenFileRead(FileName);
182 	VStream* GwaStrm = FL_OpenFileRead(GwaName);
183 	W_AddFileFromZip(FileName, WadStrm, GwaName, GwaStrm);
184 	return MAKE_HANDLE(AuxiliaryIndex, 0);
185 	unguard;
186 }
187 
188 //==========================================================================
189 //
190 //  W_CloseAuxiliary
191 //
192 //==========================================================================
193 
W_CloseAuxiliary()194 void W_CloseAuxiliary()
195 {
196 	guard(W_CloseAuxiliary);
197 	if (AuxiliaryIndex)
198 	{
199 		SearchPaths[AuxiliaryIndex]->Close();
200 		SearchPaths[AuxiliaryIndex + 1]->Close();
201 		delete SearchPaths[AuxiliaryIndex];
202 		SearchPaths[AuxiliaryIndex] = NULL;
203 		delete SearchPaths[AuxiliaryIndex + 1];
204 		SearchPaths[AuxiliaryIndex + 1] = NULL;
205 		SearchPaths.SetNum(AuxiliaryIndex);
206 		AuxiliaryIndex = 0;
207 	}
208 	unguard;
209 }
210 
211 #ifdef CLIENT
212 
213 //==========================================================================
214 //
215 //	W_BuildGLNodes
216 //
217 //==========================================================================
218 
W_BuildGLNodes(int lump)219 void W_BuildGLNodes(int lump)
220 {
221 	guard(W_BuildGLNodes);
222 	SearchPaths[FILE_INDEX(lump)]->BuildGLNodes(SearchPaths[FILE_INDEX(lump) + 1]);
223 	unguard;
224 }
225 
226 //==========================================================================
227 //
228 //	W_BuildPVS
229 //
230 //==========================================================================
231 
W_BuildPVS(int lump,int gllump)232 void W_BuildPVS(int lump, int gllump)
233 {
234 	guard(W_BuildPVS);
235 	SearchPaths[FILE_INDEX(gllump)]->BuildPVS(SearchPaths[FILE_INDEX(lump)]);
236 	unguard;
237 }
238 
239 #endif
240 
241 //==========================================================================
242 //
243 //  W_CheckNumForName
244 //
245 //  Returns -1 if name not found.
246 //
247 //==========================================================================
248 
W_CheckNumForName(VName Name,EWadNamespace NS)249 int W_CheckNumForName(VName Name, EWadNamespace NS)
250 {
251 	guard(W_CheckNumForName);
252 	for (int wi = SearchPaths.Num() - 1; wi >= 0; wi--)
253 	{
254 		int i = SearchPaths[wi]->CheckNumForName(Name, NS);
255 		if (i >= 0)
256 		{
257 			return MAKE_HANDLE(wi, i);
258 		}
259 	}
260 
261 	// Not found.
262 	return -1;
263 	unguard;
264 }
265 
266 //==========================================================================
267 //
268 //  W_GetNumForName
269 //
270 //  Calls W_CheckNumForName, but bombs out if not found.
271 //
272 //==========================================================================
273 
W_GetNumForName(VName Name,EWadNamespace NS)274 int W_GetNumForName(VName Name, EWadNamespace NS)
275 {
276 	guard(W_GetNumForName);
277 	int i = W_CheckNumForName(Name, NS);
278 	if (i == -1)
279 	{
280 		Sys_Error("W_GetNumForName: %s not found!", *Name);
281 	}
282 	return i;
283 	unguard;
284 }
285 
286 //==========================================================================
287 //
288 //  W_CheckNumForNameInFile
289 //
290 //  Returns -1 if name not found.
291 //
292 //==========================================================================
293 
W_CheckNumForNameInFile(VName Name,int File,EWadNamespace NS)294 int W_CheckNumForNameInFile(VName Name, int File, EWadNamespace NS)
295 {
296 	guard(W_CheckNumForNameInFile);
297 	check(File >= 0);
298 	check(File < SearchPaths.Num());
299 	int i = SearchPaths[File]->CheckNumForName(Name, NS);
300 	if (i >= 0)
301 	{
302 		return MAKE_HANDLE(File, i);
303 	}
304 
305 	// Not found.
306 	return -1;
307 	unguard;
308 }
309 
310 //==========================================================================
311 //
312 //  W_CheckNumForFileName
313 //
314 //  Returns -1 if name not found.
315 //
316 //==========================================================================
317 
W_CheckNumForFileName(VStr Name)318 int W_CheckNumForFileName(VStr Name)
319 {
320 	guard(W_CheckNumForFileName);
321 	for (int wi = SearchPaths.Num() - 1; wi >= 0; wi--)
322 	{
323 		int i = SearchPaths[wi]->CheckNumForFileName(Name);
324 		if (i >= 0)
325 		{
326 			return MAKE_HANDLE(wi, i);
327 		}
328 	}
329 
330 	// Not found.
331 	return -1;
332 	unguard;
333 }
334 
335 //==========================================================================
336 //
337 //	W_GetNumForFileName
338 //
339 //	Calls W_CheckNumForFileName, but bombs out if not found.
340 //
341 //==========================================================================
342 
W_GetNumForFileName(VStr Name)343 int W_GetNumForFileName(VStr Name)
344 {
345 	guard(W_GetNumForFileName);
346 	int i = W_CheckNumForFileName(Name);
347 	if (i == -1)
348 	{
349 		Sys_Error("W_GetNumForFileName: %s not found!", *Name);
350 	}
351 	return i;
352 	unguard;
353 }
354 
355 //==========================================================================
356 //
357 //  W_LumpLength
358 //
359 //  Returns the buffer size needed to load the given lump.
360 //
361 //==========================================================================
362 
W_LumpLength(int lump)363 int W_LumpLength(int lump)
364 {
365 	guard(W_LumpLength);
366 	if (FILE_INDEX(lump) >= SearchPaths.Num())
367 	{
368 		Sys_Error("W_LumpLength: %i >= num_wad_files", FILE_INDEX(lump));
369 	}
370 	VSearchPath* w = GET_LUMP_FILE(lump);
371 	int lumpindex = LUMP_INDEX(lump);
372 	return w->LumpLength(lumpindex);
373 	unguard;
374 }
375 
376 //==========================================================================
377 //
378 //  W_LumpName
379 //
380 //==========================================================================
381 
W_LumpName(int lump)382 VName W_LumpName(int lump)
383 {
384 	guard(W_LumpName);
385 	if (FILE_INDEX(lump) >= SearchPaths.Num())
386 	{
387 		return NAME_None;
388 	}
389 	VSearchPath* w = GET_LUMP_FILE(lump);
390 	int lumpindex = LUMP_INDEX(lump);
391 	return w->LumpName(lumpindex);
392 	unguard;
393 }
394 
395 //==========================================================================
396 //
397 //  W_LumpFile
398 //
399 //  Returns file index of the given lump.
400 //
401 //==========================================================================
402 
W_LumpFile(int lump)403 int W_LumpFile(int lump)
404 {
405 	return FILE_INDEX(lump);
406 }
407 
408 //==========================================================================
409 //
410 //  W_ReadFromLump
411 //
412 //==========================================================================
413 
W_ReadFromLump(int lump,void * dest,int pos,int size)414 void W_ReadFromLump(int lump, void* dest, int pos, int size)
415 {
416 	guard(W_ReadFromLump);
417 	if (FILE_INDEX(lump) >= SearchPaths.Num())
418 	{
419 		Sys_Error("W_ReadFromLump: %i >= num_wad_files", FILE_INDEX(lump));
420 	}
421 
422 	VSearchPath* w = GET_LUMP_FILE(lump);
423 	w->ReadFromLump(LUMP_INDEX(lump), dest, pos, size);
424 	unguard;
425 }
426 
427 //==========================================================================
428 //
429 //  W_CreateLumpReaderNum
430 //
431 //==========================================================================
432 
W_CreateLumpReaderNum(int lump)433 VStream* W_CreateLumpReaderNum(int lump)
434 {
435 	guard(W_CreateLumpReaderNum);
436 	return GET_LUMP_FILE(lump)->CreateLumpReaderNum(LUMP_INDEX(lump));
437 	unguard;
438 }
439 
440 //==========================================================================
441 //
442 //  W_CreateLumpReaderName
443 //
444 //==========================================================================
445 
W_CreateLumpReaderName(VName Name,EWadNamespace NS)446 VStream* W_CreateLumpReaderName(VName Name, EWadNamespace NS)
447 {
448 	guard(W_CreateLumpReaderName);
449 	return W_CreateLumpReaderNum(W_GetNumForName(Name, NS));
450 	unguard;
451 }
452 
453 //==========================================================================
454 //
455 //  W_IterateNS
456 //
457 //==========================================================================
458 
W_IterateNS(int Prev,EWadNamespace NS)459 int W_IterateNS(int Prev, EWadNamespace NS)
460 {
461 	guard(W_IterateNS);
462 	int wi = FILE_INDEX((Prev + 1));
463 	int li = LUMP_INDEX((Prev + 1));
464 	for (; wi < SearchPaths.Num(); wi++, li = 0)
465 	{
466 		li = SearchPaths[wi]->IterateNS(li, NS);
467 		if (li != -1)
468 		{
469 			return MAKE_HANDLE(wi, li);
470 		}
471 	}
472 	return -1;
473 	unguard;
474 }
475 
476 //==========================================================================
477 //
478 //  W_IterateFile
479 //
480 //==========================================================================
481 
W_IterateFile(int Prev,const VStr & Name)482 int W_IterateFile(int Prev, const VStr& Name)
483 {
484 	guard(W_IterateFile);
485 	for (int wi = FILE_INDEX(Prev) + 1; wi < SearchPaths.Num(); wi++)
486 	{
487 		int li = SearchPaths[wi]->CheckNumForFileName(Name);
488 		if (li != -1)
489 		{
490 			return MAKE_HANDLE(wi, li);
491 		}
492 	}
493 	return -1;
494 	unguard;
495 }
496 
497 //==========================================================================
498 //
499 //  W_FindLumpByFileNameWithExts
500 //
501 //==========================================================================
502 
W_FindLumpByFileNameWithExts(VStr BaseName,const char ** Exts)503 int W_FindLumpByFileNameWithExts(VStr BaseName, const char** Exts)
504 {
505 	guard(W_FindLumpByFileNameWithExts);
506 	int Found = -1;
507 	for (const char** Ext = Exts; *Ext; Ext++)
508 	{
509 		VStr Check = BaseName + "." + *Ext;
510 		int Lump = W_CheckNumForFileName(Check);
511 		if (Lump <= Found)
512 		{
513 			continue;
514 		}
515 		//	For files from the same directory the order of extensions defines
516 		// the priority order.
517 		if (Found >= 0 && W_LumpFile(Found) == W_LumpFile(Lump))
518 		{
519 			continue;
520 		}
521 		Found = Lump;
522 	}
523 	return Found;
524 	unguard;
525 }
526 
527 //==========================================================================
528 //
529 //	W_LoadTextLump
530 //
531 //==========================================================================
532 
W_LoadTextLump(VName name)533 VStr W_LoadTextLump(VName name)
534 {
535 	guard(W_LoadTextLump);
536 	VStream* Strm = W_CreateLumpReaderName(name);
537 	int msgSize = Strm->TotalSize();
538 	char* buf = new char[msgSize + 1];
539 	Strm->Serialise(buf, msgSize);
540 	delete Strm;
541 	Strm = NULL;
542 	buf[msgSize] = 0; // Append terminator
543 	VStr Ret = buf;
544 	delete[] buf;
545 	buf = NULL;
546 	if (!Ret.IsValidUtf8())
547 	{
548 		GCon->Logf("%s is not a valid UTF-8 text lump, assuming Latin 1",
549 			*name);
550 		Ret = Ret.Latin1ToUtf8();
551 	}
552 	return Ret;
553 	unguard;
554 }
555 
556 //==========================================================================
557 //
558 //  W_CreateLumpReaderNum
559 //
560 //==========================================================================
561 
W_LoadLumpIntoArray(VName LumpName,TArray<vuint8> & Array)562 void W_LoadLumpIntoArray(VName LumpName, TArray<vuint8>& Array)
563 {
564 	int Lump = W_CheckNumForFileName(*LumpName);
565 	if (Lump < 0)
566 	{
567 		Lump = W_GetNumForName(LumpName);
568 	}
569 	VStream* Strm = W_CreateLumpReaderNum(Lump);
570 	check(Strm);
571 	Array.SetNum(Strm->TotalSize());
572 	Strm->Serialise(Array.Ptr(), Strm->TotalSize());
573 	delete Strm;
574 	Strm = NULL;
575 }
576 
577 //==========================================================================
578 //
579 //  W_Profile
580 //
581 //==========================================================================
582 
583 #if 0
584 void W_Profile()
585 {
586 	static int	info[2500][10];
587 	static int	profilecount = 0;
588 	int			i;
589 	memblock_t*	block;
590 	void*		ptr;
591 	char		ch;
592 	FILE*		f;
593 	int			j;
594 	char		name[16];
595 
596 	sprintf(name,"jl/waddump%d.txt", profilecount);
597 
598 	for (i = 0; i < numlumps; i++)
599 	{
600 		ptr = lumpcache[i];
601 		if (!ptr)
602 		{
603 			ch = ' ';
604 			continue;
605 		}
606 		else
607 		{
608 			block = (memblock_t *)((byte *)ptr - sizeof(memblock_t));
609 			if (block->tag < PU_PURGELEVEL)
610 				ch = 'S';
611 			else
612 				ch = 'P';
613 		}
614 		info[i][profilecount] = ch;
615 	}
616 	profilecount++;
617 
618 	f = fopen(name, "w");
619 	name[8] = 0;
620 
621 	for (i=0 ; i<numlumps ; i++)
622 	{
623 		memcpy (name,lumpinfo[i].name,8);
624 
625 		for (j=0 ; j<8 ; j++)
626 			if (!name[j])
627 				break;
628 
629 		for ( ; j<8 ; j++)
630 			name[j] = ' ';
631 
632 		fprintf (f,"%i %s %i ", i, name, lumpinfo[i].prev);
633 
634 //		for (j=0 ; j<profilecount ; j++)
635 //			fprintf (f,"    %c",info[i][j]);
636 
637 		fprintf (f,"\n");
638 	}
639 	fclose (f);
640 }
641 #endif
642 
643 //==========================================================================
644 //
645 //  W_Shutdown
646 //
647 //==========================================================================
648 
W_Shutdown()649 void W_Shutdown()
650 {
651 	guard(W_Shutdown);
652 	for (int i = 0; i < SearchPaths.Num(); i++)
653 	{
654 		delete SearchPaths[i];
655 		SearchPaths[i] = NULL;
656 	}
657 	SearchPaths.Clear();
658 	unguard;
659 }
660