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 =============================================================================
242 mempool_t *fs_mempool;
243 mempool_t *pak_mempool;
247 pack_t *packlist = NULL;
249 searchpath_t *fs_searchpaths;
251 #define MAX_FILES_IN_PACK 65536
253 char fs_gamedir[MAX_OSPATH];
254 char fs_basedir[MAX_OSPATH];
256 qboolean fs_modified; // set true if using non-id files
260 =============================================================================
262 PRIVATE FUNCTIONS - PK3 HANDLING
264 =============================================================================
267 // Functions exported from zlib
269 # define ZEXPORT WINAPI
274 static int (ZEXPORT *qz_inflate) (z_stream* strm, int flush);
275 static int (ZEXPORT *qz_inflateEnd) (z_stream* strm);
276 static int (ZEXPORT *qz_inflateInit2_) (z_stream* strm, int windowBits, const char *version, int stream_size);
277 static int (ZEXPORT *qz_inflateReset) (z_stream* strm);
279 #define qz_inflateInit2(strm, windowBits) \
280 qz_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
282 static dllfunction_t zlibfuncs[] =
284 {"inflate", (void **) &qz_inflate},
285 {"inflateEnd", (void **) &qz_inflateEnd},
286 {"inflateInit2_", (void **) &qz_inflateInit2_},
287 {"inflateReset", (void **) &qz_inflateReset},
291 // Handle for Zlib DLL
292 static dllhandle_t zlib_dll = NULL;
302 void PK3_CloseLibrary (void)
307 Sys_UnloadLibrary (zlib_dll);
316 Try to load the Zlib DLL
319 qboolean PK3_OpenLibrary (void)
322 const dllfunction_t *func;
329 dllname = "zlib.dll";
331 dllname = "libz.so.1";
335 for (func = zlibfuncs; func && func->name != NULL; func++)
336 *func->funcvariable = NULL;
339 if (! (zlib_dll = Sys_LoadLibrary (dllname)))
341 Con_Printf("Can't find %s. Compressed files support disabled\n", dllname);
345 // Get the function adresses
346 for (func = zlibfuncs; func && func->name != NULL; func++)
347 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (zlib_dll, func->name)))
349 Con_Printf("missing function \"%s\" - broken Zlib library!\n", func->name);
354 Con_Printf("%s loaded. Compressed files support enabled\n", dllname);
361 PK3_GetEndOfCentralDir
363 Extract the end of the central directory from a PK3 package
366 qboolean PK3_GetEndOfCentralDir (const char *packfile, FILE *packhandle, pk3_endOfCentralDir_t *eocd)
368 long filesize, maxsize;
372 // Get the package size
373 fseek (packhandle, 0, SEEK_END);
374 filesize = ftell (packhandle);
375 if (filesize < ZIP_END_CDIR_SIZE)
378 // Load the end of the file in memory
379 if (filesize < ZIP_MAX_COMMENTS_SIZE + ZIP_END_CDIR_SIZE)
382 maxsize = ZIP_MAX_COMMENTS_SIZE + ZIP_END_CDIR_SIZE;
383 buffer = Mem_Alloc (tempmempool, maxsize);
384 fseek (packhandle, filesize - maxsize, SEEK_SET);
385 if (fread (buffer, 1, maxsize, packhandle) != (unsigned long) maxsize)
391 // Look for the end of central dir signature around the end of the file
392 maxsize -= ZIP_END_CDIR_SIZE;
393 ptr = &buffer[maxsize];
395 while (BuffBigLong (ptr) != ZIP_END_HEADER)
407 memcpy (eocd, ptr, ZIP_END_CDIR_SIZE);
408 eocd->signature = LittleLong (eocd->signature);
409 eocd->disknum = LittleShort (eocd->disknum);
410 eocd->cdir_disknum = LittleShort (eocd->cdir_disknum);
411 eocd->localentries = LittleShort (eocd->localentries);
412 eocd->nbentries = LittleShort (eocd->nbentries);
413 eocd->cdir_size = LittleLong (eocd->cdir_size);
414 eocd->cdir_offset = LittleLong (eocd->cdir_offset);
415 eocd->comment_size = LittleShort (eocd->comment_size);
427 Extract the file list from a PK3 file
430 int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd)
432 qbyte *central_dir, *ptr;
436 // Load the central directory in memory
437 central_dir = Mem_Alloc (tempmempool, eocd->cdir_size);
438 fseek (pack->handle, eocd->cdir_offset, SEEK_SET);
439 fread (central_dir, 1, eocd->cdir_size, pack->handle);
441 // Extract the files properties
442 // The parsing is done "by hand" because some fields have variable sizes and
443 // the constant part isn't 4-bytes aligned, which makes the use of structs difficult
444 remaining = eocd->cdir_size;
447 for (ind = 0; ind < eocd->nbentries; ind++)
449 size_t namesize, count;
452 // Checking the remaining size
453 if (remaining < ZIP_CDIR_CHUNK_BASE_SIZE)
455 Mem_Free (central_dir);
458 remaining -= ZIP_CDIR_CHUNK_BASE_SIZE;
461 if (BuffBigLong (ptr) != ZIP_CDIR_HEADER)
463 Mem_Free (central_dir);
467 namesize = BuffLittleShort (&ptr[28]); // filename length
469 // Check encryption, compression, and attributes
470 // 1st uint8 : general purpose bit flag
471 // Check bits 0 (encryption), 3 (data descriptor after the file), and 5 (compressed patched data (?))
472 // 2nd uint8 : external file attributes
473 // Check bits 3 (file is a directory) and 5 (file is a volume (?))
474 if ((ptr[8] & 0x29) == 0 && (ptr[38] & 0x18) == 0)
476 // Still enough bytes for the name?
477 if ((size_t) remaining < namesize || namesize >= sizeof (*pack->files))
479 Mem_Free (central_dir);
483 // WinZip doesn't use the "directory" attribute, so we need to check the name directly
484 if (ptr[ZIP_CDIR_CHUNK_BASE_SIZE + namesize - 1] != '/')
487 file = &pack->files[pack->numfiles];
488 memcpy (file->name, &ptr[ZIP_CDIR_CHUNK_BASE_SIZE], namesize);
489 file->name[namesize] = '\0';
491 // Compression, sizes and offset
492 if (BuffLittleShort (&ptr[10]))
493 file->flags = FILE_FLAG_DEFLATED;
494 file->packsize = BuffLittleLong (&ptr[20]);
495 file->realsize = BuffLittleLong (&ptr[24]);
496 file->offset = BuffLittleLong (&ptr[42]);
502 // Skip the name, additionnal field, and comment
503 // 1er uint16 : extra field length
504 // 2eme uint16 : file comment length
505 count = namesize + BuffLittleShort (&ptr[30]) + BuffLittleShort (&ptr[32]);
506 ptr += ZIP_CDIR_CHUNK_BASE_SIZE + count;
510 Mem_Free (central_dir);
511 return pack->numfiles;
519 Create a package entry associated with a PK3 file
522 pack_t *FS_LoadPackPK3 (const char *packfile)
525 pk3_endOfCentralDir_t eocd;
529 packhandle = fopen (packfile, "rb");
533 if (! PK3_GetEndOfCentralDir (packfile, packhandle, &eocd))
534 Sys_Error ("%s is not a PK3 file", packfile);
536 // Multi-volume ZIP archives are NOT allowed
537 if (eocd.disknum != 0 || eocd.cdir_disknum != 0)
538 Sys_Error ("%s is a multi-volume ZIP archive", packfile);
540 // We only need to do this test if MAX_FILES_IN_PACK is lesser than 65535
541 // since eocd.nbentries is an unsigned 16 bits integer
542 #if MAX_FILES_IN_PACK < 65535
543 if (eocd.nbentries > MAX_FILES_IN_PACK)
544 Sys_Error ("%s contains too many files (%hu)", packfile, eocd.nbentries);
547 // Create a package structure in memory
548 pack = Mem_Alloc (pak_mempool, sizeof (pack_t));
549 pack->ignorecase = true; // PK3 ignores case
550 strlcpy (pack->filename, packfile, sizeof (pack->filename));
551 pack->handle = packhandle;
552 pack->numfiles = eocd.nbentries;
553 pack->mempool = Mem_AllocPool (packfile);
554 pack->files = Mem_Alloc (pack->mempool, eocd.nbentries * sizeof(packfile_t));
555 pack->next = packlist;
558 real_nb_files = PK3_BuildFileList (pack, &eocd);
559 if (real_nb_files <= 0)
560 Sys_Error ("%s is not a valid PK3 file", packfile);
562 Con_Printf ("Added packfile %s (%i files)\n", packfile, real_nb_files);
569 PK3_GetTrueFileOffset
571 Find where the true file data offset is
574 void PK3_GetTrueFileOffset (packfile_t *file, pack_t *pack)
576 qbyte buffer [ZIP_LOCAL_CHUNK_BASE_SIZE];
580 if (file->flags & FILE_FLAG_TRUEOFFS)
583 // Load the local file description
584 fseek (pack->handle, file->offset, SEEK_SET);
585 count = fread (buffer, 1, ZIP_LOCAL_CHUNK_BASE_SIZE, pack->handle);
586 if (count != ZIP_LOCAL_CHUNK_BASE_SIZE || BuffBigLong (buffer) != ZIP_DATA_HEADER)
587 Sys_Error ("Can't retrieve file %s in package %s", file->name, pack->filename);
589 // Skip name and extra field
590 file->offset += BuffLittleShort (&buffer[26]) + BuffLittleShort (&buffer[28]) + ZIP_LOCAL_CHUNK_BASE_SIZE;
592 file->flags |= FILE_FLAG_TRUEOFFS;
597 =============================================================================
599 OTHER PRIVATE FUNCTIONS
601 =============================================================================
609 Only used for FS_WriteFile.
612 void FS_CreatePath (char *path)
616 for (ofs = path+1 ; *ofs ; ofs++)
618 if (*ofs == '/' || *ofs == '\\')
620 // create the directory
636 void FS_Path_f (void)
640 Con_Printf ("Current search path:\n");
641 for (s=fs_searchpaths ; s ; s=s->next)
645 Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
648 Con_Printf ("%s\n", s->filename);
657 Takes an explicit (not game tree related) path to a pak file.
659 Loads the header and directory, adding the files at the beginning
660 of the list so they override previous pack files.
663 pack_t *FS_LoadPackPAK (const char *packfile)
665 dpackheader_t header;
669 dpackfile_t *info; // temporary alloc, allowing huge pack directories
671 packhandle = fopen (packfile, "rb");
675 fread ((void *)&header, 1, sizeof(header), packhandle);
676 if (memcmp(header.id, "PACK", 4))
677 Sys_Error ("%s is not a packfile", packfile);
678 header.dirofs = LittleLong (header.dirofs);
679 header.dirlen = LittleLong (header.dirlen);
681 if (header.dirlen % sizeof(dpackfile_t))
682 Sys_Error ("%s has an invalid directory size", packfile);
684 numpackfiles = header.dirlen / sizeof(dpackfile_t);
686 if (numpackfiles > MAX_FILES_IN_PACK)
687 Sys_Error ("%s has %i files", packfile, numpackfiles);
689 pack = Mem_Alloc(pak_mempool, sizeof (pack_t));
690 pack->ignorecase = false; // PAK is case sensitive
691 strlcpy (pack->filename, packfile, sizeof (pack->filename));
692 pack->handle = packhandle;
693 pack->numfiles = numpackfiles;
694 pack->mempool = Mem_AllocPool(packfile);
695 pack->files = Mem_Alloc(pack->mempool, numpackfiles * sizeof(packfile_t));
696 pack->next = packlist;
699 info = Mem_Alloc(tempmempool, sizeof(*info) * numpackfiles);
700 fseek (packhandle, header.dirofs, SEEK_SET);
701 fread ((void *)info, 1, header.dirlen, packhandle);
703 // parse the directory
704 for (i = 0;i < numpackfiles;i++)
707 packfile_t *file = &pack->files[i];
709 strlcpy (file->name, info[i].name, sizeof (file->name));
710 file->offset = LittleLong(info[i].filepos);
711 size = LittleLong (info[i].filelen);
712 file->packsize = size;
713 file->realsize = size;
714 file->flags = FILE_FLAG_TRUEOFFS;
719 Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
728 Sets fs_gamedir, adds the directory to the head of the path,
729 then loads and adds pak1.pak pak2.pak ...
732 void FS_AddGameDirectory (char *dir)
734 stringlist_t *list, *current;
735 searchpath_t *search;
737 char pakfile[MAX_OSPATH];
739 strlcpy (fs_gamedir, dir, sizeof (fs_gamedir));
741 // add the directory to the search path
742 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
743 strlcpy (search->filename, dir, sizeof (search->filename));
744 search->next = fs_searchpaths;
745 fs_searchpaths = search;
747 list = listdirectory(dir);
749 // add any PAK package in the directory
750 for (current = list;current;current = current->next)
752 if (matchpattern(current->text, "*.pak", true))
754 snprintf (pakfile, sizeof (pakfile), "%s/%s", dir, current->text);
755 pak = FS_LoadPackPAK (pakfile);
758 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
760 search->next = fs_searchpaths;
761 fs_searchpaths = search;
764 Con_Printf("unable to load pak \"%s\"\n", pakfile);
768 // add any PK3 package in the director
769 for (current = list;current;current = current->next)
771 if (matchpattern(current->text, "*.pk3", true))
773 snprintf (pakfile, sizeof (pakfile), "%s/%s", dir, current->text);
774 pak = FS_LoadPackPK3 (pakfile);
777 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
779 search->next = fs_searchpaths;
780 fs_searchpaths = search;
783 Con_Printf("unable to load pak \"%s\"\n", pakfile);
795 char *FS_FileExtension (const char *in)
797 static char exten[8];
798 const char *slash, *backslash, *colon, *dot, *separator;
801 slash = strrchr(in, '/');
802 backslash = strrchr(in, '\\');
803 colon = strrchr(in, ':');
804 dot = strrchr(in, '.');
806 if (separator < backslash)
807 separator = backslash;
808 if (separator < colon)
813 for (i = 0;i < 7 && dot[i];i++)
830 searchpath_t *search;
832 fs_mempool = Mem_AllocPool("file management");
833 pak_mempool = Mem_AllocPool("paks");
835 Cmd_AddCommand ("path", FS_Path_f);
836 Cmd_AddCommand ("dir", FS_Dir_f);
837 Cmd_AddCommand ("ls", FS_Ls_f);
839 strcpy(fs_basedir, ".");
844 // Overrides the system supplied base directory (under GAMENAME)
845 i = COM_CheckParm ("-basedir");
846 if (i && i < com_argc-1)
847 strlcpy (fs_basedir, com_argv[i+1], sizeof (fs_basedir));
849 i = strlen (fs_basedir);
850 if (i > 0 && (fs_basedir[i-1] == '\\' || fs_basedir[i-1] == '/'))
853 // start up with GAMENAME by default (id1)
854 strlcpy (com_modname, GAMENAME, sizeof (com_modname));
855 FS_AddGameDirectory (va("%s/"GAMENAME, fs_basedir));
859 strlcpy (com_modname, gamedirname, sizeof (com_modname));
860 FS_AddGameDirectory (va("%s/%s", fs_basedir, gamedirname));
864 // Adds basedir/gamedir as an override game
865 i = COM_CheckParm ("-game");
866 if (i && i < com_argc-1)
869 strlcpy (com_modname, com_argv[i+1], sizeof (com_modname));
870 FS_AddGameDirectory (va("%s/%s", fs_basedir, com_argv[i+1]));
873 // -path <dir or packfile> [<dir or packfile>] ...
874 // Fully specifies the exact search path, overriding the generated one
875 i = COM_CheckParm ("-path");
879 fs_searchpaths = NULL;
880 while (++i < com_argc)
882 if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')
885 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
886 if (!strcasecmp (FS_FileExtension(com_argv[i]), "pak"))
888 search->pack = FS_LoadPackPAK (com_argv[i]);
890 Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
892 else if (!strcasecmp (FS_FileExtension (com_argv[i]), "pk3"))
894 search->pack = FS_LoadPackPK3 (com_argv[i]);
896 Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
899 strlcpy (search->filename, com_argv[i], sizeof (search->filename));
900 search->next = fs_searchpaths;
901 fs_searchpaths = search;
911 Internal function used to create a qfile_t and open the relevant file on disk
914 static qfile_t* FS_SysOpen (const char* filepath, const char* mode)
918 file = Mem_Alloc (fs_mempool, sizeof (*file));
919 memset (file, 0, sizeof (*file));
921 file->stream = fopen (filepath, mode);
937 qfile_t *FS_OpenRead (const char *path, int offs, int len)
941 file = FS_SysOpen (path, "rb");
944 Sys_Error ("Couldn't open %s", path);
949 if (offs < 0 || len < 0)
951 // We set fs_filesize here for normal files
952 fseek (file->stream, 0, SEEK_END);
953 fs_filesize = ftell (file->stream);
954 fseek (file->stream, 0, SEEK_SET);
959 fseek (file->stream, offs, SEEK_SET);
961 file->flags |= FS_FLAG_PACKED;
974 If the requested file is inside a packfile, a new qfile_t* will be opened
980 qfile_t *FS_FOpenFile (const char *filename, qboolean quiet)
982 searchpath_t *search;
983 char netpath[MAX_OSPATH];
985 int i, filenamelen, matched;
987 filenamelen = strlen (filename);
989 // LordHavoc: this is not written right!
990 // (should search have higher priority for files in each gamedir, while
991 // preserving the gamedir priorities, not searching for all paks in all
992 // gamedirs and then all files in all gamedirs)
994 // first we search for a real file, after that we start to search through the paks
995 // search through the path, one element at a time
996 search = fs_searchpaths;
998 for( ; search ; search = search->next)
1001 snprintf (netpath, sizeof (netpath), "%s/%s",search->filename, filename);
1003 if (!FS_SysFileExists (netpath))
1007 Sys_Printf ("FindFile: %s\n",netpath);
1008 return FS_OpenRead (netpath, -1, -1);
1011 search = fs_searchpaths;
1012 for ( ; search ; search = search->next)
1013 // is the element a pak file?
1016 // look through all the pak file elements
1018 for (i=0 ; i<pak->numfiles ; i++)
1020 if (pak->ignorecase)
1021 matched = !strcasecmp (pak->files[i].name, filename);
1023 matched = !strcmp (pak->files[i].name, filename);
1024 if (matched) // found it?
1029 Sys_Printf ("PackFile: %s : %s\n",pak->filename, pak->files[i].name);
1031 // If we don't have the true offset, get it now
1032 if (! (pak->files[i].flags & FILE_FLAG_TRUEOFFS))
1033 PK3_GetTrueFileOffset (&pak->files[i], pak);
1035 // No Zlib DLL = no compressed files
1036 if (!zlib_dll && (pak->files[i].flags & FILE_FLAG_DEFLATED))
1038 Con_Printf ("WARNING: can't open the compressed file %s\n"
1039 "You need the Zlib DLL to use compressed files\n", filename);
1044 // open a new file in the pakfile
1045 file = FS_OpenRead (pak->filename, pak->files[i].offset, pak->files[i].packsize);
1046 fs_filesize = pak->files[i].realsize;
1048 if (pak->files[i].flags & FILE_FLAG_DEFLATED)
1052 file->flags |= FS_FLAG_DEFLATED;
1054 // We need some more variables
1055 ztk = Mem_Alloc (fs_mempool, sizeof (*file->z));
1057 ztk->real_length = pak->files[i].realsize;
1059 // Initialize zlib stream
1060 ztk->zstream.next_in = ztk->input;
1061 ztk->zstream.avail_in = 0;
1063 /* From Zlib's "unzip.c":
1065 * windowBits is passed < 0 to tell that there is no zlib header.
1066 * Note that in this case inflate *requires* an extra "dummy" byte
1067 * after the compressed stream in order to complete decompression and
1068 * return Z_STREAM_END.
1069 * In unzip, i don't wait absolutely Z_STREAM_END because I known the
1070 * size of both compressed and uncompressed data
1072 if (qz_inflateInit2 (&ztk->zstream, -MAX_WBITS) != Z_OK)
1073 Sys_Error ("inflate init error (file: %s)", filename);
1075 ztk->zstream.next_out = ztk->output;
1076 ztk->zstream.avail_out = sizeof (ztk->output);
1086 // search through the path, one element at a time
1087 search = fs_searchpaths;
1089 for ( ; search ; search = search->next)
1091 // is the element a pak file?
1094 // look through all the pak file elements
1096 for (i=0 ; i<pak->numfiles ; i++)
1098 if (pak->ignorecase)
1099 matched = !strcasecmp (pak->files[i].name, filename);
1101 matched = !strcmp (pak->files[i].name, filename);
1102 if (matched) // found it?
1107 Sys_Printf ("PackFile: %s : %s\n",pak->filename, pak->files[i].name);
1109 // If we don't have the true offset, get it now
1110 if (! (pak->files[i].flags & FILE_FLAG_TRUEOFFS))
1111 PK3_GetTrueFileOffset (&pak->files[i], pak);
1113 // No Zlib DLL = no compressed files
1114 if (!zlib_dll && (pak->files[i].flags & FILE_FLAG_DEFLATED))
1116 Con_Printf ("WARNING: can't open the compressed file %s\n"
1117 "You need the Zlib DLL to use compressed files\n", filename);
1122 // open a new file in the pakfile
1123 file = FS_OpenRead (pak->filename, pak->files[i].offset, pak->files[i].packsize);
1124 fs_filesize = pak->files[i].realsize;
1126 if (pak->files[i].flags & FILE_FLAG_DEFLATED)
1130 file->flags |= FS_FLAG_DEFLATED;
1132 // We need some more variables
1133 ztk = Mem_Alloc (fs_mempool, sizeof (*file->z));
1135 ztk->real_length = pak->files[i].realsize;
1137 // Initialize zlib stream
1138 ztk->zstream.next_in = ztk->input;
1139 ztk->zstream.avail_in = 0;
1141 /* From Zlib's "unzip.c":
1143 * windowBits is passed < 0 to tell that there is no zlib header.
1144 * Note that in this case inflate *requires* an extra "dummy" byte
1145 * after the compressed stream in order to complete decompression and
1146 * return Z_STREAM_END.
1147 * In unzip, i don't wait absolutely Z_STREAM_END because I known the
1148 * size of both compressed and uncompressed data
1150 if (qz_inflateInit2 (&ztk->zstream, -MAX_WBITS) != Z_OK)
1151 Sys_Error ("inflate init error (file: %s)", filename);
1153 ztk->zstream.next_out = ztk->output;
1154 ztk->zstream.avail_out = sizeof (ztk->output);
1165 snprintf (netpath, sizeof (netpath), "%s/%s",search->filename, filename);
1167 if (!FS_SysFileExists (netpath))
1171 Sys_Printf ("FindFile: %s\n",netpath);
1172 return FS_OpenRead (netpath, -1, -1);
1178 Sys_Printf ("FindFile: can't find %s\n", filename);
1186 =============================================================================
1188 MAIN PUBLIC FUNCTIONS
1190 =============================================================================
1194 ====================
1197 Open a file. The syntax is the same as fopen
1198 ====================
1200 qfile_t* FS_Open (const char* filepath, const char* mode, qboolean quiet)
1202 // If the file is opened in "write" or "append" mode
1203 if (strchr (mode, 'w') || strchr (mode, 'a'))
1205 char real_path [MAX_OSPATH];
1207 // Open the file on disk directly
1208 snprintf (real_path, sizeof (real_path), "%s/%s", fs_gamedir, filepath);
1210 // Create directories up to the file
1211 FS_CreatePath (real_path);
1213 return FS_SysOpen (real_path, mode);
1216 // Else, we look at the various search paths
1217 return FS_FOpenFile (filepath, quiet);
1222 ====================
1226 ====================
1228 int FS_Close (qfile_t* file)
1230 if (fclose (file->stream))
1235 qz_inflateEnd (&file->z->zstream);
1245 ====================
1248 Write "datasize" bytes into a file
1249 ====================
1251 size_t FS_Write (qfile_t* file, const void* data, size_t datasize)
1253 return fwrite (data, 1, datasize, file->stream);
1258 ====================
1261 Read up to "buffersize" bytes from a file
1262 ====================
1264 size_t FS_Read (qfile_t* file, void* buffer, size_t buffersize)
1269 // Quick path for unpacked files
1270 if (! (file->flags & FS_FLAG_PACKED))
1271 return fread (buffer, 1, buffersize, file->stream);
1273 // If the file isn't compressed
1274 if (! (file->flags & FS_FLAG_DEFLATED))
1276 // We must take care to not read after the end of the file
1277 count = file->length - file->position;
1278 if (buffersize > count)
1281 nb = fread (buffer, 1, buffersize, file->stream);
1283 file->position += nb;
1287 // If the file is compressed, it's more complicated...
1290 // First, we copy as many bytes as we can from "output"
1291 if (ztk->out_ind < ztk->out_max)
1293 count = ztk->out_max - ztk->out_ind;
1295 nb = (buffersize > count) ? count : buffersize;
1296 memcpy (buffer, &ztk->output[ztk->out_ind], nb);
1298 file->position += nb;
1303 // We cycle through a few operations until we have inflated enough data
1304 while (nb < buffersize)
1306 // NOTE: at this point, "output" should always be empty
1308 // If "input" is also empty, we need to fill it
1309 if (ztk->in_ind == ztk->in_max)
1311 size_t remain = file->length - ztk->in_position;
1313 // If we are at the end of the file
1317 count = (remain > sizeof (ztk->input)) ? sizeof (ztk->input) : remain;
1318 fread (ztk->input, 1, count, file->stream);
1320 // Update indexes and counters
1322 ztk->in_max = count;
1323 ztk->in_position += count;
1326 // Now that we are sure we have compressed data available, we need to determine
1327 // if it's better to inflate it in "output" or directly in "buffer" (we are in this
1328 // case if we still need more bytes than "output" can contain)
1330 ztk->zstream.next_in = &ztk->input[ztk->in_ind];
1331 ztk->zstream.avail_in = ztk->in_max - ztk->in_ind;
1333 // If output will be able to contain at least 1 more byte than the data we need
1334 if (buffersize - nb < sizeof (ztk->output))
1338 // Inflate the data in "output"
1339 ztk->zstream.next_out = ztk->output;
1340 ztk->zstream.avail_out = sizeof (ztk->output);
1341 error = qz_inflate (&ztk->zstream, Z_SYNC_FLUSH);
1342 if (error != Z_OK && error != Z_STREAM_END)
1343 Sys_Error ("Can't inflate file");
1344 ztk->in_ind = ztk->in_max - ztk->zstream.avail_in;
1345 ztk->out_max = sizeof (ztk->output) - ztk->zstream.avail_out;
1346 ztk->out_position += ztk->out_max;
1348 // Copy the requested data in "buffer" (as much as we can)
1349 count = (buffersize - nb > ztk->out_max) ? ztk->out_max : buffersize - nb;
1350 memcpy (&((qbyte*)buffer)[nb], ztk->output, count);
1351 ztk->out_ind = count;
1354 // Else, we inflate directly in "buffer"
1359 // Inflate the data in "buffer"
1360 ztk->zstream.next_out = &((qbyte*)buffer)[nb];
1361 ztk->zstream.avail_out = buffersize - nb;
1362 error = qz_inflate (&ztk->zstream, Z_SYNC_FLUSH);
1363 if (error != Z_OK && error != Z_STREAM_END)
1364 Sys_Error ("Can't inflate file");
1365 ztk->in_ind = ztk->in_max - ztk->zstream.avail_in;
1367 // Invalidate the output data (for FS_Seek)
1371 // How much data did it inflate?
1372 count = buffersize - nb - ztk->zstream.avail_out;
1373 ztk->out_position += count;
1377 file->position += count;
1385 ====================
1388 Flush the file output stream
1389 ====================
1391 int FS_Flush (qfile_t* file)
1393 return fflush (file->stream);
1398 ====================
1401 Print a string into a file
1402 ====================
1404 int FS_Printf (qfile_t* file, const char* format, ...)
1409 va_start (args, format);
1410 result = vfprintf (file->stream, format, args);
1418 ====================
1421 Get the next character of a file
1422 ====================
1424 int FS_Getc (qfile_t* file)
1428 if (FS_Read (file, &c, 1) != 1)
1436 ====================
1439 Move the position index in a file
1440 ====================
1442 int FS_Seek (qfile_t* file, long offset, int whence)
1444 // Quick path for unpacked files
1445 if (! (file->flags & FS_FLAG_PACKED))
1446 return fseek (file->stream, offset, whence);
1448 // Seeking in compressed files is more a hack than anything else,
1449 // but we need to support it, so here it is.
1450 if (file->flags & FS_FLAG_DEFLATED)
1452 ztoolkit_t *ztk = file->z;
1453 qbyte buffer [sizeof (ztk->output)]; // it's big to force inflating into buffer directly
1458 offset += file->position;
1465 offset += ztk->real_length;
1471 if (offset < 0 || offset > (long) ztk->real_length)
1474 // If we need to go back in the file
1475 if (offset <= (long) file->position)
1477 // If we still have the data we need in the output buffer
1478 if (file->position - offset <= ztk->out_ind)
1480 ztk->out_ind -= file->position - offset;
1481 file->position = offset;
1485 // Else, we restart from the beginning of the file
1488 ztk->in_position = 0;
1491 ztk->out_position = 0;
1493 fseek (file->stream, file->offset, SEEK_SET);
1495 // Reset the Zlib stream
1496 ztk->zstream.next_in = ztk->input;
1497 ztk->zstream.avail_in = 0;
1498 qz_inflateReset (&ztk->zstream);
1501 // Skip all data until we reach the requested offset
1502 while ((long) file->position < offset)
1504 size_t diff = offset - file->position;
1507 count = (diff > sizeof (buffer)) ? sizeof (buffer) : diff;
1508 len = FS_Read (file, buffer, count);
1516 // Packed files receive a special treatment too, because
1517 // we need to make sure it doesn't go outside of the file
1521 offset += file->position;
1528 offset += file->length;
1534 if (offset < 0 || offset > (long) file->length)
1537 if (fseek (file->stream, file->offset + offset, SEEK_SET) == -1)
1539 file->position = offset;
1545 ====================
1548 Give the current position in a file
1549 ====================
1551 long FS_Tell (qfile_t* file)
1553 if (file->flags & FS_FLAG_PACKED)
1554 return file->position;
1556 return ftell (file->stream);
1561 ====================
1564 Extract a line from a file
1565 ====================
1567 char* FS_Gets (qfile_t* file, char* buffer, int buffersize)
1571 // Quick path for unpacked files
1572 if (! (file->flags & FS_FLAG_PACKED))
1573 return fgets (buffer, buffersize, file->stream);
1575 for (ind = 0; ind < (size_t) buffersize - 1; ind++)
1577 int c = FS_Getc (file);
1592 buffer[ind + 1] = '\0';
1601 buffer[buffersize - 1] = '\0';
1610 Dynamic length version of fgets. DO NOT free the buffer.
1613 char *FS_Getline (qfile_t *file)
1615 static int size = 256;
1616 static char *buf = 0;
1621 buf = Mem_Alloc (fs_mempool, size);
1623 if (!FS_Gets (file, buf, size))
1627 while (buf[len - 1] != '\n' && buf[len - 1] != '\r')
1629 t = Mem_Alloc (fs_mempool, size + 256);
1630 memcpy(t, buf, size);
1634 if (!FS_Gets (file, buf + len, size - len))
1638 while ((len = strlen(buf)) && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
1645 ====================
1648 Extract a line from a file
1649 ====================
1651 int FS_Eof (qfile_t* file)
1653 if (file->flags & FS_FLAG_PACKED)
1655 if (file->flags & FS_FLAG_DEFLATED)
1656 return (file->position == file->z->real_length);
1658 return (file->position == file->length);
1661 return feof (file->stream);
1669 Filename are relative to the quake directory.
1670 Always appends a 0 byte.
1673 qbyte *FS_LoadFile (const char *path, qboolean quiet)
1678 // look for it in the filesystem or pack files
1679 h = FS_Open (path, "rb", quiet);
1683 buf = Mem_Alloc(tempmempool, fs_filesize+1);
1685 Sys_Error ("FS_LoadFile: not enough available memory for %s (size %i)", path, fs_filesize);
1687 ((qbyte *)buf)[fs_filesize] = 0;
1689 FS_Read (h, buf, fs_filesize);
1700 The filename will be prefixed by the current game directory
1703 qboolean FS_WriteFile (const char *filename, void *data, int len)
1706 char name[MAX_OSPATH];
1708 snprintf (name, sizeof (name), "%s/%s", fs_gamedir, filename);
1710 // Create directories up to the file
1711 FS_CreatePath (name);
1713 handle = fopen (name, "wb");
1716 Con_Printf ("FS_WriteFile: failed on %s\n", name);
1720 Con_DPrintf ("FS_WriteFile: %s\n", name);
1721 fwrite (data, 1, len, handle);
1728 =============================================================================
1730 OTHERS PUBLIC FUNCTIONS
1732 =============================================================================
1740 void FS_StripExtension (const char *in, char *out, size_t size_out)
1747 while (*in && size_out > 1)
1751 else if (*in == '/' || *in == '\\' || *in == ':')
1768 void FS_DefaultExtension (char *path, const char *extension, size_t size_path)
1772 // if path doesn't have a .EXT, append extension
1773 // (extension should include the .)
1774 src = path + strlen(path) - 1;
1776 while (*src != '/' && src != path)
1779 return; // it has an extension
1783 strlcat (path, extension, size_path);
1787 qboolean FS_FileExists (const char *filename)
1789 searchpath_t *search;
1790 char netpath[MAX_OSPATH];
1794 for (search = fs_searchpaths;search;search = search->next)
1799 for (i = 0;i < pak->numfiles;i++)
1800 if (!strcmp (pak->files[i].name, filename))
1805 snprintf (netpath, sizeof (netpath), "%s/%s",search->filename, filename);
1806 if (FS_SysFileExists (netpath))
1815 qboolean FS_SysFileExists (const char *path)
1820 f = fopen (path, "rb");
1831 if (stat (path,&buf) == -1)
1838 void FS_mkdir (const char *path)
1851 Allocate and fill a search structure with information on matching filenames.
1854 fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet)
1857 searchpath_t *searchpath;
1859 int i, basepathlength, numfiles, numchars, step;
1860 stringlist_t *dir, *dirfile;
1861 const char *slash, *backslash, *colon, *separator;
1863 char netpath[MAX_OSPATH];
1865 while(!strncmp(pattern, "./", 2))
1867 while(!strncmp(pattern, ".\\", 2))
1873 slash = strrchr(pattern, '/');
1874 backslash = strrchr(pattern, '\\');
1875 colon = strrchr(pattern, ':');
1877 if (separator < backslash)
1878 separator = backslash;
1879 if (separator < colon)
1882 basepathlength = separator + 1 - pattern;
1885 basepath = Z_Malloc(basepathlength + 1);
1887 memcpy(basepath, pattern, basepathlength);
1888 basepath[basepathlength] = 0;
1890 for (step = 0;step < 2;step++)
1892 // search through the path, one element at a time
1893 for (searchpath = fs_searchpaths;searchpath;searchpath = searchpath->next)
1895 // is the element a pak file?
1896 if (searchpath->pack)
1898 // look through all the pak file elements
1899 pak = searchpath->pack;
1900 for (i = 0;i < pak->numfiles;i++)
1902 if (matchpattern(pak->files[i].name, (char *)pattern, caseinsensitive || pak->ignorecase))
1906 search->filenames[numfiles] = search->filenamesbuffer + numchars;
1907 strcpy(search->filenames[numfiles], pak->files[i].name);
1910 numchars += strlen(pak->files[i].name) + 1;
1912 Sys_Printf("SearchPackFile: %s : %s\n", pak->filename, pak->files[i].name);
1918 // get a directory listing and look at each name
1919 snprintf(netpath, sizeof (netpath), "%s/%s", searchpath->filename, pattern);
1920 if ((dir = listdirectory(netpath)))
1922 for (dirfile = dir;dirfile;dirfile = dirfile->next)
1924 if (matchpattern(dirfile->text, (char *)pattern + basepathlength, caseinsensitive || pak->ignorecase))
1928 search->filenames[numfiles] = search->filenamesbuffer + numchars;
1929 memcpy(search->filenames[numfiles], basepath, basepathlength);
1930 strcpy(search->filenames[numfiles] + basepathlength, dirfile->text);
1933 numchars += basepathlength + strlen(dirfile->text) + 1;
1935 Sys_Printf("SearchDirFile: %s\n", dirfile->text);
1945 if (!numfiles || !numchars)
1950 // prepare for second pass (allocate the memory to fill in)
1951 search = Z_Malloc(sizeof(fssearch_t) + numchars + numfiles * sizeof(char *));
1952 search->filenames = (char **)((char *)search + sizeof(fssearch_t));
1953 search->filenamesbuffer = (char *)((char *)search + sizeof(fssearch_t) + numfiles * sizeof(char *));
1954 search->numfilenames = numfiles;
1955 // these are used for tracking as the buffers are written on the second pass
1965 void FS_FreeSearch(fssearch_t *search)
1970 extern int con_linewidth;
1971 int FS_ListDirectory(const char *pattern, int oneperline)
1982 search = FS_Search(pattern, true, false);
1985 numfiles = search->numfilenames;
1988 // FIXME: the names could be added to one column list and then
1989 // gradually shifted into the next column if they fit, and then the
1990 // next to make a compact variable width listing but it's a lot more
1992 // find width for columns
1994 for (i = 0;i < numfiles;i++)
1996 l = strlen(search->filenames[i]);
1997 if (columnwidth < l)
2000 // count the spacing character
2002 // calculate number of columns
2003 numcolumns = con_linewidth / columnwidth;
2004 // don't bother with the column printing if it's only one column
2005 if (numcolumns >= 2)
2007 numlines = (numfiles + numcolumns - 1) / numcolumns;
2008 for (i = 0;i < numlines;i++)
2011 for (k = 0;k < numcolumns;k++)
2013 l = i * numcolumns + k;
2016 name = search->filenames[l];
2017 for (j = 0;name[j] && j < (int)sizeof(linebuf) - 1;j++)
2018 linebuf[linebufpos++] = name[j];
2019 // space out name unless it's the last on the line
2020 if (k < (numcolumns - 1) && l < (numfiles - 1))
2021 for (;j < columnwidth && j < (int)sizeof(linebuf) - 1;j++)
2022 linebuf[linebufpos++] = ' ';
2025 linebuf[linebufpos] = 0;
2026 Con_Printf("%s\n", linebuf);
2033 for (i = 0;i < numfiles;i++)
2034 Con_Printf("%s\n", search->filenames[i]);
2035 FS_FreeSearch(search);
2041 char pattern[MAX_OSPATH];
2044 Con_Printf("usage:\ndir [path/pattern]\n");
2047 if (Cmd_Argc() == 2)
2049 snprintf(pattern, sizeof(pattern), "%s", Cmd_Argv(1));
2050 if (!FS_ListDirectory(pattern, true))
2052 snprintf(pattern, sizeof(pattern), "%s/*", Cmd_Argv(1));
2053 if (!FS_ListDirectory(pattern, true))
2054 Con_Printf("No files found.\n");
2059 if (!FS_ListDirectory("*", true))
2060 Con_Printf("No files found.\n");
2066 char pattern[MAX_OSPATH];
2069 Con_Printf("usage:\ndir [path/pattern]\n");
2072 if (Cmd_Argc() == 2)
2074 snprintf(pattern, sizeof(pattern), "%s", Cmd_Argv(1));
2075 if (!FS_ListDirectory(pattern, false))
2077 snprintf(pattern, sizeof(pattern), "%s/*", Cmd_Argv(1));
2078 FS_ListDirectory(pattern, false);
2082 FS_ListDirectory("*", false);