From c21268c13b0dbcecc6c36164f3d0fa8f206dcd8c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 1 Jan 2024 21:20:16 +0100 Subject: [PATCH] added unpacking of Quake 2 PAK files. --- wadext.cpp | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++ wadfile.cpp | 6 +++ 2 files changed, 143 insertions(+) diff --git a/wadext.cpp b/wadext.cpp index 5266871..d8e58f5 100644 --- a/wadext.cpp +++ b/wadext.cpp @@ -677,6 +677,85 @@ void ConvertTextureX() } } +//========================================================================== +// +// CreatePath +// +// Creates a directory including all levels necessary +// +//========================================================================== +#ifdef _WIN32 +void CreatePath(const char* fn) +{ + char drive[_MAX_DRIVE]; + char dir[_MAX_DIR]; + _splitpath_s(fn, drive, sizeof drive, dir, sizeof dir, nullptr, 0, nullptr, 0); + + if ('\0' == *dir) + { + // Root/current/parent directory always exists + return; + } + + char path[_MAX_PATH]; + _makepath_s(path, sizeof path, drive, dir, nullptr, nullptr); + + if ('\0' == *path) + { + // No need to process empty relative path + return; + } + + // Remove trailing path separator(s) + for (size_t i = strlen(path); 0 != i; --i) + { + char& lastchar = path[i - 1]; + + if ('/' == lastchar || '\\' == lastchar) + { + lastchar = '\0'; + } + else + { + break; + } + } + + // Create all directories for given path + if ('\0' != *path) + { + CreatePath(path); + _mkdir(path); // PAKs are ASCII only, so we won't need Unicode extension. + } +} + +#else +void CreatePath(const char* fn) +{ + char* copy, * p; + + if (fn[0] == '/' && fn[1] == '\0') + { + return; + } + p = copy = strdup(fn); + do + { + p = strchr(p + 1, '/'); + if (p != NULL) + { + *p = '\0'; + } + mkdir(copy, 0755); + if (p != NULL) + { + *p = '/'; + } + } while (p); + free(copy); +} +#endif + //========================================================================== // // @@ -738,3 +817,61 @@ void GrpExtract(const char* filename, FILE* f) exit(1); } +//========================================================================== +// +// +// +//========================================================================== + +struct dpackfile_t +{ + char name[56]; + uint32_t filepos, filelen; +}; + +struct dpackheader_t +{ + uint32_t ident; // == IDPAKHEADER + uint32_t dirofs; + uint32_t dirlen; +}; + +void PakExtract(const char* filename, FILE* f) +{ + TArray fileinfo; + + dpackheader_t header; + + if (1 != fread(&header, sizeof(header), 1, f)) return; + + if (memcmp(&header.ident, "PACK", 4)) + { + return; + } + fseek(f, header.dirofs, SEEK_SET); + + uint32_t NumLumps = header.dirlen / sizeof(dpackfile_t); + fileinfo.Resize(NumLumps); + + if (NumLumps != fread(&fileinfo[0], sizeof(dpackfile_t), NumLumps, f)) return; + auto name = ExtractFileBase(filename, false); + mkdir(name.c_str()); + chdir(name.c_str()); + + TArray buffer; + for (uint32_t i = 0; i < NumLumps; i++) + { + buffer.Resize(fileinfo[i].filelen); + fseek(f, fileinfo[i].filepos, SEEK_SET); + if (buffer.Size() != fread(&buffer[0], 1, buffer.Size(), f)) return; + CreatePath(fileinfo[i].name); + FILE* fout = fopen(fileinfo[i].name, "wb"); + if (fout) + { + fwrite(&buffer[0], 1, fileinfo[i].filelen, fout); + fclose(fout); + } + } + exit(1); +} + diff --git a/wadfile.cpp b/wadfile.cpp index aba5831..82cd346 100644 --- a/wadfile.cpp +++ b/wadfile.cpp @@ -165,6 +165,7 @@ const char * CWADFile::GetLumpName(int lump) //========================================================================== void GrpExtract(const char* filename, FILE* f); +void PakExtract(const char* filename, FILE* f); void RffExtract(const char* filename, FILE* f); //========================================================================== @@ -207,6 +208,11 @@ void OpenMainWad(char *filename) GrpExtract(filename, f); exit(1); } + else if (memcmp(type, "PACK", 4) == 0) + { + PakExtract(filename, f); + exit(1); + } else if (!memcmp(type, "RFF\x1a", 4)) { RffExtract(filename, f);