@ -387,6 +387,19 @@ static void NORETURN SlError(StringID string, const char *extra_msg = NULL)
throw std : : exception ( ) ;
}
/**
* Error handler for corrupt savegames . Sets everything up to show the
* error message and to clean up the mess of a partial savegame load .
* @ param msg Location the corruption has been spotted .
* @ note This function does never return as it throws an exception to
* break out of all the saveload code .
*/
void NORETURN SlErrorCorrupt ( const char * msg )
{
SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , msg ) ;
}
typedef void ( * AsyncSaveFinishProc ) ( ) ; ///< Callback for when the savegame loading is finished.
static AsyncSaveFinishProc _async_save_finish = NULL ; ///< Callback to call when the savegame loading is finished.
static ThreadObject * _save_thread ; ///< The thread we're using to compress and write a savegame
@ -427,7 +440,7 @@ void ProcessAsyncSaveFinish()
static void SlReadFill ( )
{
size_t len = _sl . read_bytes ( ) ;
if ( len = = 0 ) SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Unexpected end of chunk " ) ;
if ( len = = 0 ) SlError Corrupt ( " Unexpected end of chunk " ) ;
_sl . bufp = _sl . buf ;
_sl . bufe = _sl . buf + len ;
@ -553,7 +566,7 @@ static uint SlReadSimpleGamma()
if ( HasBit ( i , 5 ) ) {
i & = ~ 0x20 ;
if ( HasBit ( i , 4 ) ) {
SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Unsupported gamma " ) ;
SlError Corrupt ( " Unsupported gamma " ) ;
}
i = ( i < < 8 ) | SlReadByte ( ) ;
}
@ -688,7 +701,7 @@ int SlIterateArray()
/* After reading in the whole array inside the loop
* we must have read in all the data , so we must be at end of current block . */
if ( _next_offs ! = 0 & & SlGetOffs ( ) ! = _next_offs ) SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Invalid chunk size " ) ;
if ( _next_offs ! = 0 & & SlGetOffs ( ) ! = _next_offs ) SlError Corrupt ( " Invalid chunk size " ) ;
while ( true ) {
uint length = SlReadArrayLength ( ) ;
@ -1136,38 +1149,38 @@ static void *IntToReference(size_t index, SLRefType rt)
switch ( rt ) {
case REF_ORDERLIST :
if ( OrderList : : IsValidID ( index ) ) return OrderList : : Get ( index ) ;
SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Referencing invalid OrderList " ) ;
SlError Corrupt ( " Referencing invalid OrderList " ) ;
case REF_ORDER :
if ( Order : : IsValidID ( index ) ) return Order : : Get ( index ) ;
/* in old versions, invalid order was used to mark end of order list */
if ( CheckSavegameVersionOldStyle ( 5 , 2 ) ) return NULL ;
SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Referencing invalid Order " ) ;
SlError Corrupt ( " Referencing invalid Order " ) ;
case REF_VEHICLE_OLD :
case REF_VEHICLE :
if ( Vehicle : : IsValidID ( index ) ) return Vehicle : : Get ( index ) ;
SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Referencing invalid Vehicle " ) ;
SlError Corrupt ( " Referencing invalid Vehicle " ) ;
case REF_STATION :
if ( Station : : IsValidID ( index ) ) return Station : : Get ( index ) ;
SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Referencing invalid Station " ) ;
SlError Corrupt ( " Referencing invalid Station " ) ;
case REF_TOWN :
if ( Town : : IsValidID ( index ) ) return Town : : Get ( index ) ;
SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Referencing invalid Town " ) ;
SlError Corrupt ( " Referencing invalid Town " ) ;
case REF_ROADSTOPS :
if ( RoadStop : : IsValidID ( index ) ) return RoadStop : : Get ( index ) ;
SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Referencing invalid RoadStop " ) ;
SlError Corrupt ( " Referencing invalid RoadStop " ) ;
case REF_ENGINE_RENEWS :
if ( EngineRenew : : IsValidID ( index ) ) return EngineRenew : : Get ( index ) ;
SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Referencing invalid EngineRenew " ) ;
SlError Corrupt ( " Referencing invalid EngineRenew " ) ;
case REF_CARGO_PACKET :
if ( CargoPacket : : IsValidID ( index ) ) return CargoPacket : : Get ( index ) ;
SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Referencing invalid CargoPacket " ) ;
SlError Corrupt ( " Referencing invalid CargoPacket " ) ;
default : NOT_REACHED ( ) ;
}
@ -1441,7 +1454,7 @@ void SlAutolength(AutolengthProc *proc, void *arg)
/* And write the stuff */
proc ( arg ) ;
if ( offs ! = SlGetOffs ( ) ) SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Invalid chunk size " ) ;
if ( offs ! = SlGetOffs ( ) ) SlError Corrupt ( " Invalid chunk size " ) ;
}
/**
@ -1473,9 +1486,9 @@ static void SlLoadChunk(const ChunkHandler *ch)
_sl . obj_len = len ;
endoffs = SlGetOffs ( ) + len ;
ch - > load_proc ( ) ;
if ( SlGetOffs ( ) ! = endoffs ) SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Invalid chunk size " ) ;
if ( SlGetOffs ( ) ! = endoffs ) SlError Corrupt ( " Invalid chunk size " ) ;
} else {
SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Invalid chunk type " ) ;
SlError Corrupt ( " Invalid chunk type " ) ;
}
break ;
}
@ -1523,9 +1536,9 @@ static void SlLoadCheckChunk(const ChunkHandler *ch)
} else {
SlSkipBytes ( len ) ;
}
if ( SlGetOffs ( ) ! = endoffs ) SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Invalid chunk size " ) ;
if ( SlGetOffs ( ) ! = endoffs ) SlError Corrupt ( " Invalid chunk size " ) ;
} else {
SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Invalid chunk type " ) ;
SlError Corrupt ( " Invalid chunk type " ) ;
}
break ;
}
@ -1632,7 +1645,7 @@ static void SlLoadChunks()
DEBUG ( sl , 2 , " Loading chunk %c%c%c%c " , id > > 24 , id > > 16 , id > > 8 , id ) ;
ch = SlFindChunkHandler ( id ) ;
if ( ch = = NULL ) SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Unknown chunk type " ) ;
if ( ch = = NULL ) SlError Corrupt ( " Unknown chunk type " ) ;
SlLoadChunk ( ch ) ;
}
}
@ -1647,7 +1660,7 @@ static void SlLoadCheckChunks()
DEBUG ( sl , 2 , " Loading chunk %c%c%c%c " , id > > 24 , id > > 16 , id > > 8 , id ) ;
ch = SlFindChunkHandler ( id ) ;
if ( ch = = NULL ) SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Unknown chunk type " ) ;
if ( ch = = NULL ) SlError Corrupt ( " Unknown chunk type " ) ;
SlLoadCheckChunk ( ch ) ;
}
}
@ -1700,13 +1713,13 @@ static size_t ReadLZO()
size = TO_BE32 ( size ) ;
}
if ( size > = sizeof ( out ) ) SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Inconsistent size " ) ;
if ( size > = sizeof ( out ) ) SlError Corrupt ( " Inconsistent size " ) ;
/* Read block */
if ( fread ( out + sizeof ( uint32 ) , size , 1 , _sl . fh ) ! = 1 ) SlError ( STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE ) ;
/* Verify checksum */
if ( tmp [ 0 ] ! = lzo_adler32 ( 0 , out , size + sizeof ( uint32 ) ) ) SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Bad checksum " ) ;
if ( tmp [ 0 ] ! = lzo_adler32 ( 0 , out , size + sizeof ( uint32 ) ) ) SlError Corrupt ( " Bad checksum " ) ;
/* Decompress */
lzo1x_decompress ( out + sizeof ( uint32 ) * 1 , size , _sl . buf , & len , NULL ) ;
@ -2099,7 +2112,7 @@ static SaveOrLoadResult SaveFileToDisk(bool threaded)
uint i = 0 ;
size_t t = _ts . count ;
if ( _ts . count ! = _sl . offs_base ) SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Unexpected size of chunk " ) ;
if ( _ts . count ! = _sl . offs_base ) SlError Corrupt ( " Unexpected size of chunk " ) ;
while ( t > = MEMORY_CHUNK_SIZE ) {
_sl . buf = _memory_savegame [ i + + ] ;
fmt - > writer ( MEMORY_CHUNK_SIZE ) ;
@ -2116,7 +2129,7 @@ static SaveOrLoadResult SaveFileToDisk(bool threaded)
}
fmt - > uninit_write ( ) ;
if ( _ts . count ! = _sl . offs_base ) SlError ( STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME , " Unexpected size of chunk " ) ;
if ( _ts . count ! = _sl . offs_base ) SlError Corrupt ( " Unexpected size of chunk " ) ;
UnInitMem ( ) ;
fclose ( _sl . fh ) ;