From 1c0c9787d4ef14d6f4bc11334f7e8ff234e86f3a Mon Sep 17 00:00:00 2001 From: Marek Kulik Date: Mon, 7 Aug 2023 22:04:05 +0200 Subject: [PATCH] Always return entire file with fileGetContents --- Client/mods/deathmatch/logic/CScriptFile.cpp | 30 +++++++++++++++++++ Client/mods/deathmatch/logic/CScriptFile.h | 2 ++ Server/mods/deathmatch/logic/CScriptFile.cpp | 30 +++++++++++++++++++ Server/mods/deathmatch/logic/CScriptFile.h | 2 ++ .../deathmatch/logic/luadefs/CLuaFileDefs.cpp | 14 +++------ .../deathmatch/logic/luadefs/CLuaFileDefs.h | 2 +- 6 files changed, 69 insertions(+), 11 deletions(-) diff --git a/Client/mods/deathmatch/logic/CScriptFile.cpp b/Client/mods/deathmatch/logic/CScriptFile.cpp index 7a464114bd..d9ee531842 100644 --- a/Client/mods/deathmatch/logic/CScriptFile.cpp +++ b/Client/mods/deathmatch/logic/CScriptFile.cpp @@ -189,6 +189,36 @@ long CScriptFile::Write(unsigned long ulSize, const char* pData) return m_pFile->FWrite(pData, ulSize); } +long CScriptFile::GetContents(std::string& buffer) +{ + if (!m_pFile) + return -1; + + // Store the current position to restore it later. + const int currentPos = m_pFile->FTell(); + + // Move to the end of the file to determine the size. + m_pFile->FSeek(0, SEEK_END); + const int fileSize = m_pFile->FTell(); + + try + { + buffer.resize(fileSize); + } + catch (const std::bad_alloc&) + { + m_pFile->FSeek(currentPos, SEEK_SET); + return -2; + } + + // Move to the start of the file to read the entire file. + m_pFile->FSeek(0, SEEK_SET); + const int bytesRead = m_pFile->FRead(buffer.data(), fileSize); + m_pFile->FSeek(currentPos, SEEK_SET); + buffer.resize(bytesRead); + return bytesRead; +} + // If file was downloaded with a resource, validate checksum void CScriptFile::DoResourceFileCheck() { diff --git a/Client/mods/deathmatch/logic/CScriptFile.h b/Client/mods/deathmatch/logic/CScriptFile.h index b4b8358f37..c3d801821d 100644 --- a/Client/mods/deathmatch/logic/CScriptFile.h +++ b/Client/mods/deathmatch/logic/CScriptFile.h @@ -68,6 +68,8 @@ class CScriptFile final : public CClientEntity long Read(unsigned long ulSize, SString& outBuffer); long Write(unsigned long ulSize, const char* pData); + long GetContents(std::string& buffer); + // Debug info for garbage collected files const SLuaDebugInfo& GetLuaDebugInfo() { return m_LuaDebugInfo; }; void SetLuaDebugInfo(const SLuaDebugInfo& luaDebugInfo) { m_LuaDebugInfo = luaDebugInfo; }; diff --git a/Server/mods/deathmatch/logic/CScriptFile.cpp b/Server/mods/deathmatch/logic/CScriptFile.cpp index 34856e3326..f8270df393 100644 --- a/Server/mods/deathmatch/logic/CScriptFile.cpp +++ b/Server/mods/deathmatch/logic/CScriptFile.cpp @@ -209,6 +209,36 @@ long CScriptFile::Write(unsigned long ulSize, const char* pData) return fwrite(pData, 1, ulSize, m_pFile); } +long CScriptFile::GetContents(std::string& buffer) +{ + if (!m_pFile) + return -1; + + // Store the current position to restore it later. + const long currentPos = ftell(m_pFile); + + // Move to the end of the file to determine the size. + fseek(m_pFile, 0, SEEK_END); + const long fileSize = ftell(m_pFile); + + try + { + buffer.resize(fileSize); + } + catch (const std::bad_alloc&) + { + fseek(m_pFile, currentPos, SEEK_SET); + return -2; + } + + // Move to the start of the file to read the entire file. + fseek(m_pFile, 0, SEEK_SET); + const long bytesRead = fread(buffer.data(), 1, fileSize, m_pFile); + fseek(m_pFile, currentPos, SEEK_SET); + buffer.resize(bytesRead); + return bytesRead; +} + CResource* CScriptFile::GetResource() { return m_pResource; diff --git a/Server/mods/deathmatch/logic/CScriptFile.h b/Server/mods/deathmatch/logic/CScriptFile.h index 4c6eedcb5b..e71a745ce6 100644 --- a/Server/mods/deathmatch/logic/CScriptFile.h +++ b/Server/mods/deathmatch/logic/CScriptFile.h @@ -62,6 +62,8 @@ class CScriptFile final : public CElement long Read(unsigned long ulSize, SString& outBuffer); long Write(unsigned long ulSize, const char* pData); + long GetContents(std::string& buffer); + // Debug info for garbage collected files const SLuaDebugInfo& GetLuaDebugInfo() { return m_LuaDebugInfo; }; void SetLuaDebugInfo(const SLuaDebugInfo& luaDebugInfo) { m_LuaDebugInfo = luaDebugInfo; }; diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaFileDefs.cpp b/Shared/mods/deathmatch/logic/luadefs/CLuaFileDefs.cpp index b7602e3649..772e569675 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaFileDefs.cpp +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaFileDefs.cpp @@ -799,14 +799,12 @@ int CLuaFileDefs::fileWrite(lua_State* luaVM) return 1; } -std::optional CLuaFileDefs::fileGetContents(lua_State* L, CScriptFile* scriptFile, std::optional maybeVerifyContents) +std::optional CLuaFileDefs::fileGetContents(lua_State* L, CScriptFile* scriptFile, std::optional maybeVerifyContents) { - // bool fileGetContents ( file target [, bool verifyContents = true ] ) + // string fileGetContents ( file target [, bool verifyContents = true ] ) - SString buffer; - - // We abuse the logic of CScriptFile::Read to determine size of file and to resize the buffer accordingly, to avoid doing that work twice. - const long bytesRead = scriptFile->Read(std::numeric_limits::max(), buffer); + std::string buffer; + const long bytesRead = scriptFile->GetContents(buffer); if (bytesRead == -2) { @@ -819,10 +817,6 @@ std::optional CLuaFileDefs::fileGetContents(lua_State* L, CScriptFile* return {}; } - // Remove EOF byte at the end of the buffer (which breaks checksum if we have to compute it below). - if (!buffer.empty()) - buffer.resize(buffer.size() - 1); - if (maybeVerifyContents.value_or(true) == false) return buffer; diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaFileDefs.h b/Shared/mods/deathmatch/logic/luadefs/CLuaFileDefs.h index 21739ecfbb..9e42e07f29 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaFileDefs.h +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaFileDefs.h @@ -30,7 +30,7 @@ class CLuaFileDefs : public CLuaDefs LUA_DECLARE(fileFlush); LUA_DECLARE(fileRead); LUA_DECLARE(fileWrite); - static std::optional fileGetContents(lua_State* L, CScriptFile* scriptFile, std::optional maybeVerifyContents); + static std::optional fileGetContents(lua_State* L, CScriptFile* scriptFile, std::optional maybeVerifyContents); LUA_DECLARE(fileGetPos); LUA_DECLARE(fileGetSize);