added unpacking of Quake 2 PAK files.

This commit is contained in:
Christoph Oelckers 2024-01-01 21:20:16 +01:00
parent 0a8f91e0b9
commit c21268c13b
2 changed files with 143 additions and 0 deletions

View file

@ -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); 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<dpackfile_t> 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<char> 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);
}

View file

@ -165,6 +165,7 @@ const char * CWADFile::GetLumpName(int lump)
//========================================================================== //==========================================================================
void GrpExtract(const char* filename, FILE* f); void GrpExtract(const char* filename, FILE* f);
void PakExtract(const char* filename, FILE* f);
void RffExtract(const char* filename, FILE* f); void RffExtract(const char* filename, FILE* f);
//========================================================================== //==========================================================================
@ -207,6 +208,11 @@ void OpenMainWad(char *filename)
GrpExtract(filename, f); GrpExtract(filename, f);
exit(1); exit(1);
} }
else if (memcmp(type, "PACK", 4) == 0)
{
PakExtract(filename, f);
exit(1);
}
else if (!memcmp(type, "RFF\x1a", 4)) else if (!memcmp(type, "RFF\x1a", 4))
{ {
RffExtract(filename, f); RffExtract(filename, f);