X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=fs.c;h=a2337b0e9836d20b7313671b0065f15080674881;hb=0d69d44e91a3d878e74e6ae7640792bfde38fc68;hp=fd20cdc17a9b689c96817c4fa6fe98e278b533fa;hpb=7403ba135fe27515470bfc6a7f8980869ccfee76;p=xonotic%2Fdarkplaces.git diff --git a/fs.c b/fs.c index fd20cdc1..a2337b0e 100644 --- a/fs.c +++ b/fs.c @@ -1,7 +1,7 @@ /* DarkPlaces file system - Copyright (C) 2003-2005 Mathieu Olivier + Copyright (C) 2003-2006 Mathieu Olivier This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -22,6 +22,9 @@ Boston, MA 02111-1307, USA */ +// on UNIX platforms we need to define this so that video saving does not cause a SIGFSZ (file size) signal when a video clip exceeds 2GB +#define _FILE_OFFSET_BITS 64 + #include "quakedef.h" #include @@ -247,6 +250,8 @@ FUNCTION PROTOTYPES void FS_Dir_f(void); void FS_Ls_f(void); +static const char *FS_FileExtension (const char *in); +static searchpath_t *FS_FindFile (const char *name, int* index, qboolean quiet); static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack, fs_offset_t offset, fs_offset_t packsize, fs_offset_t realsize, int flags); @@ -273,7 +278,7 @@ 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"}; +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)"}; /* @@ -786,6 +791,16 @@ pack_t *FS_LoadPackPAK (const char *packfile) return NULL; } + info = (dpackfile_t *)Mem_Alloc(tempmempool, sizeof(*info) * numpackfiles); + lseek (packhandle, header.dirofs, SEEK_SET); + if(header.dirlen != read (packhandle, (void *)info, header.dirlen)) + { + Con_Printf("%s is an incomplete PAK, not loading\n", packfile); + Mem_Free(info); + close(packhandle); + return NULL; + } + pack = (pack_t *)Mem_Alloc(fs_mempool, sizeof (pack_t)); pack->ignorecase = false; // PAK is case sensitive strlcpy (pack->filename, packfile, sizeof (pack->filename)); @@ -795,10 +810,6 @@ pack_t *FS_LoadPackPAK (const char *packfile) pack->next = packlist; packlist = pack; - 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++) { @@ -814,6 +825,136 @@ pack_t *FS_LoadPackPAK (const char *packfile) return pack; } +/* +================ +FS_AddPack_Fullpath + +Adds the given pack to the search path. +The pack type is autodetected by the file extension. + +Returns true if the file was successfully added to the +search path or if it was already included. + +If keep_plain_dirs is set, the pack will be added AFTER the first sequence of +plain directories. +================ +*/ +static qboolean FS_AddPack_Fullpath(const char *pakfile, qboolean *already_loaded, qboolean keep_plain_dirs) +{ + searchpath_t *search; + pack_t *pak = NULL; + const char *ext = FS_FileExtension(pakfile); + + for(search = fs_searchpaths; search; search = search->next) + { + if(search->pack && !strcasecmp(search->pack->filename, pakfile)) + { + if(already_loaded) + *already_loaded = true; + return true; // already loaded + } + } + + if(already_loaded) + *already_loaded = false; + + if(!strcasecmp(ext, "pak")) + pak = FS_LoadPackPAK (pakfile); + else if(!strcasecmp(ext, "pk3")) + pak = FS_LoadPackPK3 (pakfile); + else + Con_Printf("\"%s\" does not have a pack extension\n", pakfile); + + if (pak) + { + if(keep_plain_dirs) + { + // find the first item whose next one is a pack or NULL + searchpath_t *insertion_point = 0; + if(fs_searchpaths && !fs_searchpaths->pack) + { + insertion_point = fs_searchpaths; + for(;;) + { + if(!insertion_point->next) + break; + if(insertion_point->next->pack) + break; + insertion_point = insertion_point->next; + } + } + // If insertion_point is NULL, this means that either there is no + // item in the list yet, or that the very first item is a pack. In + // that case, we want to insert at the beginning... + if(!insertion_point) + { + search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); + search->pack = pak; + search->next = fs_searchpaths; + fs_searchpaths = search; + } + else + // otherwise we want to append directly after insertion_point. + { + search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); + search->pack = pak; + search->next = insertion_point->next; + insertion_point->next = search; + } + } + else + { + search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); + search->pack = pak; + search->next = fs_searchpaths; + fs_searchpaths = search; + } + return true; + } + else + { + Con_Printf("unable to load pak \"%s\"\n", pakfile); + return false; + } +} + + +/* +================ +FS_AddPack + +Adds the given pack to the search path and searches for it in the game path. +The pack type is autodetected by the file extension. + +Returns true if the file was successfully added to the +search path or if it was already included. + +If keep_plain_dirs is set, the pack will be added AFTER the first sequence of +plain directories. +================ +*/ +qboolean FS_AddPack(const char *pakfile, qboolean *already_loaded, qboolean keep_plain_dirs) +{ + char fullpath[MAX_QPATH]; + int index; + searchpath_t *search; + + if(already_loaded) + *already_loaded = false; + + // then find the real name... + search = FS_FindFile(pakfile, &index, true); + if(!search || search->pack) + { + Con_Printf("could not find pak \"%s\"\n", pakfile); + return false; + } + + dpsnprintf(fullpath, sizeof(fullpath), "%s%s", search->filename, pakfile); + + return FS_AddPack_Fullpath(fullpath, already_loaded, keep_plain_dirs); +} + /* ================ @@ -827,7 +968,6 @@ void FS_AddGameDirectory (const char *dir) { stringlist_t *list, *current; searchpath_t *search; - pack_t *pak; char pakfile[MAX_OSPATH]; strlcpy (fs_gamedir, dir, sizeof (fs_gamedir)); @@ -837,38 +977,20 @@ void FS_AddGameDirectory (const char *dir) // add any PAK package in the directory for (current = list;current;current = current->next) { - if (matchpattern(current->text, "*.pak", true)) + if (!strcasecmp(FS_FileExtension(current->text), "pak")) { dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, current->text); - pak = FS_LoadPackPAK (pakfile); - if (pak) - { - search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); - search->pack = pak; - search->next = fs_searchpaths; - fs_searchpaths = search; - } - else - Con_Printf("unable to load pak \"%s\"\n", pakfile); + FS_AddPack_Fullpath(pakfile, NULL, false); } } // add any PK3 package in the director for (current = list;current;current = current->next) { - if (matchpattern(current->text, "*.pk3", true)) + if (!strcasecmp(FS_FileExtension(current->text), "pk3")) { dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, current->text); - pak = FS_LoadPackPK3 (pakfile); - if (pak) - { - search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); - search->pack = pak; - search->next = fs_searchpaths; - fs_searchpaths = search; - } - else - Con_Printf("unable to load pak \"%s\"\n", pakfile); + FS_AddPack_Fullpath(pakfile, NULL, false); } } freedirectory(list); @@ -894,7 +1016,7 @@ void FS_AddGameHierarchy (const char *dir) #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 @@ -916,14 +1038,14 @@ static const char *FS_FileExtension (const char *in) separator = strrchr(in, '/'); backslash = strrchr(in, '\\'); - if (separator < backslash) + if (!separator || separator < backslash) separator = backslash; colon = strrchr(in, ':'); - if (separator < colon) + if (!separator || separator < colon) separator = colon; dot = strrchr(in, '.'); - if (dot == NULL || dot < separator) + if (dot == NULL || (separator && (dot < separator))) return ""; return dot + 1; @@ -942,8 +1064,13 @@ void FS_Init (void) fs_mempool = Mem_AllocPool("file management", 0, NULL); - strcpy(fs_basedir, "."); - strcpy(fs_gamedir, ""); + strlcpy(fs_gamedir, "", sizeof(fs_gamedir)); + +// If the base directory is explicitly defined by the compilation process +#ifdef DP_FS_BASEDIR + strlcpy(fs_basedir, DP_FS_BASEDIR, sizeof(fs_basedir)); +#else + strlcpy(fs_basedir, "", sizeof(fs_basedir)); #ifdef MACOSX // FIXME: is there a better way to find the directory outside the .app? @@ -957,6 +1084,7 @@ void FS_Init (void) strlcpy(fs_basedir, com_argv[0], sizeof(fs_basedir)); fs_basedir[split - com_argv[0]] = 0; } +#endif #endif PK3_OpenLibrary (); @@ -973,6 +1101,10 @@ void FS_Init (void) fs_basedir[i-1] = 0; } + // add a path separator to the end of the basedir if it lacks one + if (fs_basedir[0] && fs_basedir[strlen(fs_basedir) - 1] != '/' && fs_basedir[strlen(fs_basedir) - 1] != '\\') + strlcat(fs_basedir, "/", sizeof(fs_basedir)); + // -path [] ... // Fully specifies the exact search path, overriding the generated one // COMMANDLINEOPTION: Filesystem: -path specifies the full search path manually, overriding the generated one, example: -path c:\quake\id1 c:\quake\pak0.pak c:\quake\pak1.pak (not recommended) @@ -985,78 +1117,67 @@ void FS_Init (void) if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-') break; - 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) - { - Con_Printf ("Couldn't load packfile: %s\n", com_argv[i]); - Mem_Free(search); - continue; - } - } - else if (!strcasecmp (FS_FileExtension (com_argv[i]), "pk3")) + if(!FS_AddPack_Fullpath(com_argv[i], NULL, false)) { - search->pack = FS_LoadPackPK3 (com_argv[i]); - if (!search->pack) - { - Con_Printf ("Couldn't load packfile: %s\n", com_argv[i]); - Mem_Free(search); - continue; - } - } - else + search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); strlcpy (search->filename, com_argv[i], sizeof (search->filename)); - search->next = fs_searchpaths; - fs_searchpaths = search; + search->next = fs_searchpaths; + fs_searchpaths = search; + } } - return; } - - // add the game-specific paths - // gamedirname1 (typically id1) - FS_AddGameHierarchy (gamedirname1); - - // add the game-specific path, if any - if (gamedirname2) + else { - fs_modified = true; - FS_AddGameHierarchy (gamedirname2); - } - - // set the com_modname (reported in server info) - strlcpy(com_modname, gamedirname1, sizeof(com_modname)); + // add the game-specific paths + // gamedirname1 (typically id1) + FS_AddGameHierarchy (gamedirname1); - // -game - // Adds basedir/gamedir as an override game - // LordHavoc: now supports multiple -game directories - for (i = 1;i < com_argc;i++) - { - if (!com_argv[i]) - continue; - if (!strcmp (com_argv[i], "-game") && i < com_argc-1) + // add the game-specific path, if any + if (gamedirname2) { - i++; fs_modified = true; - FS_AddGameHierarchy (com_argv[i]); - // update the com_modname - strlcpy (com_modname, com_argv[i], sizeof (com_modname)); + FS_AddGameHierarchy (gamedirname2); } - } - // If "-condebug" is in the command line, remove the previous log file - if (COM_CheckParm ("-condebug") != 0) - unlink (va("%s/qconsole.log", fs_gamedir)); -} + // set the com_modname (reported in server info) + strlcpy(com_modname, gamedirname1, sizeof(com_modname)); -void FS_Init_Commands(void) -{ - Cvar_RegisterVariable (&scr_screenshot_name); + // -game + // Adds basedir/gamedir as an override game + // LordHavoc: now supports multiple -game directories + for (i = 1;i < com_argc;i++) + { + if (!com_argv[i]) + continue; + if (!strcmp (com_argv[i], "-game") && i < com_argc-1) + { + i++; + fs_modified = true; + FS_AddGameHierarchy (com_argv[i]); + // update the com_modname + strlcpy (com_modname, com_argv[i], sizeof (com_modname)); + } + } - Cmd_AddCommand ("path", FS_Path_f); - Cmd_AddCommand ("dir", FS_Dir_f); - Cmd_AddCommand ("ls", FS_Ls_f); + // If "-condebug" is in the command line, remove the previous log file + if (COM_CheckParm ("-condebug") != 0) + unlink (va("%s/qconsole.log", fs_gamedir)); + } + + // look for the pop.lmp file and set registered to true if it is found + if (gamemode == GAME_NORMAL && !FS_FileExists("gfx/pop.lmp")) + { + if (fs_modified) + Con_Print("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n"); + else + Con_Print("Playing shareware version.\n"); + } + else + { + Cvar_Set ("registered", "1"); + if (gamemode == GAME_NORMAL || gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE) + Con_Print("Playing registered version.\n"); + } // set the default screenshot name to either the mod name or the // gamemode screenshot name @@ -1066,6 +1187,15 @@ void FS_Init_Commands(void) Cvar_SetQuick (&scr_screenshot_name, gamescreenshotname); } +void FS_Init_Commands(void) +{ + Cvar_RegisterVariable (&scr_screenshot_name); + + Cmd_AddCommand ("path", FS_Path_f, "print searchpath (game directories and archives)"); + Cmd_AddCommand ("dir", FS_Dir_f, "list files in searchpath matching an * filename pattern, one per line"); + Cmd_AddCommand ("ls", FS_Ls_f, "list files in searchpath matching an * filename pattern, multiple per line"); +} + /* ================ FS_Shutdown @@ -1327,8 +1457,8 @@ static searchpath_t *FS_FindFile (const char *name, int* index, qboolean quiet) // Found it if (!diff) { - if (!quiet) - Con_DPrintf("FS_FindFile: %s in %s\n", + if (!quiet && developer.integer >= 10) + Con_Printf("FS_FindFile: %s in %s\n", pak->files[middle].name, pak->filename); if (index != NULL) @@ -1349,8 +1479,8 @@ static searchpath_t *FS_FindFile (const char *name, int* index, qboolean quiet) dpsnprintf(netpath, sizeof(netpath), "%s%s", search->filename, name); if (FS_SysFileExists (netpath)) { - if (!quiet) - Con_DPrintf("FS_FindFile: %s\n", netpath); + if (!quiet && developer.integer >= 10) + Con_Printf("FS_FindFile: %s\n", netpath); if (index != NULL) *index = -1; @@ -1359,8 +1489,8 @@ static searchpath_t *FS_FindFile (const char *name, int* index, qboolean quiet) } } - if (!quiet) - Con_DPrintf("FS_FindFile: can't find %s\n", name); + if (!quiet && developer.integer >= 10) + Con_Printf("FS_FindFile: can't find %s\n", name); if (index != NULL) *index = -1; @@ -1428,7 +1558,7 @@ qfile_t* FS_Open (const char* filepath, const char* mode, qboolean quiet, qboole char real_path [MAX_OSPATH]; // Open the file on disk directly - dpsnprintf (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); @@ -1962,17 +2092,19 @@ FS_StripExtension void FS_StripExtension (const char *in, char *out, size_t size_out) { char *last = NULL; + char currentchar; if (size_out == 0) return; - while (*in && size_out > 1) + while ((currentchar = *in) && size_out > 1) { - if (*in == '.') + if (currentchar == '.') last = out; - else if (*in == '/' || *in == '\\' || *in == ':') + else if (currentchar == '/' || currentchar == '\\' || currentchar == ':') last = NULL; - *out++ = *in++; + *out++ = currentchar; + in++; size_out--; } if (last) @@ -2110,7 +2242,7 @@ fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet) pak = searchpath->pack; for (i = 0;i < pak->numfiles;i++) { - strcpy(temp, pak->files[i].name); + strlcpy(temp, pak->files[i].name, sizeof(temp)); while (temp[0]) { if (matchpattern(temp, (char *)pattern, true)) @@ -2190,10 +2322,12 @@ fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet) numchars = 0; for (listtemp = liststart;listtemp;listtemp = listtemp->next) { + size_t textlen; search->filenames[numfiles] = search->filenamesbuffer + numchars; - strcpy(search->filenames[numfiles], listtemp->text); + textlen = strlen(listtemp->text) + 1; + memcpy(search->filenames[numfiles], listtemp->text, textlen); numfiles++; - numchars += (int)strlen(listtemp->text) + 1; + numchars += (int)textlen; } if (liststart) stringlistfree(liststart); @@ -2303,3 +2437,12 @@ void FS_Ls_f(void) FS_ListDirectoryCmd("ls", false); } +const char *FS_WhichPack(const char *filename) +{ + int index; + searchpath_t *sp = FS_FindFile(filename, &index, true); + if(sp && sp->pack) + return sp->pack->filename; + else + return 0; +}