2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
10 * All actions handling saving and loading goes on in this file. The general actions
11 * are as follows for saving a game (loading is analogous):
13 * <li>initialize the writer by creating a temporary memory-buffer for it
14 * <li>go through all to-be saved elements, each 'chunk' (#ChunkHandler) prefixed by a label
15 * <li>use their description array (#SaveLoad) to know what elements to save and in what version
16 * of the game it was active (used when loading)
17 * <li>write all data byte-by-byte to the temporary buffer so it is endian-safe
18 * <li>when the buffer is full; flush it to the output (eg save to file) (_sl.buf, _sl.bufp, _sl.bufe)
19 * <li>repeat this until everything is done, and flush any remaining output to file
23 #include "../stdafx.h"
25 #include "../station_base.h"
26 #include "../thread.h"
28 #include "../network/network.h"
29 #include "../window_func.h"
30 #include "../strings_func.h"
31 #include "../core/endian_func.hpp"
32 #include "../vehicle_base.h"
33 #include "../company_func.h"
34 #include "../timer/timer_game_economy.h"
35 #include "../autoreplace_base.h"
36 #include "../roadstop_base.h"
37 #include "../linkgraph/linkgraph.h"
38 #include "../linkgraph/linkgraphjob.h"
39 #include "../statusbar_gui.h"
40 #include "../fileio_func.h"
41 #include "../gamelog.h"
42 #include "../string_func.h"
47 # include <emscripten.h>
50 #include "table/strings.h"
52 #include "saveload_internal.h"
53 #include "saveload_filter.h"
55 #include "../safeguards.h"
57 extern const SaveLoadVersion SAVEGAME_VERSION
= (SaveLoadVersion
)(SL_MAX_VERSION
- 1); ///< Current savegame version of OpenTTD.
59 SavegameType _savegame_type
; ///< type of savegame we are loading
60 FileToSaveLoad _file_to_saveload
; ///< File to save or load in the openttd loop.
62 uint32_t _ttdp_version
; ///< version of TTDP savegame (if applicable)
63 SaveLoadVersion _sl_version
; ///< the major savegame version identifier
64 uint8_t _sl_minor_version
; ///< the minor savegame version, DO NOT USE!
65 std::string _savegame_format
; ///< how to compress savegames
66 bool _do_autosave
; ///< are we doing an autosave at the moment?
68 /** What are we currently doing? */
70 SLA_LOAD
, ///< loading
72 SLA_PTRS
, ///< fixing pointers
73 SLA_NULL
, ///< null all pointers (on loading error)
74 SLA_LOAD_CHECK
, ///< partial loading into #_load_check_data
78 NL_NONE
= 0, ///< not working in NeedLength mode
79 NL_WANTLENGTH
= 1, ///< writing length and data
80 NL_CALCLENGTH
= 2, ///< need to calculate the length
83 /** Save in chunks of 128 KiB. */
84 static const size_t MEMORY_CHUNK_SIZE
= 128 * 1024;
86 /** A buffer for reading (and buffering) savegame data. */
88 uint8_t buf
[MEMORY_CHUNK_SIZE
]; ///< Buffer we're going to read from.
89 uint8_t *bufp
; ///< Location we're at reading the buffer.
90 uint8_t *bufe
; ///< End of the buffer we can read from.
91 std::shared_ptr
<LoadFilter
> reader
; ///< The filter used to actually read.
92 size_t read
; ///< The amount of read bytes so far from the filter.
95 * Initialise our variables.
96 * @param reader The filter to actually read data.
98 ReadBuffer(std::shared_ptr
<LoadFilter
> reader
) : bufp(nullptr), bufe(nullptr), reader(reader
), read(0)
102 inline uint8_t ReadByte()
104 if (this->bufp
== this->bufe
) {
105 size_t len
= this->reader
->Read(this->buf
, lengthof(this->buf
));
106 if (len
== 0) SlErrorCorrupt("Unexpected end of chunk");
109 this->bufp
= this->buf
;
110 this->bufe
= this->buf
+ len
;
113 return *this->bufp
++;
117 * Get the size of the memory dump made so far.
120 size_t GetSize() const
122 return this->read
- (this->bufe
- this->bufp
);
127 /** Container for dumping the savegame (quickly) to memory. */
128 struct MemoryDumper
{
129 std::vector
<std::unique_ptr
<uint8_t[]>> blocks
{}; ///< Buffer with blocks of allocated memory.
130 uint8_t *buf
= nullptr; ///< Buffer we're going to write to.
131 uint8_t *bufe
= nullptr; ///< End of the buffer we write to.
134 * Write a single byte into the dumper.
135 * @param b The byte to write.
137 inline void WriteByte(uint8_t b
)
139 /* Are we at the end of this chunk? */
140 if (this->buf
== this->bufe
) {
141 this->buf
= this->blocks
.emplace_back(std::make_unique
<uint8_t[]>(MEMORY_CHUNK_SIZE
)).get();
142 this->bufe
= this->buf
+ MEMORY_CHUNK_SIZE
;
149 * Flush this dumper into a writer.
150 * @param writer The filter we want to use.
152 void Flush(std::shared_ptr
<SaveFilter
> writer
)
155 size_t t
= this->GetSize();
158 size_t to_write
= std::min(MEMORY_CHUNK_SIZE
, t
);
160 writer
->Write(this->blocks
[i
++].get(), to_write
);
168 * Get the size of the memory dump made so far.
171 size_t GetSize() const
173 return this->blocks
.size() * MEMORY_CHUNK_SIZE
- (this->bufe
- this->buf
);
177 /** The saveload struct, containing reader-writer functions, buffer, version, etc. */
178 struct SaveLoadParams
{
179 SaveLoadAction action
; ///< are we doing a save or a load atm.
180 NeedLength need_length
; ///< working in NeedLength (Autolength) mode?
181 uint8_t block_mode
; ///< ???
182 bool error
; ///< did an error occur or not
184 size_t obj_len
; ///< the length of the current object we are busy with
185 int array_index
, last_array_index
; ///< in the case of an array, the current and last positions
186 bool expect_table_header
; ///< In the case of a table, if the header is saved/loaded.
188 std::unique_ptr
<MemoryDumper
> dumper
; ///< Memory dumper to write the savegame to.
189 std::shared_ptr
<SaveFilter
> sf
; ///< Filter to write the savegame to.
191 std::unique_ptr
<ReadBuffer
> reader
; ///< Savegame reading buffer.
192 std::shared_ptr
<LoadFilter
> lf
; ///< Filter to read the savegame from.
194 StringID error_str
; ///< the translatable error message to show
195 std::string extra_msg
; ///< the error message
197 bool saveinprogress
; ///< Whether there is currently a save in progress.
200 static SaveLoadParams _sl
; ///< Parameters used for/at saveload.
202 static const std::vector
<ChunkHandlerRef
> &ChunkHandlers()
204 /* These define the chunks */
205 extern const ChunkHandlerTable _gamelog_chunk_handlers
;
206 extern const ChunkHandlerTable _map_chunk_handlers
;
207 extern const ChunkHandlerTable _misc_chunk_handlers
;
208 extern const ChunkHandlerTable _name_chunk_handlers
;
209 extern const ChunkHandlerTable _cheat_chunk_handlers
;
210 extern const ChunkHandlerTable _setting_chunk_handlers
;
211 extern const ChunkHandlerTable _company_chunk_handlers
;
212 extern const ChunkHandlerTable _engine_chunk_handlers
;
213 extern const ChunkHandlerTable _veh_chunk_handlers
;
214 extern const ChunkHandlerTable _waypoint_chunk_handlers
;
215 extern const ChunkHandlerTable _depot_chunk_handlers
;
216 extern const ChunkHandlerTable _order_chunk_handlers
;
217 extern const ChunkHandlerTable _town_chunk_handlers
;
218 extern const ChunkHandlerTable _sign_chunk_handlers
;
219 extern const ChunkHandlerTable _station_chunk_handlers
;
220 extern const ChunkHandlerTable _industry_chunk_handlers
;
221 extern const ChunkHandlerTable _economy_chunk_handlers
;
222 extern const ChunkHandlerTable _subsidy_chunk_handlers
;
223 extern const ChunkHandlerTable _cargomonitor_chunk_handlers
;
224 extern const ChunkHandlerTable _goal_chunk_handlers
;
225 extern const ChunkHandlerTable _story_page_chunk_handlers
;
226 extern const ChunkHandlerTable _league_chunk_handlers
;
227 extern const ChunkHandlerTable _ai_chunk_handlers
;
228 extern const ChunkHandlerTable _game_chunk_handlers
;
229 extern const ChunkHandlerTable _animated_tile_chunk_handlers
;
230 extern const ChunkHandlerTable _newgrf_chunk_handlers
;
231 extern const ChunkHandlerTable _group_chunk_handlers
;
232 extern const ChunkHandlerTable _cargopacket_chunk_handlers
;
233 extern const ChunkHandlerTable _autoreplace_chunk_handlers
;
234 extern const ChunkHandlerTable _labelmaps_chunk_handlers
;
235 extern const ChunkHandlerTable _linkgraph_chunk_handlers
;
236 extern const ChunkHandlerTable _airport_chunk_handlers
;
237 extern const ChunkHandlerTable _object_chunk_handlers
;
238 extern const ChunkHandlerTable _persistent_storage_chunk_handlers
;
239 extern const ChunkHandlerTable _water_region_chunk_handlers
;
240 extern const ChunkHandlerTable _randomizer_chunk_handlers
;
242 /** List of all chunks in a savegame. */
243 static const ChunkHandlerTable _chunk_handler_tables
[] = {
244 _gamelog_chunk_handlers
,
246 _misc_chunk_handlers
,
247 _name_chunk_handlers
,
248 _cheat_chunk_handlers
,
249 _setting_chunk_handlers
,
251 _waypoint_chunk_handlers
,
252 _depot_chunk_handlers
,
253 _order_chunk_handlers
,
254 _industry_chunk_handlers
,
255 _economy_chunk_handlers
,
256 _subsidy_chunk_handlers
,
257 _cargomonitor_chunk_handlers
,
258 _goal_chunk_handlers
,
259 _story_page_chunk_handlers
,
260 _league_chunk_handlers
,
261 _engine_chunk_handlers
,
262 _town_chunk_handlers
,
263 _sign_chunk_handlers
,
264 _station_chunk_handlers
,
265 _company_chunk_handlers
,
267 _game_chunk_handlers
,
268 _animated_tile_chunk_handlers
,
269 _newgrf_chunk_handlers
,
270 _group_chunk_handlers
,
271 _cargopacket_chunk_handlers
,
272 _autoreplace_chunk_handlers
,
273 _labelmaps_chunk_handlers
,
274 _linkgraph_chunk_handlers
,
275 _airport_chunk_handlers
,
276 _object_chunk_handlers
,
277 _persistent_storage_chunk_handlers
,
278 _water_region_chunk_handlers
,
279 _randomizer_chunk_handlers
,
282 static std::vector
<ChunkHandlerRef
> _chunk_handlers
;
284 if (_chunk_handlers
.empty()) {
285 for (auto &chunk_handler_table
: _chunk_handler_tables
) {
286 for (auto &chunk_handler
: chunk_handler_table
) {
287 _chunk_handlers
.push_back(chunk_handler
);
292 return _chunk_handlers
;
295 /** Null all pointers (convert index -> nullptr) */
296 static void SlNullPointers()
298 _sl
.action
= SLA_NULL
;
300 /* We don't want any savegame conversion code to run
301 * during NULLing; especially those that try to get
302 * pointers from other pools. */
303 _sl_version
= SAVEGAME_VERSION
;
305 for (const ChunkHandler
&ch
: ChunkHandlers()) {
306 Debug(sl
, 3, "Nulling pointers for {}", ch
.GetName());
310 assert(_sl
.action
== SLA_NULL
);
314 * Error handler. Sets everything up to show an error message and to clean
315 * up the mess of a partial savegame load.
316 * @param string The translatable error message to show.
317 * @param extra_msg An extra error message coming from one of the APIs.
318 * @note This function does never return as it throws an exception to
319 * break out of all the saveload code.
321 [[noreturn
]] void SlError(StringID string
, const std::string
&extra_msg
)
323 /* Distinguish between loading into _load_check_data vs. normal save/load. */
324 if (_sl
.action
== SLA_LOAD_CHECK
) {
325 _load_check_data
.error
= string
;
326 _load_check_data
.error_msg
= extra_msg
;
328 _sl
.error_str
= string
;
329 _sl
.extra_msg
= extra_msg
;
332 /* We have to nullptr all pointers here; we might be in a state where
333 * the pointers are actually filled with indices, which means that
334 * when we access them during cleaning the pool dereferences of
335 * those indices will be made with segmentation faults as result. */
336 if (_sl
.action
== SLA_LOAD
|| _sl
.action
== SLA_PTRS
) SlNullPointers();
338 /* Logging could be active. */
339 _gamelog
.StopAnyAction();
341 throw std::exception();
345 * Error handler for corrupt savegames. Sets everything up to show the
346 * error message and to clean up the mess of a partial savegame load.
347 * @param msg Location the corruption has been spotted.
348 * @note This function does never return as it throws an exception to
349 * break out of all the saveload code.
351 [[noreturn
]] void SlErrorCorrupt(const std::string
&msg
)
353 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME
, msg
);
357 typedef void (*AsyncSaveFinishProc
)(); ///< Callback for when the savegame loading is finished.
358 static std::atomic
<AsyncSaveFinishProc
> _async_save_finish
; ///< Callback to call when the savegame loading is finished.
359 static std::thread _save_thread
; ///< The thread we're using to compress and write a savegame
362 * Called by save thread to tell we finished saving.
363 * @param proc The callback to call when saving is done.
365 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc
)
367 if (_exit_game
) return;
368 while (_async_save_finish
.load(std::memory_order_acquire
) != nullptr) CSleep(10);
370 _async_save_finish
.store(proc
, std::memory_order_release
);
374 * Handle async save finishes.
376 void ProcessAsyncSaveFinish()
378 AsyncSaveFinishProc proc
= _async_save_finish
.exchange(nullptr, std::memory_order_acq_rel
);
379 if (proc
== nullptr) return;
383 if (_save_thread
.joinable()) {
389 * Wrapper for reading a byte from the buffer.
390 * @return The read byte.
394 return _sl
.reader
->ReadByte();
398 * Wrapper for writing a byte to the dumper.
399 * @param b The byte to write.
401 void SlWriteByte(uint8_t b
)
403 _sl
.dumper
->WriteByte(b
);
406 static inline int SlReadUint16()
408 int x
= SlReadByte() << 8;
409 return x
| SlReadByte();
412 static inline uint32_t SlReadUint32()
414 uint32_t x
= SlReadUint16() << 16;
415 return x
| SlReadUint16();
418 static inline uint64_t SlReadUint64()
420 uint32_t x
= SlReadUint32();
421 uint32_t y
= SlReadUint32();
422 return (uint64_t)x
<< 32 | y
;
425 static inline void SlWriteUint16(uint16_t v
)
427 SlWriteByte(GB(v
, 8, 8));
428 SlWriteByte(GB(v
, 0, 8));
431 static inline void SlWriteUint32(uint32_t v
)
433 SlWriteUint16(GB(v
, 16, 16));
434 SlWriteUint16(GB(v
, 0, 16));
437 static inline void SlWriteUint64(uint64_t x
)
439 SlWriteUint32((uint32_t)(x
>> 32));
440 SlWriteUint32((uint32_t)x
);
444 * Read in the header descriptor of an object or an array.
445 * If the highest bit is set (7), then the index is bigger than 127
446 * elements, so use the next byte to read in the real value.
447 * The actual value is then both bytes added with the first shifted
448 * 8 bits to the left, and dropping the highest bit (which only indicated a big index).
449 * x = ((x & 0x7F) << 8) + SlReadByte();
450 * @return Return the value of the index
452 static uint
SlReadSimpleGamma()
454 uint i
= SlReadByte();
464 SlErrorCorrupt("Unsupported gamma");
466 i
= SlReadByte(); // 32 bits only.
468 i
= (i
<< 8) | SlReadByte();
470 i
= (i
<< 8) | SlReadByte();
472 i
= (i
<< 8) | SlReadByte();
478 * Write the header descriptor of an object or an array.
479 * If the element is bigger than 127, use 2 bytes for saving
480 * and use the highest byte of the first written one as a notice
481 * that the length consists of 2 bytes, etc.. like this:
484 * 110xxxxx xxxxxxxx xxxxxxxx
485 * 1110xxxx xxxxxxxx xxxxxxxx xxxxxxxx
486 * 11110--- xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
487 * We could extend the scheme ad infinum to support arbitrarily
488 * large chunks, but as sizeof(size_t) == 4 is still very common
489 * we don't support anything above 32 bits. That's why in the last
490 * case the 3 most significant bits are unused.
491 * @param i Index being written
494 static void SlWriteSimpleGamma(size_t i
)
497 if (i
>= (1 << 14)) {
498 if (i
>= (1 << 21)) {
499 if (i
>= (1 << 28)) {
500 assert(i
<= UINT32_MAX
); // We can only support 32 bits for now.
501 SlWriteByte((uint8_t)(0xF0));
502 SlWriteByte((uint8_t)(i
>> 24));
504 SlWriteByte((uint8_t)(0xE0 | (i
>> 24)));
506 SlWriteByte((uint8_t)(i
>> 16));
508 SlWriteByte((uint8_t)(0xC0 | (i
>> 16)));
510 SlWriteByte((uint8_t)(i
>> 8));
512 SlWriteByte((uint8_t)(0x80 | (i
>> 8)));
515 SlWriteByte((uint8_t)i
);
518 /** Return how many bytes used to encode a gamma value */
519 static inline uint
SlGetGammaLength(size_t i
)
521 return 1 + (i
>= (1 << 7)) + (i
>= (1 << 14)) + (i
>= (1 << 21)) + (i
>= (1 << 28));
524 static inline uint
SlReadSparseIndex()
526 return SlReadSimpleGamma();
529 static inline void SlWriteSparseIndex(uint index
)
531 SlWriteSimpleGamma(index
);
534 static inline uint
SlReadArrayLength()
536 return SlReadSimpleGamma();
539 static inline void SlWriteArrayLength(size_t length
)
541 SlWriteSimpleGamma(length
);
544 static inline uint
SlGetArrayLength(size_t length
)
546 return SlGetGammaLength(length
);
550 * Return the type as saved/loaded inside the savegame.
552 static uint8_t GetSavegameFileType(const SaveLoad
&sld
)
556 return GetVarFileType(sld
.conv
); break;
562 return GetVarFileType(sld
.conv
) | SLE_FILE_HAS_LENGTH_FIELD
; break;
565 return IsSavegameVersionBefore(SLV_69
) ? SLE_FILE_U16
: SLE_FILE_U32
;
568 return (IsSavegameVersionBefore(SLV_69
) ? SLE_FILE_U16
: SLE_FILE_U32
) | SLE_FILE_HAS_LENGTH_FIELD
;
575 return SLE_FILE_STRUCT
| SLE_FILE_HAS_LENGTH_FIELD
;
577 default: NOT_REACHED();
582 * Return the size in bytes of a certain type of normal/atomic variable
583 * as it appears in memory. See VarTypes
584 * @param conv VarType type of variable that is used for calculating the size
585 * @return Return the size of this type in bytes
587 static inline uint
SlCalcConvMemLen(VarType conv
)
589 switch (GetVarMemType(conv
)) {
590 case SLE_VAR_BL
: return sizeof(bool);
591 case SLE_VAR_I8
: return sizeof(int8_t);
592 case SLE_VAR_U8
: return sizeof(uint8_t);
593 case SLE_VAR_I16
: return sizeof(int16_t);
594 case SLE_VAR_U16
: return sizeof(uint16_t);
595 case SLE_VAR_I32
: return sizeof(int32_t);
596 case SLE_VAR_U32
: return sizeof(uint32_t);
597 case SLE_VAR_I64
: return sizeof(int64_t);
598 case SLE_VAR_U64
: return sizeof(uint64_t);
599 case SLE_VAR_NULL
: return 0;
603 return SlReadArrayLength();
612 * Return the size in bytes of a certain type of normal/atomic variable
613 * as it appears in a saved game. See VarTypes
614 * @param conv VarType type of variable that is used for calculating the size
615 * @return Return the size of this type in bytes
617 static inline uint8_t SlCalcConvFileLen(VarType conv
)
619 switch (GetVarFileType(conv
)) {
620 case SLE_FILE_END
: return 0;
621 case SLE_FILE_I8
: return sizeof(int8_t);
622 case SLE_FILE_U8
: return sizeof(uint8_t);
623 case SLE_FILE_I16
: return sizeof(int16_t);
624 case SLE_FILE_U16
: return sizeof(uint16_t);
625 case SLE_FILE_I32
: return sizeof(int32_t);
626 case SLE_FILE_U32
: return sizeof(uint32_t);
627 case SLE_FILE_I64
: return sizeof(int64_t);
628 case SLE_FILE_U64
: return sizeof(uint64_t);
629 case SLE_FILE_STRINGID
: return sizeof(uint16_t);
631 case SLE_FILE_STRING
:
632 return SlReadArrayLength();
634 case SLE_FILE_STRUCT
:
640 /** Return the size in bytes of a reference (pointer) */
641 static inline size_t SlCalcRefLen()
643 return IsSavegameVersionBefore(SLV_69
) ? 2 : 4;
646 void SlSetArrayIndex(uint index
)
648 _sl
.need_length
= NL_WANTLENGTH
;
649 _sl
.array_index
= index
;
652 static size_t _next_offs
;
655 * Iterate through the elements of an array and read the whole thing
656 * @return The index of the object, or -1 if we have reached the end of current block
660 /* After reading in the whole array inside the loop
661 * we must have read in all the data, so we must be at end of current block. */
662 if (_next_offs
!= 0 && _sl
.reader
->GetSize() != _next_offs
) {
663 SlErrorCorruptFmt("Invalid chunk size iterating array - expected to be at position {}, actually at {}", _next_offs
, _sl
.reader
->GetSize());
667 uint length
= SlReadArrayLength();
669 assert(!_sl
.expect_table_header
);
674 _sl
.obj_len
= --length
;
675 _next_offs
= _sl
.reader
->GetSize() + length
;
677 if (_sl
.expect_table_header
) {
678 _sl
.expect_table_header
= false;
683 switch (_sl
.block_mode
) {
684 case CH_SPARSE_TABLE
:
685 case CH_SPARSE_ARRAY
: index
= (int)SlReadSparseIndex(); break;
687 case CH_ARRAY
: index
= _sl
.array_index
++; break;
689 Debug(sl
, 0, "SlIterateArray error");
693 if (length
!= 0) return index
;
698 * Skip an array or sparse array
702 while (SlIterateArray() != -1) {
703 SlSkipBytes(_next_offs
- _sl
.reader
->GetSize());
708 * Sets the length of either a RIFF object or the number of items in an array.
709 * This lets us load an object or an array of arbitrary size
710 * @param length The length of the sought object/array
712 void SlSetLength(size_t length
)
714 assert(_sl
.action
== SLA_SAVE
);
716 switch (_sl
.need_length
) {
718 _sl
.need_length
= NL_NONE
;
719 if ((_sl
.block_mode
== CH_TABLE
|| _sl
.block_mode
== CH_SPARSE_TABLE
) && _sl
.expect_table_header
) {
720 _sl
.expect_table_header
= false;
721 SlWriteArrayLength(length
+ 1);
725 switch (_sl
.block_mode
) {
727 /* Ugly encoding of >16M RIFF chunks
728 * The lower 24 bits are normal
729 * The uppermost 4 bits are bits 24:27 */
730 assert(length
< (1 << 28));
731 SlWriteUint32((uint32_t)((length
& 0xFFFFFF) | ((length
>> 24) << 28)));
735 assert(_sl
.last_array_index
<= _sl
.array_index
);
736 while (++_sl
.last_array_index
<= _sl
.array_index
) {
737 SlWriteArrayLength(1);
739 SlWriteArrayLength(length
+ 1);
741 case CH_SPARSE_TABLE
:
742 case CH_SPARSE_ARRAY
:
743 SlWriteArrayLength(length
+ 1 + SlGetArrayLength(_sl
.array_index
)); // Also include length of sparse index.
744 SlWriteSparseIndex(_sl
.array_index
);
746 default: NOT_REACHED();
751 _sl
.obj_len
+= (int)length
;
754 default: NOT_REACHED();
759 * Save/Load bytes. These do not need to be converted to Little/Big Endian
760 * so directly write them or read them to/from file
761 * @param ptr The source or destination of the object being manipulated
762 * @param length number of bytes this fast CopyBytes lasts
764 static void SlCopyBytes(void *ptr
, size_t length
)
766 uint8_t *p
= (uint8_t *)ptr
;
768 switch (_sl
.action
) {
771 for (; length
!= 0; length
--) *p
++ = SlReadByte();
774 for (; length
!= 0; length
--) SlWriteByte(*p
++);
776 default: NOT_REACHED();
780 /** Get the length of the current object */
781 size_t SlGetFieldLength()
787 * Return a signed-long version of the value of a setting
788 * @param ptr pointer to the variable
789 * @param conv type of variable, can be a non-clean
790 * type, eg one with other flags because it is parsed
791 * @return returns the value of the pointer-setting
793 int64_t ReadValue(const void *ptr
, VarType conv
)
795 switch (GetVarMemType(conv
)) {
796 case SLE_VAR_BL
: return (*(const bool *)ptr
!= 0);
797 case SLE_VAR_I8
: return *(const int8_t *)ptr
;
798 case SLE_VAR_U8
: return *(const uint8_t *)ptr
;
799 case SLE_VAR_I16
: return *(const int16_t *)ptr
;
800 case SLE_VAR_U16
: return *(const uint16_t*)ptr
;
801 case SLE_VAR_I32
: return *(const int32_t *)ptr
;
802 case SLE_VAR_U32
: return *(const uint32_t*)ptr
;
803 case SLE_VAR_I64
: return *(const int64_t *)ptr
;
804 case SLE_VAR_U64
: return *(const uint64_t*)ptr
;
805 case SLE_VAR_NULL
:return 0;
806 default: NOT_REACHED();
811 * Write the value of a setting
812 * @param ptr pointer to the variable
813 * @param conv type of variable, can be a non-clean type, eg
814 * with other flags. It is parsed upon read
815 * @param val the new value being given to the variable
817 void WriteValue(void *ptr
, VarType conv
, int64_t val
)
819 switch (GetVarMemType(conv
)) {
820 case SLE_VAR_BL
: *(bool *)ptr
= (val
!= 0); break;
821 case SLE_VAR_I8
: *(int8_t *)ptr
= val
; break;
822 case SLE_VAR_U8
: *(uint8_t *)ptr
= val
; break;
823 case SLE_VAR_I16
: *(int16_t *)ptr
= val
; break;
824 case SLE_VAR_U16
: *(uint16_t*)ptr
= val
; break;
825 case SLE_VAR_I32
: *(int32_t *)ptr
= val
; break;
826 case SLE_VAR_U32
: *(uint32_t*)ptr
= val
; break;
827 case SLE_VAR_I64
: *(int64_t *)ptr
= val
; break;
828 case SLE_VAR_U64
: *(uint64_t*)ptr
= val
; break;
829 case SLE_VAR_NAME
: *reinterpret_cast<std::string
*>(ptr
) = CopyFromOldName(val
); break;
830 case SLE_VAR_NULL
: break;
831 default: NOT_REACHED();
836 * Handle all conversion and typechecking of variables here.
837 * In the case of saving, read in the actual value from the struct
838 * and then write them to file, endian safely. Loading a value
839 * goes exactly the opposite way
840 * @param ptr The object being filled/read
841 * @param conv VarType type of the current element of the struct
843 static void SlSaveLoadConv(void *ptr
, VarType conv
)
845 switch (_sl
.action
) {
847 int64_t x
= ReadValue(ptr
, conv
);
849 /* Write the value to the file and check if its value is in the desired range */
850 switch (GetVarFileType(conv
)) {
851 case SLE_FILE_I8
: assert(x
>= -128 && x
<= 127); SlWriteByte(x
);break;
852 case SLE_FILE_U8
: assert(x
>= 0 && x
<= 255); SlWriteByte(x
);break;
853 case SLE_FILE_I16
:assert(x
>= -32768 && x
<= 32767); SlWriteUint16(x
);break;
854 case SLE_FILE_STRINGID
:
855 case SLE_FILE_U16
:assert(x
>= 0 && x
<= 65535); SlWriteUint16(x
);break;
857 case SLE_FILE_U32
: SlWriteUint32((uint32_t)x
);break;
859 case SLE_FILE_U64
: SlWriteUint64(x
);break;
860 default: NOT_REACHED();
867 /* Read a value from the file */
868 switch (GetVarFileType(conv
)) {
869 case SLE_FILE_I8
: x
= (int8_t )SlReadByte(); break;
870 case SLE_FILE_U8
: x
= (uint8_t )SlReadByte(); break;
871 case SLE_FILE_I16
: x
= (int16_t )SlReadUint16(); break;
872 case SLE_FILE_U16
: x
= (uint16_t)SlReadUint16(); break;
873 case SLE_FILE_I32
: x
= (int32_t )SlReadUint32(); break;
874 case SLE_FILE_U32
: x
= (uint32_t)SlReadUint32(); break;
875 case SLE_FILE_I64
: x
= (int64_t )SlReadUint64(); break;
876 case SLE_FILE_U64
: x
= (uint64_t)SlReadUint64(); break;
877 case SLE_FILE_STRINGID
: x
= RemapOldStringID((uint16_t)SlReadUint16()); break;
878 default: NOT_REACHED();
881 /* Write The value to the struct. These ARE endian safe. */
882 WriteValue(ptr
, conv
, x
);
885 case SLA_PTRS
: break;
886 case SLA_NULL
: break;
887 default: NOT_REACHED();
892 * Calculate the gross length of the string that it
893 * will occupy in the savegame. This includes the real length, returned
894 * by SlCalcNetStringLen and the length that the index will occupy.
895 * @param ptr Pointer to the \c std::string.
896 * @return The gross length of the string.
898 static inline size_t SlCalcStdStringLen(const void *ptr
)
900 const std::string
*str
= reinterpret_cast<const std::string
*>(ptr
);
902 size_t len
= str
->length();
903 return len
+ SlGetArrayLength(len
); // also include the length of the index
908 * Scan the string for old values of SCC_ENCODED and fix it to it's new, value.
909 * Note that at the moment this runs, the string has not been validated yet
910 * because the validation looks for SCC_ENCODED. If there is something invalid,
911 * just bail out and do not continue trying to replace the tokens.
912 * @param str the string to fix.
914 static void FixSCCEncoded(std::string
&str
)
916 for (size_t i
= 0; i
< str
.size(); /* nothing. */) {
917 size_t len
= Utf8EncodedCharLen(str
[i
]);
918 if (len
== 0 || i
+ len
> str
.size()) break;
921 Utf8Decode(&c
, &str
[i
]);
922 if (c
== 0xE028 || c
== 0xE02A) Utf8Encode(&str
[i
], SCC_ENCODED
);
928 * Save/Load a \c std::string.
929 * @param ptr the string being manipulated
930 * @param conv must be SLE_FILE_STRING
932 static void SlStdString(void *ptr
, VarType conv
)
934 std::string
*str
= reinterpret_cast<std::string
*>(ptr
);
936 switch (_sl
.action
) {
938 size_t len
= str
->length();
939 SlWriteArrayLength(len
);
940 SlCopyBytes(const_cast<void *>(static_cast<const void *>(str
->c_str())), len
);
946 size_t len
= SlReadArrayLength();
947 if (GetVarMemType(conv
) == SLE_VAR_NULL
) {
953 SlCopyBytes(str
->data(), len
);
955 StringValidationSettings settings
= SVS_REPLACE_WITH_QUESTION_MARK
;
956 if ((conv
& SLF_ALLOW_CONTROL
) != 0) {
957 settings
= settings
| SVS_ALLOW_CONTROL_CODE
;
958 if (IsSavegameVersionBefore(SLV_169
)) FixSCCEncoded(*str
);
960 if ((conv
& SLF_ALLOW_NEWLINE
) != 0) {
961 settings
= settings
| SVS_ALLOW_NEWLINE
;
963 *str
= StrMakeValid(*str
, settings
);
966 case SLA_PTRS
: break;
967 case SLA_NULL
: break;
968 default: NOT_REACHED();
973 * Internal function to save/Load a list of SL_VARs.
974 * SlCopy() and SlArray() are very similar, with the exception of the header.
975 * This function represents the common part.
976 * @param object The object being manipulated.
977 * @param length The length of the object in elements
978 * @param conv VarType type of the items.
980 static void SlCopyInternal(void *object
, size_t length
, VarType conv
)
982 if (GetVarMemType(conv
) == SLE_VAR_NULL
) {
983 assert(_sl
.action
!= SLA_SAVE
); // Use SL_NULL if you want to write null-bytes
984 SlSkipBytes(length
* SlCalcConvFileLen(conv
));
988 /* NOTICE - handle some buggy stuff, in really old versions everything was saved
989 * as a byte-type. So detect this, and adjust object size accordingly */
990 if (_sl
.action
!= SLA_SAVE
&& _sl_version
== 0) {
991 /* all objects except difficulty settings */
992 if (conv
== SLE_INT16
|| conv
== SLE_UINT16
|| conv
== SLE_STRINGID
||
993 conv
== SLE_INT32
|| conv
== SLE_UINT32
) {
994 SlCopyBytes(object
, length
* SlCalcConvFileLen(conv
));
997 /* used for conversion of Money 32bit->64bit */
998 if (conv
== (SLE_FILE_I32
| SLE_VAR_I64
)) {
999 for (uint i
= 0; i
< length
; i
++) {
1000 ((int64_t*)object
)[i
] = (int32_t)BSWAP32(SlReadUint32());
1006 /* If the size of elements is 1 byte both in file and memory, no special
1007 * conversion is needed, use specialized copy-copy function to speed up things */
1008 if (conv
== SLE_INT8
|| conv
== SLE_UINT8
) {
1009 SlCopyBytes(object
, length
);
1011 uint8_t *a
= (uint8_t*)object
;
1012 uint8_t mem_size
= SlCalcConvMemLen(conv
);
1014 for (; length
!= 0; length
--) {
1015 SlSaveLoadConv(a
, conv
);
1016 a
+= mem_size
; // get size
1022 * Copy a list of SL_VARs to/from a savegame.
1023 * These entries are copied as-is, and you as caller have to make sure things
1024 * like length-fields are calculated correctly.
1025 * @param object The object being manipulated.
1026 * @param length The length of the object in elements
1027 * @param conv VarType type of the items.
1029 void SlCopy(void *object
, size_t length
, VarType conv
)
1031 if (_sl
.action
== SLA_PTRS
|| _sl
.action
== SLA_NULL
) return;
1033 /* Automatically calculate the length? */
1034 if (_sl
.need_length
!= NL_NONE
) {
1035 SlSetLength(length
* SlCalcConvFileLen(conv
));
1036 /* Determine length only? */
1037 if (_sl
.need_length
== NL_CALCLENGTH
) return;
1040 SlCopyInternal(object
, length
, conv
);
1044 * Return the size in bytes of a certain type of atomic array
1045 * @param length The length of the array counted in elements
1046 * @param conv VarType type of the variable that is used in calculating the size
1048 static inline size_t SlCalcArrayLen(size_t length
, VarType conv
)
1050 return SlCalcConvFileLen(conv
) * length
+ SlGetArrayLength(length
);
1054 * Save/Load the length of the array followed by the array of SL_VAR elements.
1055 * @param array The array being manipulated
1056 * @param length The length of the array in elements
1057 * @param conv VarType type of the atomic array (int, uint8_t, uint64_t, etc.)
1059 static void SlArray(void *array
, size_t length
, VarType conv
)
1061 switch (_sl
.action
) {
1063 SlWriteArrayLength(length
);
1064 SlCopyInternal(array
, length
, conv
);
1067 case SLA_LOAD_CHECK
:
1069 if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH
)) {
1070 size_t sv_length
= SlReadArrayLength();
1071 if (GetVarMemType(conv
) == SLE_VAR_NULL
) {
1072 /* We don't know this field, so we assume the length in the savegame is correct. */
1074 } else if (sv_length
!= length
) {
1075 /* If the SLE_ARR changes size, a savegame bump is required
1076 * and the developer should have written conversion lines.
1077 * Error out to make this more visible. */
1078 SlErrorCorrupt("Fixed-length array is of wrong length");
1082 SlCopyInternal(array
, length
, conv
);
1096 * Pointers cannot be saved to a savegame, so this functions gets
1097 * the index of the item, and if not available, it hussles with
1098 * pointers (looks really bad :()
1099 * Remember that a nullptr item has value 0, and all
1100 * indices have +1, so vehicle 0 is saved as index 1.
1101 * @param obj The object that we want to get the index of
1102 * @param rt SLRefType type of the object the index is being sought of
1103 * @return Return the pointer converted to an index of the type pointed to
1105 static size_t ReferenceToInt(const void *obj
, SLRefType rt
)
1107 assert(_sl
.action
== SLA_SAVE
);
1109 if (obj
== nullptr) return 0;
1112 case REF_VEHICLE_OLD
: // Old vehicles we save as new ones
1113 case REF_VEHICLE
: return ((const Vehicle
*)obj
)->index
+ 1;
1114 case REF_STATION
: return ((const Station
*)obj
)->index
+ 1;
1115 case REF_TOWN
: return ((const Town
*)obj
)->index
+ 1;
1116 case REF_ORDER
: return ((const Order
*)obj
)->index
+ 1;
1117 case REF_ROADSTOPS
: return ((const RoadStop
*)obj
)->index
+ 1;
1118 case REF_ENGINE_RENEWS
: return ((const EngineRenew
*)obj
)->index
+ 1;
1119 case REF_CARGO_PACKET
: return ((const CargoPacket
*)obj
)->index
+ 1;
1120 case REF_ORDERLIST
: return ((const OrderList
*)obj
)->index
+ 1;
1121 case REF_STORAGE
: return ((const PersistentStorage
*)obj
)->index
+ 1;
1122 case REF_LINK_GRAPH
: return ((const LinkGraph
*)obj
)->index
+ 1;
1123 case REF_LINK_GRAPH_JOB
: return ((const LinkGraphJob
*)obj
)->index
+ 1;
1124 default: NOT_REACHED();
1129 * Pointers cannot be loaded from a savegame, so this function
1130 * gets the index from the savegame and returns the appropriate
1131 * pointer from the already loaded base.
1132 * Remember that an index of 0 is a nullptr pointer so all indices
1133 * are +1 so vehicle 0 is saved as 1.
1134 * @param index The index that is being converted to a pointer
1135 * @param rt SLRefType type of the object the pointer is sought of
1136 * @return Return the index converted to a pointer of any type
1138 static void *IntToReference(size_t index
, SLRefType rt
)
1140 static_assert(sizeof(size_t) <= sizeof(void *));
1142 assert(_sl
.action
== SLA_PTRS
);
1144 /* After version 4.3 REF_VEHICLE_OLD is saved as REF_VEHICLE,
1145 * and should be loaded like that */
1146 if (rt
== REF_VEHICLE_OLD
&& !IsSavegameVersionBefore(SLV_4
, 4)) {
1150 /* No need to look up nullptr pointers, just return immediately */
1151 if (index
== (rt
== REF_VEHICLE_OLD
? 0xFFFF : 0)) return nullptr;
1153 /* Correct index. Old vehicles were saved differently:
1154 * invalid vehicle was 0xFFFF, now we use 0x0000 for everything invalid. */
1155 if (rt
!= REF_VEHICLE_OLD
) index
--;
1159 if (OrderList::IsValidID(index
)) return OrderList::Get(index
);
1160 SlErrorCorrupt("Referencing invalid OrderList");
1163 if (Order::IsValidID(index
)) return Order::Get(index
);
1164 /* in old versions, invalid order was used to mark end of order list */
1165 if (IsSavegameVersionBefore(SLV_5
, 2)) return nullptr;
1166 SlErrorCorrupt("Referencing invalid Order");
1168 case REF_VEHICLE_OLD
:
1170 if (Vehicle::IsValidID(index
)) return Vehicle::Get(index
);
1171 SlErrorCorrupt("Referencing invalid Vehicle");
1174 if (Station::IsValidID(index
)) return Station::Get(index
);
1175 SlErrorCorrupt("Referencing invalid Station");
1178 if (Town::IsValidID(index
)) return Town::Get(index
);
1179 SlErrorCorrupt("Referencing invalid Town");
1182 if (RoadStop::IsValidID(index
)) return RoadStop::Get(index
);
1183 SlErrorCorrupt("Referencing invalid RoadStop");
1185 case REF_ENGINE_RENEWS
:
1186 if (EngineRenew::IsValidID(index
)) return EngineRenew::Get(index
);
1187 SlErrorCorrupt("Referencing invalid EngineRenew");
1189 case REF_CARGO_PACKET
:
1190 if (CargoPacket::IsValidID(index
)) return CargoPacket::Get(index
);
1191 SlErrorCorrupt("Referencing invalid CargoPacket");
1194 if (PersistentStorage::IsValidID(index
)) return PersistentStorage::Get(index
);
1195 SlErrorCorrupt("Referencing invalid PersistentStorage");
1197 case REF_LINK_GRAPH
:
1198 if (LinkGraph::IsValidID(index
)) return LinkGraph::Get(index
);
1199 SlErrorCorrupt("Referencing invalid LinkGraph");
1201 case REF_LINK_GRAPH_JOB
:
1202 if (LinkGraphJob::IsValidID(index
)) return LinkGraphJob::Get(index
);
1203 SlErrorCorrupt("Referencing invalid LinkGraphJob");
1205 default: NOT_REACHED();
1210 * Handle conversion for references.
1211 * @param ptr The object being filled/read.
1212 * @param conv VarType type of the current element of the struct.
1214 void SlSaveLoadRef(void *ptr
, VarType conv
)
1216 switch (_sl
.action
) {
1218 SlWriteUint32((uint32_t)ReferenceToInt(*(void **)ptr
, (SLRefType
)conv
));
1220 case SLA_LOAD_CHECK
:
1222 *(size_t *)ptr
= IsSavegameVersionBefore(SLV_69
) ? SlReadUint16() : SlReadUint32();
1225 *(void **)ptr
= IntToReference(*(size_t *)ptr
, (SLRefType
)conv
);
1228 *(void **)ptr
= nullptr;
1230 default: NOT_REACHED();
1235 * Template class to help with list-like types.
1237 template <template<typename
, typename
> typename Tstorage
, typename Tvar
, typename Tallocator
= std::allocator
<Tvar
>>
1238 class SlStorageHelper
{
1239 typedef Tstorage
<Tvar
, Tallocator
> SlStorageT
;
1242 * Internal templated helper to return the size in bytes of a list-like type.
1243 * @param storage The storage to find the size of
1244 * @param conv VarType type of variable that is used for calculating the size
1245 * @param cmd The SaveLoadType ware are saving/loading.
1247 static size_t SlCalcLen(const void *storage
, VarType conv
, SaveLoadType cmd
= SL_VAR
)
1249 assert(cmd
== SL_VAR
|| cmd
== SL_REF
);
1251 const SlStorageT
*list
= static_cast<const SlStorageT
*>(storage
);
1253 int type_size
= SlGetArrayLength(list
->size());
1254 int item_size
= SlCalcConvFileLen(cmd
== SL_VAR
? conv
: (VarType
)SLE_FILE_U32
);
1255 return list
->size() * item_size
+ type_size
;
1258 static void SlSaveLoadMember(SaveLoadType cmd
, Tvar
*item
, VarType conv
)
1261 case SL_VAR
: SlSaveLoadConv(item
, conv
); break;
1262 case SL_REF
: SlSaveLoadRef(item
, conv
); break;
1263 case SL_STDSTR
: SlStdString(item
, conv
); break;
1270 * Internal templated helper to save/load a list-like type.
1271 * @param storage The storage being manipulated.
1272 * @param conv VarType type of variable that is used for calculating the size.
1273 * @param cmd The SaveLoadType ware are saving/loading.
1275 static void SlSaveLoad(void *storage
, VarType conv
, SaveLoadType cmd
= SL_VAR
)
1277 assert(cmd
== SL_VAR
|| cmd
== SL_REF
|| cmd
== SL_STDSTR
);
1279 SlStorageT
*list
= static_cast<SlStorageT
*>(storage
);
1281 switch (_sl
.action
) {
1283 SlWriteArrayLength(list
->size());
1285 for (auto &item
: *list
) {
1286 SlSaveLoadMember(cmd
, &item
, conv
);
1290 case SLA_LOAD_CHECK
:
1294 case SL_VAR
: length
= IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH
) ? SlReadUint32() : SlReadArrayLength(); break;
1295 case SL_REF
: length
= IsSavegameVersionBefore(SLV_69
) ? SlReadUint16() : IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH
) ? SlReadUint32() : SlReadArrayLength(); break;
1296 case SL_STDSTR
: length
= SlReadArrayLength(); break;
1297 default: NOT_REACHED();
1300 /* Load each value and push to the end of the storage. */
1301 for (size_t i
= 0; i
< length
; i
++) {
1302 Tvar
&data
= list
->emplace_back();
1303 SlSaveLoadMember(cmd
, &data
, conv
);
1309 for (auto &item
: *list
) {
1310 SlSaveLoadMember(cmd
, &item
, conv
);
1318 default: NOT_REACHED();
1324 * Return the size in bytes of a list.
1325 * @param list The std::list to find the size of.
1326 * @param conv VarType type of variable that is used for calculating the size.
1328 static inline size_t SlCalcRefListLen(const void *list
, VarType conv
)
1330 return SlStorageHelper
<std::list
, void *>::SlCalcLen(list
, conv
, SL_REF
);
1335 * @param list The list being manipulated.
1336 * @param conv VarType type of variable that is used for calculating the size.
1338 static void SlRefList(void *list
, VarType conv
)
1340 /* Automatically calculate the length? */
1341 if (_sl
.need_length
!= NL_NONE
) {
1342 SlSetLength(SlCalcRefListLen(list
, conv
));
1343 /* Determine length only? */
1344 if (_sl
.need_length
== NL_CALCLENGTH
) return;
1347 SlStorageHelper
<std::list
, void *>::SlSaveLoad(list
, conv
, SL_REF
);
1351 * Return the size in bytes of a std::deque.
1352 * @param deque The std::deque to find the size of
1353 * @param conv VarType type of variable that is used for calculating the size
1355 static inline size_t SlCalcDequeLen(const void *deque
, VarType conv
)
1357 switch (GetVarMemType(conv
)) {
1358 case SLE_VAR_BL
: return SlStorageHelper
<std::deque
, bool>::SlCalcLen(deque
, conv
);
1359 case SLE_VAR_I8
: return SlStorageHelper
<std::deque
, int8_t>::SlCalcLen(deque
, conv
);
1360 case SLE_VAR_U8
: return SlStorageHelper
<std::deque
, uint8_t>::SlCalcLen(deque
, conv
);
1361 case SLE_VAR_I16
: return SlStorageHelper
<std::deque
, int16_t>::SlCalcLen(deque
, conv
);
1362 case SLE_VAR_U16
: return SlStorageHelper
<std::deque
, uint16_t>::SlCalcLen(deque
, conv
);
1363 case SLE_VAR_I32
: return SlStorageHelper
<std::deque
, int32_t>::SlCalcLen(deque
, conv
);
1364 case SLE_VAR_U32
: return SlStorageHelper
<std::deque
, uint32_t>::SlCalcLen(deque
, conv
);
1365 case SLE_VAR_I64
: return SlStorageHelper
<std::deque
, int64_t>::SlCalcLen(deque
, conv
);
1366 case SLE_VAR_U64
: return SlStorageHelper
<std::deque
, uint64_t>::SlCalcLen(deque
, conv
);
1369 /* Strings are a length-prefixed field type in the savegame table format,
1370 * these may not be directly stored in another length-prefixed container type. */
1373 default: NOT_REACHED();
1378 * Save/load a std::deque.
1379 * @param deque The std::deque being manipulated
1380 * @param conv VarType type of variable that is used for calculating the size
1382 static void SlDeque(void *deque
, VarType conv
)
1384 switch (GetVarMemType(conv
)) {
1385 case SLE_VAR_BL
: SlStorageHelper
<std::deque
, bool>::SlSaveLoad(deque
, conv
); break;
1386 case SLE_VAR_I8
: SlStorageHelper
<std::deque
, int8_t>::SlSaveLoad(deque
, conv
); break;
1387 case SLE_VAR_U8
: SlStorageHelper
<std::deque
, uint8_t>::SlSaveLoad(deque
, conv
); break;
1388 case SLE_VAR_I16
: SlStorageHelper
<std::deque
, int16_t>::SlSaveLoad(deque
, conv
); break;
1389 case SLE_VAR_U16
: SlStorageHelper
<std::deque
, uint16_t>::SlSaveLoad(deque
, conv
); break;
1390 case SLE_VAR_I32
: SlStorageHelper
<std::deque
, int32_t>::SlSaveLoad(deque
, conv
); break;
1391 case SLE_VAR_U32
: SlStorageHelper
<std::deque
, uint32_t>::SlSaveLoad(deque
, conv
); break;
1392 case SLE_VAR_I64
: SlStorageHelper
<std::deque
, int64_t>::SlSaveLoad(deque
, conv
); break;
1393 case SLE_VAR_U64
: SlStorageHelper
<std::deque
, uint64_t>::SlSaveLoad(deque
, conv
); break;
1396 /* Strings are a length-prefixed field type in the savegame table format,
1397 * these may not be directly stored in another length-prefixed container type.
1398 * This is permitted for load-related actions, because invalid fields of this type are present
1399 * from SLV_COMPANY_ALLOW_LIST up to SLV_COMPANY_ALLOW_LIST_V2. */
1400 assert(_sl
.action
!= SLA_SAVE
);
1401 SlStorageHelper
<std::deque
, std::string
>::SlSaveLoad(deque
, conv
, SL_STDSTR
);
1404 default: NOT_REACHED();
1409 * Return the size in bytes of a std::vector.
1410 * @param vector The std::vector to find the size of
1411 * @param conv VarType type of variable that is used for calculating the size
1413 static inline size_t SlCalcVectorLen(const void *vector
, VarType conv
)
1415 switch (GetVarMemType(conv
)) {
1416 case SLE_VAR_BL
: NOT_REACHED(); // Not supported
1417 case SLE_VAR_I8
: return SlStorageHelper
<std::vector
, int8_t>::SlCalcLen(vector
, conv
);
1418 case SLE_VAR_U8
: return SlStorageHelper
<std::vector
, uint8_t>::SlCalcLen(vector
, conv
);
1419 case SLE_VAR_I16
: return SlStorageHelper
<std::vector
, int16_t>::SlCalcLen(vector
, conv
);
1420 case SLE_VAR_U16
: return SlStorageHelper
<std::vector
, uint16_t>::SlCalcLen(vector
, conv
);
1421 case SLE_VAR_I32
: return SlStorageHelper
<std::vector
, int32_t>::SlCalcLen(vector
, conv
);
1422 case SLE_VAR_U32
: return SlStorageHelper
<std::vector
, uint32_t>::SlCalcLen(vector
, conv
);
1423 case SLE_VAR_I64
: return SlStorageHelper
<std::vector
, int64_t>::SlCalcLen(vector
, conv
);
1424 case SLE_VAR_U64
: return SlStorageHelper
<std::vector
, uint64_t>::SlCalcLen(vector
, conv
);
1427 /* Strings are a length-prefixed field type in the savegame table format,
1428 * these may not be directly stored in another length-prefixed container type. */
1431 default: NOT_REACHED();
1436 * Save/load a std::vector.
1437 * @param vector The std::vector being manipulated
1438 * @param conv VarType type of variable that is used for calculating the size
1440 static void SlVector(void *vector
, VarType conv
)
1442 switch (GetVarMemType(conv
)) {
1443 case SLE_VAR_BL
: NOT_REACHED(); // Not supported
1444 case SLE_VAR_I8
: SlStorageHelper
<std::vector
, int8_t>::SlSaveLoad(vector
, conv
); break;
1445 case SLE_VAR_U8
: SlStorageHelper
<std::vector
, uint8_t>::SlSaveLoad(vector
, conv
); break;
1446 case SLE_VAR_I16
: SlStorageHelper
<std::vector
, int16_t>::SlSaveLoad(vector
, conv
); break;
1447 case SLE_VAR_U16
: SlStorageHelper
<std::vector
, uint16_t>::SlSaveLoad(vector
, conv
); break;
1448 case SLE_VAR_I32
: SlStorageHelper
<std::vector
, int32_t>::SlSaveLoad(vector
, conv
); break;
1449 case SLE_VAR_U32
: SlStorageHelper
<std::vector
, uint32_t>::SlSaveLoad(vector
, conv
); break;
1450 case SLE_VAR_I64
: SlStorageHelper
<std::vector
, int64_t>::SlSaveLoad(vector
, conv
); break;
1451 case SLE_VAR_U64
: SlStorageHelper
<std::vector
, uint64_t>::SlSaveLoad(vector
, conv
); break;
1454 /* Strings are a length-prefixed field type in the savegame table format,
1455 * these may not be directly stored in another length-prefixed container type.
1456 * This is permitted for load-related actions, because invalid fields of this type are present
1457 * from SLV_COMPANY_ALLOW_LIST up to SLV_COMPANY_ALLOW_LIST_V2. */
1458 assert(_sl
.action
!= SLA_SAVE
);
1459 SlStorageHelper
<std::vector
, std::string
>::SlSaveLoad(vector
, conv
, SL_STDSTR
);
1462 default: NOT_REACHED();
1466 /** Are we going to save this object or not? */
1467 static inline bool SlIsObjectValidInSavegame(const SaveLoad
&sld
)
1469 return (_sl_version
>= sld
.version_from
&& _sl_version
< sld
.version_to
);
1473 * Calculate the size of the table header.
1474 * @param slt The SaveLoad table with objects to save/load.
1475 * @return size of given object.
1477 static size_t SlCalcTableHeader(const SaveLoadTable
&slt
)
1481 for (auto &sld
: slt
) {
1482 if (!SlIsObjectValidInSavegame(sld
)) continue;
1484 length
+= SlCalcConvFileLen(SLE_UINT8
);
1485 length
+= SlCalcStdStringLen(&sld
.name
);
1488 length
+= SlCalcConvFileLen(SLE_UINT8
); // End-of-list entry.
1490 for (auto &sld
: slt
) {
1491 if (!SlIsObjectValidInSavegame(sld
)) continue;
1492 if (sld
.cmd
== SL_STRUCTLIST
|| sld
.cmd
== SL_STRUCT
) {
1493 length
+= SlCalcTableHeader(sld
.handler
->GetDescription());
1501 * Calculate the size of an object.
1502 * @param object to be measured.
1503 * @param slt The SaveLoad table with objects to save/load.
1504 * @return size of given object.
1506 size_t SlCalcObjLength(const void *object
, const SaveLoadTable
&slt
)
1510 /* Need to determine the length and write a length tag. */
1511 for (auto &sld
: slt
) {
1512 length
+= SlCalcObjMemberLength(object
, sld
);
1517 size_t SlCalcObjMemberLength(const void *object
, const SaveLoad
&sld
)
1519 assert(_sl
.action
== SLA_SAVE
);
1521 if (!SlIsObjectValidInSavegame(sld
)) return 0;
1524 case SL_VAR
: return SlCalcConvFileLen(sld
.conv
);
1525 case SL_REF
: return SlCalcRefLen();
1526 case SL_ARR
: return SlCalcArrayLen(sld
.length
, sld
.conv
);
1527 case SL_REFLIST
: return SlCalcRefListLen(GetVariableAddress(object
, sld
), sld
.conv
);
1528 case SL_DEQUE
: return SlCalcDequeLen(GetVariableAddress(object
, sld
), sld
.conv
);
1529 case SL_VECTOR
: return SlCalcVectorLen(GetVariableAddress(object
, sld
), sld
.conv
);
1530 case SL_STDSTR
: return SlCalcStdStringLen(GetVariableAddress(object
, sld
));
1531 case SL_SAVEBYTE
: return 1; // a byte is logically of size 1
1532 case SL_NULL
: return SlCalcConvFileLen(sld
.conv
) * sld
.length
;
1535 case SL_STRUCTLIST
: {
1536 NeedLength old_need_length
= _sl
.need_length
;
1537 size_t old_obj_len
= _sl
.obj_len
;
1539 _sl
.need_length
= NL_CALCLENGTH
;
1542 /* Pretend that we are saving to collect the object size. Other
1543 * means are difficult, as we don't know the length of the list we
1544 * are about to store. */
1545 sld
.handler
->Save(const_cast<void *>(object
));
1546 size_t length
= _sl
.obj_len
;
1548 _sl
.obj_len
= old_obj_len
;
1549 _sl
.need_length
= old_need_length
;
1551 if (sld
.cmd
== SL_STRUCT
) {
1552 length
+= SlGetArrayLength(1);
1558 default: NOT_REACHED();
1563 static bool SlObjectMember(void *object
, const SaveLoad
&sld
)
1565 if (!SlIsObjectValidInSavegame(sld
)) return false;
1567 VarType conv
= GB(sld
.conv
, 0, 8);
1576 void *ptr
= GetVariableAddress(object
, sld
);
1579 case SL_VAR
: SlSaveLoadConv(ptr
, conv
); break;
1580 case SL_REF
: SlSaveLoadRef(ptr
, conv
); break;
1581 case SL_ARR
: SlArray(ptr
, sld
.length
, conv
); break;
1582 case SL_REFLIST
: SlRefList(ptr
, conv
); break;
1583 case SL_DEQUE
: SlDeque(ptr
, conv
); break;
1584 case SL_VECTOR
: SlVector(ptr
, conv
); break;
1585 case SL_STDSTR
: SlStdString(ptr
, sld
.conv
); break;
1586 default: NOT_REACHED();
1591 /* SL_SAVEBYTE writes a value to the savegame to identify the type of an object.
1592 * When loading, the value is read explicitly with SlReadByte() to determine which
1593 * object description to use. */
1595 void *ptr
= GetVariableAddress(object
, sld
);
1597 switch (_sl
.action
) {
1598 case SLA_SAVE
: SlWriteByte(*(uint8_t *)ptr
); break;
1599 case SLA_LOAD_CHECK
:
1602 case SLA_NULL
: break;
1603 default: NOT_REACHED();
1609 assert(GetVarMemType(sld
.conv
) == SLE_VAR_NULL
);
1611 switch (_sl
.action
) {
1612 case SLA_LOAD_CHECK
:
1613 case SLA_LOAD
: SlSkipBytes(SlCalcConvFileLen(sld
.conv
) * sld
.length
); break;
1614 case SLA_SAVE
: for (int i
= 0; i
< SlCalcConvFileLen(sld
.conv
) * sld
.length
; i
++) SlWriteByte(0); break;
1616 case SLA_NULL
: break;
1617 default: NOT_REACHED();
1624 switch (_sl
.action
) {
1626 if (sld
.cmd
== SL_STRUCT
) {
1627 /* Store in the savegame if this struct was written or not. */
1628 SlSetStructListLength(SlCalcObjMemberLength(object
, sld
) > SlGetArrayLength(1) ? 1 : 0);
1630 sld
.handler
->Save(object
);
1634 case SLA_LOAD_CHECK
: {
1635 if (sld
.cmd
== SL_STRUCT
&& !IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH
)) {
1636 SlGetStructListLength(1);
1638 sld
.handler
->LoadCheck(object
);
1643 if (sld
.cmd
== SL_STRUCT
&& !IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH
)) {
1644 SlGetStructListLength(1);
1646 sld
.handler
->Load(object
);
1651 sld
.handler
->FixPointers(object
);
1654 case SLA_NULL
: break;
1655 default: NOT_REACHED();
1659 default: NOT_REACHED();
1665 * Set the length of this list.
1666 * @param The length of the list.
1668 void SlSetStructListLength(size_t length
)
1670 /* Automatically calculate the length? */
1671 if (_sl
.need_length
!= NL_NONE
) {
1672 SlSetLength(SlGetArrayLength(length
));
1673 if (_sl
.need_length
== NL_CALCLENGTH
) return;
1676 SlWriteArrayLength(length
);
1680 * Get the length of this list; if it exceeds the limit, error out.
1681 * @param limit The maximum size the list can be.
1682 * @return The length of the list.
1684 size_t SlGetStructListLength(size_t limit
)
1686 size_t length
= SlReadArrayLength();
1687 if (length
> limit
) SlErrorCorrupt("List exceeds storage size");
1693 * Main SaveLoad function.
1694 * @param object The object that is being saved or loaded.
1695 * @param slt The SaveLoad table with objects to save/load.
1697 void SlObject(void *object
, const SaveLoadTable
&slt
)
1699 /* Automatically calculate the length? */
1700 if (_sl
.need_length
!= NL_NONE
) {
1701 SlSetLength(SlCalcObjLength(object
, slt
));
1702 if (_sl
.need_length
== NL_CALCLENGTH
) return;
1705 for (auto &sld
: slt
) {
1706 SlObjectMember(object
, sld
);
1711 * Handler that is assigned when there is a struct read in the savegame which
1712 * is not known to the code. This means we are going to skip it.
1714 class SlSkipHandler
: public SaveLoadHandler
{
1715 void Save(void *) const override
1720 void Load(void *object
) const override
1722 size_t length
= SlGetStructListLength(UINT32_MAX
);
1723 for (; length
> 0; length
--) {
1724 SlObject(object
, this->GetLoadDescription());
1728 void LoadCheck(void *object
) const override
1733 virtual SaveLoadTable
GetDescription() const override
1738 virtual SaveLoadCompatTable
GetCompatDescription() const override
1745 * Save or Load a table header.
1746 * @note a table-header can never contain more than 65535 fields.
1747 * @param slt The SaveLoad table with objects to save/load.
1748 * @return When loading, the ordered SaveLoad array to use; otherwise an empty list.
1750 std::vector
<SaveLoad
> SlTableHeader(const SaveLoadTable
&slt
)
1752 /* You can only use SlTableHeader if you are a CH_TABLE. */
1753 assert(_sl
.block_mode
== CH_TABLE
|| _sl
.block_mode
== CH_SPARSE_TABLE
);
1755 switch (_sl
.action
) {
1756 case SLA_LOAD_CHECK
:
1758 std::vector
<SaveLoad
> saveloads
;
1760 /* Build a key lookup mapping based on the available fields. */
1761 std::map
<std::string
, const SaveLoad
*> key_lookup
;
1762 for (auto &sld
: slt
) {
1763 if (!SlIsObjectValidInSavegame(sld
)) continue;
1765 /* Check that there is only one active SaveLoad for a given name. */
1766 assert(key_lookup
.find(sld
.name
) == key_lookup
.end());
1767 key_lookup
[sld
.name
] = &sld
;
1772 SlSaveLoadConv(&type
, SLE_UINT8
);
1773 if (type
== SLE_FILE_END
) break;
1776 SlStdString(&key
, SLE_STR
);
1778 auto sld_it
= key_lookup
.find(key
);
1779 if (sld_it
== key_lookup
.end()) {
1780 /* SLA_LOADCHECK triggers this debug statement a lot and is perfectly normal. */
1781 Debug(sl
, _sl
.action
== SLA_LOAD
? 2 : 6, "Field '{}' of type 0x{:02x} not found, skipping", key
, type
);
1783 std::shared_ptr
<SaveLoadHandler
> handler
= nullptr;
1784 SaveLoadType saveload_type
;
1785 switch (type
& SLE_FILE_TYPE_MASK
) {
1786 case SLE_FILE_STRING
:
1787 /* Strings are always marked with SLE_FILE_HAS_LENGTH_FIELD, as they are a list of chars. */
1788 saveload_type
= SL_STDSTR
;
1791 case SLE_FILE_STRUCT
:
1792 /* Structs are always marked with SLE_FILE_HAS_LENGTH_FIELD as SL_STRUCT is seen as a list of 0/1 in length. */
1793 saveload_type
= SL_STRUCTLIST
;
1794 handler
= std::make_shared
<SlSkipHandler
>();
1798 saveload_type
= (type
& SLE_FILE_HAS_LENGTH_FIELD
) ? SL_ARR
: SL_VAR
;
1802 /* We don't know this field, so read to nothing. */
1803 saveloads
.push_back({key
, saveload_type
, ((VarType
)type
& SLE_FILE_TYPE_MASK
) | SLE_VAR_NULL
, 1, SL_MIN_VERSION
, SL_MAX_VERSION
, nullptr, 0, handler
});
1807 /* Validate the type of the field. If it is changed, the
1808 * savegame should have been bumped so we know how to do the
1809 * conversion. If this error triggers, that clearly didn't
1810 * happen and this is a friendly poke to the developer to bump
1811 * the savegame version and add conversion code. */
1812 uint8_t correct_type
= GetSavegameFileType(*sld_it
->second
);
1813 if (correct_type
!= type
) {
1814 Debug(sl
, 1, "Field type for '{}' was expected to be 0x{:02x} but 0x{:02x} was found", key
, correct_type
, type
);
1815 SlErrorCorrupt("Field type is different than expected");
1817 saveloads
.push_back(*sld_it
->second
);
1820 for (auto &sld
: saveloads
) {
1821 if (sld
.cmd
== SL_STRUCTLIST
|| sld
.cmd
== SL_STRUCT
) {
1822 sld
.handler
->load_description
= SlTableHeader(sld
.handler
->GetDescription());
1830 /* Automatically calculate the length? */
1831 if (_sl
.need_length
!= NL_NONE
) {
1832 SlSetLength(SlCalcTableHeader(slt
));
1833 if (_sl
.need_length
== NL_CALCLENGTH
) break;
1836 for (auto &sld
: slt
) {
1837 if (!SlIsObjectValidInSavegame(sld
)) continue;
1838 /* Make sure we are not storing empty keys. */
1839 assert(!sld
.name
.empty());
1841 uint8_t type
= GetSavegameFileType(sld
);
1842 assert(type
!= SLE_FILE_END
);
1844 SlSaveLoadConv(&type
, SLE_UINT8
);
1845 SlStdString(const_cast<std::string
*>(&sld
.name
), SLE_STR
);
1848 /* Add an end-of-header marker. */
1849 uint8_t type
= SLE_FILE_END
;
1850 SlSaveLoadConv(&type
, SLE_UINT8
);
1852 /* After the table, write down any sub-tables we might have. */
1853 for (auto &sld
: slt
) {
1854 if (!SlIsObjectValidInSavegame(sld
)) continue;
1855 if (sld
.cmd
== SL_STRUCTLIST
|| sld
.cmd
== SL_STRUCT
) {
1856 /* SlCalcTableHeader already looks in sub-lists, so avoid the length being added twice. */
1857 NeedLength old_need_length
= _sl
.need_length
;
1858 _sl
.need_length
= NL_NONE
;
1860 SlTableHeader(sld
.handler
->GetDescription());
1862 _sl
.need_length
= old_need_length
;
1869 default: NOT_REACHED();
1872 return std::vector
<SaveLoad
>();
1876 * Load a table header in a savegame compatible way. If the savegame was made
1877 * before table headers were added, it will fall back to the
1878 * SaveLoadCompatTable for the order of fields while loading.
1880 * @note You only have to call this function if the chunk existed as a
1881 * non-table type before converting it to a table. New chunks created as
1882 * table can call SlTableHeader() directly.
1884 * @param slt The SaveLoad table with objects to save/load.
1885 * @param slct The SaveLoadCompat table the original order of the fields.
1886 * @return When loading, the ordered SaveLoad array to use; otherwise an empty list.
1888 std::vector
<SaveLoad
> SlCompatTableHeader(const SaveLoadTable
&slt
, const SaveLoadCompatTable
&slct
)
1890 assert(_sl
.action
== SLA_LOAD
|| _sl
.action
== SLA_LOAD_CHECK
);
1891 /* CH_TABLE / CH_SPARSE_TABLE always have a header. */
1892 if (_sl
.block_mode
== CH_TABLE
|| _sl
.block_mode
== CH_SPARSE_TABLE
) return SlTableHeader(slt
);
1894 std::vector
<SaveLoad
> saveloads
;
1896 /* Build a key lookup mapping based on the available fields. */
1897 std::map
<std::string
, std::vector
<const SaveLoad
*>> key_lookup
;
1898 for (auto &sld
: slt
) {
1899 /* All entries should have a name; otherwise the entry should just be removed. */
1900 assert(!sld
.name
.empty());
1902 key_lookup
[sld
.name
].push_back(&sld
);
1905 for (auto &slc
: slct
) {
1906 if (slc
.name
.empty()) {
1907 /* In old savegames there can be data we no longer care for. We
1908 * skip this by simply reading the amount of bytes indicated and
1909 * send those to /dev/null. */
1910 saveloads
.push_back({"", SL_NULL
, GetVarFileType(slc
.null_type
) | SLE_VAR_NULL
, slc
.null_length
, slc
.version_from
, slc
.version_to
, nullptr, 0, nullptr});
1912 auto sld_it
= key_lookup
.find(slc
.name
);
1913 /* If this branch triggers, it means that an entry in the
1914 * SaveLoadCompat list is not mentioned in the SaveLoad list. Did
1915 * you rename a field in one and not in the other? */
1916 if (sld_it
== key_lookup
.end()) {
1917 /* This isn't an assert, as that leaves no information what
1918 * field was to blame. This way at least we have breadcrumbs. */
1919 Debug(sl
, 0, "internal error: saveload compatibility field '{}' not found", slc
.name
);
1920 SlErrorCorrupt("Internal error with savegame compatibility");
1922 for (auto &sld
: sld_it
->second
) {
1923 saveloads
.push_back(*sld
);
1928 for (auto &sld
: saveloads
) {
1929 if (!SlIsObjectValidInSavegame(sld
)) continue;
1930 if (sld
.cmd
== SL_STRUCTLIST
|| sld
.cmd
== SL_STRUCT
) {
1931 sld
.handler
->load_description
= SlCompatTableHeader(sld
.handler
->GetDescription(), sld
.handler
->GetCompatDescription());
1939 * Save or Load (a list of) global variables.
1940 * @param slt The SaveLoad table with objects to save/load.
1942 void SlGlobList(const SaveLoadTable
&slt
)
1944 SlObject(nullptr, slt
);
1948 * Do something of which I have no idea what it is :P
1949 * @param proc The callback procedure that is called
1950 * @param arg The variable that will be used for the callback procedure
1952 void SlAutolength(AutolengthProc
*proc
, int arg
)
1954 assert(_sl
.action
== SLA_SAVE
);
1956 /* Tell it to calculate the length */
1957 _sl
.need_length
= NL_CALCLENGTH
;
1962 _sl
.need_length
= NL_WANTLENGTH
;
1963 SlSetLength(_sl
.obj_len
);
1965 size_t start_pos
= _sl
.dumper
->GetSize();
1966 size_t expected_offs
= start_pos
+ _sl
.obj_len
;
1968 /* And write the stuff */
1971 if (expected_offs
!= _sl
.dumper
->GetSize()) {
1972 SlErrorCorruptFmt("Invalid chunk size when writing autolength block, expected {}, got {}", _sl
.obj_len
, _sl
.dumper
->GetSize() - start_pos
);
1976 void ChunkHandler::LoadCheck(size_t len
) const
1978 switch (_sl
.block_mode
) {
1980 case CH_SPARSE_TABLE
:
1984 case CH_SPARSE_ARRAY
:
1996 * Load a chunk of data (eg vehicles, stations, etc.)
1997 * @param ch The chunkhandler that will be used for the operation
1999 static void SlLoadChunk(const ChunkHandler
&ch
)
2001 uint8_t m
= SlReadByte();
2003 _sl
.block_mode
= m
& CH_TYPE_MASK
;
2005 _sl
.expect_table_header
= (_sl
.block_mode
== CH_TABLE
|| _sl
.block_mode
== CH_SPARSE_TABLE
);
2007 /* The header should always be at the start. Read the length; the
2008 * Load() should as first action process the header. */
2009 if (_sl
.expect_table_header
) {
2013 switch (_sl
.block_mode
) {
2016 _sl
.array_index
= 0;
2018 if (_next_offs
!= 0) SlErrorCorrupt("Invalid array length");
2020 case CH_SPARSE_TABLE
:
2021 case CH_SPARSE_ARRAY
:
2023 if (_next_offs
!= 0) SlErrorCorrupt("Invalid array length");
2027 size_t len
= (SlReadByte() << 16) | ((m
>> 4) << 24);
2028 len
+= SlReadUint16();
2030 size_t start_pos
= _sl
.reader
->GetSize();
2031 size_t endoffs
= start_pos
+ len
;
2034 if (_sl
.reader
->GetSize() != endoffs
) {
2035 SlErrorCorruptFmt("Invalid chunk size in RIFF in {} - expected {}, got {}", ch
.GetName(), len
, _sl
.reader
->GetSize() - start_pos
);
2040 SlErrorCorrupt("Invalid chunk type");
2044 if (_sl
.expect_table_header
) SlErrorCorrupt("Table chunk without header");
2048 * Load a chunk of data for checking savegames.
2049 * If the chunkhandler is nullptr, the chunk is skipped.
2050 * @param ch The chunkhandler that will be used for the operation
2052 static void SlLoadCheckChunk(const ChunkHandler
&ch
)
2054 uint8_t m
= SlReadByte();
2056 _sl
.block_mode
= m
& CH_TYPE_MASK
;
2058 _sl
.expect_table_header
= (_sl
.block_mode
== CH_TABLE
|| _sl
.block_mode
== CH_SPARSE_TABLE
);
2060 /* The header should always be at the start. Read the length; the
2061 * LoadCheck() should as first action process the header. */
2062 if (_sl
.expect_table_header
) {
2066 switch (_sl
.block_mode
) {
2069 _sl
.array_index
= 0;
2072 case CH_SPARSE_TABLE
:
2073 case CH_SPARSE_ARRAY
:
2078 size_t len
= (SlReadByte() << 16) | ((m
>> 4) << 24);
2079 len
+= SlReadUint16();
2081 size_t start_pos
= _sl
.reader
->GetSize();
2082 size_t endoffs
= start_pos
+ len
;
2085 if (_sl
.reader
->GetSize() != endoffs
) {
2086 SlErrorCorruptFmt("Invalid chunk size in RIFF in {} - expected {}, got {}", ch
.GetName(), len
, _sl
.reader
->GetSize() - start_pos
);
2091 SlErrorCorrupt("Invalid chunk type");
2095 if (_sl
.expect_table_header
) SlErrorCorrupt("Table chunk without header");
2099 * Save a chunk of data (eg. vehicles, stations, etc.). Each chunk is
2100 * prefixed by an ID identifying it, followed by data, and terminator where appropriate
2101 * @param ch The chunkhandler that will be used for the operation
2103 static void SlSaveChunk(const ChunkHandler
&ch
)
2105 if (ch
.type
== CH_READONLY
) return;
2107 SlWriteUint32(ch
.id
);
2108 Debug(sl
, 2, "Saving chunk {}", ch
.GetName());
2110 _sl
.block_mode
= ch
.type
;
2111 _sl
.expect_table_header
= (_sl
.block_mode
== CH_TABLE
|| _sl
.block_mode
== CH_SPARSE_TABLE
);
2113 _sl
.need_length
= (_sl
.expect_table_header
|| _sl
.block_mode
== CH_RIFF
) ? NL_WANTLENGTH
: NL_NONE
;
2115 switch (_sl
.block_mode
) {
2121 _sl
.last_array_index
= 0;
2122 SlWriteByte(_sl
.block_mode
);
2124 SlWriteArrayLength(0); // Terminate arrays
2126 case CH_SPARSE_TABLE
:
2127 case CH_SPARSE_ARRAY
:
2128 SlWriteByte(_sl
.block_mode
);
2130 SlWriteArrayLength(0); // Terminate arrays
2132 default: NOT_REACHED();
2135 if (_sl
.expect_table_header
) SlErrorCorrupt("Table chunk without header");
2138 /** Save all chunks */
2139 static void SlSaveChunks()
2141 for (auto &ch
: ChunkHandlers()) {
2150 * Find the ChunkHandler that will be used for processing the found
2151 * chunk in the savegame or in memory
2152 * @param id the chunk in question
2153 * @return returns the appropriate chunkhandler
2155 static const ChunkHandler
*SlFindChunkHandler(uint32_t id
)
2157 for (const ChunkHandler
&ch
: ChunkHandlers()) if (ch
.id
== id
) return &ch
;
2161 /** Load all chunks */
2162 static void SlLoadChunks()
2165 const ChunkHandler
*ch
;
2167 for (id
= SlReadUint32(); id
!= 0; id
= SlReadUint32()) {
2168 Debug(sl
, 2, "Loading chunk {:c}{:c}{:c}{:c}", id
>> 24, id
>> 16, id
>> 8, id
);
2170 ch
= SlFindChunkHandler(id
);
2171 if (ch
== nullptr) SlErrorCorrupt("Unknown chunk type");
2176 /** Load all chunks for savegame checking */
2177 static void SlLoadCheckChunks()
2180 const ChunkHandler
*ch
;
2182 for (id
= SlReadUint32(); id
!= 0; id
= SlReadUint32()) {
2183 Debug(sl
, 2, "Loading chunk {:c}{:c}{:c}{:c}", id
>> 24, id
>> 16, id
>> 8, id
);
2185 ch
= SlFindChunkHandler(id
);
2186 if (ch
== nullptr) SlErrorCorrupt("Unknown chunk type");
2187 SlLoadCheckChunk(*ch
);
2191 /** Fix all pointers (convert index -> pointer) */
2192 static void SlFixPointers()
2194 _sl
.action
= SLA_PTRS
;
2196 for (const ChunkHandler
&ch
: ChunkHandlers()) {
2197 Debug(sl
, 3, "Fixing pointers for {}", ch
.GetName());
2201 assert(_sl
.action
== SLA_PTRS
);
2205 /** Yes, simply reading from a file. */
2206 struct FileReader
: LoadFilter
{
2207 std::optional
<FileHandle
> file
; ///< The file to read from.
2208 long begin
; ///< The begin of the file.
2211 * Create the file reader, so it reads from a specific file.
2212 * @param file The file to read from.
2214 FileReader(FileHandle
&&file
) : LoadFilter(nullptr), file(std::move(file
)), begin(ftell(*this->file
))
2218 /** Make sure everything is cleaned up. */
2221 if (this->file
.has_value()) {
2222 _game_session_stats
.savegame_size
= ftell(*this->file
) - this->begin
;
2226 size_t Read(uint8_t *buf
, size_t size
) override
2228 /* We're in the process of shutting down, i.e. in "failure" mode. */
2229 if (!this->file
.has_value()) return 0;
2231 return fread(buf
, 1, size
, *this->file
);
2234 void Reset() override
2236 clearerr(*this->file
);
2237 if (fseek(*this->file
, this->begin
, SEEK_SET
)) {
2238 Debug(sl
, 1, "Could not reset the file reading");
2243 /** Yes, simply writing to a file. */
2244 struct FileWriter
: SaveFilter
{
2245 std::optional
<FileHandle
> file
; ///< The file to write to.
2248 * Create the file writer, so it writes to a specific file.
2249 * @param file The file to write to.
2251 FileWriter(FileHandle
&&file
) : SaveFilter(nullptr), file(std::move(file
))
2255 /** Make sure everything is cleaned up. */
2261 void Write(uint8_t *buf
, size_t size
) override
2263 /* We're in the process of shutting down, i.e. in "failure" mode. */
2264 if (!this->file
.has_value()) return;
2266 if (fwrite(buf
, 1, size
, *this->file
) != size
) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE
);
2269 void Finish() override
2271 if (this->file
.has_value()) {
2272 _game_session_stats
.savegame_size
= ftell(*this->file
);
2278 /*******************************************
2279 ********** START OF LZO CODE **************
2280 *******************************************/
2283 #include <lzo/lzo1x.h>
2285 /** Buffer size for the LZO compressor */
2286 static const uint LZO_BUFFER_SIZE
= 8192;
2288 /** Filter using LZO compression. */
2289 struct LZOLoadFilter
: LoadFilter
{
2291 * Initialise this filter.
2292 * @param chain The next filter in this chain.
2294 LZOLoadFilter(std::shared_ptr
<LoadFilter
> chain
) : LoadFilter(chain
)
2296 if (lzo_init() != LZO_E_OK
) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR
, "cannot initialize decompressor");
2299 size_t Read(uint8_t *buf
, size_t ssize
) override
2301 assert(ssize
>= LZO_BUFFER_SIZE
);
2303 /* Buffer size is from the LZO docs plus the chunk header size. */
2304 uint8_t out
[LZO_BUFFER_SIZE
+ LZO_BUFFER_SIZE
/ 16 + 64 + 3 + sizeof(uint32_t) * 2];
2307 lzo_uint len
= ssize
;
2310 if (this->chain
->Read((uint8_t*)tmp
, sizeof(tmp
)) != sizeof(tmp
)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE
, "File read failed");
2312 /* Check if size is bad */
2313 ((uint32_t*)out
)[0] = size
= tmp
[1];
2315 if (_sl_version
!= SL_MIN_VERSION
) {
2316 tmp
[0] = TO_BE32(tmp
[0]);
2317 size
= TO_BE32(size
);
2320 if (size
>= sizeof(out
)) SlErrorCorrupt("Inconsistent size");
2323 if (this->chain
->Read(out
+ sizeof(uint32_t), size
) != size
) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE
);
2325 /* Verify checksum */
2326 if (tmp
[0] != lzo_adler32(0, out
, size
+ sizeof(uint32_t))) SlErrorCorrupt("Bad checksum");
2329 int ret
= lzo1x_decompress_safe(out
+ sizeof(uint32_t) * 1, size
, buf
, &len
, nullptr);
2330 if (ret
!= LZO_E_OK
) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE
);
2335 /** Filter using LZO compression. */
2336 struct LZOSaveFilter
: SaveFilter
{
2338 * Initialise this filter.
2339 * @param chain The next filter in this chain.
2341 LZOSaveFilter(std::shared_ptr
<SaveFilter
> chain
, uint8_t) : SaveFilter(chain
)
2343 if (lzo_init() != LZO_E_OK
) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR
, "cannot initialize compressor");
2346 void Write(uint8_t *buf
, size_t size
) override
2348 const lzo_bytep in
= buf
;
2349 /* Buffer size is from the LZO docs plus the chunk header size. */
2350 uint8_t out
[LZO_BUFFER_SIZE
+ LZO_BUFFER_SIZE
/ 16 + 64 + 3 + sizeof(uint32_t) * 2];
2351 uint8_t wrkmem
[LZO1X_1_MEM_COMPRESS
];
2355 /* Compress up to LZO_BUFFER_SIZE bytes at once. */
2356 lzo_uint len
= size
> LZO_BUFFER_SIZE
? LZO_BUFFER_SIZE
: (lzo_uint
)size
;
2357 lzo1x_1_compress(in
, len
, out
+ sizeof(uint32_t) * 2, &outlen
, wrkmem
);
2358 ((uint32_t*)out
)[1] = TO_BE32((uint32_t)outlen
);
2359 ((uint32_t*)out
)[0] = TO_BE32(lzo_adler32(0, out
+ sizeof(uint32_t), outlen
+ sizeof(uint32_t)));
2360 this->chain
->Write(out
, outlen
+ sizeof(uint32_t) * 2);
2362 /* Move to next data chunk. */
2369 #endif /* WITH_LZO */
2371 /*********************************************
2372 ******** START OF NOCOMP CODE (uncompressed)*
2373 *********************************************/
2375 /** Filter without any compression. */
2376 struct NoCompLoadFilter
: LoadFilter
{
2378 * Initialise this filter.
2379 * @param chain The next filter in this chain.
2381 NoCompLoadFilter(std::shared_ptr
<LoadFilter
> chain
) : LoadFilter(chain
)
2385 size_t Read(uint8_t *buf
, size_t size
) override
2387 return this->chain
->Read(buf
, size
);
2391 /** Filter without any compression. */
2392 struct NoCompSaveFilter
: SaveFilter
{
2394 * Initialise this filter.
2395 * @param chain The next filter in this chain.
2397 NoCompSaveFilter(std::shared_ptr
<SaveFilter
> chain
, uint8_t) : SaveFilter(chain
)
2401 void Write(uint8_t *buf
, size_t size
) override
2403 this->chain
->Write(buf
, size
);
2407 /********************************************
2408 ********** START OF ZLIB CODE **************
2409 ********************************************/
2411 #if defined(WITH_ZLIB)
2414 /** Filter using Zlib compression. */
2415 struct ZlibLoadFilter
: LoadFilter
{
2416 z_stream z
; ///< Stream state we are reading from.
2417 uint8_t fread_buf
[MEMORY_CHUNK_SIZE
]; ///< Buffer for reading from the file.
2420 * Initialise this filter.
2421 * @param chain The next filter in this chain.
2423 ZlibLoadFilter(std::shared_ptr
<LoadFilter
> chain
) : LoadFilter(chain
)
2425 memset(&this->z
, 0, sizeof(this->z
));
2426 if (inflateInit(&this->z
) != Z_OK
) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR
, "cannot initialize decompressor");
2429 /** Clean everything up. */
2432 inflateEnd(&this->z
);
2435 size_t Read(uint8_t *buf
, size_t size
) override
2437 this->z
.next_out
= buf
;
2438 this->z
.avail_out
= (uint
)size
;
2441 /* read more bytes from the file? */
2442 if (this->z
.avail_in
== 0) {
2443 this->z
.next_in
= this->fread_buf
;
2444 this->z
.avail_in
= (uint
)this->chain
->Read(this->fread_buf
, sizeof(this->fread_buf
));
2447 /* inflate the data */
2448 int r
= inflate(&this->z
, 0);
2449 if (r
== Z_STREAM_END
) break;
2451 if (r
!= Z_OK
) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR
, "inflate() failed");
2452 } while (this->z
.avail_out
!= 0);
2454 return size
- this->z
.avail_out
;
2458 /** Filter using Zlib compression. */
2459 struct ZlibSaveFilter
: SaveFilter
{
2460 z_stream z
; ///< Stream state we are writing to.
2461 uint8_t fwrite_buf
[MEMORY_CHUNK_SIZE
]; ///< Buffer for writing to the file.
2464 * Initialise this filter.
2465 * @param chain The next filter in this chain.
2466 * @param compression_level The requested level of compression.
2468 ZlibSaveFilter(std::shared_ptr
<SaveFilter
> chain
, uint8_t compression_level
) : SaveFilter(chain
)
2470 memset(&this->z
, 0, sizeof(this->z
));
2471 if (deflateInit(&this->z
, compression_level
) != Z_OK
) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR
, "cannot initialize compressor");
2474 /** Clean up what we allocated. */
2477 deflateEnd(&this->z
);
2481 * Helper loop for writing the data.
2482 * @param p The bytes to write.
2483 * @param len Amount of bytes to write.
2484 * @param mode Mode for deflate.
2486 void WriteLoop(uint8_t *p
, size_t len
, int mode
)
2489 this->z
.next_in
= p
;
2490 this->z
.avail_in
= (uInt
)len
;
2492 this->z
.next_out
= this->fwrite_buf
;
2493 this->z
.avail_out
= sizeof(this->fwrite_buf
);
2496 * For the poor next soul who sees many valgrind warnings of the
2497 * "Conditional jump or move depends on uninitialised value(s)" kind:
2498 * According to the author of zlib it is not a bug and it won't be fixed.
2499 * http://groups.google.com/group/comp.compression/browse_thread/thread/b154b8def8c2a3ef/cdf9b8729ce17ee2
2500 * [Mark Adler, Feb 24 2004, 'zlib-1.2.1 valgrind warnings' in the newsgroup comp.compression]
2502 int r
= deflate(&this->z
, mode
);
2504 /* bytes were emitted? */
2505 if ((n
= sizeof(this->fwrite_buf
) - this->z
.avail_out
) != 0) {
2506 this->chain
->Write(this->fwrite_buf
, n
);
2508 if (r
== Z_STREAM_END
) break;
2510 if (r
!= Z_OK
) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR
, "zlib returned error code");
2511 } while (this->z
.avail_in
|| !this->z
.avail_out
);
2514 void Write(uint8_t *buf
, size_t size
) override
2516 this->WriteLoop(buf
, size
, 0);
2519 void Finish() override
2521 this->WriteLoop(nullptr, 0, Z_FINISH
);
2522 this->chain
->Finish();
2526 #endif /* WITH_ZLIB */
2528 /********************************************
2529 ********** START OF LZMA CODE **************
2530 ********************************************/
2532 #if defined(WITH_LIBLZMA)
2536 * Have a copy of an initialised LZMA stream. We need this as it's
2537 * impossible to "re"-assign LZMA_STREAM_INIT to a variable in some
2538 * compilers, i.e. LZMA_STREAM_INIT can't be used to set something.
2539 * This var has to be used instead.
2541 static const lzma_stream _lzma_init
= LZMA_STREAM_INIT
;
2543 /** Filter without any compression. */
2544 struct LZMALoadFilter
: LoadFilter
{
2545 lzma_stream lzma
; ///< Stream state that we are reading from.
2546 uint8_t fread_buf
[MEMORY_CHUNK_SIZE
]; ///< Buffer for reading from the file.
2549 * Initialise this filter.
2550 * @param chain The next filter in this chain.
2552 LZMALoadFilter(std::shared_ptr
<LoadFilter
> chain
) : LoadFilter(chain
), lzma(_lzma_init
)
2554 /* Allow saves up to 256 MB uncompressed */
2555 if (lzma_auto_decoder(&this->lzma
, 1 << 28, 0) != LZMA_OK
) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR
, "cannot initialize decompressor");
2558 /** Clean everything up. */
2561 lzma_end(&this->lzma
);
2564 size_t Read(uint8_t *buf
, size_t size
) override
2566 this->lzma
.next_out
= buf
;
2567 this->lzma
.avail_out
= size
;
2570 /* read more bytes from the file? */
2571 if (this->lzma
.avail_in
== 0) {
2572 this->lzma
.next_in
= this->fread_buf
;
2573 this->lzma
.avail_in
= this->chain
->Read(this->fread_buf
, sizeof(this->fread_buf
));
2576 /* inflate the data */
2577 lzma_ret r
= lzma_code(&this->lzma
, LZMA_RUN
);
2578 if (r
== LZMA_STREAM_END
) break;
2579 if (r
!= LZMA_OK
) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR
, "liblzma returned error code");
2580 } while (this->lzma
.avail_out
!= 0);
2582 return size
- this->lzma
.avail_out
;
2586 /** Filter using LZMA compression. */
2587 struct LZMASaveFilter
: SaveFilter
{
2588 lzma_stream lzma
; ///< Stream state that we are writing to.
2589 uint8_t fwrite_buf
[MEMORY_CHUNK_SIZE
]; ///< Buffer for writing to the file.
2592 * Initialise this filter.
2593 * @param chain The next filter in this chain.
2594 * @param compression_level The requested level of compression.
2596 LZMASaveFilter(std::shared_ptr
<SaveFilter
> chain
, uint8_t compression_level
) : SaveFilter(chain
), lzma(_lzma_init
)
2598 if (lzma_easy_encoder(&this->lzma
, compression_level
, LZMA_CHECK_CRC32
) != LZMA_OK
) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR
, "cannot initialize compressor");
2601 /** Clean up what we allocated. */
2604 lzma_end(&this->lzma
);
2608 * Helper loop for writing the data.
2609 * @param p The bytes to write.
2610 * @param len Amount of bytes to write.
2611 * @param action Action for lzma_code.
2613 void WriteLoop(uint8_t *p
, size_t len
, lzma_action action
)
2616 this->lzma
.next_in
= p
;
2617 this->lzma
.avail_in
= len
;
2619 this->lzma
.next_out
= this->fwrite_buf
;
2620 this->lzma
.avail_out
= sizeof(this->fwrite_buf
);
2622 lzma_ret r
= lzma_code(&this->lzma
, action
);
2624 /* bytes were emitted? */
2625 if ((n
= sizeof(this->fwrite_buf
) - this->lzma
.avail_out
) != 0) {
2626 this->chain
->Write(this->fwrite_buf
, n
);
2628 if (r
== LZMA_STREAM_END
) break;
2629 if (r
!= LZMA_OK
) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR
, "liblzma returned error code");
2630 } while (this->lzma
.avail_in
|| !this->lzma
.avail_out
);
2633 void Write(uint8_t *buf
, size_t size
) override
2635 this->WriteLoop(buf
, size
, LZMA_RUN
);
2638 void Finish() override
2640 this->WriteLoop(nullptr, 0, LZMA_FINISH
);
2641 this->chain
->Finish();
2645 #endif /* WITH_LIBLZMA */
2647 /*******************************************
2648 ************* END OF CODE *****************
2649 *******************************************/
2651 /** The format for a reader/writer type of a savegame */
2652 struct SaveLoadFormat
{
2653 const char *name
; ///< name of the compressor/decompressor (debug-only)
2654 uint32_t tag
; ///< the 4-letter tag by which it is identified in the savegame
2656 std::shared_ptr
<LoadFilter
> (*init_load
)(std::shared_ptr
<LoadFilter
> chain
); ///< Constructor for the load filter.
2657 std::shared_ptr
<SaveFilter
> (*init_write
)(std::shared_ptr
<SaveFilter
> chain
, uint8_t compression
); ///< Constructor for the save filter.
2659 uint8_t min_compression
; ///< the minimum compression level of this format
2660 uint8_t default_compression
; ///< the default compression level of this format
2661 uint8_t max_compression
; ///< the maximum compression level of this format
2664 static const uint32_t SAVEGAME_TAG_LZO
= TO_BE32X('OTTD');
2665 static const uint32_t SAVEGAME_TAG_NONE
= TO_BE32X('OTTN');
2666 static const uint32_t SAVEGAME_TAG_ZLIB
= TO_BE32X('OTTZ');
2667 static const uint32_t SAVEGAME_TAG_LZMA
= TO_BE32X('OTTX');
2669 /** The different saveload formats known/understood by OpenTTD. */
2670 static const SaveLoadFormat _saveload_formats
[] = {
2671 #if defined(WITH_LZO)
2672 /* Roughly 75% larger than zlib level 6 at only ~7% of the CPU usage. */
2673 {"lzo", SAVEGAME_TAG_LZO
, CreateLoadFilter
<LZOLoadFilter
>, CreateSaveFilter
<LZOSaveFilter
>, 0, 0, 0},
2675 {"lzo", SAVEGAME_TAG_LZO
, nullptr, nullptr, 0, 0, 0},
2677 /* Roughly 5 times larger at only 1% of the CPU usage over zlib level 6. */
2678 {"none", SAVEGAME_TAG_NONE
, CreateLoadFilter
<NoCompLoadFilter
>, CreateSaveFilter
<NoCompSaveFilter
>, 0, 0, 0},
2679 #if defined(WITH_ZLIB)
2680 /* After level 6 the speed reduction is significant (1.5x to 2.5x slower per level), but the reduction in filesize is
2681 * fairly insignificant (~1% for each step). Lower levels become ~5-10% bigger by each level than level 6 while level
2682 * 1 is "only" 3 times as fast. Level 0 results in uncompressed savegames at about 8 times the cost of "none". */
2683 {"zlib", SAVEGAME_TAG_ZLIB
, CreateLoadFilter
<ZlibLoadFilter
>, CreateSaveFilter
<ZlibSaveFilter
>, 0, 6, 9},
2685 {"zlib", SAVEGAME_TAG_ZLIB
, nullptr, nullptr, 0, 0, 0},
2687 #if defined(WITH_LIBLZMA)
2688 /* Level 2 compression is speed wise as fast as zlib level 6 compression (old default), but results in ~10% smaller saves.
2689 * Higher compression levels are possible, and might improve savegame size by up to 25%, but are also up to 10 times slower.
2690 * The next significant reduction in file size is at level 4, but that is already 4 times slower. Level 3 is primarily 50%
2691 * slower while not improving the filesize, while level 0 and 1 are faster, but don't reduce savegame size much.
2692 * It's OTTX and not e.g. OTTL because liblzma is part of xz-utils and .tar.xz is preferred over .tar.lzma. */
2693 {"lzma", SAVEGAME_TAG_LZMA
, CreateLoadFilter
<LZMALoadFilter
>, CreateSaveFilter
<LZMASaveFilter
>, 0, 2, 9},
2695 {"lzma", SAVEGAME_TAG_LZMA
, nullptr, nullptr, 0, 0, 0},
2700 * Return the savegameformat of the game. Whether it was created with ZLIB compression
2701 * uncompressed, or another type
2702 * @param full_name Name of the savegame format. If empty it picks the first available one
2703 * @return Pair containing reference to SaveLoadFormat struct giving all characteristics of this type of savegame, and a compression level to use.
2705 static std::pair
<const SaveLoadFormat
&, uint8_t> GetSavegameFormat(const std::string
&full_name
)
2707 /* Find default savegame format, the highest one with which files can be written. */
2708 auto it
= std::find_if(std::rbegin(_saveload_formats
), std::rend(_saveload_formats
), [](const auto &slf
) { return slf
.init_write
!= nullptr; });
2709 if (it
== std::rend(_saveload_formats
)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR
, "no writeable savegame formats");
2711 const SaveLoadFormat
&def
= *it
;
2713 if (!full_name
.empty()) {
2714 /* Get the ":..." of the compression level out of the way */
2715 size_t separator
= full_name
.find(':');
2716 bool has_comp_level
= separator
!= std::string::npos
;
2717 const std::string
name(full_name
, 0, has_comp_level
? separator
: full_name
.size());
2719 for (const auto &slf
: _saveload_formats
) {
2720 if (slf
.init_write
!= nullptr && name
.compare(slf
.name
) == 0) {
2721 if (has_comp_level
) {
2722 const std::string
complevel(full_name
, separator
+ 1);
2724 /* Get the level and determine whether all went fine. */
2726 long level
= std::stol(complevel
, &processed
, 10);
2727 if (processed
== 0 || level
!= Clamp(level
, slf
.min_compression
, slf
.max_compression
)) {
2728 SetDParamStr(0, complevel
);
2729 ShowErrorMessage(STR_CONFIG_ERROR
, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL
, WL_CRITICAL
);
2731 return {slf
, ClampTo
<uint8_t>(level
)};
2734 return {slf
, slf
.default_compression
};
2738 SetDParamStr(0, name
);
2739 SetDParamStr(1, def
.name
);
2740 ShowErrorMessage(STR_CONFIG_ERROR
, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM
, WL_CRITICAL
);
2742 return {def
, def
.default_compression
};
2745 /* actual loader/saver function */
2746 void InitializeGame(uint size_x
, uint size_y
, bool reset_date
, bool reset_settings
);
2747 extern bool AfterLoadGame();
2748 extern bool LoadOldSaveGame(const std::string
&file
);
2751 * Clear temporary data that is passed between various saveload phases.
2753 static void ResetSaveloadData()
2755 ResetTempEngineData();
2757 ResetOldWaypoints();
2761 * Clear/free saveload state.
2763 static inline void ClearSaveLoadState()
2765 _sl
.dumper
= nullptr;
2767 _sl
.reader
= nullptr;
2771 /** Update the gui accordingly when starting saving and set locks on saveload. */
2772 static void SaveFileStart()
2774 SetMouseCursorBusy(true);
2776 InvalidateWindowData(WC_STATUS_BAR
, 0, SBI_SAVELOAD_START
);
2777 _sl
.saveinprogress
= true;
2780 /** Update the gui accordingly when saving is done and release locks on saveload. */
2781 static void SaveFileDone()
2783 SetMouseCursorBusy(false);
2785 InvalidateWindowData(WC_STATUS_BAR
, 0, SBI_SAVELOAD_FINISH
);
2786 _sl
.saveinprogress
= false;
2788 #ifdef __EMSCRIPTEN__
2789 EM_ASM(if (window
["openttd_syncfs"]) openttd_syncfs());
2793 /** Set the error message from outside of the actual loading/saving of the game (AfterLoadGame and friends) */
2794 void SetSaveLoadError(StringID str
)
2796 _sl
.error_str
= str
;
2799 /** Return the appropriate initial string for an error depending on whether we are saving or loading. */
2800 StringID
GetSaveLoadErrorType()
2802 return _sl
.action
== SLA_SAVE
? STR_ERROR_GAME_SAVE_FAILED
: STR_ERROR_GAME_LOAD_FAILED
;
2805 /** Return the description of the error. **/
2806 StringID
GetSaveLoadErrorMessage()
2808 SetDParamStr(0, _sl
.extra_msg
);
2809 return _sl
.error_str
;
2812 /** Show a gui message when saving has failed */
2813 static void SaveFileError()
2815 ShowErrorMessage(GetSaveLoadErrorType(), GetSaveLoadErrorMessage(), WL_ERROR
);
2820 * We have written the whole game into memory, _memory_savegame, now find
2821 * and appropriate compressor and start writing to file.
2823 static SaveOrLoadResult
SaveFileToDisk(bool threaded
)
2826 auto [fmt
, compression
] = GetSavegameFormat(_savegame_format
);
2828 /* We have written our stuff to memory, now write it to file! */
2829 uint32_t hdr
[2] = { fmt
.tag
, TO_BE32(SAVEGAME_VERSION
<< 16) };
2830 _sl
.sf
->Write((uint8_t*)hdr
, sizeof(hdr
));
2832 _sl
.sf
= fmt
.init_write(_sl
.sf
, compression
);
2833 _sl
.dumper
->Flush(_sl
.sf
);
2835 ClearSaveLoadState();
2837 if (threaded
) SetAsyncSaveFinish(SaveFileDone
);
2841 ClearSaveLoadState();
2843 AsyncSaveFinishProc asfp
= SaveFileDone
;
2845 /* We don't want to shout when saving is just
2846 * cancelled due to a client disconnecting. */
2847 if (_sl
.error_str
!= STR_NETWORK_ERROR_LOSTCONNECTION
) {
2848 /* Skip the "colour" character */
2849 Debug(sl
, 0, "{}", GetString(GetSaveLoadErrorType()).substr(3) + GetString(GetSaveLoadErrorMessage()));
2850 asfp
= SaveFileError
;
2854 SetAsyncSaveFinish(asfp
);
2862 void WaitTillSaved()
2864 if (!_save_thread
.joinable()) return;
2866 _save_thread
.join();
2868 /* Make sure every other state is handled properly as well. */
2869 ProcessAsyncSaveFinish();
2873 * Actually perform the saving of the savegame.
2874 * General tactics is to first save the game to memory, then write it to file
2875 * using the writer, either in threaded mode if possible, or single-threaded.
2876 * @param writer The filter to write the savegame to.
2877 * @param threaded Whether to try to perform the saving asynchronously.
2878 * @return Return the result of the action. #SL_OK or #SL_ERROR
2880 static SaveOrLoadResult
DoSave(std::shared_ptr
<SaveFilter
> writer
, bool threaded
)
2882 assert(!_sl
.saveinprogress
);
2884 _sl
.dumper
= std::make_unique
<MemoryDumper
>();
2887 _sl_version
= SAVEGAME_VERSION
;
2889 SaveViewportBeforeSaveGame();
2894 if (!threaded
|| !StartNewThread(&_save_thread
, "ottd:savegame", &SaveFileToDisk
, true)) {
2895 if (threaded
) Debug(sl
, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
2897 SaveOrLoadResult result
= SaveFileToDisk(false);
2907 * Save the game using a (writer) filter.
2908 * @param writer The filter to write the savegame to.
2909 * @param threaded Whether to try to perform the saving asynchronously.
2910 * @return Return the result of the action. #SL_OK or #SL_ERROR
2912 SaveOrLoadResult
SaveWithFilter(std::shared_ptr
<SaveFilter
> writer
, bool threaded
)
2915 _sl
.action
= SLA_SAVE
;
2916 return DoSave(writer
, threaded
);
2918 ClearSaveLoadState();
2924 * Determines the SaveLoadFormat that is connected to the given tag.
2925 * When the given tag is known, that format is chosen and a check on the validity of the version is performed.
2926 * Otherwise a fallback to an ancient buggy format using LZO is chosen.
2927 * @param tag The tag from the header describing the savegame compression/format.
2928 * @param raw_version The raw version from the savegame header.
2929 * @return The SaveLoadFormat to use for attempting to open the savegame.
2931 static const SaveLoadFormat
*DetermineSaveLoadFormat(uint32_t tag
, uint32_t raw_version
)
2933 auto fmt
= std::find_if(std::begin(_saveload_formats
), std::end(_saveload_formats
), [tag
](const auto &fmt
) { return fmt
.tag
== tag
; });
2934 if (fmt
!= std::end(_saveload_formats
)) {
2935 /* Check version number */
2936 _sl_version
= (SaveLoadVersion
)(TO_BE32(raw_version
) >> 16);
2937 /* Minor is not used anymore from version 18.0, but it is still needed
2938 * in versions before that (4 cases) which can't be removed easy.
2939 * Therefore it is loaded, but never saved (or, it saves a 0 in any scenario). */
2940 _sl_minor_version
= (TO_BE32(raw_version
) >> 8) & 0xFF;
2942 Debug(sl
, 1, "Loading savegame version {}", _sl_version
);
2944 /* Is the version higher than the current? */
2945 if (_sl_version
> SAVEGAME_VERSION
) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME
);
2946 if (_sl_version
>= SLV_START_PATCHPACKS
&& _sl_version
<= SLV_END_PATCHPACKS
) SlError(STR_GAME_SAVELOAD_ERROR_PATCHPACK
);
2950 Debug(sl
, 0, "Unknown savegame type, trying to load it as the buggy format");
2952 _sl_version
= SL_MIN_VERSION
;
2953 _sl_minor_version
= 0;
2955 /* Try to find the LZO savegame format; it uses 'OTTD' as tag. */
2956 fmt
= std::find_if(std::begin(_saveload_formats
), std::end(_saveload_formats
), [](const auto &fmt
) { return fmt
.tag
== SAVEGAME_TAG_LZO
; });
2957 if (fmt
== std::end(_saveload_formats
)) {
2958 /* Who removed the LZO savegame format definition? When built without LZO support,
2959 * the formats must still list it just without a method to read the file.
2960 * The caller of this function has to check for the existence of load function. */
2967 * Actually perform the loading of a "non-old" savegame.
2968 * @param reader The filter to read the savegame from.
2969 * @param load_check Whether to perform the checking ("preview") or actually load the game.
2970 * @return Return the result of the action. #SL_OK or #SL_REINIT ("unload" the game)
2972 static SaveOrLoadResult
DoLoad(std::shared_ptr
<LoadFilter
> reader
, bool load_check
)
2977 /* Clear previous check data */
2978 _load_check_data
.Clear();
2979 /* Mark SL_LOAD_CHECK as supported for this savegame. */
2980 _load_check_data
.checkable
= true;
2984 if (_sl
.lf
->Read((uint8_t*)hdr
, sizeof(hdr
)) != sizeof(hdr
)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE
);
2986 /* see if we have any loader for this type. */
2987 const SaveLoadFormat
*fmt
= DetermineSaveLoadFormat(hdr
[0], hdr
[1]);
2989 /* loader for this savegame type is not implemented? */
2990 if (fmt
->init_load
== nullptr) {
2991 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR
, fmt::format("Loader for '{}' is not available.", fmt
->name
));
2994 _sl
.lf
= fmt
->init_load(_sl
.lf
);
2995 _sl
.reader
= std::make_unique
<ReadBuffer
>(_sl
.lf
);
2999 ResetSaveloadData();
3001 /* Old maps were hardcoded to 256x256 and thus did not contain
3002 * any mapsize information. Pre-initialize to 256x256 to not to
3003 * confuse old games */
3004 InitializeGame(256, 256, true, true);
3008 if (IsSavegameVersionBefore(SLV_4
)) {
3010 * NewGRFs were introduced between 0.3,4 and 0.3.5, which both
3011 * shared savegame version 4. Anything before that 'obviously'
3012 * does not have any NewGRFs. Between the introduction and
3013 * savegame version 41 (just before 0.5) the NewGRF settings
3014 * were not stored in the savegame and they were loaded by
3015 * using the settings from the main menu.
3017 * - savegame version < 4: do not load any NewGRFs.
3018 * - savegame version >= 41: load NewGRFs from savegame, which is
3019 * already done at this stage by
3020 * overwriting the main menu settings.
3021 * - other savegame versions: use main menu settings.
3023 * This means that users *can* crash savegame version 4..40
3024 * savegames if they set incompatible NewGRFs in the main menu,
3025 * but can't crash anymore for savegame version < 4 savegames.
3027 * Note: this is done here because AfterLoadGame is also called
3028 * for TTO/TTD/TTDP savegames which have their own NewGRF logic.
3030 ClearGRFConfigList(&_grfconfig
);
3035 /* Load chunks into _load_check_data.
3036 * No pools are loaded. References are not possible, and thus do not need resolving. */
3037 SlLoadCheckChunks();
3039 /* Load chunks and resolve references */
3044 ClearSaveLoadState();
3046 _savegame_type
= SGT_OTTD
;
3049 /* The only part from AfterLoadGame() we need */
3050 _load_check_data
.grf_compatibility
= IsGoodGRFConfigList(_load_check_data
.grfconfig
);
3052 _gamelog
.StartAction(GLAT_LOAD
);
3054 /* After loading fix up savegame for any internal changes that
3055 * might have occurred since then. If it fails, load back the old game. */
3056 if (!AfterLoadGame()) {
3057 _gamelog
.StopAction();
3061 _gamelog
.StopAction();
3068 * Load the game using a (reader) filter.
3069 * @param reader The filter to read the savegame from.
3070 * @return Return the result of the action. #SL_OK or #SL_REINIT ("unload" the game)
3072 SaveOrLoadResult
LoadWithFilter(std::shared_ptr
<LoadFilter
> reader
)
3075 _sl
.action
= SLA_LOAD
;
3076 return DoLoad(reader
, false);
3078 ClearSaveLoadState();
3084 * Main Save or Load function where the high-level saveload functions are
3085 * handled. It opens the savegame, selects format and checks versions
3086 * @param filename The name of the savegame being created/loaded
3087 * @param fop Save or load mode. Load can also be a TTD(Patch) game.
3088 * @param sb The sub directory to save the savegame in
3089 * @param threaded True when threaded saving is allowed
3090 * @return Return the result of the action. #SL_OK, #SL_ERROR, or #SL_REINIT ("unload" the game)
3092 SaveOrLoadResult
SaveOrLoad(const std::string
&filename
, SaveLoadOperation fop
, DetailedFileType dft
, Subdirectory sb
, bool threaded
)
3094 /* An instance of saving is already active, so don't go saving again */
3095 if (_sl
.saveinprogress
&& fop
== SLO_SAVE
&& dft
== DFT_GAME_FILE
&& threaded
) {
3096 /* if not an autosave, but a user action, show error message */
3097 if (!_do_autosave
) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS
, INVALID_STRING_ID
, WL_ERROR
);
3103 /* Load a TTDLX or TTDPatch game */
3104 if (fop
== SLO_LOAD
&& dft
== DFT_OLD_GAME_FILE
) {
3105 ResetSaveloadData();
3107 InitializeGame(256, 256, true, true); // set a mapsize of 256x256 for TTDPatch games or it might get confused
3109 /* TTD/TTO savegames have no NewGRFs, TTDP savegame have them
3110 * and if so a new NewGRF list will be made in LoadOldSaveGame.
3111 * Note: this is done here because AfterLoadGame is also called
3112 * for OTTD savegames which have their own NewGRF logic. */
3113 ClearGRFConfigList(&_grfconfig
);
3115 if (!LoadOldSaveGame(filename
)) return SL_REINIT
;
3116 _sl_version
= SL_MIN_VERSION
;
3117 _sl_minor_version
= 0;
3118 _gamelog
.StartAction(GLAT_LOAD
);
3119 if (!AfterLoadGame()) {
3120 _gamelog
.StopAction();
3123 _gamelog
.StopAction();
3127 assert(dft
== DFT_GAME_FILE
);
3130 _sl
.action
= SLA_LOAD_CHECK
;
3134 _sl
.action
= SLA_LOAD
;
3138 _sl
.action
= SLA_SAVE
;
3141 default: NOT_REACHED();
3144 auto fh
= (fop
== SLO_SAVE
) ? FioFOpenFile(filename
, "wb", sb
) : FioFOpenFile(filename
, "rb", sb
);
3146 /* Make it a little easier to load savegames from the console */
3147 if (!fh
.has_value() && fop
!= SLO_SAVE
) fh
= FioFOpenFile(filename
, "rb", SAVE_DIR
);
3148 if (!fh
.has_value() && fop
!= SLO_SAVE
) fh
= FioFOpenFile(filename
, "rb", BASE_DIR
);
3149 if (!fh
.has_value() && fop
!= SLO_SAVE
) fh
= FioFOpenFile(filename
, "rb", SCENARIO_DIR
);
3151 if (!fh
.has_value()) {
3152 SlError(fop
== SLO_SAVE
? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE
: STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE
);
3155 if (fop
== SLO_SAVE
) { // SAVE game
3156 Debug(desync
, 1, "save: {:08x}; {:02x}; {}", TimerGameEconomy::date
, TimerGameEconomy::date_fract
, filename
);
3157 if (!_settings_client
.gui
.threaded_saves
) threaded
= false;
3159 return DoSave(std::make_shared
<FileWriter
>(std::move(*fh
)), threaded
);
3163 assert(fop
== SLO_LOAD
|| fop
== SLO_CHECK
);
3164 Debug(desync
, 1, "load: {}", filename
);
3165 return DoLoad(std::make_shared
<FileReader
>(std::move(*fh
)), fop
== SLO_CHECK
);
3167 /* This code may be executed both for old and new save games. */
3168 ClearSaveLoadState();
3170 /* Skip the "colour" character */
3171 if (fop
!= SLO_CHECK
) Debug(sl
, 0, "{}", GetString(GetSaveLoadErrorType()).substr(3) + GetString(GetSaveLoadErrorMessage()));
3173 /* A saver/loader exception!! reinitialize all variables to prevent crash! */
3174 return (fop
== SLO_LOAD
) ? SL_REINIT
: SL_ERROR
;
3179 * Create an autosave or netsave.
3180 * @param counter A reference to the counter variable to be used for rotating the file name.
3181 * @param netsave Indicates if this is a regular autosave or a netsave.
3183 void DoAutoOrNetsave(FiosNumberedSaveName
&counter
)
3185 std::string filename
;
3187 if (_settings_client
.gui
.keep_all_autosave
) {
3188 filename
= GenerateDefaultSaveName() + counter
.Extension();
3190 filename
= counter
.Filename();
3193 Debug(sl
, 2, "Autosaving to '{}'", filename
);
3194 if (SaveOrLoad(filename
, SLO_SAVE
, DFT_GAME_FILE
, AUTOSAVE_DIR
) != SL_OK
) {
3195 ShowErrorMessage(STR_ERROR_AUTOSAVE_FAILED
, INVALID_STRING_ID
, WL_ERROR
);
3200 /** Do a save when exiting the game (_settings_client.gui.autosave_on_exit) */
3203 SaveOrLoad("exit.sav", SLO_SAVE
, DFT_GAME_FILE
, AUTOSAVE_DIR
);
3207 * Get the default name for a savegame *or* screenshot.
3209 std::string
GenerateDefaultSaveName()
3211 /* Check if we have a name for this map, which is the name of the first
3212 * available company. When there's no company available we'll use
3213 * 'Spectator' as "company" name. */
3214 CompanyID cid
= _local_company
;
3215 if (!Company::IsValidID(cid
)) {
3216 for (const Company
*c
: Company::Iterate()) {
3224 /* We show the current game time differently depending on the timekeeping units used by this game. */
3225 if (TimerGameEconomy::UsingWallclockUnits()) {
3226 /* Insert time played. */
3227 const auto play_time
= TimerGameTick::counter
/ Ticks::TICKS_PER_SECOND
;
3228 SetDParam(1, STR_SAVEGAME_DURATION_REALTIME
);
3229 SetDParam(2, play_time
/ 60 / 60);
3230 SetDParam(3, (play_time
/ 60) % 60);
3232 /* Insert current date */
3233 switch (_settings_client
.gui
.date_format_in_default_names
) {
3234 case 0: SetDParam(1, STR_JUST_DATE_LONG
); break;
3235 case 1: SetDParam(1, STR_JUST_DATE_TINY
); break;
3236 case 2: SetDParam(1, STR_JUST_DATE_ISO
); break;
3237 default: NOT_REACHED();
3239 SetDParam(2, TimerGameEconomy::date
);
3242 /* Get the correct string (special string for when there's not company) */
3243 std::string filename
= GetString(!Company::IsValidID(cid
) ? STR_SAVEGAME_NAME_SPECTATOR
: STR_SAVEGAME_NAME_DEFAULT
);
3244 SanitizeFilename(filename
);
3249 * Set the mode and file type of the file to save or load based on the type of file entry at the file system.
3250 * @param ft Type of file entry of the file system.
3252 void FileToSaveLoad::SetMode(FiosType ft
)
3254 this->SetMode(SLO_LOAD
, GetAbstractFileType(ft
), GetDetailedFileType(ft
));
3258 * Set the mode and file type of the file to save or load.
3259 * @param fop File operation being performed.
3260 * @param aft Abstract file type.
3261 * @param dft Detailed file type.
3263 void FileToSaveLoad::SetMode(SaveLoadOperation fop
, AbstractFileType aft
, DetailedFileType dft
)
3265 if (aft
== FT_INVALID
|| aft
== FT_NONE
) {
3266 this->file_op
= SLO_INVALID
;
3267 this->detail_ftype
= DFT_INVALID
;
3268 this->abstract_ftype
= FT_INVALID
;
3272 this->file_op
= fop
;
3273 this->detail_ftype
= dft
;
3274 this->abstract_ftype
= aft
;
3278 * Set the title of the file.
3279 * @param title Title of the file.
3281 void FileToSaveLoad::Set(const FiosItem
&item
)
3283 this->SetMode(item
.type
);
3284 this->name
= item
.name
;
3285 this->title
= item
.title
;
3288 SaveLoadTable
SaveLoadHandler::GetLoadDescription() const
3290 assert(this->load_description
.has_value());
3291 return *this->load_description
;