mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-02-01 20:03:26 +00:00
(svn r20819) -Fix [FS#3714]: be a bit more "lenient" w.r.t. invalid savegames; don't crash on saveload related NOT_REACHEDs, just show the user an error that the savegame is corrupted
This commit is contained in:
parent
5b733f88a8
commit
97dbb1f27d
@ -79,7 +79,7 @@ void SetWaterClassDependingOnSurroundings(TileIndex t, bool include_invalid_wate
|
||||
SetWaterClass(t, WATER_CLASS_INVALID);
|
||||
return;
|
||||
} else {
|
||||
NOT_REACHED();
|
||||
SlErrorCorrupt("Invalid water class for dry tile");
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,7 +108,7 @@ void SetWaterClassDependingOnSurroundings(TileIndex t, bool include_invalid_wate
|
||||
case WATER_CLASS_SEA: has_water = true; break;
|
||||
case WATER_CLASS_CANAL: has_canal = true; break;
|
||||
case WATER_CLASS_RIVER: has_river = true; break;
|
||||
default: NOT_REACHED();
|
||||
default: SlErrorCorrupt("Invalid water class for tile");
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -871,7 +871,7 @@ bool AfterLoadGame()
|
||||
case MP_ROAD:
|
||||
SB(_m[t].m5, 6, 2, GB(_m[t].m5, 4, 2));
|
||||
switch (GetRoadTileType(t)) {
|
||||
default: NOT_REACHED();
|
||||
default: SlErrorCorrupt("Invalid road tile type");
|
||||
case ROAD_TILE_NORMAL:
|
||||
SB(_m[t].m4, 0, 4, GB(_m[t].m5, 0, 4));
|
||||
SB(_m[t].m4, 4, 4, 0);
|
||||
@ -912,7 +912,7 @@ bool AfterLoadGame()
|
||||
if (fix_roadtypes) SetRoadTypes(t, (RoadTypes)GB(_me[t].m7, 5, 3));
|
||||
SB(_me[t].m7, 5, 1, GB(_m[t].m3, 7, 1)); // snow/desert
|
||||
switch (GetRoadTileType(t)) {
|
||||
default: NOT_REACHED();
|
||||
default: SlErrorCorrupt("Invalid road tile type");
|
||||
case ROAD_TILE_NORMAL:
|
||||
SB(_me[t].m7, 0, 4, GB(_m[t].m3, 0, 4)); // road works
|
||||
SB(_m[t].m6, 3, 3, GB(_m[t].m3, 4, 3)); // ground
|
||||
@ -1031,7 +1031,7 @@ bool AfterLoadGame()
|
||||
|
||||
if (dir != DirToDiagDir(v->direction)) continue;
|
||||
switch (dir) {
|
||||
default: NOT_REACHED();
|
||||
default: SlErrorCorrupt("Invalid vehicle direction");
|
||||
case DIAGDIR_NE: if ((v->x_pos & 0xF) != 0) continue; break;
|
||||
case DIAGDIR_SE: if ((v->y_pos & 0xF) != TILE_SIZE - 1) continue; break;
|
||||
case DIAGDIR_SW: if ((v->x_pos & 0xF) != TILE_SIZE - 1) continue; break;
|
||||
|
@ -178,7 +178,7 @@ static bool LoadObjects()
|
||||
case SQSL_ARRAY_TABLE_END:
|
||||
return false;
|
||||
|
||||
default: NOT_REACHED();
|
||||
default: SlErrorCorrupt("Invalid AI data type");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1095,7 +1095,7 @@ static bool LoadOldVehicleUnion(LoadgameState *ls, int num)
|
||||
res = LoadChunk(ls, NULL, vehicle_empty_chunk);
|
||||
} else {
|
||||
switch (v->type) {
|
||||
default: NOT_REACHED();
|
||||
default: SlErrorCorrupt("Invalid vehicle type");
|
||||
case VEH_TRAIN : res = LoadChunk(ls, v, vehicle_train_chunk); break;
|
||||
case VEH_ROAD : res = LoadChunk(ls, v, vehicle_road_chunk); break;
|
||||
case VEH_SHIP : res = LoadChunk(ls, v, vehicle_ship_chunk); break;
|
||||
@ -1295,7 +1295,7 @@ bool LoadOldVehicle(LoadgameState *ls, int num)
|
||||
} else {
|
||||
/* Read the vehicle type and allocate the right vehicle */
|
||||
switch (ReadByte(ls)) {
|
||||
default: NOT_REACHED();
|
||||
default: SlErrorCorrupt("Invalid vehicle type");
|
||||
case 0x00 /* VEH_INVALID */: v = NULL; break;
|
||||
case 0x10 /* VEH_TRAIN */: v = new (_current_vehicle_id) Train(); break;
|
||||
case 0x11 /* VEH_ROAD */: v = new (_current_vehicle_id) RoadVehicle(); break;
|
||||
|
@ -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) SlErrorCorrupt("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");
|
||||
SlErrorCorrupt("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) SlErrorCorrupt("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");
|
||||
SlErrorCorrupt("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");
|
||||
SlErrorCorrupt("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");
|
||||
SlErrorCorrupt("Referencing invalid Vehicle");
|
||||
|
||||
case REF_STATION:
|
||||
if (Station::IsValidID(index)) return Station::Get(index);
|
||||
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Station");
|
||||
SlErrorCorrupt("Referencing invalid Station");
|
||||
|
||||
case REF_TOWN:
|
||||
if (Town::IsValidID(index)) return Town::Get(index);
|
||||
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Town");
|
||||
SlErrorCorrupt("Referencing invalid Town");
|
||||
|
||||
case REF_ROADSTOPS:
|
||||
if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
|
||||
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid RoadStop");
|
||||
SlErrorCorrupt("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");
|
||||
SlErrorCorrupt("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");
|
||||
SlErrorCorrupt("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()) SlErrorCorrupt("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) SlErrorCorrupt("Invalid chunk size");
|
||||
} else {
|
||||
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk type");
|
||||
SlErrorCorrupt("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) SlErrorCorrupt("Invalid chunk size");
|
||||
} else {
|
||||
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk type");
|
||||
SlErrorCorrupt("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) SlErrorCorrupt("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) SlErrorCorrupt("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)) SlErrorCorrupt("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))) SlErrorCorrupt("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) SlErrorCorrupt("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) SlErrorCorrupt("Unexpected size of chunk");
|
||||
UnInitMem();
|
||||
fclose(_sl.fh);
|
||||
|
||||
|
@ -346,6 +346,7 @@ void SlGlobList(const SaveLoadGlobVarList *sldg);
|
||||
void SlArray(void *array, size_t length, VarType conv);
|
||||
void SlObject(void *object, const SaveLoad *sld);
|
||||
bool SlObjectMember(void *object, const SaveLoad *sld);
|
||||
void NORETURN SlErrorCorrupt(const char *msg);
|
||||
|
||||
bool SaveloadCrashWithMissingNewGRFs();
|
||||
|
||||
|
@ -150,7 +150,7 @@ void ConvertOldMultiheadToNew()
|
||||
u->SetWagon();
|
||||
u->SetFreeWagon();
|
||||
break;
|
||||
default: NOT_REACHED();
|
||||
default: SlErrorCorrupt("Invalid train subtype");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -714,7 +714,7 @@ void Load_VEHS()
|
||||
case VEH_EFFECT: v = new (index) EffectVehicle(); break;
|
||||
case VEH_DISASTER: v = new (index) DisasterVehicle(); break;
|
||||
case VEH_INVALID: // Savegame shouldn't contain invalid vehicles
|
||||
default: NOT_REACHED();
|
||||
default: SlErrorCorrupt("Invalid vehicle type");
|
||||
}
|
||||
|
||||
SlObject(v, GetVehicleDescription(vtype));
|
||||
|
Loading…
Reference in New Issue
Block a user