]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - fs.c
damn, committed the old version of my patch... this now is the REAL v_flipped
[xonotic/darkplaces.git] / fs.c
diff --git a/fs.c b/fs.c
index d11ea28eacf5db40d8dbd74fcc95a6a1f6d592e0..40ec10a61ee94461039914bbca8505b57824fcf4 100644 (file)
--- a/fs.c
+++ b/fs.c
@@ -40,6 +40,7 @@
 #endif
 
 #include "fs.h"
+#include "wad.h"
 
 // Win32 requires us to add O_BINARY, but the other OSes don't have it
 #ifndef O_BINARY
@@ -273,11 +274,11 @@ char fs_gamedir[MAX_OSPATH];
 char fs_basedir[MAX_OSPATH];
 
 // list of active game directories (empty if not running a mod)
-#define MAX_GAMEDIRS 16
 int fs_numgamedirs = 0;
 char fs_gamedirs[MAX_GAMEDIRS][MAX_QPATH];
 
 cvar_t scr_screenshot_name = {0, "scr_screenshot_name","dp", "prefix name for saved screenshots (changes based on -game commandline, as well as which game mode is running)"};
+cvar_t fs_empty_files_in_pack_mark_deletions = {0, "fs_empty_files_in_pack_mark_deletions", "0", "if enabled, empty files in a pak/pk3 count as not existing but cancel the search in further packs, effectively allowing patch pak/pk3 files to 'delete' files"};
 
 
 /*
@@ -961,35 +962,38 @@ then loads and adds pak1.pak pak2.pak ...
 */
 void FS_AddGameDirectory (const char *dir)
 {
-       stringlist_t *list, *current;
+       int i;
+       stringlist_t list;
        searchpath_t *search;
        char pakfile[MAX_OSPATH];
 
        strlcpy (fs_gamedir, dir, sizeof (fs_gamedir));
 
-       list = listdirectory(dir);
+       stringlistinit(&list);
+       listdirectory(&list, dir);
+       stringlistsort(&list);
 
        // add any PAK package in the directory
-       for (current = list;current;current = current->next)
+       for (i = 0;i < list.numstrings;i++)
        {
-               if (!strcasecmp(FS_FileExtension(current->text), "pak"))
+               if (!strcasecmp(FS_FileExtension(list.strings[i]), "pak"))
                {
-                       dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, current->text);
+                       dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, list.strings[i]);
                        FS_AddPack_Fullpath(pakfile, NULL, false);
                }
        }
 
        // add any PK3 package in the directory
-       for (current = list;current;current = current->next)
+       for (i = 0;i < list.numstrings;i++)
        {
-               if (!strcasecmp(FS_FileExtension(current->text), "pk3"))
+               if (!strcasecmp(FS_FileExtension(list.strings[i]), "pk3"))
                {
-                       dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, current->text);
+                       dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, list.strings[i]);
                        FS_AddPack_Fullpath(pakfile, NULL, false);
                }
        }
 
-       freedirectory(list);
+       stringlistfreecontents(&list);
 
        // Add the directory to the search path
        // (unpacked files have the priority over packed files)
@@ -1075,12 +1079,18 @@ FS_ClearSearchPath
 */
 void FS_ClearSearchPath (void)
 {
+       // unload all packs and directory information, close all pack files
+       // (if a qfile is still reading a pack it won't be harmed because it used
+       //  dup() to get its own handle already)
        while (fs_searchpaths)
        {
                searchpath_t *search = fs_searchpaths;
                fs_searchpaths = search->next;
                if (search->pack)
                {
+                       // close the file
+                       close(search->pack->handle);
+                       // free any memory associated with it
                        if (search->pack->files)
                                Mem_Free(search->pack->files);
                        Mem_Free(search->pack);
@@ -1153,6 +1163,9 @@ void FS_Rescan (void)
                if (gamemode == GAME_NORMAL || gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
                        Con_Print("Playing registered version.\n");
        }
+
+       // unload all wads so that future queries will return the new data
+       W_UnloadAll();
 }
 
 void FS_Rescan_f(void)
@@ -1171,13 +1184,6 @@ qboolean FS_ChangeGameDirs(int numgamedirs, char gamedirs[][MAX_QPATH], qboolean
 {
        int i;
 
-       if (cls.state != ca_disconnected || sv.active)
-       {
-               if (complain)
-                       Con_Printf("Can not change gamedir while client is connected or server is running!\n");
-               return false;
-       }
-
        if (fs_numgamedirs == numgamedirs)
        {
                for (i = 0;i < numgamedirs;i++)
@@ -1215,6 +1221,9 @@ qboolean FS_ChangeGameDirs(int numgamedirs, char gamedirs[][MAX_QPATH], qboolean
                }
        }
 
+       // halt demo playback to close the file
+       CL_Disconnect();
+
        Host_SaveConfig_f();
 
        fs_numgamedirs = numgamedirs;
@@ -1227,8 +1236,8 @@ qboolean FS_ChangeGameDirs(int numgamedirs, char gamedirs[][MAX_QPATH], qboolean
        // exec the new config
        Host_LoadConfig_f();
 
-       // reinitialize the loaded sounds
-       S_Reload_f();
+       // unload all sounds so they will be reloaded from the new files as needed
+       S_UnloadAllSounds_f();
 
        // reinitialize renderer (this reloads hud/console background/etc)
        R_Modules_Restart();
@@ -1266,11 +1275,7 @@ void FS_GameDir_f (void)
        for (i = 0;i < numgamedirs;i++)
                strlcpy(gamedirs[i], Cmd_Argv(i+1), sizeof(gamedirs[i]));
 
-       // allow gamedir change during demo loop
-       if (cls.demoplayback)
-               CL_Disconnect();
-
-       if (cls.state != ca_disconnected || sv.active)
+       if ((cls.state == ca_connected && !cls.demoplayback) || sv.active)
        {
                // actually, changing during game would work fine, but would be stupid
                Con_Printf("Can not change gamedir while client is connected or server is running!\n");
@@ -1288,10 +1293,13 @@ FS_CheckGameDir
 */
 qboolean FS_CheckGameDir(const char *gamedir)
 {
-       stringlist_t *list = listdirectory(va("%s%s/", fs_basedir, gamedir));
-       if (list)
-               freedirectory(list);
-       return list != NULL;
+       qboolean success;
+       stringlist_t list;
+       stringlistinit(&list);
+       listdirectory(&list, va("%s%s/", fs_basedir, gamedir));
+       success = list.numstrings > 0;
+       stringlistfreecontents(&list);
+       return success;
 }
 
 
@@ -1380,6 +1388,7 @@ void FS_Init (void)
 void FS_Init_Commands(void)
 {
        Cvar_RegisterVariable (&scr_screenshot_name);
+       Cvar_RegisterVariable (&fs_empty_files_in_pack_mark_deletions);
 
        Cmd_AddCommand ("gamedir", FS_GameDir_f, "changes active gamedir list (can take multiple arguments), not including base directory (example usage: gamedir ctf)");
        Cmd_AddCommand ("fs_rescan", FS_Rescan_f, "rescans filesystem for new pack archives and any other changes");
@@ -1395,6 +1404,10 @@ FS_Shutdown
 */
 void FS_Shutdown (void)
 {
+       // close all pack files and such
+       // (hopefully there aren't any other open files, but they'll be cleaned up
+       //  by the OS anyway)
+       FS_ClearSearchPath();
        Mem_FreePool (&fs_mempool);
 }
 
@@ -1673,6 +1686,17 @@ static searchpath_t *FS_FindFile (const char *name, int* index, qboolean quiet)
                                // Found it
                                if (!diff)
                                {
+                                       if (fs_empty_files_in_pack_mark_deletions.integer && pak->files[middle].realsize == 0)
+                                       {
+                                               // yes, but the first one is empty so we treat it as not being there
+                                               if (!quiet && developer.integer >= 10)
+                                                       Con_Printf("FS_FindFile: %s is marked as deleted\n", name);
+
+                                               if (index != NULL)
+                                                       *index = -1;
+                                               return NULL;
+                                       }
+
                                        if (!quiet && developer.integer >= 10)
                                                Con_Printf("FS_FindFile: %s in %s\n",
                                                                        pak->files[middle].name, pak->filename);
@@ -2430,8 +2454,9 @@ fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet)
        fssearch_t *search;
        searchpath_t *searchpath;
        pack_t *pak;
-       int i, basepathlength, numfiles, numchars;
-       stringlist_t *dir, *dirfile, *liststart, *listcurrent, *listtemp;
+       int i, basepathlength, numfiles, numchars, resultlistindex, dirlistindex;
+       stringlist_t resultlist;
+       stringlist_t dirlist;
        const char *slash, *backslash, *colon, *separator;
        char *basepath;
        char netpath[MAX_OSPATH];
@@ -2446,10 +2471,9 @@ fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet)
                return NULL;
        }
 
+       stringlistinit(&resultlist);
+       stringlistinit(&dirlist);
        search = NULL;
-       liststart = NULL;
-       listcurrent = NULL;
-       listtemp = NULL;
        slash = strrchr(pattern, '/');
        backslash = strrchr(pattern, '\\');
        colon = strrchr(pattern, ':');
@@ -2476,14 +2500,12 @@ fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet)
                                {
                                        if (matchpattern(temp, (char *)pattern, true))
                                        {
-                                               for (listtemp = liststart;listtemp;listtemp = listtemp->next)
-                                                       if (!strcmp(listtemp->text, temp))
+                                               for (resultlistindex = 0;resultlistindex < resultlist.numstrings;resultlistindex++)
+                                                       if (!strcmp(resultlist.strings[resultlistindex], temp))
                                                                break;
-                                               if (listtemp == NULL)
+                                               if (resultlistindex == resultlist.numstrings)
                                                {
-                                                       listcurrent = stringlistappend(listcurrent, temp);
-                                                       if (liststart == NULL)
-                                                               liststart = listcurrent;
+                                                       stringlistappend(&resultlist, temp);
                                                        if (!quiet)
                                                                Con_DPrintf("SearchPackFile: %s : %s\n", pak->filename, temp);
                                                }
@@ -2508,59 +2530,52 @@ fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet)
                {
                        // get a directory listing and look at each name
                        dpsnprintf(netpath, sizeof (netpath), "%s%s", searchpath->filename, basepath);
-                       if ((dir = listdirectory(netpath)))
+                       stringlistinit(&dirlist);
+                       listdirectory(&dirlist, netpath);
+                       for (dirlistindex = 0;dirlistindex < dirlist.numstrings;dirlistindex++)
                        {
-                               for (dirfile = dir;dirfile;dirfile = dirfile->next)
+                               dpsnprintf(temp, sizeof(temp), "%s%s", basepath, dirlist.strings[dirlistindex]);
+                               if (matchpattern(temp, (char *)pattern, true))
                                {
-                                       dpsnprintf(temp, sizeof(temp), "%s%s", basepath, dirfile->text);
-                                       if (matchpattern(temp, (char *)pattern, true))
+                                       for (resultlistindex = 0;resultlistindex < resultlist.numstrings;resultlistindex++)
+                                               if (!strcmp(resultlist.strings[resultlistindex], temp))
+                                                       break;
+                                       if (resultlistindex == resultlist.numstrings)
                                        {
-                                               for (listtemp = liststart;listtemp;listtemp = listtemp->next)
-                                                       if (!strcmp(listtemp->text, temp))
-                                                               break;
-                                               if (listtemp == NULL)
-                                               {
-                                                       listcurrent = stringlistappend(listcurrent, temp);
-                                                       if (liststart == NULL)
-                                                               liststart = listcurrent;
-                                                       if (!quiet)
-                                                               Con_DPrintf("SearchDirFile: %s\n", temp);
-                                               }
+                                               stringlistappend(&resultlist, temp);
+                                               if (!quiet)
+                                                       Con_DPrintf("SearchDirFile: %s\n", temp);
                                        }
                                }
-                               freedirectory(dir);
                        }
+                       stringlistfreecontents(&dirlist);
                }
        }
 
-       if (liststart)
+       if (resultlist.numstrings)
        {
-               liststart = stringlistsort(liststart);
-               numfiles = 0;
+               stringlistsort(&resultlist);
+               numfiles = resultlist.numstrings;
                numchars = 0;
-               for (listtemp = liststart;listtemp;listtemp = listtemp->next)
-               {
-                       numfiles++;
-                       numchars += (int)strlen(listtemp->text) + 1;
-               }
+               for (resultlistindex = 0;resultlistindex < resultlist.numstrings;resultlistindex++)
+                       numchars += (int)strlen(resultlist.strings[resultlistindex]) + 1;
                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 = (int)numfiles;
                numfiles = 0;
                numchars = 0;
-               for (listtemp = liststart;listtemp;listtemp = listtemp->next)
+               for (resultlistindex = 0;resultlistindex < resultlist.numstrings;resultlistindex++)
                {
                        size_t textlen;
                        search->filenames[numfiles] = search->filenamesbuffer + numchars;
-                       textlen = strlen(listtemp->text) + 1;
-                       memcpy(search->filenames[numfiles], listtemp->text, textlen);
+                       textlen = strlen(resultlist.strings[resultlistindex]) + 1;
+                       memcpy(search->filenames[numfiles], resultlist.strings[resultlistindex], textlen);
                        numfiles++;
                        numchars += (int)textlen;
                }
-               if (liststart)
-                       stringlistfree(liststart);
        }
+       stringlistfreecontents(&resultlist);
 
        Mem_Free(basepath);
        return search;
@@ -2729,3 +2744,24 @@ qboolean FS_IsRegisteredQuakePack(const char *name)
 
        return false;
 }
+
+int FS_CRCFile(const char *filename, size_t *filesizepointer)
+{
+       int crc = -1;
+       unsigned char *filedata;
+       fs_offset_t filesize;
+       if (filesizepointer)
+               *filesizepointer = 0;
+       if (!filename || !*filename)
+               return crc;
+       filedata = FS_LoadFile(filename, tempmempool, true, &filesize);
+       if (filedata)
+       {
+               if (filesizepointer)
+                       *filesizepointer = filesize;
+               crc = CRC_Block(filedata, filesize);
+               Mem_Free(filedata);
+       }
+       return crc;
+}
+