From 153d3b46817325d43d370530724c4acd02214694 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 14 Apr 2006 16:25:57 +0000 Subject: [PATCH] SVN r45 (trunk) --- docs/rh-log.txt | 5 + src/p_mobj.cpp | 41 ++-- src/w_wad.cpp | 627 +++++++++++++++++++++++++++++++++++++++++++++--- src/w_wad.h | 28 ++- src/w_zip.h | 64 +++++ zdoom.vcproj | 3 + 6 files changed, 717 insertions(+), 51 deletions(-) create mode 100644 src/w_zip.h diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 6f890cecc..7667f362c 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,9 @@ April 14, 2006 (Changes by Graf Zahl) +- Added GZDoom's HI_START/HI_END lump namespace. Even though it doesn't do + anything (yet) suppporting it allows to make WADs that use hires texture + replacements but are able to run with ZDoom as well. +- Added GZDoom's Zip-support but changed it so that lumps are sorted + alphabetically. - Added the missing file 'flac/private/float.h' to the repository. - Added: In preparation for Zip-support the sound code has to be able to load music data from memory, not just from files. diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f09fbcde6..72ee365ac 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -2631,32 +2631,35 @@ void AActor::Tick () if ((flags & MF_SOLID) && !(flags & (MF_NOCLIP|MF_NOGRAVITY)) && !(flags & MF_NOBLOCKMAP) && momz <= 0 && - floorz == z && - floorsector->floorplane.c < STEEPSLOPE && - floorsector->floorplane.ZatPoint (x, y) <= floorz) + floorz == z) { - const msecnode_t *node; - bool dopush = true; - - if (floorsector->floorplane.c > STEEPSLOPE*2/3) + const secplane_t * floorplane = &floorsector->floorplane; + if (floorplane->c < STEEPSLOPE && + floorplane->ZatPoint (x, y) <= floorz) { - for (node = touching_sectorlist; node; node = node->m_tnext) + const msecnode_t *node; + bool dopush = true; + + if (floorplane->c > STEEPSLOPE*2/3) { - const sector_t *sec = node->m_sector; - if (sec->floorplane.c >= STEEPSLOPE) + for (node = touching_sectorlist; node; node = node->m_tnext) { - if (sec->floorplane.ZatPoint (x, y) >= z - MaxStepHeight) + const sector_t *sec = node->m_sector; + if (sec->floorplane.c >= STEEPSLOPE) { - dopush = false; - break; + if (floorplane->ZatPoint (x, y) >= z - MaxStepHeight) + { + dopush = false; + break; + } } } } - } - if (dopush) - { - momx += floorsector->floorplane.a; - momy += floorsector->floorplane.b; + if (dopush) + { + momx += floorplane->a; + momy += floorplane->b; + } } } @@ -3654,7 +3657,7 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position) return; // [RH] don't spawn extra weapons in coop if so desired - if (multiplayer && !deathmatch && (dmflags&DF_NO_COOP_WEAPON_SPAWN)) + if (multiplayer && !deathmatch && !(dmflags&DF_NO_COOP_WEAPON_SPAWN)) { if (i->IsDescendantOf (RUNTIME_CLASS(AWeapon))) { diff --git a/src/w_wad.cpp b/src/w_wad.cpp index a254c6e6b..db2b320ea 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -23,7 +23,9 @@ #include "m_argv.h" #include "i_system.h" #include "cmdlib.h" +#include "c_dispatch.h" #include "w_wad.h" +#include "w_zip.h" #include "m_crc32.h" #include "v_text.h" #include "templates.h" @@ -69,27 +71,37 @@ struct rfflump_t struct FWadCollection::LumpRecord { char name[8]; + char * fullname; // only valid for files loaded from a .zip file int position; int size; int namespc; short wadnum; WORD flags; + int compressedsize; }; enum { - LUMPF_BLOODCRYPT = 1 // Lump uses Blood-style encryption + LUMPF_BLOODCRYPT = 1, // Lump uses Blood-style encryption + LUMPF_COMPRESSED = 2 // Zip-compressed }; 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; + char *Name; DWORD FirstLump; DWORD LastLump; + }; @@ -121,13 +133,12 @@ FWadCollection Wads; // Suprisingly, glibc lacks this //========================================================================== -#ifndef HAVE_STRUPR +#ifdef NEED_STRUPR void strupr (char *s) { - while (*s) - { + while (*s) { *s = toupper (*s); - s++; + ++s; } } #endif @@ -139,7 +150,7 @@ void strupr (char *s) // Suprisingly, glibc lacks this //========================================================================== -#ifndef HAVE_FILELENGTH +#ifdef NEED_FILELENGTH int filelength (int handle) { struct stat fileinfo; @@ -172,10 +183,15 @@ void uppercopy (char *to, const char *from) FWadCollection::FWadCollection () : FirstLumpIndex(NULL), NextLumpIndex(NULL), LumpInfo(NULL), Wads(NULL), + FirstLumpIndex_FullName(NULL), NextLumpIndex_FullName(NULL), NumLumps(0), NumWads(0) { } +FWadCollection::~FWadCollection () +{ +} + //========================================================================== // // W_InitMultipleFiles @@ -232,13 +248,73 @@ void FWadCollection::InitMultipleFiles (wadlist_t **filenames) 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 WORD[NumLumps]; NextLumpIndex = new WORD[NumLumps]; + FirstLumpIndex_FullName = new WORD[NumLumps]; + NextLumpIndex_FullName = new WORD[NumLumps]; InitHashChains (); } +#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; + 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); + + buf = (unsigned char*)Malloc(BUFREADCOMMENT+4); + if (buf == NULL) return 0; + + 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))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + free(buf); + return uPosFound; +} + //========================================================================== // // W_AddFile @@ -248,8 +324,16 @@ void FWadCollection::InitMultipleFiles (wadlist_t **filenames) // // [RH] Removed reload hack //========================================================================== +int STACK_ARGS FWadCollection::lumpcmp(const void * a, const void * b) +{ + FWadCollection::LumpRecord * rec1 = (FWadCollection::LumpRecord *)a; + FWadCollection::LumpRecord * rec2 = (FWadCollection::LumpRecord *)b; -void FWadCollection::AddFile (const char *filename) + return !stricmp(rec1->fullname, rec2->fullname); +} + + +void FWadCollection::AddFile (const char *filename, const char * data, int length) { WadFileRecord *wadinfo; MergedHeader header; @@ -259,20 +343,30 @@ void FWadCollection::AddFile (const char *filename) int startlump; wadlump_t* fileinfo = NULL, *fileinfo2free = NULL; wadlump_t singleinfo; + TArray EmbeddedWADs; + void * directory = NULL; - // open the file and add to directory - handle = fopen (filename, "rb"); - if (handle == NULL) - { // Didn't find file - Printf (TEXTCOLOR_RED " couldn't open %s\n", filename); - PrintLastError (); - return; + if (length==-1) + { + // open the file and add to directory + handle = fopen (filename, "rb"); + if (handle == NULL) + { // Didn't find file + Printf (TEXTCOLOR_RED " couldn't open %s\n", filename); + 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; - wadinfo = new WadFileRecord (handle); // [RH] Determine if file is a WAD based on its signature, not its name. if (wadinfo->Read (&header, sizeof(header)) == 0) @@ -337,6 +431,8 @@ void FWadCollection::AddFile (const char *filename) lump_p->position = LittleLong(rff_p->FilePos); lump_p->size = LittleLong(rff_p->Size); lump_p->flags = (rff_p->Flags & 0x10) >> 4; + lump_p->fullname = NULL; + lump_p->compressedsize=-1; lump_p++; } delete[] lumps; @@ -345,6 +441,156 @@ void FWadCollection::AddFile (const char *filename) LumpInfo = (LumpRecord *)Realloc (LumpInfo, NumLumps*sizeof(LumpRecord)); } } + else if (header.magic==ZIP_ID) + { + DWORD centraldir = Zip_FindCentralDir(wadinfo); + FZipCentralInfo info; + int skipped = 0; + + if (centraldir==0) + { + Printf("\n%s: ZIP file corrupt!\n", filename); + return; + } + + // Read the central directory info. + wadinfo->Seek(centraldir, SEEK_SET); + wadinfo->Read(&info, sizeof(FZipCentralInfo)); + + // No multi-disk zips! + if (info.wEntryCount != info.wTotalEntryCount || + info.wNumberDiskWithCD != 0 || info.wNumberDisk != 0) + { + Printf("\n%s: Multipart Zip files are not supported.\n", filename); + return; + } + + NumLumps += LittleShort(info.wEntryCount); + LumpInfo = (LumpRecord *)Realloc (LumpInfo, NumLumps*sizeof(LumpRecord)); + lump_p = &LumpInfo[startlump]; + + // Load the entire central directory. Too bad that this contains variable length entries... + directory = malloc(LittleLong(info.dwCDSize)); + wadinfo->Seek(LittleLong(info.dwCDOffset), SEEK_SET); + wadinfo->Read(directory, LittleLong(info.dwCDSize)); + + char * dirptr =(char*)directory; + for (int i = 0; i < LittleShort(info.wEntryCount); i++) + { + FZipFileInfo * zip_fh = (FZipFileInfo*)dirptr; + char name[256]; + char base[256]; + FZipLocalHeader localHeader; + + int len = LittleShort(zip_fh->wFileNameSize); + strncpy(name, dirptr + sizeof(FZipFileInfo), MIN(len, 255)); + name[len]=0; + dirptr += sizeof(FZipFileInfo) + + LittleShort(zip_fh->wFileNameSize) + + LittleShort(zip_fh->wExtraSize) + + LittleShort(zip_fh->wCommentSize); + + // skip Directories + if(name[len - 1] == '/' && LittleLong(zip_fh->dwSize) == 0) + { + skipped++; + continue; + } + + // Ignore obsolete compression formats + if(LittleShort(zip_fh->wCompression) != 0 && LittleShort(zip_fh->wCompression) != Z_DEFLATED) + { + Printf("\n: %s: '%s' uses an unsupported compression algorithm.\n", filename, name); + skipped++; + continue; + } + // Also ignore encrypted entries + if(LittleShort(zip_fh->wFlags) & ZF_ENCRYPTED) + { + Printf("\n%s: '%s' is encrypted. Encryption is not supported.\n", filename, name); + skipped++; + continue; + } + + FixPathSeperator(name); + strlwr(name); + + // Check for embedded WADs. They must be extracted and added separately to the lump list. + // Embedded .zips are ignored for now. But they should be allowed later! + char * c = strstr(name, ".wad"); + if (c && strlen(c)==4) + { + EmbeddedWADs.Push(zip_fh); + skipped++; + continue; + } + + //ExtractFileBase(name, base); + char * lname=strrchr(name,'/'); + if (!lname) lname=name; + else lname++; + strcpy(base, lname); + char * dot = strrchr(base,'.'); + if (dot) *dot=0; + strupr(base); + strncpy(lump_p->name, base, 8); + lump_p->fullname = copystring(name); + lump_p->position = LittleLong(zip_fh->dwFileOffset) + sizeof(FZipLocalHeader) + LittleShort(zip_fh->wFileNameSize); + lump_p->size = zip_fh->dwSize; + lump_p->namespc = !strncmp(name, "flats/", 6) ? ns_flats : + !strncmp(name, "textures/", 9) ? ns_newtextures : + !strncmp(name, "hires/", 6) ? ns_hires : + !strncmp(name, "sprites/", 8) ? ns_sprites : + !strncmp(name, "colormaps/", 10) ? ns_colormaps : + !strncmp(name, "acs/", 4) ? ns_acslibrary : + !strncmp(name, "voices/", 7) ? ns_strifevoices : + !strncmp(name, "patches/", 8) ? ns_global : + !strncmp(name, "graphics/", 9) ? ns_global : + !strncmp(name, "sounds/", 7) ? ns_global : + !strncmp(name, "music/", 6) ? ns_global : + !strchr(name, '/') ? 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 (lump_p->namespc==-1) + { + memset(lump_p->name, 0, 8); + } + + lump_p->wadnum = (WORD)NumWads; + lump_p->flags = LittleShort(zip_fh->wCompression) == Z_DEFLATED? LUMPF_COMPRESSED : 0; + lump_p->compressedsize = LittleLong(zip_fh->dwCompressedSize); + + // 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. + if (lump_p->namespc == ns_sprites) + { + char * c; + + while (c=(char*)memchr(lump_p->name, '^', 8)) + { + *c='\\'; + } + } + + // Now it gets ugly: We must retrieve the actual offset where the data begins. + // Thanks to some bad file format design this has to do some additional steps. + + // Read the local file header, which contains the correct extra field size (Info-ZIP!). + wadinfo->Seek(LittleLong(zip_fh->dwFileOffset), SEEK_SET); + wadinfo->Read(&localHeader, sizeof(localHeader)); + lump_p->position += LittleShort(localHeader.wExtraSize); + lump_p++; + } + // Resize the lump record array to its actual size + NumLumps -= skipped; + LumpInfo = (LumpRecord *)Realloc (LumpInfo, NumLumps*sizeof(LumpRecord)); + + // Entries in Zips are sorted alphabetically. + qsort(LumpInfo + startlump, NumLumps - startlump, sizeof(LumpRecord), lumpcmp); + } else { // This is just a single lump file char name[PATH_MAX]; @@ -361,7 +607,7 @@ void FWadCollection::AddFile (const char *filename) Printf ("\n"); // Fill in lumpinfo - if (header.magic != RFF_ID) + if (header.magic != RFF_ID && header.magic != ZIP_ID) { LumpInfo = (LumpRecord *)Realloc (LumpInfo, NumLumps*sizeof(LumpRecord)); lump_p = &LumpInfo[startlump]; @@ -374,6 +620,8 @@ void FWadCollection::AddFile (const char *filename) 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) @@ -394,6 +642,48 @@ void FWadCollection::AddFile (const char *filename) { FindStrifeTeaserVoices (); } + + if (EmbeddedWADs.Size()) + { + char path[256]; + + sprintf(path, "%s:", filename); + char * wadstr = path+strlen(path); + + for(int i=0; i < EmbeddedWADs.Size(); i++) + { + FZipFileInfo * zip_fh = EmbeddedWADs[i]; + FZipLocalHeader localHeader; + + *wadstr=0; + int len = LittleShort(zip_fh->wFileNameSize); + if (len+strlen(path) > 255) len = 255-strlen(path); + strncpy(wadstr, ((char*)zip_fh) + sizeof(FZipFileInfo), len); + wadstr[len]=0; + + DWORD size = LittleLong(zip_fh->dwSize); + char * buffer = new char[size]; + + int position = LittleLong(zip_fh->dwFileOffset) ; + + wadinfo->Seek(position, SEEK_SET); + wadinfo->Read(&localHeader, sizeof(localHeader)); + position += LittleShort(localHeader.wExtraSize) + sizeof(FZipLocalHeader) + LittleShort(zip_fh->wFileNameSize); + + wadinfo->Seek(position, SEEK_SET); + if (zip_fh->wCompression == Z_DEFLATED) + { + FileReaderZ frz(*wadinfo, true); + frz.Read(buffer, size); + } + else + { + wadinfo->Read(buffer, size); + } + AddFile(path, buffer, size); + } + } + if (directory != NULL) free(directory); } //========================================================================== @@ -523,6 +813,75 @@ int FWadCollection::GetNumForName (const char *name) } +//========================================================================== +// +// W_CheckNumForFullName +// +// Same as above but looks for a fully qualified name from a .zip +// These don't care about namespaces though because those are part +// of the path. +// +//========================================================================== + +int FWadCollection::CheckNumForFullName (const char *name) +{ + WORD i; + + if (name == NULL) + { + return -1; + } + + i = FirstLumpIndex_FullName[MakeKey (name) % NumLumps]; + + while (i != NULL_INDEX && stricmp(name, LumpInfo[i].fullname)) + { + i = NextLumpIndex_FullName[i]; + } + + return i != NULL_INDEX ? i : -1; +} + +int FWadCollection::CheckNumForFullName (const char *name, int wadnum) +{ + WORD i; + + if (wadnum < 0) + { + return CheckNumForFullName (name); + } + + i = FirstLumpIndex[MakeKey (name) % NumLumps]; + + while (i != NULL_INDEX && + (stricmp(name, LumpInfo[i].fullname) || LumpInfo[i].wadnum != wadnum)) + { + i = NextLumpIndex[i]; + } + + return i != NULL_INDEX ? i : -1; +} + +//========================================================================== +// +// W_GetNumForFullName +// +// Calls W_CheckNumForFullName, but bombs out if not found. +// +//========================================================================== + +int FWadCollection::GetNumForFullName (const char *name) +{ + int i; + + i = CheckNumForFullName (name); + + if (i == -1) + I_Error ("GetNumForFullName: %s not found!", name); + + return i; +} + //========================================================================== // // W_LumpLength @@ -600,7 +959,9 @@ void FWadCollection::InitHashChains (void) // Mark all buckets as empty memset (FirstLumpIndex, 255, NumLumps*sizeof(FirstLumpIndex[0])); - memset (NextLumpIndex, 255, NumLumps*sizeof(FirstLumpIndex[0])); + memset (NextLumpIndex, 255, NumLumps*sizeof(NextLumpIndex[0])); + memset (FirstLumpIndex_FullName, 255, NumLumps*sizeof(FirstLumpIndex_FullName[0])); + memset (NextLumpIndex_FullName, 255, NumLumps*sizeof(NextLumpIndex_FullName[0])); // Now set up the chains for (i = 0; i < (unsigned)NumLumps; i++) @@ -609,6 +970,14 @@ void FWadCollection::InitHashChains (void) j = LumpNameHash (name) % NumLumps; NextLumpIndex[i] = FirstLumpIndex[j]; FirstLumpIndex[j] = i; + + // Do the same for the full paths + if (LumpInfo[i].fullname!=NULL) + { + j = MakeKey(LumpInfo[i].fullname) % NumLumps; + NextLumpIndex_FullName[i] = FirstLumpIndex_FullName[j]; + FirstLumpIndex_FullName[j] = i; + } } } @@ -918,6 +1287,25 @@ int FWadCollection::MergeLumps (const char *start, const char *end, int space) { 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[newlumps++] = LumpInfo[i]; + } + else // Check if this is the start of a block if (IsMarker (LumpInfo + i, ustart)) { @@ -929,6 +1317,7 @@ int FWadCollection::MergeLumps (const char *start, const char *end, int space) { newlumps++; strncpy (newlumpinfos[0].name, ustart, 8); + newlumpinfos[0].fullname=NULL; newlumpinfos[0].wadnum = -1; newlumpinfos[0].position = newlumpinfos[0].size = 0; @@ -969,13 +1358,14 @@ int FWadCollection::MergeLumps (const char *start, const char *end, int space) if (newlumps) { if (size_t(oldlumps + newlumps) >= NumLumps) - LumpInfo = (LumpRecord *)Realloc (LumpInfo, (oldlumps + newlumps + 1) * sizeof(LumpRecord)); + LumpInfo = (LumpRecord *)Realloc (LumpInfo, (oldlumps + newlumps + 1) * sizeof(LumpRecord) ); 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; @@ -1193,7 +1583,28 @@ FWadLump FWadCollection::OpenLumpNum (int lump) #endif wad->Seek (l->position, SEEK_SET); - return FWadLump (*wad, l->size); + + if (l->flags & LUMPF_COMPRESSED) + { + // A compressed entry in a .zip file + char * buffer = new char[l->size+1]; // the last byte is used as a reference counter + FileReaderZ frz(*wad, true); + frz.Read(buffer, l->size); + return FWadLump(buffer, l->size, true); + } + 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); + } } //========================================================================== @@ -1220,14 +1631,39 @@ FWadLump *FWadCollection::ReopenLumpNum (int lump) l = &LumpInfo[lump]; wad = Wads[l->wadnum]; - f = fopen (wad->Name, "rb"); - if (f == NULL) + + if (l->flags & LUMPF_COMPRESSED) { - I_Error ("Could not reopen %s\n", wad->Name); + // A compressed entry in a .zip file + int address = wad->Tell(); // read from the existing WadFileRecord without reopening + char * buffer = new char[l->size+1]; // the last byte is used as a reference counter + wad->Seek(l->position, SEEK_SET); + FileReaderZ frz(*wad, true); + frz.Read(buffer, l->size); + wad->Seek(address, SEEK_SET); + return new FWadLump(buffer, l->size, true); //... but restore the file pointer afterward! + } + 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); + } + + fseek (f, l->position, SEEK_SET); + return new FWadLump (f, l->size); } - fseek (f, l->position, SEEK_SET); - return new FWadLump (f, l->size); } //========================================================================== @@ -1283,7 +1719,6 @@ const char *FWadCollection::GetWadFullName (int wadnum) const bool FWadCollection::IsUncompressedFile(int lump) const { - /* if ((unsigned)lump >= (unsigned)NumLumps) { I_Error ("IsUncompressedFile: %u >= NumLumps",lump); @@ -1293,8 +1728,7 @@ bool FWadCollection::IsUncompressedFile(int lump) const if (l->flags & LUMPF_COMPRESSED) return false; else if (Wads[l->wadnum]->MemoryData!=NULL) return false; - */ - return true; + else return true; } //========================================================================== @@ -1413,6 +1847,14 @@ static void PrintLastError () FWadCollection::WadFileRecord::WadFileRecord (FILE *file) : FileReader(file), Name(NULL), FirstLump(0), LastLump(0) { + MemoryData=NULL; +} + +FWadCollection::WadFileRecord::WadFileRecord (const char * mem, int len) +: FileReader(), Name(NULL), FirstLump(0), LastLump(0), MemoryData(mem) +{ + Length = len; + FilePos = StartPos = 0; } FWadCollection::WadFileRecord::~WadFileRecord () @@ -1423,28 +1865,151 @@ FWadCollection::WadFileRecord::~WadFileRecord () } } +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; + } + if (offset<0) offset=0; + else if (offset>Length) offset=Length; + FilePos=offset; + 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::FWadLump () -: FileReader () +: FileReader (), sourceData(NULL) { } FWadLump::FWadLump (const FWadLump ©) { + // This must be defined isn't called. File = copy.File; + Length=copy.Length; + FilePos=copy.FilePos; + StartPos=copy.StartPos; + CloseOnDestruct=false; + if (copy.sourceData!=NULL) + { + sourceData=copy.sourceData; + destroySource=copy.destroySource; + if (destroySource) sourceData[copy.Length]++; + } + else sourceData=NULL; } +#ifdef _DEBUG +FWadLump & FWadLump::operator= (const FWadLump ©) +{ + // Only the debug build actually calls this! + File = copy.File; + Length=copy.Length; + FilePos=copy.FilePos; + StartPos=copy.StartPos; + CloseOnDestruct=false; // For WAD lumps this is always false! + if (copy.sourceData!=NULL) + { + sourceData=copy.sourceData; + destroySource=copy.destroySource; + if (destroySource) sourceData[copy.Length]++; + } + else sourceData=NULL; + return *this; +} +#endif + FWadLump::FWadLump (const FileReader &other, long length) -: FileReader (other, length) +: FileReader (other, length), sourceData(NULL) { } FWadLump::FWadLump (FILE *file, long length) -: FileReader (file, length) +: FileReader (file, length), sourceData(NULL) { } +FWadLump::FWadLump (char * data, long length, bool destroy) +: FileReader (), sourceData(data) +{ + FilePos = StartPos = 0; + Length=length; + destroySource=destroy; + if (destroySource) data[length]=0; +} + +FWadLump::~FWadLump() +{ + if (sourceData && destroySource) + { + if (sourceData[Length]==0) delete [] sourceData; + else sourceData[Length]--; + } +} + +long FWadLump::Seek (long offset, int origin) +{ + if (sourceData) + { + switch (origin) + { + case SEEK_CUR: + offset+=FilePos; + break; + + case SEEK_END: + offset+=Length; + break; + default: + break; + } + if (offset<0) offset=0; + else if (offset>Length) offset=Length; + FilePos=offset; + return 0; + } + else return FileReader::Seek(offset, origin); +} + +long FWadLump::Read (void *buffer, long len) +{ + if (sourceData) + { + if (FilePos+len>Length) len=Length-FilePos; + memcpy(buffer, sourceData+FilePos, len); + FilePos+=len; + return len; + } + else return FileReader::Read(buffer, len); +} + // FMemLump ----------------------------------------------------------------- FMemLump::FMemLump () diff --git a/src/w_wad.h b/src/w_wad.h index 94b9c8404..227d90148 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -76,6 +76,7 @@ typedef enum { ns_bloodsfx, ns_bloodmisc, ns_strifevoices, + ns_hires, } namespace_t; // [RH] Copy an 8-char string and uppercase it. @@ -90,14 +91,26 @@ class FWadLump : public FileReader public: FWadLump (); FWadLump (const FWadLump ©); +#ifdef _DEBUG + FWadLump & operator= (const FWadLump ©); +#endif + ~FWadLump(); + + long Seek (long offset, int origin); + long Read (void *buffer, long len); private: FWadLump (const FileReader &reader, long length); FWadLump (FILE *file, long length); + FWadLump (char * data, long length, bool destroy); + + char * sourceData; + bool destroySource; friend class FWadCollection; }; + // A lump in memory. The destructor automatically deletes the memory // the lump was copied to. Note the copy contstructor is really more of // a transfer constructor. Once an FMemLump gets copied, the original @@ -129,12 +142,13 @@ class FWadCollection { public: FWadCollection (); + ~FWadCollection (); // The wadnum for the IWAD enum { IWAD_FILENUM = 1 }; void InitMultipleFiles (wadlist_t **filenames); - void AddFile (const char *filename); + void AddFile (const char *filename, const char * data=NULL,int length=-1); bool CheckIfWadLoaded (const char *name); const char *GetWadName (int wadnum) const; @@ -149,6 +163,11 @@ public: inline int CheckNumForName (const byte *name, int ns) { return CheckNumForName ((const char *)name, ns); } inline int GetNumForName (const byte *name) { return GetNumForName ((const char *)name); } + int CheckNumForFullName (const char *name); + int CheckNumForFullName (const char *name, int wadfile); + int GetNumForFullName (const char *name); + + void ReadLump (int lump, void *dest); FMemLump ReadLump (int lump); FMemLump ReadLump (const char *name) { return ReadLump (GetNumForName (name)); } @@ -170,6 +189,8 @@ public: bool CheckLumpName (int lump, const char *name) const; // [RH] Returns true if the names match bool IsUncompressedFile(int lump) const; + + int GetNumLumps () const; protected: @@ -179,6 +200,10 @@ protected: WORD *FirstLumpIndex; // [RH] Hashing stuff moved out of lumpinfo structure WORD *NextLumpIndex; + WORD *FirstLumpIndex_FullName; // The same information for fully qualified paths from .zips + WORD *NextLumpIndex_FullName; + + LumpRecord *LumpInfo; WadFileRecord **Wads; DWORD NumLumps; @@ -193,6 +218,7 @@ protected: void FindStrifeTeaserVoices (); private: + static int STACK_ARGS lumpcmp(const void * a, const void * b); void ScanForFlatHack (int startlump); void RenameSprites (int startlump); }; diff --git a/src/w_zip.h b/src/w_zip.h new file mode 100644 index 000000000..647e7e8f8 --- /dev/null +++ b/src/w_zip.h @@ -0,0 +1,64 @@ +#ifndef __W_ZIP +#define __W_ZIP + +#pragma pack(1) +struct FZipCentralInfo +{ + // patched together from information from Q3's unzip.c + DWORD dwSignature; + WORD wNumberDisk; + WORD wNumberDiskWithCD; + WORD wEntryCount; + WORD wTotalEntryCount; + DWORD dwCDSize; + DWORD dwCDOffset; + WORD wCommentSize; +}; + +struct FZipFileInfo +{ + // patched together from information from Q3's unzip.c + DWORD dwSignature; + WORD wVersion; + WORD wRequiredVersion; + WORD wFlags; + WORD wCompression; + DWORD dwLastModified; + DWORD dwCrc; + DWORD dwCompressedSize; + DWORD dwSize; + WORD wFileNameSize; + WORD wExtraSize; + WORD wCommentSize; + WORD wDiskStart; + WORD wInternalAttributes; + DWORD wExternalAttributes; + DWORD dwFileOffset; + // file name and other variable length info follows +}; + +struct FZipLocalHeader +{ + // patched together from information from Q3's unzip.c + DWORD dwSignature; + WORD wRequiredVersion; + WORD wFlags; + WORD wCompression; + DWORD dwLastModified; + DWORD dwCrc; + DWORD dwCompressedSize; + DWORD dwSize; + WORD wFileNameSize; + WORD wExtraSize; + // file name and other variable length info follows +}; + + +#pragma pack() + +#define Z_DEFLATED 8 + +// File header flags. +#define ZF_ENCRYPTED 0x1 + +#endif \ No newline at end of file diff --git a/zdoom.vcproj b/zdoom.vcproj index e9258d6f1..48168fc18 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -2086,6 +2086,9 @@ + +