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,
}
}
- // add any PK3 package in the director
+ // add any PK3 package in the directory
for (current = list;current;current = current->next)
{
if (!strcasecmp(FS_FileExtension(current->text), "pk3"))
FS_AddPack_Fullpath(pakfile, NULL, false);
}
}
+
freedirectory(list);
// Add the directory to the search path
FS_FileExtension
============
*/
-static const char *FS_FileExtension (const char *in)
+const char *FS_FileExtension (const char *in)
{
const char *separator, *backslash, *colon, *dot;
}
+/*
+============
+FS_FileWithoutPath
+============
+*/
+const char *FS_FileWithoutPath (const char *in)
+{
+ const char *separator, *backslash, *colon;
+
+ separator = strrchr(in, '/');
+ backslash = strrchr(in, '\\');
+ if (!separator || separator < backslash)
+ separator = backslash;
+ colon = strrchr(in, ':');
+ if (!separator || separator < colon)
+ separator = colon;
+ return separator ? separator + 1 : in;
+}
+
+
/*
================
FS_ClearSearchPath
/*
================
-FS_Rescan_f
+FS_Rescan
================
*/
-void FS_Rescan_f (void)
+void FS_Rescan (void)
{
int i;
qboolean fs_modified = false;
}
}
+void FS_Rescan_f(void)
+{
+ FS_Rescan();
+}
/*
================
-FS_ChangeGameDir
+FS_ChangeGameDirs
================
*/
-void Host_SaveConfig_f (void);
-void Host_LoadConfig_f (void);
-qboolean FS_ChangeGameDir(const char *string)
+extern void Host_SaveConfig_f (void);
+extern void Host_LoadConfig_f (void);
+qboolean FS_ChangeGameDirs(int numgamedirs, char gamedirs[][MAX_QPATH], qboolean complain, qboolean failmissing)
{
- // if already using the requested gamedir, do nothing
- if (fs_numgamedirs == 1 && !strcmp(fs_gamedirs[0], string))
- return false;
+ int i;
- // if string is nasty, reject it
- if(FS_CheckNastyPath(string, true)) // overflowed or nasty?
+ if (fs_numgamedirs == numgamedirs)
{
- Con_Printf("FS_ChangeGameDir(\"%s\"): nasty filename rejected\n", string);
- return false;
+ for (i = 0;i < numgamedirs;i++)
+ if (strcasecmp(fs_gamedirs[i], gamedirs[i]))
+ break;
+ if (i == numgamedirs)
+ return true; // already using this set of gamedirs, do nothing
+ }
+
+ if (numgamedirs > MAX_GAMEDIRS)
+ {
+ if (complain)
+ Con_Printf("That is too many gamedirs (%i > %i)\n", numgamedirs, MAX_GAMEDIRS);
+ return false; // too many gamedirs
+ }
+
+ for (i = 0;i < numgamedirs;i++)
+ {
+ // if string is nasty, reject it
+ if(FS_CheckNastyPath(gamedirs[i], true))
+ {
+ if (complain)
+ Con_Printf("Nasty gamedir name rejected: %s\n", gamedirs[i]);
+ return false; // nasty gamedirs
+ }
+ }
+
+ for (i = 0;i < numgamedirs;i++)
+ {
+ if (!FS_CheckGameDir(gamedirs[i]) && failmissing)
+ {
+ if (complain)
+ Con_Printf("Gamedir missing: %s%s/\n", fs_basedir, gamedirs[i]);
+ return false; // missing gamedirs
+ }
}
- // save the current config
Host_SaveConfig_f();
- // change to the new gamedir
- fs_numgamedirs = 1;
- strlcpy(fs_gamedirs[0], string, sizeof(fs_gamedirs[0]));
+ fs_numgamedirs = numgamedirs;
+ for (i = 0;i < fs_numgamedirs;i++)
+ strlcpy(fs_gamedirs[i], gamedirs[i], sizeof(fs_gamedirs[i]));
// reinitialize filesystem to detect the new paks
- FS_Rescan_f();
+ FS_Rescan();
// exec the new config
Host_LoadConfig_f();
void FS_GameDir_f (void)
{
int i;
+ int numgamedirs;
+ char gamedirs[MAX_GAMEDIRS][MAX_QPATH];
if (Cmd_Argc() < 2)
{
return;
}
- if (cls.state != ca_disconnected || sv.active)
+ numgamedirs = Cmd_Argc() - 1;
+ if (numgamedirs > MAX_GAMEDIRS)
{
- Con_Printf("Can not change gamedir while client is connected or server is running!\n");
+ Con_Printf("Too many gamedirs (%i > %i)\n", numgamedirs, MAX_GAMEDIRS);
return;
}
- Host_SaveConfig_f();
+ for (i = 0;i < numgamedirs;i++)
+ strlcpy(gamedirs[i], Cmd_Argv(i+1), sizeof(gamedirs[i]));
- fs_numgamedirs = 0;
- for (i = 1;i < Cmd_Argc() && fs_numgamedirs < MAX_GAMEDIRS;i++)
- {
- // if string is nasty, reject it
- if(FS_CheckNastyPath(Cmd_Argv(i), true)) // overflowed or nasty?
- {
- Con_Printf("FS_GameDir_f(\"%s\"): nasty filename rejected\n", Cmd_Argv(i));
- continue;
- }
+ // allow gamedir change during demo loop
+ if (cls.demoplayback)
+ CL_Disconnect();
- strlcpy(fs_gamedirs[fs_numgamedirs], Cmd_Argv(i), sizeof(fs_gamedirs[fs_numgamedirs]));
- fs_numgamedirs++;
+ if (cls.state == ca_connected || 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");
+ return;
}
- // reinitialize filesystem to detect the new paks
- FS_Rescan_f();
-
- // exec the new config
- Host_LoadConfig_f();
+ FS_ChangeGameDirs(numgamedirs, gamedirs, true, true);
+}
- // reinitialize the loaded sounds
- S_Reload_f();
- // reinitialize renderer (this reloads hud/console background/etc)
- R_Modules_Restart();
+/*
+================
+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;
}
if (fs_basedir[0] && fs_basedir[strlen(fs_basedir) - 1] != '/' && fs_basedir[strlen(fs_basedir) - 1] != '\\')
strlcat(fs_basedir, "/", sizeof(fs_basedir));
+ if (!FS_CheckGameDir(gamedirname1))
+ Sys_Error("base gamedir %s%s/ not found!\n", fs_basedir, gamedirname1);
+
+ if (gamedirname2 && !FS_CheckGameDir(gamedirname2))
+ Sys_Error("base gamedir %s%s/ not found!\n", fs_basedir, gamedirname2);
+
// -game <gamedir>
// Adds basedir/gamedir as an override game
// LordHavoc: now supports multiple -game directories
if (!strcmp (com_argv[i], "-game") && i < com_argc-1)
{
i++;
+ if (FS_CheckNastyPath(com_argv[i], true))
+ Sys_Error("-game %s%s/ is a dangerous/non-portable path\n", fs_basedir, com_argv[i]);
+ if (!FS_CheckGameDir(com_argv[i]))
+ Sys_Error("-game %s%s/ not found!\n", fs_basedir, com_argv[i]);
// add the gamedir to the list of active gamedirs
strlcpy (fs_gamedirs[fs_numgamedirs], com_argv[i], sizeof(fs_gamedirs[fs_numgamedirs]));
fs_numgamedirs++;
}
}
- // update the searchpath
- FS_Rescan_f();
+ // generate the searchpath
+ FS_Rescan();
}
void FS_Init_Commands(void)
}
+/*
+====================
+FS_FileSize
+
+Give the total size of a file
+====================
+*/
+fs_offset_t FS_FileSize (qfile_t* file)
+{
+ return file->real_length;
+}
+
+
/*
====================
FS_Purge
else
return 0;
}
+
+/*
+====================
+FS_IsRegisteredQuakePack
+
+Look for a proof of purchase file file in the requested package
+
+If it is found, this file should NOT be downloaded.
+====================
+*/
+qboolean FS_IsRegisteredQuakePack(const char *name)
+{
+ searchpath_t *search;
+ pack_t *pak;
+
+ // search through the path, one element at a time
+ for (search = fs_searchpaths;search;search = search->next)
+ {
+ if (search->pack && !strcasecmp(FS_FileWithoutPath(search->filename), name))
+ {
+ int (*strcmp_funct) (const char* str1, const char* str2);
+ int left, right, middle;
+
+ pak = search->pack;
+ strcmp_funct = pak->ignorecase ? strcasecmp : strcmp;
+
+ // Look for the file (binary search)
+ left = 0;
+ right = pak->numfiles - 1;
+ while (left <= right)
+ {
+ int diff;
+
+ middle = (left + right) / 2;
+ diff = !strcmp_funct (pak->files[middle].name, "gfx/pop.lmp");
+
+ // Found it
+ if (!diff)
+ return true;
+
+ // If we're too far in the list
+ if (diff > 0)
+ right = middle - 1;
+ else
+ left = middle + 1;
+ }
+
+ // we found the requested pack but it is not registered quake
+ return false;
+ }
+ }
+
+ 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;
+}
+