diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 78e4baefc..c7d3ef58f 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,21 @@ -April 17, 2009 +April 23, 2009 (Changes by Graf Zahl) +- complete restructuring of resource file handling for more flexibility and future + extensions. +- Removed merging of special namespaces. For the texture manager this has + become totally useless so there is no need to do this anymore. Not merging + the namespaces also allows a much more reliable detection of lumps belonging + to special namespaces so the ScanForFlatHack function is no longer needed. + Instead, any lump up to F_END with a length of 4096 will be marked for + inclusion as a flat texture if no F_START marker is found. + +April 21, 2009 (Changes by Graf Zahl) +- fixed MustConfirm parsing in MAPINFO + +April 19, 2009 (Changes by Graf Zahl) +- Made the counting of intermission stats in Doom a GAMEINFO option so that + it can be activated in all games. + +April 17, 2009 - Gave the intermission screen sounds their own SNDINFO entries. April 16, 2009 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e172865f1..618d0143a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -656,6 +656,14 @@ add_executable( zdoom WIN32 oplsynth/music_opldumper_mididevice.cpp oplsynth/music_opl_mididevice.cpp oplsynth/opl_mus_player.cpp + resourcefiles/file_7z.cpp + resourcefiles/file_grp.cpp + resourcefiles/file_lump.cpp + resourcefiles/file_rff.cpp + resourcefiles/file_wad.cpp + resourcefiles/file.zip.cpp + resourcefiles/file_pak.cpp + resourcefiles/resourcefile.cpp sfmt/SFMT.cpp sound/fmodsound.cpp sound/i_music.cpp diff --git a/src/files.h b/src/files.h index 22e90f960..5ee70e3fd 100644 --- a/src/files.h +++ b/src/files.h @@ -29,6 +29,7 @@ public: void ResetFilePtr (); FILE *GetFile () const { return File; } + virtual const char *GetBuffer() const { return NULL; } FileReader &operator>> (BYTE &v) { @@ -279,6 +280,7 @@ public: virtual long Seek (long offset, int origin); virtual long Read (void *buffer, long len); virtual char *Gets(char *strbuf, int len); + virtual const char *GetBuffer() const { return bufptr; } protected: const char * bufptr; diff --git a/src/gi.cpp b/src/gi.cpp index 514b09e74..668a55b7e 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -260,6 +260,7 @@ void FMapInfoParser::ParseGameInfo() GAMEINFOKEY_STRING(intermissionMusic, "intermissionMusic") GAMEINFOKEY_BOOL(noloopfinalemusic, "noloopfinalemusic") GAMEINFOKEY_BOOL(drawreadthis, "drawreadthis") + GAMEINFOKEY_BOOL(intermissioncounter, "intermissioncounter") else { // ignore unkown keys. diff --git a/src/gi.h b/src/gi.h index 09908e5a3..4642e02e0 100644 --- a/src/gi.h +++ b/src/gi.h @@ -69,6 +69,7 @@ struct gameinfo_t char titlePage[9]; bool drawreadthis; bool noloopfinalemusic; + bool intermissioncounter; TArray creditPages; TArray finalePages; TArray infoPages; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 95833f398..ceb80180c 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -68,6 +68,7 @@ void P_SpawnSlopeMakers (FMapThing *firstmt, FMapThing *lastmt); void P_SetSlopes (); +void BloodCrypt (void *data, int key, int len); extern AActor *P_SpawnMapThing (FMapThing *mthing, int position); extern bool P_LoadBuildMap (BYTE *mapdata, size_t len, FMapThing **things, int *numthings); diff --git a/src/r_data.cpp b/src/r_data.cpp index b999b641e..0691dcac8 100644 --- a/src/r_data.cpp +++ b/src/r_data.cpp @@ -48,22 +48,22 @@ #include "v_palette.h" -static int R_CountGroup (const char *start, const char *end); static int R_CountTexturesX (); static int R_CountLumpTextures (int lumpnum); extern void R_DeinitBuildTiles(); extern int R_CountBuildTiles(); -static struct FakeCmap +struct FakeCmap { char name[8]; PalEntry blend; -} *fakecmaps; + int lump; +}; -size_t numfakecmaps; -int firstfakecmap; +TArray fakecmaps; BYTE *realcolormaps; +size_t numfakecmaps; //========================================================================== // @@ -138,24 +138,39 @@ void R_InitColormaps () // [RH] Try and convert BOOM colormaps into blending values. // This is a really rough hack, but it's better than // not doing anything with them at all (right?) - int lastfakecmap = Wads.CheckNumForName ("C_END"); - firstfakecmap = Wads.CheckNumForName ("C_START"); - if (firstfakecmap == -1 || lastfakecmap == -1) - numfakecmaps = 1; - else - numfakecmaps = lastfakecmap - firstfakecmap; - realcolormaps = new BYTE[256*NUMCOLORMAPS*numfakecmaps]; - fakecmaps = new FakeCmap[numfakecmaps]; + FakeCmap cm; - fakecmaps[0].name[0] = 0; + cm.name[0] = 0; + cm.blend = 0; + fakecmaps.Push(cm); + + DWORD NumLumps = Wads.GetNumLumps(); + + for (DWORD i = 0; i < NumLumps; i++) + { + if (Wads.GetLumpNamespace(i) == ns_colormaps) + { + char name[9]; + name[8] = 0; + Wads.GetLumpName (name, ns_colormaps); + + if (Wads.CheckNumForName (name, ns_colormaps) == i) + { + strncpy(cm.name, name, 8); + cm.blend = 0; + fakecmaps.Push(cm); + } + } + } + realcolormaps = new BYTE[256*NUMCOLORMAPS*fakecmaps.Size()]; R_SetDefaultColormap ("COLORMAP"); - if (numfakecmaps > 1) + if (fakecmaps.Size() > 1) { BYTE unremap[256], remap[256], mapin[256]; int i; - size_t j; + unsigned j; memcpy (remap, GPalette.Remap, 256); memset (unremap, 0, 256); @@ -164,12 +179,12 @@ void R_InitColormaps () unremap[remap[i]] = i; } remap[0] = 0; - for (i = ++firstfakecmap, j = 1; j < numfakecmaps; i++, j++) + for (j = 1; j < fakecmaps.Size(); j++) { - if (Wads.LumpLength (i) >= (NUMCOLORMAPS+1)*256) + if (Wads.LumpLength (fakecmaps[j].lump) >= (NUMCOLORMAPS+1)*256) { int k, r, g, b; - FWadLump lump = Wads.OpenLumpNum (i); + FWadLump lump = Wads.OpenLumpNum (fakecmaps[j].lump); BYTE *const map = realcolormaps + NUMCOLORMAPS*256*j; for (k = 0; k < NUMCOLORMAPS; ++k) @@ -191,12 +206,12 @@ void R_InitColormaps () g += GPalette.BaseColors[map[k]].g; b += GPalette.BaseColors[map[k]].b; } - Wads.GetLumpName (fakecmaps[j].name, i); fakecmaps[j].blend = PalEntry (255, r/256, g/256, b/256); } } } NormalLight.Maps = realcolormaps; + numfakecmaps = fakecmaps.Size(); } //========================================================================== @@ -207,11 +222,6 @@ void R_InitColormaps () void R_DeinitColormaps () { - if (fakecmaps != NULL) - { - delete[] fakecmaps; - fakecmaps = NULL; - } if (realcolormaps != NULL) { delete[] realcolormaps; @@ -229,18 +239,20 @@ void R_DeinitColormaps () DWORD R_ColormapNumForName (const char *name) { - int lump; - DWORD blend = 0; - if (strnicmp (name, "COLORMAP", 8)) { // COLORMAP always returns 0 - if (-1 != (lump = Wads.CheckNumForName (name, ns_colormaps)) ) - blend = lump - firstfakecmap + 1; - else if (!strnicmp (name, "WATERMAP", 8)) - blend = MAKEARGB (128,0,0x4f,0xa5); + for(int i=fakecmaps.Size()-1; i > 0; i++) + { + if (!strnicmp(name, fakecmaps[i].name, 8)) + { + return i; + } + } + + if (!strnicmp (name, "WATERMAP", 8)) + return MAKEARGB (128,0,0x4f,0xa5); } - - return blend; + return 0; } //========================================================================== @@ -252,7 +264,7 @@ DWORD R_ColormapNumForName (const char *name) DWORD R_BlendForColormap (DWORD map) { return APART(map) ? map : - map < numfakecmaps ? DWORD(fakecmaps[map].blend) : 0; + map < fakecmaps.Size() ? DWORD(fakecmaps[map].blend) : 0; } //========================================================================== @@ -284,38 +296,34 @@ void R_InitData () int R_GuesstimateNumTextures () { - int numtex; + int numtex = 0; + + for(int i = Wads.GetNumLumps()-1; i>=0; i--) + { + int space = Wads.GetLumpNamespace(i); + switch(space) + { + case ns_flats: + case ns_sprites: + case ns_newtextures: + case ns_hires: + case ns_patches: + case ns_graphics: + numtex++; + break; + + default: + if (Wads.GetLumpFlags(i) & LUMPF_MAYBEFLAT) numtex++; + + break; + } + } - numtex = R_CountGroup ("S_START", "S_END"); - numtex += R_CountGroup ("F_START", "F_END"); - numtex += R_CountGroup ("TX_START", "TX_END"); - numtex += R_CountGroup ("HI_START", "HI_END"); numtex += R_CountBuildTiles (); numtex += R_CountTexturesX (); return numtex; } -//=========================================================================== -// -// R_CountGroup -// -//=========================================================================== - -static int R_CountGroup (const char *start, const char *end) -{ - int startl = Wads.CheckNumForName (start); - int endl = Wads.CheckNumForName (end); - - if (startl < 0 || endl < 0) - { - return 0; - } - else - { - return endl - startl - 1; - } -} - //=========================================================================== // // R_CountTexturesX diff --git a/src/resourcefiles/file_7z.cpp b/src/resourcefiles/file_7z.cpp new file mode 100644 index 000000000..04d9fe4fd --- /dev/null +++ b/src/resourcefiles/file_7z.cpp @@ -0,0 +1,350 @@ +/* +** file_7z.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2009 Randy Heit +** Copyright 2009 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "resourcefile.h" +#include "cmdlib.h" +#include "templates.h" +#include "v_text.h" +#include "w_zip.h" +#include "i_system.h" +#include "w_wad.h" + +extern "C" { +#include "Archive/7z/7zHeader.h" +#include "Archive/7z/7zExtract.h" +#include "Archive/7z/7zIn.h" +#include "7zCrc.h" +} + + +//----------------------------------------------------------------------- +// +// Interface classes to 7z library +// +//----------------------------------------------------------------------- + +extern ISzAlloc g_Alloc; + +struct CZDFileInStream +{ + ISeekInStream s; + FileReader *File; + + CZDFileInStream(FileReader *_file) + { + s.Read = Read; + s.Seek = Seek; + File = _file; + } + + static SRes Read(void *pp, void *buf, size_t *size) + { + CZDFileInStream *p = (CZDFileInStream *)pp; + long numread = p->File->Read(buf, (long)*size); + if (numread < 0) + { + *size = 0; + return SZ_ERROR_READ; + } + *size = numread; + return SZ_OK; + } + + static SRes Seek(void *pp, Int64 *pos, ESzSeek origin) + { + CZDFileInStream *p = (CZDFileInStream *)pp; + int move_method; + int res; + if (origin == SZ_SEEK_SET) + { + move_method = SEEK_SET; + } + else if (origin == SZ_SEEK_CUR) + { + move_method = SEEK_CUR; + } + else if (origin == SZ_SEEK_END) + { + move_method = SEEK_END; + } + else + { + return 1; + } + res = p->File->Seek((long)*pos, move_method); + *pos = p->File->Tell(); + return res; + } +}; + +struct C7zArchive +{ + CSzArEx DB; + CZDFileInStream ArchiveStream; + CLookToRead LookStream; + UInt32 BlockIndex; + Byte *OutBuffer; + size_t OutBufferSize; + + C7zArchive(FileReader *file) : ArchiveStream(file) + { + if (g_CrcTable[1] == 0) + { + CrcGenerateTable(); + } + file->Seek(0, SEEK_SET); + LookToRead_CreateVTable(&LookStream, false); + LookStream.realStream = &ArchiveStream.s; + LookToRead_Init(&LookStream); + SzArEx_Init(&DB); + BlockIndex = 0xFFFFFFFF; + OutBuffer = NULL; + OutBufferSize = 0; + } + + ~C7zArchive() + { + if (OutBuffer != NULL) + { + IAlloc_Free(&g_Alloc, OutBuffer); + } + SzArEx_Free(&DB, &g_Alloc); + } + + SRes Open() + { + return SzArEx_Open(&DB, &LookStream.s, &g_Alloc, &g_Alloc); + } + + SRes Extract(UInt32 file_index, char *buffer) + { + size_t offset, out_size_processed; + SRes res = SzAr_Extract(&DB, &LookStream.s, file_index, + &BlockIndex, &OutBuffer, &OutBufferSize, + &offset, &out_size_processed, + &g_Alloc, &g_Alloc); + if (res == SZ_OK) + { + memcpy(buffer, OutBuffer + offset, out_size_processed); + } + return res; + } +}; +//========================================================================== +// +// Zip Lump +// +//========================================================================== + +struct F7ZLump : public FResourceLump +{ + int Position; + + virtual int FillCache(); + +}; + + +//========================================================================== +// +// Zip file +// +//========================================================================== + +class F7ZFile : public FResourceFile +{ + friend struct F7ZLump; + + F7ZLump *Lumps; + C7zArchive *Archive; + + static int STACK_ARGS lumpcmp(const void * a, const void * b); + +public: + F7ZFile(const char * filename, FileReader *filer); + bool Open(); + virtual ~F7ZFile(); + virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } +}; + + + +int STACK_ARGS F7ZFile::lumpcmp(const void * a, const void * b) +{ + F7ZLump * rec1 = (F7ZLump *)a; + F7ZLump * rec2 = (F7ZLump *)b; + + return stricmp(rec1->FullName, rec2->FullName); +} + + +//========================================================================== +// +// 7Z file +// +//========================================================================== + +F7ZFile::F7ZFile(const char * filename, FileReader *filer) + : FResourceFile(filename, filer) +{ + Lumps = NULL; + Archive = NULL; +} + + +//========================================================================== +// +// Open it +// +//========================================================================== + +bool F7ZFile::Open() +{ + Archive = new C7zArchive(Reader); + int skipped = 0; + SRes res; + + res = Archive->Open(); + if (res != SZ_OK) + { + delete Archive; + Archive = NULL; + Printf("\n"TEXTCOLOR_RED"%s: ", Filename); + if (res == SZ_ERROR_UNSUPPORTED) + { + Printf("Decoder does not support this archive\n"); + } + else if (res == SZ_ERROR_MEM) + { + Printf("Cannot allocate memory\n"); + } + else if (res == SZ_ERROR_CRC) + { + Printf("CRC error\n"); + } + else + { + Printf("error #%d\n", res); + } + return false; + } + NumLumps = Archive->DB.db.NumFiles; + + Lumps = new F7ZLump[NumLumps]; + + F7ZLump *lump_p = Lumps; + for (int i = 0; i < NumLumps; ++i) + { + CSzFileItem *file = &Archive->DB.db.Files[i]; + char name[256]; + + // skip Directories + if (file->IsDir) + { + skipped++; + continue; + } + + strncpy(name, file->Name, countof(name)-1); + name[countof(name)-1] = 0; + FixPathSeperator(name); + strlwr(name); + + lump_p->LumpNameSetup(name); + lump_p->LumpSize = file->Size; + lump_p->Owner = this; + lump_p->Flags = LUMPF_ZIPFILE; + lump_p->Position = i; + lump_p->CheckEmbedded(); + lump_p++; + } + // Resize the lump record array to its actual size + NumLumps -= skipped; + Printf(", %d lumps\n", NumLumps); + + // Entries in archives are sorted alphabetically + qsort(&Lumps[0], NumLumps, sizeof(F7ZLump), lumpcmp); + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +F7ZFile::~F7ZFile() +{ + if (Lumps != NULL) delete [] Lumps; +} + +//========================================================================== +// +// Fills the lump cache and performs decompression +// +//========================================================================== + +int F7ZLump::FillCache() +{ + Cache = new char[LumpSize]; + static_cast(Owner)->Archive->Extract(Position, Cache); + RefCount = 1; + return 1; +} + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile *Check7Z(const char *filename, FileReader *file) +{ + char head[k7zSignatureSize]; + + file->Seek(0, SEEK_SET); + file->Read(&head, k7zSignatureSize); + file->Seek(0, SEEK_SET); + if (!memcmp(head, k7zSignature, k7zSignatureSize)) + { + FResourceFile *rf = new F7ZFile(filename, file); + if (rf->Open()) return rf; + delete rf; + } + return NULL; +} + + + diff --git a/src/resourcefiles/file_grp.cpp b/src/resourcefiles/file_grp.cpp new file mode 100644 index 000000000..f51f84846 --- /dev/null +++ b/src/resourcefiles/file_grp.cpp @@ -0,0 +1,152 @@ +/* +** file_grp.cpp +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** Copyright 2005-2009 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "resourcefile.h" +#include "cmdlib.h" +#include "v_text.h" +#include "w_wad.h" + +//========================================================================== +// +// +// +//========================================================================== + +struct GrpInfo +{ + DWORD Magic[3]; + DWORD NumLumps; +}; + +struct GrpLump +{ + union + { + struct + { + char Name[12]; + DWORD Size; + }; + char NameWithZero[13]; + }; +}; + + +//========================================================================== +// +// Build GRP file +// +//========================================================================== + +class FGrpFile : public FUncompressedFile +{ +public: + FGrpFile(const char * filename, FileReader *file); + bool Open(); +}; + + +//========================================================================== +// +// Initializes a Build GRP file +// +//========================================================================== + +FGrpFile::FGrpFile(const char *filename, FileReader *file) +: FUncompressedFile(filename, file) +{ + Lumps = NULL; +} + +//========================================================================== +// +// Open it +// +//========================================================================== + +bool FGrpFile::Open() +{ + GrpInfo header; + + Reader->Read(&header, sizeof(header)); + NumLumps = LittleLong(header.NumLumps); + + GrpLump *fileinfo = new GrpLump[NumLumps]; + Reader->Read (fileinfo, NumLumps * sizeof(GrpLump)); + + Lumps = new FUncompressedLump[NumLumps]; + + int Position = sizeof(GrpInfo) + NumLumps * sizeof(GrpLump); + + for(DWORD i = 0; i < NumLumps; i++) + { + Lumps[i].Owner = this; + Lumps[i].Position = Position; + Lumps[i].LumpSize = LittleLong(fileinfo[i].Size); + Position += fileinfo[i].Size; + Lumps[i].Namespace = ns_global; + Lumps[i].Flags = 0; + fileinfo[i].NameWithZero[12] = '\0'; // Be sure filename is null-terminated + Lumps[i].LumpNameSetup(fileinfo[i].NameWithZero); + } + Printf(", %d lumps\n", NumLumps); + + delete[] fileinfo; + return true; +} + + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile *CheckGRP(const char *filename, FileReader *file) +{ + char head[12]; + + file->Seek(0, SEEK_SET); + file->Read(&head, 12); + file->Seek(0, SEEK_SET); + if (!memcmp(head, "KenSilverman", 12)) + { + FResourceFile *rf = new FGrpFile(filename, file); + if (rf->Open()) return rf; + delete rf; + } + return NULL; +} + diff --git a/src/resourcefiles/file_lump.cpp b/src/resourcefiles/file_lump.cpp new file mode 100644 index 000000000..da549f874 --- /dev/null +++ b/src/resourcefiles/file_lump.cpp @@ -0,0 +1,100 @@ +/* +** file_lump.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2009 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "resourcefile.h" +#include "cmdlib.h" +#include "v_text.h" +#include "w_wad.h" + +//========================================================================== +// +// Single lump +// +//========================================================================== + +class FLumpFile : public FUncompressedFile +{ +public: + FLumpFile(const char * filename, FileReader *file); + bool Open(); +}; + + +//========================================================================== +// +// FLumpFile::FLumpFile +// +//========================================================================== + +FLumpFile::FLumpFile(const char *filename, FileReader *file) : FUncompressedFile(filename, file) +{ +} + +//========================================================================== +// +// Open it +// +//========================================================================== + +bool FLumpFile::Open() +{ + FString name(ExtractFileBase (Filename)); + + Lumps = new FUncompressedLump[1]; // must use array allocator + uppercopy(Lumps->Name, name); + Lumps->Name[8] = 0; + Lumps->Owner = this; + Lumps->Position = 0; + Lumps->LumpSize = Reader->GetLength(); + Lumps->Namespace = ns_global; + Lumps->Flags = 0; + Lumps->FullName = NULL; + return true; +} + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile *CheckLump(const char *filename, FileReader *file) +{ + // always succeeds + FResourceFile *rf = new FLumpFile(filename, file); + if (rf->Open()) return rf; + delete rf; + return NULL; +} + diff --git a/src/resourcefiles/file_pak.cpp b/src/resourcefiles/file_pak.cpp new file mode 100644 index 000000000..badfc23e6 --- /dev/null +++ b/src/resourcefiles/file_pak.cpp @@ -0,0 +1 @@ +// not implemented yet diff --git a/src/resourcefiles/file_rff.cpp b/src/resourcefiles/file_rff.cpp new file mode 100644 index 000000000..b570e5f56 --- /dev/null +++ b/src/resourcefiles/file_rff.cpp @@ -0,0 +1,251 @@ +/* +** file_rff.cpp +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** Copyright 2005-2009 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "resourcefile.h" +#include "cmdlib.h" +#include "templates.h" +#include "v_text.h" +#include "w_wad.h" + +//========================================================================== +// +// +// +//========================================================================== + +struct RFFInfo +{ + // Should be "RFF\x18" + DWORD Magic; + DWORD Version; + DWORD DirOfs; + DWORD NumLumps; +}; + +struct RFFLump +{ + BYTE IDontKnow[16]; + DWORD FilePos; + DWORD Size; + BYTE IStillDontKnow[8]; + BYTE Flags; + char Extension[3]; + char Name[8+4]; // 4 bytes that I don't know what they are for +}; + +//========================================================================== +// +// Blood RFF lump (uncompressed lump with encryption) +// +//========================================================================== + +struct FRFFLump : public FUncompressedLump +{ + virtual FileReader *GetReader(); + virtual int FillCache(); +}; + +//========================================================================== +// +// BloodCrypt +// +//========================================================================== + +void BloodCrypt (void *data, int key, int len) +{ + int p = (BYTE)key, i; + + for (i = 0; i < len; ++i) + { + ((BYTE *)data)[i] ^= (unsigned char)(p+(i>>1)); + } +} + + +//========================================================================== +// +// Blood RFF file +// +//========================================================================== + +class FRFFFile : public FResourceFile +{ + FRFFLump *Lumps; + +public: + FRFFFile(const char * filename, FileReader *file); + virtual ~FRFFFile(); + virtual bool Open(); + virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } +}; + + +//========================================================================== +// +// Initializes a Blood RFF file +// +//========================================================================== + +FRFFFile::FRFFFile(const char *filename, FileReader *file) +: FResourceFile(filename, file) +{ + Lumps = NULL; +} + +//========================================================================== +// +// Initializes a Blood RFF file +// +//========================================================================== + +bool FRFFFile::Open() +{ + RFFLump *lumps; + RFFInfo header; + + Reader->Read(&header, sizeof(header)); + + NumLumps = LittleLong(header.NumLumps); + header.DirOfs = LittleLong(header.DirOfs); + lumps = new RFFLump[header.NumLumps]; + Reader->Seek (header.DirOfs, SEEK_SET); + Reader->Read (lumps, header.NumLumps * sizeof(RFFLump)); + BloodCrypt (lumps, header.DirOfs, header.NumLumps * sizeof(RFFLump)); + + Lumps = new FRFFLump[NumLumps]; + + Printf(", %d lumps\n", NumLumps); + for (DWORD i = 0; i < NumLumps; ++i) + { + if (lumps[i].Extension[0] == 'S' && lumps[i].Extension[1] == 'F' && + lumps[i].Extension[2] == 'X') + { + Lumps[i].Namespace = ns_bloodsfx; + } + else if (lumps[i].Extension[0] == 'R' && lumps[i].Extension[1] == 'A' && + lumps[i].Extension[2] == 'W') + { + Lumps[i].Namespace = ns_bloodraw; + } + else + { + Lumps[i].Namespace = ns_global; + } + + Lumps[i].Position = LittleLong(lumps[i].FilePos); + Lumps[i].LumpSize = LittleLong(lumps[i].Size); + Lumps[i].Owner = this; + if (lumps[i].Flags & 0x10) Lumps[i].Flags |= LUMPF_BLOODCRYPT; + + // Rearrange the name and extension in a part of the lump record + // that I don't have any use for in order to cnstruct the fullname. + lumps[i].Name[8] = '\0'; + strcpy ((char *)lumps[i].IDontKnow, lumps[i].Name); + strcat ((char *)lumps[i].IDontKnow, "."); + strcat ((char *)lumps[i].IDontKnow, lumps[i].Extension); + Lumps[i].LumpNameSetup((char *)lumps[i].IDontKnow); + } + delete[] lumps; + return true; +} + +FRFFFile::~FRFFFile() +{ + if (Lumps != NULL) delete [] Lumps; +} + + +//========================================================================== +// +// Get reader (only returns non-NULL if not encrypted) +// +//========================================================================== + +FileReader *FRFFLump::GetReader() +{ + // Don't return the reader if this lump is encrypted + // In that case always force caching of the lump + if (!(Flags & LUMPF_BLOODCRYPT)) return FUncompressedLump::GetReader(); + else return NULL; +} + +//========================================================================== +// +// Fills the lump cache and performs decryption +// +//========================================================================== + +int FRFFLump::FillCache() +{ + int res = FUncompressedLump::FillCache(); + + if (Flags & LUMPF_BLOODCRYPT) + { + int cryptlen = MIN (LumpSize, 256); + BYTE *data = (BYTE *)Cache; + + for (int i = 0; i < cryptlen; ++i) + { + data[i] ^= i >> 1; + } + } + return res; +} + + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile *CheckRFF(const char *filename, FileReader *file) +{ + char head[4]; + + file->Seek(0, SEEK_SET); + file->Read(&head, 4); + file->Seek(0, SEEK_SET); + if (!memcmp(head, "RFF\x1a", 4)) + { + FResourceFile *rf = new FRFFFile(filename, file); + if (rf->Open()) return rf; + delete rf; + } + return NULL; +} + + + diff --git a/src/resourcefiles/file_wad.cpp b/src/resourcefiles/file_wad.cpp new file mode 100644 index 000000000..704acbbea --- /dev/null +++ b/src/resourcefiles/file_wad.cpp @@ -0,0 +1,332 @@ +/* +** file_wad.cpp +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** Copyright 2005-2009 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "resourcefile.h" +#include "cmdlib.h" +#include "v_text.h" +#include "w_wad.h" + +//========================================================================== +// +// Wad file +// +//========================================================================== + +class FWadFile : public FUncompressedFile +{ + bool IsMarker(int lump, const char *marker); + void SetNamespace(const char *startmarker, const char *endmarker, namespace_t space, bool flathack=false); + void SkinHack (); + +public: + FWadFile(const char * filename, FileReader *file); + void FindStrifeTeaserVoices (); + bool Open(); +}; + + +//========================================================================== +// +// FWadFile::FWadFile +// +// Initializes a WAD file +// +//========================================================================== + +FWadFile::FWadFile(const char *filename, FileReader *file) : FUncompressedFile(filename, file) +{ + Lumps = NULL; +} + +//========================================================================== +// +// Open it +// +//========================================================================== + +bool FWadFile::Open() +{ + wadinfo_t header; + + Reader->Read(&header, sizeof(header)); + NumLumps = LittleLong(header.NumLumps); + header.InfoTableOfs = LittleLong(header.InfoTableOfs); + + wadlump_t *fileinfo = new wadlump_t[NumLumps]; + Reader->Seek (header.InfoTableOfs, SEEK_SET); + Reader->Read (fileinfo, NumLumps * sizeof(wadlump_t)); + + Lumps = new FUncompressedLump[NumLumps]; + + Printf(", %d lumps\n", NumLumps); + + for(DWORD i = 0; i < NumLumps; i++) + { + uppercopy (Lumps[i].Name, fileinfo[i].Name); + Lumps[i].Name[8] = 0; + Lumps[i].Owner = this; + Lumps[i].Position = LittleLong(fileinfo[i].FilePos); + Lumps[i].LumpSize = LittleLong(fileinfo[i].Size); + Lumps[i].Namespace = ns_global; + Lumps[i].Flags = 0; + Lumps[i].FullName = NULL; + } + + SetNamespace("S_START", "S_END", ns_sprites); + SetNamespace("F_START", "F_END", ns_flats, true); + SetNamespace("C_START", "C_END", ns_colormaps); + SetNamespace("A_START", "A_END", ns_acslibrary); + SetNamespace("TX_START", "TX_END", ns_newtextures); + SetNamespace("V_START", "V_END", ns_strifevoices); + SetNamespace("HI_START", "HI_END", ns_hires); + SkinHack(); + delete [] fileinfo; + return true; +} + +//========================================================================== +// +// IsMarker +// +// (from BOOM) +// +//========================================================================== + +inline bool FWadFile::IsMarker(int lump, const char *marker) +{ + if (Lumps[lump].Name[0] == marker[0]) + { + return (!strcmp(Lumps[lump].Name, marker) || + (marker[1] == '_' && !strcmp(Lumps[lump].Name+1, marker))); + } + else return false; +} + +//========================================================================== +// +// SetNameSpace +// +// Sets namespace information for the lumps. It always looks for the first +// x_START and the last x_END lump, except when loading flats. In this case +// F_START may be absent and if that is the case all lumps with a size of +// 4096 will be flagged appropriately. +// +//========================================================================== + +void FWadFile::SetNamespace(const char *startmarker, const char *endmarker, namespace_t space, bool flathack) +{ + int start=-1, end=-1; + bool warned = false; + int i; + + for(i = 0; i < (int)NumLumps; i++) + { + if (IsMarker(i, startmarker)) + { + start = i; + break; + } + } + if (!flathack && start == -1) return; + + for(i = NumLumps-1; i > start; i--) + { + if (IsMarker(i, endmarker)) + { + end = i; + break; + } + } + if (end == -1) return; + + if (start != -1) + { + for(int i = start+1; i < end; i++) + { + if (Lumps[i].Namespace != ns_global) + { + if (!warned) + { + Printf(TEXTCOLOR_YELLOW"WARNING: Overlapping namespaces found.\n"); + } + warned = true; + } + else if (IsMarker(i, startmarker)) + { + Printf(TEXTCOLOR_YELLOW"WARNING: Multiple %s markers found.\n", startmarker); + } + else if (IsMarker(i, endmarker)) + { + Printf(TEXTCOLOR_YELLOW"WARNING: Multiple %s markers found.\n", endmarker); + } + else + { + Lumps[i].Namespace = space; + } + } + } + else if (flathack) + { + Printf(TEXTCOLOR_YELLOW"WARNING: %s marker without corresponding %s found.\n", endmarker, startmarker); + for(int i = 0; i < end; i++) + { + if (Lumps[i].LumpSize == 4096) + { + // We can't add this to the flats namespace but + // it needs to be flagged for the texture manager. + Lumps[i].Flags |= LUMPF_MAYBEFLAT; + } + } + } +} + + +//========================================================================== +// +// W_SkinHack +// +// Tests a wad file to see if it contains an S_SKIN marker. If it does, +// every lump in the wad is moved into a new namespace. Because skins are +// only supposed to replace player sprites, sounds, or faces, this should +// not be a problem. Yes, there are skins that replace more than that, but +// they are such a pain, and breaking them like this was done on purpose. +// This also renames any S_SKINxx lumps to just S_SKIN. +// +//========================================================================== + +void FWadFile::SkinHack () +{ + static int namespc = ns_firstskin; + bool skinned = false; + bool hasmap = false; + DWORD i; + + for (i = 0; i < NumLumps; i++) + { + FResourceLump *lump = &Lumps[i]; + + if (lump->Name[0] == 'S' && + lump->Name[1] == '_' && + lump->Name[2] == 'S' && + lump->Name[3] == 'K' && + lump->Name[4] == 'I' && + lump->Name[5] == 'N') + { // Wad has at least one skin. + lump->Name[6] = lump->Name[7] = 0; + if (!skinned) + { + skinned = true; + DWORD j; + + for (j = 0; j < NumLumps; j++) + { + Lumps[j].Namespace = namespc; + } + namespc++; + } + } + if (lump->Name[0] == 'M' && + lump->Name[1] == 'A' && + lump->Name[2] == 'P') + { + hasmap = true; + } + } + if (skinned && hasmap) + { + Printf (TEXTCOLOR_BLUE + "The maps in %s will not be loaded because it has a skin.\n" + TEXTCOLOR_BLUE + "You should remove the skin from the wad to play these maps.\n", + Filename); + } +} + + +//========================================================================== +// +// FindStrifeTeaserVoices +// +// Strife0.wad does not have the voices between V_START/V_END markers, so +// figure out which lumps are voices based on their names. +// +//========================================================================== + +void FWadFile::FindStrifeTeaserVoices () +{ + for (DWORD i = 0; i <= NumLumps; ++i) + { + if (Lumps[i].Name[0] == 'V' && + Lumps[i].Name[1] == 'O' && + Lumps[i].Name[2] == 'C') + { + int j; + + for (j = 3; j < 8; ++j) + { + if (Lumps[i].Name[j] != 0 && !isdigit(Lumps[i].Name[j])) + break; + } + if (j == 8) + { + Lumps[i].Namespace = ns_strifevoices; + } + } + } +} + + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile *CheckWad(const char *filename, FileReader *file) +{ + char head[4]; + + file->Seek(0, SEEK_SET); + file->Read(&head, 4); + file->Seek(0, SEEK_SET); + if (!memcmp(head, "IWAD", 4) || !memcmp(head, "PWAD", 4)) + { + FResourceFile *rf = new FWadFile(filename, file); + if (rf->Open()) return rf; + delete rf; + } + return NULL; +} + diff --git a/src/resourcefiles/file_zip.cpp b/src/resourcefiles/file_zip.cpp new file mode 100644 index 000000000..a2f4b9e4d --- /dev/null +++ b/src/resourcefiles/file_zip.cpp @@ -0,0 +1,407 @@ +/* +** file_zip.cpp +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** Copyright 2005-2009 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "resourcefile.h" +#include "cmdlib.h" +#include "templates.h" +#include "v_text.h" +#include "w_wad.h" +#include "w_zip.h" +#include "i_system.h" + +#define BUFREADCOMMENT (0x400) + +//----------------------------------------------------------------------- +// +// Finds the central directory end record in the end of the file. +// Taken from Quake3 source but the file in question is not GPL'ed. ;) +// +//----------------------------------------------------------------------- + +static DWORD Zip_FindCentralDir(FileReader * fin) +{ + unsigned char buf[BUFREADCOMMENT + 4]; + DWORD FileSize; + DWORD uBackRead; + DWORD uMaxBack; // maximum size of global comment + DWORD uPosFound=0; + + fin->Seek(0, SEEK_END); + + FileSize = fin->Tell(); + uMaxBack = MIN(0xffff, FileSize); + + uBackRead = 4; + while (uBackRead < uMaxBack) + { + DWORD uReadSize, uReadPos; + int i; + if (uBackRead + BUFREADCOMMENT > uMaxBack) + uBackRead = uMaxBack; + else + uBackRead += BUFREADCOMMENT; + uReadPos = FileSize - uBackRead; + + uReadSize = MIN((BUFREADCOMMENT + 4), (FileSize - uReadPos)); + + if (fin->Seek(uReadPos, SEEK_SET) != 0) break; + + if (fin->Read(buf, (SDWORD)uReadSize) != (SDWORD)uReadSize) break; + + for (i = (int)uReadSize - 3; (i--) > 0;) + { + if (buf[i] == 'P' && buf[i+1] == 'K' && buf[i+2] == 5 && buf[i+3] == 6) + { + uPosFound = uReadPos + i; + break; + } + } + + if (uPosFound != 0) + break; + } + return uPosFound; +} + + +enum +{ + LUMPFZIP_NEEDFILESTART = 128 +}; + +//========================================================================== +// +// Zip Lump +// +//========================================================================== + +struct FZipLump : public FResourceLump +{ + BYTE Method; + int CompressedSize; + int Position; + + virtual FileReader *GetReader(); + virtual int FillCache(); + +private: + void SetLumpAddress(); + virtual int GetFileOffset() + { + if (Method != METHOD_STORED) return -1; + if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); return Position; + } +}; + + +//========================================================================== +// +// Zip file +// +//========================================================================== + +class FZipFile : public FResourceFile +{ + FZipLump *Lumps; + + static int STACK_ARGS lumpcmp(const void * a, const void * b); + +public: + FZipFile(const char * filename, FileReader *file); + virtual ~FZipFile(); + bool Open(); + virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } +}; + + + +int STACK_ARGS FZipFile::lumpcmp(const void * a, const void * b) +{ + FZipLump * rec1 = (FZipLump *)a; + FZipLump * rec2 = (FZipLump *)b; + + return stricmp(rec1->FullName, rec2->FullName); +} + + +//========================================================================== +// +// Zip file +// +//========================================================================== + +FZipFile::FZipFile(const char * filename, FileReader *file) +: FResourceFile(filename, file) +{ + Lumps = NULL; +} + +bool FZipFile::Open() +{ + DWORD centraldir = Zip_FindCentralDir(Reader); + FZipEndOfCentralDirectory info; + int skipped = 0; + + Lumps = NULL; + + if (centraldir == 0) + { + Printf("\n%s: ZIP file corrupt!\n", Filename); + return false; + } + + // Read the central directory info. + Reader->Seek(centraldir, SEEK_SET); + Reader->Read(&info, sizeof(FZipEndOfCentralDirectory)); + + // No multi-disk zips! + if (info.NumEntries != info.NumEntriesOnAllDisks || + info.FirstDisk != 0 || info.DiskNumber != 0) + { + Printf("\n%s: Multipart Zip files are not supported.\n", Filename); + return false; + } + + NumLumps = LittleShort(info.NumEntries); + Lumps = new FZipLump[NumLumps]; + + // Load the entire central directory. Too bad that this contains variable length entries... + void *directory = malloc(LittleLong(info.DirectorySize)); + Reader->Seek(LittleLong(info.DirectoryOffset), SEEK_SET); + Reader->Read(directory, LittleLong(info.DirectorySize)); + + char *dirptr = (char*)directory; + FZipLump *lump_p = Lumps; + for (int i = 0; i < NumLumps; i++) + { + FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr; + + char name[256]; + + int len = LittleShort(zip_fh->NameLength); + strncpy(name, dirptr + sizeof(FZipCentralDirectoryInfo), MIN(len, 255)); + name[len] = 0; + dirptr += sizeof(FZipCentralDirectoryInfo) + + LittleShort(zip_fh->NameLength) + + LittleShort(zip_fh->ExtraLength) + + LittleShort(zip_fh->CommentLength); + + // skip Directories + if(name[len - 1] == '/' && LittleLong(zip_fh->UncompressedSize) == 0) + { + skipped++; + continue; + } + + // Ignore unknown compression formats + zip_fh->Method = LittleShort(zip_fh->Method); + if (zip_fh->Method != METHOD_STORED && + zip_fh->Method != METHOD_DEFLATE && + zip_fh->Method != METHOD_LZMA && + zip_fh->Method != METHOD_BZIP2) + { + Printf("\n%s: '%s' uses an unsupported compression algorithm (#%d).\n", Filename, name, zip_fh->Method); + skipped++; + continue; + } + // Also ignore encrypted entries + if(LittleShort(zip_fh->Flags) & ZF_ENCRYPTED) + { + Printf("\n%s: '%s' is encrypted. Encryption is not supported.\n", Filename, name); + skipped++; + continue; + } + + FixPathSeperator(name); + strlwr(name); + + lump_p->LumpNameSetup(name); + lump_p->LumpSize = LittleLong(zip_fh->UncompressedSize); + lump_p->Owner = this; + // The start of the Reader will be determined the first time it is accessed. + lump_p->Flags = LUMPF_ZIPFILE | LUMPFZIP_NEEDFILESTART; + lump_p->Method = zip_fh->Method; + lump_p->CompressedSize = LittleLong(zip_fh->CompressedSize); + lump_p->Position = LittleLong(zip_fh->LocalHeaderOffset); + lump_p->CheckEmbedded(); + lump_p++; + } + // Resize the lump record array to its actual size + NumLumps -= skipped; + free(directory); + //LumpInfo.Resize(NumLumps); + Printf(", %d lumps\n", NumLumps); + + // Entries in Zips are sorted alphabetically. + qsort(Lumps, NumLumps, sizeof(FZipLump), lumpcmp); + return true; +} + +//========================================================================== +// +// Zip file +// +//========================================================================== + +FZipFile::~FZipFile() +{ + if (Lumps != NULL) delete [] Lumps; +} + +//========================================================================== +// +// SetLumpAddress +// +//========================================================================== + +void FZipLump::SetLumpAddress() +{ + // This file is inside a zip and has not been opened before. + // Position points to the start of the local file header, which we must + // read and skip so that we can get to the actual file data. + FZipLocalFileHeader localHeader; + int skiplen; + + FileReader *file = Owner->Reader; + + file->Seek(Position, SEEK_SET); + file->Read(&localHeader, sizeof(localHeader)); + skiplen = LittleShort(localHeader.NameLength) + LittleShort(localHeader.ExtraLength); + Position += sizeof(localHeader) + skiplen; + Flags &= ~LUMPFZIP_NEEDFILESTART; +} + +//========================================================================== +// +// Get reader (only returns non-NULL if not encrypted) +// +//========================================================================== + +FileReader *FZipLump::GetReader() +{ + // Don't return the reader if this lump is encrypted + // In that case always force caching of the lump + if (Method == METHOD_STORED) + { + if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); + Owner->Reader->Seek(Position, SEEK_SET); + return Owner->Reader; + } + else return NULL; +} + +//========================================================================== +// +// Fills the lump cache and performs decompression +// +//========================================================================== + +int FZipLump::FillCache() +{ + if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); + const char *buffer; + + if (Method == METHOD_STORED && (buffer = Owner->Reader->GetBuffer()) != NULL) + { + // This is an in-memory file so the cache can point directly to the file's data. + Cache = const_cast(buffer) + Position; + RefCount = -1; + return -1; + } + + Owner->Reader->Seek(Position, SEEK_SET); + Cache = new char[LumpSize]; + switch (Method) + { + case METHOD_STORED: + { + Owner->Reader->Read(Cache, LumpSize); + break; + } + + case METHOD_DEFLATE: + { + FileReaderZ frz(*Owner->Reader, true); + frz.Read(Cache, LumpSize); + break; + } + + case METHOD_BZIP2: + { + FileReaderBZ2 frz(*Owner->Reader); + frz.Read(Cache, LumpSize); + break; + } + + case METHOD_LZMA: + { + FileReaderLZMA frz(*Owner->Reader, LumpSize, true); + frz.Read(Cache, LumpSize); + break; + } + + default: + assert(0); + return 0; + } + RefCount = 1; + return 1; +} + + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile *CheckZip(const char *filename, FileReader *file) +{ + char head[4]; + + file->Seek(0, SEEK_SET); + file->Read(&head, 4); + file->Seek(0, SEEK_SET); + if (!memcmp(head, "PK\x3\x4", 4)) + { + FResourceFile *rf = new FZipFile(filename, file); + if (rf->Open()) return rf; + delete rf; + } + return NULL; +} + + + diff --git a/src/resourcefiles/resourcefile.cpp b/src/resourcefiles/resourcefile.cpp new file mode 100644 index 000000000..94fc8260b --- /dev/null +++ b/src/resourcefiles/resourcefile.cpp @@ -0,0 +1,384 @@ +/* +** resourcefile.cpp +** +** Base classes for resource file management +** +**--------------------------------------------------------------------------- +** Copyright 2009 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "resourcefile.h" +#include "cmdlib.h" +#include "w_wad.h" + + + +//========================================================================== +// +// FileReader that reads from a lump's cache +// +//========================================================================== + +class FLumpReader : public MemoryReader +{ + FResourceLump *source; + +public: + FLumpReader(FResourceLump *src) + : MemoryReader(NULL, src->LumpSize), source(src) + { + src->CacheLump(); + bufptr = src->Cache; + } + + ~FLumpReader() + { + source->ReleaseCache(); + } +}; + + +//========================================================================== +// +// Base class for resource lumps +// +//========================================================================== + +FResourceLump::~FResourceLump() +{ + if (FullName != NULL) + { + delete [] FullName; + FullName = NULL; + } + if (Cache != NULL) + { + delete [] Cache; + Cache = NULL; + } + Owner = NULL; +} + + +//========================================================================== +// +// Sets up the lump name information for anything not coming from a WAD file. +// +//========================================================================== + +void FResourceLump::LumpNameSetup(char *iname) +{ + char base[256]; + char *lname = strrchr(iname,'/'); + lname = (lname == NULL) ? iname : lname + 1; + strcpy(base, lname); + char *dot = strrchr(base, '.'); + if (dot != NULL) + { + *dot = 0; + } + uppercopy(Name, base); + Name[8] = 0; + FullName = copystring(iname); + + // Map some directories to WAD namespaces. + // Note that some of these namespaces don't exist in WADS. + // CheckNumForName will handle any request for these namespaces accordingly. + Namespace = !strncmp(iname, "flats/", 6) ? ns_flats : + !strncmp(iname, "textures/", 9) ? ns_newtextures : + !strncmp(iname, "hires/", 6) ? ns_hires : + !strncmp(iname, "sprites/", 8) ? ns_sprites : + !strncmp(iname, "colormaps/", 10) ? ns_colormaps : + !strncmp(iname, "acs/", 4) ? ns_acslibrary : + !strncmp(iname, "voices/", 7) ? ns_strifevoices : + !strncmp(iname, "patches/", 8) ? ns_patches : + !strncmp(iname, "graphics/", 9) ? ns_graphics : + !strncmp(iname, "sounds/", 7) ? ns_sounds : + !strncmp(iname, "music/", 6) ? ns_music : + !strchr(iname, '/') ? ns_global : + -1; + + // Anything that is not in one of these subdirectories or the main directory + // should not be accessible through the standard WAD functions but only through + // the ones which look for the full name. + if (Namespace == -1) + { + memset(Name, 0, 8); + } + + // Since '\' can't be used as a file name's part inside a ZIP + // we have to work around this for sprites because it is a valid + // frame character. + else if (Namespace == ns_sprites) + { + char *c; + + while ((c = (char*)memchr(Name, '^', 8))) + { + *c = '\\'; + } + } +} + +void FResourceLump::CheckEmbedded() +{ + // Checks for embedded archives + const char *c = strstr(Name, ".wad"); + if (c && strlen(c) == 4 && !strchr(Name, '/')) + { + // Mark all embedded WADs + Flags |= LUMPF_EMBEDDED; + } + /* later + else + { + if (c==NULL) c = strstr(Name, ".zip"); + if (c==NULL) c = strstr(Name, ".pk3"); + if (c==NULL) c = strstr(Name, ".7z"); + if (c && strlen(c) <= 4) + { + // Mark all embedded archives in any directory + Flags |= LUMPF_EMBEDDED; + } + } + */ + +} + + +//========================================================================== +// +// Returns the owner's FileReader if it can be used to access this lump +// +//========================================================================== + +FileReader *FResourceLump::GetReader() +{ + return NULL; +} + +//========================================================================== +// +// Returns a file reader to the lump's cache +// +//========================================================================== + +FileReader *FResourceLump::NewReader() +{ + return new FLumpReader(this); +} + +//========================================================================== +// +// Caches a lump's content and increases the reference counter +// +//========================================================================== + +void *FResourceLump::CacheLump() +{ + if (Cache != NULL) + { + if (RefCount > 0) RefCount++; + } + else if (LumpSize > 0) + { + FillCache(); + } + return Cache; +} + +//========================================================================== +// +// Decrements reference counter and frees lump if counter reaches 0 +// +//========================================================================== + +int FResourceLump::ReleaseCache() +{ + if (LumpSize > 0 && RefCount > 0) + { + if (--RefCount == 0) + { + delete [] Cache; + Cache = NULL; + } + } + return RefCount; +} + + + +//========================================================================== +// +// Resource file base class +// +//========================================================================== + +FResourceFile::FResourceFile(const char *filename, FileReader *r) +{ + Filename = copystring(filename); + Reader = r; +} + + +FResourceFile::~FResourceFile() +{ + delete [] Filename; + delete Reader; +} + + +//========================================================================== +// +// Needs to be virtual in the base class. Implemented only for WADs +// +//========================================================================== + +void FResourceFile::FindStrifeTeaserVoices () +{ +} + + +//========================================================================== +// +// Caches a lump's content and increases the reference counter +// +//========================================================================== + +FileReader *FUncompressedLump::GetReader() +{ + Owner->Reader->Seek(Position, SEEK_SET); + return Owner->Reader; +} + +//========================================================================== +// +// Caches a lump's content and increases the reference counter +// +//========================================================================== + +int FUncompressedLump::FillCache() +{ + const char * buffer = Owner->Reader->GetBuffer(); + + if (buffer != NULL) + { + // This is an in-memory file so the cache can point directly to the file's data. + Cache = const_cast(buffer) + Position; + RefCount = -1; + return -1; + } + + Owner->Reader->Seek(Position, SEEK_SET); + Cache = new char[LumpSize]; + Owner->Reader->Read(Cache, LumpSize); + RefCount = 1; + return 1; +} + +//========================================================================== +// +// Base class for uncompressed resource files +// +//========================================================================== + +FUncompressedFile::FUncompressedFile(const char *filename, FileReader *r) +: FResourceFile(filename, r) +{ + Lumps = NULL; +} + +FUncompressedFile::~FUncompressedFile() +{ + if (Lumps != NULL) delete [] Lumps; +} + + + +//========================================================================== +// +// external lump +// +//========================================================================== + +FExternalLump::FExternalLump(const char *_filename, int filesize) +{ + filename = _filename? copystring(_filename) : NULL; + + if (filesize == -1) + { + FILE *f = fopen(_filename,"rb"); + if (f != NULL) + { + fseek(f, 0, SEEK_END); + LumpSize = ftell(f); + fclose(f); + } + else + { + LumpSize = 0; + } + } + else + { + LumpSize = filesize; + } +} + + +FExternalLump::~FExternalLump() +{ + if (filename != NULL) delete [] filename; +} + +//========================================================================== +// +// Caches a lump's content and increases the reference counter +// For external lumps this reopens the file each time it is accessed +// +//========================================================================== + +int FExternalLump::FillCache() +{ + Cache = new char[LumpSize]; + FILE *f = fopen(filename, "rb"); + if (f != NULL) + { + fread(Cache, 1, LumpSize, f); + fclose(f); + } + else + { + memset(Cache, 0, LumpSize); + } + RefCount = 1; + return 1; +} + diff --git a/src/resourcefiles/resourcefile.h b/src/resourcefiles/resourcefile.h new file mode 100644 index 000000000..8ac3264af --- /dev/null +++ b/src/resourcefiles/resourcefile.h @@ -0,0 +1,115 @@ + + +#ifndef __RESFILE_H +#define __RESFILE_H + +#include "files.h" + +class FResourceFile; + +struct FResourceLump +{ + friend class FResourceFile; + + int LumpSize; + char * FullName; // only valid for files loaded from a .zip file + char Name[9]; + BYTE Flags; + BYTE RefCount; + char * Cache; + FResourceFile * Owner; + int Namespace; + + FResourceLump() + { + FullName = NULL; + Cache = NULL; + Owner = NULL; + Flags = 0; + RefCount = 0; + Namespace = 0; // ns_global + *Name = 0; + } + + virtual ~FResourceLump(); + virtual FileReader *GetReader(); + virtual FileReader *NewReader(); + virtual int GetFileOffset() { return -1; } + void LumpNameSetup(char *iname); + void CheckEmbedded(); + + void *CacheLump(); + int ReleaseCache(); + +protected: + virtual int FillCache() = 0; + +}; + +class FResourceFile +{ +public: + FileReader *Reader; + const char *Filename; +protected: + DWORD NumLumps; + + FResourceFile(const char *filename, FileReader *r); + +private: + DWORD FirstLump; + +public: + virtual ~FResourceFile(); + FileReader *GetReader() const { return Reader; } + DWORD LumpCount() const { return NumLumps; } + DWORD GetFirstLump() const { return FirstLump; } + void SetFirstLump(DWORD f) { FirstLump = f; } + + virtual void FindStrifeTeaserVoices (); + virtual bool Open() = 0; + virtual FResourceLump *GetLump(int no) = 0; +}; + +struct FUncompressedLump : public FResourceLump +{ + int Position; + + virtual FileReader *GetReader(); + virtual int FillCache(); + virtual int GetFileOffset() { return Position; } + +}; + + +// Base class for uncompressed resource files (WAD, GRP, PAK and single lumps) +class FUncompressedFile : public FResourceFile +{ +protected: + FUncompressedLump * Lumps; + + + FUncompressedFile(const char *filename, FileReader *r); + virtual ~FUncompressedFile(); + virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } + +public: +}; + + +struct FExternalLump : public FResourceLump +{ + const char *filename; // the actual file name. This is not necessarily the same as the lump name! + + FExternalLump(const char *_filename, int filesize = -1); + ~FExternalLump(); + virtual int FillCache(); + +}; + + + + + + +#endif \ No newline at end of file diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index dcdaa80c5..12f9412ea 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -377,30 +377,12 @@ void FTextureManager::ReplaceTexture (FTextureID picnum, FTexture *newtexture, b // //========================================================================== -void FTextureManager::AddGroup(int wadnum, const char * startlump, const char * endlump, int ns, int usetype) +void FTextureManager::AddGroup(int wadnum, int ns, int usetype) { - int firsttx; - int lasttx; - - if (startlump && endlump) - { - firsttx = Wads.CheckNumForName (startlump); - lasttx = Wads.CheckNumForName (endlump); - } - else - { - // If there are no markers we have to search the entire lump directory... :( - firsttx = 0; - lasttx = Wads.GetNumLumps() - 1; - } - + int firsttx = Wads.GetFirstLump(wadnum); + int lasttx = Wads.GetLastLump(wadnum); char name[9]; - if (firsttx == -1 || lasttx == -1) - { - return; - } - name[8] = 0; // Go from first to last so that ANIMDEFS work as expected. However, @@ -408,9 +390,9 @@ void FTextureManager::AddGroup(int wadnum, const char * startlump, const char * // later ones), the texture is only inserted if it is the one returned // by doing a check by name in the list of wads. - for (firsttx += 1; firsttx < lasttx; ++firsttx) + for (; firsttx <= lasttx; ++firsttx) { - if (Wads.GetLumpFile(firsttx) == wadnum && Wads.GetLumpNamespace(firsttx) == ns) + if (Wads.GetLumpNamespace(firsttx) == ns) { Wads.GetLumpName (name, firsttx); @@ -420,6 +402,14 @@ void FTextureManager::AddGroup(int wadnum, const char * startlump, const char * } StartScreen->Progress(); } + else if (ns == ns_flats && Wads.GetLumpFlags(firsttx) & LUMPF_MAYBEFLAT) + { + if (Wads.CheckNumForName (name, ns) < firsttx) + { + CreateTexture (firsttx, usetype); + } + StartScreen->Progress(); + } } } @@ -431,8 +421,9 @@ void FTextureManager::AddGroup(int wadnum, const char * startlump, const char * void FTextureManager::AddHiresTextures (int wadnum) { - int firsttx = Wads.CheckNumForName ("HI_START"); - int lasttx = Wads.CheckNumForName ("HI_END"); + int firsttx = Wads.GetFirstLump(wadnum); + int lasttx = Wads.GetLastLump(wadnum); + char name[9]; TArray tlist; @@ -443,15 +434,15 @@ void FTextureManager::AddHiresTextures (int wadnum) name[8] = 0; - for (firsttx += 1; firsttx < lasttx; ++firsttx) + for (;firsttx <= lasttx; ++firsttx) { - if (Wads.GetLumpFile(firsttx) == wadnum) + if (Wads.GetLumpNamespace(firsttx) == ns_hires) { - tlist.Clear(); Wads.GetLumpName (name, firsttx); if (Wads.CheckNumForName (name, ns_hires) == firsttx) { + tlist.Clear(); int amount = ListTextures(name, tlist); if (amount == 0) { @@ -717,28 +708,27 @@ void FTextureManager::AddTexturesForWad(int wadnum) int lumpcount = Wads.GetNumLumps(); // First step: Load sprites - AddGroup(wadnum, "S_START", "S_END", ns_sprites, FTexture::TEX_Sprite); + AddGroup(wadnum, ns_sprites, FTexture::TEX_Sprite); // When loading a Zip, all graphics in the patches/ directory should be // added as well. - AddGroup(wadnum, NULL, NULL, ns_patches, FTexture::TEX_WallPatch); + AddGroup(wadnum, ns_patches, FTexture::TEX_WallPatch); // Second step: TEXTUREx lumps LoadTextureX(wadnum); // Third step: Flats - AddGroup(wadnum, "F_START", "F_END", ns_flats, FTexture::TEX_Flat); + AddGroup(wadnum, ns_flats, FTexture::TEX_Flat); // Fourth step: Textures (TX_) - AddGroup(wadnum, "TX_START", "TX_END", ns_newtextures, FTexture::TEX_Override); + AddGroup(wadnum, ns_newtextures, FTexture::TEX_Override); // Sixth step: Try to find any lump in the WAD that may be a texture and load as a TEX_MiscPatch - for (int i = 0; i < lumpcount; i++) - { - int file = Wads.GetLumpFile(i); - if (file > wadnum) break; // lumps in the global namespace are ordered by WAD - if (file < wadnum) continue; + int firsttx = Wads.GetFirstLump(wadnum); + int lasttx = Wads.GetLastLump(wadnum); + for (int i= firsttx; i <= lasttx; i++) + { char name[9]; Wads.GetLumpName(name, i); name[8]=0; @@ -766,7 +756,7 @@ void FTextureManager::AddTexturesForWad(int wadnum) if (Wads.CheckLumpName(i, "BLOCKMAP")) continue; if (Wads.CheckLumpName(i, "BEHAVIOR")) continue; - // Don't bother looking this lump if something later overrides it. + // Don't bother looking at this lump if something later overrides it. if (Wads.CheckNumForName(name, ns_graphics) != i) continue; // skip this if it has already been added as a wall patch. diff --git a/src/textures/textures.h b/src/textures/textures.h index af6fe7268..aa8e4eb15 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -300,7 +300,7 @@ public: void AddTexturesLump (const void *lumpdata, int lumpsize, int deflumpnum, int patcheslump, int firstdup=0, bool texture1=false); void AddTexturesLumps (int lump1, int lump2, int patcheslump); - void AddGroup(int wadnum, const char * startlump, const char * endlump, int ns, int usetype); + void AddGroup(int wadnum, int ns, int usetype); void AddPatches (int lumpnum); void AddTiles (void *tileFile); void AddHiresTextures (int wadnum); diff --git a/src/w_wad.cpp b/src/w_wad.cpp index 33a9b8a35..0703a55c7 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -29,6 +29,8 @@ #include "v_text.h" #include "templates.h" #include "gi.h" +#include "doomerrors.h" +#include "resourcefiles/resourcefile.h" extern "C" { #include "Archive/7z/7zHeader.h" @@ -39,219 +41,19 @@ extern "C" { // MACROS ------------------------------------------------------------------ -#define NULL_INDEX (0xffff) - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -extern ISzAlloc g_Alloc; - -// TYPES ------------------------------------------------------------------- - -struct rffinfo_t -{ - // Should be "RFF\x18" - DWORD Magic; - DWORD Version; - DWORD DirOfs; - DWORD NumLumps; -}; - -struct rfflump_t -{ - BYTE IDontKnow[16]; - DWORD FilePos; - DWORD Size; - BYTE IStillDontKnow[8]; - BYTE Flags; - char Extension[3]; - char Name[8+4]; // 4 bytes that I don't know what they are for -}; - -struct grpinfo_t -{ - DWORD Magic[3]; - DWORD NumLumps; -}; - -struct grplump_t -{ - union - { - struct - { - char Name[12]; - DWORD Size; - }; - char NameWithZero[13]; - }; -}; - -union MergedHeader -{ - DWORD magic[3]; - wadinfo_t wad; - rffinfo_t rff; - grpinfo_t grp; - BYTE sevenzip[k7zSignatureSize]; -}; - +#define NULL_INDEX (0xffffffff) // // WADFILE I/O related stuff. // struct FWadCollection::LumpRecord { - char * fullname; // only valid for files loaded from a .zip file - char name[9]; - BYTE method; // zip compression method - BYTE flags; - short wadnum; - int position; - int size; - int namespc; - int compressedsize; - - void ZipNameSetup(char *name); -}; - -struct CZDFileInStream -{ - ISeekInStream s; - FileReader *File; - - CZDFileInStream(FileReader *_file) - { - s.Read = Read; - s.Seek = Seek; - File = _file; - } - - static SRes Read(void *pp, void *buf, size_t *size) - { - CZDFileInStream *p = (CZDFileInStream *)pp; - long numread = p->File->Read(buf, (long)*size); - if (numread < 0) - { - *size = 0; - return SZ_ERROR_READ; - } - *size = numread; - return SZ_OK; - } - - static SRes Seek(void *pp, Int64 *pos, ESzSeek origin) - { - CZDFileInStream *p = (CZDFileInStream *)pp; - int move_method; - int res; - if (origin == SZ_SEEK_SET) - { - move_method = SEEK_SET; - } - else if (origin == SZ_SEEK_CUR) - { - move_method = SEEK_CUR; - } - else if (origin == SZ_SEEK_END) - { - move_method = SEEK_END; - } - else - { - return 1; - } - res = p->File->Seek((long)*pos, move_method); - *pos = p->File->Tell(); - return res; - } -}; - -struct C7zArchive -{ - CSzArEx DB; - CZDFileInStream ArchiveStream; - CLookToRead LookStream; - UInt32 BlockIndex; - Byte *OutBuffer; - size_t OutBufferSize; - - C7zArchive(FileReader *file) : ArchiveStream(file) - { - if (g_CrcTable[1] == 0) - { - CrcGenerateTable(); - } - file->Seek(0, SEEK_SET); - LookToRead_CreateVTable(&LookStream, false); - LookStream.realStream = &ArchiveStream.s; - LookToRead_Init(&LookStream); - SzArEx_Init(&DB); - BlockIndex = 0xFFFFFFFF; - OutBuffer = NULL; - OutBufferSize = 0; - } - - ~C7zArchive() - { - if (OutBuffer != NULL) - { - IAlloc_Free(&g_Alloc, OutBuffer); - } - SzArEx_Free(&DB, &g_Alloc); - } - - SRes Open() - { - return SzArEx_Open(&DB, &LookStream.s, &g_Alloc, &g_Alloc); - } - - SRes Extract(UInt32 file_index, char *buffer) - { - size_t offset, out_size_processed; - SRes res = SzAr_Extract(&DB, &LookStream.s, file_index, - &BlockIndex, &OutBuffer, &OutBufferSize, - &offset, &out_size_processed, - &g_Alloc, &g_Alloc); - if (res == SZ_OK) - { - memcpy(buffer, OutBuffer + offset, out_size_processed); - } - return res; - } -}; - -class FWadCollection::WadFileRecord : public FileReader -{ -public: - WadFileRecord (FILE *file); - WadFileRecord (const char *buffer, int length); - ~WadFileRecord (); - - long Seek (long offset, int origin); - long Read (void *buffer, long len); - - const char *MemoryData; - C7zArchive *Archive; - - FString Name; - DWORD FirstLump; - DWORD LastLump; -}; - -struct FEmbeddedWAD -{ - union - { - C7zArchive *Archive; - FZipCentralDirectoryInfo *Zip; - }; - int Position; + int wadnum; + FResourceLump *lump; }; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- -void W_SysWadInit (); - // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- @@ -317,21 +119,17 @@ void FWadCollection::DeleteAll () delete[] NextLumpIndex_FullName; NextLumpIndex_FullName = NULL; } - for (DWORD i = 0; i < LumpInfo.Size(); ++i) - { - if (LumpInfo[i].fullname != NULL) - { - delete[] LumpInfo[i].fullname; - } - } + LumpInfo.Clear(); NumLumps = 0; - for (DWORD i = 0; i < Wads.Size(); ++i) + // we must count backward to enssure that embedded WADs are deleted before + // the ones that contain their data. + for (int i = Files.Size() - 1; i >= 0; --i) { - delete Wads[i]; + delete Files[i]; } - Wads.Clear(); + Files.Clear(); } //========================================================================== @@ -367,29 +165,14 @@ void FWadCollection::InitMultipleFiles (wadlist_t **filenames) AddFile (name); M_Free (*filenames); *filenames = next; - - // The first two files are always zdoom.wad and the IWAD, which - // do not contain skins. - if (++numfiles > 2) - SkinHack (baselump); } + NumLumps = LumpInfo.Size(); if (NumLumps == 0) { I_FatalError ("W_InitMultipleFiles: no files found"); } - // [RH] Merge sprite and flat groups. - // (We don't need to bother with patches, since - // Doom doesn't use markers to identify them.) - RenameSprites (MergeLumps ("S_START", "S_END", ns_sprites)); - MergeLumps ("F_START", "F_END", ns_flats); - MergeLumps ("C_START", "C_END", ns_colormaps); - MergeLumps ("A_START", "A_END", ns_acslibrary); - MergeLumps ("TX_START", "TX_END", ns_newtextures); - MergeLumps ("V_START", "V_END", ns_strifevoices); - MergeLumps ("HI_START", "HI_END", ns_hires); - // [RH] Set up hash table FirstLumpIndex = new DWORD[NumLumps]; NextLumpIndex = new DWORD[NumLumps]; @@ -408,70 +191,12 @@ void FWadCollection::InitMultipleFiles (wadlist_t **filenames) int FWadCollection::AddExternalFile(const char *filename) { - LumpRecord lump; + FResourceLump *lump = new FExternalLump(filename); - lump.fullname = copystring(filename); - memset(lump.name, 0, sizeof(lump.name)); - lump.wadnum = -1; - lump.flags = LUMPF_EXTERNAL; - lump.position = 0; - lump.namespc = ns_global; - lump.compressedsize = 0; - return LumpInfo.Push(lump); -} - -#define BUFREADCOMMENT (0x400) - -//----------------------------------------------------------------------- -// -// Finds the central directory end record in the end of the file. -// Taken from Quake3 source but the file in question is not GPL'ed. ;) -// -//----------------------------------------------------------------------- - -DWORD Zip_FindCentralDir(FileReader * fin) -{ - unsigned char buf[BUFREADCOMMENT + 4]; - DWORD FileSize; - DWORD uBackRead; - DWORD uMaxBack; // maximum size of global comment - DWORD uPosFound=0; - - fin->Seek(0, SEEK_END); - - FileSize = fin->Tell(); - uMaxBack = MIN(0xffff, FileSize); - - uBackRead = 4; - while (uBackRead < uMaxBack) - { - DWORD uReadSize, uReadPos; - int i; - if (uBackRead + BUFREADCOMMENT > uMaxBack) - uBackRead = uMaxBack; - else - uBackRead += BUFREADCOMMENT; - uReadPos = FileSize - uBackRead; - - uReadSize = MIN((BUFREADCOMMENT + 4), (FileSize - uReadPos)); - - if (fin->Seek(uReadPos, SEEK_SET) != 0) break; - - if (fin->Read(buf, (SDWORD)uReadSize) != (SDWORD)uReadSize) break; - - for (i = (int)uReadSize - 3; (i--) > 0;) - { - if (buf[i] == 'P' && buf[i+1] == 'K' && buf[i+2] == 5 && buf[i+3] == 6) - { - uPosFound = uReadPos + i; - break; - } - } - - if (uPosFound != 0) - break; - } - return uPosFound; + FWadCollection::LumpRecord *lumprec = &LumpInfo[LumpInfo.Reserve(1)]; + lumprec->lump = lump; + lumprec->wadnum = -1; + return 0; // later } //========================================================================== @@ -483,546 +208,81 @@ DWORD Zip_FindCentralDir(FileReader * fin) // // [RH] Removed reload hack //========================================================================== -int STACK_ARGS FWadCollection::lumpcmp(const void * a, const void * b) +typedef FResourceFile * (*CheckFunc)(const char *filename, FileReader *file); + +FResourceFile *CheckWad(const char *filename, FileReader *file); +FResourceFile *CheckGRP(const char *filename, FileReader *file); +FResourceFile *CheckRFF(const char *filename, FileReader *file); +FResourceFile *CheckZip(const char *filename, FileReader *file); +FResourceFile *Check7Z(const char *filename, FileReader *file); +FResourceFile *CheckLump(const char *filename, FileReader *file); + +static CheckFunc funcs[] = { CheckWad, CheckZip, Check7Z, CheckGRP, CheckRFF, CheckLump }; + + +void FWadCollection::AddFile (const char *filename, FileReader *wadinfo) { - FWadCollection::LumpRecord * rec1 = (FWadCollection::LumpRecord *)a; - FWadCollection::LumpRecord * rec2 = (FWadCollection::LumpRecord *)b; - - return stricmp(rec1->fullname, rec2->fullname); -} - - -void FWadCollection::AddFile (const char *filename, const char *data, int length) -{ - WadFileRecord *wadinfo; - MergedHeader header; - LumpRecord* lump_p; - unsigned i; - FILE* handle; int startlump; - wadlump_t* fileinfo = NULL, *fileinfo2free = NULL; - wadlump_t singleinfo; - TArray EmbeddedWADs; - void *directory = NULL; - if (length == -1) + if (wadinfo == NULL) { - // open the file and add to directory - handle = fopen (filename, "rb"); - if (handle == NULL) + try + { + wadinfo = new FileReader(filename); + } + catch (CRecoverableError &err) { // Didn't find file - Printf (TEXTCOLOR_RED " couldn't open %s\n", filename); + Printf (TEXTCOLOR_RED "%s\n", err.GetMessage()); PrintLastError (); return; } + } - wadinfo = new WadFileRecord (handle); - } - else - { - // This is an in-memory WAD created from a WAD inside a .zip - wadinfo = new WadFileRecord(data, length); - } Printf (" adding %s", filename); startlump = NumLumps; - - // [RH] Determine if file is a WAD based on its signature, not its name. - if (wadinfo->Read (&header, sizeof(header)) == 0) + for(int i = 0; i < countof(funcs); i++) { - Printf (TEXTCOLOR_RED " couldn't read %s\n", filename); - PrintLastError (); - delete wadinfo; - return; - } - - wadinfo->Name = filename; - - if (header.magic[0] == IWAD_ID || header.magic[0] == PWAD_ID) - { // This is a WAD file - - header.wad.NumLumps = LittleLong(header.wad.NumLumps); - header.wad.InfoTableOfs = LittleLong(header.wad.InfoTableOfs); - fileinfo = fileinfo2free = new wadlump_t[header.wad.NumLumps]; - wadinfo->Seek (header.wad.InfoTableOfs, SEEK_SET); - wadinfo->Read (fileinfo, header.wad.NumLumps * sizeof(wadlump_t)); - NumLumps += header.wad.NumLumps; - Printf (" (%u lumps)", header.wad.NumLumps); - } - else if (header.magic[0] == RFF_ID) - { // This is a Blood RFF file - - rfflump_t *lumps, *rff_p; - - header.rff.NumLumps = LittleLong(header.rff.NumLumps); - header.rff.DirOfs = LittleLong(header.rff.DirOfs); - lumps = new rfflump_t[header.rff.NumLumps]; - wadinfo->Seek (header.rff.DirOfs, SEEK_SET); - wadinfo->Read (lumps, header.rff.NumLumps * sizeof(rfflump_t)); - BloodCrypt (lumps, header.rff.DirOfs, header.rff.NumLumps * sizeof(rfflump_t)); - - NumLumps += header.rff.NumLumps; - LumpInfo.Resize(NumLumps); - lump_p = &LumpInfo[startlump]; - - for (i = 0, rff_p = lumps; i < header.rff.NumLumps; ++i, ++rff_p) + FResourceFile * resfile = funcs[i](filename, wadinfo); + if (resfile != NULL) { - if (rff_p->Extension[0] == 'S' && rff_p->Extension[1] == 'F' && - rff_p->Extension[2] == 'X') + DWORD lumpstart = LumpInfo.Size(); + + resfile->SetFirstLump(lumpstart); + for (DWORD i=0; i < resfile->LumpCount(); i++) { - lump_p->namespc = ns_bloodsfx; - } - else if (rff_p->Extension[0] == 'R' && rff_p->Extension[1] == 'A' && - rff_p->Extension[2] == 'W') - { - lump_p->namespc = ns_bloodraw; - } - else - { - lump_p->namespc = ns_global; + FResourceLump *lump = resfile->GetLump(i); + FWadCollection::LumpRecord *lump_p = &LumpInfo[LumpInfo.Reserve(1)]; + + lump_p->lump = lump; + lump_p->wadnum = Files.Size(); } - uppercopy (lump_p->name, rff_p->Name); - lump_p->name[8] = 0; - lump_p->wadnum = (WORD)Wads.Size(); - lump_p->position = LittleLong(rff_p->FilePos); - lump_p->size = LittleLong(rff_p->Size); - lump_p->flags = (rff_p->Flags & 0x10) >> 4; - lump_p->compressedsize = -1; - - // Rearrange the name and extension in a part of the lump record - // that I don't have any use for in order to cnstruct the fullname. - rff_p->Name[8] = '\0'; - strcpy ((char *)rff_p->IDontKnow, rff_p->Name); - strcat ((char *)rff_p->IDontKnow, "."); - strcat ((char *)rff_p->IDontKnow, rff_p->Extension); - lump_p->fullname = copystring ((char *)rff_p->IDontKnow); - lump_p++; - } - Printf (" (%u files)", header.rff.NumLumps); - delete[] lumps; - } - else if (header.magic[0] == GRP_ID_0 && header.magic[1] == GRP_ID_1 && header.magic[2] == GRP_ID_2) - { - grplump_t *lumps, *grp_p; - int pos; - - header.grp.NumLumps = LittleLong(header.grp.NumLumps); - lumps = new grplump_t[header.grp.NumLumps]; - wadinfo->Read (lumps, header.grp.NumLumps * sizeof(grplump_t)); - pos = sizeof(grpinfo_t) + header.grp.NumLumps * sizeof(grplump_t); - - NumLumps += header.grp.NumLumps; - LumpInfo.Resize(NumLumps); - lump_p = &LumpInfo[startlump]; - - for (i = 0, grp_p = lumps; i < header.grp.NumLumps; ++i, ++grp_p) - { - lump_p->wadnum = (WORD)Wads.Size(); - lump_p->position = pos; - lump_p->size = LittleLong(grp_p->Size); - pos += lump_p->size; - grp_p->NameWithZero[12] = '\0'; // Be sure filename is null-terminated - lump_p->fullname = copystring(grp_p->Name); - uppercopy (lump_p->name, grp_p->Name); - lump_p->name[8] = 0; - lump_p->compressedsize = -1; - lump_p->flags = 0; - lump_p->namespc = ns_global; - lump_p++; - } - Printf (" (%u files)", header.grp.NumLumps); - delete[] lumps; - } - else if (header.magic[0] == ZIP_ID) - { - DWORD centraldir = Zip_FindCentralDir(wadinfo); - FZipEndOfCentralDirectory info; - int skipped = 0; - - if (centraldir == 0) - { - Printf("\n%s: ZIP file corrupt!\n", filename); - delete wadinfo; - return; - } - - // Read the central directory info. - wadinfo->Seek(centraldir, SEEK_SET); - wadinfo->Read(&info, sizeof(FZipEndOfCentralDirectory)); - - // No multi-disk zips! - if (info.NumEntries != info.NumEntriesOnAllDisks || - info.FirstDisk != 0 || info.DiskNumber != 0) - { - Printf("\n%s: Multipart Zip files are not supported.\n", filename); - delete wadinfo; - return; - } - - NumLumps += LittleShort(info.NumEntries); - LumpInfo.Resize(NumLumps); - lump_p = &LumpInfo[startlump]; - - // Load the entire central directory. Too bad that this contains variable length entries... - directory = malloc(LittleLong(info.DirectorySize)); - wadinfo->Seek(LittleLong(info.DirectoryOffset), SEEK_SET); - wadinfo->Read(directory, LittleLong(info.DirectorySize)); - - char *dirptr = (char*)directory; - for (int i = 0; i < LittleShort(info.NumEntries); i++) - { - FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr; - - char name[256]; - - int len = LittleShort(zip_fh->NameLength); - strncpy(name, dirptr + sizeof(FZipCentralDirectoryInfo), MIN(len, 255)); - name[len] = 0; - dirptr += sizeof(FZipCentralDirectoryInfo) + - LittleShort(zip_fh->NameLength) + - LittleShort(zip_fh->ExtraLength) + - LittleShort(zip_fh->CommentLength); - - // skip Directories - if(name[len - 1] == '/' && LittleLong(zip_fh->UncompressedSize) == 0) + if (Files.Size() == IWAD_FILENUM && gameinfo.gametype == GAME_Strife && gameinfo.flags & GI_SHAREWARE) { - skipped++; - continue; + resfile->FindStrifeTeaserVoices(); } + Files.Push(resfile); - // Ignore unknown compression formats - zip_fh->Method = LittleShort(zip_fh->Method); - if (zip_fh->Method != METHOD_STORED && - zip_fh->Method != METHOD_DEFLATE && - zip_fh->Method != METHOD_LZMA && - zip_fh->Method != METHOD_BZIP2) - { - Printf("\n: %s: '%s' uses an unsupported compression algorithm (#%d).\n", filename, name, zip_fh->Method); - skipped++; - continue; - } - // Also ignore encrypted entries - if(LittleShort(zip_fh->Flags) & ZF_ENCRYPTED) - { - Printf("\n%s: '%s' is encrypted. Encryption is not supported.\n", filename, name); - skipped++; - continue; - } - FixPathSeperator(name); - strlwr(name); + for (DWORD i=0; i < resfile->LumpCount(); i++) + { + FResourceLump *lump = resfile->GetLump(i); + if (lump->Flags & LUMPF_EMBEDDED) + { + char path[256]; - // Check for embedded WADs in the root directory. - // They must be extracted and added separately to the lump list. - // WADs in subdirectories are added to the lump directory. - // Embedded .zips are ignored for now. But they should be allowed later! - char *c = strstr(name, ".wad"); - if (c && strlen(c) == 4 && !strchr(name, '/')) - { - FEmbeddedWAD embed; - embed.Zip = zip_fh; - embed.Position = -1; - EmbeddedWADs.Push(embed); - skipped++; - continue; - } + mysnprintf(path, countof(path), "%s:", filename); + char *wadstr = path + strlen(path); - lump_p->ZipNameSetup(name); - lump_p->size = LittleLong(zip_fh->UncompressedSize); - lump_p->wadnum = (WORD)Wads.Size(); - lump_p->flags = (zip_fh->Method != METHOD_STORED) ? LUMPF_COMPRESSED|LUMPF_ZIPFILE : LUMPF_ZIPFILE; - lump_p->method = zip_fh->Method; - lump_p->compressedsize = LittleLong(zip_fh->CompressedSize); + FileReader *embedded = lump->NewReader(); + strcpy(wadstr, lump->FullName); - // The start of the file will be determined the first time it is accessed. - lump_p->flags |= LUMPF_NEEDFILESTART; - lump_p->position = LittleLong(zip_fh->LocalHeaderOffset); - lump_p++; - } - // Resize the lump record array to its actual size - NumLumps -= skipped; - LumpInfo.Resize(NumLumps); - Printf (" (%d files)", LittleShort(info.NumEntries) - skipped); - - // Entries in Zips are sorted alphabetically. - qsort(&LumpInfo[startlump], NumLumps - startlump, sizeof(LumpRecord), lumpcmp); - } - else if (memcmp(header.sevenzip, k7zSignature, k7zSignatureSize) == 0) - { - C7zArchive *arc = new C7zArchive(wadinfo); - int skipped = 0; - SRes res; - - res = arc->Open(); - if (res != SZ_OK) - { - delete arc; - delete wadinfo; - Printf("\n%s: ", filename); - if (res == SZ_ERROR_UNSUPPORTED) - { - Printf("Decoder does not support this archive\n"); - } - else if (res == SZ_ERROR_MEM) - { - Printf("Cannot allocate memory\n"); - } - else if (res == SZ_ERROR_CRC) - { - Printf("CRC error\n"); - } - else - { - Printf("error #%d\n", res); + AddFile(wadstr, embedded); + } } return; } - wadinfo->Archive = arc; - NumLumps += arc->DB.db.NumFiles; - LumpInfo.Resize(NumLumps); - lump_p = &LumpInfo[startlump]; - - for (int i = 0; i < arc->DB.db.NumFiles; ++i) - { - CSzFileItem *file = &arc->DB.db.Files[i]; - char name[256]; - - // skip Directories - if (file->IsDir) - { - skipped++; - continue; - } - - strncpy(name, file->Name, countof(name)-1); - name[countof(name)-1] = 0; - FixPathSeperator(name); - strlwr(name); - - // Check for embedded WADs in the root directory. - char *c = strstr(name, ".wad"); - if (c && strlen(c) == 4 && !strchr(name, '/')) - { - FEmbeddedWAD embed; - embed.Archive = arc; - embed.Position = i; - EmbeddedWADs.Push(embed); - skipped++; - continue; - } - - lump_p->ZipNameSetup(name); - lump_p->size = file->Size; - lump_p->wadnum = (WORD)Wads.Size(); - lump_p->flags = LUMPF_7ZFILE | LUMPF_ZIPFILE; - lump_p->position = i; - lump_p->compressedsize = -1; - lump_p++; - } - // Resize the lump record array to its actual size - NumLumps -= skipped; - LumpInfo.Resize(NumLumps); - Printf (" (%u files)", arc->DB.db.NumFiles - skipped); - - // Entries in archives are sorted alphabetically - qsort(&LumpInfo[startlump], NumLumps - startlump, sizeof(LumpRecord), lumpcmp); - } - else - { // This is just a single lump file - fileinfo2free = NULL; - fileinfo = &singleinfo; - singleinfo.FilePos = 0; - singleinfo.Size = LittleLong(wadinfo->GetLength()); - FString name(ExtractFileBase (filename)); - uppercopy(singleinfo.Name, name); - NumLumps++; - } - Printf ("\n"); - - // Fill in lumpinfo - if (header.magic[0] != RFF_ID && - header.magic[0] != ZIP_ID && - (header.magic[0] != GRP_ID_0 || header.magic[1] != GRP_ID_1 || header.magic[2] != GRP_ID_2) && - memcmp(header.sevenzip, k7zSignature, k7zSignatureSize)) - { - LumpInfo.Resize(NumLumps); - lump_p = &LumpInfo[startlump]; - for (i = startlump; i < (unsigned)NumLumps; i++, lump_p++, fileinfo++) - { - // [RH] Convert name to uppercase during copy - uppercopy (lump_p->name, fileinfo->Name); - lump_p->name[8] = 0; - lump_p->wadnum = (WORD)Wads.Size(); - lump_p->position = LittleLong(fileinfo->FilePos); - lump_p->size = LittleLong(fileinfo->Size); - lump_p->namespc = ns_global; - lump_p->flags = 0; - lump_p->fullname = NULL; - lump_p->compressedsize=-1; - } - - if (fileinfo2free) - { - delete[] fileinfo2free; - } - - ScanForFlatHack (startlump); - } - - wadinfo->FirstLump = startlump; - wadinfo->LastLump = NumLumps - 1; - Wads.Push(wadinfo); - - // [RH] Put the Strife Teaser voices into the voices namespace - if (Wads.Size() == IWAD_FILENUM+1 && gameinfo.gametype == GAME_Strife && gameinfo.flags & GI_SHAREWARE) - { - FindStrifeTeaserVoices (); - } - - if (EmbeddedWADs.Size()) - { - char path[256]; - size_t len; - char *buffer; - - mysnprintf(path, countof(path), "%s:", filename); - char *wadstr = path + strlen(path); - - for(unsigned int i = 0; i < EmbeddedWADs.Size(); i++) - { - FEmbeddedWAD *embed = &EmbeddedWADs[i]; - - if (embed->Position == -1) - { - FZipCentralDirectoryInfo *zip_fh = embed->Zip; - FZipLocalFileHeader localHeader; - - *wadstr = 0; - len = LittleShort(zip_fh->NameLength); - if (len + strlen(path) > 255) - { - len = 255 - strlen(path); - } - strncpy(wadstr, ((char*)zip_fh) + sizeof(FZipCentralDirectoryInfo), len); - wadstr[len] = 0; - - DWORD size = LittleLong(zip_fh->UncompressedSize); - buffer = new char[size]; - - int position = LittleLong(zip_fh->LocalHeaderOffset); - - wadinfo->Seek(position, SEEK_SET); - wadinfo->Read(&localHeader, sizeof(localHeader)); - position += sizeof(FZipLocalFileHeader) + LittleShort(localHeader.ExtraLength) + LittleShort(zip_fh->NameLength); - - wadinfo->Seek(position, SEEK_SET); - if (LittleShort(zip_fh->Method) == METHOD_DEFLATE) - { - FileReaderZ frz(*wadinfo, true); - frz.Read(buffer, size); - } - else if (LittleShort(zip_fh->Method) == METHOD_LZMA) - { - FileReaderLZMA frz(*wadinfo, size, true); - frz.Read(buffer, size); - } - else if (LittleShort(zip_fh->Method) == METHOD_BZIP2) - { - FileReaderBZ2 frz(*wadinfo); - frz.Read(buffer, size); - } - else - { - wadinfo->Read(buffer, size); - } - AddFile(path, buffer, size); - } - else - { - CSzFileItem *file = &embed->Archive->DB.db.Files[embed->Position]; - len = strlen(file->Name); - if (len + strlen(path) > 255) - { - len = 255 - strlen(path); - } - strncpy(wadstr, file->Name, len); - wadstr[len] = 0; - - buffer = new char[file->Size]; - if (embed->Archive->Extract(embed->Position, buffer) == SZ_OK) - { - AddFile(path, buffer, file->Size); - } - } - } - } - if (directory != NULL) - { - free(directory); - } -} - -//========================================================================== -// -// FWadCollection :: LumpRecord :: ZipNameSetup -// -// For lumps from an archive, determine this lump's wad-compatible name, -// namespace, and set the fullname. -// -//========================================================================== - -void FWadCollection::LumpRecord::ZipNameSetup(char *iname) -{ - char base[256]; - char *lname = strrchr(iname,'/'); - lname = (lname == NULL) ? iname : lname + 1; - strcpy(base, lname); - char *dot = strrchr(base, '.'); - if (dot != NULL) - { - *dot = 0; - } - uppercopy(name, base); - name[8] = 0; - fullname = copystring(iname); - - // Map some directories to WAD namespaces. - // Note that some of these namespaces don't exist in WADS. - // CheckNumForName will handle any request for these namespaces accordingly. - namespc = !strncmp(iname, "flats/", 6) ? ns_flats : - !strncmp(iname, "textures/", 9) ? ns_newtextures : - !strncmp(iname, "hires/", 6) ? ns_hires : - !strncmp(iname, "sprites/", 8) ? ns_sprites : - !strncmp(iname, "colormaps/", 10) ? ns_colormaps : - !strncmp(iname, "acs/", 4) ? ns_acslibrary : - !strncmp(iname, "voices/", 7) ? ns_strifevoices : - !strncmp(iname, "patches/", 8) ? ns_patches : - !strncmp(iname, "graphics/", 9) ? ns_graphics : - !strncmp(iname, "sounds/", 7) ? ns_sounds : - !strncmp(iname, "music/", 6) ? ns_music : - !strchr(iname, '/') ? ns_global : - -1; - - // Anything that is not in one of these subdirectories or the main directory - // should not be accessible through the standard WAD functions but only through - // the ones which look for the full name. - if (namespc == -1) - { - memset(name, 0, 8); - } - - // Since '\' can't be used as a file name's part inside a ZIP - // we have to work around this for sprites because it is a valid - // frame character. - else if (namespc == ns_sprites) - { - char *c; - - while ((c = (char*)memchr(name, '^', 8))) - { - *c = '\\'; - } } } @@ -1043,7 +303,7 @@ int FWadCollection::CheckIfWadLoaded (const char *name) if (strrchr (name, '/') != NULL) { - for (i = 0; i < Wads.Size(); ++i) + for (i = 0; i < Files.Size(); ++i) { if (stricmp (GetWadFullName (i), name) == 0) { @@ -1053,7 +313,7 @@ int FWadCollection::CheckIfWadLoaded (const char *name) } else { - for (i = 0; i < Wads.Size(); ++i) + for (i = 0; i < Files.Size(); ++i) { if (stricmp (GetWadName (i), name) == 0) { @@ -1083,7 +343,7 @@ int FWadCollection::GetNumLumps () const int FWadCollection::GetNumWads () const { - return Wads.Size(); + return Files.Size(); } //========================================================================== @@ -1100,7 +360,7 @@ int FWadCollection::GetNumWads () const int FWadCollection::CheckNumForName (const char *name, int space) { char uname[8]; - WORD i; + DWORD i; if (name == NULL) { @@ -1119,17 +379,18 @@ int FWadCollection::CheckNumForName (const char *name, int space) while (i != NULL_INDEX) { - if (*(QWORD *)&LumpInfo[i].name == *(QWORD *)&uname) + FResourceLump *lump = LumpInfo[i].lump; + + if (*(QWORD *)&lump->Name == *(QWORD *)&uname) { - if (LumpInfo[i].namespc == space) break; + if (lump->Namespace == space) break; // If the lump is from one of the special namespaces exclusive to Zips // the check has to be done differently: // If we find a lump with this name in the global namespace that does not come // from a Zip return that. WADs don't know these namespaces and single lumps must // work as well. - if (space > ns_specialzipdirectory && - LumpInfo[i].namespc == ns_global && - !(LumpInfo[i].flags & LUMPF_ZIPFILE)) break; + if (space > ns_specialzipdirectory && lump->Namespace == ns_global && + !(lump->Flags & LUMPF_ZIPFILE)) break; } i = NextLumpIndex[i]; } @@ -1140,7 +401,7 @@ int FWadCollection::CheckNumForName (const char *name, int space) int FWadCollection::CheckNumForName (const char *name, int space, int wadnum, bool exact) { char uname[8]; - WORD i; + DWORD i; if (wadnum < 0) { @@ -1149,15 +410,18 @@ int FWadCollection::CheckNumForName (const char *name, int space, int wadnum, bo uppercopy (uname, name); i = FirstLumpIndex[LumpNameHash (uname) % NumLumps]; + FResourceLump *lump = LumpInfo[i].lump; // If exact is true if will only find lumps in the same WAD, otherwise // also those in earlier WADs. + while (i != NULL_INDEX && - (*(QWORD *)&LumpInfo[i].name != *(QWORD *)&uname || - LumpInfo[i].namespc != space || + (*(QWORD *)&lump->Name != *(QWORD *)&uname || + lump->Namespace != space || (exact? (LumpInfo[i].wadnum != wadnum) : (LumpInfo[i].wadnum > wadnum)) )) { i = NextLumpIndex[i]; + lump = LumpInfo[i].lump; } return i != NULL_INDEX ? i : -1; @@ -1196,7 +460,7 @@ int FWadCollection::GetNumForName (const char *name, int space) int FWadCollection::CheckNumForFullName (const char *name, bool trynormal, int namespc) { - WORD i; + DWORD i; if (name == NULL) { @@ -1205,7 +469,7 @@ int FWadCollection::CheckNumForFullName (const char *name, bool trynormal, int n i = FirstLumpIndex_FullName[MakeKey (name) % NumLumps]; - while (i != NULL_INDEX && stricmp(name, LumpInfo[i].fullname)) + while (i != NULL_INDEX && stricmp(name, LumpInfo[i].lump->FullName)) { i = NextLumpIndex_FullName[i]; } @@ -1221,7 +485,7 @@ int FWadCollection::CheckNumForFullName (const char *name, bool trynormal, int n int FWadCollection::CheckNumForFullName (const char *name, int wadnum) { - WORD i; + DWORD i; if (wadnum < 0) { @@ -1231,7 +495,7 @@ int FWadCollection::CheckNumForFullName (const char *name, int wadnum) i = FirstLumpIndex_FullName[MakeKey (name) % NumLumps]; while (i != NULL_INDEX && - (stricmp(name, LumpInfo[i].fullname) || LumpInfo[i].wadnum != wadnum)) + (stricmp(name, LumpInfo[i].lump->FullName) || LumpInfo[i].wadnum != wadnum)) { i = NextLumpIndex_FullName[i]; } @@ -1274,7 +538,7 @@ int FWadCollection::LumpLength (int lump) const I_Error ("W_LumpLength: %i >= NumLumps",lump); } - return LumpInfo[lump].size; + return LumpInfo[lump].lump->LumpSize; } //========================================================================== @@ -1282,6 +546,7 @@ int FWadCollection::LumpLength (int lump) const // GetLumpOffset // // Returns the offset from the beginning of the file to the lump. +// Returns -1 if the lump is compressed or can't be read directly // //========================================================================== @@ -1292,12 +557,7 @@ int FWadCollection::GetLumpOffset (int lump) I_Error ("GetLumpOffset: %i >= NumLumps",lump); } - if (LumpInfo[lump].flags & LUMPF_NEEDFILESTART) - { - SetLumpAddress(&LumpInfo[lump]); - } - - return LumpInfo[lump].position; + return LumpInfo[lump].lump->GetFileOffset(); } //========================================================================== @@ -1313,7 +573,7 @@ int FWadCollection::GetLumpFlags (int lump) return 0; } - return LumpInfo[lump].flags; + return LumpInfo[lump].lump->Flags; } //========================================================================== @@ -1364,193 +624,21 @@ void FWadCollection::InitHashChains (void) // Now set up the chains for (i = 0; i < (unsigned)NumLumps; i++) { - uppercopy (name, LumpInfo[i].name); + uppercopy (name, LumpInfo[i].lump->Name); j = LumpNameHash (name) % NumLumps; NextLumpIndex[i] = FirstLumpIndex[j]; FirstLumpIndex[j] = i; // Do the same for the full paths - if (LumpInfo[i].fullname!=NULL) + if (LumpInfo[i].lump->FullName!=NULL) { - j = MakeKey(LumpInfo[i].fullname) % NumLumps; + j = MakeKey(LumpInfo[i].lump->FullName) % NumLumps; NextLumpIndex_FullName[i] = FirstLumpIndex_FullName[j]; FirstLumpIndex_FullName[j] = i; } } } -//========================================================================== -// -// IsMarker -// -// (from BOOM) -// -//========================================================================== - -bool FWadCollection::IsMarker (const FWadCollection::LumpRecord *lump, const char *marker) const -{ - if (lump->namespc != ns_global || (lump->flags & LUMPF_ZIPFILE)) - { - return false; - } - if (strncmp (lump->name, marker, 8) == 0) - { - // If the previous lump was of the form FF_END and this one is - // of the form F_END, ignore this as a marker - if (marker[2] == 'E' && lump > &LumpInfo[0]) - { - if ((lump - 1)->name[0] == *marker && - strncmp ((lump - 1)->name + 1, marker, 7) == 0) - { - return false; - } - } - return true; - } - // Treat double-character markers the same as single-character markers. - // (So if FF_START appears in the wad, it will be treated as if it is F_START. - // However, TTX_STAR will not be treated the same as TX_START because it - // is not a single-character marker.) - if (marker[1] == '_' && - lump->name[0] == *marker && - strncmp (lump->name + 1, marker, 7) == 0) - { - return true; - } - return false; -} - -//========================================================================== -// -// ScanForFlatHack -// -// Try to detect wads that add extra flats by sticking an extra F_END -// at the end of the flat list without any corresponding FF_START. -// In other words, fix gothic2.wad. -// -//========================================================================== - -void FWadCollection::ScanForFlatHack (int startlump) -{ - if (Args->CheckParm ("-noflathack")) - { - return; - } - - for (int i = startlump; (DWORD)i < NumLumps; ++i) - { - if (LumpInfo[i].name[0] == 'F') - { - int j; - - if (strcmp (LumpInfo[i].name + 1, "_START") == 0 || - strncmp (LumpInfo[i].name + 1, "F_START", 7) == 0) - { - // If the wad has a F_START/FF_START marker, check for - // a FF_START-flats-FF_END-flats-F_END pattern as seen - // in darkhour.wad. At what point do I stop making hacks - // for wads that are incorrect? - for (i = i + 1; (DWORD)i < NumLumps; ++i) - { - if (LumpInfo[i].name[0] == 'F' && strcmp (LumpInfo[i].name + 1, "F_END") == 0) - { - // Found FF_END - break; - } - if (LumpInfo[i].size != 4096) - { - return; - } - } - if (i < (int)NumLumps) - { - // Look for flats-F_END - for (j = ++i; (DWORD)j < NumLumps; ++j) - { - if (LumpInfo[j].name[0] == 'F' && strcmp (LumpInfo[j].name + 1, "_END") == 0) - { - // Found F_END, so bump all the flats between FF_END/F_END up and move the - // FF_END so it immediately precedes F_END. - if (i != j - 1) - { - for (; i < j; ++i) - { - LumpInfo[i - 1] = LumpInfo[i]; - } - --i; - strcpy (LumpInfo[i].name, "FF_END"); - LumpInfo[i].size = 0; - LumpInfo[i].namespc = ns_global; - LumpInfo[i].flags = 0; - } - return; - } - if (LumpInfo[j].size != 4096) - { - return; - } - } - } - return; - } - - // No need to look for FF_END, because Doom doesn't. One minor - // nitpick: Doom will look for the last F_END; this finds the first - // one if there is more than one in the file. Too bad. If there's - // more than one F_END, this algorithm won't be able to properly - // determine where to put the F_START anyway. - if (strcmp (LumpInfo[i].name + 1, "_END") == 0) - { - // When F_END is found, back up past any lumps of length - // 4096, then insert an F_START marker. - for (j = i - 1; j >= startlump && LumpInfo[j].size == 4096; --j) - { - } - if (j == i - 1) - { - // Oh no! There are no flats immediately before F_END. Maybe they are - // at the beginning of the wad (e.g. slipgate.wad). - for (j = startlump; LumpInfo[j].size == 4096; ++j) - { - } - if (j > startlump) - { - // Okay, there are probably flats at the beginning of the wad. - // Move the F_END marker so it immediately follows them, and - // then add an F_START marker at the start of the wad. - for (; i > j; --i) - { - LumpInfo[i] = LumpInfo[i-1]; - } - strcpy (LumpInfo[j].name, "F_END"); - LumpInfo[j].size = 0; - LumpInfo[j].namespc = ns_global; - LumpInfo[j].flags = 0; - j = startlump - 1; - } - else - { - // Oh well. There won't be any flats loaded from this wad, I guess. - j = i - 1; - } - } - ++NumLumps; - LumpInfo.Resize(NumLumps); - for (; i > j; --i) - { - LumpInfo[i+1] = LumpInfo[i]; - } - ++i; - strcpy (LumpInfo[i].name, "F_START"); - LumpInfo[i].size = 0; - LumpInfo[i].namespc = ns_global; - LumpInfo[i].flags = 0; - return; - } - } - } -} - //========================================================================== // // RenameSprites @@ -1638,11 +726,11 @@ void FWadCollection::RenameSprites (int startlump) for (DWORD i = startlump + 1; i < NumLumps && - *(DWORD *)LumpInfo[i].name != MAKE_ID('S','_','E','N') && - *(((DWORD *)LumpInfo[i].name) + 1) != MAKE_ID('D',0,0,0); + *(DWORD *)LumpInfo[i].lump->Name != MAKE_ID('S','_','E','N') && + *(((DWORD *)LumpInfo[i].lump->Name) + 1) != MAKE_ID('D',0,0,0); ++i) { - if (!strncmp(LumpInfo[i].name, "MNTRZ", 5)) + if (!strncmp(LumpInfo[i].lump->Name, "MNTRZ", 5)) { MNTRZfound = true; break; @@ -1651,8 +739,8 @@ void FWadCollection::RenameSprites (int startlump) for (DWORD i = startlump + 1; i < NumLumps && - *(DWORD *)LumpInfo[i].name != MAKE_ID('S','_','E','N') && - *(((DWORD *)LumpInfo[i].name) + 1) != MAKE_ID('D',0,0,0); + *(DWORD *)LumpInfo[i].lump->Name != MAKE_ID('S','_','E','N') && + *(((DWORD *)LumpInfo[i].lump->Name) + 1) != MAKE_ID('D',0,0,0); ++i) { // Only sprites in the IWAD normally get renamed @@ -1660,27 +748,27 @@ void FWadCollection::RenameSprites (int startlump) { for (int j = 0; j < numrenames; ++j) { - if (*(DWORD *)LumpInfo[i].name == renames[j*2]) + if (*(DWORD *)LumpInfo[i].lump->Name == renames[j*2]) { - *(DWORD *)LumpInfo[i].name = renames[j*2+1]; + *(DWORD *)LumpInfo[i].lump->Name = renames[j*2+1]; } } if (gameinfo.gametype == GAME_Hexen) { if (CheckLumpName (i, "ARTIINVU")) { - LumpInfo[i].name[4]='D'; LumpInfo[i].name[5]='E'; - LumpInfo[i].name[6]='F'; LumpInfo[i].name[7]='N'; + LumpInfo[i].lump->Name[4]='D'; LumpInfo[i].lump->Name[5]='E'; + LumpInfo[i].lump->Name[6]='F'; LumpInfo[i].lump->Name[7]='N'; } } } if (!MNTRZfound) //gameinfo.gametype == GAME_Hexen && LumpInfo[i].wadnum == IWAD_FILENUM) { - if (*(DWORD *)LumpInfo[i].name == MAKE_ID('M', 'N', 'T', 'R')) + if (*(DWORD *)LumpInfo[i].lump->Name == MAKE_ID('M', 'N', 'T', 'R')) { - if (LumpInfo[i].name[4] >= 'F' && LumpInfo[i].name[4] <= 'K') + if (LumpInfo[i].lump->Name[4] >= 'F' && LumpInfo[i].lump->Name[4] <= 'K') { - LumpInfo[i].name[4] += 'U' - 'F'; + LumpInfo[i].lump->Name[4] += 'U' - 'F'; } } } @@ -1689,164 +777,9 @@ void FWadCollection::RenameSprites (int startlump) // the same blood states can be used everywhere if (!(gameinfo.gametype & GAME_DoomChex)) { - if (*(DWORD *)LumpInfo[i].name == MAKE_ID('B', 'L', 'O', 'D')) + if (*(DWORD *)LumpInfo[i].lump->Name == MAKE_ID('B', 'L', 'O', 'D')) { - *(DWORD *)LumpInfo[i].name = MAKE_ID('B', 'L', 'U', 'D'); - } - } - } -} - -//========================================================================== -// -// MergeLumps -// -// Merge multiple tagged groups into one -// Basically from BOOM, too, although I tried to write it independently. -// -//========================================================================== - -int FWadCollection::MergeLumps (const char *start, const char *end, int space) -{ - char ustart[8], uend[8]; - LumpRecord *newlumpinfos; - int newlumps, oldlumps; - int markerpos = -1; - unsigned int i; - bool insideBlock; - - uppercopy (ustart, start); - uppercopy (uend, end); - - newlumpinfos = new LumpRecord[NumLumps]; - - newlumps = 0; - oldlumps = 0; - insideBlock = false; - - for (i = 0; i < NumLumps; i++) - { - if (!insideBlock) - { - // The lump already has the desired namespace - // (This happens for lumps coming from .zips) - if (LumpInfo[i].namespc == space) - { - // Create start marker if we haven't already - if (!newlumps) - { - newlumps++; - strncpy (newlumpinfos[0].name, ustart, 8); - newlumpinfos[0].fullname = NULL; - newlumpinfos[0].wadnum = -1; - newlumpinfos[0].position = - newlumpinfos[0].size = 0; - newlumpinfos[0].namespc = ns_global; - newlumpinfos[0].flags = 0; - } - - newlumpinfos[newlumps++] = LumpInfo[i]; - } - else - // Check if this is the start of a block - if (IsMarker (&LumpInfo[i], ustart)) - { - insideBlock = true; - markerpos = i; - - // Create start marker if we haven't already - if (!newlumps) - { - newlumps++; - strncpy (newlumpinfos[0].name, ustart, 8); - newlumpinfos[0].fullname = NULL; - newlumpinfos[0].wadnum = -1; - newlumpinfos[0].position = - newlumpinfos[0].size = 0; - newlumpinfos[0].namespc = ns_global; - newlumpinfos[0].flags = 0; - } - } - else - { - // Copy lumpinfo down this list - LumpInfo[oldlumps++] = LumpInfo[i]; - } - } - else - { - if (i && LumpInfo[i].wadnum != LumpInfo[i-1].wadnum) - { - // Blocks cannot span multiple files - insideBlock = false; - LumpInfo[oldlumps++] = LumpInfo[i]; - } - else if (IsMarker (&LumpInfo[i], uend)) - { - // It is the end of a block. We'll add the end marker once - // we've processed everything. - insideBlock = false; - } - else - { - newlumpinfos[newlumps] = LumpInfo[i]; - newlumpinfos[newlumps++].namespc = space; - } - } - } - - // Now copy the merged lumps to the end of the old list - // and create the end marker entry. - - if (newlumps) - { - LumpInfo.Resize(oldlumps+newlumps+1); - - memcpy (&LumpInfo[oldlumps], newlumpinfos, sizeof(LumpRecord) * newlumps); - markerpos = oldlumps; - NumLumps = oldlumps + newlumps; - - strncpy (LumpInfo[NumLumps].name, uend, 8); - LumpInfo[NumLumps].fullname=NULL; - LumpInfo[NumLumps].wadnum = -1; - LumpInfo[NumLumps].position = - LumpInfo[NumLumps].size = 0; - LumpInfo[NumLumps].namespc = ns_global; - LumpInfo[NumLumps].flags = 0; - NumLumps++; - } - - delete[] newlumpinfos; - return markerpos; -} - -//========================================================================== -// -// FindStrifeTeaserVoices -// -// Strife0.wad does not have the voices between V_START/V_END markers, so -// figure out which lumps are voices based on their names. -// -//========================================================================== - -void FWadCollection::FindStrifeTeaserVoices () -{ - for (DWORD i = Wads[IWAD_FILENUM]->FirstLump; i <= Wads[IWAD_FILENUM]->LastLump; ++i) - { - if (LumpInfo[i].name[0] == 'V' && - LumpInfo[i].name[1] == 'O' && - LumpInfo[i].name[2] == 'C') - { - int j; - - for (j = 3; j < 8; ++j) - { - if (LumpInfo[i].name[j] != 0 && !isdigit(LumpInfo[i].name[j])) - break; - } - if (j == 8) - { - LumpInfo[i].namespc = ns_strifevoices; + *(DWORD *)LumpInfo[i].lump->Name = MAKE_ID('B', 'L', 'U', 'D'); } } } @@ -1871,8 +804,10 @@ int FWadCollection::FindLump (const char *name, int *lastlump, bool anyns) lump_p = &LumpInfo[*lastlump]; while (lump_p < &LumpInfo[NumLumps]) { - if ((anyns || lump_p->namespc == ns_global) && - *(QWORD *)&lump_p->name == *(QWORD *)&name8) + FResourceLump *lump = lump_p->lump; + + if ((anyns || lump->Namespace == ns_global) && + *(QWORD *)&lump->Name == *(QWORD *)&name8) { int lump = lump_p - &LumpInfo[0]; *lastlump = lump + 1; @@ -1896,7 +831,7 @@ bool FWadCollection::CheckLumpName (int lump, const char *name) if ((size_t)lump >= NumLumps) return false; - return !strnicmp (LumpInfo[lump].name, name, 8); + return !strnicmp (LumpInfo[lump].lump->Name, name, 8); } //========================================================================== @@ -1910,7 +845,7 @@ void FWadCollection::GetLumpName (char *to, int lump) const if ((size_t)lump >= NumLumps) *to = 0; else - uppercopy (to, LumpInfo[lump].name); + uppercopy (to, LumpInfo[lump].lump->Name); } //========================================================================== @@ -1925,10 +860,10 @@ const char *FWadCollection::GetLumpFullName (int lump) const { if ((size_t)lump >= NumLumps) return NULL; - else if (LumpInfo[lump].fullname != NULL) - return LumpInfo[lump].fullname; + else if (LumpInfo[lump].lump->FullName != NULL) + return LumpInfo[lump].lump->FullName; else - return LumpInfo[lump].name; + return LumpInfo[lump].lump->Name; } //========================================================================== @@ -1961,7 +896,7 @@ int FWadCollection::GetLumpNamespace (int lump) const if ((size_t)lump >= NumLumps) return ns_global; else - return LumpInfo[lump].namespc; + return LumpInfo[lump].lump->Namespace; } //========================================================================== @@ -2011,31 +946,6 @@ FMemLump FWadCollection::ReadLump (int lump) return FMemLump(FString(ELumpNum(lump))); } -//========================================================================== -// -// SetLumpAddress -// -//========================================================================== - -void FWadCollection::SetLumpAddress(LumpRecord *l) -{ - // This file is inside a zip and has not been opened before. - // Position points to the start of the local file header, which we must - // read and skip so that we can get to the actual file data. - FZipLocalFileHeader localHeader; - int skiplen; - int address; - - WadFileRecord *wad = Wads[l->wadnum]; - - address = wad->Tell(); - wad->Seek(l->position, SEEK_SET); - wad->Read(&localHeader, sizeof(localHeader)); - skiplen = LittleShort(localHeader.NameLength) + LittleShort(localHeader.ExtraLength); - l->position += sizeof(localHeader) + skiplen; - l->flags &= ~LUMPF_NEEDFILESTART; -} - //========================================================================== // // OpenLumpNum @@ -2047,75 +957,12 @@ void FWadCollection::SetLumpAddress(LumpRecord *l) FWadLump FWadCollection::OpenLumpNum (int lump) { - LumpRecord *l; - WadFileRecord *wad; - if ((unsigned)lump >= (unsigned)LumpInfo.Size()) { I_Error ("W_OpenLumpNum: %u >= NumLumps", lump); } - l = &LumpInfo[lump]; - wad = l->wadnum >= 0 ? Wads[l->wadnum] : NULL; - - if (l->flags & LUMPF_NEEDFILESTART) - { - SetLumpAddress(l); - } - - if (wad != NULL) - { - wad->Seek (l->position, SEEK_SET); - } - - if (l->flags & (LUMPF_COMPRESSED | LUMPF_7ZFILE)) - { - // A compressed entry in a .zip file - char *buffer = ReadZipLump(l); - return FWadLump(buffer, l->size, true); - } - else if (l->flags & LUMPF_EXTERNAL) - { - static char zero = '\0'; - FILE *f; - - if (wad != NULL) // The WadRecord in this case is just a means to store a path - { - FString name; - - name << wad->Name << '/' << l->fullname; - f = fopen(name, "rb"); - } - else - { - f = fopen(l->fullname, "rb"); - } - // This is an external file that cannot be kept open so we have to read - // the complete contents into a memory buffer first - if (f != NULL) - { - char *buffer = new char[l->size+1]; // the last byte is used as a reference counter - buffer[l->size] = 0; - fread(buffer, 1, l->size, f); - fclose(f); - return FWadLump(buffer, l->size, true); - } - // The file got deleted or worse. At least return something. - Printf("%s: Unable to open file\n", l->fullname); - return FWadLump(&zero, 1, false); - } - else if (wad->MemoryData != NULL) - { - // A lump from an embedded WAD - // Handling this here creates less overhead than trying - // to do it inside the FWadLump class. - return FWadLump((char*)wad->MemoryData + l->position, l->size, false); - } - else - { - // An uncompressed lump in a .wad or .zip - return FWadLump (*wad, l->size, !!(l->flags & LUMPF_BLOODCRYPT)); - } + return FWadLump(LumpInfo[lump].lump); } //========================================================================== @@ -2130,126 +977,12 @@ FWadLump FWadCollection::OpenLumpNum (int lump) FWadLump *FWadCollection::ReopenLumpNum (int lump) { - LumpRecord *l; - WadFileRecord *wad; - FILE *f; - if ((unsigned)lump >= (unsigned)LumpInfo.Size()) { I_Error ("W_ReopenLumpNum: %u >= NumLumps", lump); } - l = &LumpInfo[lump]; - wad = l->wadnum >= 0 ? Wads[l->wadnum] : NULL; - - if (l->flags & LUMPF_NEEDFILESTART) - { - SetLumpAddress(l); - } - - if (l->flags & (LUMPF_COMPRESSED | LUMPF_7ZFILE)) - { - // A compressed entry in a .zip file - int address = wad->Tell(); // read from the existing WadFileRecord without reopening - char *buffer = ReadZipLump(l); - wad->Seek(address, SEEK_SET); - return new FWadLump(buffer, l->size, true); //... but restore the file pointer afterward! - } - else if (l->flags & LUMPF_EXTERNAL) - { - static char zero = '\0'; - FILE *f; - - if (wad != NULL) // The WadRecord in this case is just a means to store a path - { - FString name; - - name << wad->Name << '/' << l->fullname; - f = fopen(name, "rb"); - } - else - { - f = fopen(l->fullname, "rb"); - } - // This is an external file that cannot be kept open so we have to read - // the complete contents into a memory buffer first - if (f != NULL) - { - char *buffer = new char[l->size+1]; // the last byte is used as a reference counter - buffer[l->size] = 0; - fread(buffer, 1, l->size, f); - fclose(f); - return new FWadLump(buffer, l->size, true); - } - // The file got deleted or worse. At least return something. - Printf("%s: Unable to open file\n", l->fullname); - return new FWadLump(&zero, 1, false); - } - else if (wad->MemoryData!=NULL) - { - // A lump from an embedded WAD - // Handling this here creates less overhead than trying - // to do it inside the FWadLump class. - - return new FWadLump((char*)wad->MemoryData+l->position, l->size, false); - } - else - { - // An uncompressed lump in a .wad or .zip - f = fopen (wad->Name, "rb"); - if (f == NULL) - { - I_Error ("Could not reopen %s\n", wad->Name.GetChars()); - } - - fseek (f, l->position, SEEK_SET); - return new FWadLump (f, l->size); - } - -} - -//========================================================================== -// -// FWadCollection :: ReadZipLump -// -// Extracts a compressed file from a zip into memory. -// -//========================================================================== - -char *FWadCollection::ReadZipLump(LumpRecord *l) -{ - WadFileRecord *wad = Wads[l->wadnum]; - char *buffer = new char[l->size + 1]; // the last byte is used as a reference counter - buffer[l->size] = 0; - - if (!(l->flags & LUMPF_7ZFILE)) - { - wad->Seek(l->position, SEEK_SET); - if (l->method == METHOD_DEFLATE) - { - FileReaderZ frz(*wad, true); - frz.Read(buffer, l->size); - } - else if (l->method == METHOD_LZMA) - { - FileReaderLZMA frz(*wad, l->size, true); - frz.Read(buffer, l->size); - } - else if (l->method == METHOD_BZIP2) - { - FileReaderBZ2 frz(*wad); - frz.Read(buffer, l->size); - } - else - { - assert(0); // Should not get here - } - } - else - { - wad->Archive->Extract(l->position, buffer); - } - return buffer; + return new FWadLump(LumpInfo[lump].lump, true); } //========================================================================== @@ -2263,11 +996,11 @@ char *FWadCollection::ReadZipLump(LumpRecord *l) FileReader *FWadCollection::GetFileReader(int wadnum) { - if ((DWORD)wadnum >= Wads.Size()) + if ((DWORD)wadnum >= Files.Size()) { return NULL; } - return Wads[wadnum]; + return Files[wadnum]->GetReader(); } //========================================================================== @@ -2282,16 +1015,46 @@ const char *FWadCollection::GetWadName (int wadnum) const { const char *name, *slash; - if ((DWORD)wadnum >= Wads.Size()) + if ((DWORD)wadnum >= Files.Size()) { return NULL; } - name = Wads[wadnum]->Name; + name = Files[wadnum]->Filename; slash = strrchr (name, '/'); return slash != NULL ? slash+1 : name; } +//========================================================================== +// +// +//========================================================================== + +int FWadCollection::GetFirstLump (int wadnum) const +{ + if ((DWORD)wadnum >= Files.Size()) + { + return 0; + } + + return Files[wadnum]->GetFirstLump(); +} + +//========================================================================== +// +// +//========================================================================== + +int FWadCollection::GetLastLump (int wadnum) const +{ + if ((DWORD)wadnum >= Files.Size()) + { + return 0; + } + + return Files[wadnum]->GetFirstLump() + Files[wadnum]->LumpCount() - 1; +} + //========================================================================== // // W_GetWadFullName @@ -2302,12 +1065,12 @@ const char *FWadCollection::GetWadName (int wadnum) const const char *FWadCollection::GetWadFullName (int wadnum) const { - if ((unsigned int)wadnum >= Wads.Size()) + if ((unsigned int)wadnum >= Files.Size()) { return NULL; } - return Wads[wadnum]->Name; + return Files[wadnum]->Filename; } @@ -2328,11 +1091,12 @@ bool FWadCollection::IsUncompressedFile(int lump) const I_Error ("IsUncompressedFile: %u >= NumLumps",lump); } - LumpRecord * l = &LumpInfo[lump]; - - if (l->flags & (LUMPF_COMPRESSED|LUMPF_EXTERNAL)) return false; - else if (Wads[l->wadnum]->MemoryData!=NULL) return false; - else return true; + FResourceLump *l = LumpInfo[lump].lump; + FileReader *f = l->GetReader(); + + // We can access the file only if we get the FILE pointer from the FileReader here. + // Any other case means it won't work. + return (f != NULL && f->GetFile() != NULL); } //========================================================================== @@ -2349,159 +1113,14 @@ bool FWadCollection::IsEncryptedFile(int lump) const { return false; } - return !!(LumpInfo[lump].flags & LUMPF_BLOODCRYPT); + return !!(LumpInfo[lump].lump->Flags & LUMPF_BLOODCRYPT); } -//========================================================================== -// -// W_SkinHack -// -// Tests a wad file to see if it contains an S_SKIN marker. If it does, -// every lump in the wad is moved into a new namespace. Because skins are -// only supposed to replace player sprites, sounds, or faces, this should -// not be a problem. Yes, there are skins that replace more than that, but -// they are such a pain, and breaking them like this was done on purpose. -// This also renames any S_SKINxx lumps to just S_SKIN. -// -//========================================================================== - -void FWadCollection::SkinHack (int baselump) -{ - bool skinned = false; - bool hasmap = false; - DWORD i; - - for (i = baselump; i < NumLumps; i++) - { - if (LumpInfo[i].name[0] == 'S' && - LumpInfo[i].name[1] == '_' && - LumpInfo[i].name[2] == 'S' && - LumpInfo[i].name[3] == 'K' && - LumpInfo[i].name[4] == 'I' && - LumpInfo[i].name[5] == 'N') - { // Wad has at least one skin. - LumpInfo[i].name[6] = LumpInfo[i].name[7] = 0; - if (!skinned) - { - skinned = true; - DWORD j; - - for (j = baselump; j < NumLumps; j++) - { - // Using the baselump as the namespace is safe, because - // zdoom.wad guarantees the first possible baselump - // passed to this function is a largish number. - LumpInfo[j].namespc = baselump; - } - } - } - if (LumpInfo[i].name[0] == 'M' && - LumpInfo[i].name[1] == 'A' && - LumpInfo[i].name[2] == 'P') - { - hasmap = true; - } - } - if (skinned && hasmap) - { - Printf (TEXTCOLOR_BLUE - "The maps in %s will not be loaded because it has a skin.\n" - TEXTCOLOR_BLUE - "You should remove the skin from the wad to play these maps.\n", - Wads[LumpInfo[baselump].wadnum]->Name.GetChars()); - } -} - -//========================================================================== -// -// BloodCrypt -// -//========================================================================== - -void BloodCrypt (void *data, int key, int len) -{ - int p = (BYTE)key, i; - - for (i = 0; i < len; ++i) - { - ((BYTE *)data)[i] ^= (unsigned char)(p+(i>>1)); - } -} - -// WadFileRecord ------------------------------------------------------------ - -FWadCollection::WadFileRecord::WadFileRecord (FILE *file) -: FileReader(file), MemoryData(NULL), Archive(NULL), FirstLump(0), LastLump(0) -{ -} - -FWadCollection::WadFileRecord::WadFileRecord (const char *mem, int len) -: FileReader(), MemoryData(mem), Archive(NULL), FirstLump(0), LastLump(0) -{ - Length = len; - FilePos = StartPos = 0; -} - -FWadCollection::WadFileRecord::~WadFileRecord () -{ - if (MemoryData != NULL) - { - delete[] MemoryData; - } - if (Archive != NULL) - { - delete Archive; - } -} - -long FWadCollection::WadFileRecord::Seek (long offset, int origin) -{ - if (MemoryData == NULL) - { - return FileReader::Seek(offset, origin); - } - else - { - switch (origin) - { - case SEEK_CUR: - offset += FilePos; - break; - - case SEEK_END: - offset += Length; - break; - - default: - break; - } - FilePos = clamp(offset, 0, Length); - return 0; - } -} - -long FWadCollection::WadFileRecord::Read (void *buffer, long len) -{ - if (MemoryData == NULL) - { - return FileReader::Read(buffer, len); - } - else - { - if (FilePos + len > Length) - { - len = Length - FilePos; - } - memcpy(buffer, MemoryData + FilePos, len); - FilePos += len; - return len; - } -} // FWadLump ----------------------------------------------------------------- FWadLump::FWadLump () -: FileReader(), SourceData(NULL), DestroySource(false), Encrypted(false) +: FileReader(), Lump(NULL) { } @@ -2513,12 +1132,7 @@ FWadLump::FWadLump (const FWadLump ©) FilePos = copy.FilePos; StartPos = copy.StartPos; CloseOnDestruct = false; - SourceData = copy.SourceData; - DestroySource = copy.DestroySource; - if (SourceData != NULL && DestroySource) - { - SourceData[copy.Length]++; - } + if ((Lump = copy.Lump)) Lump->CacheLump(); } #ifdef _DEBUG @@ -2529,56 +1143,47 @@ FWadLump & FWadLump::operator= (const FWadLump ©) Length = copy.Length; FilePos = copy.FilePos; StartPos = copy.StartPos; - CloseOnDestruct = false; // For WAD lumps this is always false! - SourceData = copy.SourceData; - DestroySource = copy.DestroySource; - if (SourceData != NULL && DestroySource) - { - SourceData[copy.Length]++; - } + CloseOnDestruct = false; + if ((Lump = copy.Lump)) Lump->CacheLump(); return *this; } #endif -FWadLump::FWadLump (const FileReader &other, long length, bool encrypted) -: FileReader(other, length), SourceData(NULL), DestroySource(false), Encrypted(encrypted) -{ -} -FWadLump::FWadLump (FILE *file, long length) -: FileReader(file, length), SourceData(NULL), DestroySource(false), Encrypted(false) +FWadLump::FWadLump(FResourceLump *lump, bool alwayscache) +: FileReader() { -} + FileReader *f = lump->GetReader(); -FWadLump::FWadLump (char *data, long length, bool destroy) -: FileReader(), SourceData(data), DestroySource(destroy), Encrypted(false) -{ - FilePos = StartPos = 0; - Length = length; - if (destroy) + if (f != NULL && f->GetFile() != NULL && !alwayscache) { - data[length] = 0; + // Uncompressed lump in a file + File = f->GetFile(); + Length = lump->LumpSize; + StartPos = FilePos = lump->GetFileOffset(); + Lump = NULL; + } + else + { + File = NULL; + Length = lump->LumpSize; + StartPos = FilePos = 0; + Lump = lump; + Lump->CacheLump(); } } FWadLump::~FWadLump() { - if (SourceData && DestroySource) + if (Lump != NULL) { - if (SourceData[Length] == 0) - { - delete[] SourceData; - } - else - { - SourceData[Length]--; - } + Lump->ReleaseCache(); } } long FWadLump::Seek (long offset, int origin) { - if (SourceData) + if (Lump != NULL) { switch (origin) { @@ -2604,13 +1209,13 @@ long FWadLump::Read (void *buffer, long len) long numread; long startread = FilePos; - if (SourceData != NULL) + if (Lump != NULL) { if (FilePos + len > Length) { len = Length - FilePos; } - memcpy(buffer, SourceData + FilePos, len); + memcpy(buffer, Lump->Cache + FilePos, len); FilePos += len; numread = len; } @@ -2618,36 +1223,14 @@ long FWadLump::Read (void *buffer, long len) { numread = FileReader::Read(buffer, len); } - - // Blood, you are so mean to me with your encryption. - if (Encrypted && startread - StartPos < 256) - { - int cryptstart = startread - StartPos; - int cryptlen = MIN (FilePos - StartPos, 256); - BYTE *data = (BYTE *)buffer - cryptstart; - - for (int i = cryptstart; i < cryptlen; ++i) - { - data[i] ^= i >> 1; - } - } - return numread; } char *FWadLump::Gets(char *strbuf, int len) { - // Blood, you are so mean to me with your encryption. - // ... and since this function will never read from Blood - // files let's just return an error here. - if (Encrypted && FilePos - StartPos < 256) + if (Lump != NULL) { - return NULL; - } - - if (SourceData != NULL) - { - return GetsFromBuffer(SourceData, strbuf, len); + return GetsFromBuffer(Lump->Cache, strbuf, len); } else { diff --git a/src/w_wad.h b/src/w_wad.h index ec6cbfec4..10e01ace7 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -27,26 +27,9 @@ #include "doomdef.h" #include "tarray.h" -// [RH] Compare wad header as ints instead of chars -#define IWAD_ID MAKE_ID('I','W','A','D') -#define PWAD_ID MAKE_ID('P','W','A','D') -#define RFF_ID MAKE_ID('R','F','F',0x1a) -#define ZIP_ID MAKE_ID('P','K',3,4) -#define GRP_ID_0 MAKE_ID('K','e','n','S') -#define GRP_ID_1 MAKE_ID('i','l','v','e') -#define GRP_ID_2 MAKE_ID('r','m','a','n') +class FResourceFile; +struct FResourceLump; -// [RH] Remove limit on number of WAD files -struct wadlist_t -{ - wadlist_t *next; - char name[1]; // +size of string -}; -extern wadlist_t *wadfiles; - -// -// TYPES -// struct wadinfo_t { // Should be "IWAD" or "PWAD". @@ -62,17 +45,18 @@ struct wadlump_t char Name[8]; }; -enum -{ - LUMPF_BLOODCRYPT = 1, // Lump uses Blood-style encryption - LUMPF_COMPRESSED = 2, // Zip-compressed - LUMPF_ZIPFILE = 4, // Inside a Zip file - used to enforce use of special directories insize Zips - LUMPF_NEEDFILESTART = 8, // Still need to process local file header to find file start inside a zip - LUMPF_EXTERNAL = 16, // Lump is from an external file that won't be kept open permanently - LUMPF_7ZFILE = 32, // Inside a 7z archive; position is its index in the archive -}; +#define IWAD_ID MAKE_ID('I','W','A','D') +#define PWAD_ID MAKE_ID('P','W','A','D') +// [RH] Remove limit on number of WAD files +struct wadlist_t +{ + wadlist_t *next; + char name[1]; // +size of string +}; +extern wadlist_t *wadfiles; + // [RH] Namespaces from BOOM. typedef enum { ns_global = 0, @@ -96,17 +80,22 @@ typedef enum { ns_patches, ns_graphics, ns_music, + + ns_firstskin, } namespace_t; +enum ELumpFlags +{ + LUMPF_MAYBEFLAT=1, + LUMPF_ZIPFILE=2, + LUMPF_EMBEDDED=4, + LUMPF_BLOODCRYPT = 8, +}; + + // [RH] Copy an 8-char string and uppercase it. void uppercopy (char *to, const char *from); -// Perform Blood encryption/decryption. -void BloodCrypt (void *data, int key, int len); - -// Locate central directory in a zip file. -DWORD Zip_FindCentralDir(FileReader * fin); - // A very loose reference to a lump on disk. This is really just a wrapper // around the main wad's FILE object with a different length recorded. Since // two lumps from the same wad share the same FILE, you cannot read from @@ -126,13 +115,9 @@ public: char *Gets(char *strbuf, int len); private: - FWadLump (const FileReader &reader, long length, bool encrypted); - FWadLump (FILE *file, long length); - FWadLump (char * data, long length, bool destroy); + FWadLump (FResourceLump *Lump, bool alwayscache = false); - char *SourceData; - bool DestroySource; - bool Encrypted; + FResourceLump *Lump; friend class FWadCollection; }; @@ -169,12 +154,15 @@ public: enum { IWAD_FILENUM = 1 }; void InitMultipleFiles (wadlist_t **filenames); - void AddFile (const char *filename, const char *data=NULL, int length=-1); + void AddFile (const char *filename, FileReader *wadinfo = NULL); int CheckIfWadLoaded (const char *name); const char *GetWadName (int wadnum) const; const char *GetWadFullName (int wadnum) const; + int GetFirstLump(int wadnum) const; + int GetLastLump(int wadnum) const; + int CheckNumForName (const char *name, int namespc); int CheckNumForName (const char *name, int namespc, int wadfile, bool exact = true); int GetNumForName (const char *name, int namespc); @@ -225,36 +213,26 @@ public: int AddExternalFile(const char *filename); protected: - class WadFileRecord; + struct LumpRecord; + TArray Files; + TArray LumpInfo; + DWORD *FirstLumpIndex; // [RH] Hashing stuff moved out of lumpinfo structure DWORD *NextLumpIndex; DWORD *FirstLumpIndex_FullName; // The same information for fully qualified paths from .zips DWORD *NextLumpIndex_FullName; - - TArray LumpInfo; - TArray Wads; DWORD NumLumps; // Not necessarily the same as LumpInfo.Size() DWORD NumWads; void SkinHack (int baselump); void InitHashChains (); // [RH] Set up the lumpinfo hashing - // [RH] Combine multiple marked ranges of lumps into one. - int MergeLumps (const char *start, const char *end, int name_space); - bool IsMarker (const LumpRecord *lump, const char *marker) const; - void FindStrifeTeaserVoices (); - - char *ReadZipLump(LumpRecord *l); - private: - static int STACK_ARGS lumpcmp(const void * a, const void * b); - void ScanForFlatHack (int startlump); void RenameSprites (int startlump); - void SetLumpAddress(LumpRecord *l); void DeleteAll(); }; diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 14dd53f50..20cd4bc49 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -1648,8 +1648,7 @@ void WI_updateStats () { WI_updateAnimatedBack (); - if ((!(gameinfo.gametype & GAME_DoomChex) || acceleratestage) - && sp_state != 10) + if ((!gameinfo.intermissioncounter || acceleratestage) && sp_state != 10) { if (acceleratestage) { @@ -1667,7 +1666,7 @@ void WI_updateStats () if (sp_state == 2) { - if (gameinfo.gametype & GAME_DoomChex) + if (gameinfo.intermissioncounter) { cnt_kills[0] += 2; @@ -1683,7 +1682,7 @@ void WI_updateStats () } else if (sp_state == 4) { - if (gameinfo.gametype & GAME_DoomChex) + if (gameinfo.intermissioncounter) { cnt_items[0] += 2; @@ -1699,7 +1698,7 @@ void WI_updateStats () } else if (sp_state == 6) { - if (gameinfo.gametype & GAME_DoomChex) + if (gameinfo.intermissioncounter) { cnt_secret[0] += 2; @@ -1715,7 +1714,7 @@ void WI_updateStats () } else if (sp_state == 8) { - if (gameinfo.gametype & GAME_DoomChex) + if (gameinfo.intermissioncounter) { if (!(bcnt&3)) S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); diff --git a/wadsrc/static/mapinfo/chex.txt b/wadsrc/static/mapinfo/chex.txt index dec8990c2..a83a51bc4 100644 --- a/wadsrc/static/mapinfo/chex.txt +++ b/wadsrc/static/mapinfo/chex.txt @@ -25,6 +25,7 @@ gameinfo backpacktype = "ZorchPack" statusbar = "sbarinfo/doom.txt" intermissionmusic = "$MUSIC_INTER" + intermissioncounter = true weaponslot = 1, "Bootspoon", "SuperBootspork" weaponslot = 2, "MiniZorcher" weaponslot = 3, "LargeZorcher", "SuperLargeZorcher" diff --git a/wadsrc/static/mapinfo/doomcommon.txt b/wadsrc/static/mapinfo/doomcommon.txt index 1de00818e..a545da8c1 100644 --- a/wadsrc/static/mapinfo/doomcommon.txt +++ b/wadsrc/static/mapinfo/doomcommon.txt @@ -25,6 +25,7 @@ gameinfo backpacktype = "Backpack" statusbar = "sbarinfo/doom.txt" intermissionmusic = "$MUSIC_DM2INT" + intermissioncounter = true weaponslot = 1, "Fist", "Chainsaw" weaponslot = 2, "Pistol" weaponslot = 3, "Shotgun", "SuperShotgun" diff --git a/wadsrc/static/mapinfo/heretic.txt b/wadsrc/static/mapinfo/heretic.txt index 733498aa9..93dc98e98 100644 --- a/wadsrc/static/mapinfo/heretic.txt +++ b/wadsrc/static/mapinfo/heretic.txt @@ -25,6 +25,7 @@ gameinfo backpacktype = "BagOfHolding" statusbar = "" intermissionmusic = "mus_intr" + intermissioncounter = false weaponslot = 1, "Staff", "Gauntlets" weaponslot = 2, "GoldWand" weaponslot = 3, "Crossbow" diff --git a/wadsrc/static/mapinfo/hexen.txt b/wadsrc/static/mapinfo/hexen.txt index be391e994..547b6d4f6 100644 --- a/wadsrc/static/mapinfo/hexen.txt +++ b/wadsrc/static/mapinfo/hexen.txt @@ -28,6 +28,7 @@ gameinfo backpacktype = "BagOfHolding" // Hexen doesn't have a backpack so use Heretic's. statusbar = "" intermissionmusic = "hub" + intermissioncounter = false weaponslot = 1, "FWeapFist", "CWeapMace", "MWeapWand" weaponslot = 2, "FWeapAxe", "CWeapStaff", "MWeapFrost" weaponslot = 3, "FWeapHammer", "CWeapFlame", "MWeapLightning" diff --git a/wadsrc/static/mapinfo/strife.txt b/wadsrc/static/mapinfo/strife.txt index b94b02846..ef3a66f8f 100644 --- a/wadsrc/static/mapinfo/strife.txt +++ b/wadsrc/static/mapinfo/strife.txt @@ -25,6 +25,7 @@ gameinfo backpacktype = "AmmoSatchel" statusbar = "" intermissionmusic = "d_slide" + intermissioncounter = false weaponslot = 1, "PunchDagger" weaponslot = 2, "StrifeCrossbow2", "StrifeCrossbow" weaponslot = 3, "AssaultGun" diff --git a/zdoom.vcproj b/zdoom.vcproj index 33a9cb130..1e86e8e24 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + @@ -1856,14 +1864,6 @@ Outputs="$(IntDir)/$(InputName).obj" /> - - - @@ -2029,14 +2029,6 @@ Outputs="$(IntDir)\$(InputName).obj" /> - - - @@ -2047,6 +2039,14 @@ Outputs="$(IntDir)\$(InputName).obj" /> + + + - - - + + + - - - @@ -5355,6 +5347,14 @@ AdditionalIncludeDirectories="src\win32;$(NoInherit)" /> + + + @@ -5633,7 +5633,7 @@ /> + + + + + + + + + + + + + + + + + + + +