mirror of
https://github.com/Shpoike/Quakespasm.git
synced 2024-11-13 00:34:11 +00:00
Host_Loadgame_f: rewritten version loads the whole .sav into memory
+ avoids "Loadgame buffer overflow" when loading saves from QS-Spike/DarkPlaces containing large comments + removes ugly } hack + should be a bit faster as we avoid calling fgetc for every byte git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1398 af15c1b1-3010-417e-b628-4374ebc0bcbd
This commit is contained in:
parent
83a0b5ae14
commit
8011b3f9fd
5 changed files with 101 additions and 48 deletions
|
@ -1872,6 +1872,56 @@ byte *COM_LoadMallocFile (const char *path, unsigned int *path_id)
|
||||||
return COM_LoadFile (path, LOADFILE_MALLOC, path_id);
|
return COM_LoadFile (path, LOADFILE_MALLOC, path_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byte *COM_LoadMallocFile_OSPath (const char *path, long *len_out)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
byte *data;
|
||||||
|
long len;
|
||||||
|
|
||||||
|
f = fopen (path, "rb");
|
||||||
|
if (f == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
len = COM_filelength (f);
|
||||||
|
if (len < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
data = (byte *) malloc (len + 1);
|
||||||
|
if (data == NULL)
|
||||||
|
return NULL;
|
||||||
|
if (fread (data, 1, len, f) != len)
|
||||||
|
{
|
||||||
|
free (data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
data[len] = '\0';
|
||||||
|
|
||||||
|
if (len_out != NULL)
|
||||||
|
*len_out = len;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *COM_ParseIntNewline(const char *buffer, int *value)
|
||||||
|
{
|
||||||
|
int consumed = 0;
|
||||||
|
sscanf (buffer, "%i\n%n", value, &consumed);
|
||||||
|
return buffer + consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *COM_ParseFloatNewline(const char *buffer, float *value)
|
||||||
|
{
|
||||||
|
int consumed = 0;
|
||||||
|
sscanf (buffer, "%f\n%n", value, &consumed);
|
||||||
|
return buffer + consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *COM_ParseStringNewline(const char *buffer)
|
||||||
|
{
|
||||||
|
int consumed = 0;
|
||||||
|
com_token[0] = '\0';
|
||||||
|
sscanf (buffer, "%1023s\n%n", com_token, &consumed);
|
||||||
|
return buffer + consumed;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
|
|
|
@ -255,6 +255,23 @@ void COM_LoadCacheFile (const char *path, struct cache_user_s *cu,
|
||||||
byte *COM_LoadMallocFile (const char *path, unsigned int *path_id);
|
byte *COM_LoadMallocFile (const char *path, unsigned int *path_id);
|
||||||
// allocates the buffer on the system mem (malloc).
|
// allocates the buffer on the system mem (malloc).
|
||||||
|
|
||||||
|
// Opens the given path directly, ignoring search paths.
|
||||||
|
// Returns NULL on failure, or else a '\0'-terminated malloc'ed buffer.
|
||||||
|
byte *COM_LoadMallocFile_OSPath (const char *path, long *len_out);
|
||||||
|
|
||||||
|
// Attempts to parse an int, followed by a newline.
|
||||||
|
// Returns advanced buffer position.
|
||||||
|
// Doesn't signal parsing failure, but this is not needed for savegame loading.
|
||||||
|
const char *COM_ParseIntNewline(const char *buffer, int *value);
|
||||||
|
|
||||||
|
// Attempts to parse a float followed by a newline.
|
||||||
|
// Returns advanced buffer position.
|
||||||
|
const char *COM_ParseFloatNewline(const char *buffer, float *value);
|
||||||
|
|
||||||
|
// Parse a string of non-whitespace into com_token, then tries to consume a
|
||||||
|
// newline. Returns advanced buffer position.
|
||||||
|
const char *COM_ParseStringNewline(const char *buffer);
|
||||||
|
|
||||||
/* The following FS_*() stdio replacements are necessary if one is
|
/* The following FS_*() stdio replacements are necessary if one is
|
||||||
* to perform non-sequential reads on files reopened on pak files
|
* to perform non-sequential reads on files reopened on pak files
|
||||||
* because we need the bookkeeping about file start/end positions.
|
* because we need the bookkeeping about file start/end positions.
|
||||||
|
|
|
@ -1105,13 +1105,13 @@ Host_Loadgame_f
|
||||||
*/
|
*/
|
||||||
void Host_Loadgame_f (void)
|
void Host_Loadgame_f (void)
|
||||||
{
|
{
|
||||||
|
static char *start;
|
||||||
|
|
||||||
char name[MAX_OSPATH];
|
char name[MAX_OSPATH];
|
||||||
FILE *f;
|
|
||||||
char mapname[MAX_QPATH];
|
char mapname[MAX_QPATH];
|
||||||
float time, tfloat;
|
float time, tfloat;
|
||||||
char str[32768];
|
const char *data;
|
||||||
const char *start;
|
int i;
|
||||||
int i, r;
|
|
||||||
edict_t *ent;
|
edict_t *ent;
|
||||||
int entnum;
|
int entnum;
|
||||||
int version;
|
int version;
|
||||||
|
@ -1142,30 +1142,38 @@ void Host_Loadgame_f (void)
|
||||||
// SCR_BeginLoadingPlaque ();
|
// SCR_BeginLoadingPlaque ();
|
||||||
|
|
||||||
Con_Printf ("Loading game from %s...\n", name);
|
Con_Printf ("Loading game from %s...\n", name);
|
||||||
f = fopen (name, "r");
|
|
||||||
if (!f)
|
// avoid leaking if the previous Host_Loadgame_f failed with a Host_Error
|
||||||
|
if (start != NULL)
|
||||||
|
free (start);
|
||||||
|
|
||||||
|
start = (char *) COM_LoadMallocFile_OSPath(name, NULL);
|
||||||
|
if (start == NULL)
|
||||||
{
|
{
|
||||||
Con_Printf ("ERROR: couldn't open.\n");
|
Con_Printf ("ERROR: couldn't open.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fscanf (f, "%i\n", &version);
|
data = start;
|
||||||
|
data = COM_ParseIntNewline (data, &version);
|
||||||
if (version != SAVEGAME_VERSION)
|
if (version != SAVEGAME_VERSION)
|
||||||
{
|
{
|
||||||
fclose (f);
|
free (start);
|
||||||
|
start = NULL;
|
||||||
Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
|
Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fscanf (f, "%s\n", str);
|
data = COM_ParseStringNewline (data);
|
||||||
for (i = 0; i < NUM_SPAWN_PARMS; i++)
|
for (i = 0; i < NUM_SPAWN_PARMS; i++)
|
||||||
fscanf (f, "%f\n", &spawn_parms[i]);
|
data = COM_ParseFloatNewline (data, &spawn_parms[i]);
|
||||||
// this silliness is so we can load 1.06 save files, which have float skill values
|
// this silliness is so we can load 1.06 save files, which have float skill values
|
||||||
fscanf (f, "%f\n", &tfloat);
|
data = COM_ParseFloatNewline(data, &tfloat);
|
||||||
current_skill = (int)(tfloat + 0.1);
|
current_skill = (int)(tfloat + 0.1);
|
||||||
Cvar_SetValue ("skill", (float)current_skill);
|
Cvar_SetValue ("skill", (float)current_skill);
|
||||||
|
|
||||||
fscanf (f, "%s\n",mapname);
|
data = COM_ParseStringNewline (data);
|
||||||
fscanf (f, "%f\n",&time);
|
q_strlcpy (mapname, com_token, sizeof(mapname));
|
||||||
|
data = COM_ParseFloatNewline (data, &time);
|
||||||
|
|
||||||
CL_Disconnect_f ();
|
CL_Disconnect_f ();
|
||||||
|
|
||||||
|
@ -1173,7 +1181,8 @@ void Host_Loadgame_f (void)
|
||||||
|
|
||||||
if (!sv.active)
|
if (!sv.active)
|
||||||
{
|
{
|
||||||
fclose (f);
|
free (start);
|
||||||
|
start = NULL;
|
||||||
Con_Printf ("Couldn't load map\n");
|
Con_Printf ("Couldn't load map\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1184,50 +1193,25 @@ void Host_Loadgame_f (void)
|
||||||
|
|
||||||
for (i = 0; i < MAX_LIGHTSTYLES; i++)
|
for (i = 0; i < MAX_LIGHTSTYLES; i++)
|
||||||
{
|
{
|
||||||
fscanf (f, "%s\n", str);
|
data = COM_ParseStringNewline (data);
|
||||||
sv.lightstyles[i] = (const char *)Hunk_Strdup (str, "lightstyles");
|
sv.lightstyles[i] = (const char *)Hunk_Strdup (com_token, "lightstyles");
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the edicts out of the savegame file
|
// load the edicts out of the savegame file
|
||||||
entnum = -1; // -1 is the globals
|
entnum = -1; // -1 is the globals
|
||||||
while (!feof(f))
|
while (*data)
|
||||||
{
|
{
|
||||||
qboolean inside_string = false;
|
data = COM_Parse (data);
|
||||||
for (i = 0; i < (int) sizeof(str) - 1; i++)
|
|
||||||
{
|
|
||||||
r = fgetc (f);
|
|
||||||
if (r == EOF || !r)
|
|
||||||
break;
|
|
||||||
str[i] = r;
|
|
||||||
if (r == '"')
|
|
||||||
{
|
|
||||||
inside_string = !inside_string;
|
|
||||||
}
|
|
||||||
else if (r == '}' && !inside_string) // only handle } characters outside of quoted strings
|
|
||||||
{
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == (int) sizeof(str) - 1)
|
|
||||||
{
|
|
||||||
fclose (f);
|
|
||||||
Sys_Error ("Loadgame buffer overflow");
|
|
||||||
}
|
|
||||||
str[i] = 0;
|
|
||||||
start = str;
|
|
||||||
start = COM_Parse(str);
|
|
||||||
if (!com_token[0])
|
if (!com_token[0])
|
||||||
break; // end of file
|
break; // end of file
|
||||||
if (strcmp(com_token,"{"))
|
if (strcmp(com_token,"{"))
|
||||||
{
|
{
|
||||||
fclose (f);
|
|
||||||
Sys_Error ("First token isn't a brace");
|
Sys_Error ("First token isn't a brace");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entnum == -1)
|
if (entnum == -1)
|
||||||
{ // parse the global vars
|
{ // parse the global vars
|
||||||
ED_ParseGlobals (start);
|
data = ED_ParseGlobals (data);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // parse an edict
|
{ // parse an edict
|
||||||
|
@ -1239,7 +1223,7 @@ void Host_Loadgame_f (void)
|
||||||
else {
|
else {
|
||||||
memset (ent, 0, pr_edict_size);
|
memset (ent, 0, pr_edict_size);
|
||||||
}
|
}
|
||||||
ED_ParseEdict (start, ent);
|
data = ED_ParseEdict (data, ent);
|
||||||
|
|
||||||
// link it into the bsp tree
|
// link it into the bsp tree
|
||||||
if (!ent->free)
|
if (!ent->free)
|
||||||
|
@ -1252,7 +1236,8 @@ void Host_Loadgame_f (void)
|
||||||
sv.num_edicts = entnum;
|
sv.num_edicts = entnum;
|
||||||
sv.time = time;
|
sv.time = time;
|
||||||
|
|
||||||
fclose (f);
|
free (start);
|
||||||
|
start = NULL;
|
||||||
|
|
||||||
for (i = 0; i < NUM_SPAWN_PARMS; i++)
|
for (i = 0; i < NUM_SPAWN_PARMS; i++)
|
||||||
svs.clients->spawn_parms[i] = spawn_parms[i];
|
svs.clients->spawn_parms[i] = spawn_parms[i];
|
||||||
|
|
|
@ -691,7 +691,7 @@ void ED_WriteGlobals (FILE *f)
|
||||||
ED_ParseGlobals
|
ED_ParseGlobals
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
void ED_ParseGlobals (const char *data)
|
const char *ED_ParseGlobals (const char *data)
|
||||||
{
|
{
|
||||||
char keyname[64];
|
char keyname[64];
|
||||||
ddef_t *key;
|
ddef_t *key;
|
||||||
|
@ -725,6 +725,7 @@ void ED_ParseGlobals (const char *data)
|
||||||
if (!ED_ParseEpair ((void *)pr_globals, key, com_token))
|
if (!ED_ParseEpair ((void *)pr_globals, key, com_token))
|
||||||
Host_Error ("ED_ParseGlobals: parse error");
|
Host_Error ("ED_ParseGlobals: parse error");
|
||||||
}
|
}
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
|
@ -87,7 +87,7 @@ void ED_Write (FILE *f, edict_t *ed);
|
||||||
const char *ED_ParseEdict (const char *data, edict_t *ent);
|
const char *ED_ParseEdict (const char *data, edict_t *ent);
|
||||||
|
|
||||||
void ED_WriteGlobals (FILE *f);
|
void ED_WriteGlobals (FILE *f);
|
||||||
void ED_ParseGlobals (const char *data);
|
const char *ED_ParseGlobals (const char *data);
|
||||||
|
|
||||||
void ED_LoadFromFile (const char *data);
|
void ED_LoadFromFile (const char *data);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue