[openjk] 52/130: Add try_read method Revise SG_GetSaveGameComment and SG_ReadSavegame

Simon McVittie smcv at debian.org
Fri Oct 28 11:09:17 UTC 2016


This is an automated email from the git hooks/post-receive script.

smcv pushed a commit to branch debian/master
in repository openjk.

commit f3862ce59428ef8231a3cdf3d30a874782ea69a6
Author: bibendovsky <bibendovsky at hotmail.com>
Date:   Sun Jul 24 17:48:48 2016 +0300

    Add try_read method
    Revise SG_GetSaveGameComment and SG_ReadSavegame
---
 code/CMakeLists.txt                   |   1 +
 code/game/CMakeLists.txt              |   2 +-
 code/rd-vanilla/CMakeLists.txt        |   1 +
 code/server/sv_savegame.cpp           | 266 +++++++++++++++++++---------------
 codeJK2/game/CMakeLists.txt           |   2 +-
 shared/qcommon/ojk_i_saved_game.h     |  57 ++++++--
 shared/qcommon/ojk_i_saved_game_fwd.h |  28 +++-
 shared/qcommon/ojk_saved_game.cpp     | 195 ++++++++++++-------------
 shared/qcommon/ojk_saved_game.h       |  27 ++--
 shared/qcommon/ojk_scope_guard.h      |  58 ++++++++
 10 files changed, 392 insertions(+), 245 deletions(-)

diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt
index 7e1dff4..571aba2 100644
--- a/code/CMakeLists.txt
+++ b/code/CMakeLists.txt
@@ -182,6 +182,7 @@ if(BuildSPEngine OR BuildJK2SPEngine)
 		"${SharedDir}/qcommon/ojk_saved_game.cpp"
 		"${SharedDir}/qcommon/ojk_saved_game_exception.h"
 		"${SharedDir}/qcommon/ojk_saved_game_exception.cpp"
+		"${SharedDir}/qcommon/ojk_scope_guard.h"
 
 		${SharedCommonFiles}
 		)
diff --git a/code/game/CMakeLists.txt b/code/game/CMakeLists.txt
index da8a64d..9438679 100644
--- a/code/game/CMakeLists.txt
+++ b/code/game/CMakeLists.txt
@@ -263,7 +263,7 @@ set(SPGameCommonFiles
 	"${SPDir}/rd-common/mdx_format.h"
 	"${SharedDir}/qcommon/ojk_i_saved_game.h"
 	"${SharedDir}/qcommon/ojk_i_saved_game_fwd.h"
-	
+	"${SharedDir}/qcommon/ojk_scope_guard.h"
 	${SharedCommonFiles}
 	)
 source_group("common" FILES ${SPGameCommonFiles})
diff --git a/code/rd-vanilla/CMakeLists.txt b/code/rd-vanilla/CMakeLists.txt
index f16462d..5172eb9 100644
--- a/code/rd-vanilla/CMakeLists.txt
+++ b/code/rd-vanilla/CMakeLists.txt
@@ -80,6 +80,7 @@ if(BuildSPRdVanilla OR BuildJK2SPRdVanilla)
 		"${SPDir}/qcommon/q_shared.h"
 		"${SharedDir}/qcommon/ojk_i_saved_game.h"
 		"${SharedDir}/qcommon/ojk_i_saved_game_fwd.h"
+		"${SharedDir}/qcommon/ojk_scope_guard.h"
 		${SharedCommonFiles}
 		)
 	source_group("common" FILES ${SPRDVanillaCommonFiles})
diff --git a/code/server/sv_savegame.cpp b/code/server/sv_savegame.cpp
index 76dfdba..2ae7b43 100644
--- a/code/server/sv_savegame.cpp
+++ b/code/server/sv_savegame.cpp
@@ -38,6 +38,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 #include <map>
 
 #include "qcommon/ojk_saved_game.h"
+#include "qcommon/ojk_saved_game_exception.h"
 
 static char	saveGameComment[iSG_COMMENT_SIZE];
 
@@ -930,65 +931,62 @@ static time_t SG_GetTime ( unsigned int timestamp )
 // Test to see if the given file name is in the save game directory
 // then grab the comment if it's there
 //
-int SG_GetSaveGameComment(const char *psPathlessBaseName, char *sComment, char *sMapName)
+int SG_GetSaveGameComment(
+    const char* psPathlessBaseName,
+    char* sComment,
+    char* sMapName)
 {
-	int ret = 0;
-	time_t tFileTime;
-#ifdef JK2_MODE
-	size_t iScreenShotLength;
-#endif
+    auto ret = 0;
 
     auto saved_game = &ojk::SavedGame::get_instance();
 
-    saved_game->set_preview_mode(
-        true);
+    try
+    {
+        if (!saved_game->open(
+            psPathlessBaseName))
+        {
+            return 0;
+        }
 
-	if (!saved_game->open(
-        psPathlessBaseName))
-	{
-		saved_game->set_preview_mode(
-            false);
+        saved_game->read_chunk(
+            INT_ID('C', 'O', 'M', 'M'),
+            sComment,
+            iSG_COMMENT_SIZE);
 
-		return 0;
-	}
+        unsigned int fileTime = 0;
 
-    if (saved_game->read_chunk(
-        INT_ID('C','O','M','M'),
-        sComment,
-        iSG_COMMENT_SIZE))
-	{
-		unsigned int fileTime = 0;
+        saved_game->read_chunk<uint32_t>(
+            INT_ID('C', 'M', 'T', 'M'),
+            fileTime);
+
+        auto tFileTime = ::SG_GetTime(
+            fileTime);
 
-		if (saved_game->read_chunk<uint32_t>(
-            INT_ID('C','M','T','M'),
-            fileTime))
-		{
-			tFileTime = SG_GetTime (fileTime);
-#ifdef JK2_MODE
-			if (saved_game->read_chunk<uint32_t>(
-                INT_ID('S','H','L','N'),
-                iScreenShotLength))
-			{
-                if (saved_game->read_chunk(INT_ID('S','H','O','T')))
-				{
-#endif
-            if (saved_game->read_chunk(
-                INT_ID('M','P','C','M'),
-                sMapName,
-                iSG_MAPCMD_SIZE))
-			{
-				ret = tFileTime;
-			}
 #ifdef JK2_MODE
-				}
-			}
+        size_t iScreenShotLength;
+
+        saved_game->read_chunk<uint32_t>(
+            INT_ID('S', 'H', 'L', 'N'),
+            iScreenShotLength);
+
+        saved_game->read_chunk(
+            INT_ID('S', 'H', 'O', 'T'));
 #endif
-		}
-	}
+
+        saved_game->read_chunk(
+            INT_ID('M', 'P', 'C', 'M'),
+            sMapName,
+            iSG_MAPCMD_SIZE);
+
+        ret = tFileTime;
+    }
+    catch (ojk::SavedGameException&)
+    {
+    }
 
     saved_game->close();
 
-	return ret;
+    return ret;
 }
 
 
@@ -1288,93 +1286,133 @@ qboolean SG_WriteSavegame(const char *psPathlessBaseName, qboolean qbAutosave)
 	return qtrue;
 }
 
-qboolean SG_ReadSavegame(const char *psPathlessBaseName)
+qboolean SG_ReadSavegame(
+    const char* psPathlessBaseName)
 {
-	char		sComment[iSG_COMMENT_SIZE];
-	char		sMapCmd [iSG_MAPCMD_SIZE];
-	qboolean	qbAutosave;
-
-	int iPrevTestSave = sv_testsave->integer;
-	sv_testsave->integer = 0;
+    char sComment[iSG_COMMENT_SIZE];
+    char sMapCmd[iSG_MAPCMD_SIZE];
 
 #ifdef JK2_MODE
-	Cvar_Set( "cg_missionstatusscreen", "0" );//reset if loading a game
+    Cvar_Set(
+        "cg_missionstatusscreen",
+        "0");
 #endif
 
     auto saved_game = &ojk::SavedGame::get_instance();
 
-	if (!saved_game->open(psPathlessBaseName))
-	{
-		Com_Printf (GetString_FailedToOpenSaveGame(psPathlessBaseName, qtrue));//S_COLOR_RED "Failed to open savegame \"%s\"\n", psPathlessBaseName);
-		sv_testsave->integer = iPrevTestSave;
-		return qfalse;
-	}
+    const auto iPrevTestSave = ::sv_testsave->integer;
 
-	// this check isn't really necessary, but it reminds me that these two strings may actually be the same physical one.
-	//
-	if (psPathlessBaseName != sLastSaveFileLoaded)
-	{
-		Q_strncpyz(sLastSaveFileLoaded,psPathlessBaseName,sizeof(sLastSaveFileLoaded));
-	}
+    ojk::ScopeGuard scope_guard(
+        [&]()
+        {
+            ::sv_testsave->integer = 0;
+        },
 
-	// Read in all the server data...
-	//
-    saved_game->read_chunk(
-        INT_ID('C','O','M','M'),
-        sComment);
-
-	Com_DPrintf("Reading: %s\n", sComment);
-
-    saved_game->read_chunk(
-        INT_ID('C','M','T','M'));
-
-#ifdef JK2_MODE
-	SG_ReadScreenshot(qtrue);	// qboolean qbSetAsLoadingScreen
-#endif
-    saved_game->read_chunk(
-        INT_ID('M','P','C','M'),
-        sMapCmd);
+        [&]()
+        {
+            saved_game->close();
 
-	SG_ReadCvars();
+            ::sv_testsave->integer = iPrevTestSave;
+        }
+    );
 
-	// read game state
-	qbAutosave = ReadGame();
-	eSavedGameJustLoaded = (qbAutosave)?eAUTO:eFULL;
-
-	SV_SpawnServer(sMapCmd, eForceReload_NOTHING, (eSavedGameJustLoaded != eFULL) );	// note that this also trashes the whole G_Alloc pool as well (of course)
+    try
+    {
+        if (!saved_game->open(psPathlessBaseName))
+        {
+            //S_COLOR_RED "Failed to open savegame \"%s\"\n", psPathlessBaseName);
+            ::Com_Printf(
+                ::GetString_FailedToOpenSaveGame(
+                    psPathlessBaseName,
+                    qtrue));
+
+            return qfalse;
+        }
+
+        // this check isn't really necessary, but it reminds me that these two strings may actually be the same physical one.
+        //
+        if (psPathlessBaseName != sLastSaveFileLoaded)
+        {
+            ::Q_strncpyz(
+                ::sLastSaveFileLoaded,
+                psPathlessBaseName,
+                sizeof(sLastSaveFileLoaded));
+        }
+
+        // Read in all the server data...
+        //
+        saved_game->read_chunk(
+            INT_ID('C', 'O', 'M', 'M'),
+            sComment);
 
-	// read in all the level data...
-	//
-	if (!qbAutosave)
-	{
-        auto saved_game = &ojk::SavedGame::get_instance();
+        ::Com_DPrintf(
+            "Reading: %s\n",
+            sComment);
 
-        saved_game->read_chunk<int32_t>(
-            INT_ID('T','I','M','E'),
-            ::sv.time);
+        saved_game->read_chunk(
+            INT_ID('C', 'M', 'T', 'M'));
 
-        saved_game->read_chunk<int32_t>(
-            INT_ID('T','I','M','R'),
-            ::sv.timeResidual);
+#ifdef JK2_MODE
+        ::SG_ReadScreenshot(
+            qtrue);
+#endif
 
-		CM_ReadPortalState();
-		SG_ReadServerConfigStrings();
-	}
-	ge->ReadLevel(qbAutosave, qbLoadTransition);	// always done now, but ent reader only does player if auto
+        saved_game->read_chunk(
+            INT_ID('M', 'P', 'C', 'M'),
+            sMapCmd);
+
+        ::SG_ReadCvars();
+
+        // read game state
+        const auto qbAutosave = ::ReadGame();
+
+        ::eSavedGameJustLoaded = (qbAutosave ? eAUTO : eFULL);
+
+        // note that this also trashes the whole G_Alloc pool as well (of course)
+        ::SV_SpawnServer(
+            sMapCmd,
+            eForceReload_NOTHING,
+            (::eSavedGameJustLoaded != eFULL));
+
+        // read in all the level data...
+        //
+        if (!qbAutosave)
+        {
+            saved_game->read_chunk<int32_t>(
+                INT_ID('T', 'I', 'M', 'E'),
+                ::sv.time);
+
+            saved_game->read_chunk<int32_t>(
+                INT_ID('T', 'I', 'M', 'R'),
+                ::sv.timeResidual);
+
+            ::CM_ReadPortalState();
+            ::SG_ReadServerConfigStrings();
+        }
+
+        // always done now, but ent reader only does player if auto
+        ::ge->ReadLevel(
+            qbAutosave,
+            qbLoadTransition);
+    }
+    catch (ojk::SavedGameException& ex)
+    {
+        ::Com_Error(
+            ERR_DROP,
+            "%s",
+            ex.what());
+    }
 
 #if 0
-	if(!SG_Close())
-	{
-		Com_Printf (GetString_FailedToOpenSaveGame(psPathlessBaseName,qfalse));//S_COLOR_RED "Failed to close savegame\n");
-		sv_testsave->integer = iPrevTestSave;
-		return qfalse;
-	}
-#else
-    saved_game->close();
+    if (!SG_Close())
+    {
+        Com_Printf(GetString_FailedToOpenSaveGame(psPathlessBaseName, qfalse));//S_COLOR_RED "Failed to close savegame\n");
+        sv_testsave->integer = iPrevTestSave;
+        return qfalse;
+    }
 #endif
 
-	sv_testsave->integer = iPrevTestSave;
-	return qtrue;
+    return true;
 }
 
 #if 0
diff --git a/codeJK2/game/CMakeLists.txt b/codeJK2/game/CMakeLists.txt
index a099777..06faddc 100644
--- a/codeJK2/game/CMakeLists.txt
+++ b/codeJK2/game/CMakeLists.txt
@@ -235,7 +235,7 @@ set(JK2SPGameCommonFiles
 	"${SPDir}/rd-common/mdx_format.h"
 	"${SharedDir}/qcommon/ojk_i_saved_game.h"
 	"${SharedDir}/qcommon/ojk_i_saved_game_fwd.h"
-
+	"${SharedDir}/qcommon/ojk_scope_guard.h"
 	${SharedCommonFiles}
 	)
 source_group("common" FILES ${JK2SPGameCommonFiles})
diff --git a/shared/qcommon/ojk_i_saved_game.h b/shared/qcommon/ojk_i_saved_game.h
index f050a78..125064c 100644
--- a/shared/qcommon/ojk_i_saved_game.h
+++ b/shared/qcommon/ojk_i_saved_game.h
@@ -10,6 +10,7 @@
 #include <cstdint>
 #include <type_traits>
 #include "ojk_i_saved_game_fwd.h"
+#include "ojk_scope_guard.h"
 
 
 namespace ojk {
@@ -34,37 +35,33 @@ inline ISavedGame::~ISavedGame()
 // read_chunk
 
 template<typename TSrc, typename TDst>
-bool ISavedGame::read_chunk(
+void ISavedGame::read_chunk(
     const ChunkId chunk_id,
     TDst& dst_value)
 {
-    auto result = read_chunk(
+    read_chunk(
         chunk_id);
 
     read<TSrc>(
         dst_value);
 
-    result &= is_all_data_read();
-
-    return result;
+    ensure_all_data_read();
 }
 
 template<typename TSrc, typename TDst>
-bool ISavedGame::read_chunk(
+void ISavedGame::read_chunk(
     const ChunkId chunk_id,
     TDst* dst_values,
     int dst_count)
 {
-    auto result = read_chunk(
+    read_chunk(
         chunk_id);
 
     read<TSrc>(
         dst_values,
         dst_count);
 
-    result &= is_all_data_read();
-
-    return result;
+    ensure_all_data_read();
 }
 
 // read_chunk
@@ -75,7 +72,7 @@ bool ISavedGame::read_chunk(
 // write_chunk
 
 template<typename TDst, typename TSrc>
-bool ISavedGame::write_chunk(
+void ISavedGame::write_chunk(
     const ChunkId chunk_id,
     const TSrc& src_value)
 {
@@ -84,12 +81,12 @@ bool ISavedGame::write_chunk(
     write<TDst>(
         src_value);
 
-    return write_chunk(
+    write_chunk(
         chunk_id);
 }
 
 template<typename TDst, typename TSrc>
-bool ISavedGame::write_chunk(
+void ISavedGame::write_chunk(
     const ChunkId chunk_id,
     const TSrc* src_values,
     int src_count)
@@ -100,7 +97,7 @@ bool ISavedGame::write_chunk(
         src_values,
         src_count);
 
-    return write_chunk(
+    write_chunk(
         chunk_id);
 }
 
@@ -251,6 +248,38 @@ void ISavedGame::read(
 
 
 // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+// try_read
+
+template<typename TSrc, typename TDst>
+bool ISavedGame::try_read(
+    TDst& dst_value)
+{
+    ScopeGuard scope_guard(
+        [this]()
+        {
+            this->allow_read_overflow(
+                true);
+        },
+
+        [this]()
+        {
+            this->allow_read_overflow(
+                false);
+        }
+    );
+
+
+    read<TSrc>(
+        dst_value);
+
+    return is_all_data_read();
+}
+
+// try_read
+// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+
+// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 // read (C-array)
 
 template<typename TSrc, typename TDst>
diff --git a/shared/qcommon/ojk_i_saved_game_fwd.h b/shared/qcommon/ojk_i_saved_game_fwd.h
index c9559fa..1ed867c 100644
--- a/shared/qcommon/ojk_i_saved_game_fwd.h
+++ b/shared/qcommon/ojk_i_saved_game_fwd.h
@@ -43,20 +43,20 @@ public:
 
 
     // Reads a chunk from the file into the internal buffer.
-    virtual bool read_chunk(
+    virtual void read_chunk(
         const ChunkId chunk_id) = 0;
 
     // Reads a value or an array of values from the file via
     // the internal buffer.
     template<typename TSrc = void, typename TDst = void>
-    bool read_chunk(
+    void read_chunk(
         const ChunkId chunk_id,
         TDst& dst_value);
 
     // Reads an array of values with specified count from
     // the file via the internal buffer.
     template<typename TSrc = void, typename TDst = void>
-    bool read_chunk(
+    void read_chunk(
         const ChunkId chunk_id,
         TDst* dst_values,
         int dst_count);
@@ -64,22 +64,25 @@ public:
     // Returns true if all data read from the internal buffer.
     virtual bool is_all_data_read() const = 0;
 
+    // Throws an exception if all data not read.
+    virtual void ensure_all_data_read() const = 0;
+
 
     // Writes a chunk into the file from the internal buffer.
-    virtual bool write_chunk(
+    virtual void write_chunk(
         const ChunkId chunk_id) = 0;
 
     // Writes a value or an array of values into the file via
     // the internal buffer.
     template<typename TDst = void, typename TSrc = void>
-    bool write_chunk(
+    void write_chunk(
         const ChunkId chunk_id,
         const TSrc& src_value);
 
     // Writes an array of values with specified count into
     // the file via the internal buffer.
     template<typename TDst = void, typename TSrc = void>
-    bool write_chunk(
+    void write_chunk(
         const ChunkId chunk_id,
         const TSrc* src_values,
         int src_count);
@@ -102,6 +105,13 @@ public:
         int dst_count);
 
 
+    // Tries to read a value or array of values from the internal buffer.
+    // Returns true on success or false otherwise.
+    template<typename TSrc = void, typename TDst = void>
+    bool try_read(
+        TDst& dst_value);
+
+
     // Writes a raw data into the internal buffer.
     virtual void raw_write(
         const void* src_data,
@@ -144,6 +154,12 @@ protected:
     class CastTag { public: };
 
 
+    // If true won't throw an exception when buffer offset is beyond it's size.
+    // Although, no data will be read beyond the buffer.
+    virtual void allow_read_overflow(
+        bool value) = 0;
+
+
     template<typename TSrc, typename TDst>
     void read(
         TDst& dst_value,
diff --git a/shared/qcommon/ojk_saved_game.cpp b/shared/qcommon/ojk_saved_game.cpp
index 9617e5f..56bb31c 100644
--- a/shared/qcommon/ojk_saved_game.cpp
+++ b/shared/qcommon/ojk_saved_game.cpp
@@ -16,8 +16,8 @@ SavedGame::SavedGame() :
         rle_buffer_(),
         is_readable_(),
         is_writable_(),
-        is_preview_mode_(),
-        is_write_failed_()
+        is_write_failed_(),
+        is_read_overflow_allowed_()
 {
 }
 
@@ -32,7 +32,7 @@ bool SavedGame::open(
     close();
 
 
-    auto&& file_path = generate_path(
+    const auto&& file_path = generate_path(
         base_file_name);
 
     auto is_succeed = true;
@@ -48,9 +48,9 @@ bool SavedGame::open(
         {
             is_succeed = false;
 
-            auto error_message = get_failed_to_open_message(
-                file_path,
-                true);
+            const auto&& error_message =
+                S_COLOR_RED "Failed to open a saved game file: \"" +
+                    file_path + "\".";
 
             ::Com_DPrintf(
                 "%s\n",
@@ -63,7 +63,7 @@ bool SavedGame::open(
         is_readable_ = true;
     }
 
-    int sg_version = -1;
+    auto sg_version = -1;
 
     if (is_succeed)
     {
@@ -100,17 +100,17 @@ bool SavedGame::create(
     remove(
         base_file_name);
 
-    auto path = generate_path(
+    const auto&& file_path = generate_path(
         base_file_name);
 
     file_handle_ = ::FS_FOpenFileWrite(
-        path.c_str());
+        file_path.c_str());
 
     if (file_handle_ == 0)
     {
-        auto error_message = get_failed_to_open_message(
-            path,
-            false);
+        const auto&& error_message =
+            S_COLOR_RED "Failed to create a saved game file: \"" +
+                file_path + "\".";
 
         ::Com_Printf(
             "%s\n",
@@ -122,11 +122,11 @@ bool SavedGame::create(
 
     is_writable_ = true;
 
-    int sg_version = iSAVEGAME_VERSION;
+    const auto sg_version = iSAVEGAME_VERSION;
 
-    static_cast<void>(write_chunk<int32_t>(
+    write_chunk<int32_t>(
         INT_ID('_', 'V', 'E', 'R'),
-        sg_version));
+        sg_version);
 
     return true;
 }
@@ -144,7 +144,6 @@ void SavedGame::close()
 
     is_readable_ = false;
     is_writable_ = false;
-    is_preview_mode_ = false;
     is_write_failed_ = false;
 }
 
@@ -158,12 +157,12 @@ bool SavedGame::is_writable() const
     return is_writable_;
 }
 
-bool SavedGame::read_chunk(
+void SavedGame::read_chunk(
     const SavedGame::ChunkId chunk_id)
 {
     io_buffer_offset_ = 0;
 
-    auto chunk_id_string = get_chunk_id_string(
+    const auto&& chunk_id_string = get_chunk_id_string(
         chunk_id);
 
     ::Com_DPrintf(
@@ -183,7 +182,7 @@ bool SavedGame::read_chunk(
         static_cast<int>(sizeof(uiLoadedLength)),
         file_handle_);
 
-    auto bBlockIsCompressed = (static_cast<int32_t>(uiLoadedLength) < 0);
+    const auto bBlockIsCompressed = (static_cast<int32_t>(uiLoadedLength) < 0);
 
     if (bBlockIsCompressed)
     {
@@ -194,9 +193,10 @@ bool SavedGame::read_chunk(
     //
     if (ulLoadedChid != chunk_id)
     {
-        auto loaded_chunk_id_string = get_chunk_id_string(
+        const auto&& loaded_chunk_id_string = get_chunk_id_string(
             ulLoadedChid);
 
+#if 0
         if (!is_preview_mode_)
         {
             ::Com_Error(
@@ -205,8 +205,17 @@ bool SavedGame::read_chunk(
                 loaded_chunk_id_string.c_str(),
                 chunk_id_string.c_str());
         }
+#else
+        const auto&& error_message =
+            "Loaded chunk ID (" +
+            loaded_chunk_id_string +
+            ") does not match requested chunk ID (" +
+            chunk_id_string +
+            ").";
 
-        return false;
+        throw_error(
+            error_message);
+#endif
     }
 
     // Load in data and magic number...
@@ -257,12 +266,13 @@ bool SavedGame::read_chunk(
 
     // Make sure the checksums match...
     //
-    auto uiCksum = ::Com_BlockChecksum(
+    const auto uiCksum = ::Com_BlockChecksum(
         io_buffer_.data(),
         static_cast<int>(io_buffer_.size()));
 
     if (uiLoadedCksum != uiCksum)
     {
+#if 0
         if (!is_preview_mode_)
         {
             ::Com_Error(
@@ -270,8 +280,13 @@ bool SavedGame::read_chunk(
                 "Failed checksum check for chunk",
                 chunk_id_string.c_str());
         }
+#else
+        const auto&& error_message =
+            "Failed checksum check for chunk " + chunk_id_string + ".";
 
-        return false;
+        throw_error(
+            error_message);
+#endif
     }
 
     // Make sure we didn't encounter any read errors...
@@ -282,6 +297,7 @@ bool SavedGame::read_chunk(
         (bBlockIsCompressed ? sizeof(uiCompressedLength) : 0) +
         (bBlockIsCompressed ? uiCompressedLength : io_buffer_.size()))
     {
+#if 0
         if (!is_preview_mode_)
         {
             ::Com_Error(
@@ -289,11 +305,14 @@ bool SavedGame::read_chunk(
                 "Error during loading chunk %s",
                 chunk_id_string.c_str());
         }
+#else
+        const auto&& error_message =
+            "Error during loading chunk " + chunk_id_string + ".";
 
-        return false;
+        throw_error(
+            error_message);
+#endif
     }
-
-    return true;
 }
 
 bool SavedGame::is_all_data_read() const
@@ -301,10 +320,19 @@ bool SavedGame::is_all_data_read() const
     return io_buffer_.size() == io_buffer_offset_;
 }
 
-bool SavedGame::write_chunk(
+void SavedGame::ensure_all_data_read() const
+{
+    if (!is_all_data_read())
+    {
+        throw_error(
+            "Not all expected data read.");
+    }
+}
+
+void SavedGame::write_chunk(
     const SavedGame::ChunkId chunk_id)
 {
-    auto chunk_id_string = get_chunk_id_string(
+    const auto&& chunk_id_string = get_chunk_id_string(
         chunk_id);
 
     ::Com_DPrintf(
@@ -313,12 +341,12 @@ bool SavedGame::write_chunk(
 
     if (::sv_testsave->integer != 0)
     {
-        return true;
+        return;
     }
 
-    auto src_size = static_cast<int>(io_buffer_.size());
+    const auto src_size = static_cast<int>(io_buffer_.size());
 
-    auto uiCksum = Com_BlockChecksum(
+    const auto uiCksum = Com_BlockChecksum(
         io_buffer_.data(),
         src_size);
 
@@ -327,7 +355,7 @@ bool SavedGame::write_chunk(
         static_cast<int>(sizeof(chunk_id)),
         file_handle_);
 
-    int iCompressedLength = -1;
+    auto iCompressedLength = -1;
 
     if (::sv_compress_saved_games->integer != 0)
     {
@@ -341,9 +369,9 @@ bool SavedGame::write_chunk(
         }
     }
 
-    if (iCompressedLength >= 0)
+    if (iCompressedLength > 0)
     {
-        auto iLength = -static_cast<int>(io_buffer_.size());
+        const auto iLength = -static_cast<int>(io_buffer_.size());
 
         uiSaved += ::FS_Write(
             &iLength,
@@ -378,12 +406,12 @@ bool SavedGame::write_chunk(
                 S_COLOR_RED "Failed to write %s chunk\n",
                 chunk_id_string.c_str());
 
-            return false;
+            return;
         }
     }
     else
     {
-        auto iLength = static_cast<uint32_t>(io_buffer_.size());
+        const auto iLength = static_cast<uint32_t>(io_buffer_.size());
 
         uiSaved += ::FS_Write(
             &iLength,
@@ -412,11 +440,9 @@ bool SavedGame::write_chunk(
                 S_COLOR_RED "Failed to write %s chunk\n",
                 chunk_id_string.c_str());
 
-            return false;
+            return;
         }
     }
-
-    return true;
 }
 
 void SavedGame::raw_read(
@@ -448,14 +474,20 @@ void SavedGame::raw_read(
 
     if ((io_buffer_offset_ + dst_size) > io_buffer_.size())
     {
-        throw_error(
-            "Not enough data.");
+        if (!is_read_overflow_allowed_)
+        {
+            throw_error(
+                "Not enough data.");
+        }
     }
 
-    std::uninitialized_copy_n(
-        &io_buffer_[io_buffer_offset_],
-        dst_size,
-        static_cast<uint8_t*>(dst_data));
+    if (!is_read_overflow_allowed_)
+    {
+        std::uninitialized_copy_n(
+            &io_buffer_[io_buffer_offset_],
+            dst_size,
+            static_cast<uint8_t*>(dst_data));
+    }
 
     io_buffer_offset_ += dst_size;
 }
@@ -487,7 +519,7 @@ void SavedGame::raw_write(
         return;
     }
 
-    auto new_buffer_size = io_buffer_offset_ + src_size;
+    const auto new_buffer_size = io_buffer_offset_ + src_size;
 
     io_buffer_.resize(
         new_buffer_size);
@@ -505,12 +537,6 @@ bool SavedGame::is_write_failed() const
     return is_write_failed_;
 }
 
-void SavedGame::set_preview_mode(
-    bool value)
-{
-    is_preview_mode_ = value;
-}
-
 void SavedGame::skip(
     int count)
 {
@@ -531,8 +557,8 @@ void SavedGame::skip(
         return;
     }
 
-    auto new_offset = io_buffer_offset_ + count;
-    auto buffer_size = io_buffer_.size();
+    const auto new_offset = io_buffer_offset_ + count;
+    const auto buffer_size = io_buffer_.size();
 
     if (new_offset > buffer_size)
     {
@@ -563,20 +589,21 @@ void SavedGame::rename(
     const std::string& old_base_file_name,
     const std::string& new_base_file_name)
 {
-    auto old_path = generate_path(
+    const auto&& old_path = generate_path(
         old_base_file_name);
 
-    auto new_path = generate_path(
+    const auto&& new_path = generate_path(
         new_base_file_name);
 
-    auto rename_result = ::FS_MoveUserGenFile(
+    const auto rename_result = ::FS_MoveUserGenFile(
         old_path.c_str(),
         new_path.c_str());
 
     if (rename_result == 0)
     {
         ::Com_Printf(
-            S_COLOR_RED "Error during savegame-rename. Check \"%s\" for write-protect or disk full!\n",
+            S_COLOR_RED "Error during savegame-rename."
+                " Check \"%s\" for write-protect or disk full!\n",
             new_path.c_str());
     }
 }
@@ -584,7 +611,7 @@ void SavedGame::rename(
 void SavedGame::remove(
     const std::string& base_file_name)
 {
-    auto path = generate_path(
+    const auto&& path = generate_path(
         base_file_name);
 
     ::FS_DeleteUserGenFile(
@@ -597,6 +624,12 @@ SavedGame& SavedGame::get_instance()
     return result;
 }
 
+void SavedGame::allow_read_overflow(
+    bool value)
+{
+    is_read_overflow_allowed_ = value;
+}
+
 void SavedGame::throw_error(
     const char* message)
 {
@@ -615,12 +648,12 @@ void SavedGame::compress(
     const Buffer& src_buffer,
     Buffer& dst_buffer)
 {
-    auto src_size = static_cast<int>(src_buffer.size());
+    const auto src_size = static_cast<int>(src_buffer.size());
 
     dst_buffer.resize(2 * src_size);
 
-    int src_count = 0;
-    int dst_index = 0;
+    auto src_count = 0;
+    auto dst_index = 0;
 
     while (src_count < src_size)
     {
@@ -678,8 +711,8 @@ void SavedGame::decompress(
     const Buffer& src_buffer,
     Buffer& dst_buffer)
 {
-    int src_index = 0;
-    int dst_index = 0;
+    auto src_index = 0;
+    auto dst_index = 0;
 
     auto remain_size = static_cast<int>(dst_buffer.size());
 
@@ -725,43 +758,11 @@ std::string SavedGame::generate_path(
         '/',
         '_');
 
-    auto path = "saves/" + normalized_file_name + ".sav";
+    auto&& path = "saves/" + normalized_file_name + ".sav";
 
     return path;
 }
 
-std::string SavedGame::get_failed_to_open_message(
-    const std::string& file_name,
-    bool is_open)
-{
-    constexpr int max_length = 256;
-
-    auto message_id =
-        is_open ?
-#if JK2_MODE
-        "MENUS3_FAILED_TO_OPEN_SAVEGAME" :
-        "MENUS3_FAILED_TO_CREATE_SAVEGAME"
-#else
-        "MENUS_FAILED_TO_OPEN_SAVEGAME" :
-        "MENUS3_FAILED_TO_CREATE_SAVEGAME"
-#endif
-        ;
-
-    std::string result(
-        S_COLOR_RED);
-
-    result += ::va(
-        ::SE_GetString(message_id),
-        file_name.c_str());
-
-    if (result.length() > max_length)
-    {
-        result.resize(max_length);
-    }
-
-    return result;
-}
-
 std::string SavedGame::get_chunk_id_string(
     uint32_t chunk_id)
 {
diff --git a/shared/qcommon/ojk_saved_game.h b/shared/qcommon/ojk_saved_game.h
index e9b04d2..3b975fa 100644
--- a/shared/qcommon/ojk_saved_game.h
+++ b/shared/qcommon/ojk_saved_game.h
@@ -57,7 +57,7 @@ public:
 
 
     // Reads a chunk from the file into the internal buffer.
-    bool read_chunk(
+    void read_chunk(
         const ChunkId chunk_id) override;
 
     using ISavedGame::read_chunk;
@@ -66,9 +66,12 @@ public:
     // Returns true if all data read from the internal buffer.
     bool is_all_data_read() const override;
 
+    // Throws an exception if all data not read.
+    void ensure_all_data_read() const override;
+
 
     // Writes a chunk into the file from the internal buffer.
-    bool write_chunk(
+    void write_chunk(
         const ChunkId chunk_id) override;
 
     using ISavedGame::write_chunk;
@@ -92,9 +95,6 @@ public:
 
     bool is_write_failed() const;
 
-    void set_preview_mode(
-        bool value);
-
     // Increments buffer's offset by the specified non-negative count.
     void skip(
         int count) override;
@@ -119,6 +119,13 @@ public:
     static SavedGame& get_instance();
 
 
+protected:
+    // If true won't throw an exception when buffer offset is beyond it's size.
+    // Although, no data will be read beyond the buffer.
+    void allow_read_overflow(
+        bool value) override;
+
+
 private:
     using BufferOffset = Buffer::size_type;
     using Paths = std::vector<std::string>;
@@ -142,12 +149,12 @@ private:
     // True if saved game opened for writing.
     bool is_writable_;
 
-    // Does not throws an exception on chunk reading if true.
-    bool is_preview_mode_;
-
     // True if any previous write operation failed.
     bool is_write_failed_;
 
+    // Controls exception throw on read overflow.
+    bool is_read_overflow_allowed_;
+
 
     // Throws an exception.
     static void throw_error(
@@ -172,10 +179,6 @@ private:
     static std::string generate_path(
         const std::string& base_file_name);
 
-    static std::string get_failed_to_open_message(
-        const std::string& file_name,
-        bool is_open);
-
 
     // Returns a string representation of a chunk id.
     static std::string get_chunk_id_string(
diff --git a/shared/qcommon/ojk_scope_guard.h b/shared/qcommon/ojk_scope_guard.h
new file mode 100644
index 0000000..3cf39c9
--- /dev/null
+++ b/shared/qcommon/ojk_scope_guard.h
@@ -0,0 +1,58 @@
+//
+// Calls specified callbacks on scope enter (optional) and exit.
+//
+
+
+#ifndef OJK_SCOPE_GUARD_INCLUDED
+#define OJK_SCOPE_GUARD_INCLUDED
+
+
+#include <functional>
+#include <utility>
+
+
+namespace ojk
+{
+
+
+class ScopeGuard
+{
+public:
+    using Callback = std::function<void()>;
+
+
+    ScopeGuard(
+        Callback leave_callback) :
+            leave_callback_(leave_callback)
+    {
+    }
+
+    ScopeGuard(
+        Callback enter_callback,
+        Callback leave_callback) :
+            ScopeGuard(leave_callback)
+    {
+        enter_callback();
+    }
+
+    ScopeGuard(
+        const ScopeGuard& that) = delete;
+
+    ScopeGuard& operator=(
+        const ScopeGuard& that) = delete;
+
+    ~ScopeGuard()
+    {
+        leave_callback_();
+    }
+
+
+private:
+    Callback leave_callback_;
+}; // ScopeGuard
+
+
+} // ojk
+
+
+#endif // OJK_SCOPE_GUARD_INCLUDED

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/openjk.git



More information about the Pkg-games-commits mailing list