X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=fs.c;h=67ffa9fd2cf34056a3a3eb8e6113ac48edcfcb8f;hp=c6742d390f527d0ac44c2ac2d3f4346d036b3497;hb=f9d8bc7ea04ff91fcbd90fe50a299b37724b349b;hpb=5e50ce0968fe5404bc5872337ed882f2505dcc9c diff --git a/fs.c b/fs.c index c6742d39..67ffa9fd 100644 --- a/fs.c +++ b/fs.c @@ -2,7 +2,6 @@ DarkPlaces file system Copyright (C) 2003-2005 Mathieu Olivier - Copyright (C) 1999,2000 contributors of the QuakeForge project This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -44,6 +43,11 @@ # define O_BINARY 0 #endif +// In case the system doesn't support the O_NONBLOCK flag +#ifndef O_NONBLOCK +# define O_NONBLOCK 0 +#endif + /* @@ -90,7 +94,11 @@ CONSTANTS #define MAX_WBITS 15 #define Z_OK 0 #define Z_STREAM_END 1 -#define ZLIB_VERSION "1.1.4" +#define ZLIB_VERSION "1.2.3" + +// Uncomment the following line if the zlib DLL you have still uses +// the 1.1.x series calling convention on Win32 (WINAPI) +//#define ZLIB_USES_WINAPI /* @@ -127,12 +135,10 @@ typedef struct } z_stream; -typedef enum -{ - QFILE_FLAG_NONE = 0, - QFILE_FLAG_PACKED = (1 << 0), // inside a package (PAK or PK3) - QFILE_FLAG_DEFLATED = (1 << 1) // file is compressed using the deflate algorithm (PK3 only) -} qfile_flags_t; +// inside a package (PAK or PK3) +#define QFILE_FLAG_PACKED (1 << 0) +// file is compressed using the deflate algorithm (PK3 only) +#define QFILE_FLAG_DEFLATED (1 << 1) #define FILE_BUFF_SIZE 2048 typedef struct @@ -146,15 +152,15 @@ typedef struct struct qfile_s { - qfile_flags_t flags; + int flags; int handle; // file descriptor - size_t real_length; // uncompressed file size (for files opened in "read" mode) - size_t position; // current position in the file - size_t offset; // offset into the package (0 if external file) + fs_offset_t real_length; // uncompressed file size (for files opened in "read" mode) + fs_offset_t position; // current position in the file + fs_offset_t offset; // offset into the package (0 if external file) int ungetc; // single stored character from ungetc, cleared to EOF when read // Contents buffer - size_t buff_ind, buff_len; // buffer current index and length + fs_offset_t buff_ind, buff_len; // buffer current index and length qbyte buff [FILE_BUFF_SIZE]; // For zipped files @@ -166,7 +172,7 @@ struct qfile_s // You can get the complete ZIP format description from PKWARE website -typedef struct +typedef struct pk3_endOfCentralDir_s { unsigned int signature; unsigned short disknum; @@ -180,13 +186,13 @@ typedef struct // ------ PAK files on disk ------ // -typedef struct +typedef struct dpackfile_s { char name[56]; int filepos, filelen; } dpackfile_t; -typedef struct +typedef struct dpackheader_s { char id[4]; int dirofs; @@ -195,20 +201,18 @@ typedef struct // Packages in memory -typedef enum -{ - PACKFILE_FLAG_NONE = 0, - PACKFILE_FLAG_TRUEOFFS = (1 << 0), // the offset in packfile_t is the true contents offset - PACKFILE_FLAG_DEFLATED = (1 << 1) // file compressed using the deflate algorithm -} packfile_flags_t; +// the offset in packfile_t is the true contents offset +#define PACKFILE_FLAG_TRUEOFFS (1 << 0) +// file compressed using the deflate algorithm +#define PACKFILE_FLAG_DEFLATED (1 << 1) -typedef struct +typedef struct packfile_s { char name [MAX_QPATH]; - packfile_flags_t flags; - size_t offset; - size_t packsize; // size in the package - size_t realsize; // real file size (uncompressed) + int flags; + fs_offset_t offset; + fs_offset_t packsize; // size in the package + fs_offset_t realsize; // real file size (uncompressed) } packfile_t; typedef struct pack_s @@ -218,7 +222,6 @@ typedef struct pack_s int ignorecase; // PK3 ignores case int numfiles; packfile_t *files; - mempool_t *mempool; struct pack_s *next; } pack_t; @@ -245,8 +248,8 @@ void FS_Dir_f(void); void FS_Ls_f(void); static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack, - size_t offset, size_t packsize, - size_t realsize, packfile_flags_t flags); + fs_offset_t offset, fs_offset_t packsize, + fs_offset_t realsize, int flags); /* @@ -258,9 +261,8 @@ VARIABLES */ mempool_t *fs_mempool; -mempool_t *pak_mempool; -int fs_filesize; +fs_offset_t fs_filesize; pack_t *packlist = NULL; @@ -273,6 +275,8 @@ char fs_basedir[MAX_OSPATH]; qboolean fs_modified; // set true if using non-id files +cvar_t scr_screenshot_name = {0, "scr_screenshot_name","dp"}; + /* ============================================================================= @@ -283,7 +287,7 @@ PRIVATE FUNCTIONS - PK3 HANDLING */ // Functions exported from zlib -#ifdef WIN32 +#if defined(WIN32) && defined(ZLIB_USES_WINAPI) # define ZEXPORT WINAPI #else # define ZEXPORT @@ -334,8 +338,15 @@ qboolean PK3_OpenLibrary (void) { const char* dllnames [] = { -#ifdef WIN32 +#if defined(WIN64) + "zlib64.dll", +#elif defined(WIN32) +# ifdef ZLIB_USES_WINAPI + "zlibwapi.dll", "zlib.dll", +# else + "zlib1.dll", +# endif #elif defined(MACOSX) "libz.dylib", #else @@ -384,9 +395,9 @@ qboolean PK3_GetEndOfCentralDir (const char *packfile, int packhandle, pk3_endOf maxsize = filesize; else maxsize = ZIP_MAX_COMMENTS_SIZE + ZIP_END_CDIR_SIZE; - buffer = Mem_Alloc (tempmempool, maxsize); + buffer = (qbyte *)Mem_Alloc (tempmempool, maxsize); lseek (packhandle, filesize - maxsize, SEEK_SET); - if (read (packhandle, buffer, maxsize) != (ssize_t) maxsize) + if (read (packhandle, buffer, maxsize) != (fs_offset_t) maxsize) { Mem_Free (buffer); return false; @@ -435,10 +446,10 @@ int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd) { qbyte *central_dir, *ptr; unsigned int ind; - int remaining; + fs_offset_t remaining; // Load the central directory in memory - central_dir = Mem_Alloc (tempmempool, eocd->cdir_size); + central_dir = (qbyte *)Mem_Alloc (tempmempool, eocd->cdir_size); lseek (pack->handle, eocd->cdir_offset, SEEK_SET); read (pack->handle, central_dir, eocd->cdir_size); @@ -450,7 +461,7 @@ int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd) ptr = central_dir; for (ind = 0; ind < eocd->nbentries; ind++) { - size_t namesize, count; + fs_offset_t namesize, count; // Checking the remaining size if (remaining < ZIP_CDIR_CHUNK_BASE_SIZE) @@ -477,7 +488,7 @@ int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd) if ((ptr[8] & 0x29) == 0 && (ptr[38] & 0x18) == 0) { // Still enough bytes for the name? - if ((size_t) remaining < namesize || namesize >= sizeof (*pack->files)) + if (remaining < namesize || namesize >= (int)sizeof (*pack->files)) { Mem_Free (central_dir); return -1; @@ -487,12 +498,11 @@ int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd) if (ptr[ZIP_CDIR_CHUNK_BASE_SIZE + namesize - 1] != '/') { char filename [sizeof (pack->files[0].name)]; - size_t offset, packsize, realsize; - packfile_flags_t flags; + fs_offset_t offset, packsize, realsize; + int flags; // Extract the name (strip it if necessary) - if (namesize >= sizeof (filename)) - namesize = sizeof (filename) - 1; + namesize = min(namesize, (int)sizeof (filename) - 1); memcpy (filename, &ptr[ZIP_CDIR_CHUNK_BASE_SIZE], namesize); filename[namesize] = '\0'; @@ -541,33 +551,49 @@ pack_t *FS_LoadPackPK3 (const char *packfile) return NULL; if (! PK3_GetEndOfCentralDir (packfile, packhandle, &eocd)) - Sys_Error ("%s is not a PK3 file", packfile); + { + Con_Printf ("%s is not a PK3 file", packfile); + close(packhandle); + return NULL; + } // Multi-volume ZIP archives are NOT allowed if (eocd.disknum != 0 || eocd.cdir_disknum != 0) - Sys_Error ("%s is a multi-volume ZIP archive", packfile); + { + Con_Printf ("%s is a multi-volume ZIP archive", packfile); + close(packhandle); + return NULL; + } // We only need to do this test if MAX_FILES_IN_PACK is lesser than 65535 // since eocd.nbentries is an unsigned 16 bits integer #if MAX_FILES_IN_PACK < 65535 if (eocd.nbentries > MAX_FILES_IN_PACK) - Sys_Error ("%s contains too many files (%hu)", packfile, eocd.nbentries); + { + Con_Printf ("%s contains too many files (%hu)", packfile, eocd.nbentries); + close(packhandle); + return NULL; + } #endif // Create a package structure in memory - pack = Mem_Alloc (pak_mempool, sizeof (pack_t)); + pack = (pack_t *)Mem_Alloc(fs_mempool, sizeof (pack_t)); pack->ignorecase = true; // PK3 ignores case strlcpy (pack->filename, packfile, sizeof (pack->filename)); pack->handle = packhandle; pack->numfiles = eocd.nbentries; - pack->mempool = Mem_AllocPool (packfile, 0, NULL); - pack->files = Mem_Alloc (pack->mempool, eocd.nbentries * sizeof(packfile_t)); + pack->files = (packfile_t *)Mem_Alloc(fs_mempool, eocd.nbentries * sizeof(packfile_t)); pack->next = packlist; packlist = pack; real_nb_files = PK3_BuildFileList (pack, &eocd); if (real_nb_files < 0) - Sys_Error ("%s is not a valid PK3 file", packfile); + { + Con_Printf ("%s is not a valid PK3 file", packfile); + close(pack->handle); + Mem_Free(pack); + return NULL; + } Con_Printf("Added packfile %s (%i files)\n", packfile, real_nb_files); return pack; @@ -581,25 +607,29 @@ PK3_GetTrueFileOffset Find where the true file data offset is ==================== */ -void PK3_GetTrueFileOffset (packfile_t *pfile, pack_t *pack) +qboolean PK3_GetTrueFileOffset (packfile_t *pfile, pack_t *pack) { qbyte buffer [ZIP_LOCAL_CHUNK_BASE_SIZE]; - size_t count; + fs_offset_t count; // Already found? if (pfile->flags & PACKFILE_FLAG_TRUEOFFS) - return; + return true; // Load the local file description lseek (pack->handle, pfile->offset, SEEK_SET); count = read (pack->handle, buffer, ZIP_LOCAL_CHUNK_BASE_SIZE); if (count != ZIP_LOCAL_CHUNK_BASE_SIZE || BuffBigLong (buffer) != ZIP_DATA_HEADER) - Sys_Error ("Can't retrieve file %s in package %s", pfile->name, pack->filename); + { + Con_Printf ("Can't retrieve file %s in package %s", pfile->name, pack->filename); + return false; + } // Skip name and extra field pfile->offset += BuffLittleShort (&buffer[26]) + BuffLittleShort (&buffer[28]) + ZIP_LOCAL_CHUNK_BASE_SIZE; pfile->flags |= PACKFILE_FLAG_TRUEOFFS; + return true; } @@ -620,8 +650,8 @@ Add a file to the list of files contained into a package ==================== */ static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack, - size_t offset, size_t packsize, - size_t realsize, packfile_flags_t flags) + fs_offset_t offset, fs_offset_t packsize, + fs_offset_t realsize, int flags) { int (*strcmp_funct) (const char* str1, const char* str2); int left, right, middle; @@ -641,8 +671,7 @@ static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack, // If we found the file, there's a problem if (!diff) - Sys_Error ("Package %s contains the file %s several times\n", - pack->filename, name); + Con_Printf ("Package %s contains the file %s several times\n", pack->filename, name); // If we're too far in the list if (diff > 0) @@ -705,9 +734,7 @@ void FS_Path_f (void) for (s=fs_searchpaths ; s ; s=s->next) { if (s->pack) - { Con_Printf("%s (%i files)\n", s->pack->filename, s->pack->numfiles); - } else Con_Printf("%s\n", s->filename); } @@ -737,37 +764,48 @@ pack_t *FS_LoadPackPAK (const char *packfile) return NULL; read (packhandle, (void *)&header, sizeof(header)); if (memcmp(header.id, "PACK", 4)) - Sys_Error ("%s is not a packfile", packfile); + { + Con_Printf ("%s is not a packfile", packfile); + close(packhandle); + return NULL; + } header.dirofs = LittleLong (header.dirofs); header.dirlen = LittleLong (header.dirlen); if (header.dirlen % sizeof(dpackfile_t)) - Sys_Error ("%s has an invalid directory size", packfile); + { + Con_Printf ("%s has an invalid directory size", packfile); + close(packhandle); + return NULL; + } numpackfiles = header.dirlen / sizeof(dpackfile_t); if (numpackfiles > MAX_FILES_IN_PACK) - Sys_Error ("%s has %i files", packfile, numpackfiles); + { + Con_Printf ("%s has %i files", packfile, numpackfiles); + close(packhandle); + return NULL; + } - pack = Mem_Alloc(pak_mempool, sizeof (pack_t)); + pack = (pack_t *)Mem_Alloc(fs_mempool, sizeof (pack_t)); pack->ignorecase = false; // PAK is case sensitive strlcpy (pack->filename, packfile, sizeof (pack->filename)); pack->handle = packhandle; pack->numfiles = 0; - pack->mempool = Mem_AllocPool(packfile, 0, NULL); - pack->files = Mem_Alloc(pack->mempool, numpackfiles * sizeof(packfile_t)); + pack->files = (packfile_t *)Mem_Alloc(fs_mempool, numpackfiles * sizeof(packfile_t)); pack->next = packlist; packlist = pack; - info = Mem_Alloc(tempmempool, sizeof(*info) * numpackfiles); + info = (dpackfile_t *)Mem_Alloc(tempmempool, sizeof(*info) * numpackfiles); lseek (packhandle, header.dirofs, SEEK_SET); read (packhandle, (void *)info, header.dirlen); // parse the directory for (i = 0;i < numpackfiles;i++) { - size_t offset = LittleLong (info[i].filepos); - size_t size = LittleLong (info[i].filelen); + fs_offset_t offset = LittleLong (info[i].filepos); + fs_offset_t size = LittleLong (info[i].filelen); FS_AddFileToPack (info[i].name, pack, offset, size, size, PACKFILE_FLAG_TRUEOFFS); } @@ -803,11 +841,11 @@ void FS_AddGameDirectory (const char *dir) { if (matchpattern(current->text, "*.pak", true)) { - snprintf (pakfile, sizeof (pakfile), "%s/%s", dir, current->text); + dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, current->text); pak = FS_LoadPackPAK (pakfile); if (pak) { - search = Mem_Alloc(pak_mempool, sizeof(searchpath_t)); + search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); search->pack = pak; search->next = fs_searchpaths; fs_searchpaths = search; @@ -822,11 +860,11 @@ void FS_AddGameDirectory (const char *dir) { if (matchpattern(current->text, "*.pk3", true)) { - snprintf (pakfile, sizeof (pakfile), "%s/%s", dir, current->text); + dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, current->text); pak = FS_LoadPackPK3 (pakfile); if (pak) { - search = Mem_Alloc(pak_mempool, sizeof(searchpath_t)); + search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); search->pack = pak; search->next = fs_searchpaths; fs_searchpaths = search; @@ -839,7 +877,7 @@ void FS_AddGameDirectory (const char *dir) // Add the directory to the search path // (unpacked files have the priority over packed files) - search = Mem_Alloc(pak_mempool, sizeof(searchpath_t)); + search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); strlcpy (search->filename, dir, sizeof (search->filename)); search->next = fs_searchpaths; fs_searchpaths = search; @@ -853,17 +891,19 @@ FS_AddGameHierarchy */ void FS_AddGameHierarchy (const char *dir) { +#ifndef WIN32 const char *homedir; - - strlcpy (com_modname, dir, sizeof (com_modname)); +#endif // Add the common game directory - FS_AddGameDirectory (va("%s/%s", fs_basedir, dir)); + FS_AddGameDirectory (va("%s/%s/", fs_basedir, dir)); +#ifndef WIN32 // Add the personal game directory homedir = getenv ("HOME"); if (homedir != NULL && homedir[0] != '\0') - FS_AddGameDirectory (va("%s/.%s/%s", homedir, gameuserdirname, dir)); + FS_AddGameDirectory (va("%s/.%s/%s/", homedir, gameuserdirname, dir)); +#endif } @@ -903,16 +943,23 @@ void FS_Init (void) searchpath_t *search; fs_mempool = Mem_AllocPool("file management", 0, NULL); - pak_mempool = Mem_AllocPool("paks", 0, NULL); - Cvar_RegisterVariable (&scr_screenshot_name); + strcpy(fs_basedir, "."); + strcpy(fs_gamedir, ""); - Cmd_AddCommand ("path", FS_Path_f); - Cmd_AddCommand ("dir", FS_Dir_f); - Cmd_AddCommand ("ls", FS_Ls_f); +#ifdef MACOSX + // FIXME: is there a better way to find the directory outside the .app? + if (strstr(com_argv[0], ".app/")) + { + char *split; - strcpy(fs_basedir, "."); - strcpy(fs_gamedir, "."); + split = strstr(com_argv[0], ".app/"); + while (split > com_argv[0] && *split != '/') + split--; + strlcpy(fs_basedir, com_argv[0], sizeof(fs_basedir)); + fs_basedir[split - com_argv[0]] = 0; + } +#endif PK3_OpenLibrary (); @@ -923,7 +970,7 @@ void FS_Init (void) if (i && i < com_argc-1) { strlcpy (fs_basedir, com_argv[i+1], sizeof (fs_basedir)); - i = strlen (fs_basedir); + i = (int)strlen (fs_basedir); if (i > 0 && (fs_basedir[i-1] == '\\' || fs_basedir[i-1] == '/')) fs_basedir[i-1] = 0; } @@ -940,18 +987,26 @@ void FS_Init (void) if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-') break; - search = Mem_Alloc(pak_mempool, sizeof(searchpath_t)); + search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); if (!strcasecmp (FS_FileExtension(com_argv[i]), "pak")) { search->pack = FS_LoadPackPAK (com_argv[i]); if (!search->pack) - Sys_Error ("Couldn't load packfile: %s", com_argv[i]); + { + Con_Printf ("Couldn't load packfile: %s", com_argv[i]); + Mem_Free(search); + continue; + } } else if (!strcasecmp (FS_FileExtension (com_argv[i]), "pk3")) { search->pack = FS_LoadPackPK3 (com_argv[i]); if (!search->pack) - Sys_Error ("Couldn't load packfile: %s", com_argv[i]); + { + Con_Printf ("Couldn't load packfile: %s", com_argv[i]); + Mem_Free(search); + continue; + } } else strlcpy (search->filename, com_argv[i], sizeof (search->filename)); @@ -964,7 +1019,6 @@ void FS_Init (void) // add the game-specific paths // gamedirname1 (typically id1) FS_AddGameHierarchy (gamedirname1); - Cvar_SetQuick (&scr_screenshot_name, gamescreenshotname); // add the game-specific path, if any if (gamedirname2) @@ -973,6 +1027,9 @@ void FS_Init (void) FS_AddGameHierarchy (gamedirname2); } + // set the com_modname (reported in server info) + strlcpy(com_modname, gamedirname1, sizeof(com_modname)); + // -game // Adds basedir/gamedir as an override game // LordHavoc: now supports multiple -game directories @@ -985,7 +1042,8 @@ void FS_Init (void) i++; fs_modified = true; FS_AddGameHierarchy (com_argv[i]); - Cvar_SetQuick (&scr_screenshot_name, com_modname); + // update the com_modname + strlcpy (com_modname, com_argv[i], sizeof (com_modname)); } } @@ -994,6 +1052,22 @@ void FS_Init (void) unlink (va("%s/qconsole.log", fs_gamedir)); } +void FS_Init_Commands(void) +{ + Cvar_RegisterVariable (&scr_screenshot_name); + + Cmd_AddCommand ("path", FS_Path_f); + Cmd_AddCommand ("dir", FS_Dir_f); + Cmd_AddCommand ("ls", FS_Ls_f); + + // set the default screenshot name to either the mod name or the + // gamemode screenshot name + if (fs_modified) + Cvar_SetQuick (&scr_screenshot_name, com_modname); + else + Cvar_SetQuick (&scr_screenshot_name, gamescreenshotname); +} + /* ================ FS_Shutdown @@ -1001,7 +1075,6 @@ FS_Shutdown */ void FS_Shutdown (void) { - Mem_FreePool (&pak_mempool); Mem_FreePool (&fs_mempool); } @@ -1012,7 +1085,7 @@ FS_SysOpen Internal function used to create a qfile_t and open the relevant non-packed file on disk ==================== */ -static qfile_t* FS_SysOpen (const char* filepath, const char* mode) +static qfile_t* FS_SysOpen (const char* filepath, const char* mode, qboolean nonblocking) { qfile_t* file; int mod, opt; @@ -1053,7 +1126,10 @@ static qfile_t* FS_SysOpen (const char* filepath, const char* mode) } } - file = Mem_Alloc (fs_mempool, sizeof (*file)); + if (nonblocking) + opt |= O_NONBLOCK; + + file = (qfile_t *)Mem_Alloc (fs_mempool, sizeof (*file)); memset (file, 0, sizeof (*file)); file->ungetc = EOF; @@ -1064,12 +1140,13 @@ static qfile_t* FS_SysOpen (const char* filepath, const char* mode) return NULL; } - // For files opened in read mode, we now need to get the length - if (mod == O_RDONLY) - { - file->real_length = lseek (file->handle, 0, SEEK_END); + file->real_length = lseek (file->handle, 0, SEEK_END); + + // For files opened in append mode, we start at the end of the file + if (mod & O_APPEND) + file->position = file->real_length; + else lseek (file->handle, 0, SEEK_SET); - } return file; } @@ -1090,9 +1167,12 @@ qfile_t *FS_OpenPackedFile (pack_t* pack, int pack_ind) pfile = &pack->files[pack_ind]; + fs_filesize = 0; + // If we don't have the true offset, get it now if (! (pfile->flags & PACKFILE_FLAG_TRUEOFFS)) - PK3_GetTrueFileOffset (pfile, pack); + if (!PK3_GetTrueFileOffset (pfile, pack)) + return NULL; // No Zlib DLL = no compressed files if (!zlib_dll && (pfile->flags & PACKFILE_FLAG_DEFLATED)) @@ -1100,15 +1180,26 @@ qfile_t *FS_OpenPackedFile (pack_t* pack, int pack_ind) Con_Printf("WARNING: can't open the compressed file %s\n" "You need the Zlib DLL to use compressed files\n", pfile->name); - fs_filesize = -1; + return NULL; + } + + // LordHavoc: lseek affects all duplicates of a handle so we do it before + // the dup() call to avoid having to close the dup_handle on error here + if (lseek (pack->handle, pfile->offset, SEEK_SET) == -1) + { + Con_Printf ("FS_OpenPackedFile: can't lseek to %s in %s (offset: %d)", + pfile->name, pack->filename, pfile->offset); return NULL; } dup_handle = dup (pack->handle); if (dup_handle < 0) - Sys_Error ("FS_OpenPackedFile: can't dup package's handle (pack: %s)", pack->filename); + { + Con_Printf ("FS_OpenPackedFile: can't dup package's handle (pack: %s)", pack->filename); + return NULL; + } - file = Mem_Alloc (fs_mempool, sizeof (*file)); + file = (qfile_t *)Mem_Alloc (fs_mempool, sizeof (*file)); memset (file, 0, sizeof (*file)); file->handle = dup_handle; file->flags = QFILE_FLAG_PACKED; @@ -1117,10 +1208,6 @@ qfile_t *FS_OpenPackedFile (pack_t* pack, int pack_ind) file->position = 0; file->ungetc = EOF; - if (lseek (file->handle, file->offset, SEEK_SET) == -1) - Sys_Error ("FS_OpenPackedFile: can't lseek to %s in %s (offset: %d)", - pfile->name, pack->filename, file->offset); - if (pfile->flags & PACKFILE_FLAG_DEFLATED) { ztoolkit_t *ztk; @@ -1128,7 +1215,7 @@ qfile_t *FS_OpenPackedFile (pack_t* pack, int pack_ind) file->flags |= QFILE_FLAG_DEFLATED; // We need some more variables - ztk = Mem_Alloc (fs_mempool, sizeof (*ztk)); + ztk = (ztoolkit_t *)Mem_Alloc (fs_mempool, sizeof (*ztk)); ztk->comp_length = pfile->packsize; @@ -1146,7 +1233,12 @@ qfile_t *FS_OpenPackedFile (pack_t* pack, int pack_ind) * size of both compressed and uncompressed data */ if (qz_inflateInit2 (&ztk->zstream, -MAX_WBITS) != Z_OK) - Sys_Error ("FS_OpenPackedFile: inflate init error (file: %s)", pfile->name); + { + Con_Printf ("FS_OpenPackedFile: inflate init error (file: %s)", pfile->name); + close(dup_handle); + Mem_Free(file); + return NULL; + } ztk->zstream.next_out = file->buff; ztk->zstream.avail_out = sizeof (file->buff); @@ -1260,7 +1352,7 @@ static searchpath_t *FS_FindFile (const char *name, int* index, qboolean quiet) else { char netpath[MAX_OSPATH]; - snprintf(netpath, sizeof(netpath), "%s/%s", search->filename, name); + dpsnprintf(netpath, sizeof(netpath), "%s%s", search->filename, name); if (FS_SysFileExists (netpath)) { if (!quiet) @@ -1291,7 +1383,7 @@ Look for a file in the search paths and open it in read-only mode Sets fs_filesize =========== */ -qfile_t *FS_OpenReadFile (const char *filename, qboolean quiet) +qfile_t *FS_OpenReadFile (const char *filename, qboolean quiet, qboolean nonblocking) { searchpath_t *search; int pack_ind; @@ -1301,7 +1393,7 @@ qfile_t *FS_OpenReadFile (const char *filename, qboolean quiet) // Not found? if (search == NULL) { - fs_filesize = -1; + fs_filesize = 0; return NULL; } @@ -1309,8 +1401,8 @@ qfile_t *FS_OpenReadFile (const char *filename, qboolean quiet) if (pack_ind < 0) { char path [MAX_OSPATH]; - snprintf (path, sizeof (path), "%s/%s", search->filename, filename); - return FS_SysOpen (path, "rb"); + dpsnprintf (path, sizeof (path), "%s%s", search->filename, filename); + return FS_SysOpen (path, "rb", nonblocking); } // So, we found it in a package... @@ -1333,7 +1425,7 @@ FS_Open Open a file. The syntax is the same as fopen ==================== */ -qfile_t* FS_Open (const char* filepath, const char* mode, qboolean quiet) +qfile_t* FS_Open (const char* filepath, const char* mode, qboolean quiet, qboolean nonblocking) { qfile_t* file; @@ -1349,16 +1441,16 @@ qfile_t* FS_Open (const char* filepath, const char* mode, qboolean quiet) char real_path [MAX_OSPATH]; // Open the file on disk directly - snprintf (real_path, sizeof (real_path), "%s/%s", fs_gamedir, filepath); + dpsnprintf (real_path, sizeof (real_path), "%s%s", fs_gamedir, filepath); // Create directories up to the file FS_CreatePath (real_path); - return FS_SysOpen (real_path, mode); + return FS_SysOpen (real_path, mode, nonblocking); } // Else, we look at the various search paths and open the file in read-only mode - file = FS_OpenReadFile (filepath, quiet); + file = FS_OpenReadFile (filepath, quiet, nonblocking); if (file != NULL) fs_filesize = file->real_length; @@ -1396,9 +1488,23 @@ FS_Write Write "datasize" bytes into a file ==================== */ -size_t FS_Write (qfile_t* file, const void* data, size_t datasize) +fs_offset_t FS_Write (qfile_t* file, const void* data, size_t datasize) { - ssize_t result = write (file->handle, data, datasize); + fs_offset_t result; + + // If necessary, seek to the exact file position we're supposed to be + if (file->buff_ind != file->buff_len) + lseek (file->handle, file->buff_ind - file->buff_len, SEEK_CUR); + + // Purge cached data + FS_Purge (file); + + // Write the buffer and update the position + result = write (file->handle, data, (fs_offset_t)datasize); + file->position = lseek (file->handle, 0, SEEK_CUR); + if (file->real_length < file->position) + file->real_length = file->position; + if (result < 0) return 0; @@ -1413,16 +1519,30 @@ FS_Read Read up to "buffersize" bytes from a file ==================== */ -size_t FS_Read (qfile_t* file, void* buffer, size_t buffersize) +fs_offset_t FS_Read (qfile_t* file, void* buffer, size_t buffersize) { - size_t count, done; + fs_offset_t count, done; + + if (buffersize == 0) + return 0; + + // Get rid of the ungetc character + if (file->ungetc != EOF) + { + ((char*)buffer)[0] = file->ungetc; + buffersize--; + file->ungetc = EOF; + done = 1; + } + else + done = 0; // First, we copy as many bytes as we can from "buff" if (file->buff_ind < file->buff_len) { count = file->buff_len - file->buff_ind; - done = (buffersize > count) ? count : buffersize; + done += ((fs_offset_t)buffersize > count) ? count : (fs_offset_t)buffersize; memcpy (buffer, &file->buff[file->buff_ind], done); file->buff_ind += done; @@ -1430,15 +1550,13 @@ size_t FS_Read (qfile_t* file, void* buffer, size_t buffersize) if (buffersize == 0) return done; } - else - done = 0; // NOTE: at this point, the read buffer is always empty // If the file isn't compressed if (! (file->flags & QFILE_FLAG_DEFLATED)) { - int nb; + fs_offset_t nb; // We must take care to not read after the end of the file count = file->real_length - file->position; @@ -1446,8 +1564,8 @@ size_t FS_Read (qfile_t* file, void* buffer, size_t buffersize) // If we have a lot of data to get, put them directly into "buffer" if (buffersize > sizeof (file->buff) / 2) { - if (count > buffersize) - count = buffersize; + if (count > (fs_offset_t)buffersize) + count = (fs_offset_t)buffersize; lseek (file->handle, file->offset + file->position, SEEK_SET); nb = read (file->handle, &((qbyte*)buffer)[done], count); if (nb > 0) @@ -1455,15 +1573,14 @@ size_t FS_Read (qfile_t* file, void* buffer, size_t buffersize) done += nb; file->position += nb; - // Invalidate the output data (for FS_Seek) - file->buff_len = 0; - file->buff_ind = 0; + // Purge cached data + FS_Purge (file); } } else { - if (count > sizeof (file->buff)) - count = sizeof (file->buff); + if (count > (fs_offset_t)sizeof (file->buff)) + count = (fs_offset_t)sizeof (file->buff); lseek (file->handle, file->offset + file->position, SEEK_SET); nb = read (file->handle, file->buff, count); if (nb > 0) @@ -1472,7 +1589,7 @@ size_t FS_Read (qfile_t* file, void* buffer, size_t buffersize) file->position += nb; // Copy the requested data in "buffer" (as much as we can) - count = (buffersize > file->buff_len) ? file->buff_len : buffersize; + count = (fs_offset_t)buffersize > file->buff_len ? file->buff_len : (fs_offset_t)buffersize; memcpy (&((qbyte*)buffer)[done], file->buff, count); file->buff_ind = count; done += count; @@ -1498,12 +1615,15 @@ size_t FS_Read (qfile_t* file, void* buffer, size_t buffersize) if (file->position == file->real_length) return done; - count = ztk->comp_length - ztk->in_position; - if (count > sizeof (ztk->input)) - count = sizeof (ztk->input); - lseek (file->handle, file->offset + ztk->in_position, SEEK_SET); - if (read (file->handle, ztk->input, count) != (ssize_t)count) - Sys_Error ("FS_Read: unexpected end of file"); + count = (fs_offset_t)(ztk->comp_length - ztk->in_position); + if (count > (fs_offset_t)sizeof (ztk->input)) + count = (fs_offset_t)sizeof (ztk->input); + lseek (file->handle, file->offset + (fs_offset_t)ztk->in_position, SEEK_SET); + if (read (file->handle, ztk->input, count) != count) + { + Con_Printf ("FS_Read: unexpected end of file"); + break; + } ztk->in_ind = 0; ztk->in_len = count; @@ -1511,7 +1631,7 @@ size_t FS_Read (qfile_t* file, void* buffer, size_t buffersize) } ztk->zstream.next_in = &ztk->input[ztk->in_ind]; - ztk->zstream.avail_in = ztk->in_len - ztk->in_ind; + ztk->zstream.avail_in = (unsigned int)(ztk->in_len - ztk->in_ind); // Now that we are sure we have compressed data available, we need to determine // if it's better to inflate it in "file->buff" or directly in "buffer" @@ -1523,14 +1643,17 @@ size_t FS_Read (qfile_t* file, void* buffer, size_t buffersize) ztk->zstream.avail_out = sizeof (file->buff); error = qz_inflate (&ztk->zstream, Z_SYNC_FLUSH); if (error != Z_OK && error != Z_STREAM_END) - Sys_Error ("Can't inflate file"); + { + Con_Printf ("FS_Read: Can't inflate file"); + break; + } ztk->in_ind = ztk->in_len - ztk->zstream.avail_in; - file->buff_len = sizeof (file->buff) - ztk->zstream.avail_out; + file->buff_len = (fs_offset_t)sizeof (file->buff) - ztk->zstream.avail_out; file->position += file->buff_len; // Copy the requested data in "buffer" (as much as we can) - count = (buffersize > file->buff_len) ? file->buff_len : buffersize; + count = (fs_offset_t)buffersize > file->buff_len ? file->buff_len : (fs_offset_t)buffersize; memcpy (&((qbyte*)buffer)[done], file->buff, count); file->buff_ind = count; } @@ -1539,19 +1662,21 @@ size_t FS_Read (qfile_t* file, void* buffer, size_t buffersize) else { ztk->zstream.next_out = &((qbyte*)buffer)[done]; - ztk->zstream.avail_out = buffersize; + ztk->zstream.avail_out = (unsigned int)buffersize; error = qz_inflate (&ztk->zstream, Z_SYNC_FLUSH); if (error != Z_OK && error != Z_STREAM_END) - Sys_Error ("Can't inflate file"); + { + Con_Printf ("FS_Read: Can't inflate file"); + break; + } ztk->in_ind = ztk->in_len - ztk->zstream.avail_in; // How much data did it inflate? - count = buffersize - ztk->zstream.avail_out; + count = (fs_offset_t)(buffersize - ztk->zstream.avail_out); file->position += count; - // Invalidate the output data (for FS_Seek) - file->buff_len = 0; - file->buff_ind = 0; + // Purge cached data + FS_Purge (file); } done += count; @@ -1571,7 +1696,7 @@ Print a string into a file */ int FS_Print (qfile_t* file, const char *msg) { - return FS_Write (file, msg, strlen (msg)); + return (int)FS_Write (file, msg, strlen (msg)); } /* @@ -1604,19 +1729,24 @@ Print a string into a file int FS_VPrintf (qfile_t* file, const char* format, va_list ap) { int len; - char tempstring [1024]; + fs_offset_t buff_size; + char *tempbuff = NULL; - len = vsnprintf (tempstring, sizeof(tempstring), format, ap); - if (len >= sizeof (tempstring)) + buff_size = 1024; + tempbuff = (char *)Mem_Alloc (tempmempool, buff_size); + len = dpvsnprintf (tempbuff, buff_size, format, ap); + while (len < 0) { - char *temp = Mem_Alloc (tempmempool, len + 1); - len = vsnprintf (temp, len + 1, format, ap); - len = write (file->handle, temp, len); - Mem_Free (temp); - return len; + Mem_Free (tempbuff); + buff_size *= 2; + tempbuff = (char *)Mem_Alloc (tempmempool, buff_size); + len = dpvsnprintf (tempbuff, buff_size, format, ap); } - return write (file->handle, tempstring, len); + len = write (file->handle, tempbuff, len); + Mem_Free (tempbuff); + + return len; } @@ -1624,19 +1754,14 @@ int FS_VPrintf (qfile_t* file, const char* format, va_list ap) ==================== FS_Getc -Get stored ungetc character or the next character of a file +Get the next character of a file ==================== */ int FS_Getc (qfile_t* file) { char c; - if (file->ungetc != EOF) - { - c = file->ungetc; - file->ungetc = EOF; - } - else if (FS_Read (file, &c, 1) != 1) + if (FS_Read (file, &c, 1) != 1) return EOF; return c; @@ -1647,12 +1772,17 @@ int FS_Getc (qfile_t* file) ==================== FS_UnGetc -Put a character back into the Getc buffer (only supports one character!) +Put a character back into the read buffer (only supports one character!) ==================== */ -void FS_UnGetc (qfile_t* file, unsigned char c) +int FS_UnGetc (qfile_t* file, unsigned char c) { + // If there's already a character waiting to be read + if (file->ungetc != EOF) + return EOF; + file->ungetc = c; + return c; } @@ -1663,11 +1793,11 @@ FS_Seek Move the position index in a file ==================== */ -int FS_Seek (qfile_t* file, long offset, int whence) +int FS_Seek (qfile_t* file, fs_offset_t offset, int whence) { ztoolkit_t *ztk; qbyte* buffer; - size_t buffersize; + fs_offset_t buffersize; // Compute the file offset switch (whence) @@ -1690,16 +1820,14 @@ int FS_Seek (qfile_t* file, long offset, int whence) return -1; // If we have the data in our read buffer, we don't need to actually seek - if (file->position - file->buff_len <= (size_t)offset && - (size_t)offset <= file->position) + if (file->position - file->buff_len <= offset && offset <= file->position) { file->buff_ind = offset + file->buff_len - file->position; return 0; } - // Invalidate the read buffer contents - file->buff_ind = 0; - file->buff_len = 0; + // Purge cached data + FS_Purge (file); // Unpacked or uncompressed files can seek directly if (! (file->flags & QFILE_FLAG_DEFLATED)) @@ -1715,7 +1843,7 @@ int FS_Seek (qfile_t* file, long offset, int whence) ztk = file->ztk; // If we have to go back in the file, we need to restart from the beginning - if ((size_t)offset <= file->position) + if (offset <= file->position) { ztk->in_ind = 0; ztk->in_len = 0; @@ -1731,13 +1859,13 @@ int FS_Seek (qfile_t* file, long offset, int whence) // We need a big buffer to force inflating into it directly buffersize = 2 * sizeof (file->buff); - buffer = Mem_Alloc (tempmempool, buffersize); + buffer = (qbyte *)Mem_Alloc (tempmempool, buffersize); // Skip all data until we reach the requested offset - while ((size_t)offset > file->position) + while (offset > file->position) { - size_t diff = offset - file->position; - size_t count, len; + fs_offset_t diff = offset - file->position; + fs_offset_t count, len; count = (diff > buffersize) ? buffersize : diff; len = FS_Read (file, buffer, count); @@ -1760,12 +1888,27 @@ FS_Tell Give the current position in a file ==================== */ -long FS_Tell (qfile_t* file) +fs_offset_t FS_Tell (qfile_t* file) { return file->position - file->buff_len + file->buff_ind; } +/* +==================== +FS_Purge + +Erases any buffered input or output data +==================== +*/ +void FS_Purge (qfile_t* file) +{ + file->buff_len = 0; + file->buff_ind = 0; + file->ungetc = EOF; +} + + /* ============ FS_LoadFile @@ -1779,11 +1922,11 @@ qbyte *FS_LoadFile (const char *path, mempool_t *pool, qboolean quiet) qfile_t *file; qbyte *buf; - file = FS_Open (path, "rb", quiet); + file = FS_Open (path, "rb", quiet, false); if (!file) return NULL; - buf = Mem_Alloc (pool, fs_filesize + 1); + buf = (qbyte *)Mem_Alloc (pool, fs_filesize + 1); buf[fs_filesize] = '\0'; FS_Read (file, buf, fs_filesize); @@ -1800,11 +1943,11 @@ FS_WriteFile The filename will be prefixed by the current game directory ============ */ -qboolean FS_WriteFile (const char *filename, void *data, int len) +qboolean FS_WriteFile (const char *filename, void *data, fs_offset_t len) { qfile_t *file; - file = FS_Open (filename, "wb", false); + file = FS_Open (filename, "wb", false, false); if (!file) { Con_Printf("FS_WriteFile: failed on %s\n", filename); @@ -1948,10 +2091,14 @@ fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet) char netpath[MAX_OSPATH]; char temp[MAX_OSPATH]; - while(!strncmp(pattern, "./", 2)) - pattern += 2; - while(!strncmp(pattern, ".\\", 2)) - pattern += 2; + for (i = 0;pattern[i] == '.' || pattern[i] == ':' || pattern[i] == '/' || pattern[i] == '\\';i++) + ; + + if (i > 0) + { + Con_Printf("Don't use punctuation at the beginning of a search pattern!\n"); + return NULL; + } search = NULL; liststart = NULL; @@ -1960,15 +2107,10 @@ fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet) slash = strrchr(pattern, '/'); backslash = strrchr(pattern, '\\'); colon = strrchr(pattern, ':'); - separator = pattern; - if (separator < slash) - separator = slash; - if (separator < backslash) - separator = backslash; - if (separator < colon) - separator = colon; - basepathlength = separator - pattern; - basepath = Mem_Alloc (tempmempool, basepathlength + 1); + separator = max(slash, backslash); + separator = max(separator, colon); + basepathlength = separator ? (separator + 1 - pattern) : 0; + basepath = (char *)Mem_Alloc (tempmempool, basepathlength + 1); if (basepathlength) memcpy(basepath, pattern, basepathlength); basepath[basepathlength] = 0; @@ -2019,12 +2161,12 @@ fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet) else { // get a directory listing and look at each name - snprintf(netpath, sizeof (netpath), "%s/%s", searchpath->filename, basepath); + dpsnprintf(netpath, sizeof (netpath), "%s%s", searchpath->filename, basepath); if ((dir = listdirectory(netpath))) { for (dirfile = dir;dirfile;dirfile = dirfile->next) { - snprintf(temp, sizeof(temp), "%s/%s", basepath, dirfile->text); + dpsnprintf(temp, sizeof(temp), "%s%s", basepath, dirfile->text); if (matchpattern(temp, (char *)pattern, true)) { for (listtemp = liststart;listtemp;listtemp = listtemp->next) @@ -2053,12 +2195,12 @@ fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet) for (listtemp = liststart;listtemp;listtemp = listtemp->next) { numfiles++; - numchars += strlen(listtemp->text) + 1; + numchars += (int)strlen(listtemp->text) + 1; } - search = Z_Malloc(sizeof(fssearch_t) + numchars + numfiles * sizeof(char *)); + search = (fssearch_t *)Z_Malloc(sizeof(fssearch_t) + numchars + numfiles * sizeof(char *)); search->filenames = (char **)((char *)search + sizeof(fssearch_t)); search->filenamesbuffer = (char *)((char *)search + sizeof(fssearch_t) + numfiles * sizeof(char *)); - search->numfilenames = numfiles; + search->numfilenames = (int)numfiles; numfiles = 0; numchars = 0; for (listtemp = liststart;listtemp;listtemp = listtemp->next) @@ -2066,7 +2208,7 @@ fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet) search->filenames[numfiles] = search->filenamesbuffer + numchars; strcpy(search->filenames[numfiles], listtemp->text); numfiles++; - numchars += strlen(listtemp->text) + 1; + numchars += (int)strlen(listtemp->text) + 1; } if (liststart) stringlistfree(liststart); @@ -2107,7 +2249,7 @@ int FS_ListDirectory(const char *pattern, int oneperline) columnwidth = 0; for (i = 0;i < numfiles;i++) { - l = strlen(search->filenames[i]); + l = (int)strlen(search->filenames[i]); if (columnwidth < l) columnwidth = l; } @@ -2128,11 +2270,11 @@ int FS_ListDirectory(const char *pattern, int oneperline) if (l < numfiles) { name = search->filenames[l]; - for (j = 0;name[j] && j < (int)sizeof(linebuf) - 1;j++) + for (j = 0;name[j] && linebufpos + 1 < (int)sizeof(linebuf);j++) linebuf[linebufpos++] = name[j]; // space out name unless it's the last on the line - if (k < (numcolumns - 1) && l < (numfiles - 1)) - for (;j < columnwidth && j < (int)sizeof(linebuf) - 1;j++) + if (k + 1 < numcolumns && l + 1 < numfiles) + for (;j < columnwidth && linebufpos + 1 < (int)sizeof(linebuf);j++) linebuf[linebufpos++] = ' '; } } @@ -2147,7 +2289,7 @@ int FS_ListDirectory(const char *pattern, int oneperline) for (i = 0;i < numfiles;i++) Con_Printf("%s\n", search->filenames[i]); FS_FreeSearch(search); - return numfiles; + return (int)numfiles; } static void FS_ListDirectoryCmd (const char* cmdname, int oneperline)