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;
145 // size_t in_position; // we use "file->position" directly instead
146 size_t out_ind, out_max;
147 size_t out_position; // virtual position in the uncompressed file
148 qbyte input [ZBUFF_SIZE];
149 qbyte output [ZBUFF_SIZE];
156 size_t length; // file size (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; // LordHavoc: 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 // LordHavoc: was 2048, increased to 65536 and changed info[MAX_PACK_FILES] to a temporary alloc
252 #define MAX_FILES_IN_PACK 65536
254 char fs_gamedir[MAX_OSPATH];
255 char fs_basedir[MAX_OSPATH];
257 qboolean fs_modified; // set true if using non-id files
261 =============================================================================
263 PRIVATE FUNCTIONS - PK3 HANDLING
265 =============================================================================
268 // Functions exported from zlib
270 # define ZEXPORT WINAPI
275 static int (ZEXPORT *qz_inflate) (z_stream* strm, int flush);
276 static int (ZEXPORT *qz_inflateEnd) (z_stream* strm);
277 static int (ZEXPORT *qz_inflateInit2_) (z_stream* strm, int windowBits, const char *version, int stream_size);
278 static int (ZEXPORT *qz_inflateReset) (z_stream* strm);
280 #define qz_inflateInit2(strm, windowBits) \
281 qz_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
283 static dllfunction_t zlibfuncs[] =
285 {"inflate", (void **) &qz_inflate},
286 {"inflateEnd", (void **) &qz_inflateEnd},
287 {"inflateInit2_", (void **) &qz_inflateInit2_},
288 {"inflateReset", (void **) &qz_inflateReset},
292 // Handle for Zlib DLL
293 static dllhandle_t zlib_dll = NULL;
303 void PK3_CloseLibrary (void)
308 Sys_UnloadLibrary (zlib_dll);
317 Try to load the Zlib DLL
320 qboolean PK3_OpenLibrary (void)
323 const dllfunction_t *func;
330 dllname = "zlib.dll";
332 dllname = "libz.so.1";
336 for (func = zlibfuncs; func && func->name != NULL; func++)
337 *func->funcvariable = NULL;
340 if (! (zlib_dll = Sys_LoadLibrary (dllname)))
342 Con_Printf("Can't find %s. Compressed files support disabled\n", dllname);
346 // Get the function adresses
347 for (func = zlibfuncs; func && func->name != NULL; func++)
348 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (zlib_dll, func->name)))
350 Con_Printf("missing function \"%s\" - broken Zlib library!\n", func->name);
355 Con_Printf("%s loaded. Compressed files support enabled\n", dllname);
362 PK3_GetEndOfCentralDir
364 Extract the end of the central directory from a PK3 package
367 qboolean PK3_GetEndOfCentralDir (const char *packfile, FILE *packhandle, pk3_endOfCentralDir_t *eocd)
369 long filesize, maxsize;
373 // Get the package size
374 fseek (packhandle, 0, SEEK_END);
375 filesize = ftell (packhandle);
376 if (filesize < ZIP_END_CDIR_SIZE)
379 // Load the end of the file in memory
380 if (filesize < ZIP_MAX_COMMENTS_SIZE + ZIP_END_CDIR_SIZE)
383 maxsize = ZIP_MAX_COMMENTS_SIZE + ZIP_END_CDIR_SIZE;
384 buffer = Mem_Alloc (tempmempool, maxsize);
385 fseek (packhandle, filesize - maxsize, SEEK_SET);
386 if (fread (buffer, 1, maxsize, packhandle) != maxsize)
392 // Look for the end of central dir signature around the end of the file
393 maxsize -= ZIP_END_CDIR_SIZE;
394 ptr = &buffer[maxsize];
396 while (BuffBigLong (ptr) != ZIP_END_HEADER)
408 memcpy (eocd, ptr, ZIP_END_CDIR_SIZE);
409 eocd->signature = LittleLong (eocd->signature);
410 eocd->disknum = LittleShort (eocd->disknum);
411 eocd->cdir_disknum = LittleShort (eocd->cdir_disknum);
412 eocd->localentries = LittleShort (eocd->localentries);
413 eocd->nbentries = LittleShort (eocd->nbentries);
414 eocd->cdir_size = LittleLong (eocd->cdir_size);
415 eocd->cdir_offset = LittleLong (eocd->cdir_offset);
416 eocd->comment_size = LittleShort (eocd->comment_size);
428 Extract the file list from a PK3 file
431 int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd)
433 qbyte *central_dir, *ptr;
437 // Load the central directory in memory
438 central_dir = Mem_Alloc (tempmempool, eocd->cdir_size);
439 fseek (pack->handle, eocd->cdir_offset, SEEK_SET);
440 fread (central_dir, 1, eocd->cdir_size, pack->handle);
442 // Extract the files properties
443 // The parsing is done "by hand" because some fields have variable sizes and
444 // the constant part isn't 4-bytes aligned, which makes the use of structs difficult
445 remaining = eocd->cdir_size;
448 for (ind = 0; ind < eocd->nbentries; ind++)
450 size_t namesize, count;
453 // Checking the remaining size
454 if (remaining < ZIP_CDIR_CHUNK_BASE_SIZE)
456 Mem_Free (central_dir);
459 remaining -= ZIP_CDIR_CHUNK_BASE_SIZE;
462 if (BuffBigLong (ptr) != ZIP_CDIR_HEADER)
464 Mem_Free (central_dir);
468 namesize = BuffLittleShort (&ptr[28]); // filename length
470 // Check encryption, compression, and attributes
471 // 1st uint8 : general purpose bit flag
472 // Check bits 0 (encryption), 3 (data descriptor after the file), and 5 (compressed patched data (?))
473 // 2nd uint8 : external file attributes
474 // Check bits 3 (file is a directory) and 5 (file is a volume (?))
475 if ((ptr[8] & 0x29) == 0 && (ptr[38] & 0x18) == 0)
477 // Still enough bytes for the name?
478 if (remaining < namesize || namesize >= sizeof (*pack->files))
480 Mem_Free (central_dir);
484 // WinZip doesn't use the "directory" attribute, so we need to check the name directly
485 if (ptr[ZIP_CDIR_CHUNK_BASE_SIZE + namesize - 1] != '/')
488 file = &pack->files[pack->numfiles];
489 memcpy (file->name, &ptr[ZIP_CDIR_CHUNK_BASE_SIZE], namesize);
490 file->name[namesize] = '\0';
492 // Compression, sizes and offset
493 if (BuffLittleShort (&ptr[10]))
494 file->flags = FILE_FLAG_DEFLATED;
495 file->packsize = BuffLittleLong (&ptr[20]);
496 file->realsize = BuffLittleLong (&ptr[24]);
497 file->offset = BuffLittleLong (&ptr[42]);
503 // Skip the name, additionnal field, and comment
504 // 1er uint16 : extra field length
505 // 2eme uint16 : file comment length
506 count = namesize + BuffLittleShort (&ptr[30]) + BuffLittleShort (&ptr[32]);
507 ptr += ZIP_CDIR_CHUNK_BASE_SIZE + count;
511 Mem_Free (central_dir);
512 return pack->numfiles;
520 Create a package entry associated with a PK3 file
523 pack_t *FS_LoadPackPK3 (const char *packfile)
526 pk3_endOfCentralDir_t eocd;
530 packhandle = fopen (packfile, "rb");
534 if (! PK3_GetEndOfCentralDir (packfile, packhandle, &eocd))
535 Sys_Error ("%s is not a PK3 file", packfile);
537 // Multi-volume ZIP archives are NOT allowed
538 if (eocd.disknum != 0 || eocd.cdir_disknum != 0)
539 Sys_Error ("%s is a multi-volume ZIP archive", packfile);
541 if (eocd.nbentries > MAX_FILES_IN_PACK)
542 Sys_Error ("%s contains too many files (%hu)", packfile, eocd.nbentries);
544 // Create a package structure in memory
545 pack = Mem_Alloc (pak_mempool, sizeof (pack_t));
546 pack->ignorecase = true; // LordHavoc: pk3 ignores case
547 strcpy (pack->filename, packfile);
548 pack->handle = packhandle;
549 pack->numfiles = eocd.nbentries;
550 pack->mempool = Mem_AllocPool (packfile);
551 pack->files = Mem_Alloc (pack->mempool, eocd.nbentries * sizeof(packfile_t));
552 pack->next = packlist;
555 real_nb_files = PK3_BuildFileList (pack, &eocd);
556 if (real_nb_files <= 0)
557 Sys_Error ("%s is not a valid PK3 file", packfile);
559 Con_Printf ("Added packfile %s (%i files)\n", packfile, real_nb_files);
566 PK3_GetTrueFileOffset
568 Find where the true file data offset is
571 void PK3_GetTrueFileOffset (packfile_t *file, pack_t *pack)
573 qbyte buffer [ZIP_LOCAL_CHUNK_BASE_SIZE];
577 if (file->flags & FILE_FLAG_TRUEOFFS)
580 // Load the local file description
581 fseek (pack->handle, file->offset, SEEK_SET);
582 count = fread (buffer, 1, ZIP_LOCAL_CHUNK_BASE_SIZE, pack->handle);
583 if (count != ZIP_LOCAL_CHUNK_BASE_SIZE || BuffBigLong (buffer) != ZIP_DATA_HEADER)
584 Sys_Error ("Can't retrieve file %s in package %s", file->name, pack->filename);
586 // Skip name and extra field
587 file->offset += BuffLittleShort (&buffer[26]) + BuffLittleShort (&buffer[28]) + ZIP_LOCAL_CHUNK_BASE_SIZE;
589 file->flags |= FILE_FLAG_TRUEOFFS;
594 =============================================================================
596 OTHER PRIVATE FUNCTIONS
598 =============================================================================
606 Only used for FS_WriteFile.
609 void FS_CreatePath (char *path)
613 for (ofs = path+1 ; *ofs ; ofs++)
615 if (*ofs == '/' || *ofs == '\\')
617 // create the directory
633 void FS_Path_f (void)
637 Con_Printf ("Current search path:\n");
638 for (s=fs_searchpaths ; s ; s=s->next)
642 Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
645 Con_Printf ("%s\n", s->filename);
654 Takes an explicit (not game tree related) path to a pak file.
656 Loads the header and directory, adding the files at the beginning
657 of the list so they override previous pack files.
660 pack_t *FS_LoadPackPAK (const char *packfile)
662 dpackheader_t header;
666 dpackfile_t *info; // temporary alloc, allowing huge pack directories
668 packhandle = fopen (packfile, "rb");
672 fread ((void *)&header, 1, sizeof(header), packhandle);
673 if (memcmp(header.id, "PACK", 4))
674 Sys_Error ("%s is not a packfile", packfile);
675 header.dirofs = LittleLong (header.dirofs);
676 header.dirlen = LittleLong (header.dirlen);
678 if (header.dirlen % sizeof(dpackfile_t))
679 Sys_Error ("%s has an invalid directory size", packfile);
681 numpackfiles = header.dirlen / sizeof(dpackfile_t);
683 if (numpackfiles > MAX_FILES_IN_PACK)
684 Sys_Error ("%s has %i files", packfile, numpackfiles);
686 pack = Mem_Alloc(pak_mempool, sizeof (pack_t));
687 pack->ignorecase = false; // LordHavoc: pak is case sensitive
688 strcpy (pack->filename, packfile);
689 pack->handle = packhandle;
690 pack->numfiles = numpackfiles;
691 pack->mempool = Mem_AllocPool(packfile);
692 pack->files = Mem_Alloc(pack->mempool, numpackfiles * sizeof(packfile_t));
693 pack->next = packlist;
696 info = Mem_Alloc(tempmempool, sizeof(*info) * numpackfiles);
697 fseek (packhandle, header.dirofs, SEEK_SET);
698 fread ((void *)info, 1, header.dirlen, packhandle);
700 // parse the directory
701 for (i = 0;i < numpackfiles;i++)
704 packfile_t *file = &pack->files[i];
706 strcpy (file->name, info[i].name);
707 file->offset = LittleLong(info[i].filepos);
708 size = LittleLong (info[i].filelen);
709 file->packsize = size;
710 file->realsize = size;
711 file->flags = FILE_FLAG_TRUEOFFS;
716 Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
725 Sets fs_gamedir, adds the directory to the head of the path,
726 then loads and adds pak1.pak pak2.pak ...
729 void FS_AddGameDirectory (char *dir)
731 stringlist_t *list, *current;
732 searchpath_t *search;
734 char pakfile[MAX_OSPATH];
736 strcpy (fs_gamedir, dir);
738 // add the directory to the search path
739 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
740 strcpy (search->filename, dir);
741 search->next = fs_searchpaths;
742 fs_searchpaths = search;
744 list = listdirectory(dir);
746 // add any PAK package in the directory
747 for (current = list;current;current = current->next)
749 if (matchpattern(current->text, "*.pak", true))
751 sprintf (pakfile, "%s/%s", dir, current->text);
752 pak = FS_LoadPackPAK (pakfile);
755 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
757 search->next = fs_searchpaths;
758 fs_searchpaths = search;
761 Con_Printf("unable to load pak \"%s\"\n", pakfile);
765 // add any PK3 package in the director
766 for (current = list;current;current = current->next)
768 if (matchpattern(current->text, "*.pk3", true))
770 sprintf (pakfile, "%s/%s", dir, current->text);
771 pak = FS_LoadPackPK3 (pakfile);
774 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
776 search->next = fs_searchpaths;
777 fs_searchpaths = search;
780 Con_Printf("unable to load pak \"%s\"\n", pakfile);
792 char *FS_FileExtension (const char *in)
794 static char exten[8];
795 const char *slash, *backslash, *colon, *dot, *separator;
798 slash = strrchr(in, '/');
799 backslash = strrchr(in, '\\');
800 colon = strrchr(in, ':');
801 dot = strrchr(in, '.');
803 if (separator < backslash)
804 separator = backslash;
805 if (separator < colon)
810 for (i = 0;i < 7 && dot[i];i++)
825 searchpath_t *search;
827 fs_mempool = Mem_AllocPool("file management");
828 pak_mempool = Mem_AllocPool("paks");
830 Cmd_AddCommand ("path", FS_Path_f);
832 strcpy(fs_basedir, ".");
837 // Overrides the system supplied base directory (under GAMENAME)
838 i = COM_CheckParm ("-basedir");
839 if (i && i < com_argc-1)
840 strcpy (fs_basedir, com_argv[i+1]);
842 i = strlen (fs_basedir);
843 if (i > 0 && (fs_basedir[i-1] == '\\' || fs_basedir[i-1] == '/'))
846 // start up with GAMENAME by default (id1)
847 strcpy(com_modname, GAMENAME);
848 FS_AddGameDirectory (va("%s/"GAMENAME, fs_basedir));
852 strcpy(com_modname, gamedirname);
853 FS_AddGameDirectory (va("%s/%s", fs_basedir, gamedirname));
857 // Adds basedir/gamedir as an override game
858 i = COM_CheckParm ("-game");
859 if (i && i < com_argc-1)
862 strcpy(com_modname, com_argv[i+1]);
863 FS_AddGameDirectory (va("%s/%s", fs_basedir, com_argv[i+1]));
866 // -path <dir or packfile> [<dir or packfile>] ...
867 // Fully specifies the exact search path, overriding the generated one
868 i = COM_CheckParm ("-path");
872 fs_searchpaths = NULL;
873 while (++i < com_argc)
875 if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')
878 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
879 if (!strcasecmp (FS_FileExtension(com_argv[i]), "pak"))
881 search->pack = FS_LoadPackPAK (com_argv[i]);
883 Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
885 else if (!strcasecmp (FS_FileExtension (com_argv[i]), "pk3"))
887 search->pack = FS_LoadPackPK3 (com_argv[i]);
889 Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
892 strcpy (search->filename, com_argv[i]);
893 search->next = fs_searchpaths;
894 fs_searchpaths = search;
904 Internal function used to create a qfile_t and open the relevant file on disk
907 static qfile_t* FS_SysOpen (const char* filepath, const char* mode)
911 file = Mem_Alloc (fs_mempool, sizeof (*file));
912 memset (file, 0, sizeof (*file));
914 file->stream = fopen (filepath, mode);
930 qfile_t *FS_OpenRead (const char *path, int offs, int len)
934 file = FS_SysOpen (path, "rb");
937 Sys_Error ("Couldn't open %s", path);
942 if (offs < 0 || len < 0)
944 // We set fs_filesize here for normal files
945 fseek (file->stream, 0, SEEK_END);
946 fs_filesize = ftell (file->stream);
947 fseek (file->stream, 0, SEEK_SET);
952 fseek (file->stream, offs, SEEK_SET);
954 file->flags |= FS_FLAG_PACKED;
967 If the requested file is inside a packfile, a new qfile_t* will be opened
973 qfile_t *FS_FOpenFile (const char *filename, qboolean quiet)
975 searchpath_t *search;
976 char netpath[MAX_OSPATH];
978 int i, filenamelen, matched;
980 filenamelen = strlen (filename);
982 // search through the path, one element at a time
983 search = fs_searchpaths;
985 for ( ; search ; search = search->next)
987 // is the element a pak file?
990 // look through all the pak file elements
992 for (i=0 ; i<pak->numfiles ; i++)
995 matched = !strcasecmp (pak->files[i].name, filename);
997 matched = !strcmp (pak->files[i].name, filename);
998 if (matched) // found it?
1003 Sys_Printf ("PackFile: %s : %s\n",pak->filename, pak->files[i].name);
1005 // If we don't have the true offset, get it now
1006 if (! (pak->files[i].flags & FILE_FLAG_TRUEOFFS))
1007 PK3_GetTrueFileOffset (&pak->files[i], pak);
1009 // No Zlib DLL = no compressed files
1010 if (!zlib_dll && (pak->files[i].flags & FILE_FLAG_DEFLATED))
1012 Con_Printf ("WARNING: can't open the compressed file %s\n"
1013 "You need the Zlib DLL to use compressed files\n", filename);
1018 // open a new file in the pakfile
1019 file = FS_OpenRead (pak->filename, pak->files[i].offset, pak->files[i].packsize);
1020 fs_filesize = pak->files[i].realsize;
1022 if (pak->files[i].flags & FILE_FLAG_DEFLATED)
1026 file->flags |= FS_FLAG_DEFLATED;
1028 // We need some more variables
1029 ztk = Mem_Alloc (fs_mempool, sizeof (*file->z));
1031 ztk->real_length = pak->files[i].realsize;
1033 // Initialize zlib stream
1034 ztk->zstream.next_in = ztk->input;
1035 ztk->zstream.avail_in = 0;
1037 /* From Zlib's "unzip.c":
1039 * windowBits is passed < 0 to tell that there is no zlib header.
1040 * Note that in this case inflate *requires* an extra "dummy" byte
1041 * after the compressed stream in order to complete decompression and
1042 * return Z_STREAM_END.
1043 * In unzip, i don't wait absolutely Z_STREAM_END because I known the
1044 * size of both compressed and uncompressed data
1046 if (qz_inflateInit2 (&ztk->zstream, -MAX_WBITS) != Z_OK)
1047 Sys_Error ("inflate init error (file: %s)", filename);
1049 ztk->zstream.next_out = ztk->output;
1050 ztk->zstream.avail_out = sizeof (ztk->output);
1061 sprintf (netpath, "%s/%s",search->filename, filename);
1063 if (!FS_SysFileExists (netpath))
1067 Sys_Printf ("FindFile: %s\n",netpath);
1068 return FS_OpenRead (netpath, -1, -1);
1073 Sys_Printf ("FindFile: can't find %s\n", filename);
1081 =============================================================================
1083 MAIN PUBLIC FUNCTIONS
1085 =============================================================================
1089 ====================
1092 Open a file. The syntax is the same as fopen
1093 ====================
1095 qfile_t* FS_Open (const char* filepath, const char* mode, qboolean quiet)
1097 // If the file is opened in "write" or "append" mode
1098 if (strchr (mode, 'w') || strchr (mode, 'a'))
1100 char real_path [MAX_OSPATH];
1102 // Open the file on disk directly
1103 snprintf (real_path, sizeof (real_path), "%s/%s", fs_gamedir, filepath);
1105 // Create directories up to the file
1106 FS_CreatePath (real_path);
1108 return FS_SysOpen (real_path, mode);
1111 // Else, we look at the various search paths
1112 return FS_FOpenFile (filepath, quiet);
1117 ====================
1121 ====================
1123 int FS_Close (qfile_t* file)
1125 if (fclose (file->stream))
1130 qz_inflateEnd (&file->z->zstream);
1140 ====================
1143 Write "datasize" bytes into a file
1144 ====================
1146 size_t FS_Write (qfile_t* file, const void* data, size_t datasize)
1148 return fwrite (data, 1, datasize, file->stream);
1153 ====================
1156 Read up to "buffersize" bytes from a file
1157 ====================
1159 size_t FS_Read (qfile_t* file, void* buffer, size_t buffersize)
1164 // Quick path for unpacked files
1165 if (! (file->flags & FS_FLAG_PACKED))
1166 return fread (buffer, 1, buffersize, file->stream);
1168 // If the file isn't compressed
1169 if (! (file->flags & FS_FLAG_DEFLATED))
1171 // We must take care to not read after the end of the file
1172 count = file->length - file->position;
1173 if (buffersize > count)
1176 nb = fread (buffer, 1, buffersize, file->stream);
1178 // Update the position index if the file is packed
1179 file->position += nb;
1184 // If the file is compressed, it's more complicated...
1187 // First, we copy as many bytes as we can from "output"
1188 if (ztk->out_ind < ztk->out_max)
1190 count = ztk->out_max - ztk->out_ind;
1192 nb = (buffersize > count) ? count : buffersize;
1193 memcpy (buffer, &ztk->output[ztk->out_ind], nb);
1199 // We cycle through a few operations until we have inflated enough data
1200 while (nb < buffersize)
1202 // NOTE: at this point, "output" should always be empty
1204 // If "input" is also empty, we need to fill it
1205 if (ztk->in_ind == ztk->in_max)
1207 size_t remain = file->length - file->position;
1209 // If we are at the end of the file
1213 count = (remain > sizeof (ztk->input)) ? sizeof (ztk->input) : remain;
1214 fread (ztk->input, 1, count, file->stream);
1216 // Update indexes and counters
1218 ztk->in_max = count;
1219 file->position += count;
1222 // Now that we are sure we have compressed data available, we need to determine
1223 // if it's better to inflate it in "output" or directly in "buffer" (we are in this
1224 // case if we still need more bytes than "output" can contain)
1226 ztk->zstream.next_in = &ztk->input[ztk->in_ind];
1227 ztk->zstream.avail_in = ztk->in_max - ztk->in_ind;
1229 // If output will be able to contain at least 1 more byte than the data we need
1230 if (buffersize - nb < sizeof (ztk->output))
1234 // Inflate the data in "output"
1235 ztk->zstream.next_out = ztk->output;
1236 ztk->zstream.avail_out = sizeof (ztk->output);
1237 error = qz_inflate (&ztk->zstream, Z_SYNC_FLUSH);
1238 if (error != Z_OK && error != Z_STREAM_END)
1239 Sys_Error ("Can't inflate file");
1240 ztk->in_ind = ztk->in_max - ztk->zstream.avail_in;
1241 ztk->out_max = sizeof (ztk->output) - ztk->zstream.avail_out;
1243 ztk->out_position += ztk->out_max;
1245 // Copy the requested data in "buffer" (as much as we can)
1246 count = (buffersize - nb > ztk->out_max) ? ztk->out_max : buffersize - nb;
1247 memcpy (&((qbyte*)buffer)[nb], ztk->output, count);
1248 ztk->out_ind = count;
1251 // Else, we inflate directly in "buffer"
1256 // Inflate the data in "buffer"
1257 ztk->zstream.next_out = &((qbyte*)buffer)[nb];
1258 ztk->zstream.avail_out = buffersize - nb;
1259 error = qz_inflate (&ztk->zstream, Z_SYNC_FLUSH);
1260 if (error != Z_OK && error != Z_STREAM_END)
1261 Sys_Error ("Can't inflate file");
1262 ztk->in_ind = ztk->in_max - ztk->zstream.avail_in;
1264 // Invalidate the output data (for FS_Seek)
1268 // How much data did it inflate?
1269 count = buffersize - nb - ztk->zstream.avail_out;
1270 ztk->out_position += count;
1281 ====================
1284 Flush the file output stream
1285 ====================
1287 int FS_Flush (qfile_t* file)
1289 return fflush (file->stream);
1294 ====================
1297 Print a string into a file
1298 ====================
1300 int FS_Printf (qfile_t* file, const char* format, ...)
1305 va_start (args, format);
1306 result = vfprintf (file->stream, format, args);
1314 ====================
1317 Get the next character of a file
1318 ====================
1320 int FS_Getc (qfile_t* file)
1324 if (FS_Read (file, &c, 1) != 1)
1332 ====================
1335 Move the position index in a file
1336 ====================
1338 int FS_Seek (qfile_t* file, long offset, int whence)
1340 // Quick path for unpacked files
1341 if (! (file->flags & FS_FLAG_PACKED))
1342 return fseek (file->stream, offset, whence);
1344 // Seeking in compressed files is more a hack than anything else,
1345 // but we need to support it, so here it is.
1346 if (file->flags & FS_FLAG_DEFLATED)
1348 ztoolkit_t *ztk = file->z;
1350 qbyte buffer [sizeof (ztk->output)]; // it's big to force inflating into buffer directly
1352 crt_offset = ztk->out_position - ztk->out_max + ztk->out_ind;
1357 offset += crt_offset;
1364 offset += ztk->real_length;
1371 // If we need to go back in the file
1372 if (offset <= crt_offset)
1374 // If we still have the data we need in the output buffer
1375 if (crt_offset - offset <= ztk->out_ind)
1377 ztk->out_ind -= crt_offset - offset;
1381 // Else, we restart from the beginning of the file
1387 ztk->out_position = 0;
1389 fseek (file->stream, file->offset, SEEK_SET);
1391 // Reset the Zlib stream
1392 ztk->zstream.next_in = ztk->input;
1393 ztk->zstream.avail_in = 0;
1394 qz_inflateReset (&ztk->zstream);
1397 // Skip all data until we reach the requested offset
1398 while (crt_offset < offset)
1400 size_t diff = offset - crt_offset;
1403 count = (diff > sizeof (buffer)) ? sizeof (buffer) : diff;
1404 len = FS_Read (file, buffer, count);
1413 // Packed files receive a special treatment too, because
1414 // we need to make sure it doesn't go outside of the file
1418 offset += file->position;
1425 offset += file->length;
1431 if (offset < 0 || offset > file->length)
1434 if (fseek (file->stream, file->offset + offset, SEEK_SET) == -1)
1436 file->position = offset;
1442 ====================
1445 Give the current position in a file
1446 ====================
1448 long FS_Tell (qfile_t* file)
1450 if (file->flags & FS_FLAG_PACKED)
1452 if (file->flags & FS_FLAG_DEFLATED)
1454 ztoolkit_t *ztk = file->z;
1455 return ztk->out_position - ztk->out_max + ztk->out_ind;
1458 return file->position;
1461 return ftell (file->stream);
1466 ====================
1469 Extract a line from a file
1470 ====================
1472 char* FS_Gets (qfile_t* file, char* buffer, int buffersize)
1476 // Quick path for unpacked files
1477 if (! (file->flags & FS_FLAG_PACKED))
1478 return fgets (buffer, buffersize, file->stream);
1480 for (ind = 0; ind < buffersize - 1; ind++)
1482 int c = FS_Getc (file);
1497 buffer[ind + 1] = '\0';
1506 buffer[buffersize - 1] = '\0';
1515 Dynamic length version of fgets. DO NOT free the buffer.
1518 char *FS_Getline (qfile_t *file)
1520 static int size = 256;
1521 static char *buf = 0;
1526 buf = Mem_Alloc (fs_mempool, size);
1528 if (!FS_Gets (file, buf, size))
1532 while (buf[len - 1] != '\n' && buf[len - 1] != '\r')
1534 t = Mem_Alloc (fs_mempool, size + 256);
1535 memcpy(t, buf, size);
1539 if (!FS_Gets (file, buf + len, size - len))
1543 while ((len = strlen(buf)) && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
1550 ====================
1553 Extract a line from a file
1554 ====================
1556 int FS_Eof (qfile_t* file)
1558 if (file->flags & FS_FLAG_PACKED)
1560 if (file->flags & FS_FLAG_DEFLATED)
1562 ztoolkit_t *ztk = file->z;
1563 return (ztk->out_position - ztk->out_max + ztk->out_ind == ztk->real_length);
1566 return (file->position == file->length);
1569 return feof (file->stream);
1577 Filename are relative to the quake directory.
1578 Always appends a 0 byte.
1581 qbyte *FS_LoadFile (const char *path, qboolean quiet)
1586 // look for it in the filesystem or pack files
1587 h = FS_Open (path, "rb", quiet);
1591 buf = Mem_Alloc(tempmempool, fs_filesize+1);
1593 Sys_Error ("FS_LoadFile: not enough available memory for %s (size %i)", path, fs_filesize);
1595 ((qbyte *)buf)[fs_filesize] = 0;
1597 FS_Read (h, buf, fs_filesize);
1608 The filename will be prefixed by the current game directory
1611 qboolean FS_WriteFile (const char *filename, void *data, int len)
1614 char name[MAX_OSPATH];
1616 sprintf (name, "%s/%s", fs_gamedir, filename);
1618 // Create directories up to the file
1619 FS_CreatePath (name);
1621 handle = fopen (name, "wb");
1624 Con_Printf ("FS_WriteFile: failed on %s\n", name);
1628 Con_DPrintf ("FS_WriteFile: %s\n", name);
1629 fwrite (data, 1, len, handle);
1636 =============================================================================
1638 OTHERS PUBLIC FUNCTIONS
1640 =============================================================================
1648 void FS_StripExtension (const char *in, char *out)
1655 else if (*in == '/' || *in == '\\' || *in == ':')
1671 void FS_DefaultExtension (char *path, const char *extension)
1675 // if path doesn't have a .EXT, append extension
1676 // (extension should include the .)
1677 src = path + strlen(path) - 1;
1679 while (*src != '/' && src != path)
1682 return; // it has an extension
1686 strcat (path, extension);
1690 qboolean FS_FileExists (const char *filename)
1692 searchpath_t *search;
1693 char netpath[MAX_OSPATH];
1697 for (search = fs_searchpaths;search;search = search->next)
1702 for (i = 0;i < pak->numfiles;i++)
1703 if (!strcmp (pak->files[i].name, filename))
1708 sprintf (netpath, "%s/%s",search->filename, filename);
1709 if (FS_SysFileExists (netpath))
1718 qboolean FS_SysFileExists (const char *path)
1723 f = fopen (path, "rb");
1734 if (stat (path,&buf) == -1)
1741 void FS_mkdir (const char *path)