1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** $Id: fs_wad.cpp 4102 2009-11-13 00:22:29Z 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 // HEADER FILES ------------------------------------------------------------
27
28 #include "gamedefs.h"
29 #include "fs_local.h"
30 #include "fwaddefs.h"
31
32 // MACROS ------------------------------------------------------------------
33
34 // TYPES -------------------------------------------------------------------
35
36 struct lumpinfo_t
37 {
38 VName Name;
39 vint32 Position;
40 vint32 Size;
41 EWadNamespace Namespace;
42 };
43
44 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
45
46 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
47
48 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
49
50 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
51
52 // PUBLIC DATA DEFINITIONS -------------------------------------------------
53
54 // PRIVATE DATA DEFINITIONS ------------------------------------------------
55
56 // CODE --------------------------------------------------------------------
57
58 //==========================================================================
59 //
60 // VWadFile::VWadFile
61 //
62 //==========================================================================
63
VWadFile()64 VWadFile::VWadFile()
65 : Stream(NULL)
66 , NumLumps(0)
67 , LumpInfo(NULL)
68 {
69 }
70
71 //==========================================================================
72 //
73 // VWadFile::~VWadFile
74 //
75 //==========================================================================
76
~VWadFile()77 VWadFile::~VWadFile()
78 {
79 Close();
80 }
81
82 //==========================================================================
83 //
84 // VWadFile::Open
85 //
86 //==========================================================================
87
Open(const VStr & FileName,const VStr & AGwaDir,bool FixVoices,VStream * InStream)88 void VWadFile::Open(const VStr& FileName, const VStr& AGwaDir, bool FixVoices,
89 VStream* InStream)
90 {
91 guard(VWadFile::Open);
92 wadinfo_t header;
93 lumpinfo_t* lump_p;
94 int i, j;
95 int length;
96 filelump_t* fileinfo;
97 filelump_t* fi_p;
98
99 Name = FileName;
100 GwaDir = AGwaDir;
101
102 if (InStream)
103 {
104 Stream = InStream;
105 }
106 else
107 {
108 // open the file and add to directory
109 Stream = FL_OpenSysFileRead(FileName);
110 if (!Stream)
111 {
112 Sys_Error("Couldn't open %s", *FileName);
113 }
114 }
115 GCon->Logf(NAME_Init, "adding %s", *FileName);
116
117 // WAD file
118 Stream->Serialise(&header, sizeof(header));
119 if (VStr::NCmp(header.identification, "IWAD", 4))
120 {
121 // Homebrew levels?
122 if (VStr::NCmp(header.identification, "PWAD", 4))
123 {
124 Sys_Error ("Wad file %s doesn't have IWAD "
125 "or PWAD id\n", *FileName);
126 }
127 }
128 header.numlumps = LittleLong(header.numlumps);
129 header.infotableofs = LittleLong(header.infotableofs);
130 NumLumps = header.numlumps;
131 // Moved here to make static data less fragmented
132 LumpInfo = new lumpinfo_t[NumLumps];
133 length = header.numlumps * sizeof(filelump_t);
134 fi_p = fileinfo = (filelump_t*)Z_Malloc(length);
135 Stream->Seek(header.infotableofs);
136 Stream->Serialise(fileinfo, length);
137
138 // Fill in lumpinfo
139 lump_p = LumpInfo;
140
141 for (i = 0; i < NumLumps; i++, lump_p++, fileinfo++)
142 {
143 // Mac demo hexen.wad: many (1784) of the lump names
144 // have their first character with the high bit (0x80)
145 // set. I don't know the reason for that.. We must
146 // clear the high bits for such Mac wad files to work
147 // in this engine. This shouldn't break other wads.
148 for (j = 0; j < 8; j++)
149 fileinfo->name[j] &= 0x7f;
150 lump_p->Name = VName(fileinfo->name, VName::AddLower8);
151 lump_p->Position = LittleLong(fileinfo->filepos);
152 lump_p->Size = LittleLong(fileinfo->size);
153 lump_p->Namespace = WADNS_Global;
154 }
155
156 Z_Free(fi_p);
157
158 // Set up namespaces.
159 InitNamespaces();
160
161 if (FixVoices)
162 {
163 FixVoiceNamespaces();
164 }
165 unguard;
166 }
167
168 //==========================================================================
169 //
170 // VWadFile::OpenSingleLump
171 //
172 //==========================================================================
173
OpenSingleLump(const VStr & FileName)174 void VWadFile::OpenSingleLump(const VStr& FileName)
175 {
176 guard(VWadFile::OpenSingleLump);
177 // open the file and add to directory
178 Stream = FL_OpenSysFileRead(FileName);
179 if (!Stream)
180 {
181 Sys_Error("Couldn't open %s", *FileName);
182 }
183 GCon->Logf(NAME_Init, "adding %s", *FileName);
184
185 Name = FileName;
186 GwaDir = VStr();
187
188 // single lump file
189 NumLumps = 1;
190 LumpInfo = new lumpinfo_t[1];
191
192 // Fill in lumpinfo
193 LumpInfo->Name = VName(*FileName.ExtractFileBase(), VName::AddLower8);
194 LumpInfo->Position = 0;
195 LumpInfo->Size = Stream->TotalSize();
196 LumpInfo->Namespace = WADNS_Global;
197 unguard;
198 }
199
200 //==========================================================================
201 //
202 // VWadFile::Close
203 //
204 //==========================================================================
205
Close()206 void VWadFile::Close()
207 {
208 guard(VWadFile::Close);
209 if (LumpInfo)
210 {
211 delete[] LumpInfo;
212 LumpInfo = NULL;
213 }
214 NumLumps = 0;
215 Name.Clean();
216 GwaDir.Clean();
217 if (Stream)
218 {
219 delete Stream;
220 Stream = NULL;
221 }
222 unguard;
223 }
224
225 //==========================================================================
226 //
227 // VWadFile::CheckNumForName
228 //
229 // Returns -1 if name not found.
230 //
231 //==========================================================================
232
CheckNumForName(VName LumpName,EWadNamespace InNS)233 int VWadFile::CheckNumForName(VName LumpName, EWadNamespace InNS)
234 {
235 guard(VWadFile::CheckNumForName);
236 // Special ZIP-file namespaces in WAD file are in global namespace.
237 EWadNamespace NS = InNS;
238 if (NS > WADNS_ZipSpecial)
239 {
240 NS = WADNS_Global;
241 }
242
243 for (int i = NumLumps - 1; i >= 0; i--)
244 {
245 if (LumpInfo[i].Namespace == NS && LumpInfo[i].Name == LumpName)
246 {
247 return i;
248 }
249 }
250
251 // Not found.
252 return -1;
253 unguard;
254 }
255
256 //==========================================================================
257 //
258 // VWadFile::ReadFromLump
259 //
260 // Loads part of the lump into the given buffer.
261 //
262 //==========================================================================
263
ReadFromLump(int lump,void * dest,int pos,int size)264 void VWadFile::ReadFromLump(int lump, void* dest, int pos, int size)
265 {
266 guard(VWadFile::ReadFromLump);
267 if ((vuint32)lump >= (vuint32)NumLumps)
268 {
269 Sys_Error("VWadFile::ReadFromLump: %i >= numlumps", lump);
270 }
271
272 lumpinfo_t &l = LumpInfo[lump];
273
274 if (pos >= l.Size)
275 {
276 return;
277 }
278
279 Stream->Seek(l.Position + pos);
280 Stream->Serialise(dest, size);
281 unguard;
282 }
283
284 //==========================================================================
285 //
286 // VWadFile::InitNamespaces
287 //
288 //==========================================================================
289
InitNamespaces()290 void VWadFile::InitNamespaces()
291 {
292 guard(VWadFile::InitNamespaces);
293 InitNamespace(WADNS_Sprites, NAME_s_start, NAME_s_end, NAME_ss_start, NAME_ss_end);
294 InitNamespace(WADNS_Flats, NAME_f_start, NAME_f_end, NAME_ff_start, NAME_ff_end);
295 InitNamespace(WADNS_ColourMaps, NAME_c_start, NAME_c_end, NAME_cc_start, NAME_cc_end);
296 InitNamespace(WADNS_ACSLibrary, NAME_a_start, NAME_a_end, NAME_aa_start, NAME_aa_end);
297 InitNamespace(WADNS_NewTextures, NAME_tx_start, NAME_tx_end);
298 InitNamespace(WADNS_Voices, NAME_v_start, NAME_v_end, NAME_vv_start, NAME_vv_end);
299 InitNamespace(WADNS_HiResTextures, NAME_hi_start, NAME_hi_end);
300 unguard;
301 }
302
303 //==========================================================================
304 //
305 // VWadFile::InitNamespace
306 //
307 //==========================================================================
308
InitNamespace(EWadNamespace NS,VName Start,VName End,VName AltStart,VName AltEnd)309 void VWadFile::InitNamespace(EWadNamespace NS, VName Start, VName End,
310 VName AltStart, VName AltEnd)
311 {
312 guard(VWadFile::InitNamespace);
313 bool InNS = false;
314 for (int i = 0; i < NumLumps; i++)
315 {
316 lumpinfo_t& L = LumpInfo[i];
317
318 // Skip if lump is already in other namespace.
319 if (L.Namespace != WADNS_Global)
320 continue;
321
322 if (InNS)
323 {
324 // Check for ending marker.
325 if (L.Name == End || (AltEnd != NAME_None && L.Name == AltEnd))
326 {
327 InNS = false;
328 }
329 else
330 {
331 L.Namespace = NS;
332 }
333 }
334 else
335 {
336 // Check for starting marker.
337 if (L.Name == Start || (AltStart != NAME_None && L.Name == AltStart))
338 {
339 InNS = true;
340 }
341 }
342 }
343 unguard;
344 }
345
346 //==========================================================================
347 //
348 // VWadFile::FixVoiceNamespaces
349 //
350 //==========================================================================
351
FixVoiceNamespaces()352 void VWadFile::FixVoiceNamespaces()
353 {
354 guard(VWadFile::FixVoiceNamespaces);
355 for (int i = 0; i < NumLumps; i++)
356 {
357 lumpinfo_t& L = LumpInfo[i];
358
359 // Skip if lump is already in other namespace.
360 if (L.Namespace != WADNS_Global)
361 continue;
362
363 const char* LName = *L.Name;
364 if (LName[0] == 'v' && LName[1] == 'o' && LName[2] == 'c' &&
365 LName[3] >= '0' && LName[3] <= '9' &&
366 (LName[4] == 0 || (LName[4] >= '0' && LName[4] <= '9' &&
367 (LName[5] == 0 || (LName[5] >= '0' && LName[5] <= '9' &&
368 (LName[6] == 0 || (LName[6] >= '0' && LName[6] <= '9' &&
369 (LName[7] == 0 || (LName[7] >= '0' && LName[7] <= '9')))))))))
370 {
371 L.Namespace = WADNS_Voices;
372 }
373 }
374 unguard;
375 }
376
377 //==========================================================================
378 //
379 // VWadFile::LumpLength
380 //
381 // Returns the buffer size needed to load the given lump.
382 //
383 //==========================================================================
384
LumpLength(int lump)385 int VWadFile::LumpLength(int lump)
386 {
387 guard(VWadFile::LumpLength);
388 return LumpInfo[lump].Size;
389 unguard;
390 }
391
392 //==========================================================================
393 //
394 // VWadFile::LumpName
395 //
396 //==========================================================================
397
LumpName(int lump)398 VName VWadFile::LumpName(int lump)
399 {
400 guard(VWadFile::LumpName);
401 if (lump >= NumLumps)
402 {
403 return NAME_None;
404 }
405 return LumpInfo[lump].Name;
406 unguard;
407 }
408
409 //==========================================================================
410 //
411 // VWadFile::IterateNS
412 //
413 //==========================================================================
414
IterateNS(int Start,EWadNamespace NS)415 int VWadFile::IterateNS(int Start, EWadNamespace NS)
416 {
417 guard(VWadFile::IterateNS);
418 for (int li = Start; li < NumLumps; li++)
419 {
420 if (LumpInfo[li].Namespace == NS)
421 {
422 return li;
423 }
424 }
425 return -1;
426 unguard;
427 }
428
429 //==========================================================================
430 //
431 // VWadFile::BuildGLNodes
432 //
433 //==========================================================================
434
BuildGLNodes(VSearchPath * GlWad)435 void VWadFile::BuildGLNodes(VSearchPath* GlWad)
436 {
437 guard(VWadFile::BuildGLNodes);
438 #ifdef CLIENT
439 VStr gwaname;
440 if (GwaDir.IsNotEmpty())
441 {
442 FL_CreatePath(GwaDir);
443 gwaname = GwaDir + "/" + Name.ExtractFileName();
444 }
445 else
446 gwaname = Name;
447 gwaname = gwaname.StripExtension() + ".gwa";
448
449 // Build GL nodes
450 if (!GLBSP_BuildNodes(*Name, *gwaname))
451 {
452 Sys_Error("Node build failed");
453 }
454
455 // Build PVS
456 GLVis_BuildPVS(*Name, *gwaname);
457
458 // Add GWA file
459 ((VWadFile*)GlWad)->Open(gwaname, VStr(), false, NULL);
460 #endif
461 unguard;
462 }
463
464 //==========================================================================
465 //
466 // VWadFile::BuildPVS
467 //
468 //==========================================================================
469
BuildPVS(VSearchPath * BaseWad)470 void VWadFile::BuildPVS(VSearchPath* BaseWad)
471 {
472 guard(VWadFile::BuildPVS);
473 #ifdef CLIENT
474 VStr name = ((VWadFile*)BaseWad)->Name;
475
476 VStr glname = Name;
477
478 // Close old file
479 Close();
480
481 // Build PVS
482 GLVis_BuildPVS(*name, BaseWad != this ? *glname : NULL);
483
484 // Add GWA file
485 Open(glname, VStr(), false, NULL);
486 #endif
487 unguard;
488 }
489
490 //==========================================================================
491 //
492 // VWadFile::CreateLumpReaderNum
493 //
494 //==========================================================================
495
CreateLumpReaderNum(int lump)496 VStream* VWadFile::CreateLumpReaderNum(int lump)
497 {
498 guard(VWadFile::CreateLumpReaderNum);
499 check((vuint32)lump < (vuint32)NumLumps);
500 lumpinfo_t &l = LumpInfo[lump];
501
502 // read the lump in
503 void* ptr = Z_Malloc(l.Size);
504 if (l.Size)
505 {
506 Stream->Seek(l.Position);
507 Stream->Serialise(ptr, l.Size);
508 }
509
510
511 // Create stream.
512 VStream* S = new VMemoryStream(ptr, l.Size);
513 Z_Free(ptr);
514 return S;
515 unguard;
516 }
517
518 //==========================================================================
519 //
520 // VWadFile::RenameSprites
521 //
522 //==========================================================================
523
RenameSprites(const TArray<VSpriteRename> & A,const TArray<VLumpRename> & LA)524 void VWadFile::RenameSprites(const TArray<VSpriteRename>& A,
525 const TArray<VLumpRename>& LA)
526 {
527 guard(VWadFile::RenameSprites);
528 for (int i = 0; i < NumLumps; i++)
529 {
530 lumpinfo_t& L = LumpInfo[i];
531 if (L.Namespace != WADNS_Sprites)
532 {
533 continue;
534 }
535 for (int j = 0; j < A.Num(); j++)
536 {
537 if ((*L.Name)[0] != A[j].Old[0] || (*L.Name)[1] != A[j].Old[1] ||
538 (*L.Name)[2] != A[j].Old[2] || (*L.Name)[3] != A[j].Old[3])
539 {
540 continue;
541 }
542 char NewName[12];
543 VStr::Cpy(NewName, *L.Name);
544 NewName[0] = A[j].New[0];
545 NewName[1] = A[j].New[1];
546 NewName[2] = A[j].New[2];
547 NewName[3] = A[j].New[3];
548 L.Name = NewName;
549 }
550 for (int j = 0; j < LA.Num(); j++)
551 {
552 if (L.Name == LA[j].Old)
553 {
554 L.Name = LA[j].New;
555 }
556 }
557 }
558 unguard;
559 }
560
CheckNumForFileName(VStr)561 int VWadFile::CheckNumForFileName(VStr)
562 {
563 return -1;
564 }
565
FileExists(const VStr &)566 bool VWadFile::FileExists(const VStr&)
567 {
568 return false;
569 }
570
OpenFileRead(const VStr &)571 VStream* VWadFile::OpenFileRead(const VStr&)
572 {
573 return NULL;
574 }
575