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 <[email protected]> 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 _______________________________________________ Pkg-games-commits mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-games-commits

