summaryrefslogtreecommitdiff
path: root/src/strife/m_saves.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/strife/m_saves.c')
-rw-r--r--src/strife/m_saves.c323
1 files changed, 318 insertions, 5 deletions
diff --git a/src/strife/m_saves.c b/src/strife/m_saves.c
index f845598e..6b99a7a8 100644
--- a/src/strife/m_saves.c
+++ b/src/strife/m_saves.c
@@ -37,21 +37,61 @@
#else
#error Need an include for dirent.h!
#endif
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
#include "z_zone.h"
#include "i_system.h"
#include "d_player.h"
#include "deh_str.h"
+#include "doomstat.h"
#include "m_misc.h"
+#include "m_saves.h"
#include "p_dialog.h"
//
+// File Paths
+//
+// Strife maintains multiple file paths related to savegames.
+//
+char *savepath;
+char *savepath2;
+char *loadpath;
+
+//
// ClearTmp
//
// Clear the temporary save directory
//
void ClearTmp(void)
{
+ DIR *sp2dir = NULL;
+ struct dirent *f = NULL;
+
+ if(savepath2 == NULL)
+ I_Error("you fucked up savedir man!");
+
+ if(!(sp2dir = opendir(savepath2)))
+ I_Error("ClearTmp: Couldn't open dir %s", savepath2);
+
+ while((f = readdir(sp2dir)))
+ {
+ char *filepath = NULL;
+
+ // haleyjd: skip "." and ".." without assuming they're the
+ // first two entries like the original code did.
+ if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+ continue;
+
+ // haleyjd: use M_SafeFilePath, not sprintf
+ filepath = M_SafeFilePath(savepath2, f->d_name);
+ remove(filepath);
+
+ Z_Free(filepath);
+ }
+
+ closedir(sp2dir);
}
//
@@ -61,16 +101,50 @@ void ClearTmp(void)
//
void ClearSlot(void)
{
+ if(savepath == NULL)
+ I_Error("userdir is fucked up man!");
+
+ // STRIFE-TODO
}
//
// FromCurr
//
-// Moving files from one directory to another...
-// STRIFE-TODO: figure out exactly what this is for.
+// Copying files from savepath2 to savepath
//
void FromCurr(void)
{
+ DIR *sp2dir = NULL;
+ struct dirent *f = NULL;
+
+ if(!(sp2dir = opendir(savepath2)))
+ I_Error("FromCurr: Couldn't open dir %s", savepath2);
+
+ while((f = readdir(sp2dir)))
+ {
+ byte *filebuffer = NULL;
+ int filelen = 0;
+ char *srcfilename = NULL;
+ char *dstfilename = NULL;
+
+ // haleyjd: skip "." and ".." without assuming they're the
+ // first two entries like the original code did.
+ if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+ continue;
+
+ // haleyjd: use M_SafeFilePath, NOT sprintf.
+ srcfilename = M_SafeFilePath(savepath2, f->d_name);
+ dstfilename = M_SafeFilePath(savepath, f->d_name);
+
+ filelen = M_ReadFile(srcfilename, &filebuffer);
+ M_WriteFile(dstfilename, filebuffer, filelen);
+
+ Z_Free(filebuffer);
+ Z_Free(srcfilename);
+ Z_Free(dstfilename);
+ }
+
+ closedir(sp2dir);
}
//
@@ -80,6 +154,7 @@ void FromCurr(void)
//
void sub_1B2F4(void)
{
+ // STRIFE-TODO
}
//
@@ -89,6 +164,27 @@ void sub_1B2F4(void)
//
void M_SaveMoveMapToHere(void)
{
+ char *mapsave = NULL;
+ char *heresave = NULL;
+ char tmpnum[33];
+
+ // haleyjd: no itoa available...
+ memset(tmpnum, 0, sizeof(tmpnum));
+ sprintf(tmpnum, "%d", gamemap);
+
+ // haleyjd: use M_SafeFilePath, not sprintf
+ mapsave = M_SafeFilePath(savepath, tmpnum);
+ heresave = M_SafeFilePath(savepath, "here");
+
+ // haleyjd: use M_FileExists, not access
+ if(M_FileExists(mapsave))
+ {
+ remove(heresave);
+ rename(mapsave, heresave);
+ }
+
+ Z_Free(mapsave);
+ Z_Free(heresave);
}
//
@@ -98,6 +194,25 @@ void M_SaveMoveMapToHere(void)
//
void M_SaveMoveHereToMap(void)
{
+ char *mapsave = NULL;
+ char *heresave = NULL;
+ char tmpnum[33];
+
+ // haleyjd: no itoa available...
+ memset(tmpnum, 0, sizeof(tmpnum));
+ sprintf(tmpnum, "%d", gamemap);
+
+ mapsave = M_SafeFilePath(savepath2, tmpnum);
+ heresave = M_SafeFilePath(savepath2, "here");
+
+ if(M_FileExists(heresave))
+ {
+ remove(mapsave);
+ rename(heresave, mapsave);
+ }
+
+ Z_Free(mapsave);
+ Z_Free(heresave);
}
//
@@ -107,10 +222,15 @@ void M_SaveMoveHereToMap(void)
//
boolean M_SaveMisObj(const char *path)
{
- char destpath[100]; // WARNING: not large enough for modern file paths!
+ boolean result;
+ char *destpath = NULL;
+
+ // haleyjd 20110210: use M_SafeFilePath, not sprintf
+ destpath = M_SafeFilePath(path, "mis_obj");
+ result = M_WriteFile(destpath, mission_objective, OBJECTIVE_LEN);
- DEH_snprintf(destpath, sizeof(destpath), "%smis_obj", path);
- return M_WriteFile(destpath, mission_objective, OBJECTIVE_LEN);
+ Z_Free(destpath);
+ return result;
}
//
@@ -120,6 +240,199 @@ boolean M_SaveMisObj(const char *path)
//
void M_ReadMisObj(void)
{
+ FILE *f = NULL;
+ char *srcpath = NULL;
+
+ // haleyjd: use M_SafeFilePath, not sprintf
+ srcpath = M_SafeFilePath(savepath2, "mis_obj");
+
+ if((f = fopen(srcpath, "rb")))
+ {
+ fread(mission_objective, 1, 300, f);
+ fclose(f);
+ }
+
+ Z_Free(srcpath);
+}
+
+//=============================================================================
+//
+// Original Routines
+//
+// haleyjd - None of the below code is derived from Strife itself, but has been
+// adapted or created in order to provide secure, portable filepath handling
+// for the purposes of savegame support. This is partially needed to allow for
+// differences in Choco due to it being multiplatform. The rest exists because
+// I cannot stand programming in an impoverished ANSI C environment that
+// calls sprintf on fixed-size buffers. :P
+//
+
+//
+// M_Calloc
+//
+// haleyjd 20110210 - original routine
+// Because Choco doesn't have Z_Calloc O_o
+//
+void *M_Calloc(size_t n1, size_t n2)
+{
+ return (n1 *= n2) ? memset(Z_Malloc(n1, PU_STATIC, NULL), 0, n1) : NULL;
+}
+
+//
+// M_StringAlloc
+//
+// haleyjd: This routine takes any number of strings and a number of extra
+// characters, calculates their combined length, and calls Z_Alloca to create
+// a temporary buffer of that size. This is extremely useful for allocation of
+// file paths, and is used extensively in d_main.c. The pointer returned is
+// to a temporary Z_Alloca buffer, which lives until the next main loop
+// iteration, so don't cache it. Note that this idiom is not possible with the
+// normal non-standard alloca function, which allocates stack space.
+//
+// [STRIFE] - haleyjd 20110210
+// This routine is taken from the Eternity Engine and adapted to do without
+// Z_Alloca. I need secure string concatenation for filepath handling. The
+// only difference from use in EE is that the pointer returned in *str must
+// be manually freed.
+//
+int M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...)
+{
+ va_list args;
+ size_t len = extra;
+
+ if(numstrs < 1)
+ I_Error("M_StringAlloc: invalid input\n");
+
+ len += strlen(str1);
+
+ --numstrs;
+
+ if(numstrs != 0)
+ {
+ va_start(args, str1);
+
+ while(numstrs != 0)
+ {
+ const char *argstr = va_arg(args, const char *);
+
+ len += strlen(argstr);
+
+ --numstrs;
+ }
+
+ va_end(args);
+ }
+
+ ++len;
+
+ *str = (char *)(M_Calloc(1, len));
+
+ return len;
+}
+
+//
+// M_NormalizeSlashes
+//
+// Remove trailing slashes, translate backslashes to slashes
+// The string to normalize is passed and returned in str
+//
+// killough 11/98: rewritten
+//
+// [STRIFE] - haleyjd 20110210: Borrowed from Eternity and adapted to respect
+// the DIR_SEPARATOR define used by Choco Doom. This routine originated in
+// BOOM.
+//
+void M_NormalizeSlashes(char *str)
+{
+ char *p;
+
+ // Convert all slashes/backslashes to DIR_SEPARATOR
+ for(p = str; *p; p++)
+ {
+ if((*p == '/' || *p == '\\') && *p != DIR_SEPARATOR)
+ *p = DIR_SEPARATOR;
+ }
+
+ // Remove trailing slashes
+ while(p > str && *--p == DIR_SEPARATOR)
+ *p = 0;
+
+ // Collapse multiple slashes
+ for(p = str; (*str++ = *p); )
+ if(*p++ == DIR_SEPARATOR)
+ while(*p == DIR_SEPARATOR)
+ p++;
+}
+
+//
+// M_SafeFilePath
+//
+// haleyjd 20110210 - original routine.
+// This routine performs safe, portable concatenation of a base file path
+// with another path component or file name. The returned string is Z_Malloc'd
+// and should be freed when it has exhausted its usefulness.
+//
+char *M_SafeFilePath(const char *basepath, const char *newcomponent)
+{
+ int newstrlen = 0;
+ char *newstr = NULL;
+
+ // Always throw in a slash. M_NormalizeSlashes will remove it in the case
+ // that either basepath or newcomponent includes a redundant slash at the
+ // end or beginning respectively.
+ newstrlen = M_StringAlloc(&newstr, 3, 1, basepath, "/", newcomponent);
+ snprintf(newstr, newstrlen, "%s/%s", basepath, newcomponent);
+ M_NormalizeSlashes(newstr);
+
+ return newstr;
+}
+
+//
+// M_GetFilePath
+//
+// haleyjd: STRIFE-FIXME: Temporary?
+// Code borrowed from Eternity, and modified to return separator char
+//
+char M_GetFilePath(const char *fn, char *dest, size_t len)
+{
+ boolean found_slash = false;
+ char *p;
+ char sepchar = '\0';
+
+ memset(dest, 0, len);
+
+ p = dest + len - 1;
+
+ strncpy(dest, fn, len);
+
+ while(p >= dest)
+ {
+ if(*p == '/' || *p == '\\')
+ {
+ sepchar = *p;
+ found_slash = true; // mark that the path ended with a slash
+ *p = '\0';
+ break;
+ }
+ *p = '\0';
+ p--;
+ }
+
+ // haleyjd: in the case that no slash was ever found, yet the
+ // path string is empty, we are dealing with a file local to the
+ // working directory. The proper path to return for such a string is
+ // not "", but ".", since the format strings add a slash now. When
+ // the string is empty but a slash WAS found, we really do want to
+ // return the empty string, since the path is relative to the root.
+ if(!found_slash && *dest == '\0')
+ *dest = '.';
+
+ // if a separator is not found, default to forward, because Windows
+ // supports that too.
+ if(sepchar == '\0')
+ sepchar = '/';
+
+ return sepchar;
}
// EOF