summaryrefslogtreecommitdiff
path: root/src/saveload
diff options
context:
space:
mode:
Diffstat (limited to 'src/saveload')
-rw-r--r--src/saveload/company_sl.cpp52
-rw-r--r--src/saveload/game_sl.cpp12
-rw-r--r--src/saveload/linkgraph_sl.cpp25
-rw-r--r--src/saveload/saveload.cpp28
-rw-r--r--src/saveload/saveload.h5
-rw-r--r--src/saveload/station_sl.cpp55
-rw-r--r--src/saveload/town_sl.cpp21
7 files changed, 156 insertions, 42 deletions
diff --git a/src/saveload/company_sl.cpp b/src/saveload/company_sl.cpp
index 550816a07..880fc9e89 100644
--- a/src/saveload/company_sl.cpp
+++ b/src/saveload/company_sl.cpp
@@ -372,8 +372,19 @@ public:
class SlCompanyOldEconomy : public SlCompanyEconomy {
public:
- void GenericSaveLoad(CompanyProperties *c) const
+ void Save(CompanyProperties *c) const override
+ {
+ SlSetStructListLength(c->num_valid_stat_ent);
+ for (int i = 0; i < c->num_valid_stat_ent; i++) {
+ SlObject(&c->old_economy[i], this->GetDescription());
+ }
+ }
+
+ void Load(CompanyProperties *c) const override
{
+ if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) {
+ c->num_valid_stat_ent = (uint8)SlGetStructListLength(UINT8_MAX);
+ }
if (c->num_valid_stat_ent > lengthof(c->old_economy)) SlErrorCorrupt("Too many old economy entries");
for (int i = 0; i < c->num_valid_stat_ent; i++) {
@@ -381,10 +392,7 @@ public:
}
}
- void Save(CompanyProperties *c) const override { this->GenericSaveLoad(c); }
- void Load(CompanyProperties *c) const override { this->GenericSaveLoad(c); }
- void LoadCheck(CompanyProperties *c) const override { this->GenericSaveLoad(c); }
- void FixPointers(CompanyProperties *c) const override { this->GenericSaveLoad(c); }
+ void LoadCheck(CompanyProperties *c) const override { this->Load(c); }
};
class SlCompanyLiveries : public DefaultSaveLoadHandler<SlCompanyLiveries, CompanyProperties> {
@@ -395,12 +403,33 @@ public:
SLE_CONDVAR(Livery, colour2, SLE_UINT8, SLV_34, SL_MAX_VERSION),
};
- void GenericSaveLoad(CompanyProperties *c) const
+ /**
+ * Get the number of liveries used by this savegame version.
+ * @return The number of liveries used by this savegame version.
+ */
+ size_t GetNumLiveries() const
{
- int num_liveries = IsSavegameVersionBefore(SLV_63) ? LS_END - 4 : (IsSavegameVersionBefore(SLV_85) ? LS_END - 2: LS_END);
+ if (IsSavegameVersionBefore(SLV_63)) return LS_END - 4;
+ if (IsSavegameVersionBefore(SLV_85)) return LS_END - 2;
+ if (IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) return LS_END;
+ /* Read from the savegame how long the list is. */
+ return SlGetStructListLength(LS_END);
+ }
+
+ void Save(CompanyProperties *c) const override
+ {
+ SlSetStructListLength(LS_END);
+ for (int i = 0; i < LS_END; i++) {
+ SlObject(&c->livery[i], this->GetDescription());
+ }
+ }
+
+ void Load(CompanyProperties *c) const override
+ {
+ size_t num_liveries = this->GetNumLiveries();
bool update_in_use = IsSavegameVersionBefore(SLV_GROUP_LIVERIES);
- for (int i = 0; i < num_liveries; i++) {
+ for (size_t i = 0; i < num_liveries; i++) {
SlObject(&c->livery[i], this->GetDescription());
if (update_in_use && i != LS_DEFAULT) {
if (c->livery[i].in_use == 0) {
@@ -426,10 +455,7 @@ public:
}
}
- void Save(CompanyProperties *c) const override { this->GenericSaveLoad(c); }
- void Load(CompanyProperties *c) const override { this->GenericSaveLoad(c); }
- void LoadCheck(CompanyProperties *c) const override { this->GenericSaveLoad(c); }
- void FixPointers(CompanyProperties *c) const override { this->GenericSaveLoad(c); }
+ void LoadCheck(CompanyProperties *c) const override { this->Load(c); }
};
/* Save/load of companies */
@@ -467,7 +493,7 @@ static const SaveLoad _company_desc[] = {
SLE_ARR(CompanyProperties, share_owners, SLE_UINT8, 4),
- SLE_VAR(CompanyProperties, num_valid_stat_ent, SLE_UINT8),
+ SLE_CONDVAR(CompanyProperties, num_valid_stat_ent, SLE_UINT8, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH),
SLE_VAR(CompanyProperties, months_of_bankruptcy, SLE_UINT8),
SLE_CONDVAR(CompanyProperties, bankrupt_asked, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104),
diff --git a/src/saveload/game_sl.cpp b/src/saveload/game_sl.cpp
index af01d5bd0..76a81e167 100644
--- a/src/saveload/game_sl.cpp
+++ b/src/saveload/game_sl.cpp
@@ -121,6 +121,8 @@ public:
void Save(LanguageStrings *ls) const override
{
+ SlSetStructListLength(ls->lines.size());
+
for (const auto &string : ls->lines) {
_game_saveload_string = string;
SlObject(nullptr, this->GetDescription());
@@ -129,7 +131,9 @@ public:
void Load(LanguageStrings *ls) const override
{
- for (uint32 i = 0; i < _game_saveload_strings; i++) {
+ uint32 length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _game_saveload_strings : (uint32)SlGetStructListLength(UINT32_MAX);
+
+ for (uint32 i = 0; i < length; i++) {
SlObject(nullptr, this->GetDescription());
ls->lines.emplace_back(_game_saveload_string);
}
@@ -138,7 +142,7 @@ public:
static const SaveLoad _game_language_desc[] = {
SLE_SSTR(LanguageStrings, language, SLE_STR),
- SLEG_VAR(_game_saveload_strings, SLE_UINT32),
+ SLEG_CONDVAR(_game_saveload_strings, SLE_UINT32, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH),
SLEG_STRUCTLIST(SlGameLanguageString),
};
@@ -170,9 +174,7 @@ static void Save_GSTR()
for (uint i = 0; i < _current_data->raw_strings.size(); i++) {
SlSetArrayIndex(i);
- LanguageStrings *ls = &_current_data->raw_strings[i];
- _game_saveload_strings = (uint32)ls->lines.size();
- SlObject(ls, _game_language_desc);
+ SlObject(&_current_data->raw_strings[i], _game_language_desc);
}
}
diff --git a/src/saveload/linkgraph_sl.cpp b/src/saveload/linkgraph_sl.cpp
index cf0292e6e..fc72d4383 100644
--- a/src/saveload/linkgraph_sl.cpp
+++ b/src/saveload/linkgraph_sl.cpp
@@ -37,6 +37,12 @@ public:
void Save(Node *bn) const override
{
+ uint16 size = 0;
+ for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->edges[_linkgraph_from][to].next_edge) {
+ size++;
+ }
+
+ SlSetStructListLength(size);
for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->edges[_linkgraph_from][to].next_edge) {
SlObject(&_linkgraph->edges[_linkgraph_from][to], this->GetDescription());
}
@@ -54,11 +60,18 @@ public:
return;
}
+ size_t used_size = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? max_size : SlGetStructListLength(UINT16_MAX);
+
/* ... but as that wasted a lot of space we save a sparse matrix now. */
for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->edges[_linkgraph_from][to].next_edge) {
+ if (used_size == 0) SlErrorCorrupt("Link graph structure overflow");
+ used_size--;
+
if (to >= max_size) SlErrorCorrupt("Link graph structure overflow");
SlObject(&_linkgraph->edges[_linkgraph_from][to], this->GetDescription());
}
+
+ if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) && used_size > 0) SlErrorCorrupt("Corrupted link graph");
}
};
@@ -77,6 +90,7 @@ public:
{
_linkgraph = lg;
+ SlSetStructListLength(lg->Size());
for (NodeID from = 0; from < lg->Size(); ++from) {
_linkgraph_from = from;
SlObject(&lg->nodes[from], this->GetDescription());
@@ -87,8 +101,9 @@ public:
{
_linkgraph = lg;
- lg->Init(_num_nodes);
- for (NodeID from = 0; from < _num_nodes; ++from) {
+ uint16 length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _num_nodes : (uint16)SlGetStructListLength(UINT16_MAX);
+ lg->Init(length);
+ for (NodeID from = 0; from < length; ++from) {
_linkgraph_from = from;
SlObject(&lg->nodes[from], this->GetDescription());
}
@@ -103,7 +118,7 @@ SaveLoadTable GetLinkGraphDesc()
{
static const SaveLoad link_graph_desc[] = {
SLE_VAR(LinkGraph, last_compression, SLE_INT32),
- SLEG_VAR(_num_nodes, SLE_UINT16),
+ SLEG_CONDVAR(_num_nodes, SLE_UINT16, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH),
SLE_VAR(LinkGraph, cargo, SLE_UINT8),
SLEG_STRUCTLIST(SlLinkgraphNode),
};
@@ -227,8 +242,6 @@ void AfterLoadLinkGraphs()
static void Save_LGRP()
{
for (LinkGraph *lg : LinkGraph::Iterate()) {
- _num_nodes = lg->Size();
-
SlSetArrayIndex(lg->index);
SlObject(lg, GetLinkGraphDesc());
}
@@ -252,8 +265,6 @@ static void Load_LGRP()
static void Save_LGRJ()
{
for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) {
- _num_nodes = lgj->Size();
-
SlSetArrayIndex(lgj->index);
SlObject(lgj, GetLinkGraphJobDesc());
}
diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp
index cb28fb6d2..3ca10b527 100644
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -1590,6 +1590,34 @@ static bool SlObjectMember(void *object, const SaveLoad &sld)
}
/**
+ * Set the length of this list.
+ * @param The length of the list.
+ */
+void SlSetStructListLength(size_t length)
+{
+ /* Automatically calculate the length? */
+ if (_sl.need_length != NL_NONE) {
+ SlSetLength(SlGetArrayLength(length));
+ if (_sl.need_length == NL_CALCLENGTH) return;
+ }
+
+ SlWriteArrayLength(length);
+}
+
+/**
+ * Get the length of this list; if it exceeds the limit, error out.
+ * @param limit The maximum size the list can be.
+ * @return The length of the list.
+ */
+size_t SlGetStructListLength(size_t limit)
+{
+ size_t length = SlReadArrayLength();
+ if (length > limit) SlErrorCorrupt("List exceeds storage size");
+
+ return length;
+}
+
+/**
* Main SaveLoad function.
* @param object The object that is being saved or loaded.
* @param slt The SaveLoad table with objects to save/load.
diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h
index 7b0127709..42d14c785 100644
--- a/src/saveload/saveload.h
+++ b/src/saveload/saveload.h
@@ -326,9 +326,11 @@ enum SaveLoadVersion : uint16 {
SLV_GS_INDUSTRY_CONTROL, ///< 287 PR#7912 and PR#8115 GS industry control.
SLV_VEH_MOTION_COUNTER, ///< 288 PR#8591 Desync safe motion counter
SLV_INDUSTRY_TEXT, ///< 289 PR#8576 v1.11.0-RC1 Additional GS text for industries.
+
SLV_MAPGEN_SETTINGS_REVAMP, ///< 290 PR#8891 v1.11 Revamp of some mapgen settings (snow coverage, desert coverage, heightmap height, custom terrain type).
SLV_GROUP_REPLACE_WAGON_REMOVAL, ///< 291 PR#7441 Per-group wagon removal flag.
SLV_CUSTOM_SUBSIDY_DURATION, ///< 292 PR#9081 Configurable subsidy duration.
+ SLV_SAVELOAD_LIST_LENGTH, ///< 293 PR#9374 Consistency in list length with SL_STRUCT / SL_STRUCTLIST / SL_DEQUE / SL_REFLIST.
SL_MAX_VERSION, ///< Highest possible saveload version
};
@@ -992,6 +994,9 @@ void WriteValue(void *ptr, VarType conv, int64 val);
void SlSetArrayIndex(uint index);
int SlIterateArray();
+void SlSetStructListLength(size_t length);
+size_t SlGetStructListLength(size_t limit);
+
void SlAutolength(AutolengthProc *proc, void *arg);
size_t SlGetFieldLength();
void SlSetLength(size_t length);
diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp
index 4421e0f9f..7144c5de4 100644
--- a/src/saveload/station_sl.cpp
+++ b/src/saveload/station_sl.cpp
@@ -157,14 +157,14 @@ static const SaveLoad _roadstop_desc[] = {
};
static uint16 _waiting_acceptance;
-static uint32 _num_flows;
+static uint32 _old_num_flows;
static uint16 _cargo_source;
static uint32 _cargo_source_xy;
static uint8 _cargo_days;
static Money _cargo_feeder_share;
std::list<CargoPacket *> _packets;
-uint32 _num_dests;
+uint32 _old_num_dests;
struct FlowSaveLoad {
FlowSaveLoad() : source(0), via(0), share(0), restricted(false) {}
@@ -209,6 +209,7 @@ public:
void Save(BaseStation *bst) const override
{
+ SlSetStructListLength(bst->num_specs);
for (uint i = 0; i < bst->num_specs; i++) {
SlObject(&bst->speclist[i], this->GetDescription());
}
@@ -216,6 +217,10 @@ public:
void Load(BaseStation *bst) const override
{
+ if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) {
+ bst->num_specs = (uint8)SlGetStructListLength(UINT8_MAX);
+ }
+
if (bst->num_specs != 0) {
/* Allocate speclist memory when loading a game */
bst->speclist = CallocT<StationSpecList>(bst->num_specs);
@@ -235,6 +240,7 @@ public:
void Save(GoodsEntry *ge) const override
{
+ SlSetStructListLength(ge->cargo.Packets()->MapSize());
for (StationCargoPacketMap::ConstMapIterator it(ge->cargo.Packets()->begin()); it != ge->cargo.Packets()->end(); ++it) {
SlObject(const_cast<StationCargoPacketMap::value_type *>(&(*it)), this->GetDescription());
}
@@ -242,8 +248,10 @@ public:
void Load(GoodsEntry *ge) const override
{
+ size_t num_dests = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _old_num_dests : SlGetStructListLength(UINT32_MAX);
+
StationCargoPair pair;
- for (uint j = 0; j < _num_dests; ++j) {
+ for (uint j = 0; j < num_dests; ++j) {
SlObject(&pair, this->GetDescription());
const_cast<StationCargoPacketMap &>(*(ge->cargo.Packets()))[pair.first].swap(pair.second);
assert(pair.second.empty());
@@ -269,6 +277,12 @@ public:
void Save(GoodsEntry *ge) const override
{
+ uint32 num_flows = 0;
+ for (FlowStatMap::const_iterator it(ge->flows.begin()); it != ge->flows.end(); ++it) {
+ num_flows += (uint32)it->second.GetShares()->size();
+ }
+ SlSetStructListLength(num_flows);
+
for (FlowStatMap::const_iterator outer_it(ge->flows.begin()); outer_it != ge->flows.end(); ++outer_it) {
const FlowStat::SharesMap *shares = outer_it->second.GetShares();
uint32 sum_shares = 0;
@@ -287,10 +301,12 @@ public:
void Load(GoodsEntry *ge) const override
{
+ size_t num_flows = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _old_num_flows : SlGetStructListLength(UINT32_MAX);
+
FlowSaveLoad flow;
FlowStat *fs = nullptr;
StationID prev_source = INVALID_STATION;
- for (uint32 j = 0; j < _num_flows; ++j) {
+ for (uint32 j = 0; j < num_flows; ++j) {
SlObject(&flow, this->GetDescription());
if (fs == nullptr || prev_source != flow.source) {
fs = &(ge->flows.insert(std::make_pair(flow.source, FlowStat(flow.via, flow.share, flow.restricted))).first->second);
@@ -330,11 +346,11 @@ public:
SLEG_CONDVAR( _cargo_feeder_share, SLE_INT64, SLV_65, SLV_68),
SLE_CONDVAR(GoodsEntry, amount_fract, SLE_UINT8, SLV_150, SL_MAX_VERSION),
SLEG_CONDREFLIST( _packets, REF_CARGO_PACKET, SLV_68, SLV_183),
- SLEG_CONDVAR( _num_dests, SLE_UINT32, SLV_183, SL_MAX_VERSION),
+ SLEG_CONDVAR( _old_num_dests, SLE_UINT32, SLV_183, SLV_SAVELOAD_LIST_LENGTH),
SLE_CONDVAR(GoodsEntry, cargo.reserved_count, SLE_UINT, SLV_181, SL_MAX_VERSION),
SLE_CONDVAR(GoodsEntry, link_graph, SLE_UINT16, SLV_183, SL_MAX_VERSION),
SLE_CONDVAR(GoodsEntry, node, SLE_UINT16, SLV_183, SL_MAX_VERSION),
- SLEG_CONDVAR( _num_flows, SLE_UINT32, SLV_183, SL_MAX_VERSION),
+ SLEG_CONDVAR( _old_num_flows, SLE_UINT32, SLV_183, SLV_SAVELOAD_LIST_LENGTH),
SLE_CONDVAR(GoodsEntry, max_waiting_cargo, SLE_UINT32, SLV_183, SL_MAX_VERSION),
SLEG_CONDSTRUCTLIST(SlStationFlow, SLV_183, SL_MAX_VERSION),
SLEG_CONDSTRUCTLIST(SlStationCargo, SLV_183, SL_MAX_VERSION),
@@ -344,15 +360,26 @@ public:
}
#endif
+ /**
+ * Get the number of cargoes used by this savegame version.
+ * @return The number of cargoes used by this savegame version.
+ */
+ size_t GetNumCargo() const
+ {
+ if (IsSavegameVersionBefore(SLV_55)) return 12;
+ if (IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES)) return 32;
+ if (IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) return NUM_CARGO;
+ /* Read from the savegame how long the list is. */
+ return SlGetStructListLength(NUM_CARGO);
+ }
+
void Save(BaseStation *bst) const override
{
Station *st = Station::From(bst);
+
+ SlSetStructListLength(NUM_CARGO);
+
for (CargoID i = 0; i < NUM_CARGO; i++) {
- _num_dests = (uint32)st->goods[i].cargo.Packets()->MapSize();
- _num_flows = 0;
- for (FlowStatMap::const_iterator it(st->goods[i].flows.begin()); it != st->goods[i].flows.end(); ++it) {
- _num_flows += (uint32)it->second.GetShares()->size();
- }
SlObject(&st->goods[i], this->GetDescription());
}
}
@@ -369,7 +396,7 @@ public:
memcpy(st->airport.psa->storage, _old_st_persistent_storage.storage, sizeof(_old_st_persistent_storage.storage));
}
- uint num_cargo = IsSavegameVersionBefore(SLV_55) ? 12 : IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO;
+ size_t num_cargo = this->GetNumCargo();
for (CargoID i = 0; i < num_cargo; i++) {
GoodsEntry *ge = &st->goods[i];
SlObject(ge, this->GetDescription());
@@ -520,7 +547,7 @@ public:
/* Used by newstations for graphic variations */
SLE_VAR(BaseStation, random_bits, SLE_UINT16),
SLE_VAR(BaseStation, waiting_triggers, SLE_UINT8),
- SLE_VAR(BaseStation, num_specs, SLE_UINT8),
+ SLE_CONDVAR(BaseStation, num_specs, SLE_UINT8, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH),
};
void GenericSaveLoad(BaseStation *bst) const
@@ -626,7 +653,7 @@ static void Save_STNN()
static void Load_STNN()
{
- _num_flows = 0;
+ _old_num_flows = 0;
int index;
while ((index = SlIterateArray()) != -1) {
diff --git a/src/saveload/town_sl.cpp b/src/saveload/town_sl.cpp
index 4151e3c75..38c000e3b 100644
--- a/src/saveload/town_sl.cpp
+++ b/src/saveload/town_sl.cpp
@@ -122,8 +122,21 @@ public:
SLE_CONDVAR(TransportedCargoStat<uint32>, new_act, SLE_UINT32, SLV_165, SL_MAX_VERSION),
};
+ /**
+ * Get the number of cargoes used by this savegame version.
+ * @return The number of cargoes used by this savegame version.
+ */
+ size_t GetNumCargo() const
+ {
+ if (IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES)) return 32;
+ if (IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) return NUM_CARGO;
+ /* Read from the savegame how long the list is. */
+ return SlGetStructListLength(NUM_CARGO);
+ }
+
void Save(Town *t) const override
{
+ SlSetStructListLength(NUM_CARGO);
for (CargoID i = 0; i < NUM_CARGO; i++) {
SlObject(&t->supplied[i], this->GetDescription());
}
@@ -131,7 +144,7 @@ public:
void Load(Town *t) const override
{
- uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO;
+ size_t num_cargo = this->GetNumCargo();
for (CargoID i = 0; i < num_cargo; i++) {
SlObject(&t->supplied[i], this->GetDescription());
}
@@ -149,14 +162,16 @@ public:
void Save(Town *t) const override
{
- for (int i = TE_BEGIN; i < TE_END; i++) {
+ SlSetStructListLength(NUM_TE);
+ for (size_t i = TE_BEGIN; i < TE_END; i++) {
SlObject(&t->received[i], this->GetDescription());
}
}
void Load(Town *t) const override
{
- for (int i = TE_BEGIN; i < TE_END; i++) {
+ size_t length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? (size_t)TE_END : SlGetStructListLength(TE_END);
+ for (size_t i = 0; i < length; i++) {
SlObject(&t->received[i], this->GetDescription());
}
}