summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/saveload/saveload.cpp90
-rw-r--r--src/saveload/saveload.h41
2 files changed, 99 insertions, 32 deletions
diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp
index 82e96080e..69bbc75b1 100644
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -314,9 +314,9 @@ static void SlNullPointers()
_sl_version = SAVEGAME_VERSION;
for (auto &ch : ChunkHandlers()) {
- if (ch.ptrs_proc != nullptr) {
+ if (ch.fix_pointers) {
Debug(sl, 3, "Nulling pointers for {:c}{:c}{:c}{:c}", ch.id >> 24, ch.id >> 16, ch.id >> 8, ch.id);
- ch.ptrs_proc();
+ ch.FixPointers();
}
}
@@ -2114,6 +2114,48 @@ void SlAutolength(AutolengthProc *proc, void *arg)
if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
}
+void ChunkHandler::Save() const
+{
+ assert(this->save_proc != nullptr);
+ this->save_proc();
+}
+
+void ChunkHandler::Load() const
+{
+ assert(this->load_proc != nullptr);
+ this->load_proc();
+}
+
+void ChunkHandler::FixPointers() const
+{
+ assert(this->ptrs_proc != nullptr);
+ this->ptrs_proc();
+}
+
+void ChunkHandler::LoadCheck(size_t len) const
+{
+ if (this->load_check) {
+ assert(this->load_check_proc != nullptr);
+ this->load_check_proc();
+ } else {
+ switch (_sl.block_mode) {
+ case CH_TABLE:
+ case CH_SPARSE_TABLE:
+ SlTableHeader({});
+ FALLTHROUGH;
+ case CH_ARRAY:
+ case CH_SPARSE_ARRAY:
+ SlSkipArray();
+ break;
+ case CH_RIFF:
+ SlSkipBytes(len);
+ break;
+ default:
+ NOT_REACHED();
+ }
+ }
+}
+
/**
* Load a chunk of data (eg vehicles, stations, etc.)
* @param ch The chunkhandler that will be used for the operation
@@ -2129,7 +2171,7 @@ static void SlLoadChunk(const ChunkHandler &ch)
_sl.expect_table_header = (_sl.block_mode == CH_TABLE || _sl.block_mode == CH_SPARSE_TABLE);
/* The header should always be at the start. Read the length; the
- * load_proc() should as first action process the header. */
+ * Load() should as first action process the header. */
if (_sl.expect_table_header) {
SlIterateArray();
}
@@ -2138,12 +2180,12 @@ static void SlLoadChunk(const ChunkHandler &ch)
case CH_TABLE:
case CH_ARRAY:
_sl.array_index = 0;
- ch.load_proc();
+ ch.Load();
if (_next_offs != 0) SlErrorCorrupt("Invalid array length");
break;
case CH_SPARSE_TABLE:
case CH_SPARSE_ARRAY:
- ch.load_proc();
+ ch.Load();
if (_next_offs != 0) SlErrorCorrupt("Invalid array length");
break;
case CH_RIFF:
@@ -2152,7 +2194,7 @@ static void SlLoadChunk(const ChunkHandler &ch)
len += SlReadUint16();
_sl.obj_len = len;
endoffs = _sl.reader->GetSize() + len;
- ch.load_proc();
+ ch.Load();
if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
break;
default:
@@ -2179,9 +2221,8 @@ static void SlLoadCheckChunk(const ChunkHandler &ch)
_sl.expect_table_header = (_sl.block_mode == CH_TABLE || _sl.block_mode == CH_SPARSE_TABLE);
/* The header should always be at the start. Read the length; the
- * load_check_proc() should as first action process the header. */
- if (_sl.expect_table_header && ch.load_check_proc != nullptr) {
- /* If load_check_proc() is nullptr, SlSkipArray() will already skip the header. */
+ * LoadCheck() should as first action process the header. */
+ if (_sl.expect_table_header) {
SlIterateArray();
}
@@ -2189,19 +2230,11 @@ static void SlLoadCheckChunk(const ChunkHandler &ch)
case CH_TABLE:
case CH_ARRAY:
_sl.array_index = 0;
- if (ch.load_check_proc != nullptr) {
- ch.load_check_proc();
- } else {
- SlSkipArray();
- }
+ ch.LoadCheck();
break;
case CH_SPARSE_TABLE:
case CH_SPARSE_ARRAY:
- if (ch.load_check_proc != nullptr) {
- ch.load_check_proc();
- } else {
- SlSkipArray();
- }
+ ch.LoadCheck();
break;
case CH_RIFF:
/* Read length */
@@ -2209,11 +2242,7 @@ static void SlLoadCheckChunk(const ChunkHandler &ch)
len += SlReadUint16();
_sl.obj_len = len;
endoffs = _sl.reader->GetSize() + len;
- if (ch.load_check_proc) {
- ch.load_check_proc();
- } else {
- SlSkipBytes(len);
- }
+ ch.LoadCheck(len);
if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
break;
default:
@@ -2233,9 +2262,6 @@ static void SlSaveChunk(const ChunkHandler &ch)
{
if (ch.type == CH_READONLY) return;
- ChunkSaveLoadProc *proc = ch.save_proc;
- assert(proc != nullptr);
-
SlWriteUint32(ch.id);
Debug(sl, 2, "Saving chunk {:c}{:c}{:c}{:c}", ch.id >> 24, ch.id >> 16, ch.id >> 8, ch.id);
@@ -2246,19 +2272,19 @@ static void SlSaveChunk(const ChunkHandler &ch)
switch (_sl.block_mode) {
case CH_RIFF:
- proc();
+ ch.Save();
break;
case CH_TABLE:
case CH_ARRAY:
_sl.last_array_index = 0;
SlWriteByte(_sl.block_mode);
- proc();
+ ch.Save();
SlWriteArrayLength(0); // Terminate arrays
break;
case CH_SPARSE_TABLE:
case CH_SPARSE_ARRAY:
SlWriteByte(_sl.block_mode);
- proc();
+ ch.Save();
SlWriteArrayLength(0); // Terminate arrays
break;
default: NOT_REACHED();
@@ -2326,9 +2352,9 @@ static void SlFixPointers()
_sl.action = SLA_PTRS;
for (auto &ch : ChunkHandlers()) {
- if (ch.ptrs_proc != nullptr) {
+ if (ch.fix_pointers) {
Debug(sl, 3, "Fixing pointers for {:c}{:c}{:c}{:c}", ch.id >> 24, ch.id >> 16, ch.id >> 8, ch.id);
- ch.ptrs_proc();
+ ch.FixPointers();
}
}
diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h
index 34dea3cb1..381e355e0 100644
--- a/src/saveload/saveload.h
+++ b/src/saveload/saveload.h
@@ -407,6 +407,47 @@ struct ChunkHandler {
ChunkSaveLoadProc *ptrs_proc; ///< Manipulate pointers in the chunk.
ChunkSaveLoadProc *load_check_proc; ///< Load procedure for game preview.
ChunkType type; ///< Type of the chunk. @see ChunkType
+
+ bool fix_pointers = false;
+ bool load_check = false;
+
+ ChunkHandler(uint32 id, ChunkType type) : id(id), type(type) {}
+
+ ChunkHandler(uint32 id, ChunkSaveLoadProc *save_proc, ChunkSaveLoadProc *load_proc, ChunkSaveLoadProc *ptrs_proc, ChunkSaveLoadProc *load_check_proc, ChunkType type)
+ : id(id), save_proc(save_proc), load_proc(load_proc), ptrs_proc(ptrs_proc), load_check_proc(load_check_proc), type(type)
+ {
+ this->fix_pointers = ptrs_proc != nullptr;
+ this->load_check = load_check_proc != nullptr;
+ }
+
+ virtual ~ChunkHandler() {}
+
+ /**
+ * Save the chunk.
+ * Must be overridden, unless Chunk type is CH_READONLY.
+ */
+ virtual void Save() const;
+
+ /**
+ * Load the chunk.
+ * Must be overridden.
+ */
+ virtual void Load() const;
+
+ /**
+ * Fix the pointers.
+ * Pointers are saved using the index of the pointed object.
+ * On load, pointers are filled with indices and need to be fixed to point to the real object.
+ * Must be overridden if the chunk saves any pointer.
+ */
+ virtual void FixPointers() const;
+
+ /**
+ * Load the chunk for game preview.
+ * Default implementation just skips the data.
+ * @param len Number of bytes to skip.
+ */
+ virtual void LoadCheck(size_t len = 0) const;
};
/** A table of ChunkHandler entries. */