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
36 # include <sys/stat.h>
49 All of Quake's data access is through a hierchal file system, but the contents
50 of the file system can be transparently merged from several sources.
52 The "base directory" is the path to the directory holding the quake.exe and
53 all game directories. The sys_* files pass this to host_init in
54 quakeparms_t->basedir. This can be overridden with the "-basedir" command
55 line parm to allow code debugging in a different directory. The base
56 directory is only used during filesystem initialization.
58 The "game directory" is the first tree on the search path and directory that
59 all generated files (savegames, screenshots, demos, config files) will be
60 saved to. This can be overridden with the "-game" command line parameter.
61 The game directory can never be changed while quake is executing. This is a
62 precacution against having a malicious server instruct clients to write files
63 over areas they shouldn't.
69 =============================================================================
73 =============================================================================
76 // Magic numbers of a ZIP file (big-endian format)
77 #define ZIP_DATA_HEADER 0x504B0304 // "PK\3\4"
78 #define ZIP_CDIR_HEADER 0x504B0102 // "PK\1\2"
79 #define ZIP_END_HEADER 0x504B0506 // "PK\5\6"
81 // Other constants for ZIP files
82 #define ZIP_MAX_COMMENTS_SIZE ((unsigned short)0xFFFF)
83 #define ZIP_END_CDIR_SIZE 22
84 #define ZIP_CDIR_CHUNK_BASE_SIZE 46
85 #define ZIP_LOCAL_CHUNK_BASE_SIZE 30
87 // Zlib constants (from zlib.h)
88 #define Z_SYNC_FLUSH 2
91 #define Z_STREAM_END 1
92 #define ZLIB_VERSION "1.1.4"
96 =============================================================================
100 =============================================================================
103 // Zlib stream (from zlib.h)
104 // Warning: some pointers we don't use directly have
105 // been cast to "void*" for a matter of simplicity
108 qbyte *next_in; // next input byte
109 unsigned int avail_in; // number of bytes available at next_in
110 unsigned long total_in; // total nb of input bytes read so far
112 qbyte *next_out; // next output byte should be put there
113 unsigned int avail_out; // remaining free space at next_out
114 unsigned long total_out; // total nb of bytes output so far
116 char *msg; // last error message, NULL if no error
117 void *state; // not visible by applications
119 void *zalloc; // used to allocate the internal state
120 void *zfree; // used to free the internal state
121 void *opaque; // private data object passed to zalloc and zfree
123 int data_type; // best guess about the data type: ascii or binary
124 unsigned long adler; // adler32 value of the uncompressed data
125 unsigned long reserved; // reserved for future use
129 // Our own file structure on top of FILE
133 FS_FLAG_PACKED = (1 << 0), // inside a package (PAK or PK3)
134 FS_FLAG_DEFLATED = (1 << 1) // file is compressed using the deflate algorithm (PK3 only)
137 #define ZBUFF_SIZE 1024
141 size_t real_length; // length of the uncompressed file
142 size_t in_ind, in_max; // input buffer index and counter
143 size_t in_position; // position in the compressed file
144 size_t out_ind, out_max; // output buffer index and counter
145 size_t out_position; // how many bytes did we uncompress until now?
146 qbyte input [ZBUFF_SIZE];
147 qbyte output [ZBUFF_SIZE];
154 size_t length; // file size on disk (PACKED only)
155 size_t offset; // offset into a package (PACKED only)
156 size_t position; // current position in the file (PACKED only)
157 ztoolkit_t* z; // used for inflating (DEFLATED only)
161 // ------ PK3 files on disk ------ //
163 // You can get the complete ZIP format description from PKWARE website
167 unsigned int signature;
168 unsigned short disknum;
169 unsigned short cdir_disknum; // number of the disk with the start of the central directory
170 unsigned short localentries; // number of entries in the central directory on this disk
171 unsigned short nbentries; // total number of entries in the central directory on this disk
172 unsigned int cdir_size; // size of the central directory
173 unsigned int cdir_offset; // with respect to the starting disk number
174 unsigned short comment_size;
175 } pk3_endOfCentralDir_t;
178 // ------ PAK files on disk ------ //
182 int filepos, filelen;
193 // Packages in memory
197 FILE_FLAG_TRUEOFFS = (1 << 0), // the offset in packfile_t is the true contents offset
198 FILE_FLAG_DEFLATED = (1 << 1) // file compressed using the deflate algorithm
203 char name [MAX_QPATH];
206 size_t packsize; // size in the package
207 size_t realsize; // real file size (uncompressed)
210 typedef struct pack_s
212 char filename [MAX_OSPATH];
214 int ignorecase; // PK3 ignores case
222 // Search paths for files (including packages)
223 typedef struct searchpath_s
225 // only one of filename / pack will be used
226 char filename[MAX_OSPATH];
228 struct searchpath_s *next;
233 =============================================================================
237 =============================================================================
243 static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack,
244 size_t offset, size_t packsize,
245 size_t realsize, file_flags_t flags);
249 =============================================================================
253 =============================================================================
256 mempool_t *fs_mempool;
257 mempool_t *pak_mempool;
261 pack_t *packlist = NULL;
263 searchpath_t *fs_searchpaths = NULL;
265 #define MAX_FILES_IN_PACK 65536
267 char fs_gamedir[MAX_OSPATH];
268 char fs_basedir[MAX_OSPATH];
270 qboolean fs_modified; // set true if using non-id files
274 =============================================================================
276 PRIVATE FUNCTIONS - PK3 HANDLING
278 =============================================================================
281 // Functions exported from zlib
283 # define ZEXPORT WINAPI
288 static int (ZEXPORT *qz_inflate) (z_stream* strm, int flush);
289 static int (ZEXPORT *qz_inflateEnd) (z_stream* strm);
290 static int (ZEXPORT *qz_inflateInit2_) (z_stream* strm, int windowBits, const char *version, int stream_size);
291 static int (ZEXPORT *qz_inflateReset) (z_stream* strm);
293 #define qz_inflateInit2(strm, windowBits) \
294 qz_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
296 static dllfunction_t zlibfuncs[] =
298 {"inflate", (void **) &qz_inflate},
299 {"inflateEnd", (void **) &qz_inflateEnd},
300 {"inflateInit2_", (void **) &qz_inflateInit2_},
301 {"inflateReset", (void **) &qz_inflateReset},
305 // Handle for Zlib DLL
306 static dllhandle_t zlib_dll = NULL;
316 void PK3_CloseLibrary (void)
318 Sys_UnloadLibrary (&zlib_dll);
326 Try to load the Zlib DLL
329 qboolean PK3_OpenLibrary (void)
338 dllname = "zlib.dll";
344 if (! Sys_LoadLibrary (dllname, &zlib_dll, zlibfuncs))
346 Con_Printf ("Compressed files support disabled\n");
350 Con_Printf ("Compressed files support enabled\n");
357 PK3_GetEndOfCentralDir
359 Extract the end of the central directory from a PK3 package
362 qboolean PK3_GetEndOfCentralDir (const char *packfile, FILE *packhandle, pk3_endOfCentralDir_t *eocd)
364 long filesize, maxsize;
368 // Get the package size
369 fseek (packhandle, 0, SEEK_END);
370 filesize = ftell (packhandle);
371 if (filesize < ZIP_END_CDIR_SIZE)
374 // Load the end of the file in memory
375 if (filesize < ZIP_MAX_COMMENTS_SIZE + ZIP_END_CDIR_SIZE)
378 maxsize = ZIP_MAX_COMMENTS_SIZE + ZIP_END_CDIR_SIZE;
379 buffer = Mem_Alloc (tempmempool, maxsize);
380 fseek (packhandle, filesize - maxsize, SEEK_SET);
381 if (fread (buffer, 1, maxsize, packhandle) != (unsigned long) maxsize)
387 // Look for the end of central dir signature around the end of the file
388 maxsize -= ZIP_END_CDIR_SIZE;
389 ptr = &buffer[maxsize];
391 while (BuffBigLong (ptr) != ZIP_END_HEADER)
403 memcpy (eocd, ptr, ZIP_END_CDIR_SIZE);
404 eocd->signature = LittleLong (eocd->signature);
405 eocd->disknum = LittleShort (eocd->disknum);
406 eocd->cdir_disknum = LittleShort (eocd->cdir_disknum);
407 eocd->localentries = LittleShort (eocd->localentries);
408 eocd->nbentries = LittleShort (eocd->nbentries);
409 eocd->cdir_size = LittleLong (eocd->cdir_size);
410 eocd->cdir_offset = LittleLong (eocd->cdir_offset);
411 eocd->comment_size = LittleShort (eocd->comment_size);
423 Extract the file list from a PK3 file
426 int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd)
428 qbyte *central_dir, *ptr;
432 // Load the central directory in memory
433 central_dir = Mem_Alloc (tempmempool, eocd->cdir_size);
434 fseek (pack->handle, eocd->cdir_offset, SEEK_SET);
435 fread (central_dir, 1, eocd->cdir_size, pack->handle);
437 // Extract the files properties
438 // The parsing is done "by hand" because some fields have variable sizes and
439 // the constant part isn't 4-bytes aligned, which makes the use of structs difficult
440 remaining = eocd->cdir_size;
443 for (ind = 0; ind < eocd->nbentries; ind++)
445 size_t namesize, count;
447 // Checking the remaining size
448 if (remaining < ZIP_CDIR_CHUNK_BASE_SIZE)
450 Mem_Free (central_dir);
453 remaining -= ZIP_CDIR_CHUNK_BASE_SIZE;
456 if (BuffBigLong (ptr) != ZIP_CDIR_HEADER)
458 Mem_Free (central_dir);
462 namesize = BuffLittleShort (&ptr[28]); // filename length
464 // Check encryption, compression, and attributes
465 // 1st uint8 : general purpose bit flag
466 // Check bits 0 (encryption), 3 (data descriptor after the file), and 5 (compressed patched data (?))
467 // 2nd uint8 : external file attributes
468 // Check bits 3 (file is a directory) and 5 (file is a volume (?))
469 if ((ptr[8] & 0x29) == 0 && (ptr[38] & 0x18) == 0)
471 // Still enough bytes for the name?
472 if ((size_t) remaining < namesize || namesize >= sizeof (*pack->files))
474 Mem_Free (central_dir);
478 // WinZip doesn't use the "directory" attribute, so we need to check the name directly
479 if (ptr[ZIP_CDIR_CHUNK_BASE_SIZE + namesize - 1] != '/')
481 char filename [sizeof (pack->files[0].name)];
482 size_t offset, packsize, realsize;
485 // Extract the name (strip it if necessary)
486 if (namesize >= sizeof (filename))
487 namesize = sizeof (filename) - 1;
488 memcpy (filename, &ptr[ZIP_CDIR_CHUNK_BASE_SIZE], namesize);
489 filename[namesize] = '\0';
491 if (BuffLittleShort (&ptr[10]))
492 flags = FILE_FLAG_DEFLATED;
495 offset = BuffLittleLong (&ptr[42]);
496 packsize = BuffLittleLong (&ptr[20]);
497 realsize = BuffLittleLong (&ptr[24]);
498 FS_AddFileToPack (filename, pack, offset, packsize, realsize, flags);
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, 0, NULL);
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 Add a file to the list of files contained into a package
612 static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack,
613 size_t offset, size_t packsize,
614 size_t realsize, file_flags_t flags)
616 int (*strcmp_funct) (const char* str1, const char* str2);
617 size_t left, right, middle;
621 strcmp_funct = pack->ignorecase ? strcasecmp : strcmp;
623 // Look for the slot we should put that file into (binary search)
625 right = pack->numfiles;
626 while (left != right)
628 middle = (left + right - 1) / 2;
629 diff = strcmp_funct (pack->files[middle].name, name);
631 // If we found the file, there's a problem
633 Sys_Error ("Package %s contains several time the file %s\n",
634 pack->filename, name);
636 // If we're too far in the list
643 // We have to move the right of the list by one slot to free the one we need
644 file = &pack->files[left];
645 memmove (file + 1, file, (pack->numfiles - left) * sizeof (*file));
648 strlcpy (file->name, name, sizeof (file->name));
649 file->offset = offset;
650 file->packsize = packsize;
651 file->realsize = realsize;
662 Only used for FS_Open.
665 void FS_CreatePath (char *path)
669 for (ofs = path+1 ; *ofs ; ofs++)
671 if (*ofs == '/' || *ofs == '\\')
673 // create the directory
689 void FS_Path_f (void)
693 Con_Print("Current search path:\n");
694 for (s=fs_searchpaths ; s ; s=s->next)
698 Con_Printf("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
701 Con_Printf("%s\n", s->filename);
710 Takes an explicit (not game tree related) path to a pak file.
712 Loads the header and directory, adding the files at the beginning
713 of the list so they override previous pack files.
716 pack_t *FS_LoadPackPAK (const char *packfile)
718 dpackheader_t header;
722 dpackfile_t *info; // temporary alloc, allowing huge pack directories
724 packhandle = fopen (packfile, "rb");
728 fread ((void *)&header, 1, sizeof(header), packhandle);
729 if (memcmp(header.id, "PACK", 4))
730 Sys_Error ("%s is not a packfile", packfile);
731 header.dirofs = LittleLong (header.dirofs);
732 header.dirlen = LittleLong (header.dirlen);
734 if (header.dirlen % sizeof(dpackfile_t))
735 Sys_Error ("%s has an invalid directory size", packfile);
737 numpackfiles = header.dirlen / sizeof(dpackfile_t);
739 if (numpackfiles > MAX_FILES_IN_PACK)
740 Sys_Error ("%s has %i files", packfile, numpackfiles);
742 pack = Mem_Alloc(pak_mempool, sizeof (pack_t));
743 pack->ignorecase = false; // PAK is case sensitive
744 strlcpy (pack->filename, packfile, sizeof (pack->filename));
745 pack->handle = packhandle;
747 pack->mempool = Mem_AllocPool(packfile, 0, NULL);
748 pack->files = Mem_Alloc(pack->mempool, numpackfiles * sizeof(packfile_t));
749 pack->next = packlist;
752 info = Mem_Alloc(tempmempool, sizeof(*info) * numpackfiles);
753 fseek (packhandle, header.dirofs, SEEK_SET);
754 fread ((void *)info, 1, header.dirlen, packhandle);
756 // parse the directory
757 for (i = 0;i < numpackfiles;i++)
759 size_t offset = LittleLong (info[i].filepos);
760 size_t size = LittleLong (info[i].filelen);
762 FS_AddFileToPack (info[i].name, pack, offset, size, size, FILE_FLAG_TRUEOFFS);
767 Con_Printf("Added packfile %s (%i files)\n", packfile, numpackfiles);
776 Sets fs_gamedir, adds the directory to the head of the path,
777 then loads and adds pak1.pak pak2.pak ...
780 void FS_AddGameDirectory (char *dir)
782 stringlist_t *list, *current;
783 searchpath_t *search;
785 char pakfile[MAX_OSPATH];
787 strlcpy (fs_gamedir, dir, sizeof (fs_gamedir));
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 // Add the directory to the search path
831 // (unpacked files have the priority over packed files)
832 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
833 strlcpy (search->filename, dir, sizeof (search->filename));
834 search->next = fs_searchpaths;
835 fs_searchpaths = search;
844 char *FS_FileExtension (const char *in)
846 static char exten[8];
847 const char *slash, *backslash, *colon, *dot, *separator;
850 slash = strrchr(in, '/');
851 backslash = strrchr(in, '\\');
852 colon = strrchr(in, ':');
853 dot = strrchr(in, '.');
855 if (separator < backslash)
856 separator = backslash;
857 if (separator < colon)
859 if (dot == NULL || dot < separator)
862 for (i = 0;i < 7 && dot[i];i++)
877 searchpath_t *search;
879 fs_mempool = Mem_AllocPool("file management", 0, NULL);
880 pak_mempool = Mem_AllocPool("paks", 0, NULL);
882 Cvar_RegisterVariable (&scr_screenshot_name);
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, ".");
889 strcpy(fs_gamedir, ".");
894 // Overrides the system supplied base directory (under GAMENAME)
895 // COMMANDLINEOPTION: Filesystem: -basedir <path> chooses what base directory the game data is in, inside this there should be a data directory for the game (for example id1)
896 i = COM_CheckParm ("-basedir");
897 if (i && i < com_argc-1)
899 strlcpy (fs_basedir, com_argv[i+1], sizeof (fs_basedir));
900 i = strlen (fs_basedir);
901 if (i > 0 && (fs_basedir[i-1] == '\\' || fs_basedir[i-1] == '/'))
905 // -path <dir or packfile> [<dir or packfile>] ...
906 // Fully specifies the exact search path, overriding the generated one
907 // COMMANDLINEOPTION: Filesystem: -path <path ..> specifies the full search path manually, overriding the generated one, example: -path c:\quake\id1 c:\quake\pak0.pak c:\quake\pak1.pak (not recommended)
908 i = COM_CheckParm ("-path");
912 while (++i < com_argc)
914 if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')
917 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
918 if (!strcasecmp (FS_FileExtension(com_argv[i]), "pak"))
920 search->pack = FS_LoadPackPAK (com_argv[i]);
922 Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
924 else if (!strcasecmp (FS_FileExtension (com_argv[i]), "pk3"))
926 search->pack = FS_LoadPackPK3 (com_argv[i]);
928 Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
931 strlcpy (search->filename, com_argv[i], sizeof (search->filename));
932 search->next = fs_searchpaths;
933 fs_searchpaths = search;
938 // start up with GAMENAME by default (id1)
939 strlcpy (com_modname, GAMENAME, sizeof (com_modname));
940 FS_AddGameDirectory (va("%s/"GAMENAME, fs_basedir));
941 Cvar_SetQuick (&scr_screenshot_name, gamescreenshotname);
943 // add the game-specific path, if any
947 strlcpy (com_modname, gamedirname, sizeof (com_modname));
948 FS_AddGameDirectory (va("%s/%s", fs_basedir, gamedirname));
952 // Adds basedir/gamedir as an override game
953 // LordHavoc: now supports multiple -game directories
954 for (i = 1;i < com_argc;i++)
958 if (!strcmp (com_argv[i], "-game") && i < com_argc-1)
962 strlcpy (com_modname, com_argv[i], sizeof (com_modname));
963 FS_AddGameDirectory (va("%s/%s", fs_basedir, com_argv[i]));
964 Cvar_SetQuick (&scr_screenshot_name, com_modname);
974 Internal function used to create a qfile_t and open the relevant file on disk
977 static qfile_t* FS_SysOpen (const char* filepath, const char* mode)
981 file = Mem_Alloc (fs_mempool, sizeof (*file));
982 memset (file, 0, sizeof (*file));
984 file->stream = fopen (filepath, mode);
1000 qfile_t *FS_OpenRead (const char *path, int offs, int len)
1004 file = FS_SysOpen (path, "rb");
1007 Sys_Error ("Couldn't open %s", path);
1012 if (offs < 0 || len < 0)
1014 // We set fs_filesize here for normal files
1015 fseek (file->stream, 0, SEEK_END);
1016 fs_filesize = ftell (file->stream);
1017 fseek (file->stream, 0, SEEK_SET);
1022 fseek (file->stream, offs, SEEK_SET);
1024 file->flags |= FS_FLAG_PACKED;
1026 file->offset = offs;
1035 ====================
1038 Look for a file in the packages and in the filesystem
1040 Return the searchpath where the file was found (or NULL)
1041 and the file index in the package if relevant
1042 ====================
1044 static searchpath_t *FS_FindFile (const char *name, int* index, qboolean quiet)
1046 searchpath_t *search;
1048 int (*strcmp_funct) (const char* str1, const char* str2);
1050 // search through the path, one element at a time
1051 for (search = fs_searchpaths;search;search = search->next)
1053 // is the element a pak file?
1056 size_t left, right, middle;
1059 strcmp_funct = pak->ignorecase ? strcasecmp : strcmp;
1061 // Look for the file (binary search)
1063 right = pak->numfiles;
1064 while (left != right)
1068 middle = (left + right - 1) / 2;
1069 diff = strcmp_funct (pak->files[middle].name, name);
1075 Sys_Printf("FS_FindFile: %s in %s\n",
1076 pak->files[middle].name, pak->filename);
1083 // If we're too far in the list
1092 char netpath[MAX_OSPATH];
1093 snprintf(netpath, sizeof(netpath), "%s/%s", search->filename, name);
1094 if (FS_SysFileExists (netpath))
1097 Sys_Printf("FS_FindFile: %s\n", netpath);
1107 Sys_Printf("FS_FindFile: can't find %s\n", name);
1119 If the requested file is inside a packfile, a new qfile_t* will be opened
1125 qfile_t *FS_FOpenFile (const char *filename, qboolean quiet)
1127 searchpath_t *search;
1128 packfile_t *packfile;
1132 search = FS_FindFile (filename, &i, quiet);
1141 // Found in the filesystem?
1144 char netpath[MAX_OSPATH];
1145 snprintf(netpath, sizeof(netpath), "%s/%s", search->filename, filename);
1146 return FS_OpenRead(netpath, -1, -1);
1149 // So, we found it in a package...
1150 packfile = &search->pack->files[i];
1152 // If we don't have the true offset, get it now
1153 if (! (packfile->flags & FILE_FLAG_TRUEOFFS))
1154 PK3_GetTrueFileOffset (packfile, search->pack);
1156 // No Zlib DLL = no compressed files
1157 if (!zlib_dll && (packfile->flags & FILE_FLAG_DEFLATED))
1159 Con_Printf("WARNING: can't open the compressed file %s\n"
1160 "You need the Zlib DLL to use compressed files\n",
1166 // open a new file in the pakfile
1167 file = FS_OpenRead (search->pack->filename, packfile->offset, packfile->packsize);
1168 fs_filesize = packfile->realsize;
1170 if (packfile->flags & FILE_FLAG_DEFLATED)
1174 file->flags |= FS_FLAG_DEFLATED;
1176 // We need some more variables
1177 ztk = Mem_Alloc (fs_mempool, sizeof (*file->z));
1179 ztk->real_length = packfile->realsize;
1181 // Initialize zlib stream
1182 ztk->zstream.next_in = ztk->input;
1183 ztk->zstream.avail_in = 0;
1185 /* From Zlib's "unzip.c":
1187 * windowBits is passed < 0 to tell that there is no zlib header.
1188 * Note that in this case inflate *requires* an extra "dummy" byte
1189 * after the compressed stream in order to complete decompression and
1190 * return Z_STREAM_END.
1191 * In unzip, i don't wait absolutely Z_STREAM_END because I known the
1192 * size of both compressed and uncompressed data
1194 if (qz_inflateInit2 (&ztk->zstream, -MAX_WBITS) != Z_OK)
1195 Sys_Error ("inflate init error (file: %s)", filename);
1197 ztk->zstream.next_out = ztk->output;
1198 ztk->zstream.avail_out = sizeof (ztk->output);
1208 =============================================================================
1210 MAIN PUBLIC FUNCTIONS
1212 =============================================================================
1216 ====================
1219 Open a file. The syntax is the same as fopen
1220 ====================
1222 qfile_t* FS_Open (const char* filepath, const char* mode, qboolean quiet)
1224 // If the file is opened in "write" or "append" mode
1225 if (strchr (mode, 'w') || strchr (mode, 'a'))
1227 char real_path [MAX_OSPATH];
1229 // Open the file on disk directly
1230 snprintf (real_path, sizeof (real_path), "%s/%s", fs_gamedir, filepath);
1232 // Create directories up to the file
1233 FS_CreatePath (real_path);
1235 return FS_SysOpen (real_path, mode);
1238 // Else, we look at the various search paths
1239 return FS_FOpenFile (filepath, quiet);
1244 ====================
1248 ====================
1250 int FS_Close (qfile_t* file)
1252 if (fclose (file->stream))
1257 qz_inflateEnd (&file->z->zstream);
1267 ====================
1270 Write "datasize" bytes into a file
1271 ====================
1273 size_t FS_Write (qfile_t* file, const void* data, size_t datasize)
1275 return fwrite (data, 1, datasize, file->stream);
1280 ====================
1283 Read up to "buffersize" bytes from a file
1284 ====================
1286 size_t FS_Read (qfile_t* file, void* buffer, size_t buffersize)
1291 // Quick path for unpacked files
1292 if (! (file->flags & FS_FLAG_PACKED))
1293 return fread (buffer, 1, buffersize, file->stream);
1295 // If the file isn't compressed
1296 if (! (file->flags & FS_FLAG_DEFLATED))
1298 // We must take care to not read after the end of the file
1299 count = file->length - file->position;
1300 if (buffersize > count)
1303 nb = fread (buffer, 1, buffersize, file->stream);
1305 file->position += nb;
1309 // If the file is compressed, it's more complicated...
1312 // First, we copy as many bytes as we can from "output"
1313 if (ztk->out_ind < ztk->out_max)
1315 count = ztk->out_max - ztk->out_ind;
1317 nb = (buffersize > count) ? count : buffersize;
1318 memcpy (buffer, &ztk->output[ztk->out_ind], nb);
1320 file->position += nb;
1325 // We cycle through a few operations until we have inflated enough data
1326 while (nb < buffersize)
1328 // NOTE: at this point, "output" should always be empty
1330 // If "input" is also empty, we need to fill it
1331 if (ztk->in_ind == ztk->in_max)
1335 // If we are at the end of the file
1336 if (ztk->out_position == ztk->real_length)
1339 remain = file->length - ztk->in_position;
1340 count = (remain > sizeof (ztk->input)) ? sizeof (ztk->input) : remain;
1341 fread (ztk->input, 1, count, file->stream);
1343 // Update indexes and counters
1345 ztk->in_max = count;
1346 ztk->in_position += count;
1349 // Now that we are sure we have compressed data available, we need to determine
1350 // if it's better to inflate it in "output" or directly in "buffer" (we are in this
1351 // case if we still need more bytes than "output" can contain)
1353 ztk->zstream.next_in = &ztk->input[ztk->in_ind];
1354 ztk->zstream.avail_in = ztk->in_max - ztk->in_ind;
1356 // If output will be able to contain at least 1 more byte than the data we need
1357 if (buffersize - nb < sizeof (ztk->output))
1361 // Inflate the data in "output"
1362 ztk->zstream.next_out = ztk->output;
1363 ztk->zstream.avail_out = sizeof (ztk->output);
1364 error = qz_inflate (&ztk->zstream, Z_SYNC_FLUSH);
1365 if (error != Z_OK && error != Z_STREAM_END)
1366 Sys_Error ("Can't inflate file");
1367 ztk->in_ind = ztk->in_max - ztk->zstream.avail_in;
1368 ztk->out_max = sizeof (ztk->output) - ztk->zstream.avail_out;
1369 ztk->out_position += ztk->out_max;
1371 // Copy the requested data in "buffer" (as much as we can)
1372 count = (buffersize - nb > ztk->out_max) ? ztk->out_max : buffersize - nb;
1373 memcpy (&((qbyte*)buffer)[nb], ztk->output, count);
1374 ztk->out_ind = count;
1377 // Else, we inflate directly in "buffer"
1382 // Inflate the data in "buffer"
1383 ztk->zstream.next_out = &((qbyte*)buffer)[nb];
1384 ztk->zstream.avail_out = buffersize - nb;
1385 error = qz_inflate (&ztk->zstream, Z_SYNC_FLUSH);
1386 if (error != Z_OK && error != Z_STREAM_END)
1387 Sys_Error ("Can't inflate file");
1388 ztk->in_ind = ztk->in_max - ztk->zstream.avail_in;
1390 // Invalidate the output data (for FS_Seek)
1394 // How much data did it inflate?
1395 count = buffersize - nb - ztk->zstream.avail_out;
1396 ztk->out_position += count;
1400 file->position += count;
1408 ====================
1411 Flush the file output stream
1412 ====================
1414 int FS_Flush (qfile_t* file)
1416 return fflush (file->stream);
1421 ====================
1424 Print a string into a file
1425 ====================
1427 int FS_Print(qfile_t* file, const char *msg)
1429 return FS_Write(file, msg, strlen(msg));
1433 ====================
1436 Print a string into a file
1437 ====================
1439 int FS_Printf(qfile_t* file, const char* format, ...)
1444 va_start (args, format);
1445 result = vfprintf (file->stream, format, args);
1453 ====================
1456 Print a string into a file
1457 ====================
1459 int FS_VPrintf(qfile_t* file, const char* format, va_list ap)
1461 return vfprintf (file->stream, format, ap);
1466 ====================
1469 Get the next character of a file
1470 ====================
1472 int FS_Getc (qfile_t* file)
1476 if (FS_Read (file, &c, 1) != 1)
1484 ====================
1487 Move the position index in a file
1488 ====================
1490 int FS_Seek (qfile_t* file, long offset, int whence)
1492 // Quick path for unpacked files
1493 if (! (file->flags & FS_FLAG_PACKED))
1494 return fseek (file->stream, offset, whence);
1496 // Seeking in compressed files is more a hack than anything else,
1497 // but we need to support it, so here it is.
1498 if (file->flags & FS_FLAG_DEFLATED)
1500 ztoolkit_t *ztk = file->z;
1501 qbyte buffer [sizeof (ztk->output)]; // it's big to force inflating into buffer directly
1506 offset += file->position;
1513 offset += ztk->real_length;
1519 if (offset < 0 || offset > (long) ztk->real_length)
1522 // If we need to go back in the file
1523 if (offset <= (long) file->position)
1525 // If we still have the data we need in the output buffer
1526 if (file->position - offset <= ztk->out_ind)
1528 ztk->out_ind -= file->position - offset;
1529 file->position = offset;
1533 // Else, we restart from the beginning of the file
1536 ztk->in_position = 0;
1539 ztk->out_position = 0;
1541 fseek (file->stream, file->offset, SEEK_SET);
1543 // Reset the Zlib stream
1544 ztk->zstream.next_in = ztk->input;
1545 ztk->zstream.avail_in = 0;
1546 qz_inflateReset (&ztk->zstream);
1549 // Skip all data until we reach the requested offset
1550 while ((long) file->position < offset)
1552 size_t diff = offset - file->position;
1555 count = (diff > sizeof (buffer)) ? sizeof (buffer) : diff;
1556 len = FS_Read (file, buffer, count);
1564 // Packed files receive a special treatment too, because
1565 // we need to make sure it doesn't go outside of the file
1569 offset += file->position;
1576 offset += file->length;
1582 if (offset < 0 || offset > (long) file->length)
1585 if (fseek (file->stream, file->offset + offset, SEEK_SET) == -1)
1587 file->position = offset;
1593 ====================
1596 Give the current position in a file
1597 ====================
1599 long FS_Tell (qfile_t* file)
1601 if (file->flags & FS_FLAG_PACKED)
1602 return file->position;
1604 return ftell (file->stream);
1609 ====================
1612 Extract a line from a file
1613 ====================
1615 char* FS_Gets (qfile_t* file, char* buffer, int buffersize)
1619 // Quick path for unpacked files
1620 if (! (file->flags & FS_FLAG_PACKED))
1621 return fgets (buffer, buffersize, file->stream);
1623 for (ind = 0; ind < (size_t) buffersize - 1; ind++)
1625 int c = FS_Getc (file);
1640 buffer[ind + 1] = '\0';
1649 buffer[buffersize - 1] = '\0';
1658 Dynamic length version of fgets. DO NOT free the buffer.
1661 char *FS_Getline (qfile_t *file)
1663 static int size = 256;
1664 static char *buf = 0;
1669 buf = Mem_Alloc (fs_mempool, size);
1671 if (!FS_Gets (file, buf, size))
1675 while (buf[len - 1] != '\n' && buf[len - 1] != '\r')
1677 t = Mem_Alloc (fs_mempool, size + 256);
1678 memcpy(t, buf, size);
1682 if (!FS_Gets (file, buf + len, size - len))
1686 while ((len = strlen(buf)) && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
1693 ====================
1696 Extract a line from a file
1697 ====================
1699 int FS_Eof (qfile_t* file)
1701 if (file->flags & FS_FLAG_PACKED)
1703 if (file->flags & FS_FLAG_DEFLATED)
1704 return (file->position == file->z->real_length);
1706 return (file->position == file->length);
1709 return feof (file->stream);
1717 Filename are relative to the quake directory.
1718 Always appends a 0 byte.
1721 qbyte *FS_LoadFile (const char *path, mempool_t *pool, qboolean quiet)
1726 // look for it in the filesystem or pack files
1727 h = FS_Open (path, "rb", quiet);
1731 buf = Mem_Alloc(pool, fs_filesize+1);
1733 Sys_Error ("FS_LoadFile: not enough available memory for %s (size %i)", path, fs_filesize);
1735 ((qbyte *)buf)[fs_filesize] = 0;
1737 FS_Read (h, buf, fs_filesize);
1748 The filename will be prefixed by the current game directory
1751 qboolean FS_WriteFile (const char *filename, void *data, int len)
1755 handle = FS_Open (filename, "wb", false);
1758 Con_Printf("FS_WriteFile: failed on %s\n", filename);
1762 Con_DPrintf("FS_WriteFile: %s\n", filename);
1763 FS_Write (handle, data, len);
1770 =============================================================================
1772 OTHERS PUBLIC FUNCTIONS
1774 =============================================================================
1782 void FS_StripExtension (const char *in, char *out, size_t size_out)
1789 while (*in && size_out > 1)
1793 else if (*in == '/' || *in == '\\' || *in == ':')
1810 void FS_DefaultExtension (char *path, const char *extension, size_t size_path)
1814 // if path doesn't have a .EXT, append extension
1815 // (extension should include the .)
1816 src = path + strlen(path) - 1;
1818 while (*src != '/' && src != path)
1821 return; // it has an extension
1825 strlcat (path, extension, size_path);
1833 Look for a file in the packages and in the filesystem
1836 qboolean FS_FileExists (const char *filename)
1838 return (FS_FindFile (filename, NULL, true) != NULL);
1846 Look for a file in the filesystem only
1849 qboolean FS_SysFileExists (const char *path)
1854 f = fopen (path, "rb");
1865 if (stat (path,&buf) == -1)
1872 void FS_mkdir (const char *path)
1885 Allocate and fill a search structure with information on matching filenames.
1888 fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet)
1891 searchpath_t *searchpath;
1893 int i, basepathlength, numfiles, numchars;
1894 stringlist_t *dir, *dirfile, *liststart, *listcurrent, *listtemp;
1895 const char *slash, *backslash, *colon, *separator;
1897 char netpath[MAX_OSPATH];
1898 char temp[MAX_OSPATH];
1900 while(!strncmp(pattern, "./", 2))
1902 while(!strncmp(pattern, ".\\", 2))
1909 slash = strrchr(pattern, '/');
1910 backslash = strrchr(pattern, '\\');
1911 colon = strrchr(pattern, ':');
1912 separator = pattern;
1913 if (separator < slash)
1915 if (separator < backslash)
1916 separator = backslash;
1917 if (separator < colon)
1919 basepathlength = separator - pattern;
1920 basepath = Mem_Alloc (tempmempool, basepathlength + 1);
1922 memcpy(basepath, pattern, basepathlength);
1923 basepath[basepathlength] = 0;
1925 // search through the path, one element at a time
1926 for (searchpath = fs_searchpaths;searchpath;searchpath = searchpath->next)
1928 // is the element a pak file?
1929 if (searchpath->pack)
1931 // look through all the pak file elements
1932 pak = searchpath->pack;
1933 for (i = 0;i < pak->numfiles;i++)
1935 strcpy(temp, pak->files[i].name);
1938 if (matchpattern(temp, (char *)pattern, true))
1940 for (listtemp = liststart;listtemp;listtemp = listtemp->next)
1941 if (!strcmp(listtemp->text, temp))
1943 if (listtemp == NULL)
1945 listcurrent = stringlistappend(listcurrent, temp);
1946 if (liststart == NULL)
1947 liststart = listcurrent;
1949 Sys_Printf("SearchPackFile: %s : %s\n", pak->filename, temp);
1952 // strip off one path element at a time until empty
1953 // this way directories are added to the listing if they match the pattern
1954 slash = strrchr(temp, '/');
1955 backslash = strrchr(temp, '\\');
1956 colon = strrchr(temp, ':');
1958 if (separator < slash)
1960 if (separator < backslash)
1961 separator = backslash;
1962 if (separator < colon)
1964 *((char *)separator) = 0;
1970 // get a directory listing and look at each name
1971 snprintf(netpath, sizeof (netpath), "%s/%s", searchpath->filename, basepath);
1972 if ((dir = listdirectory(netpath)))
1974 for (dirfile = dir;dirfile;dirfile = dirfile->next)
1976 snprintf(temp, sizeof(temp), "%s/%s", basepath, dirfile->text);
1977 if (matchpattern(temp, (char *)pattern, true))
1979 for (listtemp = liststart;listtemp;listtemp = listtemp->next)
1980 if (!strcmp(listtemp->text, temp))
1982 if (listtemp == NULL)
1984 listcurrent = stringlistappend(listcurrent, temp);
1985 if (liststart == NULL)
1986 liststart = listcurrent;
1988 Sys_Printf("SearchDirFile: %s\n", temp);
1999 liststart = stringlistsort(liststart);
2002 for (listtemp = liststart;listtemp;listtemp = listtemp->next)
2005 numchars += strlen(listtemp->text) + 1;
2007 search = Z_Malloc(sizeof(fssearch_t) + numchars + numfiles * sizeof(char *));
2008 search->filenames = (char **)((char *)search + sizeof(fssearch_t));
2009 search->filenamesbuffer = (char *)((char *)search + sizeof(fssearch_t) + numfiles * sizeof(char *));
2010 search->numfilenames = numfiles;
2013 for (listtemp = liststart;listtemp;listtemp = listtemp->next)
2015 search->filenames[numfiles] = search->filenamesbuffer + numchars;
2016 strcpy(search->filenames[numfiles], listtemp->text);
2018 numchars += strlen(listtemp->text) + 1;
2021 stringlistfree(liststart);
2028 void FS_FreeSearch(fssearch_t *search)
2033 extern int con_linewidth;
2034 int FS_ListDirectory(const char *pattern, int oneperline)
2045 search = FS_Search(pattern, true, true);
2048 numfiles = search->numfilenames;
2051 // FIXME: the names could be added to one column list and then
2052 // gradually shifted into the next column if they fit, and then the
2053 // next to make a compact variable width listing but it's a lot more
2055 // find width for columns
2057 for (i = 0;i < numfiles;i++)
2059 l = strlen(search->filenames[i]);
2060 if (columnwidth < l)
2063 // count the spacing character
2065 // calculate number of columns
2066 numcolumns = con_linewidth / columnwidth;
2067 // don't bother with the column printing if it's only one column
2068 if (numcolumns >= 2)
2070 numlines = (numfiles + numcolumns - 1) / numcolumns;
2071 for (i = 0;i < numlines;i++)
2074 for (k = 0;k < numcolumns;k++)
2076 l = i * numcolumns + k;
2079 name = search->filenames[l];
2080 for (j = 0;name[j] && j < (int)sizeof(linebuf) - 1;j++)
2081 linebuf[linebufpos++] = name[j];
2082 // space out name unless it's the last on the line
2083 if (k < (numcolumns - 1) && l < (numfiles - 1))
2084 for (;j < columnwidth && j < (int)sizeof(linebuf) - 1;j++)
2085 linebuf[linebufpos++] = ' ';
2088 linebuf[linebufpos] = 0;
2089 Con_Printf("%s\n", linebuf);
2096 for (i = 0;i < numfiles;i++)
2097 Con_Printf("%s\n", search->filenames[i]);
2098 FS_FreeSearch(search);
2102 static void FS_ListDirectoryCmd (const char* cmdname, int oneperline)
2104 const char *pattern;
2107 Con_Printf("usage:\n%s [path/pattern]\n", cmdname);
2110 if (Cmd_Argc() == 2)
2111 pattern = Cmd_Argv(1);
2114 if (!FS_ListDirectory(pattern, oneperline))
2115 Con_Print("No files found.\n");
2120 FS_ListDirectoryCmd("dir", true);
2125 FS_ListDirectoryCmd("ls", false);