[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