mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-24 02:30:46 +00:00
- various fixes and improvements related to file location management:
* saving of demos and savegames no longer mindlessly writes to the mod directory. All such access is now being rerouted through the special paths interface so that the game data can reside in write protected locations. * refactored all occurences of klistpath except fnlist_getnames. * do not allow CON scripts to write to arbitrary files. This is a massive exploit and can be used to cause real damage if someone knows how to play this thing - it's far easier than people may think! It will now write any such data to a special section in the main config which is safe and cannot be manipulated to write to random locations on the hard drive.
This commit is contained in:
parent
cfca8060ba
commit
1149b4f4aa
24 changed files with 302 additions and 153 deletions
|
@ -722,6 +722,7 @@ set (PCH_SOURCES
|
|||
mact/src/keyboard.cpp
|
||||
mact/src/input.cpp
|
||||
|
||||
thirdparty/src/base64.cpp
|
||||
thirdparty/src/sjson.cpp
|
||||
thirdparty/src/crc32.cpp
|
||||
thirdparty/src/fix16.cpp
|
||||
|
|
|
@ -515,12 +515,6 @@ extern void G_ExtInit(void);
|
|||
|
||||
extern void G_SetupGlobalPsky(void);
|
||||
|
||||
#define G_ModDirSnprintf(buf, size, basename, ...) \
|
||||
(((g_modDir[0] != '/') ? Bsnprintf(buf, size, "%s/" basename, g_modDir, ##__VA_ARGS__) : Bsnprintf(buf, size, basename, ##__VA_ARGS__)) \
|
||||
>= ((int32_t)size) - 1)
|
||||
|
||||
#define G_ModDirSnprintfLite(buf, size, basename) \
|
||||
((g_modDir[0] != '/') ? Bsnprintf(buf, size, "%s/%s", g_modDir, basename) : Bsnprintf(buf, size, "%s", basename))
|
||||
|
||||
static inline int gameHandleEvents(void)
|
||||
{
|
||||
|
|
|
@ -46,7 +46,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#include "network.h"
|
||||
#include "player.h"
|
||||
#include "screen.h"
|
||||
#include "i_specialpaths.h"
|
||||
#include "view.h"
|
||||
#include "gamecontrol.h"
|
||||
|
||||
BEGIN_BLD_NS
|
||||
|
||||
|
@ -131,7 +133,7 @@ bool CDemo::Create(const char *pzFile)
|
|||
{
|
||||
for (int i = 0; i < 8 && !vc; i++)
|
||||
{
|
||||
G_ModDirSnprintf(buffer, BMAX_PATH, "%s0%02d.dem", BloodIniPre, i);
|
||||
snprintf(buffer, BMAX_PATH, "%s%s0%02d.dem", M_GetDemoPath().GetChars(), BloodIniPre, i);
|
||||
if (access(buffer, 0) != -1)
|
||||
vc = 1;
|
||||
}
|
||||
|
@ -144,7 +146,7 @@ bool CDemo::Create(const char *pzFile)
|
|||
}
|
||||
else
|
||||
{
|
||||
G_ModDirSnprintfLite(buffer, BMAX_PATH, pzFile);
|
||||
snprintf(buffer, BMAX_PATH, "%s%s", M_GetDemoPath().GetChars(), pzFile);
|
||||
hRFile = fopen(buffer, "wb");
|
||||
if (hRFile == NULL)
|
||||
return false;
|
||||
|
@ -428,12 +430,12 @@ void CDemo::LoadDemoInfo(void)
|
|||
auto pDemo = &pFirstDemo;
|
||||
at59ef = 0;
|
||||
char zFN[BMAX_PATH];
|
||||
Bsnprintf(zFN, BMAX_PATH, "%s*.dem", BloodIniPre);
|
||||
auto pList = klistpath("/", zFN, BUILDVFS_FIND_FILE);
|
||||
auto pIterator = pList;
|
||||
while (pIterator != NULL)
|
||||
Bsnprintf(zFN, BMAX_PATH, "%s%s*.dem", M_GetDemoPath().GetChars(), BloodIniPre);
|
||||
TArray<FString> demos;
|
||||
D_AddWildFile(demos, zFN);
|
||||
for (auto &filename : demos)
|
||||
{
|
||||
auto hFile = fopenFileReader(pIterator->name, 0);
|
||||
auto hFile = fopenFileReader(filename, 0);
|
||||
if (!hFile.isOpen())
|
||||
ThrowError("Error loading demo file header.");
|
||||
hFile.Read(&atf, sizeof(atf));
|
||||
|
@ -446,13 +448,11 @@ void CDemo::LoadDemoInfo(void)
|
|||
{
|
||||
*pDemo = new DEMOCHAIN;
|
||||
(*pDemo)->pNext = NULL;
|
||||
Bstrncpy((*pDemo)->zName, pIterator->name, BMAX_PATH);
|
||||
Bstrncpy((*pDemo)->zName, filename, BMAX_PATH);
|
||||
at59ef++;
|
||||
pDemo = &(*pDemo)->pNext;
|
||||
}
|
||||
pIterator = pIterator->next;
|
||||
}
|
||||
klistfree(pList);
|
||||
pCurrentDemo = pFirstDemo;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#include "seq.h"
|
||||
#include "sfx.h"
|
||||
#include "sound.h"
|
||||
#include "i_specialpaths.h"
|
||||
#include "view.h"
|
||||
|
||||
BEGIN_BLD_NS
|
||||
|
@ -426,11 +427,13 @@ void MyLoadSave::Save(void)
|
|||
|
||||
void LoadSavedInfo(void)
|
||||
{
|
||||
auto pList = klistpath("./", "game*.sav", BUILDVFS_FIND_FILE);
|
||||
FString path = M_GetSavegamesPath() + "%sgame*.sav";
|
||||
TArray<FString> saves;
|
||||
D_AddWildFile(saves, path);
|
||||
int nCount = 0;
|
||||
for (auto pIterator = pList; pIterator != NULL && nCount < 10; pIterator = pIterator->next, nCount++)
|
||||
for (auto & savename : saves)
|
||||
{
|
||||
auto hFile = fopenFileReader(pIterator->name, 0);
|
||||
auto hFile = fopenFileReader(savename, 0);
|
||||
if (!hFile.isOpen())
|
||||
ThrowError("Error loading save file header.");
|
||||
int vc;
|
||||
|
@ -453,8 +456,8 @@ void LoadSavedInfo(void)
|
|||
if ((uint32_t)hFile.Read(&gSaveGameOptions[nCount], sizeof(gSaveGameOptions[0])) != sizeof(gSaveGameOptions[0]))
|
||||
ThrowError("Error reading save file.");
|
||||
strcpy(strRestoreGameStrings[gSaveGameOptions[nCount].nSaveGameSlot], gSaveGameOptions[nCount].szUserGameName);
|
||||
nCount++;
|
||||
}
|
||||
klistfree(pList);
|
||||
}
|
||||
|
||||
void UpdateSavedInfo(int nSlot)
|
||||
|
|
|
@ -41,6 +41,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#include "screen.h"
|
||||
#include "sound.h"
|
||||
#include "view.h"
|
||||
#include "i_specialpaths.h"
|
||||
|
||||
EXTERN_CVAR(Bool, hud_powerupduration)
|
||||
|
||||
|
@ -2102,7 +2103,7 @@ void SaveGame(CGameMenuItemZEditBitmap *pItem, CGameMenuEvent *event)
|
|||
gGameMenuMgr.Deactivate();
|
||||
return;
|
||||
}
|
||||
G_ModDirSnprintf(strSaveGameName, BMAX_PATH, "game00%02d.sav", nSlot);
|
||||
snprintf(strSaveGameName, BMAX_PATH, "%sgame00%02d.sav", M_GetSavegamesPath().GetChars(), nSlot);
|
||||
strcpy(gGameOptions.szUserGameName, strRestoreGameStrings[nSlot]);
|
||||
sprintf(gGameOptions.szSaveGameName, "%s", strSaveGameName);
|
||||
gGameOptions.nSaveGameSlot = nSlot;
|
||||
|
@ -2124,7 +2125,7 @@ void QuickSaveGame(void)
|
|||
gGameMenuMgr.Deactivate();
|
||||
return;
|
||||
}*/
|
||||
G_ModDirSnprintf(strSaveGameName, BMAX_PATH, "game00%02d.sav", gQuickSaveSlot);
|
||||
snprintf(strSaveGameName, BMAX_PATH, "%sgame00%02d.sav", M_GetSavegamesPath().GetChars(), gQuickSaveSlot);
|
||||
strcpy(gGameOptions.szUserGameName, strRestoreGameStrings[gQuickSaveSlot]);
|
||||
sprintf(gGameOptions.szSaveGameName, "%s", strSaveGameName);
|
||||
gGameOptions.nSaveGameSlot = gQuickSaveSlot;
|
||||
|
@ -2144,7 +2145,7 @@ void LoadGame(CGameMenuItemZEditBitmap *pItem, CGameMenuEvent *event)
|
|||
int nSlot = pItem->at28;
|
||||
if (gGameOptions.nGameType > 0)
|
||||
return;
|
||||
G_ModDirSnprintf(strLoadGameName, BMAX_PATH, "game00%02d.sav", nSlot);
|
||||
snprintf(strLoadGameName, BMAX_PATH, "%sgame00%02d.sav", M_GetSavegamesPath().GetChars(), nSlot);
|
||||
if (!testkopen(strLoadGameName, 0))
|
||||
return;
|
||||
viewLoadingScreen(2518, "Loading", "Loading Saved Game", strRestoreGameStrings[nSlot]);
|
||||
|
@ -2159,7 +2160,7 @@ void QuickLoadGame(void)
|
|||
char strLoadGameName[BMAX_PATH];
|
||||
if (gGameOptions.nGameType > 0)
|
||||
return;
|
||||
G_ModDirSnprintf(strLoadGameName, BMAX_PATH, "game00%02d.sav", gQuickLoadSlot);
|
||||
snprintf(strLoadGameName, BMAX_PATH, "%sgame00%02d.sav", M_GetSavegamesPath().GetChars(), gQuickLoadSlot);
|
||||
if (!testkopen(strLoadGameName, 0))
|
||||
return;
|
||||
viewLoadingScreen(2518, "Loading", "Loading Saved Game", strRestoreGameStrings[gQuickLoadSlot]);
|
||||
|
|
|
@ -22,8 +22,6 @@ using buildvfs_kfd = int32_t;
|
|||
|
||||
extern int32_t pathsearchmode; // 0 = gamefs mode (default), 1 = localfs mode (editor's mode)
|
||||
|
||||
extern char g_modDir[BMAX_PATH];
|
||||
|
||||
|
||||
enum {
|
||||
CACHE1D_FIND_FILE = 1,
|
||||
|
|
|
@ -122,9 +122,6 @@ static size_t maxsearchpathlen = 0;
|
|||
int32_t pathsearchmode = 0;
|
||||
|
||||
|
||||
char g_modDir[BMAX_PATH] = "/";
|
||||
|
||||
|
||||
|
||||
int32_t klistaddentry(CACHE1D_FIND_REC **rec, const char *name, int32_t type, int32_t source)
|
||||
{
|
||||
|
|
|
@ -38,8 +38,7 @@
|
|||
#include "resourcefile.h"
|
||||
#include "name.h"
|
||||
#include "m_swap.h"
|
||||
|
||||
extern FString LumpFilter;
|
||||
#include "gamecontrol.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
#include "gamecvars.h"
|
||||
|
||||
extern FString currentGame;
|
||||
extern FString LumpFilter;
|
||||
class FArgs;
|
||||
|
||||
void D_AddWildFile(TArray<FString>& wadfiles, const char* value);
|
||||
|
||||
extern uint8_t KeyboardKeys[NUMGAMEFUNCTIONS][2];
|
||||
|
||||
|
|
|
@ -462,12 +462,6 @@ CUSTOM_CVAR(String, rtsname, "", CVAR_ARCHIVE | CVAR_USERINFO)
|
|||
{
|
||||
RTS_Init(self);
|
||||
}
|
||||
#if 0
|
||||
|
||||
// These will be redone once the resource management has been swapped out.
|
||||
//GameConfig->SetValueForKey("Setup", "ModDir", &g_modDir[0]);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
|
|
|
@ -11,6 +11,7 @@ FString M_GetConfigPath(bool for_reading);
|
|||
FString M_GetScreenshotsPath();
|
||||
FString M_GetSavegamesPath();
|
||||
FString M_GetDocumentsPath();
|
||||
FString M_GetDemoPath();
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
|
|
@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#include "menus.h"
|
||||
#include "savegame.h"
|
||||
#include "screens.h"
|
||||
#include "i_specialpaths.h"
|
||||
|
||||
#include "vfs.h"
|
||||
|
||||
|
@ -156,7 +157,7 @@ void G_OpenDemoWrite(void)
|
|||
if (demonum == MAXDEMOS)
|
||||
return;
|
||||
|
||||
if (G_ModDirSnprintf(demofn, sizeof(demofn), DEMOFN_FMT, demonum))
|
||||
if (snprintf(demofn, sizeof(demofn), "%s" DEMOFN_FMT, M_GetDemoPath().GetChars(), demonum))
|
||||
{
|
||||
initprintf("Couldn't start demo writing: INTERNAL ERROR: file name too long\n");
|
||||
goto error_wopen_demo;
|
||||
|
|
|
@ -460,13 +460,6 @@ enum
|
|||
};
|
||||
|
||||
|
||||
#define G_ModDirSnprintf(buf, size, basename, ...) \
|
||||
(((g_modDir[0] != '/') ? Bsnprintf(buf, size, "%s/" basename, g_modDir, ##__VA_ARGS__) : Bsnprintf(buf, size, basename, ##__VA_ARGS__)) \
|
||||
>= ((int32_t)size) - 1)
|
||||
|
||||
#define G_ModDirSnprintfLite(buf, size, basename) \
|
||||
((g_modDir[0] != '/') ? Bsnprintf(buf, size, "%s/%s", g_modDir, basename) : Bsnprintf(buf, size, basename))
|
||||
|
||||
static inline void G_NewGame_EnterLevel(void)
|
||||
{
|
||||
G_NewGame(ud.m_volume_number, ud.m_level_number, ud.m_player_skill);
|
||||
|
|
|
@ -34,6 +34,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#include "gamecvars.h"
|
||||
#include "gamecontrol.h"
|
||||
#include "gameconfigfile.h"
|
||||
#include "files.h"
|
||||
#include "base64.h"
|
||||
|
||||
#include "vfs.h"
|
||||
|
||||
|
@ -5615,13 +5617,21 @@ badindex:
|
|||
int const quoteFilename = *insptr++;
|
||||
|
||||
VM_ASSERT((unsigned)quoteFilename < MAXQUOTES && apStrings[quoteFilename], "invalid quote %d\n", quoteFilename);
|
||||
FStringf IniSection("UserStrings.%s", LumpFilter.GetChars());
|
||||
auto IniKey = apStrings[quoteFilename];
|
||||
if (!GameConfig->SetSection(IniSection))
|
||||
{
|
||||
dispatch();
|
||||
}
|
||||
auto base64 = GameConfig->GetValueForKey(IniKey);
|
||||
if (base64 == nullptr)
|
||||
{
|
||||
dispatch();
|
||||
}
|
||||
auto decoded = base64_decode(base64);
|
||||
FileReader fr;
|
||||
|
||||
auto kFile = kopenFileReader(apStrings[quoteFilename], 0);
|
||||
|
||||
if (!kFile.isOpen())
|
||||
dispatch();
|
||||
|
||||
size_t const filelength = kFile.GetLength();
|
||||
size_t const filelength = decoded.length();
|
||||
size_t const numElements = Gv_GetArrayCountForAllocSize(arrayNum, filelength);
|
||||
|
||||
if (numElements > 0)
|
||||
|
@ -5649,7 +5659,7 @@ badindex:
|
|||
{
|
||||
void *const pArray = Xcalloc(1, newBytes);
|
||||
|
||||
kFile.Read(pArray, readBytes);
|
||||
memcpy(pArray, decoded.c_str(), readBytes);
|
||||
|
||||
if (flags & GAMEARRAY_UNSIGNED)
|
||||
{
|
||||
|
@ -5668,12 +5678,11 @@ badindex:
|
|||
#endif
|
||||
default:
|
||||
memset((char *)pValues + readBytes, 0, newBytes - readBytes);
|
||||
kFile.Read(pValues, readBytes);
|
||||
memcpy(pValues, decoded.c_str(), readBytes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
kFile.Close();
|
||||
dispatch();
|
||||
}
|
||||
|
||||
|
@ -5684,22 +5693,12 @@ badindex:
|
|||
int const quoteFilename = *insptr++;
|
||||
|
||||
VM_ASSERT((unsigned)quoteFilename < MAXQUOTES && apStrings[quoteFilename], "invalid quote %d\n", quoteFilename);
|
||||
|
||||
char temp[BMAX_PATH];
|
||||
|
||||
if (EDUKE32_PREDICT_FALSE(G_ModDirSnprintf(temp, sizeof(temp), "%s", apStrings[quoteFilename])))
|
||||
{
|
||||
CON_ERRPRINTF("file name too long\n");
|
||||
abort_after_error();
|
||||
}
|
||||
|
||||
buildvfs_FILE const fil = buildvfs_fopen_write(temp);
|
||||
|
||||
if (EDUKE32_PREDICT_FALSE(fil == NULL))
|
||||
{
|
||||
CON_ERRPRINTF("couldn't open file \"%s\"\n", temp);
|
||||
abort_after_error();
|
||||
}
|
||||
// No, we are not writing stuff to an arbitrary file on the hard drive! This is a first grade exploit for doing serious damage.
|
||||
// Instead, encode the data as BASE64 and write it to the config file,
|
||||
// which doesn't create a wide open door for exploits.
|
||||
FStringf IniSection("UserStrings.%s", LumpFilter.GetChars());
|
||||
auto IniKey = apStrings[quoteFilename];
|
||||
BufferWriter bw;
|
||||
|
||||
switch (aGameArrays[arrayNum].flags & GAMEARRAY_SIZE_MASK)
|
||||
{
|
||||
|
@ -5713,15 +5712,19 @@ badindex:
|
|||
for (unative_t k = 0; k < numElements; ++k)
|
||||
pArray[k] = Gv_GetArrayValue(arrayNum, k);
|
||||
|
||||
buildvfs_fwrite(pArray, 1, numDiskBytes, fil);
|
||||
bw.Write(pArray, numDiskBytes);
|
||||
Xfree(pArray);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default: buildvfs_fwrite(aGameArrays[arrayNum].pValues, 1, Gv_GetArrayAllocSize(arrayNum), fil); break;
|
||||
default: bw.Write(aGameArrays[arrayNum].pValues, Gv_GetArrayAllocSize(arrayNum)); break;
|
||||
}
|
||||
auto base64 = base64_encode(bw.GetBuffer()->Data(), bw.GetBuffer()->Size());
|
||||
if (GameConfig->SetSection(IniSection))
|
||||
{
|
||||
GameConfig->SetValueForKey(IniKey, base64.c_str());
|
||||
}
|
||||
|
||||
buildvfs_fclose(fil);
|
||||
dispatch();
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#include "enet.h"
|
||||
#include "sjson.h"
|
||||
#include "gamecvars.h"
|
||||
#include "i_specialpaths.h"
|
||||
|
||||
BEGIN_DUKE_NS
|
||||
|
||||
|
@ -5631,7 +5632,7 @@ int portableBackupSave(const char * path, const char * name, int volume, int lev
|
|||
|
||||
char fn[BMAX_PATH];
|
||||
|
||||
if (G_ModDirSnprintf(fn, sizeof(fn), "%s.ext", path))
|
||||
if (snprintf(fn, sizeof(fn), "%s%s.ext", M_GetSavegamesPath().GetChars(), path))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#include "prlights.h"
|
||||
#include "savegame.h"
|
||||
#include "sjson.h"
|
||||
#include "i_specialpaths.h"
|
||||
#include "gamecontrol.h"
|
||||
|
||||
#include "vfs.h"
|
||||
|
||||
|
@ -149,13 +151,13 @@ uint16_t g_nummenusaves;
|
|||
static menusave_t * g_internalsaves;
|
||||
static uint16_t g_numinternalsaves;
|
||||
|
||||
static void ReadSaveGameHeaders_CACHE1D(CACHE1D_FIND_REC *f)
|
||||
static void ReadSaveGameHeaders_CACHE1D(TArray<FString> &saves)
|
||||
{
|
||||
savehead_t h;
|
||||
|
||||
for (; f != nullptr; f = f->next)
|
||||
for (auto &save : saves)
|
||||
{
|
||||
char const * fn = f->name;
|
||||
char const * fn = save;
|
||||
auto fil = fopenFileReader(fn, 0);
|
||||
if (!fil.isOpen())
|
||||
continue;
|
||||
|
@ -201,22 +203,13 @@ static void ReadSaveGameHeaders_CACHE1D(CACHE1D_FIND_REC *f)
|
|||
}
|
||||
}
|
||||
|
||||
static int countcache1dfind(CACHE1D_FIND_REC *f)
|
||||
{
|
||||
int x = 0;
|
||||
for (; f != nullptr; f = f->next)
|
||||
++x;
|
||||
return x;
|
||||
}
|
||||
|
||||
static void ReadSaveGameHeaders_Internal(void)
|
||||
{
|
||||
static char const DefaultPath[] = "/", SavePattern[] = "*.esv";
|
||||
|
||||
CACHE1D_FIND_REC *findfiles_default = klistpath(DefaultPath, SavePattern, CACHE1D_FIND_FILE);
|
||||
|
||||
FString pattern = M_GetSavegamesPath() + "*.esv";
|
||||
TArray<FString> saves;
|
||||
D_AddWildFile(saves, pattern);
|
||||
// potentially overallocating but programmatically simple
|
||||
int const numfiles = countcache1dfind(findfiles_default);
|
||||
int const numfiles = saves.Size();
|
||||
size_t const internalsavesize = sizeof(menusave_t) * numfiles;
|
||||
|
||||
g_internalsaves = (menusave_t *)Xrealloc(g_internalsaves, internalsavesize);
|
||||
|
@ -225,8 +218,7 @@ static void ReadSaveGameHeaders_Internal(void)
|
|||
g_internalsaves[x].clear();
|
||||
|
||||
g_numinternalsaves = 0;
|
||||
ReadSaveGameHeaders_CACHE1D(findfiles_default);
|
||||
klistfree(findfiles_default);
|
||||
ReadSaveGameHeaders_CACHE1D(saves);
|
||||
|
||||
g_nummenusaves = 0;
|
||||
for (int x = g_numinternalsaves-1; x >= 0; --x)
|
||||
|
@ -707,7 +699,7 @@ void G_DeleteSave(savebrief_t const & sv)
|
|||
|
||||
char temp[BMAX_PATH];
|
||||
|
||||
if (G_ModDirSnprintf(temp, sizeof(temp), "%s", sv.path))
|
||||
if (snprintf(temp, sizeof(temp), "%s%s", M_GetSavegamesPath().GetChars(), sv.path))
|
||||
{
|
||||
OSD_Printf("G_SavePlayer: file name \"%s\" too long\n", sv.path);
|
||||
return;
|
||||
|
@ -763,7 +755,7 @@ int32_t G_SavePlayer(savebrief_t & sv, bool isAutoSave)
|
|||
|
||||
if (sv.isValid())
|
||||
{
|
||||
if (G_ModDirSnprintf(fn, sizeof(fn), "%s", sv.path))
|
||||
if (snprintf(fn, sizeof(fn), "%s%s", M_GetSavegamesPath().GetChars(), sv.path))
|
||||
{
|
||||
OSD_Printf("G_SavePlayer: file name \"%s\" too long\n", sv.path);
|
||||
goto saveproblem;
|
||||
|
@ -773,7 +765,7 @@ int32_t G_SavePlayer(savebrief_t & sv, bool isAutoSave)
|
|||
else
|
||||
{
|
||||
static char const SaveName[] = "save0000.esv";
|
||||
int const len = G_ModDirSnprintfLite(fn, ARRAY_SIZE(fn), SaveName);
|
||||
int const len = snprintf(fn, ARRAY_SIZE(fn), "%s%s", M_GetSavegamesPath().GetChars(), SaveName);
|
||||
if (len >= ARRAY_SSIZE(fn)-1)
|
||||
{
|
||||
OSD_Printf("G_SavePlayer: could not form automatic save path\n");
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
#include "printf.h"
|
||||
#include "cmdlib.h"
|
||||
#include "i_findfile.h"
|
||||
#include "gamecontrol.h"
|
||||
#include "m_argv.h"
|
||||
//#include "version.h" // for GAMENAME
|
||||
|
||||
// Stuff that needs to be set up later.
|
||||
|
@ -245,19 +247,19 @@ FString M_GetScreenshotsPath()
|
|||
|
||||
if (!UseKnownFolders())
|
||||
{
|
||||
return progdir;
|
||||
path << progdir << "/Screenshots/";
|
||||
}
|
||||
else if (GetKnownFolder(-1, MyFOLDERID_Screenshots, true, path))
|
||||
{
|
||||
path << "/" GAMENAME;
|
||||
path << "/" GAMENAME "/";
|
||||
}
|
||||
else if (GetKnownFolder(CSIDL_MYPICTURES, FOLDERID_Pictures, true, path))
|
||||
{
|
||||
path << "/Screenshots/" GAMENAME;
|
||||
path << "/Screenshots/" GAMENAME "/";
|
||||
}
|
||||
else
|
||||
{
|
||||
return progdir;
|
||||
path << progdir << "/Screenshots/";
|
||||
}
|
||||
CreatePath(path);
|
||||
return path;
|
||||
|
@ -270,32 +272,47 @@ FString M_GetScreenshotsPath()
|
|||
// Returns the path to the default save games directory.
|
||||
//
|
||||
//===========================================================================
|
||||
CVAR(String, cl_savedir, "", CVAR_ARCHIVE)
|
||||
|
||||
FString M_GetSavegamesPath()
|
||||
{
|
||||
FString path;
|
||||
|
||||
if (!UseKnownFolders())
|
||||
auto dir = Args->CheckValue("-savedir");
|
||||
if (dir)
|
||||
{
|
||||
return progdir;
|
||||
path = dir;
|
||||
path.Substitute("\\", "/");
|
||||
if (path[path.Len() - 1] != '/') path << '/';
|
||||
}
|
||||
else if (*cl_savedir)
|
||||
{
|
||||
path = cl_savedir;
|
||||
path.Substitute("\\", "/");
|
||||
if (path[path.Len() - 1] != '/') path << '/';
|
||||
path << LumpFilter << '/';
|
||||
}
|
||||
else if (!UseKnownFolders())
|
||||
{
|
||||
path << progdir << "Save/" << LumpFilter << "/";
|
||||
}
|
||||
// Try standard Saved Games folder
|
||||
else if (GetKnownFolder(-1, FOLDERID_SavedGames, true, path))
|
||||
{
|
||||
path << "/" GAMENAME;
|
||||
path << "/" GAMENAME "/" << LumpFilter << "/";
|
||||
}
|
||||
// Try defacto My Documents/My Games folder
|
||||
else if (GetKnownFolder(CSIDL_PERSONAL, FOLDERID_Documents, true, path))
|
||||
{
|
||||
// I assume since this isn't a standard folder, it doesn't have
|
||||
// a localized name either.
|
||||
path << "/My Games/" GAMENAME;
|
||||
CreatePath(path);
|
||||
path << "/My Games/" GAMENAME "/" << LumpFilter << "/";
|
||||
}
|
||||
else
|
||||
{
|
||||
path = progdir;
|
||||
path << progdir << "Save/" << LumpFilter << "/";
|
||||
}
|
||||
CreatePath(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
|
@ -327,7 +344,7 @@ FString M_GetDocumentsPath()
|
|||
{
|
||||
// I assume since this isn't a standard folder, it doesn't have
|
||||
// a localized name either.
|
||||
path << "/My Games/" GAMENAME;
|
||||
path << "/My Games/" GAMENAME "/";
|
||||
CreatePath(path);
|
||||
}
|
||||
else
|
||||
|
@ -337,6 +354,40 @@ FString M_GetDocumentsPath()
|
|||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetDocumentsPath Windows
|
||||
//
|
||||
// Returns the path to the default documents directory.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetDemoPath()
|
||||
{
|
||||
FString path;
|
||||
|
||||
// A portable INI means that this storage location should also be portable.
|
||||
path.Format("%s" GAMENAME "_portable.ini", progdir.GetChars());
|
||||
if (FileExists(path) || !UseKnownFolders())
|
||||
{
|
||||
path << progdir << "Demos/" << LumpFilter << '/';
|
||||
}
|
||||
else
|
||||
// Try defacto My Documents/My Games folder
|
||||
if (GetKnownFolder(CSIDL_PERSONAL, FOLDERID_Documents, true, path))
|
||||
{
|
||||
// I assume since this isn't a standard folder, it doesn't have
|
||||
// a localized name either.
|
||||
path << "/My Games/" GAMENAME "/" << LumpFilter << '/';
|
||||
}
|
||||
else
|
||||
{
|
||||
path << progdir << "Demos/" << LumpFilter << '/';
|
||||
}
|
||||
CreatePath(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// I_FindFirst
|
||||
|
|
|
@ -83,8 +83,6 @@ static inline void clearfilenames(void)
|
|||
|
||||
static inline void getfilenames(char const *path)
|
||||
{
|
||||
clearfilenames();
|
||||
finddirs = klistpath(path,"*",CACHE1D_FIND_DIR);
|
||||
}
|
||||
|
||||
#define POPULATE_VIDEO 1
|
||||
|
|
|
@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#include "menus.h"
|
||||
#include "savegame.h"
|
||||
#include "screens.h"
|
||||
#include "i_specialpaths.h"
|
||||
|
||||
#include "vfs.h"
|
||||
|
||||
|
@ -159,7 +160,7 @@ void G_OpenDemoWrite(void)
|
|||
if (demonum == MAXDEMOS)
|
||||
return;
|
||||
|
||||
if (G_ModDirSnprintf(demofn, sizeof(demofn), DEMOFN_FMT, demonum))
|
||||
if (snprintf(demofn, sizeof(demofn), "%s" DEMOFN_FMT, M_GetSavegamesPath().GetChars(), demonum))
|
||||
{
|
||||
initprintf("Couldn't start demo writing: INTERNAL ERROR: file name too long\n");
|
||||
goto error_wopen_demo;
|
||||
|
|
|
@ -436,16 +436,6 @@ enum
|
|||
};
|
||||
|
||||
|
||||
#define G_ModDirSnprintf(buf, size, basename, ...) \
|
||||
\
|
||||
(((g_modDir[0] != '/') ? Bsnprintf(buf, size, "%s/" basename, g_modDir, ##__VA_ARGS__) \
|
||||
: Bsnprintf(buf, size, basename, ##__VA_ARGS__)) >= ((int32_t)size) - 1\
|
||||
)
|
||||
#define G_ModDirSnprintfLite(buf, size, basename) \
|
||||
\
|
||||
((g_modDir[0] != '/') ? Bsnprintf(buf, size, "%s/%s", g_modDir, basename) \
|
||||
: Bsnprintf(buf, size, basename))
|
||||
|
||||
static inline void G_NewGame_EnterLevel(void)
|
||||
{
|
||||
G_NewGame(ud.m_volume_number, ud.m_level_number, ud.m_player_skill);
|
||||
|
|
|
@ -25,6 +25,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#include "premap.h"
|
||||
#include "prlights.h"
|
||||
#include "savegame.h"
|
||||
#include "i_specialpaths.h"
|
||||
#include "gamecontrol.h"
|
||||
|
||||
BEGIN_RR_NS
|
||||
|
||||
|
@ -144,14 +146,14 @@ uint16_t g_nummenusaves;
|
|||
static menusave_t * g_internalsaves;
|
||||
static uint16_t g_numinternalsaves;
|
||||
|
||||
static void ReadSaveGameHeaders_CACHE1D(CACHE1D_FIND_REC *f)
|
||||
static void ReadSaveGameHeaders_CACHE1D(TArray<FString>& saves)
|
||||
{
|
||||
savehead_t h;
|
||||
|
||||
for (; f != nullptr; f = f->next)
|
||||
{
|
||||
char const * fn = f->name;
|
||||
auto fil = fopenFileReader(fn, 0);
|
||||
for (auto& save : saves)
|
||||
{
|
||||
char const* fn = save;
|
||||
auto fil = fopenFileReader(fn, 0);
|
||||
if (!fil.isOpen())
|
||||
continue;
|
||||
|
||||
|
@ -181,23 +183,15 @@ static void ReadSaveGameHeaders_CACHE1D(CACHE1D_FIND_REC *f)
|
|||
}
|
||||
}
|
||||
|
||||
static int countcache1dfind(CACHE1D_FIND_REC *f)
|
||||
{
|
||||
int x = 0;
|
||||
for (; f != nullptr; f = f->next)
|
||||
++x;
|
||||
return x;
|
||||
}
|
||||
|
||||
static void ReadSaveGameHeaders_Internal(void)
|
||||
{
|
||||
static char const DefaultPath[] = "/", SavePattern[] = "*.esv";
|
||||
|
||||
CACHE1D_FIND_REC *findfiles_default = klistpath(DefaultPath, SavePattern, CACHE1D_FIND_FILE);
|
||||
FString pattern = M_GetSavegamesPath() + "*.esv";
|
||||
TArray<FString> saves;
|
||||
D_AddWildFile(saves, pattern);
|
||||
|
||||
// potentially overallocating but programmatically simple
|
||||
int const numfiles = countcache1dfind(findfiles_default);
|
||||
size_t const internalsavesize = sizeof(menusave_t) * numfiles;
|
||||
int const numfiles = saves.Size();
|
||||
size_t const internalsavesize = sizeof(menusave_t) * numfiles;
|
||||
|
||||
g_internalsaves = (menusave_t *)Xrealloc(g_internalsaves, internalsavesize);
|
||||
|
||||
|
@ -205,8 +199,7 @@ static void ReadSaveGameHeaders_Internal(void)
|
|||
g_internalsaves[x].clear();
|
||||
|
||||
g_numinternalsaves = 0;
|
||||
ReadSaveGameHeaders_CACHE1D(findfiles_default);
|
||||
klistfree(findfiles_default);
|
||||
ReadSaveGameHeaders_CACHE1D(saves);
|
||||
|
||||
g_nummenusaves = 0;
|
||||
for (int x = g_numinternalsaves-1; x >= 0; --x)
|
||||
|
@ -439,7 +432,7 @@ void G_DeleteSave(savebrief_t const & sv)
|
|||
|
||||
char temp[BMAX_PATH];
|
||||
|
||||
if (G_ModDirSnprintf(temp, sizeof(temp), "%s", sv.path))
|
||||
if (snprintf(temp, sizeof(temp), "%s%s", M_GetSavegamesPath().GetChars(), sv.path))
|
||||
{
|
||||
OSD_Printf("G_SavePlayer: file name \"%s\" too long\n", sv.path);
|
||||
return;
|
||||
|
@ -493,7 +486,7 @@ int32_t G_SavePlayer(savebrief_t & sv, bool isAutoSave)
|
|||
|
||||
if (sv.isValid())
|
||||
{
|
||||
if (G_ModDirSnprintf(temp, sizeof(temp), "%s", sv.path))
|
||||
if (snprintf(temp, sizeof(temp), "%s%s", M_GetSavegamesPath().GetChars(), sv.path))
|
||||
{
|
||||
OSD_Printf("G_SavePlayer: file name \"%s\" too long\n", sv.path);
|
||||
goto saveproblem;
|
||||
|
@ -503,7 +496,7 @@ int32_t G_SavePlayer(savebrief_t & sv, bool isAutoSave)
|
|||
else
|
||||
{
|
||||
static char const SaveName[] = "save0000.esv";
|
||||
int const len = G_ModDirSnprintfLite(temp, ARRAY_SIZE(temp), SaveName);
|
||||
int const len = snprintf(temp, ARRAY_SIZE(temp), "%s%s", M_GetSavegamesPath().GetChars(), SaveName);
|
||||
if (len >= ARRAY_SSIZE(temp)-1)
|
||||
{
|
||||
OSD_Printf("G_SavePlayer: could not form automatic save path\n");
|
||||
|
|
|
@ -55,6 +55,7 @@ Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
|
|||
#include "cache.h"
|
||||
#include "colormap.h"
|
||||
#include "player.h"
|
||||
#include "i_specialpaths.h"
|
||||
|
||||
//void TimerFunc(task * Task);
|
||||
BEGIN_SW_NS
|
||||
|
@ -240,13 +241,13 @@ int SaveGame(short save_num)
|
|||
PANEL_SPRITE tpanel_sprite;
|
||||
PANEL_SPRITEp psp,cur,next;
|
||||
SECTOR_OBJECTp sop;
|
||||
char game_name[80];
|
||||
char game_name[256];
|
||||
int cnt = 0, saveisshot=0;
|
||||
OrgTileP otp, next_otp;
|
||||
|
||||
Saveable_Init();
|
||||
|
||||
sprintf(game_name,"game%d.sav",save_num);
|
||||
snprintf(game_name, 256, "%sgame%d.sav", M_GetSavegamesPath().GetChars(), save_num);
|
||||
if ((fil = MOPEN_WRITE(game_name)) == MOPEN_WRITE_ERR)
|
||||
return -1;
|
||||
|
||||
|
@ -702,12 +703,12 @@ int SaveGame(short save_num)
|
|||
int LoadGameFullHeader(short save_num, char *descr, short *level, short *skill)
|
||||
{
|
||||
MFILE_READ fil;
|
||||
char game_name[80];
|
||||
char game_name[256];
|
||||
short tile;
|
||||
int ver;
|
||||
|
||||
sprintf(game_name,"game%d.sav",save_num);
|
||||
if ((fil = MOPEN_READ(game_name)) == MOPEN_READ_ERR)
|
||||
snprintf(game_name, 256, "%sgame%d.sav", M_GetSavegamesPath().GetChars(), save_num);
|
||||
if ((fil = MOPEN_READ(game_name)) == MOPEN_READ_ERR)
|
||||
return -1;
|
||||
|
||||
MREAD(&ver,sizeof(ver),1,fil);
|
||||
|
@ -733,12 +734,12 @@ int LoadGameFullHeader(short save_num, char *descr, short *level, short *skill)
|
|||
void LoadGameDescr(short save_num, char *descr)
|
||||
{
|
||||
MFILE_READ fil;
|
||||
char game_name[80];
|
||||
char game_name[256];
|
||||
short tile;
|
||||
int ver;
|
||||
|
||||
sprintf(game_name,"game%d.sav",save_num);
|
||||
if ((fil = MOPEN_READ(game_name)) == MOPEN_READ_ERR)
|
||||
snprintf(game_name, 256, "%sgame%d.sav", M_GetSavegamesPath().GetChars(), save_num);
|
||||
if ((fil = MOPEN_READ(game_name)) == MOPEN_READ_ERR)
|
||||
return;
|
||||
|
||||
MREAD(&ver,sizeof(ver),1,fil);
|
||||
|
@ -770,7 +771,7 @@ int LoadGame(short save_num)
|
|||
int16_t data_ndx;
|
||||
PANEL_SPRITEp psp,next,cur;
|
||||
PANEL_SPRITE tpanel_sprite;
|
||||
char game_name[80];
|
||||
char game_name[256];
|
||||
OrgTileP otp, next_otp;
|
||||
|
||||
int RotNdx;
|
||||
|
@ -781,8 +782,8 @@ int LoadGame(short save_num)
|
|||
|
||||
Saveable_Init();
|
||||
|
||||
sprintf(game_name,"game%d.sav",save_num);
|
||||
if ((fil = MOPEN_READ(game_name)) == MOPEN_READ_ERR)
|
||||
snprintf(game_name, 256, "%sgame%d.sav", M_GetSavegamesPath().GetChars(), save_num);
|
||||
if ((fil = MOPEN_READ(game_name)) == MOPEN_READ_ERR)
|
||||
return -1;
|
||||
|
||||
MREAD(&i,sizeof(i),1,fil);
|
||||
|
|
14
source/thirdparty/include/base64.h
vendored
Normal file
14
source/thirdparty/include/base64.h
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// base64 encoding and decoding with C++.
|
||||
// Version: 1.01.00
|
||||
//
|
||||
|
||||
#ifndef BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
|
||||
#define BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string base64_encode(unsigned char const* , unsigned int len);
|
||||
std::string base64_decode(std::string const& s);
|
||||
|
||||
#endif /* BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A */
|
121
source/thirdparty/src/base64.cpp
vendored
Normal file
121
source/thirdparty/src/base64.cpp
vendored
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
base64.cpp and base64.h
|
||||
|
||||
base64 encoding and decoding with C++.
|
||||
|
||||
Version: 1.01.00
|
||||
|
||||
Copyright (C) 2004-2017 René Nyffenegger
|
||||
|
||||
This source code is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the author be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this source code must not be misrepresented; you must not
|
||||
claim that you wrote the original source code. If you use this source code
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original source code.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||
|
||||
*/
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
static const std::string base64_chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
|
||||
static inline bool is_base64(unsigned char c) {
|
||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||
}
|
||||
|
||||
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
unsigned char char_array_3[3];
|
||||
unsigned char char_array_4[4];
|
||||
|
||||
while (in_len--) {
|
||||
char_array_3[i++] = *(bytes_to_encode++);
|
||||
if (i == 3) {
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for(i = 0; (i <4) ; i++)
|
||||
ret += base64_chars[char_array_4[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i)
|
||||
{
|
||||
for(j = i; j < 3; j++)
|
||||
char_array_3[j] = '\0';
|
||||
|
||||
char_array_4[0] = ( char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
|
||||
for (j = 0; (j < i + 1); j++)
|
||||
ret += base64_chars[char_array_4[j]];
|
||||
|
||||
while((i++ < 3))
|
||||
ret += '=';
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
std::string base64_decode(std::string const& encoded_string) {
|
||||
size_t in_len = encoded_string.size();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int in_ = 0;
|
||||
unsigned char char_array_4[4], char_array_3[3];
|
||||
std::string ret;
|
||||
|
||||
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
|
||||
char_array_4[i++] = encoded_string[in_]; in_++;
|
||||
if (i ==4) {
|
||||
for (i = 0; i <4; i++)
|
||||
char_array_4[i] = base64_chars.find(char_array_4[i]) & 0xff;
|
||||
|
||||
char_array_3[0] = ( char_array_4[0] << 2 ) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (i = 0; (i < 3); i++)
|
||||
ret += char_array_3[i];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = 0; j < i; j++)
|
||||
char_array_4[j] = base64_chars.find(char_array_4[j]) & 0xff;
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
|
||||
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
Loading…
Reference in a new issue