4 Copyright (C) 2003 Mathieu Olivier
5 Copyright (C) 1999,2000 contributors of the QuakeForge project
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 See the GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to:
21 Free Software Foundation, Inc.
22 59 Temple Place - Suite 330
23 Boston, MA 02111-1307, USA
38 # include <sys/stat.h>
51 All of Quake's data access is through a hierchal file system, but the contents
52 of the file system can be transparently merged from several sources.
54 The "base directory" is the path to the directory holding the quake.exe and
55 all game directories. The sys_* files pass this to host_init in
56 quakeparms_t->basedir. This can be overridden with the "-basedir" command
57 line parm to allow code debugging in a different directory. The base
58 directory is only used during filesystem initialization.
60 The "game directory" is the first tree on the search path and directory that
61 all generated files (savegames, screenshots, demos, config files) will be
62 saved to. This can be overridden with the "-game" command line parameter.
63 The game directory can never be changed while quake is executing. This is a
64 precacution against having a malicious server instruct clients to write files
65 over areas they shouldn't.
71 =============================================================================
75 =============================================================================
78 // Magic numbers of a ZIP file (big-endian format)
79 #define ZIP_DATA_HEADER 0x504B0304 // "PK\3\4"
80 #define ZIP_CDIR_HEADER 0x504B0102 // "PK\1\2"
81 #define ZIP_END_HEADER 0x504B0506 // "PK\5\6"
83 // Other constants for ZIP files
84 #define ZIP_MAX_COMMENTS_SIZE ((unsigned short)0xFFFF)
85 #define ZIP_END_CDIR_SIZE 22
86 #define ZIP_CDIR_CHUNK_BASE_SIZE 46
87 #define ZIP_LOCAL_CHUNK_BASE_SIZE 30
89 // Zlib constants (from zlib.h)
90 #define Z_SYNC_FLUSH 2
93 #define Z_STREAM_END 1
94 #define ZLIB_VERSION "1.1.4"
98 =============================================================================
102 =============================================================================
105 // Zlib stream (from zlib.h)
106 // Warning: some pointers we don't use directly have
107 // been cast to "void*" for a matter of simplicity
110 qbyte *next_in; // next input byte
111 unsigned int avail_in; // number of bytes available at next_in
112 unsigned long total_in; // total nb of input bytes read so far
114 qbyte *next_out; // next output byte should be put there
115 unsigned int avail_out; // remaining free space at next_out
116 unsigned long total_out; // total nb of bytes output so far
118 char *msg; // last error message, NULL if no error
119 void *state; // not visible by applications
121 void *zalloc; // used to allocate the internal state
122 void *zfree; // used to free the internal state
123 void *opaque; // private data object passed to zalloc and zfree
125 int data_type; // best guess about the data type: ascii or binary
126 unsigned long adler; // adler32 value of the uncompressed data
127 unsigned long reserved; // reserved for future use
131 // Our own file structure on top of FILE
135 FS_FLAG_PACKED = (1 << 0), // inside a package (PAK or PK3)
136 FS_FLAG_DEFLATED = (1 << 1) // file is compressed using the deflate algorithm (PK3 only)
139 #define ZBUFF_SIZE 1024
143 size_t real_length; // length of the uncompressed file
144 size_t in_ind, in_max; // input buffer index and counter
145 size_t in_position; // position in the compressed file
146 size_t out_ind, out_max; // output buffer index and counter
147 size_t out_position; // how many bytes did we uncompress until now?
148 qbyte input [ZBUFF_SIZE];
149 qbyte output [ZBUFF_SIZE];
156 size_t length; // file size on disk (PACKED only)
157 size_t offset; // offset into a package (PACKED only)
158 size_t position; // current position in the file (PACKED only)
159 ztoolkit_t* z; // used for inflating (DEFLATED only)
163 // ------ PK3 files on disk ------ //
165 // You can get the complete ZIP format description from PKWARE website
169 unsigned int signature;
170 unsigned short disknum;
171 unsigned short cdir_disknum; // number of the disk with the start of the central directory
172 unsigned short localentries; // number of entries in the central directory on this disk
173 unsigned short nbentries; // total number of entries in the central directory on this disk
174 unsigned int cdir_size; // size of the central directory
175 unsigned int cdir_offset; // with respect to the starting disk number
176 unsigned short comment_size;
177 } pk3_endOfCentralDir_t;
180 // ------ PAK files on disk ------ //
184 int filepos, filelen;
195 // Packages in memory
199 FILE_FLAG_TRUEOFFS = (1 << 0), // the offset in packfile_t is the true contents offset
200 FILE_FLAG_DEFLATED = (1 << 1) // file compressed using the deflate algorithm
205 char name [MAX_QPATH];
208 size_t packsize; // size in the package
209 size_t realsize; // real file size (uncompressed)
212 typedef struct pack_s
214 char filename [MAX_OSPATH];
216 int ignorecase; // PK3 ignores case
224 // Search paths for files (including packages)
225 typedef struct searchpath_s
227 // only one of filename / pack will be used
228 char filename[MAX_OSPATH];
230 struct searchpath_s *next;
235 =============================================================================
239 =============================================================================
245 static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack,
246 size_t offset, size_t packsize,
247 size_t realsize, file_flags_t flags);
251 =============================================================================
255 =============================================================================
258 mempool_t *fs_mempool;
259 mempool_t *pak_mempool;
263 pack_t *packlist = NULL;
265 searchpath_t *fs_searchpaths = NULL;
267 #define MAX_FILES_IN_PACK 65536
269 char fs_gamedir[MAX_OSPATH];
270 char fs_basedir[MAX_OSPATH];
272 qboolean fs_modified; // set true if using non-id files
276 =============================================================================
278 PRIVATE FUNCTIONS - PK3 HANDLING
280 =============================================================================
283 // Functions exported from zlib
285 # define ZEXPORT WINAPI
290 static int (ZEXPORT *qz_inflate) (z_stream* strm, int flush);
291 static int (ZEXPORT *qz_inflateEnd) (z_stream* strm);
292 static int (ZEXPORT *qz_inflateInit2_) (z_stream* strm, int windowBits, const char *version, int stream_size);
293 static int (ZEXPORT *qz_inflateReset) (z_stream* strm);
295 #define qz_inflateInit2(strm, windowBits) \
296 qz_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
298 static dllfunction_t zlibfuncs[] =
300 {"inflate", (void **) &qz_inflate},
301 {"inflateEnd", (void **) &qz_inflateEnd},
302 {"inflateInit2_", (void **) &qz_inflateInit2_},
303 {"inflateReset", (void **) &qz_inflateReset},
307 // Handle for Zlib DLL
308 static dllhandle_t zlib_dll = NULL;
318 void PK3_CloseLibrary (void)
320 Sys_UnloadLibrary (&zlib_dll);
328 Try to load the Zlib DLL
331 qboolean PK3_OpenLibrary (void)
340 dllname = "zlib.dll";
346 if (! Sys_LoadLibrary (dllname, &zlib_dll, zlibfuncs))
348 Con_Printf ("Compressed files support disabled\n");
352 Con_Printf ("Compressed files support enabled\n");
359 PK3_GetEndOfCentralDir
361 Extract the end of the central directory from a PK3 package
364 qboolean PK3_GetEndOfCentralDir (const char *packfile, FILE *packhandle, pk3_endOfCentralDir_t *eocd)
366 long filesize, maxsize;
370 // Get the package size
371 fseek (packhandle, 0, SEEK_END);
372 filesize = ftell (packhandle);
373 if (filesize < ZIP_END_CDIR_SIZE)
376 // Load the end of the file in memory
377 if (filesize < ZIP_MAX_COMMENTS_SIZE + ZIP_END_CDIR_SIZE)
380 maxsize = ZIP_MAX_COMMENTS_SIZE + ZIP_END_CDIR_SIZE;
381 buffer = Mem_Alloc (tempmempool, maxsize);
382 fseek (packhandle, filesize - maxsize, SEEK_SET);
383 if (fread (buffer, 1, maxsize, packhandle) != (unsigned long) maxsize)
389 // Look for the end of central dir signature around the end of the file
390 maxsize -= ZIP_END_CDIR_SIZE;
391 ptr = &buffer[maxsize];
393 while (BuffBigLong (ptr) != ZIP_END_HEADER)
405 memcpy (eocd, ptr, ZIP_END_CDIR_SIZE);
406 eocd->signature = LittleLong (eocd->signature);
407 eocd->disknum = LittleShort (eocd->disknum);
408 eocd->cdir_disknum = LittleShort (eocd->cdir_disknum);
409 eocd->localentries = LittleShort (eocd->localentries);
410 eocd->nbentries = LittleShort (eocd->nbentries);
411 eocd->cdir_size = LittleLong (eocd->cdir_size);
412 eocd->cdir_offset = LittleLong (eocd->cdir_offset);
413 eocd->comment_size = LittleShort (eocd->comment_size);
425 Extract the file list from a PK3 file
428 int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd)
430 qbyte *central_dir, *ptr;
434 // Load the central directory in memory
435 central_dir = Mem_Alloc (tempmempool, eocd->cdir_size);
436 fseek (pack->handle, eocd->cdir_offset, SEEK_SET);
437 fread (central_dir, 1, eocd->cdir_size, pack->handle);
439 // Extract the files properties
440 // The parsing is done "by hand" because some fields have variable sizes and
441 // the constant part isn't 4-bytes aligned, which makes the use of structs difficult
442 remaining = eocd->cdir_size;
445 for (ind = 0; ind < eocd->nbentries; ind++)
447 size_t namesize, count;
449 // Checking the remaining size
450 if (remaining < ZIP_CDIR_CHUNK_BASE_SIZE)
452 Mem_Free (central_dir);
455 remaining -= ZIP_CDIR_CHUNK_BASE_SIZE;
458 if (BuffBigLong (ptr) != ZIP_CDIR_HEADER)
460 Mem_Free (central_dir);
464 namesize = BuffLittleShort (&ptr[28]); // filename length
466 // Check encryption, compression, and attributes
467 // 1st uint8 : general purpose bit flag
468 // Check bits 0 (encryption), 3 (data descriptor after the file), and 5 (compressed patched data (?))
469 // 2nd uint8 : external file attributes
470 // Check bits 3 (file is a directory) and 5 (file is a volume (?))
471 if ((ptr[8] & 0x29) == 0 && (ptr[38] & 0x18) == 0)
473 // Still enough bytes for the name?
474 if ((size_t) remaining < namesize || namesize >= sizeof (*pack->files))
476 Mem_Free (central_dir);
480 // WinZip doesn't use the "directory" attribute, so we need to check the name directly
481 if (ptr[ZIP_CDIR_CHUNK_BASE_SIZE + namesize - 1] != '/')
483 char filename [sizeof (pack->files[0].name)];
484 size_t offset, packsize, realsize;
487 // Extract the name (strip it if necessary)
488 if (namesize >= sizeof (filename))
489 namesize = sizeof (filename) - 1;
490 memcpy (filename, &ptr[ZIP_CDIR_CHUNK_BASE_SIZE], namesize);
491 filename[namesize] = '\0';
493 if (BuffLittleShort (&ptr[10]))
494 flags = FILE_FLAG_DEFLATED;
497 offset = BuffLittleLong (&ptr[42]);
498 packsize = BuffLittleLong (&ptr[20]);
499 realsize = BuffLittleLong (&ptr[24]);
500 FS_AddFileToPack (filename, pack, offset, packsize, realsize, flags);
504 // Skip the name, additionnal field, and comment
505 // 1er uint16 : extra field length
506 // 2eme uint16 : file comment length
507 count = namesize + BuffLittleShort (&ptr[30]) + BuffLittleShort (&ptr[32]);
508 ptr += ZIP_CDIR_CHUNK_BASE_SIZE + count;
512 Mem_Free (central_dir);
513 return pack->numfiles;
521 Create a package entry associated with a PK3 file
524 pack_t *FS_LoadPackPK3 (const char *packfile)
527 pk3_endOfCentralDir_t eocd;
531 packhandle = fopen (packfile, "rb");
535 if (! PK3_GetEndOfCentralDir (packfile, packhandle, &eocd))
536 Sys_Error ("%s is not a PK3 file", packfile);
538 // Multi-volume ZIP archives are NOT allowed
539 if (eocd.disknum != 0 || eocd.cdir_disknum != 0)
540 Sys_Error ("%s is a multi-volume ZIP archive", packfile);
542 // We only need to do this test if MAX_FILES_IN_PACK is lesser than 65535
543 // since eocd.nbentries is an unsigned 16 bits integer
544 #if MAX_FILES_IN_PACK < 65535
545 if (eocd.nbentries > MAX_FILES_IN_PACK)
546 Sys_Error ("%s contains too many files (%hu)", packfile, eocd.nbentries);
549 // Create a package structure in memory
550 pack = Mem_Alloc (pak_mempool, sizeof (pack_t));
551 pack->ignorecase = true; // PK3 ignores case
552 strlcpy (pack->filename, packfile, sizeof (pack->filename));
553 pack->handle = packhandle;
554 pack->numfiles = eocd.nbentries;
555 pack->mempool = Mem_AllocPool (packfile);
556 pack->files = Mem_Alloc (pack->mempool, eocd.nbentries * sizeof(packfile_t));
557 pack->next = packlist;
560 real_nb_files = PK3_BuildFileList (pack, &eocd);
561 if (real_nb_files <= 0)
562 Sys_Error ("%s is not a valid PK3 file", packfile);
564 Con_Printf("Added packfile %s (%i files)\n", packfile, real_nb_files);
571 PK3_GetTrueFileOffset
573 Find where the true file data offset is
576 void PK3_GetTrueFileOffset (packfile_t *file, pack_t *pack)
578 qbyte buffer [ZIP_LOCAL_CHUNK_BASE_SIZE];
582 if (file->flags & FILE_FLAG_TRUEOFFS)
585 // Load the local file description
586 fseek (pack->handle, file->offset, SEEK_SET);
587 count = fread (buffer, 1, ZIP_LOCAL_CHUNK_BASE_SIZE, pack->handle);
588 if (count != ZIP_LOCAL_CHUNK_BASE_SIZE || BuffBigLong (buffer) != ZIP_DATA_HEADER)
589 Sys_Error ("Can't retrieve file %s in package %s", file->name, pack->filename);
591 // Skip name and extra field
592 file->offset += BuffLittleShort (&buffer[26]) + BuffLittleShort (&buffer[28]) + ZIP_LOCAL_CHUNK_BASE_SIZE;
594 file->flags |= FILE_FLAG_TRUEOFFS;
599 =============================================================================
601 OTHER PRIVATE FUNCTIONS
603 =============================================================================
611 Add a file to the list of files contained into a package
614 static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack,
615 size_t offset, size_t packsize,
616 size_t realsize, file_flags_t flags)
618 int (*strcmp_funct) (const char* str1, const char* str2);
619 size_t left, right, middle;
623 strcmp_funct = pack->ignorecase ? strcasecmp : strcmp;
625 // Look for the slot we should put that file into (binary search)
627 right = pack->numfiles;
628 while (left != right)
630 middle = (left + right - 1) / 2;
631 diff = strcmp_funct (pack->files[middle].name, name);
633 // If we found the file, there's a problem
635 Sys_Error ("Package %s contains several time the file %s\n",
636 pack->filename, name);
638 // If we're too far in the list
645 // We have to move the right of the list by one slot to free the one we need
646 file = &pack->files[left];
647 memmove (file + 1, file, (pack->numfiles - left) * sizeof (*file));
650 strlcpy (file->name, name, sizeof (file->name));
651 file->offset = offset;
652 file->packsize = packsize;
653 file->realsize = realsize;
664 Only used for FS_Open.
667 void FS_CreatePath (char *path)
671 for (ofs = path+1 ; *ofs ; ofs++)
673 if (*ofs == '/' || *ofs == '\\')
675 // create the directory
691 void FS_Path_f (void)
695 Con_Print("Current search path:\n");
696 for (s=fs_searchpaths ; s ; s=s->next)
700 Con_Printf("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
703 Con_Printf("%s\n", s->filename);
712 Takes an explicit (not game tree related) path to a pak file.
714 Loads the header and directory, adding the files at the beginning
715 of the list so they override previous pack files.
718 pack_t *FS_LoadPackPAK (const char *packfile)
720 dpackheader_t header;
724 dpackfile_t *info; // temporary alloc, allowing huge pack directories
726 packhandle = fopen (packfile, "rb");
730 fread ((void *)&header, 1, sizeof(header), packhandle);
731 if (memcmp(header.id, "PACK", 4))
732 Sys_Error ("%s is not a packfile", packfile);
733 header.dirofs = LittleLong (header.dirofs);
734 header.dirlen = LittleLong (header.dirlen);
736 if (header.dirlen % sizeof(dpackfile_t))
737 Sys_Error ("%s has an invalid directory size", packfile);
739 numpackfiles = header.dirlen / sizeof(dpackfile_t);
741 if (numpackfiles > MAX_FILES_IN_PACK)
742 Sys_Error ("%s has %i files", packfile, numpackfiles);
744 pack = Mem_Alloc(pak_mempool, sizeof (pack_t));
745 pack->ignorecase = false; // PAK is case sensitive
746 strlcpy (pack->filename, packfile, sizeof (pack->filename));
747 pack->handle = packhandle;
749 pack->mempool = Mem_AllocPool(packfile);
750 pack->files = Mem_Alloc(pack->mempool, numpackfiles * sizeof(packfile_t));
751 pack->next = packlist;
754 info = Mem_Alloc(tempmempool, sizeof(*info) * numpackfiles);
755 fseek (packhandle, header.dirofs, SEEK_SET);
756 fread ((void *)info, 1, header.dirlen, packhandle);
758 // parse the directory
759 for (i = 0;i < numpackfiles;i++)
761 size_t offset = LittleLong (info[i].filepos);
762 size_t size = LittleLong (info[i].filelen);
764 FS_AddFileToPack (info[i].name, pack, offset, size, size, FILE_FLAG_TRUEOFFS);
769 Con_Printf("Added packfile %s (%i files)\n", packfile, numpackfiles);
778 Sets fs_gamedir, adds the directory to the head of the path,
779 then loads and adds pak1.pak pak2.pak ...
782 void FS_AddGameDirectory (char *dir)
784 stringlist_t *list, *current;
785 searchpath_t *search;
787 char pakfile[MAX_OSPATH];
789 strlcpy (fs_gamedir, dir, sizeof (fs_gamedir));
792 // add the directory to the search path
793 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
794 strlcpy (search->filename, dir, sizeof (search->filename));
795 search->next = fs_searchpaths;
796 fs_searchpaths = search;
799 list = listdirectory(dir);
801 // add any PAK package in the directory
802 for (current = list;current;current = current->next)
804 if (matchpattern(current->text, "*.pak", true))
806 snprintf (pakfile, sizeof (pakfile), "%s/%s", dir, current->text);
807 pak = FS_LoadPackPAK (pakfile);
810 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
812 search->next = fs_searchpaths;
813 fs_searchpaths = search;
816 Con_Printf("unable to load pak \"%s\"\n", pakfile);
820 // add any PK3 package in the director
821 for (current = list;current;current = current->next)
823 if (matchpattern(current->text, "*.pk3", true))
825 snprintf (pakfile, sizeof (pakfile), "%s/%s", dir, current->text);
826 pak = FS_LoadPackPK3 (pakfile);
829 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
831 search->next = fs_searchpaths;
832 fs_searchpaths = search;
835 Con_Printf("unable to load pak \"%s\"\n", pakfile);
840 // Unpacked files have the priority over packed files if AKVERSION is defined
842 // add the directory to the search path
843 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
844 strlcpy (search->filename, dir, sizeof (search->filename));
845 search->next = fs_searchpaths;
846 fs_searchpaths = search;
856 char *FS_FileExtension (const char *in)
858 static char exten[8];
859 const char *slash, *backslash, *colon, *dot, *separator;
862 slash = strrchr(in, '/');
863 backslash = strrchr(in, '\\');
864 colon = strrchr(in, ':');
865 dot = strrchr(in, '.');
867 if (separator < backslash)
868 separator = backslash;
869 if (separator < colon)
871 if (dot == NULL || dot < separator)
874 for (i = 0;i < 7 && dot[i];i++)
889 searchpath_t *search;
891 fs_mempool = Mem_AllocPool("file management");
892 pak_mempool = Mem_AllocPool("paks");
894 Cvar_RegisterVariable (&scr_screenshot_name);
896 Cmd_AddCommand ("path", FS_Path_f);
897 Cmd_AddCommand ("dir", FS_Dir_f);
898 Cmd_AddCommand ("ls", FS_Ls_f);
900 strcpy(fs_basedir, ".");
901 strcpy(fs_gamedir, ".");
906 // Overrides the system supplied base directory (under GAMENAME)
907 i = COM_CheckParm ("-basedir");
908 if (i && i < com_argc-1)
910 strlcpy (fs_basedir, com_argv[i+1], sizeof (fs_basedir));
911 i = strlen (fs_basedir);
912 if (i > 0 && (fs_basedir[i-1] == '\\' || fs_basedir[i-1] == '/'))
916 // -path <dir or packfile> [<dir or packfile>] ...
917 // Fully specifies the exact search path, overriding the generated one
918 i = COM_CheckParm ("-path");
922 while (++i < com_argc)
924 if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')
927 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
928 if (!strcasecmp (FS_FileExtension(com_argv[i]), "pak"))
930 search->pack = FS_LoadPackPAK (com_argv[i]);
932 Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
934 else if (!strcasecmp (FS_FileExtension (com_argv[i]), "pk3"))
936 search->pack = FS_LoadPackPK3 (com_argv[i]);
938 Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
941 strlcpy (search->filename, com_argv[i], sizeof (search->filename));
942 search->next = fs_searchpaths;
943 fs_searchpaths = search;
951 Cvar_SetQuick (&scr_screenshot_name, "dp");
954 Cvar_SetQuick (&scr_screenshot_name, "hipnotic");
957 Cvar_SetQuick (&scr_screenshot_name, "rogue");
960 Cvar_SetQuick (&scr_screenshot_name, "nehahra");
963 Cvar_SetQuick (&scr_screenshot_name, "nexuiz");
965 case GAME_TRANSFUSION:
966 Cvar_SetQuick (&scr_screenshot_name, "transfusion");
968 case GAME_GOODVSBAD2:
969 Cvar_SetQuick (&scr_screenshot_name, "gvb2");
972 Cvar_SetQuick (&scr_screenshot_name, "teu");
974 case GAME_BATTLEMECH:
975 Cvar_SetQuick (&scr_screenshot_name, "battlemech");
978 Cvar_SetQuick (&scr_screenshot_name, "zymotic");
981 Cvar_SetQuick (&scr_screenshot_name, "fniggium");
984 Cvar_SetQuick (&scr_screenshot_name, "setheral");
987 Cvar_SetQuick (&scr_screenshot_name, "som");
990 Cvar_SetQuick (&scr_screenshot_name, "tenebrae");
993 Cvar_SetQuick (&scr_screenshot_name, "dp");
997 // start up with GAMENAME by default (id1)
998 strlcpy (com_modname, GAMENAME, sizeof (com_modname));
999 FS_AddGameDirectory (va("%s/"GAMENAME, fs_basedir));
1001 // add the game-specific path, if any
1005 strlcpy (com_modname, gamedirname, sizeof (com_modname));
1006 FS_AddGameDirectory (va("%s/%s", fs_basedir, gamedirname));
1010 // Adds basedir/gamedir as an override game
1011 i = COM_CheckParm ("-game");
1012 if (i && i < com_argc-1)
1015 strlcpy (com_modname, com_argv[i+1], sizeof (com_modname));
1016 FS_AddGameDirectory (va("%s/%s", fs_basedir, com_argv[i+1]));
1017 Cvar_SetQuick (&scr_screenshot_name, com_modname);
1023 ====================
1026 Internal function used to create a qfile_t and open the relevant file on disk
1027 ====================
1029 static qfile_t* FS_SysOpen (const char* filepath, const char* mode)
1033 file = Mem_Alloc (fs_mempool, sizeof (*file));
1034 memset (file, 0, sizeof (*file));
1036 file->stream = fopen (filepath, mode);
1052 qfile_t *FS_OpenRead (const char *path, int offs, int len)
1056 file = FS_SysOpen (path, "rb");
1059 Sys_Error ("Couldn't open %s", path);
1064 if (offs < 0 || len < 0)
1066 // We set fs_filesize here for normal files
1067 fseek (file->stream, 0, SEEK_END);
1068 fs_filesize = ftell (file->stream);
1069 fseek (file->stream, 0, SEEK_SET);
1074 fseek (file->stream, offs, SEEK_SET);
1076 file->flags |= FS_FLAG_PACKED;
1078 file->offset = offs;
1087 ====================
1090 Look for a file in the packages and in the filesystem
1092 Return the searchpath where the file was found (or NULL)
1093 and the file index in the package if relevant
1094 ====================
1096 static searchpath_t *FS_FindFile (const char *name, int* index, qboolean quiet)
1098 searchpath_t *search;
1100 int (*strcmp_funct) (const char* str1, const char* str2);
1102 // search through the path, one element at a time
1103 for (search = fs_searchpaths;search;search = search->next)
1105 // is the element a pak file?
1108 size_t left, right, middle;
1111 strcmp_funct = pak->ignorecase ? strcasecmp : strcmp;
1113 // Look for the file (binary search)
1115 right = pak->numfiles;
1116 while (left != right)
1120 middle = (left + right - 1) / 2;
1121 diff = strcmp_funct (pak->files[middle].name, name);
1127 Sys_Printf("FS_FindFile: %s in %s\n",
1128 pak->files[middle].name, pak->filename);
1135 // If we're too far in the list
1144 char netpath[MAX_OSPATH];
1145 snprintf(netpath, sizeof(netpath), "%s/%s", search->filename, name);
1146 if (FS_SysFileExists (netpath))
1149 Sys_Printf("FS_FindFile: %s\n", netpath);
1159 Sys_Printf("FS_FindFile: can't find %s\n", name);
1171 If the requested file is inside a packfile, a new qfile_t* will be opened
1177 qfile_t *FS_FOpenFile (const char *filename, qboolean quiet)
1179 searchpath_t *search;
1180 packfile_t *packfile;
1184 search = FS_FindFile (filename, &i, quiet);
1193 // Found in the filesystem?
1196 char netpath[MAX_OSPATH];
1197 snprintf(netpath, sizeof(netpath), "%s/%s", search->filename, filename);
1198 return FS_OpenRead(netpath, -1, -1);
1201 // So, we found it in a package...
1202 packfile = &search->pack->files[i];
1204 // If we don't have the true offset, get it now
1205 if (! (packfile->flags & FILE_FLAG_TRUEOFFS))
1206 PK3_GetTrueFileOffset (packfile, search->pack);
1208 // No Zlib DLL = no compressed files
1209 if (!zlib_dll && (packfile->flags & FILE_FLAG_DEFLATED))
1211 Con_Printf("WARNING: can't open the compressed file %s\n"
1212 "You need the Zlib DLL to use compressed files\n",
1218 // open a new file in the pakfile
1219 file = FS_OpenRead (search->pack->filename, packfile->offset, packfile->packsize);
1220 fs_filesize = packfile->realsize;
1222 if (packfile->flags & FILE_FLAG_DEFLATED)
1226 file->flags |= FS_FLAG_DEFLATED;
1228 // We need some more variables
1229 ztk = Mem_Alloc (fs_mempool, sizeof (*file->z));
1231 ztk->real_length = packfile->realsize;
1233 // Initialize zlib stream
1234 ztk->zstream.next_in = ztk->input;
1235 ztk->zstream.avail_in = 0;
1237 /* From Zlib's "unzip.c":
1239 * windowBits is passed < 0 to tell that there is no zlib header.
1240 * Note that in this case inflate *requires* an extra "dummy" byte
1241 * after the compressed stream in order to complete decompression and
1242 * return Z_STREAM_END.
1243 * In unzip, i don't wait absolutely Z_STREAM_END because I known the
1244 * size of both compressed and uncompressed data
1246 if (qz_inflateInit2 (&ztk->zstream, -MAX_WBITS) != Z_OK)
1247 Sys_Error ("inflate init error (file: %s)", filename);
1249 ztk->zstream.next_out = ztk->output;
1250 ztk->zstream.avail_out = sizeof (ztk->output);
1260 =============================================================================
1262 MAIN PUBLIC FUNCTIONS
1264 =============================================================================
1268 ====================
1271 Open a file. The syntax is the same as fopen
1272 ====================
1274 qfile_t* FS_Open (const char* filepath, const char* mode, qboolean quiet)
1276 // If the file is opened in "write" or "append" mode
1277 if (strchr (mode, 'w') || strchr (mode, 'a'))
1279 char real_path [MAX_OSPATH];
1281 // Open the file on disk directly
1282 snprintf (real_path, sizeof (real_path), "%s/%s", fs_gamedir, filepath);
1284 // Create directories up to the file
1285 FS_CreatePath (real_path);
1287 return FS_SysOpen (real_path, mode);
1290 // Else, we look at the various search paths
1291 return FS_FOpenFile (filepath, quiet);
1296 ====================
1300 ====================
1302 int FS_Close (qfile_t* file)
1304 if (fclose (file->stream))
1309 qz_inflateEnd (&file->z->zstream);
1319 ====================
1322 Write "datasize" bytes into a file
1323 ====================
1325 size_t FS_Write (qfile_t* file, const void* data, size_t datasize)
1327 return fwrite (data, 1, datasize, file->stream);
1332 ====================
1335 Read up to "buffersize" bytes from a file
1336 ====================
1338 size_t FS_Read (qfile_t* file, void* buffer, size_t buffersize)
1343 // Quick path for unpacked files
1344 if (! (file->flags & FS_FLAG_PACKED))
1345 return fread (buffer, 1, buffersize, file->stream);
1347 // If the file isn't compressed
1348 if (! (file->flags & FS_FLAG_DEFLATED))
1350 // We must take care to not read after the end of the file
1351 count = file->length - file->position;
1352 if (buffersize > count)
1355 nb = fread (buffer, 1, buffersize, file->stream);
1357 file->position += nb;
1361 // If the file is compressed, it's more complicated...
1364 // First, we copy as many bytes as we can from "output"
1365 if (ztk->out_ind < ztk->out_max)
1367 count = ztk->out_max - ztk->out_ind;
1369 nb = (buffersize > count) ? count : buffersize;
1370 memcpy (buffer, &ztk->output[ztk->out_ind], nb);
1372 file->position += nb;
1377 // We cycle through a few operations until we have inflated enough data
1378 while (nb < buffersize)
1380 // NOTE: at this point, "output" should always be empty
1382 // If "input" is also empty, we need to fill it
1383 if (ztk->in_ind == ztk->in_max)
1387 // If we are at the end of the file
1388 if (ztk->out_position == ztk->real_length)
1391 remain = file->length - ztk->in_position;
1392 count = (remain > sizeof (ztk->input)) ? sizeof (ztk->input) : remain;
1393 fread (ztk->input, 1, count, file->stream);
1395 // Update indexes and counters
1397 ztk->in_max = count;
1398 ztk->in_position += count;
1401 // Now that we are sure we have compressed data available, we need to determine
1402 // if it's better to inflate it in "output" or directly in "buffer" (we are in this
1403 // case if we still need more bytes than "output" can contain)
1405 ztk->zstream.next_in = &ztk->input[ztk->in_ind];
1406 ztk->zstream.avail_in = ztk->in_max - ztk->in_ind;
1408 // If output will be able to contain at least 1 more byte than the data we need
1409 if (buffersize - nb < sizeof (ztk->output))
1413 // Inflate the data in "output"
1414 ztk->zstream.next_out = ztk->output;
1415 ztk->zstream.avail_out = sizeof (ztk->output);
1416 error = qz_inflate (&ztk->zstream, Z_SYNC_FLUSH);
1417 if (error != Z_OK && error != Z_STREAM_END)
1418 Sys_Error ("Can't inflate file");
1419 ztk->in_ind = ztk->in_max - ztk->zstream.avail_in;
1420 ztk->out_max = sizeof (ztk->output) - ztk->zstream.avail_out;
1421 ztk->out_position += ztk->out_max;
1423 // Copy the requested data in "buffer" (as much as we can)
1424 count = (buffersize - nb > ztk->out_max) ? ztk->out_max : buffersize - nb;
1425 memcpy (&((qbyte*)buffer)[nb], ztk->output, count);
1426 ztk->out_ind = count;
1429 // Else, we inflate directly in "buffer"
1434 // Inflate the data in "buffer"
1435 ztk->zstream.next_out = &((qbyte*)buffer)[nb];
1436 ztk->zstream.avail_out = buffersize - nb;
1437 error = qz_inflate (&ztk->zstream, Z_SYNC_FLUSH);
1438 if (error != Z_OK && error != Z_STREAM_END)
1439 Sys_Error ("Can't inflate file");
1440 ztk->in_ind = ztk->in_max - ztk->zstream.avail_in;
1442 // Invalidate the output data (for FS_Seek)
1446 // How much data did it inflate?
1447 count = buffersize - nb - ztk->zstream.avail_out;
1448 ztk->out_position += count;
1452 file->position += count;
1460 ====================
1463 Flush the file output stream
1464 ====================
1466 int FS_Flush (qfile_t* file)
1468 return fflush (file->stream);
1473 ====================
1476 Print a string into a file
1477 ====================
1479 int FS_Print(qfile_t* file, const char *msg)
1481 return FS_Write(file, msg, strlen(msg));
1485 ====================
1488 Print a string into a file
1489 ====================
1491 int FS_Printf(qfile_t* file, const char* format, ...)
1496 va_start (args, format);
1497 result = vfprintf (file->stream, format, args);
1505 ====================
1508 Print a string into a file
1509 ====================
1511 int FS_VPrintf(qfile_t* file, const char* format, va_list ap)
1513 return vfprintf (file->stream, format, ap);
1518 ====================
1521 Get the next character of a file
1522 ====================
1524 int FS_Getc (qfile_t* file)
1528 if (FS_Read (file, &c, 1) != 1)
1536 ====================
1539 Move the position index in a file
1540 ====================
1542 int FS_Seek (qfile_t* file, long offset, int whence)
1544 // Quick path for unpacked files
1545 if (! (file->flags & FS_FLAG_PACKED))
1546 return fseek (file->stream, offset, whence);
1548 // Seeking in compressed files is more a hack than anything else,
1549 // but we need to support it, so here it is.
1550 if (file->flags & FS_FLAG_DEFLATED)
1552 ztoolkit_t *ztk = file->z;
1553 qbyte buffer [sizeof (ztk->output)]; // it's big to force inflating into buffer directly
1558 offset += file->position;
1565 offset += ztk->real_length;
1571 if (offset < 0 || offset > (long) ztk->real_length)
1574 // If we need to go back in the file
1575 if (offset <= (long) file->position)
1577 // If we still have the data we need in the output buffer
1578 if (file->position - offset <= ztk->out_ind)
1580 ztk->out_ind -= file->position - offset;
1581 file->position = offset;
1585 // Else, we restart from the beginning of the file
1588 ztk->in_position = 0;
1591 ztk->out_position = 0;
1593 fseek (file->stream, file->offset, SEEK_SET);
1595 // Reset the Zlib stream
1596 ztk->zstream.next_in = ztk->input;
1597 ztk->zstream.avail_in = 0;
1598 qz_inflateReset (&ztk->zstream);
1601 // Skip all data until we reach the requested offset
1602 while ((long) file->position < offset)
1604 size_t diff = offset - file->position;
1607 count = (diff > sizeof (buffer)) ? sizeof (buffer) : diff;
1608 len = FS_Read (file, buffer, count);
1616 // Packed files receive a special treatment too, because
1617 // we need to make sure it doesn't go outside of the file
1621 offset += file->position;
1628 offset += file->length;
1634 if (offset < 0 || offset > (long) file->length)
1637 if (fseek (file->stream, file->offset + offset, SEEK_SET) == -1)
1639 file->position = offset;
1645 ====================
1648 Give the current position in a file
1649 ====================
1651 long FS_Tell (qfile_t* file)
1653 if (file->flags & FS_FLAG_PACKED)
1654 return file->position;
1656 return ftell (file->stream);
1661 ====================
1664 Extract a line from a file
1665 ====================
1667 char* FS_Gets (qfile_t* file, char* buffer, int buffersize)
1671 // Quick path for unpacked files
1672 if (! (file->flags & FS_FLAG_PACKED))
1673 return fgets (buffer, buffersize, file->stream);
1675 for (ind = 0; ind < (size_t) buffersize - 1; ind++)
1677 int c = FS_Getc (file);
1692 buffer[ind + 1] = '\0';
1701 buffer[buffersize - 1] = '\0';
1710 Dynamic length version of fgets. DO NOT free the buffer.
1713 char *FS_Getline (qfile_t *file)
1715 static int size = 256;
1716 static char *buf = 0;
1721 buf = Mem_Alloc (fs_mempool, size);
1723 if (!FS_Gets (file, buf, size))
1727 while (buf[len - 1] != '\n' && buf[len - 1] != '\r')
1729 t = Mem_Alloc (fs_mempool, size + 256);
1730 memcpy(t, buf, size);
1734 if (!FS_Gets (file, buf + len, size - len))
1738 while ((len = strlen(buf)) && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
1745 ====================
1748 Extract a line from a file
1749 ====================
1751 int FS_Eof (qfile_t* file)
1753 if (file->flags & FS_FLAG_PACKED)
1755 if (file->flags & FS_FLAG_DEFLATED)
1756 return (file->position == file->z->real_length);
1758 return (file->position == file->length);
1761 return feof (file->stream);
1769 Filename are relative to the quake directory.
1770 Always appends a 0 byte.
1773 qbyte *FS_LoadFile (const char *path, mempool_t *pool, qboolean quiet)
1778 // look for it in the filesystem or pack files
1779 h = FS_Open (path, "rb", quiet);
1783 buf = Mem_Alloc(pool, fs_filesize+1);
1785 Sys_Error ("FS_LoadFile: not enough available memory for %s (size %i)", path, fs_filesize);
1787 ((qbyte *)buf)[fs_filesize] = 0;
1789 FS_Read (h, buf, fs_filesize);
1800 The filename will be prefixed by the current game directory
1803 qboolean FS_WriteFile (const char *filename, void *data, int len)
1807 handle = FS_Open (filename, "wb", false);
1810 Con_Printf("FS_WriteFile: failed on %s\n", filename);
1814 Con_DPrintf("FS_WriteFile: %s\n", filename);
1815 FS_Write (handle, data, len);
1822 =============================================================================
1824 OTHERS PUBLIC FUNCTIONS
1826 =============================================================================
1834 void FS_StripExtension (const char *in, char *out, size_t size_out)
1841 while (*in && size_out > 1)
1845 else if (*in == '/' || *in == '\\' || *in == ':')
1862 void FS_DefaultExtension (char *path, const char *extension, size_t size_path)
1866 // if path doesn't have a .EXT, append extension
1867 // (extension should include the .)
1868 src = path + strlen(path) - 1;
1870 while (*src != '/' && src != path)
1873 return; // it has an extension
1877 strlcat (path, extension, size_path);
1885 Look for a file in the packages and in the filesystem
1888 qboolean FS_FileExists (const char *filename)
1890 return (FS_FindFile (filename, NULL, true) != NULL);
1898 Look for a file in the filesystem only
1901 qboolean FS_SysFileExists (const char *path)
1906 f = fopen (path, "rb");
1917 if (stat (path,&buf) == -1)
1924 void FS_mkdir (const char *path)
1937 Allocate and fill a search structure with information on matching filenames.
1940 fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet)
1943 searchpath_t *searchpath;
1945 int i, basepathlength, numfiles, numchars;
1946 stringlist_t *dir, *dirfile, *liststart, *listcurrent, *listtemp;
1947 const char *slash, *backslash, *colon, *separator;
1949 char netpath[MAX_OSPATH];
1950 char temp[MAX_OSPATH];
1952 while(!strncmp(pattern, "./", 2))
1954 while(!strncmp(pattern, ".\\", 2))
1961 slash = strrchr(pattern, '/');
1962 backslash = strrchr(pattern, '\\');
1963 colon = strrchr(pattern, ':');
1964 separator = pattern;
1965 if (separator < slash)
1967 if (separator < backslash)
1968 separator = backslash;
1969 if (separator < colon)
1971 basepathlength = separator - pattern;
1972 basepath = Mem_Alloc (tempmempool, basepathlength + 1);
1974 memcpy(basepath, pattern, basepathlength);
1975 basepath[basepathlength] = 0;
1977 // search through the path, one element at a time
1978 for (searchpath = fs_searchpaths;searchpath;searchpath = searchpath->next)
1980 // is the element a pak file?
1981 if (searchpath->pack)
1983 // look through all the pak file elements
1984 pak = searchpath->pack;
1985 for (i = 0;i < pak->numfiles;i++)
1987 strcpy(temp, pak->files[i].name);
1990 if (matchpattern(temp, (char *)pattern, true))
1992 for (listtemp = liststart;listtemp;listtemp = listtemp->next)
1993 if (!strcmp(listtemp->text, temp))
1995 if (listtemp == NULL)
1997 listcurrent = stringlistappend(listcurrent, temp);
1998 if (liststart == NULL)
1999 liststart = listcurrent;
2001 Sys_Printf("SearchPackFile: %s : %s\n", pak->filename, temp);
2004 // strip off one path element at a time until empty
2005 // this way directories are added to the listing if they match the pattern
2006 slash = strrchr(temp, '/');
2007 backslash = strrchr(temp, '\\');
2008 colon = strrchr(temp, ':');
2010 if (separator < slash)
2012 if (separator < backslash)
2013 separator = backslash;
2014 if (separator < colon)
2016 *((char *)separator) = 0;
2022 // get a directory listing and look at each name
2023 snprintf(netpath, sizeof (netpath), "%s/%s", searchpath->filename, basepath);
2024 if ((dir = listdirectory(netpath)))
2026 for (dirfile = dir;dirfile;dirfile = dirfile->next)
2028 snprintf(temp, sizeof(temp), "%s/%s", basepath, dirfile->text);
2029 if (matchpattern(temp, (char *)pattern, true))
2031 for (listtemp = liststart;listtemp;listtemp = listtemp->next)
2032 if (!strcmp(listtemp->text, temp))
2034 if (listtemp == NULL)
2036 listcurrent = stringlistappend(listcurrent, temp);
2037 if (liststart == NULL)
2038 liststart = listcurrent;
2040 Sys_Printf("SearchDirFile: %s\n", temp);
2051 liststart = stringlistsort(liststart);
2054 for (listtemp = liststart;listtemp;listtemp = listtemp->next)
2057 numchars += strlen(listtemp->text) + 1;
2059 search = Z_Malloc(sizeof(fssearch_t) + numchars + numfiles * sizeof(char *));
2060 search->filenames = (char **)((char *)search + sizeof(fssearch_t));
2061 search->filenamesbuffer = (char *)((char *)search + sizeof(fssearch_t) + numfiles * sizeof(char *));
2062 search->numfilenames = numfiles;
2065 for (listtemp = liststart;listtemp;listtemp = listtemp->next)
2067 search->filenames[numfiles] = search->filenamesbuffer + numchars;
2068 strcpy(search->filenames[numfiles], listtemp->text);
2070 numchars += strlen(listtemp->text) + 1;
2073 stringlistfree(liststart);
2080 void FS_FreeSearch(fssearch_t *search)
2085 extern int con_linewidth;
2086 int FS_ListDirectory(const char *pattern, int oneperline)
2097 search = FS_Search(pattern, true, true);
2100 numfiles = search->numfilenames;
2103 // FIXME: the names could be added to one column list and then
2104 // gradually shifted into the next column if they fit, and then the
2105 // next to make a compact variable width listing but it's a lot more
2107 // find width for columns
2109 for (i = 0;i < numfiles;i++)
2111 l = strlen(search->filenames[i]);
2112 if (columnwidth < l)
2115 // count the spacing character
2117 // calculate number of columns
2118 numcolumns = con_linewidth / columnwidth;
2119 // don't bother with the column printing if it's only one column
2120 if (numcolumns >= 2)
2122 numlines = (numfiles + numcolumns - 1) / numcolumns;
2123 for (i = 0;i < numlines;i++)
2126 for (k = 0;k < numcolumns;k++)
2128 l = i * numcolumns + k;
2131 name = search->filenames[l];
2132 for (j = 0;name[j] && j < (int)sizeof(linebuf) - 1;j++)
2133 linebuf[linebufpos++] = name[j];
2134 // space out name unless it's the last on the line
2135 if (k < (numcolumns - 1) && l < (numfiles - 1))
2136 for (;j < columnwidth && j < (int)sizeof(linebuf) - 1;j++)
2137 linebuf[linebufpos++] = ' ';
2140 linebuf[linebufpos] = 0;
2141 Con_Printf("%s\n", linebuf);
2148 for (i = 0;i < numfiles;i++)
2149 Con_Printf("%s\n", search->filenames[i]);
2150 FS_FreeSearch(search);
2154 static void FS_ListDirectoryCmd (const char* cmdname, int oneperline)
2156 const char *pattern;
2159 Con_Printf("usage:\n%s [path/pattern]\n", cmdname);
2162 if (Cmd_Argc() == 2)
2163 pattern = Cmd_Argv(1);
2166 if (!FS_ListDirectory(pattern, oneperline))
2167 Con_Print("No files found.\n");
2172 FS_ListDirectoryCmd("dir", true);
2177 FS_ListDirectoryCmd("ls", false);