From a70715ef41a1ee6b319666db4334bbb1400c2cff Mon Sep 17 00:00:00 2001 From: toni Date: Sun, 25 Aug 2024 15:42:26 +0200 Subject: [PATCH] PK3 file support, file system refactor --- Quake/Makefile | 1 + Quake/Makefile.w32 | 1 + Quake/Makefile.w64 | 1 + Quake/bgmusic.c | 2 +- Quake/cfgfile.c | 52 +- Quake/cfgfile.h | 9 +- Quake/cl_demo.c | 54 +- Quake/client.h | 4 +- Quake/cmd.c | 4 +- Quake/common.c | 595 +--------- Quake/common.h | 69 +- Quake/filesys.c | 1047 +++++++++++++++++ Quake/filesys.h | 242 ++++ Quake/gl_draw.c | 2 +- Quake/gl_model.c | 89 +- Quake/gl_screen.c | 3 +- Quake/gl_sky.c | 2 +- Quake/gl_texmgr.c | 24 +- Quake/gl_vidsdl.c | 19 +- Quake/host.c | 4 +- Quake/host_cmd.c | 47 +- Quake/image.c | 96 +- Quake/menu.c | 12 +- Quake/miniz.c | 3 +- Quake/pr_edict.c | 9 +- Quake/quakedef.h | 1 + Quake/r_part.c | 13 +- Quake/snd_codec.c | 16 +- Quake/snd_codec.h | 3 +- Quake/snd_flac.c | 16 +- Quake/snd_mem.c | 5 +- Quake/snd_mikmod.c | 22 +- Quake/snd_modplug.c | 6 +- Quake/snd_mp3.c | 15 +- Quake/snd_mp3tag.c | 163 +-- Quake/snd_mpg123.c | 11 +- Quake/snd_opus.c | 13 +- Quake/snd_umx.c | 65 +- Quake/snd_vorbis.c | 22 +- Quake/snd_wave.c | 45 +- Quake/snd_xmp.c | 44 +- Quake/sys.h | 12 +- Quake/sys_sdl_unix.c | 75 -- Quake/sys_sdl_win.c | 76 -- Quake/wad.c | 2 +- Windows/VisualStudio/ironwail.vcxproj | 2 + Windows/VisualStudio/ironwail.vcxproj.filters | 6 + 47 files changed, 1791 insertions(+), 1233 deletions(-) create mode 100644 Quake/filesys.c create mode 100644 Quake/filesys.h diff --git a/Quake/Makefile b/Quake/Makefile index dad352932..84f060a1f 100644 --- a/Quake/Makefile +++ b/Quake/Makefile @@ -264,6 +264,7 @@ OBJS = strlcat.o \ crc.o \ cvar.o \ cfgfile.o \ + filesys.o \ host.o \ host_cmd.o \ mathlib.o \ diff --git a/Quake/Makefile.w32 b/Quake/Makefile.w32 index 4218a250f..735f24cd9 100644 --- a/Quake/Makefile.w32 +++ b/Quake/Makefile.w32 @@ -270,6 +270,7 @@ OBJS = strlcat.o \ crc.o \ cvar.o \ cfgfile.o \ + filesys.o \ host.o \ host_cmd.o \ mathlib.o \ diff --git a/Quake/Makefile.w64 b/Quake/Makefile.w64 index 877edf0cb..98845c19f 100644 --- a/Quake/Makefile.w64 +++ b/Quake/Makefile.w64 @@ -263,6 +263,7 @@ OBJS = strlcat.o \ crc.o \ cvar.o \ cfgfile.o \ + filesys.o \ host.o \ host_cmd.o \ mathlib.o \ diff --git a/Quake/bgmusic.c b/Quake/bgmusic.c index 25a75a238..470dc934f 100644 --- a/Quake/bgmusic.c +++ b/Quake/bgmusic.c @@ -328,7 +328,7 @@ void BGM_PlayCDtrack (byte track, qboolean looping) goto _next; q_snprintf(tmp, sizeof(tmp), "%s/track%02d.%s", MUSIC_DIRNAME, (int)track, handler->ext); - if (! COM_FileExists(tmp, &path_id)) + if (!QFS_FileExists(tmp, &path_id)) goto _next; if (path_id > prev_id) { diff --git a/Quake/cfgfile.c b/Quake/cfgfile.c index 3373db4dc..5648bd4bb 100644 --- a/Quake/cfgfile.c +++ b/Quake/cfgfile.c @@ -21,9 +21,6 @@ #include "quakedef.h" - -static fshandle_t *cfg_file; - /* =================== CFG_ReadCvars @@ -35,12 +32,17 @@ the num_vars argument must be the exact number of strings in the array, otherwise I have nothing against going out of bounds. =================== */ -void CFG_ReadCvars (const char **vars, int num_vars) +void CFG_ReadCvars (const char *cfg_name, const char **vars, int num_vars) { char buff[1024], *tmp; int i, j; + qfshandle_t *cfg_file; - if (!cfg_file || num_vars < 1) + if (num_vars < 1) + return; + + cfg_file = QFS_OpenFile (cfg_name, NULL); + if (!cfg_file) return; j = 0; @@ -52,7 +54,7 @@ void CFG_ReadCvars (const char **vars, int num_vars) // writes to the config file. although I'm trying to be as // much cautious as possible, if the user screws it up by // editing it, it's his fault. - if (FS_fgets(buff, sizeof(buff), cfg_file)) + if (QFS_GetLine (cfg_file, buff, sizeof(buff))) { // remove end-of-line characters while (buff[i]) @@ -104,9 +106,7 @@ void CFG_ReadCvars (const char **vars, int num_vars) if (j == num_vars) break; - } while (!FS_feof(cfg_file) && !FS_ferror(cfg_file)); - - FS_rewind (cfg_file); + } while (!QFS_Eof (cfg_file)); } /* @@ -139,37 +139,3 @@ void CFG_ReadCvarOverrides (const char **vars, int num_vars) } } } - -void CFG_CloseConfig (void) -{ - if (cfg_file) - { - FS_fclose(cfg_file); - Z_Free(cfg_file); - cfg_file = NULL; - } -} - -int CFG_OpenConfig (const char *cfg_name) -{ - FILE *f; - long length; - qboolean pak; - - CFG_CloseConfig (); - - length = (long) COM_FOpenFile (cfg_name, &f, NULL); - pak = file_from_pak; - if (length == -1) - return -1; - - cfg_file = (fshandle_t *) Z_Malloc(sizeof(fshandle_t)); - cfg_file->file = f; - cfg_file->start = ftell(f); - cfg_file->pos = 0; - cfg_file->length = length; - cfg_file->pak = pak; - - return 0; -} - diff --git a/Quake/cfgfile.h b/Quake/cfgfile.h index dbe8f39f8..4343b0212 100644 --- a/Quake/cfgfile.h +++ b/Quake/cfgfile.h @@ -22,14 +22,7 @@ #ifndef __CFGFILE_H #define __CFGFILE_H -int CFG_OpenConfig (const char *cfg_name); -// opens the given config file. only one open config file is -// kept: previosly opened one, if any, will be closed. - -void CFG_CloseConfig (void); -// closes the currently open config file. - -void CFG_ReadCvars (const char **vars, int num_vars); +void CFG_ReadCvars (const char *cfg_name, const char **vars, int num_vars); // reads the values of cvars in the given list from the opened // config file. diff --git a/Quake/cl_demo.c b/Quake/cl_demo.c index a18bd2c16..24e238fe1 100644 --- a/Quake/cl_demo.c +++ b/Quake/cl_demo.c @@ -104,13 +104,12 @@ void CL_StopPlayback (void) if (!cls.demoplayback) return; - fclose (cls.demofile); + QFS_CloseFile (cls.inpdemo); cls.demoplayback = false; cls.demopaused = false; cls.demospeed = 1.f; - cls.demofile = NULL; + cls.inpdemo = NULL; cls.demofilesize = 0; - cls.demofilestart = 0; cls.demofilename[0] = '\0'; cls.state = ca_disconnected; @@ -137,14 +136,14 @@ static void CL_WriteDemoMessage (void) float f; len = LittleLong (net_message.cursize); - fwrite (&len, 4, 1, cls.demofile); + fwrite (&len, 4, 1, cls.outpdemo); for (i = 0; i < 3; i++) { f = LittleFloat (cl.viewangles[i]); - fwrite (&f, 4, 1, cls.demofile); + fwrite (&f, 4, 1, cls.outpdemo); } - fwrite (net_message.data, net_message.cursize, 1, cls.demofile); - fflush (cls.demofile); + fwrite (net_message.data, net_message.cursize, 1, cls.outpdemo); + fflush (cls.outpdemo); } /* @@ -257,7 +256,7 @@ static qboolean CL_NextDemoFrame (void) demoframe_t newframe; memset (&newframe, 0, sizeof (newframe)); - newframe.fileofs = Sys_ftell (cls.demofile); + newframe.fileofs = QFS_Tell (cls.inpdemo); newframe.intermission = cl.intermission; newframe.forceunderwater = cl.forceunderwater; VEC_PUSH (demo_rewind.frames, newframe); @@ -276,7 +275,7 @@ static qboolean CL_NextDemoFrame (void) return false; lastframe = &demo_rewind.frames[framecount - 1]; - Sys_fseek (cls.demofile, lastframe->fileofs, SEEK_SET); + QFS_Seek (cls.inpdemo, lastframe->fileofs, SEEK_SET); if (framecount == 1) demo_rewind.backstop = true; @@ -448,12 +447,12 @@ static int CL_GetDemoMessage (void) if (!CL_NextDemoFrame ()) return 0; - if (fread (&net_message.cursize, 4, 1, cls.demofile) != 1) + if (QFS_ReadFile (cls.inpdemo, &net_message.cursize, 4) != 4) goto readerror; VectorCopy (cl.mviewangles[0], cl.mviewangles[1]); for (i = 0 ; i < 3 ; i++) { - if (fread (&f, 4, 1, cls.demofile) != 1) + if (QFS_ReadFile (cls.inpdemo, &f, 4) != 4) goto readerror; cl.mviewangles[0][i] = LittleFloat (f); } @@ -461,7 +460,7 @@ static int CL_GetDemoMessage (void) net_message.cursize = LittleLong (net_message.cursize); if (net_message.cursize > MAX_MSGLEN) Sys_Error ("Demo message > MAX_MSGLEN"); - if (fread (net_message.data, net_message.cursize, 1, cls.demofile) != 1) + if (QFS_ReadFile (cls.inpdemo, net_message.data, net_message.cursize) != (size_t)net_message.cursize) { readerror: CL_StopPlayback (); @@ -538,8 +537,8 @@ void CL_Stop_f (void) CL_WriteDemoMessage (); // finish up - fclose (cls.demofile); - cls.demofile = NULL; + fclose (cls.outpdemo); + cls.outpdemo = NULL; cls.demorecording = false; Con_Printf ("Completed demo\n"); @@ -629,15 +628,15 @@ void CL_Record_f (void) Con_LinkPrintf (name, "%s", relname); Con_SafePrintf (".\n"); - cls.demofile = Sys_fopen (name, "wb"); - if (!cls.demofile) + cls.outpdemo = Sys_fopen (name, "wb"); + if (!cls.outpdemo) { Con_Printf ("ERROR: couldn't create %s\n", relname); return; } cls.forcetrack = track; - fprintf (cls.demofile, "%i\n", cls.forcetrack); + fprintf (cls.outpdemo, "%i\n", cls.forcetrack); q_strlcpy (cls.demofilename, name, sizeof (cls.demofilename)); cls.demorecording = true; @@ -760,6 +759,7 @@ play [demoname] void CL_PlayDemo_f (void) { char name[MAX_OSPATH]; + char linebuf[32]; if (cmd_source != src_command) return; @@ -779,22 +779,19 @@ void CL_PlayDemo_f (void) Con_Printf ("Playing demo from %s.\n", name); - COM_FOpenFile (name, &cls.demofile, NULL); - if (!cls.demofile) + cls.inpdemo = QFS_FOpenFile (name, NULL); + if (!cls.inpdemo) { Con_Printf ("ERROR: couldn't open %s\n", name); cls.demonum = -1; // stop demo loop return; } -// ZOID, fscanf is evil -// O.S.: if a space character e.g. 0x20 (' ') follows '\n', -// fscanf skips that byte too and screws up further reads. -// fscanf (cls.demofile, "%i\n", &cls.forcetrack); - if (fscanf (cls.demofile, "%i", &cls.forcetrack) != 1 || fgetc (cls.demofile) != '\n') + if (QFS_GetLine (cls.inpdemo, linebuf, sizeof(linebuf)) == 0 + || sscanf (linebuf, "%i", &cls.forcetrack) != 1) { - fclose (cls.demofile); - cls.demofile = NULL; + QFS_CloseFile (cls.inpdemo); + cls.inpdemo = NULL; cls.demonum = -1; // stop demo loop Con_Printf ("ERROR: demo \"%s\" is invalid\n", name); return; @@ -810,8 +807,7 @@ void CL_PlayDemo_f (void) q_strlcpy (cls.demofilename, name, sizeof (cls.demofilename)); cls.state = ca_connected; cls.demoloop = Cmd_Argc () >= 3 ? Q_atoi (Cmd_Argv (2)) != 0 : false; - cls.demofilestart = Sys_ftell (cls.demofile); - cls.demofilesize = com_filesize; + cls.demofilesize = QFS_FileSize (cls.inpdemo); // if this is a player-initiated demo, get rid of the console if (cls.demonum == -1 && key_dest == key_console) @@ -858,7 +854,7 @@ void CL_TimeDemo_f (void) } CL_PlayDemo_f (); - if (!cls.demofile) + if (!cls.inpdemo) return; // cls.td_starttime will be grabbed at the second frame of the demo, so diff --git a/Quake/client.h b/Quake/client.h index 3b36c3f4c..81e10e85e 100644 --- a/Quake/client.h +++ b/Quake/client.h @@ -134,8 +134,8 @@ typedef struct qboolean timedemo; int forcetrack; // -1 = use normal cd track char demofilename[MAX_OSPATH]; - FILE *demofile; - qfileofs_t demofilestart; // for demos in pak files + qfshandle_t *inpdemo; + FILE *outpdemo; qfileofs_t demofilesize; int td_lastframe; // to meter out one message a frame int td_startframe; // host_framecount at start diff --git a/Quake/cmd.c b/Quake/cmd.c index 816ef5003..85f716291 100644 --- a/Quake/cmd.c +++ b/Quake/cmd.c @@ -303,7 +303,7 @@ void Cmd_Exec_f (void) // "exec config.cfg pls" will execute config.cfg if (Cmd_Argc () == 2 && !strcmp (path, "config.cfg")) { - f = (const char *)COM_LoadHunkFile (CONFIG_NAME, NULL); + f = (const char *)QFS_LoadHunkFile (CONFIG_NAME, NULL, NULL); if (f) { path = CONFIG_NAME; @@ -311,7 +311,7 @@ void Cmd_Exec_f (void) } } - f = (const char *)COM_LoadHunkFile (path, NULL); + f = (const char *)QFS_LoadHunkFile (path, NULL, NULL); if (!f && !strcmp(Cmd_Argv(1), "default.cfg")) { f = default_cfg; /* see above.. */ } diff --git a/Quake/common.c b/Quake/common.c index 6ba1a6331..0a6e1e410 100644 --- a/Quake/common.c +++ b/Quake/common.c @@ -29,6 +29,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include "miniz.h" #include "unicode_translit.h" +#include "filesys.h" static const char *largv[MAX_NUM_ARGVS + 1]; static char argvdummy[] = " "; @@ -1436,13 +1437,12 @@ being registered. */ static void COM_CheckRegistered (void) { - int h; unsigned short check[128]; - int i; + size_t i; - COM_OpenFile("gfx/pop.lmp", &h, NULL); + qfshandle_t* h = QFS_OpenFile("gfx/pop.lmp", NULL); - if (h == -1) + if (h == NULL) { Cvar_SetROM ("registered", "0"); Con_Printf ("Playing shareware version.\n"); @@ -1455,9 +1455,9 @@ static void COM_CheckRegistered (void) return; } - i = Sys_FileRead (h, check, sizeof(check)); - COM_CloseFile (h); - if (i != (int) sizeof(check)) + i = QFS_ReadFile (h, check, sizeof(check)); + QFS_CloseFile (h); + if (i != sizeof(check)) goto corrupt; for (i = 0; i < 128; i++) @@ -1605,38 +1605,17 @@ QUAKE FILESYSTEM ============================================================================= */ -THREAD_LOCAL qfileofs_t com_filesize; - - -// -// on-disk pakfile -// -typedef struct -{ - char name[56]; - int filepos, filelen; -} dpackfile_t; - -typedef struct -{ - char id[4]; - int dirofs; - int dirlen; -} dpackheader_t; - -#define MAX_FILES_IN_PACK 2048 - char com_gamenames[1024]; //eg: "hipnotic;quoth;warp" ... no id1 char com_gamedir[MAX_OSPATH]; char com_basedirs[MAX_BASEDIRS][MAX_OSPATH]; int com_numbasedirs; char com_nightdivedir[MAX_OSPATH]; char com_userprefdir[MAX_OSPATH]; -THREAD_LOCAL int file_from_pak; // ZOID: global indicating that file came from a pak searchpath_t *com_searchpaths; searchpath_t *com_base_searchpaths; + /* ============ COM_Path_f @@ -1649,9 +1628,10 @@ static void COM_Path_f (void) Con_Printf ("Current search path:\n"); for (s = com_searchpaths; s; s = s->next) { - if (s->pack) + const char* pack_filename = QFS_PackInfoName (s->pack); + if (pack_filename) { - Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles); + Con_Printf ("%s (%i files)\n", pack_filename, QFS_PackInfoNumFiles (s->pack)); } else Con_Printf ("%s\n", s->filename); @@ -1667,21 +1647,22 @@ The filename will be prefixed by the current game directory */ void COM_WriteFile (const char *filename, const void *data, int len) { - int handle; + FILE* handle; char name[MAX_OSPATH]; q_snprintf (name, sizeof(name), "%s/%s", com_gamedir, filename); - handle = Sys_FileOpenWrite (name); - if (handle == -1) + handle = Sys_fopen (name, "rb"); + if (!handle) { Sys_Printf ("COM_WriteFile: failed on %s\n", name); return; } Sys_Printf ("COM_WriteFile: %s\n", name); - Sys_FileWrite (handle, data, len); - Sys_FileClose (handle); + + fwrite (data, len, 1, handle); + fclose (handle); } /* @@ -1799,261 +1780,6 @@ void COM_CreatePath (char *path) } } -/* -================ -COM_filelength -================ -*/ -qfileofs_t COM_filelength (FILE *f) -{ - qfileofs_t pos, end; - - pos = Sys_ftell (f); - Sys_fseek (f, 0, SEEK_END); - end = Sys_ftell (f); - Sys_fseek (f, pos, SEEK_SET); - - return end; -} - -/* -=========== -COM_FindFile - -Finds the file in the search path. -Sets com_filesize and one of handle or file -If neither of file or handle is set, this -can be used for detecting a file's presence. -=========== -*/ -static int COM_FindFile (const char *filename, int *handle, FILE **file, - unsigned int *path_id) -{ - searchpath_t *search; - char netpath[MAX_OSPATH]; - pack_t *pak; - int i; - - if (file && handle) - Sys_Error ("COM_FindFile: both handle and file set"); - - file_from_pak = 0; - -// -// search through the path, one element at a time -// - for (search = com_searchpaths; search; search = search->next) - { - if (search->pack) /* look through all the pak file elements */ - { - pak = search->pack; - for (i = 0; i < pak->numfiles; i++) - { - if (strcmp(pak->files[i].name, filename) != 0) - continue; - // found it! - com_filesize = pak->files[i].filelen; - file_from_pak = 1; - if (path_id) - *path_id = search->path_id; - if (handle) - { - *handle = pak->handle; - Sys_FileSeek (pak->handle, pak->files[i].filepos); - return com_filesize; - } - else if (file) - { /* open a new file on the pakfile */ - *file = Sys_fopen (pak->filename, "rb"); - if (*file) - fseek (*file, pak->files[i].filepos, SEEK_SET); - return com_filesize; - } - else /* for COM_FileExists() */ - { - return com_filesize; - } - } - } - else /* check a file in the directory tree */ - { - if (!registered.value) - { /* if not a registered version, don't ever go beyond base */ - if ( strchr (filename, '/') || strchr (filename,'\\')) - continue; - } - - q_snprintf (netpath, sizeof(netpath), "%s/%s",search->filename, filename); - if (! (Sys_FileType(netpath) & FS_ENT_FILE)) - continue; - - if (path_id) - *path_id = search->path_id; - if (handle) - { - com_filesize = Sys_FileOpenRead (netpath, &i); - *handle = i; - return com_filesize; - } - else if (file) - { - *file = Sys_fopen (netpath, "rb"); - com_filesize = (*file == NULL) ? -1 : COM_filelength (*file); - return com_filesize; - } - else - { - return 0; /* dummy valid value for COM_FileExists() */ - } - } - } - - if (developer.value) - { - const char *ext = COM_FileGetExtension (filename); - - if (strcmp(ext, "pcx") != 0 && - strcmp(ext, "tga") != 0 && - strcmp(ext, "lit") != 0 && - strcmp(ext, "vis") != 0 && - strcmp(ext, "ent") != 0) - Con_DPrintf ("FindFile: can't find %s\n", filename); - else - Con_DPrintf2 ("FindFile: can't find %s\n", filename); - } - - if (handle) - *handle = -1; - if (file) - *file = NULL; - com_filesize = -1; - return com_filesize; -} - - -/* -=========== -COM_FileExists - -Returns whether the file is found in the quake filesystem. -=========== -*/ -qboolean COM_FileExists (const char *filename, unsigned int *path_id) -{ - int ret = COM_FindFile (filename, NULL, NULL, path_id); - return (ret == -1) ? false : true; -} - -/* -=========== -COM_OpenFile - -filename never has a leading slash, but may contain directory walks -returns a handle and a length -it may actually be inside a pak file -=========== -*/ -int COM_OpenFile (const char *filename, int *handle, unsigned int *path_id) -{ - return COM_FindFile (filename, handle, NULL, path_id); -} - -/* -=========== -COM_FOpenFile - -If the requested file is inside a packfile, a new FILE * will be opened -into the file. -=========== -*/ -int COM_FOpenFile (const char *filename, FILE **file, unsigned int *path_id) -{ - return COM_FindFile (filename, NULL, file, path_id); -} - -/* -============ -COM_CloseFile - -If it is a pak file handle, don't really close it -============ -*/ -void COM_CloseFile (int h) -{ - searchpath_t *s; - - for (s = com_searchpaths; s; s = s->next) - if (s->pack && s->pack->handle == h) - return; - - Sys_FileClose (h); -} - - -/* -============ -COM_LoadFile - -Filename are reletive to the quake directory. -Allways appends a 0 byte. -============ -*/ -#define LOADFILE_HUNK 0 -#define LOADFILE_MALLOC 1 - -byte *COM_LoadFile (const char *path, int usehunk, unsigned int *path_id) -{ - int h; - byte *buf; - char base[32]; - int len, nread; - - buf = NULL; // quiet compiler warning - -// look for it in the filesystem or pack files - len = COM_OpenFile (path, &h, path_id); - if (h == -1) - return NULL; - -// extract the filename base name for hunk tag - COM_FileBase (path, base, sizeof(base)); - - switch (usehunk) - { - case LOADFILE_HUNK: - buf = (byte *) Hunk_AllocNameNoFill (len+1, base); - break; - case LOADFILE_MALLOC: - buf = (byte *) malloc (len+1); - break; - default: - Sys_Error ("COM_LoadFile: bad usehunk"); - } - - if (!buf) - Sys_Error ("COM_LoadFile: not enough space for %s", path); - - ((byte *)buf)[len] = 0; - - nread = Sys_FileRead (h, buf, len); - COM_CloseFile (h); - if (nread != len) - Sys_Error ("COM_LoadFile: Error reading %s", path); - - return buf; -} - -byte *COM_LoadHunkFile (const char *path, unsigned int *path_id) -{ - return COM_LoadFile (path, LOADFILE_HUNK, path_id); -} - -// returns malloc'd memory -byte *COM_LoadMallocFile (const char *path, unsigned int *path_id) -{ - return COM_LoadFile (path, LOADFILE_MALLOC, path_id); -} - byte *COM_LoadMallocFile_TextMode_OSPath (const char *path, long *len_out) { FILE *f; @@ -2068,7 +1794,7 @@ byte *COM_LoadMallocFile_TextMode_OSPath (const char *path, long *len_out) if (f == NULL) return NULL; - len = COM_filelength (f); + len = (long)Sys_filelength (f); if (len < 0) { fclose (f); @@ -2162,87 +1888,6 @@ const char *COM_ParseStringNewline(const char *buffer) return buffer + i; } -/* -================= -COM_LoadPackFile -- johnfitz -- modified based on topaz's tutorial - -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 pack_t *COM_LoadPackFile (const char *packfile) -{ - dpackheader_t header; - int i; - packfile_t *newfiles; - int numpackfiles; - pack_t *pack; - int packhandle; - dpackfile_t info[MAX_FILES_IN_PACK]; - - if (Sys_FileOpenRead (packfile, &packhandle) == -1) - return NULL; - - if (Sys_FileRead(packhandle, &header, sizeof(header)) != (int) sizeof(header) || - header.id[0] != 'P' || header.id[1] != 'A' || header.id[2] != 'C' || header.id[3] != 'K') - Sys_Error ("%s is not a packfile", packfile); - - header.dirofs = LittleLong (header.dirofs); - header.dirlen = LittleLong (header.dirlen); - - numpackfiles = header.dirlen / sizeof(dpackfile_t); - - if (header.dirlen < 0 || header.dirofs < 0) - { - Sys_Error ("Invalid packfile %s (dirlen: %i, dirofs: %i)", - packfile, header.dirlen, header.dirofs); - } - if (!numpackfiles) - { - Sys_Printf ("WARNING: %s has no files, ignored\n", packfile); - Sys_FileClose (packhandle); - return NULL; - } - if (numpackfiles > MAX_FILES_IN_PACK) - Sys_Error ("%s has %i files", packfile, numpackfiles); - - if (numpackfiles != PAK0_COUNT) - com_modified = true; // not the original file - - newfiles = (packfile_t *) Z_Malloc(numpackfiles * sizeof(packfile_t)); - - Sys_FileSeek (packhandle, header.dirofs); - if (Sys_FileRead(packhandle, info, header.dirlen) != header.dirlen) - Sys_Error ("Error reading %s", packfile); - - // crc the directory to check for modifications - if (!com_modified) - { - unsigned short crc = CRC_Block (info, header.dirlen); - if (crc != PAK0_CRC_V106 && crc != PAK0_CRC_V101 && crc != PAK0_CRC_V100) - com_modified = true; - } - - // parse the directory - for (i = 0; i < numpackfiles; i++) - { - q_strlcpy (newfiles[i].name, info[i].name, sizeof(newfiles[i].name)); - newfiles[i].filepos = LittleLong(info[i].filepos); - newfiles[i].filelen = LittleLong(info[i].filelen); - } - - pack = (pack_t *) Z_Malloc (sizeof (pack_t)); - q_strlcpy (pack->filename, packfile, sizeof(pack->filename)); - pack->handle = packhandle; - pack->numfiles = numpackfiles; - pack->files = newfiles; - - //Sys_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles); - return pack; -} - const char *COM_GetGameNames(qboolean full) { if (full) @@ -2253,7 +1898,6 @@ const char *COM_GetGameNames(qboolean full) return GAMENAME; } return com_gamenames; -// return COM_SkipPath(com_gamedir); } /* @@ -2265,19 +1909,19 @@ static void COM_AddEnginePak (void) { int i; char pakfile[MAX_OSPATH]; - pack_t *pak = NULL; + int pak = 0; qboolean modified = com_modified; if (host_parms->exedir) { q_snprintf (pakfile, sizeof(pakfile), "%s/" ENGINE_PAK, host_parms->exedir); - pak = COM_LoadPackFile (pakfile); + pak = QFS_LoadPackFile (pakfile); } if (!pak) { q_snprintf (pakfile, sizeof(pakfile), "%s/" ENGINE_PAK, host_parms->basedir); - pak = COM_LoadPackFile (pakfile); + pak = QFS_LoadPackFile (pakfile); } if (!pak) @@ -2285,7 +1929,7 @@ static void COM_AddEnginePak (void) for (i = 0; i < com_numbasedirs; i++) { q_snprintf (pakfile, sizeof(pakfile), "%s/" ENGINE_PAK, com_basedirs[i]); - pak = COM_LoadPackFile (pakfile); + pak = QFS_LoadPackFile (pakfile); if (pak) break; } @@ -2311,11 +1955,12 @@ COM_AddGameDirectory -- johnfitz -- modified based on topaz's tutorial void COM_AddGameDirectory (const char *dir) { const char *base; - int i, j; + int i, j, k; unsigned int path_id; searchpath_t *search; - pack_t *pak; + int pak = 0; char pakfile[MAX_OSPATH]; + static const char* pkext[2] = { "pak", "pk3" }; if (*com_gamenames) q_strlcat(com_gamenames, ";", sizeof(com_gamenames)); @@ -2353,11 +1998,18 @@ void COM_AddGameDirectory (const char *dir) search->next = com_searchpaths; com_searchpaths = search; - // add any pak files in the format pak0.pak pak1.pak, ... + // add any pak files (or pk3 files) in the format pak0.pak pak1.pak, ... + // pak files and pk3 files can not have the same number, if it exists + // with both extensions, the pak file will be used and the pk3 file ignored for (i = 0; ; i++) { - q_snprintf (pakfile, sizeof(pakfile), "%s/pak%i.pak", com_gamedir, i); - pak = COM_LoadPackFile (pakfile); + for (k = 0; k < countof(pkext); ++k) + { + q_snprintf (pakfile, sizeof(pakfile), "%s/pak%i.%s", com_gamedir, i, pkext[k]); + pak = QFS_LoadPackFile (pakfile); + if (pak) + break; + } if (!pak) break; @@ -2382,11 +2034,8 @@ void COM_ResetGameDirectories(const char *newgamedirs) while (com_searchpaths != com_base_searchpaths) { if (com_searchpaths->pack) - { - Sys_FileClose (com_searchpaths->pack->handle); - Z_Free (com_searchpaths->pack->files); - Z_Free (com_searchpaths->pack); - } + QFS_FreePack(com_searchpaths->pack); + search = com_searchpaths->next; Z_Free (com_searchpaths); com_searchpaths = search; @@ -3247,176 +2896,6 @@ void COM_InitFilesystem (void) //johnfitz -- modified based on topaz's tutorial COM_CheckRegistered (); } - -/* The following FS_*() stdio replacements are necessary if one is - * to perform non-sequential reads on files reopened on pak files - * because we need the bookkeeping about file start/end positions. - * Allocating and filling in the fshandle_t structure is the users' - * responsibility when the file is initially opened. */ - -size_t FS_fread(void *ptr, size_t size, size_t nmemb, fshandle_t *fh) -{ - long byte_size; - long bytes_read; - size_t nmemb_read; - - if (!fh) { - errno = EBADF; - return 0; - } - if (!ptr) { - errno = EFAULT; - return 0; - } - if (!size || !nmemb) { /* no error, just zero bytes wanted */ - errno = 0; - return 0; - } - - byte_size = nmemb * size; - if (byte_size > fh->length - fh->pos) /* just read to end */ - byte_size = fh->length - fh->pos; - bytes_read = fread(ptr, 1, byte_size, fh->file); - fh->pos += bytes_read; - - /* fread() must return the number of elements read, - * not the total number of bytes. */ - nmemb_read = bytes_read / size; - /* even if the last member is only read partially - * it is counted as a whole in the return value. */ - if (bytes_read % size) - nmemb_read++; - - return nmemb_read; -} - -int FS_fseek(fshandle_t *fh, long offset, int whence) -{ -/* I don't care about 64 bit off_t or fseeko() here. - * the quake/hexen2 file system is 32 bits, anyway. */ - int ret; - - if (!fh) { - errno = EBADF; - return -1; - } - - /* the relative file position shouldn't be smaller - * than zero or bigger than the filesize. */ - switch (whence) - { - case SEEK_SET: - break; - case SEEK_CUR: - offset += fh->pos; - break; - case SEEK_END: - offset = fh->length + offset; - break; - default: - errno = EINVAL; - return -1; - } - - if (offset < 0) { - errno = EINVAL; - return -1; - } - - if (offset > fh->length) /* just seek to end */ - offset = fh->length; - - ret = fseek(fh->file, fh->start + offset, SEEK_SET); - if (ret < 0) - return ret; - - fh->pos = offset; - return 0; -} - -int FS_fclose(fshandle_t *fh) -{ - if (!fh) { - errno = EBADF; - return -1; - } - return fclose(fh->file); -} - -long FS_ftell(fshandle_t *fh) -{ - if (!fh) { - errno = EBADF; - return -1; - } - return fh->pos; -} - -void FS_rewind(fshandle_t *fh) -{ - if (!fh) return; - clearerr(fh->file); - fseek(fh->file, fh->start, SEEK_SET); - fh->pos = 0; -} - -int FS_feof(fshandle_t *fh) -{ - if (!fh) { - errno = EBADF; - return -1; - } - if (fh->pos >= fh->length) - return -1; - return 0; -} - -int FS_ferror(fshandle_t *fh) -{ - if (!fh) { - errno = EBADF; - return -1; - } - return ferror(fh->file); -} - -int FS_fgetc(fshandle_t *fh) -{ - if (!fh) { - errno = EBADF; - return EOF; - } - if (fh->pos >= fh->length) - return EOF; - fh->pos += 1; - return fgetc(fh->file); -} - -char *FS_fgets(char *s, int size, fshandle_t *fh) -{ - char *ret; - - if (FS_feof(fh)) - return NULL; - - if (size > (fh->length - fh->pos) + 1) - size = (fh->length - fh->pos) + 1; - - ret = fgets(s, size, fh->file); - fh->pos = ftell(fh->file) - fh->start; - - return ret; -} - -long FS_filelength (fshandle_t *fh) -{ - if (!fh) { - errno = EBADF; - return -1; - } - return fh->length; -} - /* ============================================================================ LOCALIZATION diff --git a/Quake/common.h b/Quake/common.h index 4b4a48525..a94163a5b 100644 --- a/Quake/common.h +++ b/Quake/common.h @@ -115,8 +115,8 @@ typedef struct sizebuf_s qboolean allowoverflow; // if false, do a Sys_Error qboolean overflowed; // set to true if the buffer size failed byte *data; - int maxsize; - int cursize; + int32_t maxsize; + int32_t cursize; } sizebuf_t; void SZ_Alloc (sizebuf_t *buf, int startsize); @@ -205,10 +205,10 @@ static inline void ToggleBit (uint32_t *arr, uint32_t i) #define host_bigendian 0 #endif -#define BigShort(s) ((short)SDL_SwapBE16((s))) -#define LittleShort(s) ((short)SDL_SwapLE16((s))) -#define BigLong(l) ((int)SDL_SwapBE32((l))) -#define LittleLong(l) ((int)SDL_SwapLE32((l))) +#define BigShort(s) ((int16_t)SDL_SwapBE16((s))) +#define LittleShort(s) ((int16_t)SDL_SwapLE16((s))) +#define BigLong(l) ((int32_t)SDL_SwapBE32((l))) +#define LittleLong(l) ((int32_t)SDL_SwapLE32((l))) #define BigFloat(f) SDL_SwapFloatBE((f)) #define LittleFloat(f) SDL_SwapFloatLE((f)) @@ -360,34 +360,19 @@ size_t UTF8_ToQuake (char *dst, size_t maxbytes, const char *src); //============================================================================ // QUAKEFS -typedef struct -{ - char name[MAX_QPATH]; - int filepos, filelen; -} packfile_t; - -typedef struct pack_s -{ - char filename[MAX_OSPATH]; - int handle; - int numfiles; - packfile_t *files; -} pack_t; - typedef struct searchpath_s { unsigned int path_id; // identifier assigned to the game directory // Note that /game1 and // /game1 have the same id. char filename[MAX_OSPATH]; - pack_t *pack; // only one of filename / pack will be used + int pack; // only one of filename / pack will be used struct searchpath_s *next; } searchpath_t; extern searchpath_t *com_searchpaths; extern searchpath_t *com_base_searchpaths; -extern THREAD_LOCAL qfileofs_t com_filesize; struct cache_user_s; #define MAX_BASEDIRS 64 @@ -396,22 +381,9 @@ extern int com_numbasedirs; extern char com_basedirs[MAX_BASEDIRS][MAX_OSPATH]; extern char com_gamedir[MAX_OSPATH]; extern char com_nightdivedir[MAX_OSPATH]; -extern THREAD_LOCAL int file_from_pak; // global indicating that file came from a pak void COM_WriteFile (const char *filename, const void *data, int len); qboolean COM_WriteFile_OSPath (const char *filename, const void *data, size_t len); -int COM_OpenFile (const char *filename, int *handle, unsigned int *path_id); -int COM_FOpenFile (const char *filename, FILE **file, unsigned int *path_id); -qboolean COM_FileExists (const char *filename, unsigned int *path_id); -void COM_CloseFile (int h); - -// these procedures open a file using COM_FindFile and loads it into a proper -// buffer. the buffer is allocated with a total size of com_filesize + 1. the -// procedures differ by their buffer allocation method. -byte *COM_LoadHunkFile (const char *path, unsigned int *path_id); - // allocates the buffer on the hunk. -byte *COM_LoadMallocFile (const char *path, unsigned int *path_id); - // allocates the buffer on the system mem (malloc). // Opens the given path directly, ignoring search paths. // Returns NULL on failure, or else a '\0'-terminated malloc'ed buffer. @@ -439,33 +411,6 @@ const char *COM_ParseStringNewline(const char *buffer); #define FS_ENT_FILE (1 << 0) #define FS_ENT_DIRECTORY (1 << 1) -/* The following FS_*() stdio replacements are necessary if one is - * to perform non-sequential reads on files reopened on pak files - * because we need the bookkeeping about file start/end positions. - * Allocating and filling in the fshandle_t structure is the users' - * responsibility when the file is initially opened. */ - -typedef struct _fshandle_t -{ - FILE *file; - qboolean pak; /* is the file read from a pak */ - long start; /* file or data start position */ - long length; /* file or data size */ - long pos; /* current position relative to start */ -} fshandle_t; - -size_t FS_fread(void *ptr, size_t size, size_t nmemb, fshandle_t *fh); -int FS_fseek(fshandle_t *fh, long offset, int whence); -long FS_ftell(fshandle_t *fh); -void FS_rewind(fshandle_t *fh); -int FS_feof(fshandle_t *fh); -int FS_ferror(fshandle_t *fh); -int FS_fclose(fshandle_t *fh); -int FS_fgetc(fshandle_t *fh); -char *FS_fgets(char *s, int size, fshandle_t *fh); -long FS_filelength (fshandle_t *fh); - - extern struct cvar_s registered; extern qboolean standard_quake, rogue, hipnotic; extern qboolean fitzmode; diff --git a/Quake/filesys.c b/Quake/filesys.c new file mode 100644 index 000000000..cdd7beb2d --- /dev/null +++ b/Quake/filesys.c @@ -0,0 +1,1047 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2010-2014 QuakeSpasm developers +Copyright (C) 2024-2024 ironwail developers + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +/* +Implementation of the Quake File System, a virtual file system that can read +contents from pack files or file system files in the search directories. + +Supported pack files are: + + *Regular Quake .pak files that the original Quake supports + + *Quake 3 .pk3 files (zip files with a different extension). + + This support is limited to either zip entries compressed with + the regular DEFLATE method of zip files, or uncompressed entries. +*/ +#include "quakedef.h" +#include "filesys.h" +#include "miniz.h" + +typedef struct +{ + char name[MAX_QPATH]; + int filepos, filelen; +} packfile_t; + +typedef struct file_handle_s +{ + void *data; + void *impl_data; + int fileno; + qboolean owns_data; + qboolean from_pak; + qfileofs_t offs; + qfileofs_t pak_offset; + qfileofs_t start, endtrim; + qfileofs_t (*filesize)(struct file_handle_s *handle); + size_t (*read)(struct file_handle_s *handle, void* buf, size_t sz); + void (*close)(struct file_handle_s *handle); + int (*seek)(struct file_handle_s *handle, qfileofs_t pos); +} qfshandle_t; + +typedef struct pack_s +{ + FILE* handle; + char filename[MAX_OSPATH]; + int numfiles; + packfile_t *files; + void* impl_data; + int pakver; + qfshandle_t* (*open_file)(const struct pack_s* pack, int idx, qboolean reopen_pack); +} pack_t; +// on-disk pakfile +// +typedef struct +{ + char name[56]; + int filepos, filelen; +} dpackfile_t; + +typedef struct +{ + char id[4]; + int dirofs; + int dirlen; +} dpackheader_t; + +#define MAX_FILES_IN_PACK 2048 +#define MAX_PACK_FILES 32 + +//Loaded pack files (.pak or .pk3) +//Index 0 is just a placeholder so 0 can be used to indicate error. First pack is loaded at index 1. +static pack_t* packs[1 + MAX_PACK_FILES] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +/* +================= +QFS_FreePackHandle + +Close a pack file and free the data. +================= +*/ +static void QFS_FreePackHandle (pack_t *pack) +{ + if (pack != NULL) + { + fclose (pack->handle); + if (pack->impl_data) + { + if (pack->pakver == 3) + mz_zip_reader_end ((mz_zip_archive*)pack->impl_data); + free(pack->impl_data); + } + if (pack->files) + free (pack->files); + free (pack); + } +} + +/* +================= +QFS_RegisterPack + +Add a pack to the program-wide array of packs. +Will return 0 if the array is already full and the pack +is closed and freed. +================= +*/ +static int QFS_RegisterPack (pack_t *pack) +{ + for (size_t i = 1; i < countof(packs); ++i) + { + if (packs[i] == NULL) + { + packs[i] = pack; + return (int)i; + } + } + QFS_FreePackHandle (pack); + + Sys_Printf ("WARNING: Too many pack files loaded."); + return 0; +} + + +static void QFS_CheckHandle (qfshandle_t* handle) +{ + if (handle == NULL || handle->data == NULL) + Sys_Error ("Attempting to read from invalid file handle"); +} + +static void* QFS_Alloc (size_t sz) +{ + void *palloc = calloc (1, sz); + if (palloc == NULL) + Sys_Error ("QFS_Alloc of size %" SDL_PRIu64 " failed.", (uint64_t)sz); + + return palloc; +} + +static qfshandle_t* QFS_AllocHandle (void) +{ + return (qfshandle_t *)QFS_Alloc (sizeof(qfshandle_t)); +} + +/*============ +FS_* +file_handle_t implementation functions for regular disk files +============ +*/ +static void FS_Close (qfshandle_t* handle) +{ + if (handle) + { + if (handle->owns_data) + fclose ((FILE*)handle->data); + free (handle); + } +} + +static size_t FS_Read(qfshandle_t* handle, void* buf, size_t sz) +{ + QFS_CheckHandle (handle); + + sz = fread (buf, 1, sz, (FILE*)handle->data); + handle->offs += sz; + return sz; +} + +static qfileofs_t FS_FileSize (qfshandle_t* handle) +{ + return Sys_filelength ((FILE*)handle->data); +} + +int FS_Seek(qfshandle_t* handle, qfileofs_t pos) +{ + return Sys_fseek ((FILE*)handle->data, pos, SEEK_SET); +} + +static qfshandle_t* FS_Open (const char* filename) +{ + FILE *stdio_handle = fopen (filename, "rb"); + if (stdio_handle == NULL) + return NULL; + + qfshandle_t* handle = QFS_AllocHandle (); + if (handle) + { + handle->data = stdio_handle; + handle->close = &FS_Close; + handle->read = &FS_Read; + handle->filesize = &FS_FileSize; + handle->seek = &FS_Seek; + handle->owns_data = true; + } + return handle; +} + +/* +============ +PAK_* +qfshandle_t implementation functions for PAK file content files +============ +*/ +static void PAK_Close (qfshandle_t* handle) +{ + if (handle) + { + if (handle->owns_data) + { + pack_t* pack = (pack_t*)handle->data; + pack->files = NULL; + QFS_FreePackHandle (pack); + } + if (handle->impl_data) + free (handle->impl_data); + free (handle); + } +} + +static size_t PAK_Read (qfshandle_t* handle, void* buf, size_t sz) +{ + pack_t* pack; + qfileofs_t actualofs; + size_t filesize; + + QFS_CheckHandle (handle); + pack = (pack_t*)handle->data; + actualofs = handle->offs + handle->start; + + filesize = (size_t)handle->filesize(handle); + if (actualofs + sz > filesize) + sz = filesize - (size_t)actualofs; + + if (sz > 0 && Sys_fseek (pack->handle, handle->pak_offset + handle->offs + handle->start, SEEK_SET) == 0) + { + sz = fread (buf, 1, sz, pack->handle); + handle->offs += sz; + } + + return sz; +} + +static qfileofs_t PAK_FileSize (qfshandle_t* handle) +{ + pack_t* pack = (pack_t*)handle->data; + return pack->files[handle->fileno].filelen; +} + +int PAK_Seek(qfshandle_t* handle, qfileofs_t pos) +{ + handle->offs = pos; + return 0; +} + +static qfshandle_t* PAK_Open(const pack_t* pack, int idx, qboolean reopen_pack) +{ + qfshandle_t *handle = QFS_AllocHandle (); + handle->fileno = idx; + handle->close = &PAK_Close; + handle->read = &PAK_Read; + handle->filesize = &PAK_FileSize; + handle->seek = &PAK_Seek; + + if (reopen_pack) + { + //This will create a shallow copy that doesn't copy all the file + //entries, but references the original. This should be fine + handle->owns_data = true; + pack_t* newpack = (pack_t*)QFS_Alloc (sizeof(pack_t)); + *newpack = *pack; + newpack->handle = fopen (pack->filename, "rb"); + if (newpack->handle == NULL) + Sys_Error ("%s failed to reopen.", pack->filename); + handle->data = newpack; + } + else + { + handle->data = (void*)pack; + } + + //Position PAK at the selected file + pack_t* refpack = (pack_t*)handle->data; + handle->pak_offset = refpack->files[idx].filepos; + return handle; +} + +/* +============ +ZIP_* +qfshandle_t implementation functions for pk3 (zip) file content files +============ +*/ + +typedef struct +{ + byte* inbuf; + byte* outbuf; + qfileofs_t foffs_in, foffs_out; + size_t bsz_in, bsz_out; //Max buffer sizes + size_t readsz_in; //Valid data in input buffer + size_t p_out; //Bytes already read from the out buffer + size_t p_in; //Bytes already consumed from input buffer + size_t out_read_ptr; //indicates how much of the out buffer has been read by user + qboolean eof_flag; //End reached on deflate stream + mz_zip_archive_file_stat stat; + tinfl_decompressor infl; +} +inflbuffers_t; + +static size_t ZIP_LowLevelRead (void *opaque, mz_uint64 ofs, void *buf, size_t n) +{ + FILE *handle = (FILE*)opaque; + + if (ofs > LONG_MAX || Sys_fseek (handle, ofs, SEEK_SET) != 0) + Sys_Error ("Invalid read of at offset %" SDL_PRIu64, (uint64_t)n); + + return fread (buf, 1, n, handle); +} + +static void ZIP_Close (qfshandle_t* handle) +{ + inflbuffers_t* zip = (inflbuffers_t*)handle->impl_data; + handle->impl_data = NULL; + if (zip) + { + if (zip->inbuf) + free (zip->inbuf); + if (zip->outbuf) + free (zip->outbuf); + free (zip); + } + + PAK_Close (handle); +} + +static size_t ZIP_Read (qfshandle_t* handle, void* buf, size_t sz) +{ + inflbuffers_t *p = (inflbuffers_t*)handle->impl_data; + pack_t *pack = (pack_t*)handle->data; + mz_zip_archive *z = (mz_zip_archive*)pack->impl_data; + + if (p->stat.m_is_directory || p->stat.m_uncomp_size == 0 || sz == 0 ) + { + return 0; + } + + byte* outbuf = (byte*)buf; + size_t rd = 0; + + tinfl_status status = TINFL_STATUS_DONE; + for (;;) + { + if (p->p_out >= p->bsz_out || p->eof_flag) + { + size_t ncpy = q_min (p->p_out - p->out_read_ptr, sz - rd); + if (outbuf != NULL) + { + memcpy (outbuf, p->outbuf + p->out_read_ptr, ncpy); + outbuf += ncpy; + } + rd += ncpy; + p->out_read_ptr += ncpy; + + handle->offs += ncpy; + + if (p->out_read_ptr >= p->p_out) + p->out_read_ptr = p->p_out = 0; + + if (rd >= sz || p->p_out == 0 && p->eof_flag) + return rd; + } + + if (p->p_in >= p->readsz_in) + { + size_t sz = (size_t)q_min ((qfileofs_t)p->bsz_in, p->stat.m_comp_size - p->foffs_in); + p->readsz_in = z->m_pRead (z->m_pIO_opaque, + (mz_uint64)(handle->pak_offset + p->foffs_in), + p->inbuf, sz); + + if (p->readsz_in != sz) + Sys_Error ("File I/O error on %s", pack->filename); + + p->p_in = 0; + p->foffs_in += p->readsz_in; + } + + size_t szin = p->readsz_in - p->p_in, szout = p->bsz_out - p->p_out; + + status = tinfl_decompress (&p->infl, + (mz_uint8*)p->inbuf + p->p_in, &szin, + (mz_uint8*)p->outbuf, + (mz_uint8*)p->outbuf + p->p_out, &szout, + (qfileofs_t)p->stat.m_comp_size >= p->foffs_in ? TINFL_FLAG_HAS_MORE_INPUT : 0 | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + + p->p_in += szin; + p->p_out += szout; + p->foffs_out += szout; + p->eof_flag = status == TINFL_STATUS_DONE; + + if (status < TINFL_STATUS_DONE) + Sys_Error ("Failed to inflate %s in %s", p->stat.m_filename, pack->filename); + } +} + +int ZIP_Seek(qfshandle_t* handle, qfileofs_t pos) +{ + inflbuffers_t *p = (inflbuffers_t*)handle->impl_data; + qfileofs_t buf_start = handle->offs - (qfileofs_t)p->out_read_ptr; + + if (pos >= buf_start && pos - buf_start <= (qfileofs_t)p->p_out) + { + //good, we're still inside our deflate output + p->out_read_ptr = (size_t)(pos - buf_start); + return 0; + } + else if (pos > buf_start + (qfileofs_t)p->p_out) + { + //We need to skip forward + size_t skipcnt = (size_t)(pos - handle->offs); + return ZIP_Read (handle, NULL, skipcnt) == skipcnt ? 0 : -1; + } + else + { + //Start from the beginning + p->out_read_ptr = p->p_out = p->readsz_in = 0; + p->foffs_out = p->foffs_in = handle->offs = 0; + p->eof_flag = false; + tinfl_init (&p->infl); + return ZIP_Read (handle, NULL, (size_t)pos) == (size_t)pos ? 0 : -1; + } +} + +static qfshandle_t* ZIP_Open (const pack_t* pack, int idx, qboolean reopen_pack) +{ + const pack_t* refpack = pack; + uint32_t local_header1 = 0; + uint16_t local_header2[2]; + qfshandle_t *handle = PAK_Open (pack, idx, reopen_pack); + + handle->close = &ZIP_Close; + + inflbuffers_t *zip = (inflbuffers_t*)QFS_Alloc (sizeof(inflbuffers_t)); + + if (reopen_pack) + { + mz_zip_archive** za = (mz_zip_archive**)&pack->impl_data; + *za = (mz_zip_archive*)QFS_Alloc (sizeof(mz_zip_archive)); + (*za)->m_pRead = ZIP_LowLevelRead; + (*za)->m_pIO_opaque = refpack->handle; + handle->owns_data = true; + + if (!mz_zip_reader_init (*za, Sys_filelength (refpack->handle), 0)) + Sys_Error ("%s failed to reopen.", refpack->filename); + } + + mz_zip_archive* arch = (mz_zip_archive*)pack->impl_data; + + mz_zip_reader_file_stat (arch, refpack->files[idx].filepos, &zip->stat); + if (!zip->stat.m_is_supported) + Sys_Error("Unsupported zip file entry %s", refpack->files[idx].name); + + if (arch->m_pRead(arch->m_pIO_opaque, zip->stat.m_local_header_ofs, &local_header1, sizeof(local_header1)) != sizeof(local_header1) + || SDL_SwapLE32(local_header1) != 0x04034b50 + || arch->m_pRead(arch->m_pIO_opaque, zip->stat.m_local_header_ofs + 26, &local_header2, sizeof(local_header2)) != sizeof(local_header2)) + { + Sys_Error ("Truncated or corrupt directory entry in %s", pack->filename); + } + + handle->pak_offset = zip->stat.m_local_header_ofs + 30 + + SDL_SwapLE16 (local_header2[0]) + + SDL_SwapLE16 (local_header2[1]); + + if (handle->pak_offset + zip->stat.m_comp_size > arch->m_archive_size) + Sys_Error ("Truncated zip file %s", pack->filename); + + if (zip->stat.m_method) + { + handle->impl_data = zip; + + zip->bsz_in = q_min ((size_t)zip->stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE / 2); + zip->inbuf = (byte*)malloc(zip->bsz_in); + + zip->bsz_out = MZ_ZIP_MAX_IO_BUF_SIZE; + zip->outbuf = (byte*)malloc (zip->bsz_out); + + tinfl_init (&zip->infl); + handle->read = &ZIP_Read; + handle->seek = &ZIP_Seek; + } + else + { + //An uncompressed zip entry - we can just read with the + //regular PAK read functions + handle->read = &PAK_Read; + handle->seek = &PAK_Seek; + free (zip); + } + + return handle; +} + +/* +================= +QFS_GetPack + +Get the pack with the specified number, or NULL of there is none. +If parameter unregister is set, it will be removed from the +program wide list and the caller becomes the new owner. +================= +*/ +static pack_t* QFS_GetPack (int num, qboolean unregister) +{ + if (num > 0 && num < MAX_PACK_FILES) + { + pack_t* pack = packs[num]; + if (unregister) + packs[num] = NULL; + return pack; + } + return NULL; +} + +const char* QFS_PackInfoName (int packid) +{ + pack_t* pack = QFS_GetPack (packid, false); + return pack ? pack->filename : NULL; +} + +int QFS_PackInfoNumFiles (int packid) +{ + pack_t* pack = QFS_GetPack (packid, false); + return pack ? pack->numfiles : 0; +} + +void QFS_FreePack (int packid) +{ + pack_t* pack = QFS_GetPack (packid, true); + QFS_FreePackHandle (pack); +} + +void QFS_Shutdown (void) +{ + for (size_t i = 1; i < countof(packs); ++i) + { + if (packs[i] != NULL) + { + QFS_FreePackHandle(packs[i]); + packs[i] = NULL; + } + } +} + +qfileofs_t QFS_PackInfoEntrySize (int packid, int idx) +{ + pack_t* pack = QFS_GetPack (packid, false); + if (pack && idx >= 0 && idx < pack->numfiles) + return pack->files[idx].filelen; + + return 0; +} + +const char* QFS_PackInfoEntryName (int packid, int idx) +{ + pack_t* pack = QFS_GetPack (packid, false); + if (pack && idx >= 0 && idx < pack->numfiles) + return pack->files[idx].name; + + return NULL; +} +/* +================= +QFS_LoadPAKFile -- johnfitz -- modified based on topaz's tutorial + +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. +================= +*/ +/* +================= +QFS_LoadPAKFile -- johnfitz -- modified based on topaz's tutorial + +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 int QFS_LoadPAKFile (const char *packfile) +{ + dpackheader_t header; + int i; + packfile_t *newfiles; + int numpackfiles; + pack_t *pack; + FILE *packhandle; + dpackfile_t info[MAX_FILES_IN_PACK]; + + packhandle = fopen(packfile, "rb"); + if (packhandle == NULL) + return 0; + + if (fread(&header, 1, sizeof(header), packhandle) != sizeof(header) || + header.id[0] != 'P' || header.id[1] != 'A' || header.id[2] != 'C' || header.id[3] != 'K') + Sys_Error ("%s is not a packfile", packfile); + + header.dirofs = (header.dirofs); + header.dirlen = (header.dirlen); + + numpackfiles = header.dirlen / sizeof(dpackfile_t); + + if (header.dirlen < 0 || header.dirofs < 0) + { + Sys_Error ("Invalid packfile %s (dirlen: %i, dirofs: %i)", + packfile, header.dirlen, header.dirofs); + } + if (!numpackfiles) + { + printf ("WARNING: %s has no files, ignored\n", packfile); + fclose (packhandle); + return 0; + } + if (numpackfiles > MAX_FILES_IN_PACK) + Sys_Error ("%s has %i files", packfile, numpackfiles); + + newfiles = (packfile_t *) QFS_Alloc(numpackfiles * sizeof(packfile_t)); + + fseek (packhandle, header.dirofs, SEEK_SET); + if ((int)fread(info, 1, header.dirlen, packhandle) != header.dirlen) + Sys_Error ("Error reading %s", packfile); + + // parse the directory + for (i = 0; i < numpackfiles; i++) + { + q_strlcpy (newfiles[i].name, info[i].name, sizeof(newfiles[i].name)); + newfiles[i].filepos = (info[i].filepos); + newfiles[i].filelen = (info[i].filelen); + } + + pack = (pack_t *) QFS_Alloc(sizeof (pack_t)); + q_strlcpy (pack->filename, packfile, sizeof(pack->filename)); + pack->handle = packhandle; + pack->numfiles = numpackfiles; + pack->files = newfiles; + pack->open_file = &PAK_Open; + pack->pakver = 1; + + return QFS_RegisterPack (pack); +} + +static int QFS_LoadPK3File(const char *packfile) +{ + mz_zip_archive *pk3; + FILE *pk3handle; + mz_uint i, numpackfiles; + packfile_t *newfiles; + + pk3handle = fopen (packfile, "rb"); + if (!pk3handle) + return 0; + + pk3 = (mz_zip_archive*)QFS_Alloc (sizeof(mz_zip_archive)); + pk3->m_pRead = ZIP_LowLevelRead; + pk3->m_pIO_opaque = pk3handle; + char buf[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + + if (!mz_zip_reader_init (pk3, (mz_uint64)Sys_filelength (pk3handle), 0)) + Sys_Error("%s can not be opened as a .pk3 file.", packfile); + + mz_uint entrycount = pk3->m_total_files; + if (!entrycount) + { + printf("WARNING: %s has no files, ignored\n", packfile); + fclose(pk3handle); + free(pk3); + return 0; + } + + newfiles = (packfile_t *)QFS_Alloc(entrycount * sizeof(packfile_t)); + + for (i = 0, numpackfiles = 0; i < entrycount; ++i) + { + mz_uint len = mz_zip_reader_get_filename (pk3, i, buf, countof(buf)); + if (len >= sizeof(newfiles[numpackfiles].name)) + Sys_Error ("File name %s in %s exceeds maximum allowed length.", buf, packfile); + + mz_zip_archive_file_stat st; + if (!mz_zip_reader_file_stat(pk3, i, &st)) + Sys_Error ("Failed to get status of %s in %s.", buf, packfile); + + if (!st.m_is_directory) + { + if (st.m_uncomp_size > INT_MAX) + Sys_Error("File %s in %s is too large.", buf, packfile); + + newfiles[numpackfiles].filelen = (int)st.m_uncomp_size; + newfiles[numpackfiles].filepos = (int)st.m_file_index; + + q_strlcpy (newfiles[numpackfiles].name, buf, sizeof(newfiles[numpackfiles].name)); + ++numpackfiles; + } + } + + pack_t* pack = (pack_t*) QFS_Alloc(sizeof(pack_t)); + q_strlcpy(pack->filename, packfile, sizeof(pack->filename)); + pack->handle = pk3handle; + pack->numfiles = numpackfiles; + pack->files = newfiles; + pack->open_file = &ZIP_Open; + pack->impl_data = pk3; + pack->pakver = 3; + + return QFS_RegisterPack (pack); +} + +int QFS_LoadPackFile(const char *packfile) +{ + if (q_strcasecmp (COM_FileGetExtension (packfile), "pk3") == 0) + return QFS_LoadPK3File (packfile); + else + return QFS_LoadPAKFile (packfile); +} + +/* +=========== +QFS_FindFile + +Finds the file in the search path. +Sets file to a new file handle, if reopen is true and file is in a pak, +a new handle to the pak will be opened. +If file is not set, it can be used for detecting a file's presence. +=========== +*/ +static qfileofs_t QFS_FindFile (const char *filename, qfshandle_t** file, qboolean reopen, unsigned int *path_id) +{ + searchpath_t *search; + char netpath[MAX_OSPATH]; + pack_t *pak; + int i; + + if (file) + *file = NULL; +// +// search through the path, one element at a time +// + for (search = com_searchpaths; search; search = search->next) + { + if (search->pack) /* look through all the pak file elements */ + { + pak = QFS_GetPack (search->pack, false); + if (!pak) + Sys_Error ("QFS_FindFile: invalid pack id."); + + for (i = 0; i < pak->numfiles; i++) + { + if (strcmp(pak->files[i].name, filename) != 0) + continue; + // found it! + if (path_id) + *path_id = search->path_id; + + if (file) + *file = pak->open_file(pak, i, reopen); + + return pak->files[i].filelen; + } + } + else /* check a file in the directory tree */ + { + if (!registered.value) + { /* if not a registered version, don't ever go beyond base */ + if ( strchr (filename, '/') || strchr (filename,'\\')) + continue; + } + + q_snprintf (netpath, sizeof(netpath), "%s/%s",search->filename, filename); + if (! (Sys_FileType(netpath) & FS_ENT_FILE)) + continue; + + if (path_id) + *path_id = search->path_id; + + if (file) + { + *file = FS_Open (netpath); + if (*file == NULL) + return -1; + return Sys_filelength ((FILE*)(*file)->data); + } + else + { + return 0; /* dummy valid value for QFS_FileExists() */ + } + } + } + + if (developer.value) + { + const char *ext = COM_FileGetExtension (filename); + + if (strcmp(ext, "pcx") != 0 && + strcmp(ext, "tga") != 0 && + strcmp(ext, "lit") != 0 && + strcmp(ext, "vis") != 0 && + strcmp(ext, "ent") != 0) + Con_DPrintf ("FindFile: can't find %s\n", filename); + else + Con_DPrintf2 ("FindFile: can't find %s\n", filename); + } + + if (file) + *file = NULL; + + return -1; +} + +typedef enum +{ + LOADFILE_HUNK, + LOADFILE_MALLOC +} loadfile_alloc_t; + +byte *QFS_LoadFile (const char *path, loadfile_alloc_t method, unsigned int *path_id, size_t* ldsize) +{ + byte *buf; + char base[32]; + size_t len, nread; + + buf = NULL; // quiet compiler warning + +// look for it in the filesystem or pack files + qfshandle_t *h = QFS_OpenFile (path, path_id); + if (h == NULL) + return NULL; + + len = (size_t)QFS_FileSize (h); + if (ldsize) + *ldsize = len; + +// extract the filename base name for hunk tag + COM_FileBase (path, base, sizeof(base)); + + switch (method) + { + case LOADFILE_HUNK: + buf = (byte *) Hunk_AllocNameNoFill (len+1, base); + break; + case LOADFILE_MALLOC: + buf = (byte *) malloc (len+1); + break; + default: + Sys_Error ("COM_LoadFile: bad usehunk"); + } + + if (!buf) + Sys_Error ("COM_LoadFile: not enough space for %s", path); + + ((byte *)buf)[len] = 0; + + nread = QFS_ReadFile (h, buf, len); + QFS_CloseFile (h); + if (nread != len) + Sys_Error ("COM_LoadFile: Error reading %s", path); + + return buf; +} + +byte *QFS_LoadHunkFile (const char *path, unsigned int *path_id, size_t* ldsize) +{ + return QFS_LoadFile (path, LOADFILE_HUNK, path_id, ldsize); +} + +// returns malloc'd memory +byte *QFS_LoadMallocFile (const char *path, unsigned int *path_id, size_t* ldsize) +{ + return QFS_LoadFile (path, LOADFILE_MALLOC, path_id, ldsize); +} + +qboolean QFS_FileExists (const char *filename, unsigned int *path_id) +{ + qfileofs_t ret = QFS_FindFile (filename, NULL, false, path_id); + return (ret == -1) ? false : true; +} + +qfshandle_t* QFS_OpenFile (const char *filename, unsigned int *path_id) +{ + qfshandle_t* handle; + if (QFS_FindFile (filename, &handle, false, path_id) >= 0) + return handle; + return NULL; +} + +qfshandle_t* QFS_FOpenFile (const char *filename, unsigned int *path_id) +{ + qfshandle_t* handle; + if (QFS_FindFile (filename, &handle, true, path_id) >= 0) + return handle; + return NULL; +} + +qboolean QFS_Eof (qfshandle_t* handle) +{ + if (!handle || handle->offs - handle->endtrim >= handle->filesize(handle) - handle->start) + return true; + return false; +} + +size_t QFS_ReadFile(qfshandle_t* handle, void* buf, size_t size) +{ + if (handle) + { + qfileofs_t filesize = handle->filesize(handle); + if (handle->offs + (qfileofs_t)size > filesize - handle->endtrim) + size = (size_t)(filesize - handle->endtrim); + + return handle->read(handle, buf, size); + } + return 0; +} + +qfileofs_t QFS_FileSize (qfshandle_t* handle) +{ + return handle ? handle->filesize(handle) - handle->start - handle->endtrim : 0; +} + +void QFS_CloseFile (qfshandle_t *handle) +{ + if (handle) + handle->close (handle); +} + +qfileofs_t QFS_Seek (qfshandle_t* handle, qfileofs_t offs, int whence) +{ + qfileofs_t actual_pos; + if (!handle) + return -1; + + switch (whence) + { + case SEEK_SET: + actual_pos = handle->start + offs; + break; + case SEEK_CUR: + actual_pos = handle->start + handle->offs + offs; + break; + case SEEK_END: + actual_pos = handle->filesize(handle) - handle->endtrim + offs; + break; + default: + return -1; + } + if (actual_pos < handle->start || actual_pos > handle->filesize(handle) - (handle->start + handle->endtrim)) + return -1; + + if (handle->seek(handle, actual_pos) == 0) + { + handle->offs = actual_pos; + return 0; + } + return -1; +} + +qfileofs_t QFS_Tell (qfshandle_t* handle) +{ + return handle ? handle->offs - handle->start : 0; +} + +qboolean QFS_IgnoreBytes (qfshandle_t* handle, qfileofs_t cut, int whence) +{ + if (handle) + { + qfileofs_t filesize = handle->filesize(handle); + if (whence == SEEK_SET && cut <= filesize - handle->endtrim) + handle->start = cut; + else if (whence == SEEK_END && cut <= filesize - handle->start) + handle->endtrim = cut; + else if (whence == SEEK_SET && cut == 0) + handle->endtrim = handle->start = 0; + else + return false; + + if (handle->offs < handle->start) + return handle->seek (handle, handle->start) == 0; + if (handle->offs > handle->start - handle->endtrim) + return handle->seek (handle, filesize - handle->start - handle->endtrim) == 0; + } + return false; +} + +char QFS_GetChar (qfshandle_t* handle, qboolean* eof_flag) +{ + char ch = '\0'; + if (QFS_ReadFile (handle, &ch, 1) == 1) + { + if (eof_flag) + *eof_flag = false; + return ch; + } + if (eof_flag) + *eof_flag = true; + return '\0'; +} + +size_t QFS_GetLine (qfshandle_t* handle, char *buf, size_t bufsz) +{ + size_t i, o; + qboolean eof_flag = false; + if (bufsz < 1) + return 0; + + for (i = 0, o = 0; o < bufsz - 1; ++i) + { + char ch = QFS_GetChar (handle, &eof_flag); + if (ch == '\n' || ch == '\0' || eof_flag) + break; + else if (ch != '\r') + buf[o++] = ch; + } + + buf[o] = '\0'; + return o; +} + diff --git a/Quake/filesys.h b/Quake/filesys.h new file mode 100644 index 000000000..9952de6e5 --- /dev/null +++ b/Quake/filesys.h @@ -0,0 +1,242 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2010-2014 QuakeSpasm developers +Copyright (C) 2024-2024 ironwail developers + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef QUAKE_FILESYSTEM_H +#define QUAKE_FILESYSTEM_H + +//Opaque file handle that is used for Quake file system operations +typedef struct file_handle_s qfshandle_t; + +/* +=========== +QFS_OpenFile + +Attempts to open the requested file, returns NULL if it is not found. +Filename never has a leading slash, but may contain directory walks + +Files opened with this will all use the same FILE* for the pack file +=========== +*/ +qfshandle_t* QFS_OpenFile (const char* filename, unsigned int* path_id); + +/* +=========== +QFS_FOpenFile + +If the requested file is inside a packfile, a new FILE* will be opened +into the file pack. Unsure why this would make anything better but it +seems to be used in a handful of places. +=========== +*/ +qfshandle_t* QFS_FOpenFile (const char *filename, unsigned int *path_id); + + +/* +=========== +QFS_FileExists + +Returns whether the file is found in the quake filesystem. +=========== +*/ +qboolean QFS_FileExists (const char *filename, unsigned int *path_id); + +/* +============ +QFS_CloseFile + +Must be called when you are done with the file to free used resources +============ +*/ +void QFS_CloseFile (qfshandle_t *handle); + +/* +============ +QFS_ReadFile + +Read binary data from the file, returns the number of bytes read from the file. +============ +*/ +size_t QFS_ReadFile (qfshandle_t* handle, void* buf, size_t size); + +/* +============ +QFS_Eof + +Returns true if end of file has been reached on the handle +============ +*/ +qboolean QFS_Eof (qfshandle_t* handle); + +/* +============ +QFS_FileSize + +Returns the total size, in bytes, of the opened file. +============ +*/ +qfileofs_t QFS_FileSize (qfshandle_t* handle); + +/* +============ +QFS_Seek + +Move to a specific position in the file. +whence can be one of SEEK_SET, SEEK_CUR, or SEEK_END and works like fseek in C. +Like fseek, it returns 0 on success and -1 on failure. +Unlike fseek, errno is not set on failure. + +When using .pk3 files this is a more expensive operation than .pak or regular files, +especially when seeking backwards. For optimal results it is recommended to store +already compressed music files without deflate compression inside pk3 files - in +these cases the seek will be as efficient as a regular .pak file. +============ +*/ +qfileofs_t QFS_Seek (qfshandle_t* handle, qfileofs_t offs, int whence); + +/* +============ +QFS_Tell + +Determine the corrent seek position in the file. +============ +*/ +qfileofs_t QFS_Tell (qfshandle_t* handle); + +/* +============ +QFS_IgnoreBytes + +Specify a number of bytes that the file length should be shortened with. +This could be useful for ignoring garbage at the end of a file such as id3 tags. + +whence can be either SEEK_END or SEEK_SET, SEEK_END will cut off at the end +and SEEK_SET will cut off in the beginning. + +If the current file position is inside the removed area, the file cursor +will be moved either to the beginning (SEEK_SET) or the end (SEEK_END) + +If you specify whence as SEEK_CUR and cut as 0, the ignore effect will be reset. +============ +*/ +qboolean QFS_IgnoreBytes (qfshandle_t* handle, qfileofs_t cut, int whence); + + +// these procedures open a file using COM_FindFile and loads it into a proper +// buffer. the buffer is allocated with a total size of file size + 1. the +// procedures differ by their buffer allocation method. +// If you don't need the file size, you can give ldsize as NULL. +byte *QFS_LoadHunkFile (const char *path, unsigned int *path_id, size_t* ldsize); + // allocates the buffer on the hunk. +byte *QFS_LoadMallocFile (const char *path, unsigned int *path_id, size_t* ldsize); + // allocates the buffer on the system mem (malloc). + +/* +============ +QFS_LoadPackFile + +Load a pack file and return the id of the new pack +============ +*/ +int QFS_LoadPackFile (const char *packfile); + +/* +============ +QFS_FreePack + +Close handle and release all resources associated with the pack +============ +*/ +void QFS_FreePack (int packid); + +/* +============ +QFS_Shutdown + +Close all packs that are open +============ +*/ +void QFS_Shutdown (void); + +/* +============ +QFS_PackInfoName + +Returns the pack filename of the pack with the id or NULL if the pack doesn't exist +============ +*/ +const char* QFS_PackInfoName (int packid); + +/* +============ +QFS_PackInfoName + +Returns the number of files in the pack with the id or 0 if the pack doesn't exist +============ +*/ +int QFS_PackInfoNumFiles (int packid); + +/* +============ +QFS_PackInfoEntrySize + +Returns the total size, in bytes, specified file in the pack or 0 if it does not exist +============ +*/ +qfileofs_t QFS_PackInfoEntrySize (int packid, int idx); + +/* +============ +QFS_PackInfoEntryName + +Returns the file name, specified file in the pack or NULL if it does not exist +============ +*/ +const char* QFS_PackInfoEntryName (int packid, int idx); + +/* +============ +QFS_GetChar + +Reads a single text character from the file. It is the basis +for implementing other text mode read functions. +returns 0 and sets eof_flag if there are no characters to read +============ +*/ +char QFS_GetChar (qfshandle_t* handle, qboolean* eof_flag); + +/* +============ +QFS_GetLine + +Reads a single line of text from the file. Returns the number of +characters copied to buf. This will skip '\r' always. +Newline '\n' is considered end of the line, '\n' will +not be copied to buf. + +If buf is full before encountering '\n' the string will be truncated. +The buf will always be NUL-terminated so it can at most +extract bufsz-1 characters. +============ +*/ +size_t QFS_GetLine (qfshandle_t* handle, char *buf, size_t bufsz); + +#endif /* QUAKE_FILESYSTEM_H */ diff --git a/Quake/gl_draw.c b/Quake/gl_draw.c index 82b77101f..dad4b5065 100644 --- a/Quake/gl_draw.c +++ b/Quake/gl_draw.c @@ -371,7 +371,7 @@ qpic_t *Draw_TryCachePic (const char *path, unsigned int texflags) // // load the pic from disk // - dat = (qpic_t *)COM_LoadMallocFile (path, NULL); + dat = (qpic_t *)QFS_LoadMallocFile (path, NULL, NULL); if (!dat) return NULL; SwapPic (dat); diff --git a/Quake/gl_model.c b/Quake/gl_model.c index 3f9416f71..2c8675d41 100644 --- a/Quake/gl_model.c +++ b/Quake/gl_model.c @@ -373,7 +373,7 @@ static qmodel_t *Mod_LoadModel (qmodel_t *mod, qboolean crash) // // load the file // - buf = COM_LoadMallocFile (mod->name, &mod->path_id); + buf = QFS_LoadMallocFile (mod->name, &mod->path_id, NULL); if (!buf) { if (crash) @@ -829,6 +829,7 @@ static void Mod_LoadLighting (lump_t *l) byte d, q64_b0, q64_b1; char litfilename[MAX_OSPATH]; unsigned int path_id; + size_t filesize; loadmodel->lightdata = NULL; loadmodel->litfile = false; @@ -837,7 +838,7 @@ static void Mod_LoadLighting (lump_t *l) COM_StripExtension(litfilename, litfilename, sizeof(litfilename)); q_strlcat(litfilename, ".lit", sizeof(litfilename)); mark = Hunk_LowMark(); - data = (byte*) COM_LoadHunkFile (litfilename, &path_id); + data = (byte*) QFS_LoadHunkFile (litfilename, &path_id, &filesize); if (data) { // use lit file only from the same gamedir as the map @@ -853,7 +854,7 @@ static void Mod_LoadLighting (lump_t *l) i = LittleLong(((int *)data)[1]); if (i == 1) { - if (8+l->filelen*3 == com_filesize) + if (8+l->filelen*3 == (int)filesize) { Con_DPrintf2("%s loaded\n", litfilename); loadmodel->lightdata = data + 8; @@ -861,7 +862,7 @@ static void Mod_LoadLighting (lump_t *l) return; } Hunk_FreeToLowMark(mark); - Con_Printf("Outdated .lit file (%s should be %u bytes, not %" SDL_PRIs64 "\n", litfilename, 8+l->filelen*3, com_filesize); + Con_Printf("Outdated .lit file (%s should be %" SDL_PRIs32 " bytes, not %" SDL_PRIu64 "\n", litfilename, 8+l->filelen*3, (uint64_t)filesize); } else { @@ -960,13 +961,13 @@ static void Mod_LoadEntities (lump_t *l) q_snprintf(entfilename, sizeof(entfilename), "%s@%04x.ent", basemapname, crc); Con_DPrintf2("trying to load %s\n", entfilename); - ents = (char *) COM_LoadHunkFile (entfilename, &path_id); + ents = (char *) QFS_LoadHunkFile (entfilename, &path_id, NULL); if (!ents) { q_snprintf(entfilename, sizeof(entfilename), "%s.ent", basemapname); Con_DPrintf2("trying to load %s\n", entfilename); - ents = (char *) COM_LoadHunkFile (entfilename, &path_id); + ents = (char *) QFS_LoadHunkFile (entfilename, &path_id, NULL); } if (ents) @@ -2221,23 +2222,25 @@ typedef struct vispatch_s } vispatch_t; #define VISPATCH_HEADER_LEN 36 -static FILE *Mod_FindVisibilityExternal(void) +static qfshandle_t *Mod_FindVisibilityExternal(void) { vispatch_t header; char visfilename[MAX_QPATH]; const char* shortname; unsigned int path_id; - FILE *f; + qfshandle_t *f; long pos; size_t r; q_snprintf(visfilename, sizeof(visfilename), "maps/%s.vis", loadname); - if (COM_FOpenFile(visfilename, &f, &path_id) < 0) + f = QFS_FOpenFile(visfilename, &path_id); + if (f == NULL) { Con_DPrintf("%s not found, trying ", visfilename); q_snprintf(visfilename, sizeof(visfilename), "%s.vis", COM_SkipPath(com_gamedir)); Con_DPrintf("%s\n", visfilename); - if (COM_FOpenFile(visfilename, &f, &path_id) < 0) + f = QFS_FOpenFile(visfilename, &path_id); + if (f == NULL) { Con_DPrintf("external vis not found\n"); return NULL; @@ -2245,7 +2248,7 @@ static FILE *Mod_FindVisibilityExternal(void) } if (path_id < loadmodel->path_id) { - fclose(f); + QFS_CloseFile(f); Con_DPrintf("ignored %s from a gamedir with lower priority\n", visfilename); return NULL; } @@ -2254,20 +2257,20 @@ static FILE *Mod_FindVisibilityExternal(void) shortname = COM_SkipPath(loadmodel->name); pos = 0; - while ((r = fread(&header, 1, VISPATCH_HEADER_LEN, f)) == VISPATCH_HEADER_LEN) + while ((r = QFS_ReadFile(f, &header, VISPATCH_HEADER_LEN)) == VISPATCH_HEADER_LEN) { header.filelen = LittleLong(header.filelen); if (header.filelen <= 0) { /* bad entry -- don't trust the rest. */ - fclose(f); + QFS_CloseFile(f); return NULL; } if (!q_strcasecmp(header.mapname, shortname)) break; pos += header.filelen + VISPATCH_HEADER_LEN; - fseek(f, pos, SEEK_SET); + QFS_Seek(f, pos, SEEK_SET); } if (r != VISPATCH_HEADER_LEN) { - fclose(f); + QFS_CloseFile(f); Con_DPrintf("%s not found in %s\n", shortname, visfilename); return NULL; } @@ -2275,20 +2278,20 @@ static FILE *Mod_FindVisibilityExternal(void) return f; } -static byte *Mod_LoadVisibilityExternal(FILE* f) +static byte *Mod_LoadVisibilityExternal(qfshandle_t* f) { - int mark, filelen; + int32_t mark, filelen; byte* visdata; filelen = 0; - if (fread(&filelen, 4, 1, f) != 1) + if (QFS_ReadFile(f, &filelen, 4) != 4) return NULL; filelen = LittleLong(filelen); if (filelen <= 0) return NULL; - Con_DPrintf("...%d bytes visibility data\n", filelen); + Con_DPrintf("...%" SDL_PRIs32 " bytes visibility data\n", filelen); mark = Hunk_LowMark (); visdata = (byte *) Hunk_AllocNameNoFill (filelen, "EXT_VIS"); - if (!fread(visdata, filelen, 1, f)) + if (QFS_ReadFile(f, visdata, filelen) != (size_t)filelen) { Hunk_FreeToLowMark (mark); return NULL; @@ -2296,23 +2299,23 @@ static byte *Mod_LoadVisibilityExternal(FILE* f) return visdata; } -static void Mod_LoadLeafsExternal(FILE* f) +static void Mod_LoadLeafsExternal(qfshandle_t* f) { - int mark, filelen; + int32_t mark, filelen; void* in; filelen = 0; - if (fread(&filelen, 4, 1, f) != 1) + if (QFS_ReadFile(f, &filelen, 4) != 4) { Con_Warning ("Couldn't read external leaf data length\n"); return; } filelen = LittleLong(filelen); if (filelen <= 0) return; - Con_DPrintf("...%d bytes leaf data\n", filelen); + Con_DPrintf("...%" SDL_PRIs32 " bytes leaf data\n", filelen); mark = Hunk_LowMark (); in = Hunk_AllocNameNoFill (filelen, "EXT_LEAF"); - if (!fread(in, filelen, 1, f)) + if (QFS_ReadFile(f, in, filelen) != (size_t)filelen) { Hunk_FreeToLowMark (mark); return; @@ -2378,7 +2381,7 @@ static void Mod_LoadBrushModel (qmodel_t *mod, void *buffer) if (mod->bspversion == BSPVERSION && external_vis.value && sv.modelname[0] && !q_strcasecmp(loadname, sv.name)) { - FILE* fvis; + qfshandle_t* fvis; Con_DPrintf("trying to open external vis file\n"); fvis = Mod_FindVisibilityExternal(); if (fvis) { @@ -2390,7 +2393,7 @@ static void Mod_LoadBrushModel (qmodel_t *mod, void *buffer) if (loadmodel->visdata) { Mod_LoadLeafsExternal(fvis); } - fclose(fvis); + QFS_CloseFile(fvis); if (loadmodel->visdata && loadmodel->leafs && loadmodel->numleafs) { goto visdone; } @@ -2538,7 +2541,7 @@ qboolean Mod_LoadMapDescription (char *desc, size_t maxchars, const char *map) char buf[4 * 1024]; char path[MAX_QPATH]; const char *data; - FILE *f; + qfshandle_t *f; lump_t *entlump; dheader_t header; int i, filesize; @@ -2551,17 +2554,18 @@ qboolean Mod_LoadMapDescription (char *desc, size_t maxchars, const char *map) if ((size_t) q_snprintf (path, sizeof (path), "maps/%s.bsp", map) >= sizeof (path)) return false; - filesize = COM_FOpenFile (path, &f, NULL); + f = QFS_FOpenFile(path, NULL); + filesize = f ? (int)QFS_FileSize(f) : -1; if (filesize <= (int) sizeof (header)) { if (filesize != -1) - fclose (f); + QFS_CloseFile (f); return false; } - if (fread (&header, sizeof (header), 1, f) != 1) + if (QFS_ReadFile (f, &header, sizeof (header)) != sizeof (header)) { - fclose (f); + QFS_CloseFile (f); return false; } @@ -2575,7 +2579,7 @@ qboolean Mod_LoadMapDescription (char *desc, size_t maxchars, const char *map) case BSPVERSION_QUAKE64: break; default: - fclose (f); + QFS_CloseFile (f); return false; } @@ -2586,7 +2590,7 @@ qboolean Mod_LoadMapDescription (char *desc, size_t maxchars, const char *map) if (entlump->filelen < 0 || entlump->filelen >= filesize || entlump->fileofs < 0 || entlump->fileofs + entlump->filelen > filesize) { - fclose (f); + QFS_CloseFile (f); return false; } @@ -2598,9 +2602,9 @@ qboolean Mod_LoadMapDescription (char *desc, size_t maxchars, const char *map) entlump->filelen = sizeof (buf) - 1; } - fseek (f, entlump->fileofs - sizeof (header), SEEK_CUR); - i = fread (buf, 1, entlump->filelen, f); - fclose (f); + QFS_Seek (f, entlump->fileofs - sizeof (header), SEEK_CUR); + i = (int)QFS_ReadFile (f, buf, entlump->filelen); + QFS_CloseFile (f); if (i <= 0) return false; @@ -3150,9 +3154,9 @@ static void Mod_LoadAliasModel (qmodel_t *mod, void *buffer) COM_StripExtension (mod->name, path, sizeof (path)); COM_AddExtension (path, ".md5mesh", sizeof (path)); - if (COM_FileExists (path, &md5_path_id) && md5_path_id >= mod->path_id) + if (QFS_FileExists (path, &md5_path_id) && md5_path_id >= mod->path_id) { - char *md5buffer = (char *) COM_LoadMallocFile (path, NULL); + char *md5buffer = (char *) QFS_LoadMallocFile (path, NULL, NULL); if (md5buffer) { Mod_LoadMD5MeshModel (mod, md5buffer); @@ -3834,14 +3838,15 @@ static unsigned int MD5_HackyModelFlags(const char *name) { unsigned int ret = 0; char oldmodel[MAX_QPATH]; + size_t filesize; mdl_t *f; COM_StripExtension(name, oldmodel, sizeof(oldmodel)); COM_AddExtension(oldmodel, ".mdl", sizeof(oldmodel)); - f = (mdl_t*)COM_LoadMallocFile(oldmodel, NULL); + f = (mdl_t*)QFS_LoadMallocFile(oldmodel, NULL, &filesize); if (f) { - if (com_filesize >= sizeof(*f) && LittleLong(f->ident) == IDPOLYHEADER && LittleLong(f->version) == ALIAS_VERSION) + if (filesize >= sizeof(*f) && LittleLong(f->ident) == IDPOLYHEADER && LittleLong(f->version) == ALIAS_VERSION) ret = f->flags; free(f); } @@ -3864,7 +3869,7 @@ static void MD5Anim_Begin(md5animctx_t *ctx, const char *fname) COM_StripExtension(fname, ctx->fname, sizeof(ctx->fname)); COM_AddExtension(ctx->fname, ".md5anim", sizeof(ctx->fname)); fname = ctx->fname; - ctx->animfile = (char *) COM_LoadMallocFile(fname, NULL); + ctx->animfile = (char *) QFS_LoadMallocFile(fname, NULL, NULL); ctx->numposes = 0; if (ctx->animfile) diff --git a/Quake/gl_screen.c b/Quake/gl_screen.c index b2a68d3b8..99f8b4ffc 100644 --- a/Quake/gl_screen.c +++ b/Quake/gl_screen.c @@ -803,8 +803,7 @@ void SCR_DrawDemoControls (void) // Approximate the fraction of the demo that's already been played back // based on the current file offset and total demo size - // Note: we need to take into account the starting offset for pak files - frac = (Sys_ftell (cls.demofile) - cls.demofilestart) / (double)cls.demofilesize; + frac = QFS_Tell (cls.inpdemo) / (double)cls.demofilesize; frac = CLAMP (0.f, frac, 1.f); if (cl.intermission) diff --git a/Quake/gl_sky.c b/Quake/gl_sky.c index a83404a50..26580f4ef 100644 --- a/Quake/gl_sky.c +++ b/Quake/gl_sky.c @@ -215,7 +215,7 @@ static void Skywind_Load_f (void) } q_snprintf (relname, sizeof (relname), "gfx/env/%s" SKYWIND_CFG, skybox->name); - buf = (char *) COM_LoadMallocFile (relname, NULL); + buf = (char *) QFS_LoadMallocFile (relname, NULL, NULL); if (!buf) { Con_DPrintf ("Sky wind config not found '%s'.\n", relname); diff --git a/Quake/gl_texmgr.c b/Quake/gl_texmgr.c index 0b68015d1..92f39e04d 100644 --- a/Quake/gl_texmgr.c +++ b/Quake/gl_texmgr.c @@ -738,25 +738,25 @@ void TexMgr_LoadPalette (void) { byte *pal, *src, *colormap; int i, j, mark, numfb; - FILE *f; + qfshandle_t *f; - COM_FOpenFile ("gfx/palette.lmp", &f, NULL); + f = QFS_FOpenFile ("gfx/palette.lmp", NULL); if (!f) Sys_Error ("Couldn't load gfx/palette.lmp"); mark = Hunk_LowMark (); pal = (byte *) Hunk_AllocNoFill (768); - if (fread (pal, 768, 1, f) != 1) + if (QFS_ReadFile (f, pal, 768) != 768) Sys_Error ("Failed reading gfx/palette.lmp"); - fclose(f); + QFS_CloseFile(f); - COM_FOpenFile ("gfx/colormap.lmp", &f, NULL); + f = QFS_FOpenFile ("gfx/colormap.lmp", NULL); if (!f) Sys_Error ("Couldn't load gfx/colormap.lmp"); colormap = (byte *) Hunk_AllocNoFill (256 * 64); - if (fread (colormap, 256 * 64, 1, f) != 1) + if (QFS_ReadFile (f, colormap, 256 * 64) != 256 * 64) Sys_Error ("TexMgr_LoadPalette: colormap read error"); - fclose(f); + QFS_CloseFile(f); //find fullbright colors memset (is_fullbright, 0, sizeof (is_fullbright)); @@ -1663,11 +1663,11 @@ void TexMgr_ReloadImage (gltexture_t *glt, int shirt, int pants) if (glt->source_file[0] && glt->source_offset) { //lump inside file - FILE *f; + qfshandle_t *f; int sz; - COM_FOpenFile(glt->source_file, &f, NULL); + f = QFS_FOpenFile(glt->source_file, NULL); if (!f) goto invalid; - fseek (f, glt->source_offset, SEEK_CUR); + QFS_Seek (f, glt->source_offset, SEEK_CUR); size = glt->source_width * glt->source_height; /* should be SRC_INDEXED, but no harm being paranoid: */ if (glt->source_format == SRC_RGBA) { @@ -1677,8 +1677,8 @@ void TexMgr_ReloadImage (gltexture_t *glt, int shirt, int pants) size *= lightmap_bytes; } data = (byte *) Hunk_AllocNoFill (size); - sz = (int) fread (data, 1, size, f); - fclose (f); + sz = (int) QFS_ReadFile (f, data, size); + QFS_CloseFile (f); if (sz != size) { Hunk_FreeToLowMark(mark); Host_Error("Read error for %s", glt->name); diff --git a/Quake/gl_vidsdl.c b/Quake/gl_vidsdl.c index 3898e6848..b83aa26a6 100644 --- a/Quake/gl_vidsdl.c +++ b/Quake/gl_vidsdl.c @@ -1543,6 +1543,11 @@ static void VID_InitModelist (void) } } +static const char* config_names[] = +{ + CONFIG_NAME, "config.cfg" +}; + /* =================== VID_Init @@ -1555,6 +1560,7 @@ void VID_Init (void) int display_width, display_height, display_refreshrate; qboolean fullscreen; cmd_function_t *cmd; + size_t idxcfg; const char *read_vars[] = { "vid_fullscreen", @@ -1570,7 +1576,6 @@ void VID_Init (void) "r_softemu_metric", "scr_pixelaspect", }; -#define num_readvars Q_COUNTOF(read_vars) Con_SafePrintf ("\nVideo initialization\n"); @@ -1634,12 +1639,16 @@ void VID_Init (void) Cvar_SetValueQuick (&vid_height, (float)display_height); Cvar_SetValueQuick (&vid_refreshrate, (float)display_refreshrate); - if (CFG_OpenConfig(CONFIG_NAME) == 0 || CFG_OpenConfig("config.cfg") == 0) + for (idxcfg = 0; idxcfg < Q_COUNTOF(config_names); ++idxcfg) { - CFG_ReadCvars(read_vars, num_readvars); - CFG_CloseConfig(); + if (QFS_FileExists (config_names[idxcfg], NULL)) + { + CFG_ReadCvars (config_names[idxcfg], read_vars, Q_COUNTOF(read_vars)); + break; + } } - CFG_ReadCvarOverrides(read_vars, num_readvars); + + CFG_ReadCvarOverrides(read_vars, Q_COUNTOF(read_vars)); VID_InitModelist(); VID_InitMouseCursors(); diff --git a/Quake/host.c b/Quake/host.c index fe645d302..02e224bdf 100644 --- a/Quake/host.c +++ b/Quake/host.c @@ -1370,7 +1370,7 @@ void Host_Init (void) if (cls.state != ca_dedicated) { - host_colormap = (byte *)COM_LoadHunkFile ("gfx/colormap.lmp", NULL); + host_colormap = (byte *)QFS_LoadHunkFile ("gfx/colormap.lmp", NULL, NULL); if (!host_colormap) Sys_Error ("Couldn't load gfx/colormap.lmp"); @@ -1454,6 +1454,8 @@ void Host_Shutdown(void) NET_Shutdown (); + QFS_Shutdown(); + if (cls.state != ca_dedicated) { if (con_initialized) diff --git a/Quake/host_cmd.c b/Quake/host_cmd.c index 662e2c649..a1e12baea 100644 --- a/Quake/host_cmd.c +++ b/Quake/host_cmd.c @@ -444,7 +444,6 @@ void ExtraMaps_Init (void) char mapname[32]; char ignorepakdir[32]; searchpath_t *search; - pack_t *pak; int i; // we don't want to list the maps in id1 pakfiles, @@ -469,15 +468,19 @@ void ExtraMaps_Init (void) } else //pakfile { - qboolean isbase = (strstr(search->pack->filename, ignorepakdir) != NULL); - for (i = 0, pak = search->pack; i < pak->numfiles; i++) + const char* pack_filename = QFS_PackInfoName(search->pack); + qboolean isbase = (pack_filename && strstr(pack_filename, ignorepakdir) != NULL); + int filecnt = QFS_PackInfoNumFiles(search->pack); + for (i = 0; i < filecnt; ++i) { - if (pak->files[i].filelen > 32*1024 && // don't list files under 32k (ammo boxes etc) - !strncmp (pak->files[i].name, "maps/", 5) && // don't list files outside of maps/ - !strchr (pak->files[i].name + 5, '/') && // don't list files in subdirectories - !strcmp (COM_FileGetExtension (pak->files[i].name), "bsp")) + const char* entry_filename = QFS_PackInfoEntryName(search->pack, i); + if (entry_filename && + QFS_PackInfoEntrySize(search->pack, i) > 32*1024 && // don't list files under 32k (ammo boxes etc) + !strncmp (entry_filename, "maps/", 5) && // don't list files outside of maps/ + !strchr (entry_filename + 5, '/') && // don't list files in subdirectories + !strcmp (COM_FileGetExtension (entry_filename), "bsp")) { - COM_StripExtension (pak->files[i].name + 5, mapname, sizeof (mapname)); + COM_StripExtension (entry_filename + 5, mapname, sizeof (mapname)); ExtraMaps_Add (mapname, isbase ? NULL : search); } } @@ -1129,7 +1132,7 @@ static void Modlist_Add (const char *name) // look for mapdb.json file if (!info->full_name) { - char *mapdb = (char *) COM_LoadMallocFile ("mapdb.json", &path_id); + char *mapdb = (char *) QFS_LoadMallocFile ("mapdb.json", &path_id, NULL); if (mapdb) { qboolean is_base_mapdb = !com_searchpaths || path_id < com_searchpaths->path_id; @@ -1197,6 +1200,10 @@ static qboolean Modlist_Check (const char *modname, const char *base) q_snprintf (itempath, sizeof (itempath), "%s/pak0.pak", modpath); if (Sys_FileExists (itempath)) return true; + + q_snprintf (itempath, sizeof (itempath), "%s/pak0.pk3", modpath); + if (Sys_FileExists (itempath)) + return true; q_snprintf (itempath, sizeof (itempath), "%s/progs.dat", modpath); if (Sys_FileExists (itempath)) @@ -1339,7 +1346,6 @@ void DemoList_Init (void) char demname[32]; char ignorepakdir[32]; searchpath_t *search; - pack_t *pak; int i; // we don't want to list the demos in id1 pakfiles, @@ -1361,13 +1367,16 @@ void DemoList_Init (void) } else //pakfile { - if (!strstr(search->pack->filename, ignorepakdir)) + const char* pack_filename = QFS_PackInfoName(search->pack); + if (!strstr(pack_filename, ignorepakdir)) { //don't list standard id demos - for (i = 0, pak = search->pack; i < pak->numfiles; i++) + int filecnt = QFS_PackInfoNumFiles(search->pack); + for (i = 0; i < filecnt; ++i) { - if (!strcmp (COM_FileGetExtension (pak->files[i].name), "dem")) + const char* entry_filename = QFS_PackInfoEntryName(search->pack, i); + if (!strcmp (COM_FileGetExtension (entry_filename), "dem")) { - COM_StripExtension (pak->files[i].name, demname, sizeof (demname)); + COM_StripExtension (entry_filename, demname, sizeof (demname)); FileList_Add (demname, &demolist); } } @@ -1498,7 +1507,6 @@ static void SkyList_AddDirRec (const char *root, const char *relpath) void SkyList_Init (void) { searchpath_t *search; - pack_t *pak; int i; for (search = com_searchpaths; search; search = search->next) @@ -1506,8 +1514,11 @@ void SkyList_Init (void) if (*search->filename) //directory SkyList_AddDirRec (search->filename, "gfx/env"); else //pakfile - for (i = 0, pak = search->pack; i < pak->numfiles; i++) - SkyList_AddFile (pak->files[i].name); + { + int entry_count = QFS_PackInfoNumFiles(search->pack); + for (i = 0; i < entry_count; ++i) + SkyList_AddFile (QFS_PackInfoEntryName(search->pack, i)); + } } } @@ -2085,7 +2096,7 @@ static void Host_Changelevel_f (void) //johnfitz -- check for client having map before anything else q_snprintf (level, sizeof(level), "maps/%s.bsp", Cmd_Argv(1)); - if (!COM_FileExists(level, NULL)) + if (!QFS_FileExists(level, NULL)) Host_Error ("cannot find map %s", level); //johnfitz diff --git a/Quake/image.c b/Quake/image.c index 1bea36089..14eff3a73 100644 --- a/Quake/image.c +++ b/Quake/image.c @@ -23,8 +23,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" -static byte *Image_LoadPCX (FILE *f, int *width, int *height); -static byte *Image_LoadLMP (FILE *f, int *width, int *height); +static byte *Image_LoadPCX (qfshandle_t *f, int *width, int *height); +static byte *Image_LoadLMP (qfshandle_t *f, int *width, int *height); #ifdef __GNUC__ // Suppress unused function warnings on GCC/clang @@ -61,32 +61,32 @@ static byte *Image_LoadLMP (FILE *f, int *width, int *height); static char loadfilename[MAX_OSPATH]; //file scope so that error messages can use it -typedef struct stdio_buffer_s { - FILE *f; +typedef struct io_buffer_s { + qfshandle_t *f; unsigned char buffer[1024]; - int size; - int pos; -} stdio_buffer_t; + size_t size; + size_t pos; +} io_buffer_t; -static stdio_buffer_t *Buf_Alloc(FILE *f) +static io_buffer_t *Buf_Alloc(qfshandle_t *f) { - stdio_buffer_t *buf = (stdio_buffer_t *) calloc(1, sizeof(stdio_buffer_t)); + io_buffer_t *buf = (io_buffer_t *) calloc(1, sizeof(io_buffer_t)); if (!buf) Sys_Error ("Buf_Alloc: out of memory"); buf->f = f; return buf; } -static void Buf_Free(stdio_buffer_t *buf) +static void Buf_Free(io_buffer_t *buf) { free(buf); } -static inline int Buf_GetC(stdio_buffer_t *buf) +static inline int Buf_GetC(io_buffer_t *buf) { if (buf->pos >= buf->size) { - buf->size = fread(buf->buffer, 1, sizeof(buf->buffer), buf->f); + buf->size = QFS_ReadFile(buf->f, buf->buffer, sizeof(buf->buffer)); buf->pos = 0; if (buf->size == 0) @@ -96,6 +96,25 @@ static inline int Buf_GetC(stdio_buffer_t *buf) return buf->buffer[buf->pos++]; } +/* +Callback functions that stb can use to read from QFS files +*/ + +static int STBCB_Read(void *f, char *data, int size) +{ + return (int)QFS_ReadFile((qfshandle_t*)f, data, (size_t)size); +} + +static void STBCB_Skip(void *f, int n) +{ + QFS_Seek((qfshandle_t*)f, (qfileofs_t)n, SEEK_CUR); +} + +static int STBCB_Eof(void* f) +{ + return QFS_Eof((qfshandle_t*)f) ? 1 : 0; +} + /* ============ Image_LoadImage @@ -106,16 +125,21 @@ returns a pointer to hunk allocated RGBA data byte *Image_LoadImage (const char *name, int *width, int *height, enum srcformat *fmt) { static const char *const stbi_formats[] = {"png", "tga", "jpg", NULL}; - FILE *f; + qfshandle_t *f; + stbi_io_callbacks callbacks; int i; for (i = 0; stbi_formats[i]; i++) { q_snprintf (loadfilename, sizeof(loadfilename), "%s.%s", name, stbi_formats[i]); - COM_FOpenFile (loadfilename, &f, NULL); + f = QFS_FOpenFile (loadfilename, NULL); if (f) { - byte *data = stbi_load_from_file (f, width, height, NULL, 4); + callbacks.read = &STBCB_Read; + callbacks.skip = &STBCB_Skip; + callbacks.eof = &STBCB_Eof; + + byte *data = stbi_load_from_callbacks (&callbacks, f, width, height, NULL, 4); if (data) { int numbytes = (*width) * (*height) * 4; @@ -127,13 +151,13 @@ byte *Image_LoadImage (const char *name, int *width, int *height, enum srcformat } else Con_Warning ("couldn't load %s (%s)\n", loadfilename, stbi_failure_reason ()); - fclose (f); + QFS_CloseFile (f); return data; } } q_snprintf (loadfilename, sizeof(loadfilename), "%s.pcx", name); - COM_FOpenFile (loadfilename, &f, NULL); + f = QFS_FOpenFile (loadfilename, NULL); if (f) { *fmt = SRC_RGBA; @@ -141,7 +165,7 @@ byte *Image_LoadImage (const char *name, int *width, int *height, enum srcformat } q_snprintf (loadfilename, sizeof(loadfilename), "%s.lmp", name); - COM_FOpenFile (loadfilename, &f, NULL); + f = QFS_FOpenFile (loadfilename, NULL); if (f) { *fmt = SRC_INDEXED; @@ -238,17 +262,15 @@ typedef struct Image_LoadPCX ============ */ -static byte *Image_LoadPCX (FILE *f, int *width, int *height) +static byte *Image_LoadPCX (qfshandle_t *f, int *width, int *height) { pcxheader_t pcx; - int x, y, w, h, readbyte, runlength, start; + int x, y, w, h, readbyte, runlength; byte *p, *data; byte palette[768]; - stdio_buffer_t *buf; - - start = ftell (f); //save start of file (since we might be inside a pak file, SEEK_SET might not be the start of the pcx) + io_buffer_t *buf; - if (fread(&pcx, sizeof(pcx), 1, f) != 1) + if (QFS_ReadFile(f, &pcx, sizeof(pcx)) != sizeof(pcx)) Sys_Error ("Failed reading header from '%s'", loadfilename); pcx.xmin = (unsigned short)LittleShort (pcx.xmin); @@ -272,12 +294,14 @@ static byte *Image_LoadPCX (FILE *f, int *width, int *height) data = (byte *) Hunk_Alloc((w*h+1)*4); //+1 to allow reading padding byte on last line //load palette - fseek (f, start + com_filesize - 768, SEEK_SET); - if (fread (palette, 768, 1, f) != 1) + if (QFS_Seek (f, QFS_FileSize(f) - sizeof(palette), SEEK_SET) != 0 + || QFS_ReadFile (f, palette, sizeof(palette)) != sizeof(palette)) + { Sys_Error ("Failed reading palette from '%s'", loadfilename); + } //back to start of image data - fseek (f, start + sizeof(pcx), SEEK_SET); + QFS_Seek (f, sizeof(pcx), SEEK_SET); buf = Buf_Alloc(f); @@ -310,7 +334,7 @@ static byte *Image_LoadPCX (FILE *f, int *width, int *height) } Buf_Free(buf); - fclose(f); + QFS_CloseFile(f); *width = w; *height = h; @@ -333,16 +357,16 @@ typedef struct Image_LoadLMP ============ */ -static byte *Image_LoadLMP (FILE *f, int *width, int *height) +static byte *Image_LoadLMP (qfshandle_t *f, int *width, int *height) { lmpheader_t qpic; size_t pix; int mark; void *data; - if (fread (&qpic, sizeof(qpic), 1, f) != 1) + if (QFS_ReadFile (f, &qpic, sizeof(qpic)) != sizeof(qpic)) { - fclose (f); + QFS_CloseFile (f); return NULL; } qpic.width = LittleLong (qpic.width); @@ -350,21 +374,21 @@ static byte *Image_LoadLMP (FILE *f, int *width, int *height) pix = qpic.width*qpic.height; - if (com_filesize != sizeof (qpic) + pix) + if (QFS_FileSize(f) != (qfileofs_t)(sizeof (qpic) + pix)) { - fclose (f); + QFS_CloseFile (f); return NULL; } mark = Hunk_LowMark (); data = (byte *) Hunk_Alloc (pix); - if (fread (data, 1, pix, f) != pix) + if (QFS_ReadFile (f, data, pix) != pix) { Hunk_FreeToLowMark (mark); - fclose (f); + QFS_CloseFile (f); return NULL; } - fclose (f); + QFS_CloseFile (f); *width = qpic.width; *height = qpic.height; diff --git a/Quake/menu.c b/Quake/menu.c index ade8935fb..ae7e000d6 100644 --- a/Quake/menu.c +++ b/Quake/menu.c @@ -7322,20 +7322,22 @@ void M_ConfigureNetSubsystem(void) static qboolean M_CheckCustomGfx (const char *custompath, const char *basepath, int knownlength, const unsigned int *hashes, int numhashes) { unsigned int id_custom, id_base; - int h, length; + qfshandle_t* h; + int length; qboolean ret = false; - if (!COM_FileExists (custompath, &id_custom)) + if (!QFS_FileExists (custompath, &id_custom)) return false; - length = COM_OpenFile (basepath, &h, &id_base); + h = QFS_OpenFile (basepath, &id_base); + length = (int)QFS_FileSize (h); if (id_custom >= id_base) ret = true; else if (length == knownlength) { int mark = Hunk_LowMark (); byte* data = (byte*) Hunk_Alloc (length); - if (length == Sys_FileRead (h, data, length)) + if (length == (int)QFS_ReadFile (h, data, length)) { unsigned int hash = COM_HashBlock (data, length); while (numhashes-- > 0 && !ret) @@ -7345,7 +7347,7 @@ static qboolean M_CheckCustomGfx (const char *custompath, const char *basepath, Hunk_FreeToLowMark (mark); } - COM_CloseFile (h); + QFS_CloseFile (h); return ret; } diff --git a/Quake/miniz.c b/Quake/miniz.c index a9318862d..97a0777bc 100644 --- a/Quake/miniz.c +++ b/Quake/miniz.c @@ -2247,7 +2247,7 @@ mz_bool mz_zip_end(mz_zip_archive *pZip) return MZ_FALSE; } - +#endif /* unused */ mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) { mz_uint n; @@ -2268,7 +2268,6 @@ mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, cha } return n + 1; } -#endif /* unused */ mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) { diff --git a/Quake/pr_edict.c b/Quake/pr_edict.c index 815a5b6e0..107b48e19 100644 --- a/Quake/pr_edict.c +++ b/Quake/pr_edict.c @@ -2042,15 +2042,16 @@ PR_LoadProgs qboolean PR_LoadProgs (const char *filename, qboolean fatal) { int i; + size_t filesize; PR_ClearProgs(qcvm); //just in case. - qcvm->progs = (dprograms_t *)COM_LoadHunkFile (filename, NULL); + qcvm->progs = (dprograms_t *)QFS_LoadHunkFile (filename, NULL, &filesize); if (!qcvm->progs) return false; - Con_DPrintf ("Programs occupy %" SDL_PRIs64 "K.\n", com_filesize/1024); + Con_DPrintf ("Programs occupy %" SDL_PRIs64 "K.\n", (int64_t)(filesize/1024)); - qcvm->crc = CRC_Block (qcvm->progs, com_filesize); + qcvm->crc = CRC_Block (qcvm->progs, filesize); // byte swap the header for (i = 0; i < (int) sizeof(*qcvm->progs) / 4; i++) @@ -2108,7 +2109,7 @@ qboolean PR_LoadProgs (const char *filename, qboolean fatal) qcvm->functions = (dfunction_t *)((byte *)qcvm->progs + qcvm->progs->ofs_functions); qcvm->strings = (char *)qcvm->progs + qcvm->progs->ofs_strings; - if (qcvm->progs->ofs_strings + qcvm->progs->numstrings >= com_filesize) + if (qcvm->progs->ofs_strings + qcvm->progs->numstrings >= (int64_t)filesize) Host_Error ("progs.dat strings go past end of file\n"); // initialize the strings diff --git a/Quake/quakedef.h b/Quake/quakedef.h index accc815c4..4d1cceaf6 100644 --- a/Quake/quakedef.h +++ b/Quake/quakedef.h @@ -242,6 +242,7 @@ typedef struct #include "sys.h" #include "common.h" +#include "filesys.h" #include "bspfile.h" #include "zone.h" #include "mathlib.h" diff --git a/Quake/r_part.c b/Quake/r_part.c index e78e25dff..96c7a2707 100644 --- a/Quake/r_part.c +++ b/Quake/r_part.c @@ -193,19 +193,20 @@ R_ReadPointFile_f */ void R_ReadPointFile_f (void) { - FILE *f; + qfshandle_t *f; vec3_t org; int r; int c; particle_t *p; char name[MAX_QPATH]; + char rdbuf[256]; if (cls.state != ca_connected) return; // need an active map. q_snprintf (name, sizeof(name), "maps/%s.pts", cl.mapname); - COM_FOpenFile (name, &f, NULL); + f = QFS_FOpenFile (name, NULL); if (!f) { Con_Printf ("couldn't open %s\n", name); @@ -215,9 +216,11 @@ void R_ReadPointFile_f (void) Con_Printf ("Reading %s...\n", name); c = 0; org[0] = org[1] = org[2] = 0; // silence pesky compiler warnings - for ( ;; ) + while (!QFS_Eof (f)) { - r = fscanf (f,"%f %f %f\n", &org[0], &org[1], &org[2]); + memset (rdbuf, 0, sizeof(rdbuf)); + QFS_GetLine (f, rdbuf, sizeof(rdbuf)); + r = sscanf (rdbuf,"%f %f %f", &org[0], &org[1], &org[2]); if (r != 3) break; c++; @@ -235,7 +238,7 @@ void R_ReadPointFile_f (void) VectorCopy (org, p->org); } - fclose (f); + QFS_CloseFile (f); Con_Printf ("%i points read\n", c); } diff --git a/Quake/snd_codec.c b/Quake/snd_codec.c index 7c332e7f5..08cf1de1f 100644 --- a/Quake/snd_codec.c +++ b/Quake/snd_codec.c @@ -283,14 +283,10 @@ int S_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer) snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec, qboolean loop) { snd_stream_t *stream; - FILE *handle; - qboolean pak; - long length; /* Try to open the file */ - length = (long) COM_FOpenFile(filename, &handle, NULL); - pak = file_from_pak; - if (length == -1) + qfshandle_t* handle = QFS_FOpenFile(filename, NULL); + if (handle == NULL) { Con_DPrintf("Couldn't open %s\n", filename); return NULL; @@ -300,11 +296,7 @@ snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec, qboolean stream = (snd_stream_t *) Z_Malloc(sizeof(snd_stream_t)); stream->codec = codec; stream->loop = loop; - stream->fh.file = handle; - stream->fh.start = ftell(handle); - stream->fh.pos = 0; - stream->fh.length = length; - stream->fh.pak = stream->pak = pak; + stream->fh = handle; q_strlcpy(stream->name, filename, MAX_QPATH); return stream; @@ -312,7 +304,7 @@ snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec, qboolean void S_CodecUtilClose(snd_stream_t **stream) { - fclose((*stream)->fh.file); + QFS_CloseFile((*stream)->fh); Z_Free(*stream); *stream = NULL; } diff --git a/Quake/snd_codec.h b/Quake/snd_codec.h index fcc9f8644..f70f48dc8 100644 --- a/Quake/snd_codec.h +++ b/Quake/snd_codec.h @@ -48,8 +48,7 @@ typedef struct snd_codec_s snd_codec_t; typedef struct snd_stream_s { - fshandle_t fh; - qboolean pak; + qfshandle_t *fh; char name[MAX_QPATH]; /* name of the source file */ snd_info_t info; stream_status_t status; diff --git a/Quake/snd_flac.c b/Quake/snd_flac.c index 838404b3b..d57873073 100644 --- a/Quake/snd_flac.c +++ b/Quake/snd_flac.c @@ -69,7 +69,7 @@ typedef size_t FLAC_SIZE_T; typedef struct { FLAC__StreamDecoder *decoder; - fshandle_t *file; + qfshandle_t *file; snd_info_t *info; byte *buffer; int size, pos, error; @@ -92,9 +92,7 @@ flac_read_func (const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], flacfile_t *ff = (flacfile_t *) client_data; if (*bytes > 0) { - *bytes = FS_fread(buffer, 1, *bytes, ff->file); - if (FS_ferror(ff->file)) - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + *bytes = (FLAC_SIZE_T)QFS_ReadFile(ff->file, buffer, (size_t)*bytes); if (*bytes == 0) return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; @@ -107,7 +105,7 @@ flac_seek_func (const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) { flacfile_t *ff = (flacfile_t *) client_data; - if (FS_fseek(ff->file, (long)absolute_byte_offset, SEEK_SET) < 0) + if (QFS_Seek(ff->file, (qfileofs_t)absolute_byte_offset, SEEK_SET) < 0) return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; return FLAC__STREAM_DECODER_SEEK_STATUS_OK; } @@ -117,7 +115,7 @@ flac_tell_func (const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) { flacfile_t *ff = (flacfile_t *) client_data; - long pos = FS_ftell (ff->file); + qfileofs_t pos = QFS_Tell (ff->file); if (pos < 0) return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; *absolute_byte_offset = (FLAC__uint64) pos; return FLAC__STREAM_DECODER_TELL_STATUS_OK; @@ -128,7 +126,7 @@ flac_length_func (const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) { flacfile_t *ff = (flacfile_t *) client_data; - *stream_length = (FLAC__uint64) FS_filelength (ff->file); + *stream_length = (FLAC__uint64) QFS_FileSize (ff->file); return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; } @@ -136,7 +134,7 @@ static FLAC__bool flac_eof_func (const FLAC__StreamDecoder *decoder, void *client_data) { flacfile_t *ff = (flacfile_t *) client_data; - if (FS_feof (ff->file)) return true; + if (QFS_Eof (ff->file)) return true; return false; } @@ -249,7 +247,7 @@ static qboolean S_FLAC_CodecOpenStream (snd_stream_t *stream) stream->priv = ff; ff->info = & stream->info; - ff->file = & stream->fh; + ff->file = stream->fh; ff->info->dataofs = -1; /* check for STREAMINFO metadata existence */ #ifdef LEGACY_FLAC diff --git a/Quake/snd_mem.c b/Quake/snd_mem.c index b7951b486..28256f47f 100644 --- a/Quake/snd_mem.c +++ b/Quake/snd_mem.c @@ -99,6 +99,7 @@ sfxcache_t *S_LoadSound (sfx_t *s) wavinfo_t info; int len; float stepscale; + size_t filesize; sfxcache_t *sc; // see if still in memory @@ -114,7 +115,7 @@ sfxcache_t *S_LoadSound (sfx_t *s) // Con_Printf ("loading %s\n",namebuffer); - data = COM_LoadMallocFile (namebuffer, NULL); + data = QFS_LoadMallocFile (namebuffer, NULL, &filesize); if (!data) { @@ -122,7 +123,7 @@ sfxcache_t *S_LoadSound (sfx_t *s) return NULL; } - info = GetWavinfo (s->name, data, com_filesize); + info = GetWavinfo (s->name, data, filesize); if (info.channels != 1) { free (data); diff --git a/Quake/snd_mikmod.c b/Quake/snd_mikmod.c index bc0859b2d..6ea4faa51 100644 --- a/Quake/snd_mikmod.c +++ b/Quake/snd_mikmod.c @@ -52,33 +52,41 @@ typedef struct _mik_priv { /* no iobase members in libmikmod <= 3.2.0-beta2 */ long iobase, prev_iobase; - fshandle_t *fh; + qfshandle_t *fh; MODULE *module; } mik_priv_t; static int MIK_Seek (MREADER *r, long ofs, int whence) { - return FS_fseek(((mik_priv_t *)r)->fh, ofs, whence); + mik_priv_t* pmik = (mik_priv_t*)r; + return (int)QFS_Seek(pmik->fh, (qfileofs_t)ofs, whence); } static long MIK_Tell (MREADER *r) { - return FS_ftell(((mik_priv_t *)r)->fh); + mik_priv_t* pmik = (mik_priv_t*)r; + return (long)QFS_Tell(pmik->fh); } static BOOL MIK_Read (MREADER *r, void *ptr, size_t siz) { - return !!FS_fread(ptr, siz, 1, ((mik_priv_t *)r)->fh); + mik_priv_t* pmik = (mik_priv_t*)r; + return QFS_ReadFile(pmik->fh, ptr, siz) == siz; } static int MIK_Get (MREADER *r) { - return FS_fgetc(((mik_priv_t *)r)->fh); + char c; + qboolean eof_flag; + mik_priv_t* pmik = (mik_priv_t*)r; + c = QFS_GetChar(pmik->fh, &eof_flag); + return eof_flag ? EOF : (int)c; } static BOOL MIK_Eof (MREADER *r) { - return FS_feof(((mik_priv_t *)r)->fh); + mik_priv_t* pmik = (mik_priv_t*)r; + return QFS_Eof(pmik->fh) ? 1 : 0; } static qboolean S_MIKMOD_CodecInitialize (void) @@ -140,7 +148,7 @@ static qboolean S_MIKMOD_CodecOpenStream (snd_stream_t *stream) priv->Read = MIK_Read; priv->Get = MIK_Get; priv->Eof = MIK_Eof; - priv->fh = &stream->fh; + priv->fh = stream->fh; priv->module = Player_LoadGeneric((MREADER *)stream->priv, 64, 0); if (!priv->module) diff --git a/Quake/snd_modplug.c b/Quake/snd_modplug.c index 806c09a79..48227705c 100644 --- a/Quake/snd_modplug.c +++ b/Quake/snd_modplug.c @@ -61,13 +61,13 @@ static qboolean S_MODPLUG_CodecOpenStream (snd_stream_t *stream) { /* need to load the whole file into memory and pass it to libmodplug */ byte *moddata; - long len; + qfileofs_t len; int mark; - len = FS_filelength (&stream->fh); + len = QFS_FileSize (stream->fh); mark = Hunk_LowMark(); moddata = (byte *) Hunk_Alloc(len); - FS_fread(moddata, 1, len, &stream->fh); + QFS_ReadFile(stream->fh, moddata, len); S_MODPLUG_SetSettings(stream); stream->priv = ModPlug_Load(moddata, len); diff --git a/Quake/snd_mp3.c b/Quake/snd_mp3.c index b3bf9a145..31f33badb 100644 --- a/Quake/snd_mp3.c +++ b/Quake/snd_mp3.c @@ -84,8 +84,7 @@ static int mp3_inputdata(snd_stream_t *stream) */ memmove(p->mp3_buffer, p->Stream.next_frame, remaining); - bytes_read = FS_fread(p->mp3_buffer + remaining, 1, - MP3_BUFFER_SIZE - remaining, &stream->fh); + bytes_read = QFS_ReadFile(stream->fh, p->mp3_buffer + remaining, MP3_BUFFER_SIZE - remaining); if (bytes_read == 0) return -1; @@ -109,8 +108,8 @@ static int mp3_startread(snd_stream_t *stream) * format. The decoded frame will be saved off so that it * can be processed later. */ - ReadSize = FS_fread(p->mp3_buffer, 1, MP3_BUFFER_SIZE, &stream->fh); - if (!ReadSize || FS_ferror(&stream->fh)) + ReadSize = QFS_ReadFile(stream->fh, p->mp3_buffer, MP3_BUFFER_SIZE); + if (!ReadSize) return -1; mad_stream_buffer(&p->Stream, p->mp3_buffer, ReadSize); @@ -279,7 +278,7 @@ static int mp3_madseek(snd_stream_t *stream, unsigned long offset) unsigned long to_skip_samples = 0; /* Reset all */ - FS_rewind(&stream->fh); + QFS_Seek(stream->fh, 0, SEEK_SET); mad_timer_reset(&p->Timer); p->FrameCount = 0; @@ -301,8 +300,8 @@ static int mp3_madseek(snd_stream_t *stream, unsigned long offset) size_t leftover = p->Stream.bufend - p->Stream.next_frame; memcpy(p->mp3_buffer, p->Stream.this_frame, leftover); - bytes_read = FS_fread(p->mp3_buffer + leftover, (size_t) 1, - MP3_BUFFER_SIZE - leftover, &stream->fh); + bytes_read = QFS_ReadFile(stream->fh, p->mp3_buffer + leftover, + MP3_BUFFER_SIZE - leftover); if (bytes_read <= 0) { Con_DPrintf("seek failure. unexpected EOF (frames=%lu leftover=%lu)\n", @@ -362,7 +361,7 @@ static int mp3_madseek(snd_stream_t *stream, unsigned long offset) { p->FrameCount = offset / samples; to_skip_samples = offset % samples; - if (0 != FS_fseek(&stream->fh, (p->FrameCount * consumed / 64), SEEK_SET)) + if (0 != QFS_Seek(stream->fh, (p->FrameCount * consumed / 64), SEEK_SET)) return -1; /* Reset Stream for refilling buffer */ diff --git a/Quake/snd_mp3tag.c b/Quake/snd_mp3tag.c index d778d10af..1efa729ce 100644 --- a/Quake/snd_mp3tag.c +++ b/Quake/snd_mp3tag.c @@ -100,13 +100,16 @@ static inline int is_lyrics3tag(const unsigned char *data, long length) { return 0; } static long get_lyrics3v1_len(snd_stream_t *stream) { - const char *p; long i, len; + const char *p; long i; + qfileofs_t len; char buf[5104]; /* needs manual search: http://id3.org/Lyrics3 */ - if (stream->fh.length < 20) return -1; - len = (stream->fh.length > 5109)? 5109 : stream->fh.length; - FS_fseek(&stream->fh, -len, SEEK_END); - FS_fread(buf, 1, (len -= 9), &stream->fh); /* exclude footer */ + qfileofs_t filesize = QFS_FileSize(stream->fh); + if (filesize < 20) + return -1; + len = (filesize > 5109)? 5109 : (long)filesize; + QFS_Seek(stream->fh, -len, SEEK_END); + QFS_ReadFile(stream->fh, buf, (len -= 9)); /* exclude footer */ /* strstr() won't work here. */ for (i = len - 11, p = buf; i >= 0; --i, ++p) { if (memcmp(p, "LYRICSBEGIN", 11) == 0) @@ -126,7 +129,7 @@ static inline qboolean verify_lyrics3v2(const unsigned char *data, long length) if (memcmp(data,"LYRICSBEGIN",11) == 0) return true; return false; } -#define MMTAG_PARANOID + static qboolean is_musicmatch(const unsigned char *data, long length) { /* From docs/musicmatch.txt in id3lib: https://sourceforge.net/projects/id3lib/ Overall tag structure: @@ -162,12 +165,12 @@ static qboolean is_musicmatch(const unsigned char *data, long length) { !q_isdigit(data[34]) ||!q_isdigit(data[35])) { return false; } - #ifdef MMTAG_PARANOID + /* [36..47]: 12 bytes trailing space */ for (length = 36; length < 48; ++length) { if (data[length] != ' ') return false; } - #endif + return true; } static long get_musicmatch_len(snd_stream_t *stream) { @@ -175,10 +178,13 @@ static long get_musicmatch_len(snd_stream_t *stream) { const unsigned char syncstr[10] = {'1','8','2','7','3','6','4','5',0,0}; unsigned char buf[256]; int i, j, imgext_ofs, version_ofs; - long len; + qfileofs_t len, filesize; + + memset(buf, 0, sizeof(buf)); + filesize = QFS_FileSize(stream->fh); - FS_fseek(&stream->fh, -68, SEEK_END); - FS_fread(buf, 1, 20, &stream->fh); + QFS_Seek(stream->fh, -68, SEEK_END); + QFS_ReadFile(stream->fh, buf, 20); imgext_ofs = (int)((buf[3] <<24) | (buf[2] <<16) | (buf[1] <<8) | buf[0] ); version_ofs = (int)((buf[15]<<24) | (buf[14]<<16) | (buf[13]<<8) | buf[12]); if (version_ofs <= imgext_ofs) return -1; @@ -189,58 +195,64 @@ static long get_musicmatch_len(snd_stream_t *stream) { * bytes), we can _not_ directly calculate using deltas from the offsets * section. */ for (i = 0; i < 4; ++i) { + memset(buf, 0, sizeof(buf)); /* 48: footer, 20: offsets, 256: version info */ len = metasizes[i] + 48 + 20 + 256; - if (stream->fh.length < len) return -1; - FS_fseek(&stream->fh, -len, SEEK_END); - FS_fread(buf, 1, 256, &stream->fh); + if (filesize < len) + return -1; + QFS_Seek(stream->fh, -len, SEEK_END); + QFS_ReadFile(stream->fh, buf, 256); /* [0..9]: sync string, [30..255]: 0x20 */ - #ifdef MMTAG_PARANOID + for (j = 30; j < 256; ++j) { if (buf[j] != ' ') break; } if (j < 256) continue; - #endif + if (memcmp(buf, syncstr, 10) == 0) { break; } } if (i == 4) return -1; /* no luck. */ - #ifdef MMTAG_PARANOID + memset(buf, 0, sizeof(buf)); /* unused section: (4 bytes of 0x00) */ - FS_fseek(&stream->fh, -(len + 4), SEEK_END); - FS_fread(buf, 1, 4, &stream->fh); j = 0; + QFS_Seek(stream->fh, -(len + 4), SEEK_END); + QFS_ReadFile(stream->fh, buf, 4); + j = 0; if (memcmp(buf, &j, 4) != 0) return -1; - #endif + len += (version_ofs - imgext_ofs); - if (stream->fh.length < len) return -1; - FS_fseek(&stream->fh, -len, SEEK_END); - FS_fread(buf, 1, 8, &stream->fh); + if (filesize < len) return -1; + memset(buf, 0, sizeof(buf)); + QFS_Seek(stream->fh, -len, SEEK_END); + QFS_ReadFile(stream->fh, buf, 8); j = (int)((buf[7] <<24) | (buf[6] <<16) | (buf[5] <<8) | buf[4]); if (j < 0) return -1; /* verify image size: */ /* without this, we may land at a wrong place. */ if (j + 12 != version_ofs - imgext_ofs) return -1; /* try finding the optional header */ - if (stream->fh.length < len + 256) return len; - FS_fseek(&stream->fh, -(len + 256), SEEK_END); - FS_fread(buf, 1, 256, &stream->fh); + if (filesize < len + 256) return len; + QFS_Seek(stream->fh, -(len + 256), SEEK_END); + QFS_ReadFile(stream->fh, buf, 256); /* [0..9]: sync string, [30..255]: 0x20 */ if (memcmp(buf, syncstr, 10) != 0) { return len; } - #ifdef MMTAG_PARANOID + for (j = 30; j < 256; ++j) { if (buf[j] != ' ') return len; } - #endif + return len + 256; /* header is present. */ } -static int probe_id3v1(snd_stream_t *stream, unsigned char *buf, int atend) { - if (stream->fh.length >= 128) { - FS_fseek(&stream->fh, -128, SEEK_END); - if (FS_fread(buf, 1, 128, &stream->fh) != 128) +static int probe_id3v1(snd_stream_t *stream, unsigned char *buf, int atend) +{ + qfileofs_t filesize = QFS_FileSize(stream->fh); + if (filesize >= 128) { + QFS_Seek(stream->fh, -128, SEEK_END); + if (QFS_ReadFile(stream->fh, buf, 128) != 128) return -1; if (is_id3v1(buf, 128)) { if (!atend) { /* possible false positive? */ @@ -250,7 +262,7 @@ static int probe_id3v1(snd_stream_t *stream, unsigned char *buf, int atend) { return 0; } } - stream->fh.length -= 128; + QFS_IgnoreBytes(stream->fh, 128, SEEK_END); Con_DPrintf("MP3: skipped %ld bytes ID3v1 tag\n", 128L); return 1; /* FIXME: handle possible double-ID3v1 tags? */ @@ -258,33 +270,37 @@ static int probe_id3v1(snd_stream_t *stream, unsigned char *buf, int atend) { } return 0; } -static int probe_mmtag(snd_stream_t *stream, unsigned char *buf) { +static int probe_mmtag(snd_stream_t *stream, unsigned char *buf) +{ long len; - if (stream->fh.length >= 68) { - FS_fseek(&stream->fh, -48, SEEK_END); - if (FS_fread(buf, 1, 48, &stream->fh) != 48) + qfileofs_t filesize = QFS_FileSize(stream->fh); + if (filesize >= 68) + { + QFS_Seek(stream->fh, -48, SEEK_END); + if (QFS_ReadFile(stream->fh, buf, 48) != 48) return -1; if (is_musicmatch(buf, 48)) { len = get_musicmatch_len(stream); - if (len < 0) return -1; - if (len >= stream->fh.length) return -1; - stream->fh.length -= len; + if (len < 0) + return -1; + QFS_IgnoreBytes(stream->fh, (qfileofs_t)len, SEEK_END); Con_DPrintf("MP3: skipped %ld bytes MusicMatch tag\n", len); return 1; } } return 0; } -static int probe_apetag(snd_stream_t *stream, unsigned char *buf) { +static int probe_apetag(snd_stream_t *stream, unsigned char *buf) +{ long len; - if (stream->fh.length >= 32) { - FS_fseek(&stream->fh, -32, SEEK_END); - if (FS_fread(buf, 1, 32, &stream->fh) != 32) + qfileofs_t filesize = QFS_FileSize(stream->fh); + if (filesize >= 32) { + QFS_Seek(stream->fh, -32, SEEK_END); + if (QFS_ReadFile(stream->fh, buf, 32) != 32) return -1; if (is_apetag(buf, 32)) { len = get_ape_len(buf); - if (len >= stream->fh.length) return -1; - stream->fh.length -= len; + QFS_IgnoreBytes(stream->fh, (qfileofs_t)len, SEEK_END); Con_DPrintf("MP3: skipped %ld bytes APE tag\n", len); return 1; } @@ -293,27 +309,31 @@ static int probe_apetag(snd_stream_t *stream, unsigned char *buf) { } static int probe_lyrics3(snd_stream_t *stream, unsigned char *buf) { long len; - if (stream->fh.length >= 15) { - FS_fseek(&stream->fh, -15, SEEK_END); - if (FS_fread(buf, 1, 15, &stream->fh) != 15) + qfileofs_t filesize = QFS_FileSize(stream->fh); + if (filesize >= 15) { + QFS_Seek(stream->fh, -15, SEEK_END); + if (QFS_ReadFile(stream->fh, buf, 15) != 15) return -1; len = is_lyrics3tag(buf, 15); if (len == 2) { len = get_lyrics3v2_len(buf, 6); - if (len >= stream->fh.length) return -1; - if (len < 15) return -1; - FS_fseek(&stream->fh, -len, SEEK_END); - if (FS_fread(buf, 1, 11, &stream->fh) != 11) + if (len >= filesize) + return -1; + if (len < 15) + return -1; + QFS_Seek(stream->fh, -len, SEEK_END); + if (QFS_ReadFile(stream->fh, buf, 11) != 11) return -1; - if (!verify_lyrics3v2(buf, 11)) return -1; - stream->fh.length -= len; + if (!verify_lyrics3v2(buf, 11)) + return -1; + QFS_IgnoreBytes(stream->fh, len, SEEK_END); Con_DPrintf("MP3: skipped %ld bytes Lyrics3 tag\n", len); return 1; } else if (len == 1) { len = get_lyrics3v1_len(stream); if (len < 0) return -1; - stream->fh.length -= len; + QFS_IgnoreBytes(stream->fh, len, SEEK_END); Con_DPrintf("MP3: skipped %ld bytes Lyrics3 tag\n", len); return 1; } @@ -327,9 +347,6 @@ int mp3_skiptags(snd_stream_t *stream) long len; size_t readsize; int c_id3, c_ape, c_lyr, c_mm; int rc = -1; - /* failsafe */ - long oldlength = stream->fh.length; - long oldstart = stream->fh.start; /* MP3 standard has no metadata format, so everyone invented * their own thing, even with extensions, until ID3v2 became @@ -339,24 +356,21 @@ int mp3_skiptags(snd_stream_t *stream) * double tags. -- O.S. */ - readsize = FS_fread(buf, 1, 128, &stream->fh); - if (!readsize || FS_ferror(&stream->fh)) goto fail; + readsize = QFS_ReadFile(stream->fh, buf, 128); + if (readsize != 128) + goto fail; /* ID3v2 tag is at the start */ if (is_id3v2(buf, readsize)) { len = get_id3v2_len(buf, (long)readsize); - if (len >= stream->fh.length) goto fail; - stream->fh.start += len; - stream->fh.length -= len; + QFS_IgnoreBytes(stream->fh, len, SEEK_SET); Con_DPrintf("MP3: skipped %ld bytes ID3v2 tag\n", len); } /* APE tag _might_ be at the start (discouraged * but not forbidden, either.) read the header. */ else if (is_apetag(buf, readsize)) { len = get_ape_len(buf); - if (len >= stream->fh.length) goto fail; - stream->fh.start += len; - stream->fh.length -= len; + QFS_IgnoreBytes(stream->fh, len, SEEK_SET); Con_DPrintf("MP3: skipped %ld bytes APE tag\n", len); } @@ -393,13 +407,12 @@ int mp3_skiptags(snd_stream_t *stream) break; } /* for (;;) */ - rc = (stream->fh.length > 0)? 0 : -1; - fail: - if (rc < 0) { - stream->fh.start = oldstart; - stream->fh.length = oldlength; - } - FS_rewind(&stream->fh); - return rc; + rc = (QFS_FileSize(stream->fh) > 0)? 0 : -1; +fail: + if (rc < 0) + QFS_IgnoreBytes(stream->fh, 0, SEEK_CUR); + + QFS_Seek(stream->fh, 0, SEEK_SET); + return rc; } #endif /* USE_CODEC_MP3 */ diff --git a/Quake/snd_mpg123.c b/Quake/snd_mpg123.c index 74508f23d..878b3ba6a 100644 --- a/Quake/snd_mpg123.c +++ b/Quake/snd_mpg123.c @@ -42,17 +42,14 @@ typedef struct _mp3_priv_t /* CALLBACKS: libmpg123 expects POSIX read/lseek() behavior! */ static ssize_t mp3_read (void *f, void *buf, size_t size) { - ssize_t ret = (ssize_t) FS_fread(buf, 1, size, (fshandle_t *)f); - if (ret == 0 && errno != 0) - return -1; - return ret; + return (ssize_t) QFS_ReadFile((qfshandle_t*)f, buf, size); } static off_t mp3_seek (void *f, off_t offset, int whence) { if (f == NULL) return -1; - if (FS_fseek((fshandle_t *)f, (long) offset, whence) < 0) + if (QFS_Seek((qfshandle_t *)f, (qfileofs_t) offset, whence) < 0) return (off_t)-1; - return (off_t) FS_ftell((fshandle_t *)f); + return (off_t) QFS_Tell((qfshandle_t *)f); } static qboolean S_MP3_CodecInitialize (void) @@ -100,7 +97,7 @@ static qboolean S_MP3_CodecOpenStream (snd_stream_t *stream) } if (mpg123_replace_reader_handle(priv->handle, mp3_read, mp3_seek, NULL) != MPG123_OK || - mpg123_open_handle(priv->handle, &stream->fh) != MPG123_OK) + mpg123_open_handle(priv->handle, stream->fh) != MPG123_OK) { Con_Printf("Unable to open mpg123 handle\n"); goto _fail; diff --git a/Quake/snd_opus.c b/Quake/snd_opus.c index ea5e4f248..8f5f81d84 100644 --- a/Quake/snd_opus.c +++ b/Quake/snd_opus.c @@ -41,29 +41,24 @@ static int opc_fclose (void *f) static int opc_fread (void *f, unsigned char *buf, int size) { - int ret; - if (size < 0) { errno = EINVAL; return -1; } - ret = (int) FS_fread(buf, 1, (size_t)size, (fshandle_t *)f); - if (ret == 0 && errno != 0) - ret = -1; - return ret; + return (int) QFS_ReadFile((qfshandle_t*)f, buf, (size_t)size); } static int opc_fseek (void *f, opus_int64 off, int whence) { if (f == NULL) return (-1); - return FS_fseek((fshandle_t *)f, (long) off, whence); + return QFS_Seek((qfshandle_t*)f, (long) off, whence); } static opus_int64 opc_ftell (void *f) { - return (opus_int64) FS_ftell((fshandle_t *)f); + return (opus_int64) QFS_Tell((qfshandle_t *)f); } static const OpusFileCallbacks opc_qfs = @@ -90,7 +85,7 @@ static qboolean S_OPUS_CodecOpenStream (snd_stream_t *stream) long numstreams; int res; - opFile = op_open_callbacks(&stream->fh, &opc_qfs, NULL, 0, &res); + opFile = op_open_callbacks(stream->fh, &opc_qfs, NULL, 0, &res); if (!opFile) { Con_Printf("%s is not a valid Opus file (error %i).\n", diff --git a/Quake/snd_umx.c b/Quake/snd_umx.c index 11bfbcd35..4d1b06c43 100644 --- a/Quake/snd_umx.c +++ b/Quake/snd_umx.c @@ -116,13 +116,13 @@ static fci_t get_fci (const char *in, int *pos) return a; } -static int get_objtype (fshandle_t *f, int32_t ofs, int type) +static int get_objtype (qfshandle_t *f, int32_t ofs, int type) { char sig[16]; _retry: memset(sig, 0, sizeof(sig)); - FS_fseek(f, ofs, SEEK_SET); - FS_fread(sig, 16, 1, f); + QFS_Seek(f, ofs, SEEK_SET); + QFS_ReadFile(f, sig, 16); if (type == UMUSIC_IT) { if (memcmp(sig, "IMPM", 4) == 0) return UMUSIC_IT; @@ -131,9 +131,11 @@ static int get_objtype (fshandle_t *f, int32_t ofs, int type) if (type == UMUSIC_XM) { if (memcmp(sig, "Extended Module:", 16) != 0) return -1; - FS_fread(sig, 16, 1, f); + memset(sig, 0, sizeof(sig)); + QFS_ReadFile(f, sig, 16); if (sig[0] != ' ') return -1; - FS_fread(sig, 16, 1, f); + memset(sig, 0, sizeof(sig)); + QFS_ReadFile(f, sig, 16); if (sig[5] != 0x1a) return -1; return UMUSIC_XM; } @@ -150,8 +152,9 @@ static int get_objtype (fshandle_t *f, int32_t ofs, int type) return -1; } - FS_fseek(f, ofs + 44, SEEK_SET); - FS_fread(sig, 4, 1, f); + memset(sig, 0, sizeof(sig)); + QFS_Seek(f, ofs + 44, SEEK_SET); + QFS_ReadFile(f, sig, 4); if (type == UMUSIC_S3M) { if (memcmp(sig, "SCRM", 4) == 0) return UMUSIC_S3M; @@ -161,9 +164,9 @@ static int get_objtype (fshandle_t *f, int32_t ofs, int type) type = UMUSIC_IT; goto _retry; } - - FS_fseek(f, ofs + 1080, SEEK_SET); - FS_fread(sig, 4, 1, f); + memset(sig, 0, sizeof(sig)); + QFS_Seek(f, ofs + 1080, SEEK_SET); + QFS_ReadFile(f, sig, 4); if (type == UMUSIC_MOD) { if (memcmp(sig, "M.K.", 4) == 0 || memcmp(sig, "M!K!", 4) == 0) return UMUSIC_MOD; @@ -173,14 +176,14 @@ static int get_objtype (fshandle_t *f, int32_t ofs, int type) return -1; } -static int read_export (fshandle_t *f, const struct upkg_hdr *hdr, +static int read_export (qfshandle_t *f, const struct upkg_hdr *hdr, int32_t *ofs, int32_t *objsize) { char buf[40]; int idx = 0, t; - FS_fseek(f, *ofs, SEEK_SET); - if (FS_fread(buf, 4, 10, f) < 10) + QFS_Seek(f, *ofs, SEEK_SET); + if (QFS_ReadFile(f, buf, sizeof(buf)) < sizeof(buf)) return -1; if (hdr->file_version < 40) idx += 8; /* 00 00 00 00 00 00 00 00 */ @@ -194,7 +197,7 @@ static int read_export (fshandle_t *f, const struct upkg_hdr *hdr, return t; /* return type_name index */ } -static int read_typname(fshandle_t *f, const struct upkg_hdr *hdr, +static int read_typname(qfshandle_t *f, const struct upkg_hdr *hdr, int idx, char *out) { int i, s; @@ -202,10 +205,10 @@ static int read_typname(fshandle_t *f, const struct upkg_hdr *hdr, char buf[64]; if (idx >= hdr->name_count) return -1; - memset(buf, 0, 64); + memset(buf, 0, sizeof(buf)); for (i = 0, l = 0; i <= idx; i++) { - if (FS_fseek(f, hdr->name_offset + l, SEEK_SET) < 0) return -1; - if (!FS_fread(buf, 1, 63, f)) return -1; + if (QFS_Seek(f, hdr->name_offset + l, SEEK_SET) < 0) return -1; + if (!QFS_ReadFile(f, buf, 63)) return -1; if (hdr->file_version >= 64) { s = *(signed char *)buf; /* numchars *including* terminator */ if (s <= 0) return -1; @@ -220,16 +223,16 @@ static int read_typname(fshandle_t *f, const struct upkg_hdr *hdr, return 0; } -static int probe_umx (fshandle_t *f, const struct upkg_hdr *hdr, +static int probe_umx (qfshandle_t *f, const struct upkg_hdr *hdr, int32_t *ofs, int32_t *objsize) { int i, idx, t; int32_t s, pos; - long fsiz; + qfileofs_t fsiz; char buf[64]; idx = 0; - fsiz = FS_filelength (f); + fsiz = QFS_FileSize (f); if (hdr->name_offset >= fsiz || hdr->export_offset >= fsiz || @@ -243,9 +246,9 @@ static int probe_umx (fshandle_t *f, const struct upkg_hdr *hdr, * have only one export. Kran32.umx from Unreal has two, * but both pointing to the same music. */ if (hdr->export_offset >= fsiz) return -1; - memset(buf, 0, 64); - FS_fseek(f, hdr->export_offset, SEEK_SET); - FS_fread(buf, 1, 64, f); + memset(buf, 0, sizeof(buf)); + QFS_Seek(f, hdr->export_offset, SEEK_SET); + QFS_ReadFile(f, buf, sizeof(buf)); get_fci(&buf[idx], &idx); /* skip class_index */ get_fci(&buf[idx], &idx); /* skip super_index */ @@ -276,9 +279,9 @@ static int probe_umx (fshandle_t *f, const struct upkg_hdr *hdr, return t; } -static int32_t probe_header (fshandle_t *f, struct upkg_hdr *hdr) +static int32_t probe_header (qfshandle_t *f, struct upkg_hdr *hdr) { - if (FS_fread(hdr, 1, UPKG_HDR_SIZE, f) < UPKG_HDR_SIZE) + if (QFS_ReadFile(f, hdr, UPKG_HDR_SIZE) < UPKG_HDR_SIZE) return -1; /* byte swap the header - all members are 32 bit LE values */ hdr->tag = (uint32_t) LittleLong(hdr->tag); @@ -329,7 +332,7 @@ static int32_t probe_header (fshandle_t *f, struct upkg_hdr *hdr) #endif /* #if 0 */ } -static int process_upkg (fshandle_t *f, int32_t *ofs, int32_t *objsize) +static int process_upkg (qfshandle_t *f, int32_t *ofs, int32_t *objsize) { struct upkg_hdr header; @@ -354,18 +357,16 @@ static qboolean S_UMX_CodecOpenStream (snd_stream_t *stream) int type; int32_t ofs = 0, size = 0; - type = process_upkg(&stream->fh, &ofs, &size); + type = process_upkg(stream->fh, &ofs, &size); if (type < 0) { Con_DPrintf("%s: unrecognized umx\n", stream->name); return false; } Con_DPrintf("%s: %s data @ 0x%x, %d bytes\n", stream->name, mustype[type], ofs, size); - /* hack the fshandle_t start pos and length members so - * that only the relevant data is accessed from now on */ - stream->fh.start += ofs; - stream->fh.length = size; - FS_fseek(&stream->fh, 0, SEEK_SET); + QFS_IgnoreBytes(stream->fh, (qfileofs_t)ofs, SEEK_SET); + QFS_IgnoreBytes(stream->fh, QFS_FileSize(stream->fh) - size, SEEK_END); + QFS_Seek(stream->fh, 0, SEEK_SET); switch (type) { case UMUSIC_IT: diff --git a/Quake/snd_vorbis.c b/Quake/snd_vorbis.c index 7ea02bd9a..568aeacb4 100644 --- a/Quake/snd_vorbis.c +++ b/Quake/snd_vorbis.c @@ -50,18 +50,28 @@ static int ovc_fclose (void *f) return 0; /* we fclose() elsewhere. */ } +static size_t ovc_fread(void* buf, size_t size, size_t nmemb, void* f) +{ + return QFS_ReadFile((qfshandle_t*)f, buf, size * nmemb); +} + static int ovc_fseek (void *f, ogg_int64_t off, int whence) { if (f == NULL) return (-1); - return FS_fseek((fshandle_t *)f, (long) off, whence); + return (int)QFS_Seek((qfshandle_t *)f, (qfileofs_t) off, whence); +} + +static long ovc_ftell(void* f) +{ + return (long)QFS_Tell((qfshandle_t*)f); } static ov_callbacks ovc_qfs = { - (size_t (*)(void *, size_t, size_t, void *)) FS_fread, - (int (*)(void *, ogg_int64_t, int)) ovc_fseek, - (int (*)(void *)) ovc_fclose, - (long (*)(void *)) FS_ftell + &ovc_fread, + &ovc_fseek, + &ovc_fclose, + &ovc_ftell }; static qboolean S_VORBIS_CodecInitialize (void) @@ -82,7 +92,7 @@ static qboolean S_VORBIS_CodecOpenStream (snd_stream_t *stream) ovFile = (OggVorbis_File *) Z_Malloc(sizeof(OggVorbis_File)); stream->priv = ovFile; - res = ov_open_callbacks(&stream->fh, ovFile, NULL, 0, ovc_qfs); + res = ov_open_callbacks(stream->fh, ovFile, NULL, 0, ovc_qfs); if (res != 0) { Con_Printf("%s is not a valid Ogg Vorbis file (error %i).\n", diff --git a/Quake/snd_wave.c b/Quake/snd_wave.c index b494b6af9..ab8c690f1 100644 --- a/Quake/snd_wave.c +++ b/Quake/snd_wave.c @@ -34,10 +34,10 @@ FGetLittleLong ================= */ -static int FGetLittleLong (FILE *f, qboolean *ok) +static int32_t FGetLittleLong (qfshandle_t *f, qboolean *ok) { - int v; - *ok &= fread(&v, sizeof(v), 1, f) == 1; + int32_t v; + *ok &= QFS_ReadFile(f, &v, sizeof(v)) == sizeof(v); return LittleLong(v); } @@ -46,10 +46,10 @@ static int FGetLittleLong (FILE *f, qboolean *ok) FGetLittleShort ================= */ -static short FGetLittleShort(FILE *f, qboolean *ok) +static short FGetLittleShort(qfshandle_t *f, qboolean *ok) { - short v; - *ok &= fread(&v, sizeof(v), 1, f) == 1; + int16_t v; + *ok &= QFS_ReadFile(f, &v, sizeof(v)) == sizeof(v); return LittleShort(v); } @@ -58,14 +58,14 @@ static short FGetLittleShort(FILE *f, qboolean *ok) WAV_ReadChunkInfo ================= */ -static int WAV_ReadChunkInfo(FILE *f, char *name) +static int WAV_ReadChunkInfo(qfshandle_t *f, char *name) { int len, r; qboolean ok = true; name[4] = 0; - r = fread(name, 1, 4, f); + r = QFS_ReadFile(f, name, 4); if (r != 4) return -1; @@ -92,7 +92,7 @@ WAV_FindRIFFChunk Returns the length of the data in the chunk, or -1 if not found ================= */ -static int WAV_FindRIFFChunk(FILE *f, const char *chunk) +static int WAV_FindRIFFChunk(qfshandle_t *f, const char *chunk) { char name[5]; int len; @@ -105,7 +105,7 @@ static int WAV_FindRIFFChunk(FILE *f, const char *chunk) len = ((len + 1) & ~1); /* pad by 2 . */ /* Not the right chunk - skip it */ - fseek(f, len, SEEK_CUR); + QFS_Seek(f, len, SEEK_CUR); } return -1; @@ -116,14 +116,14 @@ static int WAV_FindRIFFChunk(FILE *f, const char *chunk) WAV_ReadRIFFHeader ================= */ -static qboolean WAV_ReadRIFFHeader(const char *name, FILE *file, snd_info_t *info) +static qboolean WAV_ReadRIFFHeader(const char *name, qfshandle_t *file, snd_info_t *info) { char dump[16]; int wav_format; int fmtlen = 0; qboolean ok = true; - if (fread(dump, 1, 12, file) < 12 || + if (QFS_ReadFile(file, dump, 12) < 12 || strncmp(dump, "RIFF", 4) != 0 || strncmp(&dump[8], "WAVE", 4) != 0) { @@ -170,7 +170,7 @@ static qboolean WAV_ReadRIFFHeader(const char *name, FILE *file, snd_info_t *inf if (fmtlen > 16) { fmtlen -= 16; - fseek(file, fmtlen, SEEK_CUR); + QFS_Seek(file, fmtlen, SEEK_CUR); } /* Scan for the data chunk */ @@ -203,17 +203,12 @@ S_WAV_CodecOpenStream */ static qboolean S_WAV_CodecOpenStream(snd_stream_t *stream) { - long start = stream->fh.start; - /* Read the RIFF header */ - /* The file reads are sequential, therefore no need - * for the FS_*() functions: We will manipulate the - * file by ourselves from now on. */ - if (!WAV_ReadRIFFHeader(stream->name, stream->fh.file, &stream->info)) + + if (!WAV_ReadRIFFHeader(stream->name, stream->fh, &stream->info)) return false; - stream->fh.start = ftell(stream->fh.file); /* reset to data position */ - if (stream->fh.start - start + stream->info.size > stream->fh.length) + if (QFS_Tell(stream->fh) + stream->info.size > QFS_FileSize(stream->fh)) { Con_Printf("%s data size mismatch\n", stream->name); return false; @@ -229,15 +224,15 @@ S_WAV_CodecReadStream */ int S_WAV_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer) { - int remaining = stream->info.size - stream->fh.pos; + int remaining = stream->info.size - (int)QFS_Tell(stream->fh); int i, samples; if (remaining <= 0) return 0; if (bytes > remaining) bytes = remaining; - stream->fh.pos += bytes; - if (fread(buffer, 1, bytes, stream->fh.file) != bytes) + + if (QFS_ReadFile(stream->fh, buffer, bytes) != (qfileofs_t)bytes) Sys_Error ("S_WAV_CodecReadStream: read error on %d bytes (%s)", bytes, stream->name); if (stream->info.width == 2) { @@ -255,7 +250,7 @@ static void S_WAV_CodecCloseStream (snd_stream_t *stream) static int S_WAV_CodecRewindStream (snd_stream_t *stream) { - FS_rewind(&stream->fh); + QFS_Seek(stream->fh, 0, SEEK_SET); return 0; } diff --git a/Quake/snd_xmp.c b/Quake/snd_xmp.c index 3e9fd9b4a..5ce170121 100644 --- a/Quake/snd_xmp.c +++ b/Quake/snd_xmp.c @@ -1,4 +1,4 @@ -/* tracker music (module file) decoding support using libxmp >= v4.2.0 +/* tracker music (module file) decoding support using libxmp >= v4.5.0 * https://sourceforge.net/projects/xmp/ * https://github.com/libxmp/libxmp.git * @@ -30,8 +30,8 @@ #define BUILDING_STATIC #endif #include -#if ((XMP_VERCODE+0) < 0x040200) -#error libxmp version 4.2 or newer is required +#if ((XMP_VERCODE+0) < 0x040500) +#error libxmp version 4.5 or newer is required #endif static qboolean S_XMP_CodecInitialize (void) @@ -43,62 +43,38 @@ static void S_XMP_CodecShutdown (void) { } -#if (XMP_VERCODE >= 0x040500) static unsigned long xmp_fread(void *dest, unsigned long len, unsigned long nmemb, void *f) { - return FS_fread(dest, len, nmemb, (fshandle_t *)f); + return (unsigned long)QFS_ReadFile((qfshandle_t*)f, dest, (size_t)len); } static int xmp_fseek(void *f, long offset, int whence) { - return FS_fseek((fshandle_t *)f, offset, whence); + return QFS_Seek((qfshandle_t*)f, (qfileofs_t)offset, whence); } static long xmp_ftell(void *f) { - return FS_ftell((fshandle_t *)f); + return (long)QFS_Tell((qfshandle_t*)f); } -#endif + static qboolean S_XMP_CodecOpenStream (snd_stream_t *stream) { -/* need to load the whole file into memory and pass it to libxmp - * using xmp_load_module_from_memory() which requires libxmp >= 4.2. - * libxmp-4.0/4.1 only have xmp_load_module() which accepts a file - * name which isn't good with files in containers like paks, etc. - * On the other hand, libxmp >= 4.5 introduces file callbacks: use - * if available. */ +/* libxmp >= 4.5 introduces file callbacks, we now require this feature. */ xmp_context c; -#if (XMP_VERCODE >= 0x040500) struct xmp_callbacks file_callbacks = { xmp_fread, xmp_fseek, xmp_ftell, NULL }; -#else - byte *moddata; - long len; - int mark; -#endif + int fmt; c = xmp_create_context(); if (c == NULL) return false; -#if (XMP_VERCODE >= 0x040500) - if (xmp_load_module_from_callbacks(c, &stream->fh, file_callbacks) < 0) { + if (xmp_load_module_from_callbacks(c, stream->fh, file_callbacks) < 0) { Con_DPrintf("Could not load module %s\n", stream->name); goto err1; } -#else - len = FS_filelength (&stream->fh); - mark = Hunk_LowMark(); - moddata = (byte *) Hunk_Alloc(len); - FS_fread(moddata, 1, len, &stream->fh); - if (xmp_load_module_from_memory(c, moddata, len) < 0) { - Hunk_FreeToLowMark(mark); - Con_DPrintf("Could not load module %s\n", stream->name); - goto err1; - } - Hunk_FreeToLowMark(mark); /* free original file data */ -#endif stream->priv = c; if (shm->speed > XMP_MAX_SRATE) diff --git a/Quake/sys.h b/Quake/sys.h index da460d400..4dbd57951 100644 --- a/Quake/sys.h +++ b/Quake/sys.h @@ -66,23 +66,13 @@ qboolean Sys_Explore (const char *path); typedef int64_t qfileofs_t; -// returns the file size or -1 if file is not present. -// the file should be in BINARY mode for stupid OSs that care -qfileofs_t Sys_FileOpenRead (const char *path, int *hndl); - -// Returns a file handle -int Sys_FileOpenWrite (const char *path); - -void Sys_FileClose (int handle); -void Sys_FileSeek (int handle, int position); -int Sys_FileRead (int handle, void *dest, int count); -int Sys_FileWrite (int handle,const void *data, int count); qboolean Sys_FileExists (const char *path); qboolean Sys_GetFileTime (const char *path, time_t *out); void Sys_mkdir (const char *path); FILE *Sys_fopen (const char *path, const char *mode); int Sys_fseek (FILE *file, qfileofs_t ofs, int origin); qfileofs_t Sys_ftell (FILE *file); +qfileofs_t Sys_filelength (FILE *f); int Sys_remove (const char *path); int Sys_rename (const char *oldname, const char *newname); diff --git a/Quake/sys_sdl_unix.c b/Quake/sys_sdl_unix.c index e488c275b..d4771f556 100644 --- a/Quake/sys_sdl_unix.c +++ b/Quake/sys_sdl_unix.c @@ -51,25 +51,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. qboolean isDedicated; -#define MAX_HANDLES 32 /* johnfitz -- was 10 */ -static FILE *sys_handles[MAX_HANDLES]; static qboolean stdinIsATTY; /* from ioquake3 source */ static double rcp_counter_freq; -static int findhandle (void) -{ - int i; - - for (i = 1; i < MAX_HANDLES; i++) - { - if (!sys_handles[i]) - return i; - } - Sys_Error ("out of handles"); - return -1; -} - FILE *Sys_fopen (const char *path, const char *mode) { if (strchr (mode, 'w')) @@ -132,66 +117,6 @@ qfileofs_t Sys_filelength (FILE *f) return end; } -qfileofs_t Sys_FileOpenRead (const char *path, int *hndl) -{ - FILE *f; - int i; - qfileofs_t retval; - - i = findhandle (); - f = fopen(path, "rb"); - - if (!f) - { - *hndl = -1; - retval = -1; - } - else - { - sys_handles[i] = f; - *hndl = i; - retval = Sys_filelength(f); - } - - return retval; -} - -int Sys_FileOpenWrite (const char *path) -{ - FILE *f; - int i; - - i = findhandle (); - f = Sys_fopen(path, "wb"); - - if (!f) - Sys_Error ("Error opening %s: %s", path, strerror(errno)); - - sys_handles[i] = f; - return i; -} - -void Sys_FileClose (int handle) -{ - fclose (sys_handles[handle]); - sys_handles[handle] = NULL; -} - -void Sys_FileSeek (int handle, int position) -{ - fseek (sys_handles[handle], position, SEEK_SET); -} - -int Sys_FileRead (int handle, void *dest, int count) -{ - return fread (dest, 1, count, sys_handles[handle]); -} - -int Sys_FileWrite (int handle, const void *data, int count) -{ - return fwrite (data, 1, count, sys_handles[handle]); -} - qboolean Sys_FileExists (const char *path) { return access (path, F_OK) == 0; diff --git a/Quake/sys_sdl_win.c b/Quake/sys_sdl_win.c index 1737586dc..ca59387ce 100644 --- a/Quake/sys_sdl_win.c +++ b/Quake/sys_sdl_win.c @@ -66,24 +66,8 @@ qboolean isDedicated; static HANDLE hinput, houtput; -#define MAX_HANDLES 32 /* johnfitz -- was 10 */ -static FILE *sys_handles[MAX_HANDLES]; - static double rcp_counter_freq; -static int findhandle (void) -{ - int i; - - for (i = 1; i < MAX_HANDLES; i++) - { - if (!sys_handles[i]) - return i; - } - Sys_Error ("out of handles"); - return -1; -} - static void UTF8ToWideString (const char *src, wchar_t *dst, size_t maxchars) { if (!MultiByteToWideChar (CP_UTF8, 0, src, -1, dst, maxchars)) @@ -185,66 +169,6 @@ qfileofs_t Sys_filelength (FILE *f) return end; } -qfileofs_t Sys_FileOpenRead (const char *path, int *hndl) -{ - FILE *f; - int i; - qfileofs_t retval; - - i = findhandle (); - f = Sys_fopen (path, "rb"); - - if (!f) - { - *hndl = -1; - retval = -1; - } - else - { - sys_handles[i] = f; - *hndl = i; - retval = Sys_filelength(f); - } - - return retval; -} - -int Sys_FileOpenWrite (const char *path) -{ - FILE *f; - int i; - - i = findhandle (); - f = Sys_fopen (path, "wb"); - - if (!f) - Sys_Error ("Error opening %s: %s", path, strerror(errno)); - - sys_handles[i] = f; - return i; -} - -void Sys_FileClose (int handle) -{ - fclose (sys_handles[handle]); - sys_handles[handle] = NULL; -} - -void Sys_FileSeek (int handle, int position) -{ - fseek (sys_handles[handle], position, SEEK_SET); -} - -int Sys_FileRead (int handle, void *dest, int count) -{ - return fread (dest, 1, count, sys_handles[handle]); -} - -int Sys_FileWrite (int handle, const void *data, int count) -{ - return fwrite (data, 1, count, sys_handles[handle]); -} - #ifndef INVALID_FILE_ATTRIBUTES #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) #endif diff --git a/Quake/wad.c b/Quake/wad.c index cf0144215..678af35a2 100644 --- a/Quake/wad.c +++ b/Quake/wad.c @@ -77,7 +77,7 @@ void W_LoadWadFile (void) //johnfitz -- filename is now hard-coded for honesty //TODO: use cache_alloc if (wad_base) free (wad_base); - wad_base = COM_LoadMallocFile (filename, NULL); + wad_base = QFS_LoadMallocFile (filename, NULL, NULL); if (!wad_base) Sys_Error ("W_LoadWadFile: couldn't load %s\n\n" "Basedir is: %s\n\n" diff --git a/Windows/VisualStudio/ironwail.vcxproj b/Windows/VisualStudio/ironwail.vcxproj index e445161c1..2f2f6c513 100644 --- a/Windows/VisualStudio/ironwail.vcxproj +++ b/Windows/VisualStudio/ironwail.vcxproj @@ -237,6 +237,7 @@ copy "$(SolutionDir)..\zlib\$(PlatformShortName)\*.dll" "$(TargetDir)" + @@ -357,6 +358,7 @@ copy "$(SolutionDir)..\zlib\$(PlatformShortName)\*.dll" "$(TargetDir)" + diff --git a/Windows/VisualStudio/ironwail.vcxproj.filters b/Windows/VisualStudio/ironwail.vcxproj.filters index d71c1415f..b02b223b9 100644 --- a/Windows/VisualStudio/ironwail.vcxproj.filters +++ b/Windows/VisualStudio/ironwail.vcxproj.filters @@ -267,6 +267,9 @@ Source Files + + Source Files + @@ -479,6 +482,9 @@ Header Files + + Header Files +