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