diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index f69b35030..ccf90b616 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -819,6 +819,7 @@ set (PCH_SOURCES common/utility/memarena.cpp common/utility/sc_man.cpp + common/filesystem/filesystem.cpp common/filesystem/ancientzip.cpp common/filesystem/file_zip.cpp common/filesystem/file_7z.cpp diff --git a/source/common/filesystem/file_lump.cpp b/source/common/filesystem/file_lump.cpp index dcb2adea5..e33bb96e0 100644 --- a/source/common/filesystem/file_lump.cpp +++ b/source/common/filesystem/file_lump.cpp @@ -74,8 +74,11 @@ bool FLumpFile::Open(bool quiet) Lumps[0].LumpSize = (int)Reader.GetLength(); Lumps[0].Flags = 0; Lumps[0].FullName = FileName; - Lumps[0].BaseName = ExtractFileBase(FileName); + auto p = FileName.LastIndexOf('/'); + Lumps[0].PathLen = FileName.LastIndexOf('/') + 1; + Lumps[0].ExtStart = FileName.LastIndexOf('.'); NumLumps = 1; + if (Lumps[0].ExtStart < Lumps[0].PathLen) Lumps[0].ExtStart = -1; /* if (!quiet) { diff --git a/source/common/filesystem/file_rff.cpp b/source/common/filesystem/file_rff.cpp index a33f4b25f..035ddfda6 100644 --- a/source/common/filesystem/file_rff.cpp +++ b/source/common/filesystem/file_rff.cpp @@ -104,11 +104,10 @@ void BloodCrypt (void *data, int key, int len) class FRFFFile : public FResourceFile { - FRFFLump *Lumps; + TArray Lumps; public: FRFFFile(const char * filename, FileReader &file); - virtual ~FRFFFile(); virtual bool Open(bool quiet); virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } }; @@ -123,7 +122,6 @@ public: FRFFFile::FRFFFile(const char *filename, FileReader &file) : FResourceFile(filename, file) { - Lumps = NULL; } //========================================================================== @@ -146,19 +144,22 @@ bool FRFFFile::Open(bool quiet) Reader.Read (lumps, header.NumLumps * sizeof(RFFLump)); BloodCrypt (lumps, header.DirOfs, header.NumLumps * sizeof(RFFLump)); - Lumps = new FRFFLump[NumLumps]; + Lumps.Grow(NumLumps); //if (!quiet) Printf(", %d lumps\n", NumLumps); for (uint32_t i = 0; i < NumLumps; ++i) { - Lumps[i].Position = LittleLong(lumps[i].FilePos); - Lumps[i].LumpSize = LittleLong(lumps[i].Size); - Lumps[i].Owner = this; + Lumps.Reserve(1); + auto& Lump = Lumps.Last(); + + Lump.Position = LittleLong(lumps[i].FilePos); + Lump.LumpSize = LittleLong(lumps[i].Size); + Lump.Owner = this; if (lumps[i].Flags & 0x10) { - Lumps[i].Flags |= LUMPF_BLOODCRYPT; + Lump.Flags |= LUMPF_BLOODCRYPT; } - Lumps[i].IndexNum = LittleLong(lumps[i].IndexNum); + Lump.IndexNum = LittleLong(lumps[i].IndexNum); // Rearrange the name and extension to construct the fullname. char name[13]; strncpy(name, lumps[i].Name, 8); @@ -170,20 +171,20 @@ bool FRFFFile::Open(bool quiet) name[len+2] = lumps[i].Extension[1]; name[len+3] = lumps[i].Extension[2]; name[len+4] = 0; - Lumps[i].LumpNameSetup(name); + Lump.LumpNameSetup(name); + if (Lump.IndexNum > 0) + { + // Create a second entry for looking up by index. + Lumps.Reserve(1); + auto& l = Lumps.Last(); + l = Lumps[Lumps.Size() - 2]; + snprintf(name, 13, "{%d}.%c%c%c", l.IndexNum, lumps[i].Extension[0], lumps[i].Extension[1], lumps[i].Extension[2]); + } } delete[] lumps; return true; } -FRFFFile::~FRFFFile() -{ - if (Lumps != NULL) - { - delete[] Lumps; - } -} - //========================================================================== // diff --git a/source/common/filesystem/filesystem.cpp b/source/common/filesystem/filesystem.cpp new file mode 100644 index 000000000..30ecfcd5f --- /dev/null +++ b/source/common/filesystem/filesystem.cpp @@ -0,0 +1,919 @@ +/* +** filesystem.cpp +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** Copyright 2005-2019 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. +**--------------------------------------------------------------------------- +** +** +*/ + + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include + +#include "m_argv.h" +#include "cmdlib.h" +#include "printf.h" +//#include "c_dispatch.h" +#include "filesystem.h" +#include "superfasthash.h" +#include "resourcefile.h" +//#include "md5.h" +//#include "doomstat.h" + +// MACROS ------------------------------------------------------------------ + +#define NULL_INDEX (0xffffffff) + +struct FileSystem::FileRecord +{ + int rfnum; + FResourceLump *lump; +}; + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static void PrintLastError (); + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +FileSystem Files; + +// CODE -------------------------------------------------------------------- + + +FileSystem::~FileSystem () +{ + DeleteAll(); +} + +void FileSystem::DeleteAll () +{ + FileInfo.Clear(); + NumEntries = 0; + + for (int i = Files.Size() - 1; i >= 0; --i) + { + delete Files[i]; + } + Files.Clear(); +} + +//========================================================================== +// +// InitMultipleFiles +// +// Pass a null terminated list of files to use. All files are optional, +// but at least one file must be found. Lump names can appear multiple +// times. The name searcher looks backwards, so a later file can +// override an earlier one. +// +//========================================================================== + +int FileSystem::InitMultipleFiles (TArray &filenames, const TArray &deletelumps) +{ + int numfiles; + + // open all the files, load headers, and count lumps + DeleteAll(); + numfiles = 0; + + for(unsigned i=0;iSetFirstLump(lumpstart); + for (uint32_t i=0; i < resfile->LumpCount(); i++) + { + FResourceLump *lump = resfile->GetLump(i); + FileSystem::FileRecord *lump_p = &FileInfo[FileInfo.Reserve(1)]; + + lump_p->lump = lump; + lump_p->rfnum = Files.Size(); + } + + Files.Push(resfile); + } +} + +//========================================================================== +// +// GetFileRecordCheckIfWadLoaded +// +// Returns true if the specified wad is loaded, false otherwise. +// If a fully-qualified path is specified, then the wad must match exactly. +// Otherwise, any wad with that name will work, whatever its path. +// Returns the wads index if found, or -1 if not. +// +//========================================================================== + +int FileSystem::CheckIfResourceFileLoaded (const char *name) noexcept +{ + unsigned int i; + + if (strrchr (name, '/') != NULL) + { + for (i = 0; i < Files.Size(); ++i) + { + if (stricmp (GetResourceFileFullName (i), name) == 0) + { + return i; + } + } + } + else + { + for (i = 0; i < Files.Size(); ++i) + { + if (stricmp (GetResourceFileName (i), name) == 0) + { + return i; + } + } + } + return -1; +} + +//========================================================================== +// +// GetFileRecordFindFile +// +// 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 FileSystem::FindFile (const char *name, ELookupMode lookupmode, int filenum) const noexcept +{ + uint32_t i; + + if (name == NULL) + { + return -1; + } + uint32_t* fli; + uint32_t* nli; + + switch (lookupmode) + { + case ELookupMode::FullName: + fli = FirstFileIndex_FullName; + nli = NextFileIndex_FullName; + break; + + case ELookupMode::NoExtension: + fli = FirstFileIndex_NoExt; + nli = NextFileIndex_NoExt; + break; + + case ELookupMode::BaseName: + fli = FirstFileIndex_BaseName; + nli = NextFileIndex_BaseName; + break; + + case ELookupMode::BaseWithExtension: + fli = FirstFileIndex_BaseExt; + nli = NextFileIndex_BaseExt; + break; + + } + auto len = strlen(name); + + for (i = fli[MakeKey(name) % NumEntries]; i != NULL_INDEX; i = nli[i]) + { + auto lump = FileInfo[i].lump; + if (FileInfo[i].rfnum != filenum) continue; + const char* fn = lump->FullName.GetChars(); + const char* fnstart, * fnend; + if (lookupmode == ELookupMode::BaseName || lookupmode == ELookupMode::BaseWithExtension) fnstart = fn + lump->PathLen; + else fnstart = fn; + + if ((lookupmode == ELookupMode::NoExtension || lookupmode == ELookupMode::BaseName) && lump->ExtStart >= 0) fnend = fn + lump->ExtStart; + else fnend = fn + lump->FullName.Len(); + + if ((fnend - fnstart) == (ptrdiff_t)len) + { + if (!strnicmp(name, fnstart, len)) + { + return i; + } + } + } + return -1; +} + +//========================================================================== +// +// GetFileRecordGetFile +// +// Calls GetFileRecordFindFile, but bombs out if not found. +// +//========================================================================== + +int FileSystem::GetFile (const char *name, ELookupMode lookupmode, int filenum) const +{ + int i; + + i = FindFile (name, lookupmode, filenum); + + if (i == -1) + { + FStringf error("GetFile: %s not found!", name); + throw FileSystemError(error.GetChars()); + } + return i; +} + +//========================================================================== +// +// GetFileRecordLumpLength +// +// Returns the buffer size needed to load the given lump. +// +//========================================================================== + +int FileSystem::FileLength (int lump) const +{ + if ((size_t)lump >= NumEntries) + { + return -1; + } + return FileInfo[lump].lump->LumpSize; +} + +//========================================================================== +// +// 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 +// +//========================================================================== + +int FileSystem::GetFileOffset (int lump) +{ + if ((size_t)lump >= NumEntries) + { + return -1; + } + return FileInfo[lump].lump->GetFileOffset(); +} + +//========================================================================== +// +// GetLumpOffset +// +//========================================================================== + +int FileSystem::GetFileFlags (int lump) +{ + if ((size_t)lump >= NumEntries) + { + return 0; + } + + return FileInfo[lump].lump->Flags; +} + +//========================================================================== +// +// GetFileRecordInitHashChains +// +// Prepares the lumpinfos for hashing. +// (Hey! This looks suspiciously like something from Boom! :-) +// +//========================================================================== + +void FileSystem::InitHashChains (void) +{ + char name[8]; + unsigned int i, j; + + // Mark all buckets as empty + memset(FirstFileIndex_BaseExt, 255, NumEntries * sizeof(FirstFileIndex_BaseExt[0])); + memset(NextFileIndex_BaseExt, 255, NumEntries * sizeof(NextFileIndex_BaseExt[0])); + memset (FirstFileIndex_BaseName, 255, NumEntries*sizeof(FirstFileIndex_BaseName[0])); + memset (NextFileIndex_BaseName, 255, NumEntries*sizeof(NextFileIndex_BaseName[0])); + memset (FirstFileIndex_FullName, 255, NumEntries*sizeof(FirstFileIndex_FullName[0])); + memset (NextFileIndex_FullName, 255, NumEntries*sizeof(NextFileIndex_FullName[0])); + memset(FirstFileIndex_NoExt, 255, NumEntries * sizeof(FirstFileIndex_NoExt[0])); + memset(NextFileIndex_NoExt, 255, NumEntries * sizeof(NextFileIndex_NoExt[0])); + + // Now set up the chains + for (i = 0; i < (unsigned)NumEntries; i++) + { + + // Do the same for the full paths + auto lump = FileInfo[i].lump; + auto& Name = lump->FullName; + if (Name.IsNotEmpty()) + { + j = MakeKey(Name) % NumEntries; + NextFileIndex_FullName[i] = FirstFileIndex_FullName[j]; + FirstFileIndex_FullName[j] = i; + + j = MakeKey(Name + lump->PathLen) % NumEntries; + NextFileIndex_BaseExt[i] = FirstFileIndex_BaseExt[j]; + FirstFileIndex_BaseExt[j] = i; + + j = MakeKey(Name, lump->ExtStart) % NumEntries; + NextFileIndex_NoExt[i] = FirstFileIndex_NoExt[j]; + FirstFileIndex_NoExt[j] = i; + + if (lump->ExtStart > lump->PathLen) + { + j = MakeKey(Name, lump->ExtStart) % NumEntries; + NextFileIndex_NoExt[i] = FirstFileIndex_NoExt[j]; + FirstFileIndex_NoExt[j] = i; + + j = MakeKey(Name + lump->PathLen, lump->ExtStart - lump->PathLen) % NumEntries; + NextFileIndex_BaseName[i] = FirstFileIndex_BaseName[j]; + FirstFileIndex_BaseName[j] = i; + } + else + { + NextFileIndex_NoExt[i] = NextFileIndex_FullName[i]; + FirstFileIndex_NoExt[i] = FirstFileIndex_FullName[i]; + + NextFileIndex_BaseName[i] = NextFileIndex_BaseExt[i]; + FirstFileIndex_BaseName[j] = FirstFileIndex_BaseExt[i]; + } + + FString nameNoExt = Name; + auto dot = nameNoExt.LastIndexOf('.'); + auto slash = nameNoExt.LastIndexOf('/'); + if (dot > slash) nameNoExt.Truncate(dot); + + j = MakeKey(nameNoExt) % NumEntries; + NextFileIndex_NoExt[i] = FirstFileIndex_NoExt[j]; + FirstFileIndex_NoExt[j] = i; + + } + } +} + + +//========================================================================== +// +// Iterate +// +// Find a named lump. Specifically allows duplicates for merging of e.g. +// SNDINFO lumps. +// +//========================================================================== + +int FileSystem::Iterate (const char *name, int *lastlump, ELookupMode lookupmode) +{ + union + { + char name8[8]; + uint64_t qname; + }; + FileRecord *lump_p; + + + assert(lastlump != NULL && *lastlump >= 0); + lump_p = &FileInfo[*lastlump]; + auto len = strlen(name); + while (lump_p < &FileInfo[NumEntries]) + { + auto lump = lump_p->lump; + const char* fn = lump->FullName.GetChars(); + const char* fnstart, * fnend; + if (lookupmode == ELookupMode::BaseName || lookupmode == ELookupMode::BaseWithExtension) fnstart = fn + lump->PathLen; + else fnstart = fn; + + if ((lookupmode == ELookupMode::NoExtension || lookupmode == ELookupMode::BaseName) && lump->ExtStart >= 0) fnend = fn + lump->ExtStart; + else fnend = fn + lump->FullName.Len(); + + if ((fnend - fnstart) == (ptrdiff_t)len) + { + if (!strnicmp(name, fnstart, len)) + { + int lump = int(lump_p - &FileInfo[0]); + *lastlump = lump + 1; + return lump; + } + } + lump_p++; + } + *lastlump = NumEntries; + return -1; +} + +//========================================================================== +// +// GetFileRecordGetLumpName +// +//========================================================================== + +const char *FileSystem::GetFileName (int lump) const +{ + if ((size_t)lump >= NumEntries) + return nullptr; + else + return FileInfo[lump].lump->FullName; +} + +//========================================================================== +// +// FileSystem :: GetLumpFullPath +// +// Returns the name of the lump's wad prefixed to the lump's full name. +// +//========================================================================== + +FString FileSystem::GetFileFullPath(int lump) const +{ + FString foo; + + if ((size_t) lump < NumEntries) + { + foo << GetResourceFileName(FileInfo[lump].rfnum) << ':' << GetFileName(lump); + } + return foo; +} + +//========================================================================== +// +// FileSystem :: GetFileIndexNum +// +// Returns the index number for this lump. This is *not* the lump's position +// in the lump directory, but rather a special value that RFF can associate +// with files. Other archive types will return 0, since they don't have it. +// +//========================================================================== + +int FileSystem::GetRFFIndexNum(int lump) const +{ + if ((size_t)lump >= NumEntries) + return 0; + else + return FileInfo[lump].lump->GetIndexNum(); +} + +//========================================================================== +// +// GetFileRecordGetLumpFile +// +//========================================================================== + +int FileSystem::GetFileContainer (int lump) const +{ + if ((size_t)lump >= FileInfo.Size()) + return -1; + return FileInfo[lump].rfnum; +} + +//========================================================================== +// +// GetLumpsInFolder +// +// Gets all lumps within a single folder in the hierarchy. +// If 'atomic' is set, it treats folders as atomic, i.e. only the +// content of the last found resource file having the given folder name gets used. +// +//========================================================================== + +static int folderentrycmp(const void *a, const void *b) +{ + auto A = (FolderEntry*)a; + auto B = (FolderEntry*)b; + return strcmp(A->name, B->name); +} + +//========================================================================== +// +// +// +//========================================================================== + +unsigned FileSystem::GetFilesInFolder(const char *inpath, TArray &result, bool atomic) const +{ + FString path = inpath; + path.Substitute("\\", "/"); + path.ToLower(); + if (path[path.Len() - 1] != '/') path += '/'; + result.Clear(); + for (unsigned i = 0; i < FileInfo.Size(); i++) + { + if (FileInfo[i].lump->FullName.IndexOf(path) == 0) + { + // Only if it hasn't been replaced. + if ((unsigned)FindFile(FileInfo[i].lump->FullName) == i) + { + result.Push({ FileInfo[i].lump->FullName.GetChars(), i }); + } + } + } + if (result.Size()) + { + int maxfile = -1; + if (atomic) + { + // Find the highest resource file having content in the given folder. + for (auto & entry : result) + { + int thisfile = FileInfo[entry.lumpnum].rfnum; + if (thisfile > maxfile) maxfile = thisfile; + } + // Delete everything from older files. + for (int i = result.Size() - 1; i >= 0; i--) + { + if (FileInfo[result[i].lumpnum].rfnum != maxfile) result.Delete(i); + } + } + qsort(result.Data(), result.Size(), sizeof(FolderEntry), folderentrycmp); + } + return result.Size(); +} + + +//========================================================================== +// +// GetFileRecordReadFile +// +// Loads the lump into a TArray and returns it. +// +//========================================================================== + +TArray FileSystem::GetFileData(int lump, int pad) +{ + auto lumpr = OpenFileReader(lump); + auto size = lumpr.GetLength(); + TArray data(size + pad, true); + auto numread = lumpr.Read(data.Data(), size); + + if (numread != size) + { + FStringf err("GetFileRecordReadFile: only read %ld of %ld on lump %i\n", numread, size, lump); + throw FileSystemError(err); + } + if (pad > 0) memset(&data[size], 0, pad); + return data; +} + +//========================================================================== +// +// ReadFile - variant 2 +// +// Loads the lump into a newly created buffer and returns it. +// +//========================================================================== + +FileData FileSystem::ReadFile (int lump) +{ + return FileData(FString(ELumpNum(lump))); +} + +//========================================================================== +// +// OpenLumpReader +// +// uses a more abstract interface to allow for easier low level optimization later +// +//========================================================================== + + +FileReader FileSystem::OpenFileReader(int lump) +{ + if ((unsigned)lump >= (unsigned)FileInfo.Size()) + { + FStringf err("OpenFileReader: %u >= NumEntries", lump); + throw FileSystemError(err); + } + + auto rl = FileInfo[lump].lump; + auto rd = rl->GetReader(); + + if (rl->RefCount == 0 && rd != nullptr && !rd->GetBuffer() && !(rl->Flags & (LUMPF_BLOODCRYPT | LUMPF_COMPRESSED))) + { + FileReader rdr; + rdr.OpenFilePart(*rd, rl->GetFileOffset(), rl->LumpSize); + return rdr; + } + return rl->NewReader(); // This always gets a reader to the cache +} + +FileReader FileSystem::ReopenFileReader(int lump, bool alwayscache) +{ + if ((unsigned)lump >= (unsigned)FileInfo.Size()) + { + FStringf err("ReopenFileReader: %u >= NumEntries", lump); + throw FileSystemError(err); + } + + auto rl = FileInfo[lump].lump; + auto rd = rl->GetReader(); + + if (rl->RefCount == 0 && rd != nullptr && !rd->GetBuffer() && !alwayscache && !(rl->Flags & (LUMPF_BLOODCRYPT|LUMPF_COMPRESSED))) + { + int fileno = FileInfo[lump].rfnum; + const char *filename = GetResourceFileFullName(fileno); + FileReader fr; + if (fr.OpenFile(filename, rl->GetFileOffset(), rl->LumpSize)) + { + return fr; + } + } + return rl->NewReader(); // This always gets a reader to the cache +} + +//========================================================================== +// +// GetFileRecordGetResourceFileName +// +// Returns the name of the given wad. +// +//========================================================================== + +const char *FileSystem::GetResourceFileName (int rfnum) const noexcept +{ + const char *name, *slash; + + if ((uint32_t)rfnum >= Files.Size()) + { + return NULL; + } + + name = Files[rfnum]->FileName; + slash = strrchr (name, '/'); + return slash != NULL ? slash+1 : name; +} + +//========================================================================== +// +// +//========================================================================== + +int FileSystem::GetFirstEntry (int rfnum) const noexcept +{ + if ((uint32_t)rfnum >= Files.Size()) + { + return 0; + } + + return Files[rfnum]->GetFirstLump(); +} + +//========================================================================== +// +// +//========================================================================== + +int FileSystem::GetLastEntry (int rfnum) const noexcept +{ + if ((uint32_t)rfnum >= Files.Size()) + { + return 0; + } + + return Files[rfnum]->GetFirstLump() + Files[rfnum]->LumpCount() - 1; +} + +//========================================================================== +// +// +//========================================================================== + +int FileSystem::GetEntryCount (int rfnum) const noexcept +{ + if ((uint32_t)rfnum >= Files.Size()) + { + return 0; + } + + return Files[rfnum]->LumpCount(); +} + + +//========================================================================== +// +// GetFileRecordGetResourceFileFullName +// +// Returns the name of the given wad, including any path +// +//========================================================================== + +const char *FileSystem::GetResourceFileFullName (int rfnum) const noexcept +{ + if ((unsigned int)rfnum >= Files.Size()) + { + return nullptr; + } + + return Files[rfnum]->FileName; +} + + +//========================================================================== +// +// IsEncryptedFile +// +// Returns true if the first 256 bytes of the lump are encrypted for Blood. +// +//========================================================================== + +bool FileSystem::IsEncryptedFile(int lump) const noexcept +{ + if ((unsigned)lump >= (unsigned)NumEntries) + { + return false; + } + return !!(FileInfo[lump].lump->Flags & LUMPF_BLOODCRYPT); +} + + +// FileData ----------------------------------------------------------------- + +FileData::FileData () +{ +} + +FileData::FileData (const FileData ©) +{ + Block = copy.Block; +} + +FileData &FileData::operator = (const FileData ©) +{ + Block = copy.Block; + return *this; +} + +FileData::FileData (const FString &source) +: Block (source) +{ +} + +FileData::~FileData () +{ +} + +FString::FString (ELumpNum lumpnum) +{ + auto lumpr = Files.OpenFileReader ((int)lumpnum); + auto size = lumpr.GetLength (); + AllocBuffer (1 + size); + auto numread = lumpr.Read (&Chars[0], size); + Chars[size] = '\0'; + + if (numread != size) + { + FStringf err("ConstructStringFromLump: Only read %ld of %ld bytes on lump %i (%s)\n", + numread, size, lumpnum, Files.GetFileName((int)lumpnum)); + } +} + +//========================================================================== +// +// PrintLastError +// +//========================================================================== + +#ifdef _WIN32 +//#define WIN32_LEAN_AND_MEAN +//#include + +#if 0 +extern "C" { +__declspec(dllimport) unsigned long __stdcall FormatMessageA( + unsigned long dwFlags, + const void *lpSource, + unsigned long dwMessageId, + unsigned long dwLanguageId, + char **lpBuffer, + unsigned long nSize, + va_list *Arguments + ); +__declspec(dllimport) void * __stdcall LocalFree (void *); +__declspec(dllimport) unsigned long __stdcall GetLastError (); +} +#endif + +static void PrintLastError () +{ + char *lpMsgBuf; + FormatMessageA(0x1300 /*FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS*/, + NULL, + GetLastError(), + 1 << 10 /*MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)*/, // Default language + (LPSTR)&lpMsgBuf, + 0, + NULL + ); + Printf (TEXTCOLOR_RED " %s\n", lpMsgBuf); + // Free the buffer. + LocalFree( lpMsgBuf ); +} +#else +static void PrintLastError () +{ + Printf (TEXTCOLOR_RED " %s\n", strerror(errno)); +} +#endif + diff --git a/source/common/filesystem/filesystem.h b/source/common/filesystem/filesystem.h new file mode 100644 index 000000000..fc4674b4e --- /dev/null +++ b/source/common/filesystem/filesystem.h @@ -0,0 +1,142 @@ +#pragma once +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// File system I/O functions. +// +//----------------------------------------------------------------------------- + + +#include +#include "files.h" +#include "tarray.h" +#include "zstring.h" + +// We do not want to expose the resource file interface here. +class FResourceFile; +struct FResourceLump; + +class FileSystemError : std::runtime_error +{ +public: + FileSystemError(const char* err) : std::runtime_error(err) {} +}; + +// A file in memory. +class FileData +{ +public: + FileData (); + + FileData (const FileData ©); + FileData &operator= (const FileData ©); + ~FileData (); + void *GetMem () { return Block.Len() == 0 ? NULL : (void *)Block.GetChars(); } + size_t GetSize () { return Block.Len(); } + FString GetString () { return Block; } + +private: + FileData (const FString &source); + + FString Block; + + friend class FileSystem; +}; + +struct FolderEntry +{ + const char *name; + unsigned lumpnum; +}; + +enum class ELookupMode +{ + FullName = 0, + NoExtension = 1, + BaseName = 2, + BaseWithExtension = 3 +}; + +class FileSystem +{ +public: + FileSystem () = default; + ~FileSystem (); + + int InitMultipleFiles (TArray &filenames, const TArray &todelete); + void AddFile (const char *filename, FileReader *wadinfo = NULL); + int CheckIfResourceFileLoaded (const char *name) noexcept; + + const char *GetResourceFileName (int filenum) const noexcept; + const char *GetResourceFileFullName (int filenum) const noexcept; + + int GetFirstEntry(int filenum) const noexcept; + int GetLastEntry(int filenum) const noexcept; + int GetEntryCount(int filenum) const noexcept; + + int FindFile (const char *name, ELookupMode lookupmode = ELookupMode::FullName, int filenum = -1) const noexcept; + int GetFile (const char *name, ELookupMode lookupmode = ELookupMode::FullName, int filenum = -1) const; // Like FindFile, but throws an exception when it cannot find what it looks for. + + int FindFile (const FString &name, ELookupMode lookupmode = ELookupMode::FullName, int filenum = -1) const noexcept { return FindFile(name.GetChars(), lookupmode, filenum); } + int GetFile (const FString &name, ELookupMode lookupmode = ELookupMode::FullName, int filenum = -1) const { return GetFile(name.GetChars(), lookupmode, filenum); } + + int FindFile (const std::string &name, ELookupMode lookupmode = ELookupMode::FullName, int filenum = -1) const noexcept { return FindFile(name.c_str(), lookupmode, filenum); } + int GetFile (const std::string &name, ELookupMode lookupmode = ELookupMode::FullName, int filenum = -1) const { return GetFile(name.c_str(), lookupmode, filenum); } + + TArray GetFileData(int file, int pad = 0); // reads file into a writable buffer and optionally adds some padding at the end. (FileData isn't writable!) + FileData ReadFile (int file); + FileData ReadFile (const char *name) { return ReadFile (GetFile (name)); } + + FileReader OpenFileReader(int file); // opens a reader that redirects to the containing file's one. + FileReader ReopenFileReader(int file, bool alwayscache = false); // opens an independent reader. + + int Iterate (const char *name, int *lastfile, ELookupMode lookupmode = ELookupMode::FullName); // [RH] Find files with duplication + + static uint32_t FileNameHash (const char *name); // [RH] Create hash key from a given name + + int FileLength (int file) const; + int GetFileOffset (int file); // [RH] Returns offset of file in the wadfile + int GetFileFlags (int file); // Return the flags for this file + void GetFileName (char *to, int file) const; // [RH] Copies the file name to to using uppercopy + const char *GetFileName (int file) const; + FString GetFileFullPath (int file) const; // [RH] Returns wad's name + file's full name + int GetFileContainer (int file) const; // [RH] Returns filenum for a specified file + int GetRFFIndexNum (int file) const; // Returns the RFF index number for this file + unsigned GetFilesInFolder(const char *path, TArray &result, bool atomic) const; + + bool IsEncryptedFile(int file) const noexcept; + + int GetNumResourceFiles() const { return NumFiles; } + int GetNumEntries () const { return NumEntries; } + +protected: + + struct FileRecord; + + TArray Files; + TArray FileInfo; + + TArray Hashes; // one allocation for all hash lists. + uint32_t *FirstFileIndex_BaseName; // Hash information for the base name (no path and no extension) + uint32_t *NextFileIndex_BaseName; + + uint32_t* FirstFileIndex_BaseExt; // Hash information for the base name (no path and no extension) + uint32_t* NextFileIndex_BaseExt; + + uint32_t *FirstFileIndex_FullName; // The same information for fully qualified paths + uint32_t *NextFileIndex_FullName; + + uint32_t *FirstFileIndex_NoExt; // The same information for fully qualified paths but without the extension + uint32_t *NextFileIndex_NoExt; + + uint32_t NumFiles = 0; // Not necessarily the same as FileInfo.Size() + uint32_t NumEntries; + + void InitHashChains (); // [RH] Set up the lumpinfo hashing + +private: + void DeleteAll(); +}; + +extern FileSystem Files; + diff --git a/source/common/filesystem/resourcefile.cpp b/source/common/filesystem/resourcefile.cpp index 957a077f9..468383e3a 100644 --- a/source/common/filesystem/resourcefile.cpp +++ b/source/common/filesystem/resourcefile.cpp @@ -84,11 +84,9 @@ FResourceLump::~FResourceLump() void FResourceLump::LumpNameSetup(FString iname) { - long slash = iname.LastIndexOf('/'); - FString base = (slash >= 0) ? iname.Mid(slash + 1) : iname; - auto dot = base.LastIndexOf('.'); - if (dot >= 0) base.Truncate(dot); - BaseName = base; + PathLen = iname.LastIndexOf('/') + 1; + ExtStart = iname.LastIndexOf('.'); + if (ExtStart <= PathLen) ExtStart = -1; FullName = iname; } @@ -373,7 +371,6 @@ void FResourceFile::JunkLeftoverFilters(void *lumps, size_t lumpsize, uint32_t m { FResourceLump *lump = (FResourceLump *)p; lump->FullName = ""; - lump->BaseName = ""; } } } diff --git a/source/common/filesystem/resourcefile.h b/source/common/filesystem/resourcefile.h index c1fd9b30f..19be3da91 100644 --- a/source/common/filesystem/resourcefile.h +++ b/source/common/filesystem/resourcefile.h @@ -49,8 +49,9 @@ struct FResourceLump int LumpSize = 0; int RefCount = 0; int Flags = 0; + int PathLen = 0; + int ExtStart = -1; FString FullName; // Name with extension and path - FString BaseName; // Name without extension and path FResourceFile * Owner = nullptr; TArray Cache; diff --git a/source/common/resourcefiles/file_zip.cpp b/source/common/resourcefiles/file_zip.cpp deleted file mode 100644 index 12586c026..000000000 --- a/source/common/resourcefiles/file_zip.cpp +++ /dev/null @@ -1,653 +0,0 @@ -/* -** 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 -#include -#include "file_zip.h" -#include "cmdlib.h" -#include "basics.h" -#include "w_zip.h" - -#include "ancientzip.h" - -#define BUFREADCOMMENT (0x400) - -//========================================================================== -// -// Decompression subroutine -// -//========================================================================== - -static bool UncompressZipLump(char *Cache, FileReader &Reader, int Method, int LumpSize, int CompressedSize, int GPFlags) -{ - try - { - switch (Method) - { - case METHOD_STORED: - { - Reader.Read(Cache, LumpSize); - break; - } - - case METHOD_DEFLATE: - case METHOD_BZIP2: - case METHOD_LZMA: - { - FileReader frz; - if (frz.OpenDecompressor(Reader, LumpSize, Method, false, [](const char* err) { throw std::runtime_error(err); })) - { - frz.Read(Cache, LumpSize); - } - break; - } - - // Fixme: These should also use a stream - case METHOD_IMPLODE: - { - FZipExploder exploder; - exploder.Explode((unsigned char *)Cache, LumpSize, Reader, CompressedSize, GPFlags); - break; - } - - case METHOD_SHRINK: - { - ShrinkLoop((unsigned char *)Cache, LumpSize, Reader, CompressedSize); - break; - } - - default: - assert(0); - return false; - } - } - catch (const std::runtime_error &err) - { - Printf("%s\n", err.what()); - return false; - } - return true; -} - -bool FCompressedBuffer::Decompress(char *destbuffer) -{ - FileReader mr; - mr.OpenMemory(mBuffer, mCompressedSize); - return UncompressZipLump(destbuffer, mr, mMethod, mSize, mCompressedSize, mZipFlags); -} - -//----------------------------------------------------------------------- -// -// 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 uint32_t Zip_FindCentralDir(FileReader &fin) -{ - unsigned char buf[BUFREADCOMMENT + 4]; - uint32_t FileSize; - uint32_t uBackRead; - uint32_t uMaxBack; // maximum size of global comment - uint32_t uPosFound=0; - - FileSize = (uint32_t)fin.GetLength(); - uMaxBack = std::min(0xffff, FileSize); - - uBackRead = 4; - while (uBackRead < uMaxBack) - { - uint32_t uReadSize, uReadPos; - int i; - if (uBackRead + BUFREADCOMMENT > uMaxBack) - uBackRead = uMaxBack; - else - uBackRead += BUFREADCOMMENT; - uReadPos = FileSize - uBackRead; - - uReadSize = std::min((BUFREADCOMMENT + 4), (FileSize - uReadPos)); - - if (fin.Seek(uReadPos, FileReader::SeekSet) != 0) break; - - if (fin.Read(buf, (int32_t)uReadSize) != (int32_t)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; -} - -//========================================================================== -// -// Zip file -// -//========================================================================== - -FZipFile::FZipFile(const char * filename, FileReader &file) -: FResourceFile(filename, file) -{ - Lumps = NULL; -} - -bool FZipFile::Open(bool quiet) -{ - uint32_t centraldir = Zip_FindCentralDir(Reader); - FZipEndOfCentralDirectory info; - int skipped = 0; - - Lumps = NULL; - - if (centraldir == 0) - { - if (!quiet) Printf(TEXTCOLOR_RED "\n%s: ZIP file corrupt!\n", FileName.GetChars()); - return false; - } - - // Read the central directory info. - Reader.Seek(centraldir, FileReader::SeekSet); - Reader.Read(&info, sizeof(FZipEndOfCentralDirectory)); - - // No multi-disk zips! - if (info.NumEntries != info.NumEntriesOnAllDisks || - info.FirstDisk != 0 || info.DiskNumber != 0) - { - if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Multipart Zip files are not supported.\n", FileName.GetChars()); - return false; - } - - NumLumps = LittleShort(info.NumEntries); - Lumps = new FZipLump[NumLumps]; - - // Load the entire central directory. Too bad that this contains variable length entries... - int dirsize = LittleLong(info.DirectorySize); - void *directory = malloc(dirsize); - Reader.Seek(LittleLong(info.DirectoryOffset), FileReader::SeekSet); - Reader.Read(directory, dirsize); - - char *dirptr = (char*)directory; - FZipLump *lump_p = Lumps; - - FString name0; - bool foundspeciallump = false; - - // Check if all files have the same prefix so that this can be stripped out. - // This will only be done if there is either a MAPINFO, ZMAPINFO or GAMEINFO lump in the subdirectory, denoting a ZDoom mod. - if (NumLumps > 1) for (uint32_t i = 0; i < NumLumps; i++) - { - FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr; - - int len = LittleShort(zip_fh->NameLength); - FString name(dirptr + sizeof(FZipCentralDirectoryInfo), len); - - dirptr += sizeof(FZipCentralDirectoryInfo) + - LittleShort(zip_fh->NameLength) + - LittleShort(zip_fh->ExtraLength) + - LittleShort(zip_fh->CommentLength); - - if (dirptr > ((char*)directory) + dirsize) // This directory entry goes beyond the end of the file. - { - free(directory); - if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Central directory corrupted.", FileName.GetChars()); - return false; - } - - name.ToLower(); - if (i == 0) - { - // check for special names, if one of these gets found this must be treated as a normal zip. - bool isspecial = !name.Compare("flats/") || - name.IndexOf("/") < 0 || - !name.Compare("textures/") || - !name.Compare("hires/") || - !name.Compare("sprites/") || - !name.Compare("voxels/") || - !name.Compare("colormaps/") || - !name.Compare("acs/") || - !name.Compare("maps/") || - !name.Compare("voices/") || - !name.Compare("patches/") || - !name.Compare("graphics/") || - !name.Compare("sounds/") || - !name.Compare("music/"); - if (isspecial) break; - name0 = name; - } - else - { - if (name.IndexOf(name0) != 0) - { - name0 = ""; - break; - } - else if (!foundspeciallump) - { - // at least one of the more common definition lumps must be present. - if (name.IndexOf(name0 + "mapinfo") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "zmapinfo") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "gameinfo") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "sndinfo") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "sbarinfo") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "menudef") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "gldefs") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "animdefs") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "decorate.") == 0) foundspeciallump = true; // DECORATE is a common subdirectory name, so the check needs to be a bit different. - else if (name.Compare(name0 + "decorate") == 0) foundspeciallump = true; - else if (name.IndexOf(name0 + "zscript.") == 0) foundspeciallump = true; // same here. - else if (name.Compare(name0 + "zscript") == 0) foundspeciallump = true; - else if (name.Compare(name0 + "maps/") == 0) foundspeciallump = true; - } - } - } - // If it ran through the list without finding anything it should not attempt any path remapping. - if (!foundspeciallump) name0 = ""; - - dirptr = (char*)directory; - lump_p = Lumps; - for (uint32_t i = 0; i < NumLumps; i++) - { - FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr; - - int len = LittleShort(zip_fh->NameLength); - FString name(dirptr + sizeof(FZipCentralDirectoryInfo), len); - if (name0.IsNotEmpty()) name = name.Mid(name0.Len()); - dirptr += sizeof(FZipCentralDirectoryInfo) + - LittleShort(zip_fh->NameLength) + - LittleShort(zip_fh->ExtraLength) + - LittleShort(zip_fh->CommentLength); - - if (dirptr > ((char*)directory) + dirsize) // This directory entry goes beyond the end of the file. - { - free(directory); - if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Central directory corrupted.", FileName.GetChars()); - return false; - } - - // skip Directories - if (name.IsEmpty() || (name.Back() == '/' && 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 && - zip_fh->Method != METHOD_IMPLODE && - zip_fh->Method != METHOD_SHRINK) - { - if (!quiet) Printf(TEXTCOLOR_YELLOW "\n%s: '%s' uses an unsupported compression algorithm (#%d).\n", FileName.GetChars(), name.GetChars(), zip_fh->Method); - skipped++; - continue; - } - // Also ignore encrypted entries - zip_fh->Flags = LittleShort(zip_fh->Flags); - if (zip_fh->Flags & ZF_ENCRYPTED) - { - if (!quiet) Printf(TEXTCOLOR_YELLOW "\n%s: '%s' is encrypted. Encryption is not supported.\n", FileName.GetChars(), name.GetChars()); - skipped++; - continue; - } - - FixPathSeperator(name); - name.ToLower(); - - 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 = uint8_t(zip_fh->Method); - if (lump_p->Method != METHOD_STORED) lump_p->Flags |= LUMPF_COMPRESSED; - lump_p->GPFlags = zip_fh->Flags; - lump_p->CRC32 = zip_fh->CRC32; - lump_p->CompressedSize = LittleLong(zip_fh->CompressedSize); - lump_p->Position = LittleLong(zip_fh->LocalHeaderOffset); - - lump_p++; - } - // Resize the lump record array to its actual size - NumLumps -= skipped; - free(directory); - - if (!quiet) Printf(TEXTCOLOR_NORMAL ", %d lumps\n", NumLumps); - - PostProcessArchive(&Lumps[0], sizeof(FZipLump)); - return true; -} - -//========================================================================== -// -// Zip file -// -//========================================================================== - -FZipFile::~FZipFile() -{ - if (Lumps != NULL) delete [] Lumps; -} - -//========================================================================== -// -// -// -//========================================================================== - -FCompressedBuffer FZipLump::GetRawData() -{ - FCompressedBuffer cbuf = { (unsigned)LumpSize, (unsigned)CompressedSize, Method, GPFlags, CRC32, new char[CompressedSize] }; - if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); - Owner->Reader.Seek(Position, FileReader::SeekSet); - Owner->Reader.Read(cbuf.mBuffer, CompressedSize); - return cbuf; -} - -//========================================================================== -// -// 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; - - Owner->Reader.Seek(Position, FileReader::SeekSet); - Owner->Reader.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, FileReader::SeekSet); - return &Owner->Reader; - } - else return NULL; -} - -//========================================================================== -// -// Fills the lump cache and performs decompression -// -//========================================================================== - -int FZipLump::FillCache() -{ - if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); - - Owner->Reader.Seek(Position, FileReader::SeekSet); - Cache.Resize(LumpSize); - UncompressZipLump((char*)Cache.Data(), Owner->Reader, Method, LumpSize, CompressedSize, GPFlags); - RefCount = 1; - return 1; -} - -//========================================================================== -// -// -// -//========================================================================== - -int FZipLump::GetFileOffset() -{ - if (Method != METHOD_STORED) return -1; - if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); - return Position; -} - -//========================================================================== -// -// File open -// -//========================================================================== - -FResourceFile *CheckZip(const char *filename, FileReader &file, bool quiet) -{ - char head[4]; - - if (file.GetLength() >= (long)sizeof(FZipLocalFileHeader)) - { - file.Seek(0, FileReader::SeekSet); - file.Read(&head, 4); - file.Seek(0, FileReader::SeekSet); - if (!memcmp(head, "PK\x3\x4", 4)) - { - FResourceFile *rf = new FZipFile(filename, file); - if (rf->Open(quiet)) return rf; - - file = std::move(rf->Reader); // to avoid destruction of reader - delete rf; - } - } - return NULL; -} - - - -//========================================================================== -// -// time_to_dos -// -// Converts time from struct tm to the DOS format used by zip files. -// -//========================================================================== - -static std::pair time_to_dos(struct tm *time) -{ - std::pair val; - if (time == NULL || time->tm_year < 80) - { - val.first = val.second = 0; - } - else - { - val.first = (time->tm_year - 80) * 512 + (time->tm_mon + 1) * 32 + time->tm_mday; - val.second= time->tm_hour * 2048 + time->tm_min * 32 + time->tm_sec / 2; - } - return val; -} - -//========================================================================== -// -// append_to_zip -// -// Write a given file to the zipFile. -// -// zipfile: zip object to be written to -// -// returns: position = success, -1 = error -// -//========================================================================== - -int AppendToZip(FileWriter *zip_file, const char *filename, FCompressedBuffer &content, std::pair &dostime) -{ - FZipLocalFileHeader local; - int position; - - local.Magic = ZIP_LOCALFILE; - local.VersionToExtract[0] = 20; - local.VersionToExtract[1] = 0; - local.Flags = content.mMethod == METHOD_DEFLATE ? LittleShort((uint16_t)2) : LittleShort((uint16_t)content.mZipFlags); - local.Method = LittleShort((uint16_t)content.mMethod); - local.ModDate = LittleShort(dostime.first); - local.ModTime = LittleShort(dostime.second); - local.CRC32 = content.mCRC32; - local.UncompressedSize = LittleLong(content.mSize); - local.CompressedSize = LittleLong(content.mCompressedSize); - local.NameLength = LittleShort((unsigned short)strlen(filename)); - local.ExtraLength = 0; - - // Fill in local directory header. - - position = (int)zip_file->Tell(); - - // Write out the header, file name, and file data. - if (zip_file->Write(&local, sizeof(local)) != sizeof(local) || - zip_file->Write(filename, strlen(filename)) != strlen(filename) || - zip_file->Write(content.mBuffer, content.mCompressedSize) != content.mCompressedSize) - { - return -1; - } - return position; -} - - -//========================================================================== -// -// write_central_dir -// -// Writes the central directory entry for a file. -// -//========================================================================== - -int AppendCentralDirectory(FileWriter *zip_file, const char *filename, FCompressedBuffer &content, std::pair &dostime, int position) -{ - FZipCentralDirectoryInfo dir; - - dir.Magic = ZIP_CENTRALFILE; - dir.VersionMadeBy[0] = 20; - dir.VersionMadeBy[1] = 0; - dir.VersionToExtract[0] = 20; - dir.VersionToExtract[1] = 0; - dir.Flags = content.mMethod == METHOD_DEFLATE ? LittleShort((uint16_t)2) : LittleShort((uint16_t)content.mZipFlags); - dir.Method = LittleShort((uint16_t)content.mMethod); - dir.ModTime = LittleShort(dostime.first); - dir.ModDate = LittleShort(dostime.second); - dir.CRC32 = content.mCRC32; - dir.CompressedSize = LittleLong(content.mCompressedSize); - dir.UncompressedSize = LittleLong(content.mSize); - dir.NameLength = LittleShort((unsigned short)strlen(filename)); - dir.ExtraLength = 0; - dir.CommentLength = 0; - dir.StartingDiskNumber = 0; - dir.InternalAttributes = 0; - dir.ExternalAttributes = 0; - dir.LocalHeaderOffset = LittleLong(position); - - if (zip_file->Write(&dir, sizeof(dir)) != sizeof(dir) || - zip_file->Write(filename, strlen(filename)) != strlen(filename)) - { - return -1; - } - return 0; -} - -bool WriteZip(const char *filename, TArray &filenames, TArray &content) -{ - // try to determine local time - struct tm *ltime; - time_t ttime; - ttime = time(nullptr); - ltime = localtime(&ttime); - auto dostime = time_to_dos(ltime); - - TArray positions; - - if (filenames.Size() != content.Size()) return false; - - auto f = FileWriter::Open(filename); - if (f != nullptr) - { - for (unsigned i = 0; i < filenames.Size(); i++) - { - int pos = AppendToZip(f, filenames[i], content[i], dostime); - if (pos == -1) - { - delete f; - remove(filename); - return false; - } - positions.Push(pos); - } - - int dirofs = (int)f->Tell(); - for (unsigned i = 0; i < filenames.Size(); i++) - { - if (AppendCentralDirectory(f, filenames[i], content[i], dostime, positions[i]) < 0) - { - delete f; - remove(filename); - return false; - } - } - - // Write the directory terminator. - FZipEndOfCentralDirectory dirend; - dirend.Magic = ZIP_ENDOFDIR; - dirend.DiskNumber = 0; - dirend.FirstDisk = 0; - dirend.NumEntriesOnAllDisks = dirend.NumEntries = LittleShort((uint16_t)filenames.Size()); - dirend.DirectoryOffset = LittleLong(dirofs); - dirend.DirectorySize = LittleLong((uint32_t)(f->Tell() - dirofs)); - dirend.ZipCommentLength = 0; - if (f->Write(&dirend, sizeof(dirend)) != sizeof(dirend)) - { - delete f; - remove(filename); - return false; - } - delete f; - return true; - } - return false; -} diff --git a/source/common/resourcefiles/file_zip.h b/source/common/resourcefiles/file_zip.h deleted file mode 100644 index 466292e40..000000000 --- a/source/common/resourcefiles/file_zip.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef __FILE_ZIP_H -#define __FILE_ZIP_H - -#include "resourcefile.h" - -enum -{ - LUMPFZIP_NEEDFILESTART = 128 -}; - -//========================================================================== -// -// Zip Lump -// -//========================================================================== - -struct FZipLump : public FResourceLump -{ - uint16_t GPFlags; - uint8_t Method; - int CompressedSize; - int Position; - unsigned CRC32; - - virtual FileReader *GetReader(); - virtual int FillCache(); - -private: - void SetLumpAddress(); - virtual int GetFileOffset(); - FCompressedBuffer GetRawData(); -}; - - -//========================================================================== -// -// Zip file -// -//========================================================================== - -class FZipFile : public FResourceFile -{ - FZipLump *Lumps; - -public: - FZipFile(const char * filename, FileReader &file); - virtual ~FZipFile(); - bool Open(bool quiet); - virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } -}; - - -#endif \ No newline at end of file diff --git a/source/common/resourcefiles/resourcefile.cpp b/source/common/resourcefiles/resourcefile.cpp deleted file mode 100644 index 3d71b4577..000000000 --- a/source/common/resourcefiles/resourcefile.cpp +++ /dev/null @@ -1,602 +0,0 @@ -/* -** 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 -#include "resourcefile.h" -#include "cmdlib.h" -#include "basics.h" -#include "gametype.h" - - -//========================================================================== -// -// File reader 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 = (const char*)src->Cache.Data(); - } - - ~FLumpReader() - { - source->ReleaseCache(); - } -}; - - -//========================================================================== -// -// Base class for resource lumps -// -//========================================================================== - -FResourceLump::~FResourceLump() -{ - Owner = NULL; -} - - -//========================================================================== -// -// Sets up the lump name information for anything not coming from a WAD file. -// -//========================================================================== - -void FResourceLump::LumpNameSetup(FString iname) -{ - long slash = iname.LastIndexOf('/'); - FString base = (slash >= 0) ? iname.Mid(slash + 1) : iname; - auto dot = base.LastIndexOf('.'); - if (dot >= 0) base.Truncate(dot); - BaseName = base; - FullName = iname; -} - -//========================================================================== -// -// this is just for completeness. For non-Zips only an uncompressed lump can -// be returned. -// -//========================================================================== - -FCompressedBuffer FResourceLump::GetRawData() -{ - FCompressedBuffer cbuf = { (unsigned)LumpSize, (unsigned)LumpSize, METHOD_STORED, 0, 0, new char[LumpSize] }; - memcpy(cbuf.mBuffer, CacheLump(), LumpSize); - cbuf.mCRC32 = crc32(0, (uint8_t*)cbuf.mBuffer, LumpSize); - ReleaseCache(); - return cbuf; -} - - -//========================================================================== -// -// 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 FileReader(new FLumpReader(this)); -} - -//========================================================================== -// -// Caches a lump's content and increases the reference counter -// -//========================================================================== - -void *FResourceLump::CacheLump() -{ - if (Cache.Size()) - { - if (RefCount > 0) RefCount++; - } - else if (LumpSize > 0) - { - FillCache(); - } - return Cache.Data(); -} - -//========================================================================== -// -// Decrements reference counter and frees lump if counter reaches 0 -// -//========================================================================== - -int FResourceLump::ReleaseCache() -{ - if (LumpSize > 0 && RefCount > 0) - { - if (--RefCount == 0) - { - Cache.Reset(); - } - } - return RefCount; -} - -//========================================================================== -// -// Opens a resource file -// -//========================================================================== - -typedef FResourceFile * (*CheckFunc)(const char *filename, FileReader &file, bool quiet); - -FResourceFile *CheckWad(const char *filename, FileReader &file, bool quiet); -FResourceFile *CheckGRP(const char *filename, FileReader &file, bool quiet); -FResourceFile *CheckRFF(const char *filename, FileReader &file, bool quiet); -FResourceFile *CheckPak(const char *filename, FileReader &file, bool quiet); -FResourceFile *CheckZip(const char *filename, FileReader &file, bool quiet); -FResourceFile *Check7Z(const char *filename, FileReader &file, bool quiet); -FResourceFile *CheckLump(const char *filename,FileReader &file, bool quiet); -FResourceFile *CheckDir(const char *filename, bool quiet); - -static CheckFunc funcs[] = { CheckGRP, CheckRFF, CheckZip, Check7Z, CheckPak, CheckLump }; - -FResourceFile *FResourceFile::DoOpenResourceFile(const char *filename, FileReader &file, bool quiet, bool containeronly) -{ - for(size_t i = 0; i < countof(funcs) - containeronly; i++) - { - FResourceFile *resfile = funcs[i](filename, file, quiet); - if (resfile != NULL) return resfile; - } - return NULL; -} - -FResourceFile *FResourceFile::OpenResourceFile(const char *filename, FileReader &file, bool quiet, bool containeronly) -{ - return DoOpenResourceFile(filename, file, quiet, containeronly); -} - - -FResourceFile *FResourceFile::OpenResourceFile(const char *filename, bool quiet, bool containeronly) -{ - FileReader file; - if (!file.OpenFile(filename)) return nullptr; - return DoOpenResourceFile(filename, file, quiet, containeronly); -} - -/* -FResourceFile *FResourceFile::OpenResourceFileFromLump(int lumpnum, bool quiet, bool containeronly) -{ - FileReader file = Wads.ReopenLumpReader(lumpnum); - return DoOpenResourceFile("internal", file, quiet, containeronly); -} -*/ - -FResourceFile *FResourceFile::OpenDirectory(const char *filename, bool quiet) -{ - return CheckDir(filename, quiet); -} - -//========================================================================== -// -// Resource file base class -// -//========================================================================== - -FResourceFile::FResourceFile(const char *filename) - : FileName(filename) -{ -} - -FResourceFile::FResourceFile(const char *filename, FileReader &r) - : FResourceFile(filename) -{ - Reader = std::move(r); -} - -FResourceFile::~FResourceFile() -{ -} - -int lumpcmp(const void * a, const void * b) -{ - FResourceLump * rec1 = (FResourceLump *)a; - FResourceLump * rec2 = (FResourceLump *)b; - - return rec1->FullName.CompareNoCase(rec2->FullName); -} - -//========================================================================== -// -// FResourceFile :: PostProcessArchive -// -// Sorts files by name. -// For files named "filter//*": Using the same filter rules as config -// autoloading, move them to the end and rename them without the "filter/" -// prefix. Filtered files that don't match are deleted. -// -//========================================================================== - -void FResourceFile::PostProcessArchive(void *lumps, size_t lumpsize) -{ - // Entries in archives are sorted alphabetically - qsort(lumps, NumLumps, lumpsize, lumpcmp); - - - // Filter out lumps using the same names as the Autoload.* sections - // in the ini file use. We reduce the maximum lump concidered after - // each one so that we don't risk refiltering already filtered lumps. - uint32_t max = NumLumps; - max -= FilterLumpsByGameType(gametype, lumps, lumpsize, max); - - long len; - int lastpos = -1; - FString file; - - while ((len = LumpFilterIWAD.IndexOf('.', lastpos+1)) > 0) - { - max -= FilterLumps(LumpFilterIWAD.Left(len), lumps, lumpsize, max); - lastpos = len; - } - JunkLeftoverFilters(lumps, lumpsize, max); -} - -//========================================================================== -// -// FResourceFile :: FilterLumps -// -// Finds any lumps between [0,) that match the pattern -// "filter//*" and moves them to the end of the lump list. -// Returns the number of lumps moved. -// -//========================================================================== - -int FResourceFile::FilterLumps(FString filtername, void *lumps, size_t lumpsize, uint32_t max) -{ - FString filter; - uint32_t start, end; - - if (filtername.IsEmpty()) - { - return 0; - } - filter << "filter/" << filtername << '/'; - - bool found = FindPrefixRange(filter, lumps, lumpsize, max, start, end); - - // Workaround for old Doom filter names. - if (!found && filtername.IndexOf("doom.id.doom") == 0) - { - filter.Substitute("doom.id.doom", "doom.doom"); - found = FindPrefixRange(filter, lumps, lumpsize, max, start, end); - } - - if (found) - { - void *from = (uint8_t *)lumps + start * lumpsize; - - // Remove filter prefix from every name - void *lump_p = from; - for (uint32_t i = start; i < end; ++i, lump_p = (uint8_t *)lump_p + lumpsize) - { - FResourceLump *lump = (FResourceLump *)lump_p; - assert(lump->FullName.CompareNoCase(filter, (int)filter.Len()) == 0); - lump->LumpNameSetup(lump->FullName.Mid(filter.Len())); - } - - // Move filtered lumps to the end of the lump list. - size_t count = (end - start) * lumpsize; - void *to = (uint8_t *)lumps + NumLumps * lumpsize - count; - assert (to >= from); - - if (from != to) - { - // Copy filtered lumps to a temporary buffer. - uint8_t *filteredlumps = new uint8_t[count]; - memcpy(filteredlumps, from, count); - - // Shift lumps left to make room for the filtered ones at the end. - memmove(from, (uint8_t *)from + count, (NumLumps - end) * lumpsize); - - // Copy temporary buffer to newly freed space. - memcpy(to, filteredlumps, count); - - delete[] filteredlumps; - } - } - return end - start; -} - -//========================================================================== -// -// FResourceFile :: FilterLumpsByGameType -// -// Matches any lumps that match "filter/game-/*". Includes -// inclusive gametypes like Raven. -// -//========================================================================== - -int FResourceFile::FilterLumpsByGameType(int type, void *lumps, size_t lumpsize, uint32_t max) -{ - int count = 0; - for (int i = GAME_MAX; i >= 0; i++) - { - if ((type & i) && GameFilters[i]) - { - count += FilterLumps(GameFilters[i], lumps, lumpsize, max); - } - } - return count; -} - -//========================================================================== -// -// FResourceFile :: JunkLeftoverFilters -// -// Deletes any lumps beginning with "filter/" that were not matched. -// -//========================================================================== - -void FResourceFile::JunkLeftoverFilters(void *lumps, size_t lumpsize, uint32_t max) -{ - uint32_t start, end; - if (FindPrefixRange("filter/", lumps, lumpsize, max, start, end)) - { - // Since the resource lumps may contain non-POD data besides the - // full name, we "delete" them by erasing their names so they - // can't be found. - void *stop = (uint8_t *)lumps + end * lumpsize; - for (void *p = (uint8_t *)lumps + start * lumpsize; p < stop; p = (uint8_t *)p + lumpsize) - { - FResourceLump *lump = (FResourceLump *)p; - lump->FullName = ""; - lump->BaseName = ""; - } - } -} - -//========================================================================== -// -// FResourceFile :: FindPrefixRange -// -// Finds a range of lumps that start with the prefix string. is left -// indicating the first matching one. is left at one plus the last -// matching one. -// -//========================================================================== - -bool FResourceFile::FindPrefixRange(FString filter, void *lumps, size_t lumpsize, uint32_t maxlump, uint32_t &start, uint32_t &end) -{ - uint32_t min, max, mid, inside; - FResourceLump *lump; - int cmp; - - end = start = 0; - - // Pretend that our range starts at 1 instead of 0 so that we can avoid - // unsigned overflow if the range starts at the first lump. - lumps = (uint8_t *)lumps - lumpsize; - - // Binary search to find any match at all. - min = 1, max = maxlump; - while (min <= max) - { - mid = min + (max - min) / 2; - lump = (FResourceLump *)((uint8_t *)lumps + mid * lumpsize); - cmp = lump->FullName.CompareNoCase(filter, (int)filter.Len()); - if (cmp == 0) - break; - else if (cmp < 0) - min = mid + 1; - else - max = mid - 1; - } - if (max < min) - { // matched nothing - return false; - } - - // Binary search to find first match. - inside = mid; - min = 1, max = mid; - while (min <= max) - { - mid = min + (max - min) / 2; - lump = (FResourceLump *)((uint8_t *)lumps + mid * lumpsize); - cmp = lump->FullName.CompareNoCase(filter, (int)filter.Len()); - // Go left on matches and right on misses. - if (cmp == 0) - max = mid - 1; - else - min = mid + 1; - } - start = mid + (cmp != 0) - 1; - - // Binary search to find last match. - min = inside, max = maxlump; - while (min <= max) - { - mid = min + (max - min) / 2; - lump = (FResourceLump *)((uint8_t *)lumps + mid * lumpsize); - cmp = lump->FullName.CompareNoCase(filter, (int)filter.Len()); - // Go right on matches and left on misses. - if (cmp == 0) - min = mid + 1; - else - max = mid - 1; - } - end = mid - (cmp != 0); - return true; -} - -//========================================================================== -// -// Needs to be virtual in the base class. Implemented only for WADs -// -//========================================================================== - -void FResourceFile::FindStrifeTeaserVoices () -{ -} - -//========================================================================== -// -// Finds a lump by a given name. Used for savegames -// -//========================================================================== - -FResourceLump *FResourceFile::FindLump(const char *name) -{ - for (unsigned i = 0; i < NumLumps; i++) - { - FResourceLump *lump = GetLump(i); - if (!stricmp(name, lump->FullName)) - { - return lump; - } - } - return nullptr; -} - -//========================================================================== -// -// Caches a lump's content and increases the reference counter -// -//========================================================================== - -FileReader *FUncompressedLump::GetReader() -{ - Owner->Reader.Seek(Position, FileReader::SeekSet); - return &Owner->Reader; -} - -//========================================================================== -// -// Caches a lump's content and increases the reference counter -// -//========================================================================== - -int FUncompressedLump::FillCache() -{ - Owner->Reader.Seek(Position, FileReader::SeekSet); - Cache.Resize(LumpSize); - Owner->Reader.Read(Cache.Data(), LumpSize); - RefCount = 1; - return 1; -} - -//========================================================================== -// -// Base class for uncompressed resource files -// -//========================================================================== - -FUncompressedFile::FUncompressedFile(const char *filename) -: FResourceFile(filename) -{} - -FUncompressedFile::FUncompressedFile(const char *filename, FileReader &r) - : FResourceFile(filename, r) -{} - - -//========================================================================== -// -// external lump -// -//========================================================================== - -FExternalLump::FExternalLump(const char *_filename, int filesize) - : Filename(_filename) -{ - if (filesize == -1) - { - FileReader f; - - if (f.OpenFile(_filename)) - { - LumpSize = (int)f.GetLength(); - } - else - { - LumpSize = 0; - } - } - else - { - LumpSize = filesize; - } -} - - -//========================================================================== -// -// 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.Resize(LumpSize); - FileReader f; - - if (f.OpenFile(Filename)) - { - f.Read(Cache.Data(), LumpSize); - } - else - { - memset(Cache.Data(), 0, LumpSize); - } - RefCount = 1; - return 1; -} diff --git a/source/common/resourcefiles/resourcefile.h b/source/common/resourcefiles/resourcefile.h deleted file mode 100644 index 5cc2ca151..000000000 --- a/source/common/resourcefiles/resourcefile.h +++ /dev/null @@ -1,148 +0,0 @@ - - -#ifndef __RESFILE_H -#define __RESFILE_H - -#include "zstring.h" -#include "files.h" -#include "printf.h" - -enum ELumpFlags -{ - LUMPF_ZIPFILE=1, // contains a full path - LUMPF_BLOODCRYPT = 2, // encrypted - LUMPF_COMPRESSED = 4, // compressed - LUMPF_SEQUENTIAL = 8, // compressed but a sequential reader can be retrieved. -}; - -class FResourceFile; - -// This holds a compresed Zip entry with all needed info to decompress it. -struct FCompressedBuffer -{ - unsigned mSize; - unsigned mCompressedSize; - int mMethod; - int mZipFlags; - unsigned mCRC32; - char *mBuffer; - - bool Decompress(char *destbuffer); - void Clean() - { - mSize = mCompressedSize = 0; - if (mBuffer != nullptr) - { - delete[] mBuffer; - mBuffer = nullptr; - } - } -}; - -struct FResourceLump -{ - friend class FResourceFile; - - int LumpSize = 0; - int RefCount = 0; - int Flags = 0; - FString FullName; // Name with extension and path - FString BaseName; // Name without extension and path - FResourceFile * Owner = nullptr; - TArray Cache; - - FResourceLump() = default; - - virtual ~FResourceLump(); - virtual FileReader *GetReader(); - virtual FileReader NewReader(); - virtual int GetFileOffset() { return -1; } - virtual int GetIndexNum() const { return 0; } - void LumpNameSetup(FString iname); - virtual FCompressedBuffer GetRawData(); - - void *CacheLump(); - int ReleaseCache(); - -protected: - virtual int FillCache() { return -1; } - -}; - -class FResourceFile -{ -public: - FileReader Reader; - FString FileName; -protected: - uint32_t NumLumps; - - FResourceFile(const char *filename); - FResourceFile(const char *filename, FileReader &r); - - // for archives that can contain directories - void PostProcessArchive(void *lumps, size_t lumpsize); - -private: - uint32_t FirstLump; - - int FilterLumps(FString filtername, void *lumps, size_t lumpsize, uint32_t max); - int FilterLumpsByGameType(int gametype, void *lumps, size_t lumpsize, uint32_t max); - bool FindPrefixRange(FString filter, void *lumps, size_t lumpsize, uint32_t max, uint32_t &start, uint32_t &end); - void JunkLeftoverFilters(void *lumps, size_t lumpsize, uint32_t max); - static FResourceFile *DoOpenResourceFile(const char *filename, FileReader &file, bool quiet, bool containeronly); - -public: - static FResourceFile *OpenResourceFile(const char *filename, FileReader &file, bool quiet = false, bool containeronly = false); - static FResourceFile *OpenResourceFile(const char *filename, bool quiet = false, bool containeronly = false); - //static FResourceFile *OpenResourceFileFromLump(int lumpnum, bool quiet = false, bool containeronly = false); - static FResourceFile *OpenDirectory(const char *filename, bool quiet = false); - virtual ~FResourceFile(); - // If this FResourceFile represents a directory, the Reader object is not usable so don't return it. - FileReader *GetReader() { return Reader.isOpen()? &Reader : nullptr; } - uint32_t LumpCount() const { return NumLumps; } - uint32_t GetFirstLump() const { return FirstLump; } - void SetFirstLump(uint32_t f) { FirstLump = f; } - - - virtual void FindStrifeTeaserVoices (); - virtual bool Open(bool quiet) = 0; - virtual FResourceLump *GetLump(int no) = 0; - FResourceLump *FindLump(const char *name); -}; - -struct FUncompressedLump : public FResourceLump -{ - int Position; - - virtual FileReader *GetReader(); - virtual int FillCache(); - virtual int GetFileOffset() { return Position; } - -}; - - -// Base class for uncompressed resource files (GRP, PAK and single lumps) -class FUncompressedFile : public FResourceFile -{ -protected: - TArray Lumps; - - FUncompressedFile(const char *filename); - FUncompressedFile(const char *filename, FileReader &r); - virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } -}; - - -struct FExternalLump : public FResourceLump -{ - FString Filename; - - FExternalLump(const char *_filename, int filesize = -1); - virtual int FillCache(); - -}; - - - -#endif diff --git a/source/common/resourcefiles/w_zip.h b/source/common/resourcefiles/w_zip.h deleted file mode 100644 index fddae1d18..000000000 --- a/source/common/resourcefiles/w_zip.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef __W_ZIP -#define __W_ZIP - -#ifdef __GNUC__ -// With versions of GCC newer than 4.2, it appears it was determined that the -// cost of an unaligned pointer on PPC was high enough to add padding to the -// end of packed structs. For whatever reason __packed__ and pragma pack are -// handled differently in this regard. Note that this only needs to be applied -// to types which are used in arrays. -#define FORCE_PACKED __attribute__((__packed__)) -#else -#define FORCE_PACKED -#endif - - -#pragma pack(1) -// FZipCentralInfo -struct FZipEndOfCentralDirectory -{ - uint32_t Magic; - uint16_t DiskNumber; - uint16_t FirstDisk; - uint16_t NumEntries; - uint16_t NumEntriesOnAllDisks; - uint32_t DirectorySize; - uint32_t DirectoryOffset; - uint16_t ZipCommentLength; -} FORCE_PACKED; - -// FZipFileInfo -struct FZipCentralDirectoryInfo -{ - uint32_t Magic; - uint8_t VersionMadeBy[2]; - uint8_t VersionToExtract[2]; - uint16_t Flags; - uint16_t Method; - uint16_t ModTime; - uint16_t ModDate; - uint32_t CRC32; - uint32_t CompressedSize; - uint32_t UncompressedSize; - uint16_t NameLength; - uint16_t ExtraLength; - uint16_t CommentLength; - uint16_t StartingDiskNumber; - uint16_t InternalAttributes; - uint32_t ExternalAttributes; - uint32_t LocalHeaderOffset; - // file name and other variable length info follows -} FORCE_PACKED; - -// FZipLocalHeader -struct FZipLocalFileHeader -{ - uint32_t Magic; - uint8_t VersionToExtract[2]; - uint16_t Flags; - uint16_t Method; - uint16_t ModTime; - uint16_t ModDate; - uint32_t CRC32; - uint32_t CompressedSize; - uint32_t UncompressedSize; - uint16_t NameLength; - uint16_t ExtraLength; - // file name and other variable length info follows -} FORCE_PACKED; - - -#pragma pack() - -#define ZIP_LOCALFILE MAKE_ID('P','K',3,4) -#define ZIP_CENTRALFILE MAKE_ID('P','K',1,2) -#define ZIP_ENDOFDIR MAKE_ID('P','K',5,6) - -// File header flags. -#define ZF_ENCRYPTED 0x1 - -#endif