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;
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)
323 Sys_UnloadLibrary (zlib_dll);
332 Try to load the Zlib DLL
335 qboolean PK3_OpenLibrary (void)
338 const dllfunction_t *func;
345 dllname = "zlib.dll";
351 for (func = zlibfuncs; func && func->name != NULL; func++)
352 *func->funcvariable = NULL;
355 if (! (zlib_dll = Sys_LoadLibrary (dllname)))
357 Con_Printf("Can't find %s. Compressed files support disabled\n", dllname);
361 // Get the function adresses
362 for (func = zlibfuncs; func && func->name != NULL; func++)
363 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (zlib_dll, func->name)))
365 Con_Printf("missing function \"%s\" - broken Zlib library!\n", func->name);
370 Con_Printf("%s loaded. Compressed files support enabled\n", dllname);
377 PK3_GetEndOfCentralDir
379 Extract the end of the central directory from a PK3 package
382 qboolean PK3_GetEndOfCentralDir (const char *packfile, FILE *packhandle, pk3_endOfCentralDir_t *eocd)
384 long filesize, maxsize;
388 // Get the package size
389 fseek (packhandle, 0, SEEK_END);
390 filesize = ftell (packhandle);
391 if (filesize < ZIP_END_CDIR_SIZE)
394 // Load the end of the file in memory
395 if (filesize < ZIP_MAX_COMMENTS_SIZE + ZIP_END_CDIR_SIZE)
398 maxsize = ZIP_MAX_COMMENTS_SIZE + ZIP_END_CDIR_SIZE;
399 buffer = Mem_Alloc (tempmempool, maxsize);
400 fseek (packhandle, filesize - maxsize, SEEK_SET);
401 if (fread (buffer, 1, maxsize, packhandle) != (unsigned long) maxsize)
407 // Look for the end of central dir signature around the end of the file
408 maxsize -= ZIP_END_CDIR_SIZE;
409 ptr = &buffer[maxsize];
411 while (BuffBigLong (ptr) != ZIP_END_HEADER)
423 memcpy (eocd, ptr, ZIP_END_CDIR_SIZE);
424 eocd->signature = LittleLong (eocd->signature);
425 eocd->disknum = LittleShort (eocd->disknum);
426 eocd->cdir_disknum = LittleShort (eocd->cdir_disknum);
427 eocd->localentries = LittleShort (eocd->localentries);
428 eocd->nbentries = LittleShort (eocd->nbentries);
429 eocd->cdir_size = LittleLong (eocd->cdir_size);
430 eocd->cdir_offset = LittleLong (eocd->cdir_offset);
431 eocd->comment_size = LittleShort (eocd->comment_size);
443 Extract the file list from a PK3 file
446 int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd)
448 qbyte *central_dir, *ptr;
452 // Load the central directory in memory
453 central_dir = Mem_Alloc (tempmempool, eocd->cdir_size);
454 fseek (pack->handle, eocd->cdir_offset, SEEK_SET);
455 fread (central_dir, 1, eocd->cdir_size, pack->handle);
457 // Extract the files properties
458 // The parsing is done "by hand" because some fields have variable sizes and
459 // the constant part isn't 4-bytes aligned, which makes the use of structs difficult
460 remaining = eocd->cdir_size;
463 for (ind = 0; ind < eocd->nbentries; ind++)
465 size_t namesize, count;
467 // Checking the remaining size
468 if (remaining < ZIP_CDIR_CHUNK_BASE_SIZE)
470 Mem_Free (central_dir);
473 remaining -= ZIP_CDIR_CHUNK_BASE_SIZE;
476 if (BuffBigLong (ptr) != ZIP_CDIR_HEADER)
478 Mem_Free (central_dir);
482 namesize = BuffLittleShort (&ptr[28]); // filename length
484 // Check encryption, compression, and attributes
485 // 1st uint8 : general purpose bit flag
486 // Check bits 0 (encryption), 3 (data descriptor after the file), and 5 (compressed patched data (?))
487 // 2nd uint8 : external file attributes
488 // Check bits 3 (file is a directory) and 5 (file is a volume (?))
489 if ((ptr[8] & 0x29) == 0 && (ptr[38] & 0x18) == 0)
491 // Still enough bytes for the name?
492 if ((size_t) remaining < namesize || namesize >= sizeof (*pack->files))
494 Mem_Free (central_dir);
498 // WinZip doesn't use the "directory" attribute, so we need to check the name directly
499 if (ptr[ZIP_CDIR_CHUNK_BASE_SIZE + namesize - 1] != '/')
501 char filename [sizeof (pack->files[0].name)];
502 size_t offset, packsize, realsize;
505 // Extract the name (strip it if necessary)
506 if (namesize >= sizeof (filename))
507 namesize = sizeof (filename) - 1;
508 memcpy (filename, &ptr[ZIP_CDIR_CHUNK_BASE_SIZE], namesize);
509 filename[namesize] = '\0';
511 if (BuffLittleShort (&ptr[10]))
512 flags = FILE_FLAG_DEFLATED;
515 offset = BuffLittleLong (&ptr[42]);
516 packsize = BuffLittleLong (&ptr[20]);
517 realsize = BuffLittleLong (&ptr[24]);
518 FS_AddFileToPack (filename, pack, offset, packsize, realsize, flags);
522 // Skip the name, additionnal field, and comment
523 // 1er uint16 : extra field length
524 // 2eme uint16 : file comment length
525 count = namesize + BuffLittleShort (&ptr[30]) + BuffLittleShort (&ptr[32]);
526 ptr += ZIP_CDIR_CHUNK_BASE_SIZE + count;
530 Mem_Free (central_dir);
531 return pack->numfiles;
539 Create a package entry associated with a PK3 file
542 pack_t *FS_LoadPackPK3 (const char *packfile)
545 pk3_endOfCentralDir_t eocd;
549 packhandle = fopen (packfile, "rb");
553 if (! PK3_GetEndOfCentralDir (packfile, packhandle, &eocd))
554 Sys_Error ("%s is not a PK3 file", packfile);
556 // Multi-volume ZIP archives are NOT allowed
557 if (eocd.disknum != 0 || eocd.cdir_disknum != 0)
558 Sys_Error ("%s is a multi-volume ZIP archive", packfile);
560 // We only need to do this test if MAX_FILES_IN_PACK is lesser than 65535
561 // since eocd.nbentries is an unsigned 16 bits integer
562 #if MAX_FILES_IN_PACK < 65535
563 if (eocd.nbentries > MAX_FILES_IN_PACK)
564 Sys_Error ("%s contains too many files (%hu)", packfile, eocd.nbentries);
567 // Create a package structure in memory
568 pack = Mem_Alloc (pak_mempool, sizeof (pack_t));
569 pack->ignorecase = true; // PK3 ignores case
570 strlcpy (pack->filename, packfile, sizeof (pack->filename));
571 pack->handle = packhandle;
572 pack->numfiles = eocd.nbentries;
573 pack->mempool = Mem_AllocPool (packfile);
574 pack->files = Mem_Alloc (pack->mempool, eocd.nbentries * sizeof(packfile_t));
575 pack->next = packlist;
578 real_nb_files = PK3_BuildFileList (pack, &eocd);
579 if (real_nb_files <= 0)
580 Sys_Error ("%s is not a valid PK3 file", packfile);
582 Con_Printf ("Added packfile %s (%i files)\n", packfile, real_nb_files);
589 PK3_GetTrueFileOffset
591 Find where the true file data offset is
594 void PK3_GetTrueFileOffset (packfile_t *file, pack_t *pack)
596 qbyte buffer [ZIP_LOCAL_CHUNK_BASE_SIZE];
600 if (file->flags & FILE_FLAG_TRUEOFFS)
603 // Load the local file description
604 fseek (pack->handle, file->offset, SEEK_SET);
605 count = fread (buffer, 1, ZIP_LOCAL_CHUNK_BASE_SIZE, pack->handle);
606 if (count != ZIP_LOCAL_CHUNK_BASE_SIZE || BuffBigLong (buffer) != ZIP_DATA_HEADER)
607 Sys_Error ("Can't retrieve file %s in package %s", file->name, pack->filename);
609 // Skip name and extra field
610 file->offset += BuffLittleShort (&buffer[26]) + BuffLittleShort (&buffer[28]) + ZIP_LOCAL_CHUNK_BASE_SIZE;
612 file->flags |= FILE_FLAG_TRUEOFFS;
617 =============================================================================
619 OTHER PRIVATE FUNCTIONS
621 =============================================================================
629 Add a file to the list of files contained into a package
631 TODO: do some sorting here to allow faster file searching afterwards
634 static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack,
635 size_t offset, size_t packsize,
636 size_t realsize, file_flags_t flags)
638 packfile_t *file = &pack->files[pack->numfiles++];
640 strlcpy (file->name, name, sizeof (file->name));
641 file->offset = offset;
642 file->packsize = packsize;
643 file->realsize = realsize;
654 Only used for FS_WriteFile.
657 void FS_CreatePath (char *path)
661 for (ofs = path+1 ; *ofs ; ofs++)
663 if (*ofs == '/' || *ofs == '\\')
665 // create the directory
681 void FS_Path_f (void)
685 Con_Printf ("Current search path:\n");
686 for (s=fs_searchpaths ; s ; s=s->next)
690 Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
693 Con_Printf ("%s\n", s->filename);
702 Takes an explicit (not game tree related) path to a pak file.
704 Loads the header and directory, adding the files at the beginning
705 of the list so they override previous pack files.
708 pack_t *FS_LoadPackPAK (const char *packfile)
710 dpackheader_t header;
714 dpackfile_t *info; // temporary alloc, allowing huge pack directories
716 packhandle = fopen (packfile, "rb");
720 fread ((void *)&header, 1, sizeof(header), packhandle);
721 if (memcmp(header.id, "PACK", 4))
722 Sys_Error ("%s is not a packfile", packfile);
723 header.dirofs = LittleLong (header.dirofs);
724 header.dirlen = LittleLong (header.dirlen);
726 if (header.dirlen % sizeof(dpackfile_t))
727 Sys_Error ("%s has an invalid directory size", packfile);
729 numpackfiles = header.dirlen / sizeof(dpackfile_t);
731 if (numpackfiles > MAX_FILES_IN_PACK)
732 Sys_Error ("%s has %i files", packfile, numpackfiles);
734 pack = Mem_Alloc(pak_mempool, sizeof (pack_t));
735 pack->ignorecase = false; // PAK is case sensitive
736 strlcpy (pack->filename, packfile, sizeof (pack->filename));
737 pack->handle = packhandle;
739 pack->mempool = Mem_AllocPool(packfile);
740 pack->files = Mem_Alloc(pack->mempool, numpackfiles * sizeof(packfile_t));
741 pack->next = packlist;
744 info = Mem_Alloc(tempmempool, sizeof(*info) * numpackfiles);
745 fseek (packhandle, header.dirofs, SEEK_SET);
746 fread ((void *)info, 1, header.dirlen, packhandle);
748 // parse the directory
749 for (i = 0;i < numpackfiles;i++)
751 size_t offset = LittleLong (info[i].filepos);
752 size_t size = LittleLong (info[i].filelen);
754 FS_AddFileToPack (info[i].name, pack, offset, size, size, FILE_FLAG_TRUEOFFS);
759 Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
768 Sets fs_gamedir, adds the directory to the head of the path,
769 then loads and adds pak1.pak pak2.pak ...
772 void FS_AddGameDirectory (char *dir)
774 stringlist_t *list, *current;
775 searchpath_t *search;
777 char pakfile[MAX_OSPATH];
779 strlcpy (fs_gamedir, dir, sizeof (fs_gamedir));
782 // add the directory to the search path
783 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
784 strlcpy (search->filename, dir, sizeof (search->filename));
785 search->next = fs_searchpaths;
786 fs_searchpaths = search;
789 list = listdirectory(dir);
791 // add any PAK package in the directory
792 for (current = list;current;current = current->next)
794 if (matchpattern(current->text, "*.pak", true))
796 snprintf (pakfile, sizeof (pakfile), "%s/%s", dir, current->text);
797 pak = FS_LoadPackPAK (pakfile);
800 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
802 search->next = fs_searchpaths;
803 fs_searchpaths = search;
806 Con_Printf("unable to load pak \"%s\"\n", pakfile);
810 // add any PK3 package in the director
811 for (current = list;current;current = current->next)
813 if (matchpattern(current->text, "*.pk3", true))
815 snprintf (pakfile, sizeof (pakfile), "%s/%s", dir, current->text);
816 pak = FS_LoadPackPK3 (pakfile);
819 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
821 search->next = fs_searchpaths;
822 fs_searchpaths = search;
825 Con_Printf("unable to load pak \"%s\"\n", pakfile);
830 // Unpacked files have the priority over packed files in AKVERSION is defined
832 // add the directory to the search path
833 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
834 strlcpy (search->filename, dir, sizeof (search->filename));
835 search->next = fs_searchpaths;
836 fs_searchpaths = search;
846 char *FS_FileExtension (const char *in)
848 static char exten[8];
849 const char *slash, *backslash, *colon, *dot, *separator;
852 slash = strrchr(in, '/');
853 backslash = strrchr(in, '\\');
854 colon = strrchr(in, ':');
855 dot = strrchr(in, '.');
857 if (separator < backslash)
858 separator = backslash;
859 if (separator < colon)
864 for (i = 0;i < 7 && dot[i];i++)
879 searchpath_t *search;
881 fs_mempool = Mem_AllocPool("file management");
882 pak_mempool = Mem_AllocPool("paks");
884 Cmd_AddCommand ("path", FS_Path_f);
885 Cmd_AddCommand ("dir", FS_Dir_f);
886 Cmd_AddCommand ("ls", FS_Ls_f);
888 strcpy(fs_basedir, ".");
893 // Overrides the system supplied base directory (under GAMENAME)
894 i = COM_CheckParm ("-basedir");
895 if (i && i < com_argc-1)
896 strlcpy (fs_basedir, com_argv[i+1], sizeof (fs_basedir));
898 i = strlen (fs_basedir);
899 if (i > 0 && (fs_basedir[i-1] == '\\' || fs_basedir[i-1] == '/'))
902 // start up with GAMENAME by default (id1)
903 strlcpy (com_modname, GAMENAME, sizeof (com_modname));
904 FS_AddGameDirectory (va("%s/"GAMENAME, fs_basedir));
908 strlcpy (com_modname, gamedirname, sizeof (com_modname));
909 FS_AddGameDirectory (va("%s/%s", fs_basedir, gamedirname));
913 // Adds basedir/gamedir as an override game
914 i = COM_CheckParm ("-game");
915 if (i && i < com_argc-1)
918 strlcpy (com_modname, com_argv[i+1], sizeof (com_modname));
919 FS_AddGameDirectory (va("%s/%s", fs_basedir, com_argv[i+1]));
922 // -path <dir or packfile> [<dir or packfile>] ...
923 // Fully specifies the exact search path, overriding the generated one
924 i = COM_CheckParm ("-path");
928 fs_searchpaths = NULL;
929 while (++i < com_argc)
931 if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')
934 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
935 if (!strcasecmp (FS_FileExtension(com_argv[i]), "pak"))
937 search->pack = FS_LoadPackPAK (com_argv[i]);
939 Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
941 else if (!strcasecmp (FS_FileExtension (com_argv[i]), "pk3"))
943 search->pack = FS_LoadPackPK3 (com_argv[i]);
945 Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
948 strlcpy (search->filename, com_argv[i], sizeof (search->filename));
949 search->next = fs_searchpaths;
950 fs_searchpaths = search;
960 Internal function used to create a qfile_t and open the relevant file on disk
963 static qfile_t* FS_SysOpen (const char* filepath, const char* mode)
967 file = Mem_Alloc (fs_mempool, sizeof (*file));
968 memset (file, 0, sizeof (*file));
970 file->stream = fopen (filepath, mode);
986 qfile_t *FS_OpenRead (const char *path, int offs, int len)
990 file = FS_SysOpen (path, "rb");
993 Sys_Error ("Couldn't open %s", path);
998 if (offs < 0 || len < 0)
1000 // We set fs_filesize here for normal files
1001 fseek (file->stream, 0, SEEK_END);
1002 fs_filesize = ftell (file->stream);
1003 fseek (file->stream, 0, SEEK_SET);
1008 fseek (file->stream, offs, SEEK_SET);
1010 file->flags |= FS_FLAG_PACKED;
1012 file->offset = offs;
1023 If the requested file is inside a packfile, a new qfile_t* will be opened
1029 qfile_t *FS_FOpenFile (const char *filename, qboolean quiet)
1031 searchpath_t *search;
1032 char netpath[MAX_OSPATH];
1034 int i, filenamelen, matched;
1036 filenamelen = strlen (filename);
1038 // search through the path, one element at a time
1039 search = fs_searchpaths;
1041 for ( ; search ; search = search->next)
1043 // is the element a pak file?
1046 // look through all the pak file elements
1048 for (i=0 ; i<pak->numfiles ; i++)
1050 if (pak->ignorecase)
1051 matched = !strcasecmp (pak->files[i].name, filename);
1053 matched = !strcmp (pak->files[i].name, filename);
1054 if (matched) // found it?
1059 Sys_Printf ("PackFile: %s : %s\n",pak->filename, pak->files[i].name);
1061 // If we don't have the true offset, get it now
1062 if (! (pak->files[i].flags & FILE_FLAG_TRUEOFFS))
1063 PK3_GetTrueFileOffset (&pak->files[i], pak);
1065 // No Zlib DLL = no compressed files
1066 if (!zlib_dll && (pak->files[i].flags & FILE_FLAG_DEFLATED))
1068 Con_Printf ("WARNING: can't open the compressed file %s\n"
1069 "You need the Zlib DLL to use compressed files\n", filename);
1074 // open a new file in the pakfile
1075 file = FS_OpenRead (pak->filename, pak->files[i].offset, pak->files[i].packsize);
1076 fs_filesize = pak->files[i].realsize;
1078 if (pak->files[i].flags & FILE_FLAG_DEFLATED)
1082 file->flags |= FS_FLAG_DEFLATED;
1084 // We need some more variables
1085 ztk = Mem_Alloc (fs_mempool, sizeof (*file->z));
1087 ztk->real_length = pak->files[i].realsize;
1089 // Initialize zlib stream
1090 ztk->zstream.next_in = ztk->input;
1091 ztk->zstream.avail_in = 0;
1093 /* From Zlib's "unzip.c":
1095 * windowBits is passed < 0 to tell that there is no zlib header.
1096 * Note that in this case inflate *requires* an extra "dummy" byte
1097 * after the compressed stream in order to complete decompression and
1098 * return Z_STREAM_END.
1099 * In unzip, i don't wait absolutely Z_STREAM_END because I known the
1100 * size of both compressed and uncompressed data
1102 if (qz_inflateInit2 (&ztk->zstream, -MAX_WBITS) != Z_OK)
1103 Sys_Error ("inflate init error (file: %s)", filename);
1105 ztk->zstream.next_out = ztk->output;
1106 ztk->zstream.avail_out = sizeof (ztk->output);
1117 snprintf (netpath, sizeof (netpath), "%s/%s",search->filename, filename);
1119 if (!FS_SysFileExists (netpath))
1123 Sys_Printf ("FindFile: %s\n",netpath);
1124 return FS_OpenRead (netpath, -1, -1);
1129 Sys_Printf ("FindFile: can't find %s\n", filename);
1137 =============================================================================
1139 MAIN PUBLIC FUNCTIONS
1141 =============================================================================
1145 ====================
1148 Open a file. The syntax is the same as fopen
1149 ====================
1151 qfile_t* FS_Open (const char* filepath, const char* mode, qboolean quiet)
1153 // If the file is opened in "write" or "append" mode
1154 if (strchr (mode, 'w') || strchr (mode, 'a'))
1156 char real_path [MAX_OSPATH];
1158 // Open the file on disk directly
1159 snprintf (real_path, sizeof (real_path), "%s/%s", fs_gamedir, filepath);
1161 // Create directories up to the file
1162 FS_CreatePath (real_path);
1164 return FS_SysOpen (real_path, mode);
1167 // Else, we look at the various search paths
1168 return FS_FOpenFile (filepath, quiet);
1173 ====================
1177 ====================
1179 int FS_Close (qfile_t* file)
1181 if (fclose (file->stream))
1186 qz_inflateEnd (&file->z->zstream);
1196 ====================
1199 Write "datasize" bytes into a file
1200 ====================
1202 size_t FS_Write (qfile_t* file, const void* data, size_t datasize)
1204 return fwrite (data, 1, datasize, file->stream);
1209 ====================
1212 Read up to "buffersize" bytes from a file
1213 ====================
1215 size_t FS_Read (qfile_t* file, void* buffer, size_t buffersize)
1220 // Quick path for unpacked files
1221 if (! (file->flags & FS_FLAG_PACKED))
1222 return fread (buffer, 1, buffersize, file->stream);
1224 // If the file isn't compressed
1225 if (! (file->flags & FS_FLAG_DEFLATED))
1227 // We must take care to not read after the end of the file
1228 count = file->length - file->position;
1229 if (buffersize > count)
1232 nb = fread (buffer, 1, buffersize, file->stream);
1234 file->position += nb;
1238 // If the file is compressed, it's more complicated...
1241 // First, we copy as many bytes as we can from "output"
1242 if (ztk->out_ind < ztk->out_max)
1244 count = ztk->out_max - ztk->out_ind;
1246 nb = (buffersize > count) ? count : buffersize;
1247 memcpy (buffer, &ztk->output[ztk->out_ind], nb);
1249 file->position += nb;
1254 // We cycle through a few operations until we have inflated enough data
1255 while (nb < buffersize)
1257 // NOTE: at this point, "output" should always be empty
1259 // If "input" is also empty, we need to fill it
1260 if (ztk->in_ind == ztk->in_max)
1262 size_t remain = file->length - ztk->in_position;
1264 // If we are at the end of the file
1268 count = (remain > sizeof (ztk->input)) ? sizeof (ztk->input) : remain;
1269 fread (ztk->input, 1, count, file->stream);
1271 // Update indexes and counters
1273 ztk->in_max = count;
1274 ztk->in_position += count;
1277 // Now that we are sure we have compressed data available, we need to determine
1278 // if it's better to inflate it in "output" or directly in "buffer" (we are in this
1279 // case if we still need more bytes than "output" can contain)
1281 ztk->zstream.next_in = &ztk->input[ztk->in_ind];
1282 ztk->zstream.avail_in = ztk->in_max - ztk->in_ind;
1284 // If output will be able to contain at least 1 more byte than the data we need
1285 if (buffersize - nb < sizeof (ztk->output))
1289 // Inflate the data in "output"
1290 ztk->zstream.next_out = ztk->output;
1291 ztk->zstream.avail_out = sizeof (ztk->output);
1292 error = qz_inflate (&ztk->zstream, Z_SYNC_FLUSH);
1293 if (error != Z_OK && error != Z_STREAM_END)
1294 Sys_Error ("Can't inflate file");
1295 ztk->in_ind = ztk->in_max - ztk->zstream.avail_in;
1296 ztk->out_max = sizeof (ztk->output) - ztk->zstream.avail_out;
1297 ztk->out_position += ztk->out_max;
1299 // Copy the requested data in "buffer" (as much as we can)
1300 count = (buffersize - nb > ztk->out_max) ? ztk->out_max : buffersize - nb;
1301 memcpy (&((qbyte*)buffer)[nb], ztk->output, count);
1302 ztk->out_ind = count;
1305 // Else, we inflate directly in "buffer"
1310 // Inflate the data in "buffer"
1311 ztk->zstream.next_out = &((qbyte*)buffer)[nb];
1312 ztk->zstream.avail_out = buffersize - nb;
1313 error = qz_inflate (&ztk->zstream, Z_SYNC_FLUSH);
1314 if (error != Z_OK && error != Z_STREAM_END)
1315 Sys_Error ("Can't inflate file");
1316 ztk->in_ind = ztk->in_max - ztk->zstream.avail_in;
1318 // Invalidate the output data (for FS_Seek)
1322 // How much data did it inflate?
1323 count = buffersize - nb - ztk->zstream.avail_out;
1324 ztk->out_position += count;
1328 file->position += count;
1336 ====================
1339 Flush the file output stream
1340 ====================
1342 int FS_Flush (qfile_t* file)
1344 return fflush (file->stream);
1349 ====================
1352 Print a string into a file
1353 ====================
1355 int FS_Printf (qfile_t* file, const char* format, ...)
1360 va_start (args, format);
1361 result = vfprintf (file->stream, format, args);
1369 ====================
1372 Get the next character of a file
1373 ====================
1375 int FS_Getc (qfile_t* file)
1379 if (FS_Read (file, &c, 1) != 1)
1387 ====================
1390 Move the position index in a file
1391 ====================
1393 int FS_Seek (qfile_t* file, long offset, int whence)
1395 // Quick path for unpacked files
1396 if (! (file->flags & FS_FLAG_PACKED))
1397 return fseek (file->stream, offset, whence);
1399 // Seeking in compressed files is more a hack than anything else,
1400 // but we need to support it, so here it is.
1401 if (file->flags & FS_FLAG_DEFLATED)
1403 ztoolkit_t *ztk = file->z;
1404 qbyte buffer [sizeof (ztk->output)]; // it's big to force inflating into buffer directly
1409 offset += file->position;
1416 offset += ztk->real_length;
1422 if (offset < 0 || offset > (long) ztk->real_length)
1425 // If we need to go back in the file
1426 if (offset <= (long) file->position)
1428 // If we still have the data we need in the output buffer
1429 if (file->position - offset <= ztk->out_ind)
1431 ztk->out_ind -= file->position - offset;
1432 file->position = offset;
1436 // Else, we restart from the beginning of the file
1439 ztk->in_position = 0;
1442 ztk->out_position = 0;
1444 fseek (file->stream, file->offset, SEEK_SET);
1446 // Reset the Zlib stream
1447 ztk->zstream.next_in = ztk->input;
1448 ztk->zstream.avail_in = 0;
1449 qz_inflateReset (&ztk->zstream);
1452 // Skip all data until we reach the requested offset
1453 while ((long) file->position < offset)
1455 size_t diff = offset - file->position;
1458 count = (diff > sizeof (buffer)) ? sizeof (buffer) : diff;
1459 len = FS_Read (file, buffer, count);
1467 // Packed files receive a special treatment too, because
1468 // we need to make sure it doesn't go outside of the file
1472 offset += file->position;
1479 offset += file->length;
1485 if (offset < 0 || offset > (long) file->length)
1488 if (fseek (file->stream, file->offset + offset, SEEK_SET) == -1)
1490 file->position = offset;
1496 ====================
1499 Give the current position in a file
1500 ====================
1502 long FS_Tell (qfile_t* file)
1504 if (file->flags & FS_FLAG_PACKED)
1505 return file->position;
1507 return ftell (file->stream);
1512 ====================
1515 Extract a line from a file
1516 ====================
1518 char* FS_Gets (qfile_t* file, char* buffer, int buffersize)
1522 // Quick path for unpacked files
1523 if (! (file->flags & FS_FLAG_PACKED))
1524 return fgets (buffer, buffersize, file->stream);
1526 for (ind = 0; ind < (size_t) buffersize - 1; ind++)
1528 int c = FS_Getc (file);
1543 buffer[ind + 1] = '\0';
1552 buffer[buffersize - 1] = '\0';
1561 Dynamic length version of fgets. DO NOT free the buffer.
1564 char *FS_Getline (qfile_t *file)
1566 static int size = 256;
1567 static char *buf = 0;
1572 buf = Mem_Alloc (fs_mempool, size);
1574 if (!FS_Gets (file, buf, size))
1578 while (buf[len - 1] != '\n' && buf[len - 1] != '\r')
1580 t = Mem_Alloc (fs_mempool, size + 256);
1581 memcpy(t, buf, size);
1585 if (!FS_Gets (file, buf + len, size - len))
1589 while ((len = strlen(buf)) && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
1596 ====================
1599 Extract a line from a file
1600 ====================
1602 int FS_Eof (qfile_t* file)
1604 if (file->flags & FS_FLAG_PACKED)
1606 if (file->flags & FS_FLAG_DEFLATED)
1607 return (file->position == file->z->real_length);
1609 return (file->position == file->length);
1612 return feof (file->stream);
1620 Filename are relative to the quake directory.
1621 Always appends a 0 byte.
1624 qbyte *FS_LoadFile (const char *path, qboolean quiet)
1629 // look for it in the filesystem or pack files
1630 h = FS_Open (path, "rb", quiet);
1634 buf = Mem_Alloc(tempmempool, fs_filesize+1);
1636 Sys_Error ("FS_LoadFile: not enough available memory for %s (size %i)", path, fs_filesize);
1638 ((qbyte *)buf)[fs_filesize] = 0;
1640 FS_Read (h, buf, fs_filesize);
1651 The filename will be prefixed by the current game directory
1654 qboolean FS_WriteFile (const char *filename, void *data, int len)
1657 char name[MAX_OSPATH];
1659 snprintf (name, sizeof (name), "%s/%s", fs_gamedir, filename);
1661 // Create directories up to the file
1662 FS_CreatePath (name);
1664 handle = fopen (name, "wb");
1667 Con_Printf ("FS_WriteFile: failed on %s\n", name);
1671 Con_DPrintf ("FS_WriteFile: %s\n", name);
1672 fwrite (data, 1, len, handle);
1679 =============================================================================
1681 OTHERS PUBLIC FUNCTIONS
1683 =============================================================================
1691 void FS_StripExtension (const char *in, char *out, size_t size_out)
1698 while (*in && size_out > 1)
1702 else if (*in == '/' || *in == '\\' || *in == ':')
1719 void FS_DefaultExtension (char *path, const char *extension, size_t size_path)
1723 // if path doesn't have a .EXT, append extension
1724 // (extension should include the .)
1725 src = path + strlen(path) - 1;
1727 while (*src != '/' && src != path)
1730 return; // it has an extension
1734 strlcat (path, extension, size_path);
1738 qboolean FS_FileExists (const char *filename)
1740 searchpath_t *search;
1741 char netpath[MAX_OSPATH];
1745 for (search = fs_searchpaths;search;search = search->next)
1750 for (i = 0;i < pak->numfiles;i++)
1751 if (!strcmp (pak->files[i].name, filename))
1756 snprintf (netpath, sizeof (netpath), "%s/%s",search->filename, filename);
1757 if (FS_SysFileExists (netpath))
1766 qboolean FS_SysFileExists (const char *path)
1771 f = fopen (path, "rb");
1782 if (stat (path,&buf) == -1)
1789 void FS_mkdir (const char *path)
1802 Allocate and fill a search structure with information on matching filenames.
1805 fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet)
1808 searchpath_t *searchpath;
1810 int i, basepathlength, numfiles, numchars;
1811 stringlist_t *dir, *dirfile, *liststart, *listcurrent, *listtemp;
1812 const char *slash, *backslash, *colon, *separator;
1814 char netpath[MAX_OSPATH];
1815 char temp[MAX_OSPATH];
1817 while(!strncmp(pattern, "./", 2))
1819 while(!strncmp(pattern, ".\\", 2))
1826 slash = strrchr(pattern, '/');
1827 backslash = strrchr(pattern, '\\');
1828 colon = strrchr(pattern, ':');
1829 separator = pattern;
1830 if (separator < slash)
1832 if (separator < backslash)
1833 separator = backslash;
1834 if (separator < colon)
1836 basepathlength = separator - pattern;
1837 basepath = Z_Malloc(basepathlength + 1);
1839 memcpy(basepath, pattern, basepathlength);
1840 basepath[basepathlength] = 0;
1842 // search through the path, one element at a time
1843 for (searchpath = fs_searchpaths;searchpath;searchpath = searchpath->next)
1845 // is the element a pak file?
1846 if (searchpath->pack)
1848 // look through all the pak file elements
1849 pak = searchpath->pack;
1850 for (i = 0;i < pak->numfiles;i++)
1852 strcpy(temp, pak->files[i].name);
1855 if (matchpattern(temp, (char *)pattern, true))
1857 for (listtemp = liststart;listtemp;listtemp = listtemp->next)
1858 if (!strcmp(listtemp->text, temp))
1860 if (listtemp == NULL)
1862 listcurrent = stringlistappend(listcurrent, temp);
1863 if (liststart == NULL)
1864 liststart = listcurrent;
1866 Sys_Printf("SearchPackFile: %s : %s\n", pak->filename, temp);
1869 // strip off one path element at a time until empty
1870 // this way directories are added to the listing if they match the pattern
1871 slash = strrchr(temp, '/');
1872 backslash = strrchr(temp, '\\');
1873 colon = strrchr(temp, ':');
1875 if (separator < slash)
1877 if (separator < backslash)
1878 separator = backslash;
1879 if (separator < colon)
1881 *((char *)separator) = 0;
1887 // get a directory listing and look at each name
1888 snprintf(netpath, sizeof (netpath), "%s/%s", searchpath->filename, basepath);
1889 if ((dir = listdirectory(netpath)))
1891 for (dirfile = dir;dirfile;dirfile = dirfile->next)
1893 snprintf(temp, sizeof(temp), "%s/%s", basepath, dirfile->text);
1894 if (matchpattern(temp, (char *)pattern, true))
1896 for (listtemp = liststart;listtemp;listtemp = listtemp->next)
1897 if (!strcmp(listtemp->text, temp))
1899 if (listtemp == NULL)
1901 listcurrent = stringlistappend(listcurrent, temp);
1902 if (liststart == NULL)
1903 liststart = listcurrent;
1905 Sys_Printf("SearchDirFile: %s\n", temp);
1916 liststart = stringlistsort(liststart);
1919 for (listtemp = liststart;listtemp;listtemp = listtemp->next)
1922 numchars += strlen(listtemp->text) + 1;
1924 search = Z_Malloc(sizeof(fssearch_t) + numchars + numfiles * sizeof(char *));
1925 search->filenames = (char **)((char *)search + sizeof(fssearch_t));
1926 search->filenamesbuffer = (char *)((char *)search + sizeof(fssearch_t) + numfiles * sizeof(char *));
1927 search->numfilenames = numfiles;
1930 for (listtemp = liststart;listtemp;listtemp = listtemp->next)
1932 search->filenames[numfiles] = search->filenamesbuffer + numchars;
1933 strcpy(search->filenames[numfiles], listtemp->text);
1935 numchars += strlen(listtemp->text) + 1;
1938 stringlistfree(liststart);
1945 void FS_FreeSearch(fssearch_t *search)
1950 extern int con_linewidth;
1951 int FS_ListDirectory(const char *pattern, int oneperline)
1962 search = FS_Search(pattern, true, false);
1965 numfiles = search->numfilenames;
1968 // FIXME: the names could be added to one column list and then
1969 // gradually shifted into the next column if they fit, and then the
1970 // next to make a compact variable width listing but it's a lot more
1972 // find width for columns
1974 for (i = 0;i < numfiles;i++)
1976 l = strlen(search->filenames[i]);
1977 if (columnwidth < l)
1980 // count the spacing character
1982 // calculate number of columns
1983 numcolumns = con_linewidth / columnwidth;
1984 // don't bother with the column printing if it's only one column
1985 if (numcolumns >= 2)
1987 numlines = (numfiles + numcolumns - 1) / numcolumns;
1988 for (i = 0;i < numlines;i++)
1991 for (k = 0;k < numcolumns;k++)
1993 l = i * numcolumns + k;
1996 name = search->filenames[l];
1997 for (j = 0;name[j] && j < (int)sizeof(linebuf) - 1;j++)
1998 linebuf[linebufpos++] = name[j];
1999 // space out name unless it's the last on the line
2000 if (k < (numcolumns - 1) && l < (numfiles - 1))
2001 for (;j < columnwidth && j < (int)sizeof(linebuf) - 1;j++)
2002 linebuf[linebufpos++] = ' ';
2005 linebuf[linebufpos] = 0;
2006 Con_Printf("%s\n", linebuf);
2013 for (i = 0;i < numfiles;i++)
2014 Con_Printf("%s\n", search->filenames[i]);
2015 FS_FreeSearch(search);
2019 static void FS_ListDirectoryCmd (const char* cmdname, int oneperline)
2021 char pattern[MAX_OSPATH];
2024 Con_Printf("usage:\n%s [path/pattern]\n", cmdname);
2027 if (Cmd_Argc() == 2)
2028 snprintf(pattern, sizeof(pattern), "%s", Cmd_Argv(1));
2030 strcpy(pattern, "*");
2031 if (!FS_ListDirectory(pattern, oneperline))
2032 Con_Printf("No files found.\n");
2037 FS_ListDirectoryCmd("dir", true);
2042 FS_ListDirectoryCmd("ls", false);