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];
223 // Search paths for files (including packages)
224 typedef struct searchpath_s
226 // only one of filename / pack will be used
227 char filename[MAX_OSPATH];
229 struct searchpath_s *next;
234 =============================================================================
238 =============================================================================
241 mempool_t *fs_mempool;
242 mempool_t *pak_mempool;
246 pack_t *packlist = NULL;
248 searchpath_t *fs_searchpaths;
250 // LordHavoc: was 2048, increased to 65536 and changed info[MAX_PACK_FILES] to a temporary alloc
251 #define MAX_FILES_IN_PACK 65536
253 char fs_gamedir[MAX_OSPATH];
254 char fs_basedir[MAX_OSPATH];
256 qboolean fs_modified; // set true if using non-id files
260 =============================================================================
262 PRIVATE FUNCTIONS - PK3 HANDLING
264 =============================================================================
267 // Functions exported from zlib
269 # define ZEXPORT WINAPI
274 static int (ZEXPORT *qz_inflate) (z_stream* strm, int flush);
275 static int (ZEXPORT *qz_inflateEnd) (z_stream* strm);
276 static int (ZEXPORT *qz_inflateInit2_) (z_stream* strm, int windowBits, const char *version, int stream_size);
277 static int (ZEXPORT *qz_inflateReset) (z_stream* strm);
279 #define qz_inflateInit2(strm, windowBits) \
280 qz_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
282 static dllfunction_t zlibfuncs[] =
284 {"inflate", (void **) &qz_inflate},
285 {"inflateEnd", (void **) &qz_inflateEnd},
286 {"inflateInit2_", (void **) &qz_inflateInit2_},
287 {"inflateReset", (void **) &qz_inflateReset},
291 // Handle for Zlib DLL
292 static dllhandle_t zlib_dll = NULL;
302 void PK3_CloseLibrary (void)
307 Sys_UnloadLibrary (zlib_dll);
316 Try to load the Zlib DLL
319 qboolean PK3_OpenLibrary (void)
322 const dllfunction_t *func;
329 dllname = "zlib.dll";
331 dllname = "libz.so.1";
335 for (func = zlibfuncs; func && func->name != NULL; func++)
336 *func->funcvariable = NULL;
339 if (! (zlib_dll = Sys_LoadLibrary (dllname)))
341 Con_Printf("Can't find %s. Compressed files support disabled\n", dllname);
345 // Get the function adresses
346 for (func = zlibfuncs; func && func->name != NULL; func++)
347 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (zlib_dll, func->name)))
349 Con_Printf("missing function \"%s\" - broken Zlib library!\n", func->name);
354 Con_Printf("%s loaded. Compressed files support enabled\n", dllname);
361 PK3_GetEndOfCentralDir
363 Extract the end of the central directory from a PK3 package
366 qboolean PK3_GetEndOfCentralDir (const char *packfile, FILE *packhandle, pk3_endOfCentralDir_t *eocd)
368 long filesize, maxsize;
372 // Get the package size
373 fseek (packhandle, 0, SEEK_END);
374 filesize = ftell (packhandle);
375 if (filesize < ZIP_END_CDIR_SIZE)
378 // Load the end of the file in memory
379 if (filesize < ZIP_MAX_COMMENTS_SIZE + ZIP_END_CDIR_SIZE)
382 maxsize = ZIP_MAX_COMMENTS_SIZE + ZIP_END_CDIR_SIZE;
383 buffer = Mem_Alloc (tempmempool, maxsize);
384 fseek (packhandle, filesize - maxsize, SEEK_SET);
385 if (fread (buffer, 1, maxsize, packhandle) != maxsize)
391 // Look for the end of central dir signature around the end of the file
392 maxsize -= ZIP_END_CDIR_SIZE;
393 ptr = &buffer[maxsize];
395 while (BuffBigLong (ptr) != ZIP_END_HEADER)
407 memcpy (eocd, ptr, ZIP_END_CDIR_SIZE);
408 eocd->signature = LittleLong (eocd->signature);
409 eocd->disknum = LittleShort (eocd->disknum);
410 eocd->cdir_disknum = LittleShort (eocd->cdir_disknum);
411 eocd->localentries = LittleShort (eocd->localentries);
412 eocd->nbentries = LittleShort (eocd->nbentries);
413 eocd->cdir_size = LittleLong (eocd->cdir_size);
414 eocd->cdir_offset = LittleLong (eocd->cdir_offset);
415 eocd->comment_size = LittleShort (eocd->comment_size);
427 Extract the file list from a PK3 file
430 int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd)
432 qbyte *central_dir, *ptr;
436 // Load the central directory in memory
437 central_dir = Mem_Alloc (tempmempool, eocd->cdir_size);
438 fseek (pack->handle, eocd->cdir_offset, SEEK_SET);
439 fread (central_dir, 1, eocd->cdir_size, pack->handle);
441 // Extract the files properties
442 // The parsing is done "by hand" because some fields have variable sizes and
443 // the constant part isn't 4-bytes aligned, which makes the use of structs difficult
444 remaining = eocd->cdir_size;
447 for (ind = 0; ind < eocd->nbentries; ind++)
449 size_t namesize, count;
452 // Checking the remaining size
453 if (remaining < ZIP_CDIR_CHUNK_BASE_SIZE)
455 Mem_Free (central_dir);
458 remaining -= ZIP_CDIR_CHUNK_BASE_SIZE;
461 if (BuffBigLong (ptr) != ZIP_CDIR_HEADER)
463 Mem_Free (central_dir);
467 namesize = BuffLittleShort (&ptr[28]); // filename length
469 // Check encryption, compression, and attributes
470 // 1st uint8 : general purpose bit flag
471 // Check bits 0 (encryption), 3 (data descriptor after the file), and 5 (compressed patched data (?))
472 // 2nd uint8 : external file attributes
473 // Check bits 3 (file is a directory) and 5 (file is a volume (?))
474 if ((ptr[8] & 0x29) == 0 && (ptr[38] & 0x18) == 0)
476 // Still enough bytes for the name?
477 if (remaining < namesize || namesize >= sizeof (*pack->files))
479 Mem_Free (central_dir);
483 // WinZip doesn't use the "directory" attribute, so we need to check the name directly
484 if (ptr[ZIP_CDIR_CHUNK_BASE_SIZE + namesize - 1] != '/')
487 file = &pack->files[pack->numfiles];
488 memcpy (file->name, &ptr[ZIP_CDIR_CHUNK_BASE_SIZE], namesize);
489 file->name[namesize] = '\0';
491 // Compression, sizes and offset
492 if (BuffLittleShort (&ptr[10]))
493 file->flags = FILE_FLAG_DEFLATED;
494 file->packsize = BuffLittleLong (&ptr[20]);
495 file->realsize = BuffLittleLong (&ptr[24]);
496 file->offset = BuffLittleLong (&ptr[42]);
502 // Skip the name, additionnal field, and comment
503 // 1er uint16 : extra field length
504 // 2eme uint16 : file comment length
505 count = namesize + BuffLittleShort (&ptr[30]) + BuffLittleShort (&ptr[32]);
506 ptr += ZIP_CDIR_CHUNK_BASE_SIZE + count;
510 Mem_Free (central_dir);
511 return pack->numfiles;
519 Create a package entry associated with a PK3 file
522 pack_t *FS_LoadPackPK3 (const char *packfile)
525 pk3_endOfCentralDir_t eocd;
529 packhandle = fopen (packfile, "rb");
533 if (! PK3_GetEndOfCentralDir (packfile, packhandle, &eocd))
534 Sys_Error ("%s is not a PK3 file", packfile);
536 // Multi-volume ZIP archives are NOT allowed
537 if (eocd.disknum != 0 || eocd.cdir_disknum != 0)
538 Sys_Error ("%s is a multi-volume ZIP archive", packfile);
540 if (eocd.nbentries > MAX_FILES_IN_PACK)
541 Sys_Error ("%s contains too many files (%hu)", packfile, eocd.nbentries);
543 // Create a package structure in memory
544 pack = Mem_Alloc (pak_mempool, sizeof (pack_t));
545 strcpy (pack->filename, packfile);
546 pack->handle = packhandle;
547 pack->numfiles = eocd.nbentries;
548 pack->mempool = Mem_AllocPool (packfile);
549 pack->files = Mem_Alloc (pack->mempool, eocd.nbentries * sizeof(packfile_t));
550 pack->next = packlist;
553 real_nb_files = PK3_BuildFileList (pack, &eocd);
554 if (real_nb_files <= 0)
555 Sys_Error ("%s is not a valid PK3 file", packfile);
557 Con_Printf ("Added packfile %s (%i files)\n", packfile, real_nb_files);
564 PK3_GetTrueFileOffset
566 Find where the true file data offset is
569 void PK3_GetTrueFileOffset (packfile_t *file, pack_t *pack)
571 qbyte buffer [ZIP_LOCAL_CHUNK_BASE_SIZE];
575 if (file->flags & FILE_FLAG_TRUEOFFS)
578 // Load the local file description
579 fseek (pack->handle, file->offset, SEEK_SET);
580 count = fread (buffer, 1, ZIP_LOCAL_CHUNK_BASE_SIZE, pack->handle);
581 if (count != ZIP_LOCAL_CHUNK_BASE_SIZE || BuffBigLong (buffer) != ZIP_DATA_HEADER)
582 Sys_Error ("Can't retrieve file %s in package %s", file->name, pack->filename);
584 // Skip name and extra field
585 file->offset += BuffLittleShort (&buffer[26]) + BuffLittleShort (&buffer[28]) + ZIP_LOCAL_CHUNK_BASE_SIZE;
587 file->flags |= FILE_FLAG_TRUEOFFS;
592 =============================================================================
594 OTHER PRIVATE FUNCTIONS
596 =============================================================================
604 Only used for FS_WriteFile.
607 void FS_CreatePath (char *path)
611 for (ofs = path+1 ; *ofs ; ofs++)
613 if (*ofs == '/' || *ofs == '\\')
615 // create the directory
631 void FS_Path_f (void)
635 Con_Printf ("Current search path:\n");
636 for (s=fs_searchpaths ; s ; s=s->next)
640 Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
643 Con_Printf ("%s\n", s->filename);
652 Takes an explicit (not game tree related) path to a pak file.
654 Loads the header and directory, adding the files at the beginning
655 of the list so they override previous pack files.
658 pack_t *FS_LoadPackPAK (const char *packfile)
660 dpackheader_t header;
664 dpackfile_t *info; // temporary alloc, allowing huge pack directories
666 packhandle = fopen (packfile, "rb");
670 fread ((void *)&header, 1, sizeof(header), packhandle);
671 if (memcmp(header.id, "PACK", 4))
672 Sys_Error ("%s is not a packfile", packfile);
673 header.dirofs = LittleLong (header.dirofs);
674 header.dirlen = LittleLong (header.dirlen);
676 if (header.dirlen % sizeof(dpackfile_t))
677 Sys_Error ("%s has an invalid directory size", packfile);
679 numpackfiles = header.dirlen / sizeof(dpackfile_t);
681 if (numpackfiles > MAX_FILES_IN_PACK)
682 Sys_Error ("%s has %i files", packfile, numpackfiles);
684 pack = Mem_Alloc(pak_mempool, sizeof (pack_t));
685 strcpy (pack->filename, packfile);
686 pack->handle = packhandle;
687 pack->numfiles = numpackfiles;
688 pack->mempool = Mem_AllocPool(packfile);
689 pack->files = Mem_Alloc(pack->mempool, numpackfiles * sizeof(packfile_t));
690 pack->next = packlist;
693 info = Mem_Alloc(tempmempool, sizeof(*info) * numpackfiles);
694 fseek (packhandle, header.dirofs, SEEK_SET);
695 fread ((void *)info, 1, header.dirlen, packhandle);
697 // parse the directory
698 for (i = 0;i < numpackfiles;i++)
701 packfile_t *file = &pack->files[i];
703 strcpy (file->name, info[i].name);
704 file->offset = LittleLong(info[i].filepos);
705 size = LittleLong (info[i].filelen);
706 file->packsize = size;
707 file->realsize = size;
708 file->flags = FILE_FLAG_TRUEOFFS;
713 Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
722 Sets fs_gamedir, adds the directory to the head of the path,
723 then loads and adds pak1.pak pak2.pak ...
726 void FS_AddGameDirectory (char *dir)
728 stringlist_t *list, *current;
729 searchpath_t *search;
731 char pakfile[MAX_OSPATH];
733 strcpy (fs_gamedir, dir);
735 // add the directory to the search path
736 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
737 strcpy (search->filename, dir);
738 search->next = fs_searchpaths;
739 fs_searchpaths = search;
741 list = listdirectory(dir);
743 // add any PAK package in the directory
744 for (current = list;current;current = current->next)
746 if (matchpattern(current->text, "*.pak", true))
748 sprintf (pakfile, "%s/%s", dir, current->text);
749 pak = FS_LoadPackPAK (pakfile);
752 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
754 search->next = fs_searchpaths;
755 fs_searchpaths = search;
758 Con_Printf("unable to load pak \"%s\"\n", pakfile);
762 // add any PK3 package in the director
763 for (current = list;current;current = current->next)
765 if (matchpattern(current->text, "*.pk3", true))
767 sprintf (pakfile, "%s/%s", dir, current->text);
768 pak = FS_LoadPackPK3 (pakfile);
771 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
773 search->next = fs_searchpaths;
774 fs_searchpaths = search;
777 Con_Printf("unable to load pak \"%s\"\n", pakfile);
789 char *FS_FileExtension (const char *in)
791 static char exten[8];
794 while (*in && *in != '.')
799 for (i=0 ; i<7 && *in ; i++,in++)
814 searchpath_t *search;
816 fs_mempool = Mem_AllocPool("file management");
817 pak_mempool = Mem_AllocPool("paks");
819 Cmd_AddCommand ("path", FS_Path_f);
821 strcpy(fs_basedir, ".");
826 // Overrides the system supplied base directory (under GAMENAME)
827 i = COM_CheckParm ("-basedir");
828 if (i && i < com_argc-1)
829 strcpy (fs_basedir, com_argv[i+1]);
831 i = strlen (fs_basedir);
832 if (i > 0 && (fs_basedir[i-1] == '\\' || fs_basedir[i-1] == '/'))
835 // start up with GAMENAME by default (id1)
836 strcpy(com_modname, GAMENAME);
837 FS_AddGameDirectory (va("%s/"GAMENAME, fs_basedir));
841 strcpy(com_modname, gamedirname);
842 FS_AddGameDirectory (va("%s/%s", fs_basedir, gamedirname));
846 // Adds basedir/gamedir as an override game
847 i = COM_CheckParm ("-game");
848 if (i && i < com_argc-1)
851 strcpy(com_modname, com_argv[i+1]);
852 FS_AddGameDirectory (va("%s/%s", fs_basedir, com_argv[i+1]));
855 // -path <dir or packfile> [<dir or packfile>] ...
856 // Fully specifies the exact search path, overriding the generated one
857 i = COM_CheckParm ("-path");
861 fs_searchpaths = NULL;
862 while (++i < com_argc)
864 if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')
867 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
868 if (!strcasecmp (FS_FileExtension(com_argv[i]), "pak"))
870 search->pack = FS_LoadPackPAK (com_argv[i]);
872 Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
874 else if (!strcasecmp (FS_FileExtension (com_argv[i]), "pk3"))
876 search->pack = FS_LoadPackPK3 (com_argv[i]);
878 Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
881 strcpy (search->filename, com_argv[i]);
882 search->next = fs_searchpaths;
883 fs_searchpaths = search;
893 Internal function used to create a qfile_t and open the relevant file on disk
896 static qfile_t* FS_SysOpen (const char* filepath, const char* mode)
900 file = Mem_Alloc (fs_mempool, sizeof (*file));
901 memset (file, 0, sizeof (*file));
903 file->stream = fopen (filepath, mode);
919 qfile_t *FS_OpenRead (const char *path, int offs, int len)
923 file = FS_SysOpen (path, "rb");
926 Sys_Error ("Couldn't open %s", path);
931 if (offs < 0 || len < 0)
933 // We set fs_filesize here for normal files
934 fseek (file->stream, 0, SEEK_END);
935 fs_filesize = ftell (file->stream);
936 fseek (file->stream, 0, SEEK_SET);
941 fseek (file->stream, offs, SEEK_SET);
943 file->flags |= FS_FLAG_PACKED;
956 If the requested file is inside a packfile, a new qfile_t* will be opened
962 qfile_t *FS_FOpenFile (const char *filename, qboolean quiet)
964 searchpath_t *search;
965 char netpath[MAX_OSPATH];
969 filenamelen = strlen (filename);
971 // search through the path, one element at a time
972 search = fs_searchpaths;
974 for ( ; search ; search = search->next)
976 // is the element a pak file?
979 // look through all the pak file elements
981 for (i=0 ; i<pak->numfiles ; i++)
982 if (!strcmp (pak->files[i].name, filename)) // found it?
987 Sys_Printf ("PackFile: %s : %s\n",pak->filename, pak->files[i].name);
989 // If we don't have the true offset, get it now
990 if (! (pak->files[i].flags & FILE_FLAG_TRUEOFFS))
991 PK3_GetTrueFileOffset (&pak->files[i], pak);
993 // No Zlib DLL = no compressed files
994 if (!zlib_dll && (pak->files[i].flags & FILE_FLAG_DEFLATED))
996 Con_Printf ("WARNING: can't open the compressed file %s\n"
997 "You need the Zlib DLL to use compressed files\n", filename);
1002 // open a new file in the pakfile
1003 file = FS_OpenRead (pak->filename, pak->files[i].offset, pak->files[i].packsize);
1004 fs_filesize = pak->files[i].realsize;
1006 if (pak->files[i].flags & FILE_FLAG_DEFLATED)
1010 file->flags |= FS_FLAG_DEFLATED;
1012 // We need some more variables
1013 ztk = Mem_Alloc (fs_mempool, sizeof (*file->z));
1015 ztk->real_length = pak->files[i].realsize;
1017 // Initialize zlib stream
1018 ztk->zstream.next_in = ztk->input;
1019 ztk->zstream.avail_in = 0;
1021 /* From Zlib's "unzip.c":
1023 * windowBits is passed < 0 to tell that there is no zlib header.
1024 * Note that in this case inflate *requires* an extra "dummy" byte
1025 * after the compressed stream in order to complete decompression and
1026 * return Z_STREAM_END.
1027 * In unzip, i don't wait absolutely Z_STREAM_END because I known the
1028 * size of both compressed and uncompressed data
1030 if (qz_inflateInit2 (&ztk->zstream, -MAX_WBITS) != Z_OK)
1031 Sys_Error ("inflate init error (file: %s)", filename);
1033 ztk->zstream.next_out = ztk->output;
1034 ztk->zstream.avail_out = sizeof (ztk->output);
1044 sprintf (netpath, "%s/%s",search->filename, filename);
1046 if (!FS_SysFileExists (netpath))
1050 Sys_Printf ("FindFile: %s\n",netpath);
1051 return FS_OpenRead (netpath, -1, -1);
1056 Sys_Printf ("FindFile: can't find %s\n", filename);
1064 =============================================================================
1066 MAIN PUBLIC FUNCTIONS
1068 =============================================================================
1072 ====================
1075 Open a file. The syntax is the same as fopen
1076 ====================
1078 qfile_t* FS_Open (const char* filepath, const char* mode, qboolean quiet)
1080 // If the file is opened in "write" or "append" mode
1081 if (strchr (mode, 'w') || strchr (mode, 'a'))
1083 char real_path [MAX_OSPATH];
1085 // Open the file on disk directly
1086 snprintf (real_path, sizeof (real_path), "%s/%s", fs_gamedir, filepath);
1088 // Create directories up to the file
1089 FS_CreatePath (real_path);
1091 return FS_SysOpen (real_path, mode);
1094 // Else, we look at the various search paths
1095 return FS_FOpenFile (filepath, quiet);
1100 ====================
1104 ====================
1106 int FS_Close (qfile_t* file)
1108 if (fclose (file->stream))
1113 qz_inflateEnd (&file->z->zstream);
1123 ====================
1126 Write "datasize" bytes into a file
1127 ====================
1129 size_t FS_Write (qfile_t* file, const void* data, size_t datasize)
1131 return fwrite (data, 1, datasize, file->stream);
1136 ====================
1139 Read up to "buffersize" bytes from a file
1140 ====================
1142 size_t FS_Read (qfile_t* file, void* buffer, size_t buffersize)
1147 // Quick path for unpacked files
1148 if (! (file->flags & FS_FLAG_PACKED))
1149 return fread (buffer, 1, buffersize, file->stream);
1151 // If the file isn't compressed
1152 if (! (file->flags & FS_FLAG_DEFLATED))
1154 // We must take care to not read after the end of the file
1155 count = file->length - file->position;
1156 if (buffersize > count)
1159 nb = fread (buffer, 1, buffersize, file->stream);
1161 // Update the position index if the file is packed
1162 file->position += nb;
1167 // If the file is compressed, it's more complicated...
1170 // First, we copy as many bytes as we can from "output"
1171 if (ztk->out_ind < ztk->out_max)
1173 count = ztk->out_max - ztk->out_ind;
1175 nb = (buffersize > count) ? count : buffersize;
1176 memcpy (buffer, &ztk->output[ztk->out_ind], nb);
1182 // We cycle through a few operations until we have inflated enough data
1183 while (nb < buffersize)
1185 // NOTE: at this point, "output" should always be empty
1187 // If "input" is also empty, we need to fill it
1188 if (ztk->in_ind == ztk->in_max)
1190 size_t remain = file->length - file->position;
1192 // If we are at the end of the file
1196 count = (remain > sizeof (ztk->input)) ? sizeof (ztk->input) : remain;
1197 fread (ztk->input, 1, count, file->stream);
1199 // Update indexes and counters
1201 ztk->in_max = count;
1202 file->position += count;
1205 // Now that we are sure we have compressed data available, we need to determine
1206 // if it's better to inflate it in "output" or directly in "buffer" (we are in this
1207 // case if we still need more bytes than "output" can contain)
1209 ztk->zstream.next_in = &ztk->input[ztk->in_ind];
1210 ztk->zstream.avail_in = ztk->in_max - ztk->in_ind;
1212 // If output will be able to contain at least 1 more byte than the data we need
1213 if (buffersize - nb < sizeof (ztk->output))
1217 // Inflate the data in "output"
1218 ztk->zstream.next_out = ztk->output;
1219 ztk->zstream.avail_out = sizeof (ztk->output);
1220 error = qz_inflate (&ztk->zstream, Z_SYNC_FLUSH);
1221 if (error != Z_OK && error != Z_STREAM_END)
1222 Sys_Error ("Can't inflate file");
1223 ztk->in_ind = ztk->in_max - ztk->zstream.avail_in;
1224 ztk->out_max = sizeof (ztk->output) - ztk->zstream.avail_out;
1226 ztk->out_position += ztk->out_max;
1228 // Copy the requested data in "buffer" (as much as we can)
1229 count = (buffersize - nb > ztk->out_max) ? ztk->out_max : buffersize - nb;
1230 memcpy (&((qbyte*)buffer)[nb], ztk->output, count);
1231 ztk->out_ind = count;
1234 // Else, we inflate directly in "buffer"
1239 // Inflate the data in "buffer"
1240 ztk->zstream.next_out = &((qbyte*)buffer)[nb];
1241 ztk->zstream.avail_out = buffersize - nb;
1242 error = qz_inflate (&ztk->zstream, Z_SYNC_FLUSH);
1243 if (error != Z_OK && error != Z_STREAM_END)
1244 Sys_Error ("Can't inflate file");
1245 ztk->in_ind = ztk->in_max - ztk->zstream.avail_in;
1247 // Invalidate the output data (for FS_Seek)
1251 // How much data did it inflate?
1252 count = buffersize - nb - ztk->zstream.avail_out;
1253 ztk->out_position += count;
1264 ====================
1267 Flush the file output stream
1268 ====================
1270 int FS_Flush (qfile_t* file)
1272 return fflush (file->stream);
1277 ====================
1280 Print a string into a file
1281 ====================
1283 int FS_Printf (qfile_t* file, const char* format, ...)
1288 va_start (args, format);
1289 result = vfprintf (file->stream, format, args);
1297 ====================
1300 Get the next character of a file
1301 ====================
1303 int FS_Getc (qfile_t* file)
1307 if (FS_Read (file, &c, 1) != 1)
1315 ====================
1318 Move the position index in a file
1319 ====================
1321 int FS_Seek (qfile_t* file, long offset, int whence)
1323 // Quick path for unpacked files
1324 if (! (file->flags & FS_FLAG_PACKED))
1325 return fseek (file->stream, offset, whence);
1327 // Seeking in compressed files is more a hack than anything else,
1328 // but we need to support it, so here it is.
1329 if (file->flags & FS_FLAG_DEFLATED)
1331 ztoolkit_t *ztk = file->z;
1333 qbyte buffer [sizeof (ztk->output)]; // it's big to force inflating into buffer directly
1335 crt_offset = ztk->out_position - ztk->out_max + ztk->out_ind;
1340 offset += crt_offset;
1347 offset += ztk->real_length;
1354 // If we need to go back in the file
1355 if (offset <= crt_offset)
1357 // If we still have the data we need in the output buffer
1358 if (crt_offset - offset <= ztk->out_ind)
1360 ztk->out_ind -= crt_offset - offset;
1364 // Else, we restart from the beginning of the file
1370 ztk->out_position = 0;
1372 fseek (file->stream, file->offset, SEEK_SET);
1374 // Reset the Zlib stream
1375 ztk->zstream.next_in = ztk->input;
1376 ztk->zstream.avail_in = 0;
1377 qz_inflateReset (&ztk->zstream);
1380 // Skip all data until we reach the requested offset
1381 while (crt_offset < offset)
1383 size_t diff = offset - crt_offset;
1386 count = (diff > sizeof (buffer)) ? sizeof (buffer) : diff;
1387 len = FS_Read (file, buffer, count);
1396 // Packed files receive a special treatment too, because
1397 // we need to make sure it doesn't go outside of the file
1401 offset += file->position;
1408 offset += file->length;
1414 if (offset < 0 || offset > file->length)
1417 if (fseek (file->stream, file->offset + offset, SEEK_SET) == -1)
1419 file->position = offset;
1425 ====================
1428 Give the current position in a file
1429 ====================
1431 long FS_Tell (qfile_t* file)
1433 if (file->flags & FS_FLAG_PACKED)
1435 if (file->flags & FS_FLAG_DEFLATED)
1437 ztoolkit_t *ztk = file->z;
1438 return ztk->out_position - ztk->out_max + ztk->out_ind;
1441 return file->position;
1444 return ftell (file->stream);
1449 ====================
1452 Extract a line from a file
1453 ====================
1455 char* FS_Gets (qfile_t* file, char* buffer, int buffersize)
1459 // Quick path for unpacked files
1460 if (! (file->flags & FS_FLAG_PACKED))
1461 return fgets (buffer, buffersize, file->stream);
1463 for (ind = 0; ind < buffersize - 1; ind++)
1465 int c = FS_Getc (file);
1480 buffer[ind + 1] = '\0';
1489 buffer[buffersize - 1] = '\0';
1498 Dynamic length version of fgets. DO NOT free the buffer.
1501 char *FS_Getline (qfile_t *file)
1503 static int size = 256;
1504 static char *buf = 0;
1509 buf = Mem_Alloc (fs_mempool, size);
1511 if (!FS_Gets (file, buf, size))
1515 while (buf[len - 1] != '\n' && buf[len - 1] != '\r')
1517 t = Mem_Alloc (fs_mempool, size + 256);
1518 memcpy(t, buf, size);
1522 if (!FS_Gets (file, buf + len, size - len))
1526 while ((len = strlen(buf)) && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
1533 ====================
1536 Extract a line from a file
1537 ====================
1539 int FS_Eof (qfile_t* file)
1541 if (file->flags & FS_FLAG_PACKED)
1543 if (file->flags & FS_FLAG_DEFLATED)
1545 ztoolkit_t *ztk = file->z;
1546 return (ztk->out_position - ztk->out_max + ztk->out_ind == ztk->real_length);
1549 return (file->position == file->length);
1552 return feof (file->stream);
1560 Filename are relative to the quake directory.
1561 Always appends a 0 byte.
1564 qbyte *FS_LoadFile (const char *path, qboolean quiet)
1569 // look for it in the filesystem or pack files
1570 h = FS_Open (path, "rb", quiet);
1574 buf = Mem_Alloc(tempmempool, fs_filesize+1);
1576 Sys_Error ("FS_LoadFile: not enough available memory for %s (size %i)", path, fs_filesize);
1578 ((qbyte *)buf)[fs_filesize] = 0;
1580 FS_Read (h, buf, fs_filesize);
1591 The filename will be prefixed by the current game directory
1594 qboolean FS_WriteFile (const char *filename, void *data, int len)
1597 char name[MAX_OSPATH];
1599 sprintf (name, "%s/%s", fs_gamedir, filename);
1601 // Create directories up to the file
1602 FS_CreatePath (name);
1604 handle = fopen (name, "wb");
1607 Con_Printf ("FS_WriteFile: failed on %s\n", name);
1611 Con_DPrintf ("FS_WriteFile: %s\n", name);
1612 fwrite (data, 1, len, handle);
1619 =============================================================================
1621 OTHERS PUBLIC FUNCTIONS
1623 =============================================================================
1631 void FS_StripExtension (const char *in, char *out)
1638 else if (*in == '/' || *in == '\\' || *in == ':')
1654 void FS_DefaultExtension (char *path, const char *extension)
1658 // if path doesn't have a .EXT, append extension
1659 // (extension should include the .)
1660 src = path + strlen(path) - 1;
1662 while (*src != '/' && src != path)
1665 return; // it has an extension
1669 strcat (path, extension);
1673 qboolean FS_FileExists (const char *filename)
1675 searchpath_t *search;
1676 char netpath[MAX_OSPATH];
1680 for (search = fs_searchpaths;search;search = search->next)
1685 for (i = 0;i < pak->numfiles;i++)
1686 if (!strcmp (pak->files[i].name, filename))
1691 sprintf (netpath, "%s/%s",search->filename, filename);
1692 if (FS_SysFileExists (netpath))
1701 qboolean FS_SysFileExists (const char *path)
1706 f = fopen (path, "rb");
1717 if (stat (path,&buf) == -1)
1724 void FS_mkdir (const char *path)