summaryrefslogtreecommitdiff
path: root/src/saveload/saveload.cpp
diff options
context:
space:
mode:
authorsmatz <smatz@openttd.org>2009-05-17 16:28:29 +0000
committersmatz <smatz@openttd.org>2009-05-17 16:28:29 +0000
commit570af0ce449b6c94427233d7eae07c40bb789197 (patch)
tree81450baf6a65200503c2871c31e586ac5214d054 /src/saveload/saveload.cpp
parent83dc6ef6e6064441c9a5ebc22061de313147821a (diff)
downloadopenttd-570af0ce449b6c94427233d7eae07c40bb789197.tar.xz
(svn r16338) -Codechange: split loading of references to two phases
In the first phase, indexes are stored. In the second phase, indexes are checked for validity and converted to pointers
Diffstat (limited to 'src/saveload/saveload.cpp')
-rw-r--r--src/saveload/saveload.cpp119
1 files changed, 83 insertions, 36 deletions
diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp
index e7091b6bf..c0b6561c2 100644
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -56,6 +56,7 @@ typedef size_t ReaderProc();
enum SaveLoadAction {
SLA_LOAD, ///< loading
SLA_SAVE, ///< saving
+ SLA_PTRS, ///< fixing pointers
};
enum NeedLength {
@@ -564,6 +565,7 @@ static void SlSaveLoadConv(void *ptr, VarType conv)
WriteValue(ptr, conv, x);
break;
}
+ case SLA_PTRS: break;
default: NOT_REACHED();
}
}
@@ -671,6 +673,7 @@ static void SlString(void *ptr, size_t length, VarType conv)
str_validate((char *)ptr, (char *)ptr + len);
break;
}
+ case SLA_PTRS: break;
default: NOT_REACHED();
}
}
@@ -693,6 +696,8 @@ static inline size_t SlCalcArrayLen(size_t length, VarType conv)
*/
void SlArray(void *array, size_t length, VarType conv)
{
+ if (_sl.action == SLA_PTRS) return;
+
/* Automatically calculate the length? */
if (_sl.need_length != NL_NONE) {
SlSetLength(SlCalcArrayLen(length, conv));
@@ -767,13 +772,14 @@ void SlList(void *list, SLRefType conv)
if (_sl.need_length == NL_CALCLENGTH) return;
}
- std::list<void *> *l = (std::list<void *> *) list;
+ typedef std::list<void *> PtrList;
+ PtrList *l = (PtrList *)list;
switch (_sl.action) {
case SLA_SAVE: {
SlWriteUint32((uint32)l->size());
- std::list<void *>::iterator iter;
+ PtrList::iterator iter;
for (iter = l->begin(); iter != l->end(); ++iter) {
void *ptr = *iter;
SlWriteUint32(ReferenceToInt(ptr, conv));
@@ -785,7 +791,18 @@ void SlList(void *list, SLRefType conv)
/* Load each reference and push to the end of the list */
for (uint i = 0; i < length; i++) {
- void *ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), conv);
+ size_t data = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
+ l->push_back((void *)data);
+ }
+ break;
+ }
+ case SLA_PTRS: {
+ PtrList temp = *l;
+
+ l->clear();
+ PtrList::iterator iter;
+ for (iter = temp.begin(); iter != temp.end(); ++iter) {
+ void *ptr = IntToReference((size_t)*iter, conv);
l->push_back(ptr);
}
break;
@@ -885,7 +902,10 @@ bool SlObjectMember(void *ptr, const SaveLoad *sld)
SlWriteUint32(ReferenceToInt(*(void **)ptr, (SLRefType)conv));
break;
case SLA_LOAD:
- *(void **)ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), (SLRefType)conv);
+ *(size_t *)ptr = (size_t)(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32());
+ break;
+ case SLA_PTRS:
+ *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
break;
default: NOT_REACHED();
}
@@ -906,6 +926,7 @@ bool SlObjectMember(void *ptr, const SaveLoad *sld)
switch (_sl.action) {
case SLA_SAVE: SlWriteByte(sld->version_to); break;
case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
+ case SLA_PTRS: break;
default: NOT_REACHED();
}
break;
@@ -1116,6 +1137,33 @@ static void SlLoadChunks()
}
}
+/** Fix all pointers (convert index -> pointer) */
+static void SlFixPointers()
+{
+ const ChunkHandler *ch;
+ const ChunkHandler * const *chsc;
+
+ _sl.action = SLA_PTRS;
+
+ DEBUG(sl, 1, "Fixing pointers");
+
+ for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
+ while (true) {
+ if (ch->ptrs_proc != NULL) {
+ DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
+ ch->ptrs_proc();
+ }
+ if (ch->flags & CH_LAST)
+ break;
+ ch++;
+ }
+ }
+
+ DEBUG(sl, 1, "All pointers fixed");
+
+ assert(_sl.action == SLA_PTRS);
+}
+
/*******************************************
********** START OF LZO CODE **************
*******************************************/
@@ -1424,6 +1472,8 @@ static const ChunkHandler * const _chunk_handlers[] = {
*/
static uint ReferenceToInt(const void *obj, SLRefType rt)
{
+ assert(_sl.action == SLA_SAVE);
+
if (obj == NULL) return 0;
switch (rt) {
@@ -1452,8 +1502,13 @@ static uint ReferenceToInt(const void *obj, SLRefType rt)
* @param rt SLRefType type of the object the pointer is sought of
* @return Return the index converted to a pointer of any type
*/
+
+assert_compile(sizeof(size_t) <= sizeof(void *));
+
static void *IntToReference(uint index, SLRefType rt)
{
+ assert(_sl.action == SLA_PTRS);
+
/* After version 4.3 REF_VEHICLE_OLD is saved as REF_VEHICLE,
* and should be loaded like that */
if (rt == REF_VEHICLE_OLD && !CheckSavegameVersionOldStyle(4, 4)) {
@@ -1461,59 +1516,50 @@ static void *IntToReference(uint index, SLRefType rt)
}
/* No need to look up NULL pointers, just return immediately */
- if (rt != REF_VEHICLE_OLD && index == 0) {
- return NULL;
- }
+ if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
- index--; // correct for the NULL index
+ /* Correct index. Old vehicles were saved differently:
+ * invalid vehicle was 0xFFFF, now we use 0x0000 for everything invalid. */
+ if (rt != REF_VEHICLE_OLD) index--;
switch (rt) {
case REF_ORDERLIST:
- if (_OrderList_pool.AddBlockIfNeeded(index)) return OrderList::Get(index);
- SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "OrderList index out of range");
+ if (OrderList::IsValidID(index)) return OrderList::Get(index);
+ SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid OrderList");
case REF_ORDER:
- if (_Order_pool.AddBlockIfNeeded(index)) return Order::Get(index);
- SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Order index out of range");
+ 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");
+ case REF_VEHICLE_OLD:
case REF_VEHICLE:
- if (_Vehicle_pool.AddBlockIfNeeded(index)) return Vehicle::Get(index);
- SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Vehicle index out of range");
+ if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
+ SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Vehicle");
case REF_STATION:
- if (_Station_pool.AddBlockIfNeeded(index)) return Station::Get(index);
- SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Station index out of range");
+ if (Station::IsValidID(index)) return Station::Get(index);
+ SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Station");
case REF_TOWN:
- if (_Town_pool.AddBlockIfNeeded(index)) return Town::Get(index);
- SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Town index out of range");
+ if (Town::IsValidID(index)) return Town::Get(index);
+ SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Town");
case REF_ROADSTOPS:
- if (_RoadStop_pool.AddBlockIfNeeded(index)) return RoadStop::Get(index);
- SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "RoadStop index out of range");
+ if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
+ SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid RoadStop");
case REF_ENGINE_RENEWS:
- if (_EngineRenew_pool.AddBlockIfNeeded(index)) return EngineRenew::Get(index);
- SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "EngineRenew index out of range");
+ if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
+ SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid EngineRenew");
case REF_CARGO_PACKET:
- if (_CargoPacket_pool.AddBlockIfNeeded(index)) return CargoPacket::Get(index);
- SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "CargoPacket index out of range");
-
- case REF_VEHICLE_OLD:
- /* Old vehicles were saved differently:
- * invalid vehicle was 0xFFFF,
- * and the index was not - 1.. correct for this */
- index++;
- if (index == INVALID_VEHICLE) return NULL;
-
- if (_Vehicle_pool.AddBlockIfNeeded(index)) return Vehicle::Get(index);
- SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Vehicle index out of range");
+ if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
+ SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid CargoPacket");
default: NOT_REACHED();
}
-
- return NULL;
}
/** The format for a reader/writer type of a savegame */
@@ -1852,6 +1898,7 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb)
GamelogReset();
SlLoadChunks();
+ SlFixPointers();
fmt->uninit_read();
fclose(_sl.fh);