mirror of
https://github.com/Shpoike/Quakespasm.git
synced 2024-11-10 07:21:58 +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);
|
||||
}
|
||||
|
||||
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);
|
||||
// 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
|
||||
* to perform non-sequential reads on files reopened on pak files
|
||||
* because we need the bookkeeping about file start/end positions.
|
||||
|
|
|
@ -1105,13 +1105,13 @@ Host_Loadgame_f
|
|||
*/
|
||||
void Host_Loadgame_f (void)
|
||||
{
|
||||
static char *start;
|
||||
|
||||
char name[MAX_OSPATH];
|
||||
FILE *f;
|
||||
char mapname[MAX_QPATH];
|
||||
float time, tfloat;
|
||||
char str[32768];
|
||||
const char *start;
|
||||
int i, r;
|
||||
const char *data;
|
||||
int i;
|
||||
edict_t *ent;
|
||||
int entnum;
|
||||
int version;
|
||||
|
@ -1142,30 +1142,38 @@ void Host_Loadgame_f (void)
|
|||
// SCR_BeginLoadingPlaque ();
|
||||
|
||||
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");
|
||||
return;
|
||||
}
|
||||
|
||||
fscanf (f, "%i\n", &version);
|
||||
data = start;
|
||||
data = COM_ParseIntNewline (data, &version);
|
||||
if (version != SAVEGAME_VERSION)
|
||||
{
|
||||
fclose (f);
|
||||
free (start);
|
||||
start = NULL;
|
||||
Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
|
||||
return;
|
||||
}
|
||||
fscanf (f, "%s\n", str);
|
||||
data = COM_ParseStringNewline (data);
|
||||
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
|
||||
fscanf (f, "%f\n", &tfloat);
|
||||
data = COM_ParseFloatNewline(data, &tfloat);
|
||||
current_skill = (int)(tfloat + 0.1);
|
||||
Cvar_SetValue ("skill", (float)current_skill);
|
||||
|
||||
fscanf (f, "%s\n",mapname);
|
||||
fscanf (f, "%f\n",&time);
|
||||
data = COM_ParseStringNewline (data);
|
||||
q_strlcpy (mapname, com_token, sizeof(mapname));
|
||||
data = COM_ParseFloatNewline (data, &time);
|
||||
|
||||
CL_Disconnect_f ();
|
||||
|
||||
|
@ -1173,7 +1181,8 @@ void Host_Loadgame_f (void)
|
|||
|
||||
if (!sv.active)
|
||||
{
|
||||
fclose (f);
|
||||
free (start);
|
||||
start = NULL;
|
||||
Con_Printf ("Couldn't load map\n");
|
||||
return;
|
||||
}
|
||||
|
@ -1184,50 +1193,25 @@ void Host_Loadgame_f (void)
|
|||
|
||||
for (i = 0; i < MAX_LIGHTSTYLES; i++)
|
||||
{
|
||||
fscanf (f, "%s\n", str);
|
||||
sv.lightstyles[i] = (const char *)Hunk_Strdup (str, "lightstyles");
|
||||
data = COM_ParseStringNewline (data);
|
||||
sv.lightstyles[i] = (const char *)Hunk_Strdup (com_token, "lightstyles");
|
||||
}
|
||||
|
||||
// load the edicts out of the savegame file
|
||||
entnum = -1; // -1 is the globals
|
||||
while (!feof(f))
|
||||
while (*data)
|
||||
{
|
||||
qboolean inside_string = false;
|
||||
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);
|
||||
data = COM_Parse (data);
|
||||
if (!com_token[0])
|
||||
break; // end of file
|
||||
if (strcmp(com_token,"{"))
|
||||
{
|
||||
fclose (f);
|
||||
Sys_Error ("First token isn't a brace");
|
||||
}
|
||||
|
||||
if (entnum == -1)
|
||||
{ // parse the global vars
|
||||
ED_ParseGlobals (start);
|
||||
data = ED_ParseGlobals (data);
|
||||
}
|
||||
else
|
||||
{ // parse an edict
|
||||
|
@ -1239,7 +1223,7 @@ void Host_Loadgame_f (void)
|
|||
else {
|
||||
memset (ent, 0, pr_edict_size);
|
||||
}
|
||||
ED_ParseEdict (start, ent);
|
||||
data = ED_ParseEdict (data, ent);
|
||||
|
||||
// link it into the bsp tree
|
||||
if (!ent->free)
|
||||
|
@ -1252,7 +1236,8 @@ void Host_Loadgame_f (void)
|
|||
sv.num_edicts = entnum;
|
||||
sv.time = time;
|
||||
|
||||
fclose (f);
|
||||
free (start);
|
||||
start = NULL;
|
||||
|
||||
for (i = 0; i < NUM_SPAWN_PARMS; i++)
|
||||
svs.clients->spawn_parms[i] = spawn_parms[i];
|
||||
|
|
|
@ -691,7 +691,7 @@ void ED_WriteGlobals (FILE *f)
|
|||
ED_ParseGlobals
|
||||
=============
|
||||
*/
|
||||
void ED_ParseGlobals (const char *data)
|
||||
const char *ED_ParseGlobals (const char *data)
|
||||
{
|
||||
char keyname[64];
|
||||
ddef_t *key;
|
||||
|
@ -725,6 +725,7 @@ void ED_ParseGlobals (const char *data)
|
|||
if (!ED_ParseEpair ((void *)pr_globals, key, com_token))
|
||||
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);
|
||||
|
||||
void ED_WriteGlobals (FILE *f);
|
||||
void ED_ParseGlobals (const char *data);
|
||||
const char *ED_ParseGlobals (const char *data);
|
||||
|
||||
void ED_LoadFromFile (const char *data);
|
||||
|
||||
|
|
Loading…
Reference in a new issue