diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/saveload/saveload.cpp | 90 | ||||
-rw-r--r-- | src/saveload/saveload.h | 41 |
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. */ |