diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 172977b17..802c2169a 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -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 diff --git a/source/blood/src/common_game.h b/source/blood/src/common_game.h index 8ca7e8890..25216260d 100644 --- a/source/blood/src/common_game.h +++ b/source/blood/src/common_game.h @@ -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) { diff --git a/source/blood/src/demo.cpp b/source/blood/src/demo.cpp index a42173af9..95e5324a5 100644 --- a/source/blood/src/demo.cpp +++ b/source/blood/src/demo.cpp @@ -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 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; } diff --git a/source/blood/src/loadsave.cpp b/source/blood/src/loadsave.cpp index d576f6106..9e3234690 100644 --- a/source/blood/src/loadsave.cpp +++ b/source/blood/src/loadsave.cpp @@ -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 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) diff --git a/source/blood/src/menu.cpp b/source/blood/src/menu.cpp index 07382b881..afbc017d1 100644 --- a/source/blood/src/menu.cpp +++ b/source/blood/src/menu.cpp @@ -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]); diff --git a/source/build/include/cache1d.h b/source/build/include/cache1d.h index 8bf9aa2e1..2c3fac8fa 100644 --- a/source/build/include/cache1d.h +++ b/source/build/include/cache1d.h @@ -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, diff --git a/source/build/src/cache1d.cpp b/source/build/src/cache1d.cpp index 488f32dcd..245991840 100644 --- a/source/build/src/cache1d.cpp +++ b/source/build/src/cache1d.cpp @@ -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) { diff --git a/source/common/filesystem/resourcefile.cpp b/source/common/filesystem/resourcefile.cpp index 3fed881f8..36857ee67 100644 --- a/source/common/filesystem/resourcefile.cpp +++ b/source/common/filesystem/resourcefile.cpp @@ -38,8 +38,7 @@ #include "resourcefile.h" #include "name.h" #include "m_swap.h" - -extern FString LumpFilter; +#include "gamecontrol.h" //========================================================================== // diff --git a/source/common/gamecontrol.h b/source/common/gamecontrol.h index 68cf9bfbb..59013abd0 100644 --- a/source/common/gamecontrol.h +++ b/source/common/gamecontrol.h @@ -9,8 +9,10 @@ #include "gamecvars.h" extern FString currentGame; +extern FString LumpFilter; class FArgs; +void D_AddWildFile(TArray& wadfiles, const char* value); extern uint8_t KeyboardKeys[NUMGAMEFUNCTIONS][2]; diff --git a/source/common/gamecvars.cpp b/source/common/gamecvars.cpp index cd58531f3..3e92e61bf 100644 --- a/source/common/gamecvars.cpp +++ b/source/common/gamecvars.cpp @@ -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 diff --git a/source/common/i_specialpaths.h b/source/common/i_specialpaths.h index 7c51bae37..e8929a048 100644 --- a/source/common/i_specialpaths.h +++ b/source/common/i_specialpaths.h @@ -11,6 +11,7 @@ FString M_GetConfigPath(bool for_reading); FString M_GetScreenshotsPath(); FString M_GetSavegamesPath(); FString M_GetDocumentsPath(); +FString M_GetDemoPath(); #ifdef __APPLE__ diff --git a/source/duke3d/src/demo.cpp b/source/duke3d/src/demo.cpp index 7e642b905..9dc616f14 100644 --- a/source/duke3d/src/demo.cpp +++ b/source/duke3d/src/demo.cpp @@ -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; diff --git a/source/duke3d/src/game.h b/source/duke3d/src/game.h index 8627c2137..90cea299e 100644 --- a/source/duke3d/src/game.h +++ b/source/duke3d/src/game.h @@ -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); diff --git a/source/duke3d/src/gameexec.cpp b/source/duke3d/src/gameexec.cpp index a64a1ee1b..db5949985 100644 --- a/source/duke3d/src/gameexec.cpp +++ b/source/duke3d/src/gameexec.cpp @@ -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(); } diff --git a/source/duke3d/src/player.cpp b/source/duke3d/src/player.cpp index b1052bc8c..083431131 100644 --- a/source/duke3d/src/player.cpp +++ b/source/duke3d/src/player.cpp @@ -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; } diff --git a/source/duke3d/src/savegame.cpp b/source/duke3d/src/savegame.cpp index 360737321..1cbc73b6e 100644 --- a/source/duke3d/src/savegame.cpp +++ b/source/duke3d/src/savegame.cpp @@ -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 &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 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"); diff --git a/source/platform/win32/i_specialpaths.cpp b/source/platform/win32/i_specialpaths.cpp index f520ed207..3cd9c8a20 100644 --- a/source/platform/win32/i_specialpaths.cpp +++ b/source/platform/win32/i_specialpaths.cpp @@ -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 diff --git a/source/platform/win32/startwin.game.cpp b/source/platform/win32/startwin.game.cpp index 343791cb7..88255ffa3 100644 --- a/source/platform/win32/startwin.game.cpp +++ b/source/platform/win32/startwin.game.cpp @@ -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 diff --git a/source/rr/src/demo.cpp b/source/rr/src/demo.cpp index cb06ee09d..861920fdc 100644 --- a/source/rr/src/demo.cpp +++ b/source/rr/src/demo.cpp @@ -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; diff --git a/source/rr/src/game.h b/source/rr/src/game.h index 63e8b89b0..83b72377f 100644 --- a/source/rr/src/game.h +++ b/source/rr/src/game.h @@ -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); diff --git a/source/rr/src/savegame.cpp b/source/rr/src/savegame.cpp index 1d4495a0f..2147e7360 100644 --- a/source/rr/src/savegame.cpp +++ b/source/rr/src/savegame.cpp @@ -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& 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 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"); diff --git a/source/sw/src/save.cpp b/source/sw/src/save.cpp index be11dbf44..3ee8e5b48 100644 --- a/source/sw/src/save.cpp +++ b/source/sw/src/save.cpp @@ -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); diff --git a/source/thirdparty/include/base64.h b/source/thirdparty/include/base64.h new file mode 100644 index 000000000..dd1134c30 --- /dev/null +++ b/source/thirdparty/include/base64.h @@ -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 + +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 */ diff --git a/source/thirdparty/src/base64.cpp b/source/thirdparty/src/base64.cpp new file mode 100644 index 000000000..7dfc7dd4e --- /dev/null +++ b/source/thirdparty/src/base64.cpp @@ -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; +}