filesystem: add sin pack file support

Based on: https://github.com/yquake2/pakextract
This commit is contained in:
Denis Pauk 2024-03-31 23:50:55 +03:00
parent 8cf9848291
commit 2c0fca8458
4 changed files with 132 additions and 16 deletions

View file

@ -973,6 +973,7 @@ SCR_PlayCinematic(char *arg)
#ifdef AVMEDIADECODE
if (dot && (!strcmp(dot, ".cin") ||
!strcmp(dot, ".ogv") ||
!strcmp(dot, ".avi") ||
!strcmp(dot, ".mpg") ||
!strcmp(dot, ".smk") ||
!strcmp(dot, ".roq")))
@ -986,6 +987,7 @@ SCR_PlayCinematic(char *arg)
if (SCR_LoadAVcodec(namewe, ".ogv") ||
SCR_LoadAVcodec(namewe, ".roq") ||
SCR_LoadAVcodec(namewe, ".mpg") ||
SCR_LoadAVcodec(namewe, ".avi") ||
SCR_LoadAVcodec(namewe, dot))
{
SCR_EndLoadingPlaque();

View file

@ -100,6 +100,7 @@ typedef struct fsSearchPath_s
typedef enum
{
DAT,
SIN,
PAK,
PK3
} fsPackFormat_t;
@ -118,6 +119,7 @@ fsSearchPath_t *fs_baseSearchPaths = NULL;
/* Pack formats / suffixes. */
fsPackTypes_t fs_packtypes[] = {
{"dat", DAT},
{"sin", SIN},
{"pak", PAK},
{"pk2", PK3},
{"pk3", PK3},
@ -911,12 +913,6 @@ FS_FreeSearchPaths(fsSearchPath_t *start, fsSearchPath_t *end)
return cur;
}
/*
* Takes an explicit (not game tree related) path to a pak file.
*
* Loads the header and directory, adding the files at the beginning of the
* list so they override previous pack files.
*/
static fsPack_t *
FS_LoadDAT(const char *packPath)
{
@ -940,8 +936,8 @@ FS_LoadDAT(const char *packPath)
fread(&header, 1, sizeof(ddatheader_t), handle);
if (LittleLong(header.ident) != IDDATHEADER ||
LittleLong(header.version) != IDDATVERSION)
if (LittleLong(header.ident) != DATHEADER ||
LittleLong(header.version) != DATVERSION)
{
fclose(handle);
Com_Error(ERR_FATAL, "%s: '%s' is not a dat file", __func__, packPath);
@ -950,7 +946,7 @@ FS_LoadDAT(const char *packPath)
header.dirofs = LittleLong(header.dirofs);
header.dirlen = LittleLong(header.dirlen);
numFiles = header.dirlen / sizeof(ddatfile_t);
numFiles = header.dirlen / sizeof(*info);
if ((numFiles == 0) || (header.dirlen < 0) || (header.dirofs < 0))
{
@ -1039,6 +1035,95 @@ FS_LoadDAT(const char *packPath)
return pack;
}
fsPack_t *
FS_LoadSIN(const char *packPath)
{
int i; /* Loop counter. */
int numFiles; /* Number of files in SIN. */
FILE *handle; /* File handle. */
fsPackFile_t *files; /* List of files in PAK. */
fsPack_t *pack; /* SIN file. */
dpackheader_t header; /* SIN file header. */
dsinfile_t *info = NULL; /* SIN info. */
handle = Q_fopen(packPath, "rb");
if (handle == NULL)
{
return NULL;
}
fread(&header, 1, sizeof(dpackheader_t), handle);
if (LittleLong(header.ident) != SINHEADER)
{
fclose(handle);
Com_Error(ERR_FATAL, "%s: '%s' is not a pack file", __func__, packPath);
}
header.dirofs = LittleLong(header.dirofs);
header.dirlen = LittleLong(header.dirlen);
if ((header.dirlen <= 0) ||
(header.dirofs < 0) ||
((header.dirlen % sizeof(*info)) != 0))
{
fclose(handle);
Com_Error(ERR_FATAL, "%s: '%s' is too short.",
__func__, packPath);
}
numFiles = header.dirlen / sizeof(*info);
if (numFiles > MAX_FILES_IN_PACK)
{
Com_Printf("%s: '%s' has %i > %i files\n",
__func__, packPath, numFiles, MAX_FILES_IN_PACK);
}
info = malloc(header.dirlen);
if (!info)
{
Com_Error(ERR_FATAL, "%s: '%s' is to big for read %d",
__func__, packPath, header.dirlen);
}
files = Z_Malloc(numFiles * sizeof(fsPackFile_t));
fseek(handle, header.dirofs, SEEK_SET);
fread(info, 1, header.dirlen, handle);
/* Parse the directory. */
for (i = 0; i < numFiles; i++)
{
Q_strlcpy(files[i].name, info[i].name,
Q_min(sizeof(files[i].name), sizeof(files[i].name)));
files[i].offset = LittleLong(info[i].filepos);
files[i].size = LittleLong(info[i].filelen);
files[i].compressed_size = 0;
files[i].format = PAK_MODE_Q2;
printf("sin: %s:%d\n", files[i].name, files[i].size);
}
free(info);
pack = Z_Malloc(sizeof(fsPack_t));
Q_strlcpy(pack->name, packPath, sizeof(pack->name));
pack->pak = handle;
pack->pk3 = NULL;
pack->numFiles = numFiles;
pack->files = files;
Com_Printf("Added sinfile '%s' (%i files).\n", pack->name, numFiles);
return pack;
}
/*
* Takes an explicit (not game tree related) path to a pak file.
*
* Loads the header and directory, adding the files at the beginning of the
* list so they override previous pack files.
*/
static fsPack_t *
FS_LoadPAKQ2(dpackheader_t *header, FILE *handle, const char *packPath)
{
@ -1048,7 +1133,7 @@ FS_LoadPAKQ2(dpackheader_t *header, FILE *handle, const char *packPath)
fsPack_t *pack; /* PAK file. */
dpackfile_t *info = NULL; /* PAK info. */
numFiles = header->dirlen / sizeof(dpackfile_t);
numFiles = header->dirlen / sizeof(*info);
if (numFiles == 0)
{
@ -1078,7 +1163,8 @@ FS_LoadPAKQ2(dpackheader_t *header, FILE *handle, const char *packPath)
/* Parse the directory. */
for (i = 0; i < numFiles; i++)
{
Q_strlcpy(files[i].name, info[i].name, sizeof(files[i].name));
Q_strlcpy(files[i].name, info[i].name,
Q_min(sizeof(files[i].name), sizeof(files[i].name)));
files[i].offset = LittleLong(info[i].filepos);
files[i].size = LittleLong(info[i].filelen);
files[i].compressed_size = 0;
@ -1107,7 +1193,7 @@ FS_LoadPAKDK(dpackheader_t *header, FILE *handle, const char *packPath)
fsPack_t *pack; /* PAK file. */
dpackdkfile_t *info = NULL; /* PAK info. */
numFiles = header->dirlen / sizeof(dpackdkfile_t);
numFiles = header->dirlen / sizeof(*info);
if (numFiles == 0)
{
@ -1137,7 +1223,8 @@ FS_LoadPAKDK(dpackheader_t *header, FILE *handle, const char *packPath)
/* Parse the directory. */
for (i = 0; i < numFiles; i++)
{
Q_strlcpy(files[i].name, info[i].name, sizeof(files[i].name));
Q_strlcpy(files[i].name, info[i].name,
Q_min(sizeof(files[i].name), sizeof(files[i].name)));
files[i].offset = LittleLong(info[i].filepos);
files[i].size = LittleLong(info[i].filelen);
if (info[i].is_compressed)
@ -1953,6 +2040,9 @@ FS_AddPAKFromGamedir(const char *pak)
case DAT:
pakfile = FS_LoadDAT(path);
break;
case SIN:
pakfile = FS_LoadSIN(path);
break;
case PAK:
pakfile = FS_LoadPAK(path);
break;
@ -2079,6 +2169,16 @@ FS_AddDirToSearchPath(char *dir, qboolean create) {
pack->isProtectedPak = true;
}
break;
case SIN:
pack = FS_LoadSIN(path);
if (pack)
{
pack->isProtectedPak = true;
}
break;
case PAK:
pack = FS_LoadPAK(path);
@ -2162,6 +2262,9 @@ FS_AddDirToSearchPath(char *dir, qboolean create) {
case DAT:
pack = FS_LoadDAT(list[j]);
break;
case SIN:
pack = FS_LoadSIN(list[j]);
break;
case PAK:
pack = FS_LoadPAK(list[j]);
break;

View file

@ -29,8 +29,8 @@
/* The .dat files are just a linear collapse of a directory tree */
#define IDDATHEADER (('T' << 24) + ('A' << 16) + ('D' << 8) + 'A')
#define IDDATVERSION 9
#define DATHEADER (('T' << 24) + ('A' << 16) + ('D' << 8) + 'A')
#define DATVERSION 9
typedef struct
{
@ -43,12 +43,22 @@ typedef struct
typedef struct
{
int ident; /* == IDDATHEADER */
int ident; /* == DATHEADER */
int dirofs;
int dirlen;
int version; /* == IDPAKVERSION */
} ddatheader_t;
/* The .sin files are just a linear collapse of a directory tree */
#define SINHEADER (('K' << 24) + ('A' << 16) + ('P' << 8) + 'S')
typedef struct
{
char name[120];
int filepos, filelen;
} dsinfile_t;
/* The .pak files are just a linear collapse of a directory tree */
#define IDPAKHEADER (('K' << 24) + ('C' << 16) + ('A' << 8) + 'P')

View file

@ -553,6 +553,7 @@ SV_Map(qboolean attractloop, char *levelstring, qboolean loadgame, qboolean isau
if ((l > 4) && (!strcmp(level + l - 4, ".cin") ||
!strcmp(level + l - 4, ".ogv") ||
!strcmp(level + l - 4, ".avi") ||
!strcmp(level + l - 4, ".roq") ||
!strcmp(level + l - 4, ".mpg") ||
!strcmp(level + l - 4, ".smk")))