mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2025-01-22 09:11:33 +00:00
filesystem: support daikatana pak files
Release leafs have 32 != 28 bytes record size, and unsupported for now.
This commit is contained in:
parent
6b6da54054
commit
8cf9848291
2 changed files with 199 additions and 13 deletions
|
@ -46,6 +46,13 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
PAK_MODE_Q2,
|
||||||
|
PAK_MODE_DK,
|
||||||
|
PAK_MODE_DAT,
|
||||||
|
} fsPackCompress_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char name[MAX_FILENAME];
|
char name[MAX_FILENAME];
|
||||||
|
@ -53,6 +60,7 @@ typedef struct
|
||||||
FILE *file; /* Only one will be used. */
|
FILE *file; /* Only one will be used. */
|
||||||
unzFile *zip; /* (file or zip) */
|
unzFile *zip; /* (file or zip) */
|
||||||
int compressed_size; /* Should be zero for original PAK files */
|
int compressed_size; /* Should be zero for original PAK files */
|
||||||
|
fsPackCompress_t format;
|
||||||
} fsHandle_t;
|
} fsHandle_t;
|
||||||
|
|
||||||
typedef struct fsLink_s
|
typedef struct fsLink_s
|
||||||
|
@ -69,6 +77,7 @@ typedef struct
|
||||||
int size;
|
int size;
|
||||||
int offset; /* Ignored in PK3 files. */
|
int offset; /* Ignored in PK3 files. */
|
||||||
int compressed_size; /* Should be zero for original PAK files */
|
int compressed_size; /* Should be zero for original PAK files */
|
||||||
|
fsPackCompress_t format;
|
||||||
} fsPackFile_t;
|
} fsPackFile_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -455,6 +464,7 @@ FS_FOpenFile(const char *rawname, fileHandle_t *f, qboolean gamedir_only)
|
||||||
// because it's from pak, but save/bla/MAPname.sav/sv2 will have wrong case and can't be found then)
|
// because it's from pak, but save/bla/MAPname.sav/sv2 will have wrong case and can't be found then)
|
||||||
Q_strlcpy(handle->name, pack->files[i].name, sizeof(handle->name));
|
Q_strlcpy(handle->name, pack->files[i].name, sizeof(handle->name));
|
||||||
handle->compressed_size = 0;
|
handle->compressed_size = 0;
|
||||||
|
handle->format = PAK_MODE_Q2;
|
||||||
|
|
||||||
if (pack->pak)
|
if (pack->pak)
|
||||||
{
|
{
|
||||||
|
@ -469,6 +479,7 @@ FS_FOpenFile(const char *rawname, fileHandle_t *f, qboolean gamedir_only)
|
||||||
if (handle->file)
|
if (handle->file)
|
||||||
{
|
{
|
||||||
handle->compressed_size = pack->files[i].compressed_size;
|
handle->compressed_size = pack->files[i].compressed_size;
|
||||||
|
handle->format = pack->files[i].format;
|
||||||
fseek(handle->file, pack->files[i].offset, SEEK_SET);
|
fseek(handle->file, pack->files[i].offset, SEEK_SET);
|
||||||
return pack->files[i].size;
|
return pack->files[i].size;
|
||||||
}
|
}
|
||||||
|
@ -550,23 +561,110 @@ FS_DecompressFile(void *buffer, int size, const fsHandle_t *handle)
|
||||||
{
|
{
|
||||||
unsigned long uncomressed_size;
|
unsigned long uncomressed_size;
|
||||||
byte *comressed_buffer;
|
byte *comressed_buffer;
|
||||||
int status;
|
|
||||||
|
|
||||||
comressed_buffer = malloc(handle->compressed_size);
|
comressed_buffer = malloc(handle->compressed_size);
|
||||||
uncomressed_size = size;
|
uncomressed_size = size;
|
||||||
|
|
||||||
memcpy(comressed_buffer, buffer, handle->compressed_size);
|
memcpy(comressed_buffer, buffer, handle->compressed_size);
|
||||||
|
|
||||||
status = uncompress(buffer, &uncomressed_size, comressed_buffer, handle->compressed_size);
|
if (handle->format == PAK_MODE_DAT)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
|
||||||
|
status = uncompress(buffer, &uncomressed_size, comressed_buffer,
|
||||||
|
handle->compressed_size);
|
||||||
|
|
||||||
free(comressed_buffer);
|
free(comressed_buffer);
|
||||||
|
|
||||||
if (status != MZ_OK)
|
if (status != MZ_OK)
|
||||||
{
|
{
|
||||||
Com_Error(ERR_FATAL, "%s: can't decompress file '%s'", __func__, handle->name);
|
Com_Error(ERR_FATAL, "%s: can't decompress file '%s'",
|
||||||
|
__func__, handle->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (handle->format == PAK_MODE_DK)
|
||||||
|
{
|
||||||
|
int read = 0;
|
||||||
|
int written = 0;
|
||||||
|
|
||||||
|
while ((read < handle->compressed_size) || (written < size))
|
||||||
|
{
|
||||||
|
byte x;
|
||||||
|
|
||||||
|
x = comressed_buffer[read];
|
||||||
|
++read;
|
||||||
|
|
||||||
|
/* x + 1 bytes of uncompressed data */
|
||||||
|
if (x < 64)
|
||||||
|
{
|
||||||
|
if ((written + x + 1) > size)
|
||||||
|
{
|
||||||
|
Com_Error(ERR_FATAL, "%s: can't decompress file '%s'",
|
||||||
|
__func__, handle->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memmove(buffer + written, comressed_buffer + read, x + 1);
|
||||||
|
|
||||||
|
read += x + 1;
|
||||||
|
written += x + 1;
|
||||||
|
}
|
||||||
|
/* x - 62 zeros */
|
||||||
|
else if (x < 128)
|
||||||
|
{
|
||||||
|
if ((written + x - 62) > size)
|
||||||
|
{
|
||||||
|
Com_Error(ERR_FATAL, "%s: can't decompress file '%s'",
|
||||||
|
__func__, handle->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(buffer + written, 0, x - 62);
|
||||||
|
|
||||||
|
written += x - 62;
|
||||||
|
}
|
||||||
|
/* x - 126 times the next byte */
|
||||||
|
else if (x < 192)
|
||||||
|
{
|
||||||
|
if ((written + x - 126) > size)
|
||||||
|
{
|
||||||
|
Com_Error(ERR_FATAL, "%s: can't decompress file '%s'",
|
||||||
|
__func__, handle->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(buffer + written, comressed_buffer[read], x - 126);
|
||||||
|
|
||||||
|
++read;
|
||||||
|
written += x - 126;
|
||||||
|
}
|
||||||
|
/* Reference previously uncompressed data */
|
||||||
|
else if (x < 254)
|
||||||
|
{
|
||||||
|
if ((written + x - 190) > size)
|
||||||
|
{
|
||||||
|
Com_Error(ERR_FATAL, "%s: can't decompress file '%s'",
|
||||||
|
__func__, handle->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memmove(buffer + written, (buffer + written) - (
|
||||||
|
(int)comressed_buffer[read] + 2), x - 190);
|
||||||
|
|
||||||
|
++read;
|
||||||
|
written += x - 190;
|
||||||
|
}
|
||||||
|
/* Terminate */
|
||||||
|
else if (x == 255)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(comressed_buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
@ -924,7 +1022,8 @@ FS_LoadDAT(const char *packPath)
|
||||||
/* copy length */
|
/* copy length */
|
||||||
files[i].offset = LittleLong(info[i].filepos);
|
files[i].offset = LittleLong(info[i].filepos);
|
||||||
files[i].size = LittleLong(info[i].filelen);
|
files[i].size = LittleLong(info[i].filelen);
|
||||||
files[i].compressed_size = LittleLong(info[i].compressedlen);
|
files[i].compressed_size = LittleLong(info[i].compressed_size);
|
||||||
|
files[i].format = files[i].compressed_size ? PAK_MODE_DAT : PAK_MODE_Q2;
|
||||||
}
|
}
|
||||||
free(info);
|
free(info);
|
||||||
|
|
||||||
|
@ -951,7 +1050,7 @@ FS_LoadPAKQ2(dpackheader_t *header, FILE *handle, const char *packPath)
|
||||||
|
|
||||||
numFiles = header->dirlen / sizeof(dpackfile_t);
|
numFiles = header->dirlen / sizeof(dpackfile_t);
|
||||||
|
|
||||||
if ((numFiles == 0) || (header->dirlen < 0) || (header->dirofs < 0))
|
if (numFiles == 0)
|
||||||
{
|
{
|
||||||
fclose(handle);
|
fclose(handle);
|
||||||
Com_Error(ERR_FATAL, "%s: '%s' is too short.",
|
Com_Error(ERR_FATAL, "%s: '%s' is too short.",
|
||||||
|
@ -983,6 +1082,74 @@ FS_LoadPAKQ2(dpackheader_t *header, FILE *handle, const char *packPath)
|
||||||
files[i].offset = LittleLong(info[i].filepos);
|
files[i].offset = LittleLong(info[i].filepos);
|
||||||
files[i].size = LittleLong(info[i].filelen);
|
files[i].size = LittleLong(info[i].filelen);
|
||||||
files[i].compressed_size = 0;
|
files[i].compressed_size = 0;
|
||||||
|
files[i].format = PAK_MODE_Q2;
|
||||||
|
}
|
||||||
|
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 packfile '%s' (%i files).\n", pack->name, numFiles);
|
||||||
|
|
||||||
|
return pack;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fsPack_t *
|
||||||
|
FS_LoadPAKDK(dpackheader_t *header, FILE *handle, const char *packPath)
|
||||||
|
{
|
||||||
|
int i; /* Loop counter. */
|
||||||
|
int numFiles; /* Number of files in PAK. */
|
||||||
|
fsPackFile_t *files; /* List of files in PAK. */
|
||||||
|
fsPack_t *pack; /* PAK file. */
|
||||||
|
dpackdkfile_t *info = NULL; /* PAK info. */
|
||||||
|
|
||||||
|
numFiles = header->dirlen / sizeof(dpackdkfile_t);
|
||||||
|
|
||||||
|
if (numFiles == 0)
|
||||||
|
{
|
||||||
|
fclose(handle);
|
||||||
|
Com_Error(ERR_FATAL, "%s: '%s' is too short.",
|
||||||
|
__func__, packPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
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, sizeof(files[i].name));
|
||||||
|
files[i].offset = LittleLong(info[i].filepos);
|
||||||
|
files[i].size = LittleLong(info[i].filelen);
|
||||||
|
if (info[i].is_compressed)
|
||||||
|
{
|
||||||
|
files[i].compressed_size = LittleLong(info[i].compressed_size);
|
||||||
|
files[i].format = PAK_MODE_DK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
files[i].compressed_size = 0;
|
||||||
|
files[i].format = PAK_MODE_Q2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
free(info);
|
free(info);
|
||||||
|
|
||||||
|
@ -1022,19 +1189,32 @@ FS_LoadPAK(const char *packPath)
|
||||||
if (LittleLong(header.ident) != IDPAKHEADER)
|
if (LittleLong(header.ident) != IDPAKHEADER)
|
||||||
{
|
{
|
||||||
fclose(handle);
|
fclose(handle);
|
||||||
Com_Error(ERR_FATAL, "%s: '%s' is not a pack file", __func__, packPath);
|
Com_Error(ERR_FATAL, "%s: '%s' is not a pack file",
|
||||||
|
__func__, packPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
header.dirofs = LittleLong(header.dirofs);
|
header.dirofs = LittleLong(header.dirofs);
|
||||||
header.dirlen = LittleLong(header.dirlen);
|
header.dirlen = LittleLong(header.dirlen);
|
||||||
|
|
||||||
|
if((header.dirlen <= 0) || (header.dirofs < 0))
|
||||||
|
{
|
||||||
|
fclose(handle);
|
||||||
|
Com_Error(ERR_FATAL, "%s: '%s' is too short.",
|
||||||
|
__func__, packPath);
|
||||||
|
}
|
||||||
|
|
||||||
if ((header.dirlen % sizeof(dpackfile_t)) == 0)
|
if ((header.dirlen % sizeof(dpackfile_t)) == 0)
|
||||||
{
|
{
|
||||||
return FS_LoadPAKQ2(&header, handle, packPath);
|
return FS_LoadPAKQ2(&header, handle, packPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((header.dirlen % sizeof(dpackdkfile_t)) == 0)
|
||||||
|
{
|
||||||
|
return FS_LoadPAKDK(&header, handle, packPath);
|
||||||
|
}
|
||||||
|
|
||||||
fclose(handle);
|
fclose(handle);
|
||||||
Com_Printf("WARNING: '%s' looks as Daikatana pak. Skipped it!\n",
|
Com_Printf("WARNING: skipped unsupported '%s' PAK format.\n",
|
||||||
packPath);
|
packPath);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ typedef struct
|
||||||
char name[128];
|
char name[128];
|
||||||
int filepos;
|
int filepos;
|
||||||
int filelen;
|
int filelen;
|
||||||
int compressedlen;
|
int compressed_size;
|
||||||
int checksum;
|
int checksum;
|
||||||
} ddatfile_t;
|
} ddatfile_t;
|
||||||
|
|
||||||
|
@ -59,6 +59,12 @@ typedef struct
|
||||||
int filepos, filelen;
|
int filepos, filelen;
|
||||||
} dpackfile_t;
|
} dpackfile_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char name[56];
|
||||||
|
int filepos, filelen, compressed_size, is_compressed;
|
||||||
|
} dpackdkfile_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int ident; /* == IDPAKHEADER */
|
int ident; /* == IDPAKHEADER */
|
||||||
|
|
Loading…
Reference in a new issue