1 /*
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/>.
6  */
7 
8 /**
9  * @file saveload.cpp
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):
12  * <ol>
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
20  * </ol>
21  */
22 
23 #include "../stdafx.h"
24 #include "../debug.h"
25 #include "../station_base.h"
26 #include "../thread.h"
27 #include "../town.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 "../date_func.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"
43 #include "../fios.h"
44 #include "../error.h"
45 #include <atomic>
46 #include <deque>
47 #include <vector>
48 #include <string>
49 #ifdef __EMSCRIPTEN__
50 #	include <emscripten.h>
51 #endif
52 
53 #include "table/strings.h"
54 
55 #include "saveload_internal.h"
56 #include "saveload_filter.h"
57 
58 #include "../safeguards.h"
59 
60 extern const SaveLoadVersion SAVEGAME_VERSION = (SaveLoadVersion)(SL_MAX_VERSION - 1); ///< Current savegame version of OpenTTD.
61 
62 SavegameType _savegame_type; ///< type of savegame we are loading
63 FileToSaveLoad _file_to_saveload; ///< File to save or load in the openttd loop.
64 
65 uint32 _ttdp_version;         ///< version of TTDP savegame (if applicable)
66 SaveLoadVersion _sl_version;  ///< the major savegame version identifier
67 byte   _sl_minor_version;     ///< the minor savegame version, DO NOT USE!
68 std::string _savegame_format; ///< how to compress savegames
69 bool _do_autosave;            ///< are we doing an autosave at the moment?
70 
71 /** What are we currently doing? */
72 enum SaveLoadAction {
73 	SLA_LOAD,        ///< loading
74 	SLA_SAVE,        ///< saving
75 	SLA_PTRS,        ///< fixing pointers
76 	SLA_NULL,        ///< null all pointers (on loading error)
77 	SLA_LOAD_CHECK,  ///< partial loading into #_load_check_data
78 };
79 
80 enum NeedLength {
81 	NL_NONE = 0,       ///< not working in NeedLength mode
82 	NL_WANTLENGTH = 1, ///< writing length and data
83 	NL_CALCLENGTH = 2, ///< need to calculate the length
84 };
85 
86 /** Save in chunks of 128 KiB. */
87 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
88 
89 /** A buffer for reading (and buffering) savegame data. */
90 struct ReadBuffer {
91 	byte buf[MEMORY_CHUNK_SIZE]; ///< Buffer we're going to read from.
92 	byte *bufp;                  ///< Location we're at reading the buffer.
93 	byte *bufe;                  ///< End of the buffer we can read from.
94 	LoadFilter *reader;          ///< The filter used to actually read.
95 	size_t read;                 ///< The amount of read bytes so far from the filter.
96 
97 	/**
98 	 * Initialise our variables.
99 	 * @param reader The filter to actually read data.
100 	 */
ReadBufferReadBuffer101 	ReadBuffer(LoadFilter *reader) : bufp(nullptr), bufe(nullptr), reader(reader), read(0)
102 	{
103 	}
104 
ReadByteReadBuffer105 	inline byte ReadByte()
106 	{
107 		if (this->bufp == this->bufe) {
108 			size_t len = this->reader->Read(this->buf, lengthof(this->buf));
109 			if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
110 
111 			this->read += len;
112 			this->bufp = this->buf;
113 			this->bufe = this->buf + len;
114 		}
115 
116 		return *this->bufp++;
117 	}
118 
119 	/**
120 	 * Get the size of the memory dump made so far.
121 	 * @return The size.
122 	 */
GetSizeReadBuffer123 	size_t GetSize() const
124 	{
125 		return this->read - (this->bufe - this->bufp);
126 	}
127 };
128 
129 
130 /** Container for dumping the savegame (quickly) to memory. */
131 struct MemoryDumper {
132 	std::vector<byte *> blocks; ///< Buffer with blocks of allocated memory.
133 	byte *buf;                  ///< Buffer we're going to write to.
134 	byte *bufe;                 ///< End of the buffer we write to.
135 
136 	/** Initialise our variables. */
MemoryDumperMemoryDumper137 	MemoryDumper() : buf(nullptr), bufe(nullptr)
138 	{
139 	}
140 
~MemoryDumperMemoryDumper141 	~MemoryDumper()
142 	{
143 		for (auto p : this->blocks) {
144 			free(p);
145 		}
146 	}
147 
148 	/**
149 	 * Write a single byte into the dumper.
150 	 * @param b The byte to write.
151 	 */
WriteByteMemoryDumper152 	inline void WriteByte(byte b)
153 	{
154 		/* Are we at the end of this chunk? */
155 		if (this->buf == this->bufe) {
156 			this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
157 			this->blocks.push_back(this->buf);
158 			this->bufe = this->buf + MEMORY_CHUNK_SIZE;
159 		}
160 
161 		*this->buf++ = b;
162 	}
163 
164 	/**
165 	 * Flush this dumper into a writer.
166 	 * @param writer The filter we want to use.
167 	 */
FlushMemoryDumper168 	void Flush(SaveFilter *writer)
169 	{
170 		uint i = 0;
171 		size_t t = this->GetSize();
172 
173 		while (t > 0) {
174 			size_t to_write = std::min(MEMORY_CHUNK_SIZE, t);
175 
176 			writer->Write(this->blocks[i++], to_write);
177 			t -= to_write;
178 		}
179 
180 		writer->Finish();
181 	}
182 
183 	/**
184 	 * Get the size of the memory dump made so far.
185 	 * @return The size.
186 	 */
GetSizeMemoryDumper187 	size_t GetSize() const
188 	{
189 		return this->blocks.size() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
190 	}
191 };
192 
193 /** The saveload struct, containing reader-writer functions, buffer, version, etc. */
194 struct SaveLoadParams {
195 	SaveLoadAction action;               ///< are we doing a save or a load atm.
196 	NeedLength need_length;              ///< working in NeedLength (Autolength) mode?
197 	byte block_mode;                     ///< ???
198 	bool error;                          ///< did an error occur or not
199 
200 	size_t obj_len;                      ///< the length of the current object we are busy with
201 	int array_index, last_array_index;   ///< in the case of an array, the current and last positions
202 	bool expect_table_header;            ///< In the case of a table, if the header is saved/loaded.
203 
204 	MemoryDumper *dumper;                ///< Memory dumper to write the savegame to.
205 	SaveFilter *sf;                      ///< Filter to write the savegame to.
206 
207 	ReadBuffer *reader;                  ///< Savegame reading buffer.
208 	LoadFilter *lf;                      ///< Filter to read the savegame from.
209 
210 	StringID error_str;                  ///< the translatable error message to show
211 	char *extra_msg;                     ///< the error message
212 
213 	uint16 game_speed;                   ///< The game speed when saving started.
214 	bool saveinprogress;                 ///< Whether there is currently a save in progress.
215 };
216 
217 static SaveLoadParams _sl; ///< Parameters used for/at saveload.
218 
ChunkHandlers()219 static const std::vector<ChunkHandlerRef> &ChunkHandlers()
220 {
221 	/* These define the chunks */
222 	extern const ChunkHandlerTable _gamelog_chunk_handlers;
223 	extern const ChunkHandlerTable _map_chunk_handlers;
224 	extern const ChunkHandlerTable _misc_chunk_handlers;
225 	extern const ChunkHandlerTable _name_chunk_handlers;
226 	extern const ChunkHandlerTable _cheat_chunk_handlers;
227 	extern const ChunkHandlerTable _setting_chunk_handlers;
228 	extern const ChunkHandlerTable _company_chunk_handlers;
229 	extern const ChunkHandlerTable _engine_chunk_handlers;
230 	extern const ChunkHandlerTable _veh_chunk_handlers;
231 	extern const ChunkHandlerTable _waypoint_chunk_handlers;
232 	extern const ChunkHandlerTable _depot_chunk_handlers;
233 	extern const ChunkHandlerTable _order_chunk_handlers;
234 	extern const ChunkHandlerTable _town_chunk_handlers;
235 	extern const ChunkHandlerTable _sign_chunk_handlers;
236 	extern const ChunkHandlerTable _station_chunk_handlers;
237 	extern const ChunkHandlerTable _industry_chunk_handlers;
238 	extern const ChunkHandlerTable _economy_chunk_handlers;
239 	extern const ChunkHandlerTable _subsidy_chunk_handlers;
240 	extern const ChunkHandlerTable _cargomonitor_chunk_handlers;
241 	extern const ChunkHandlerTable _goal_chunk_handlers;
242 	extern const ChunkHandlerTable _story_page_chunk_handlers;
243 	extern const ChunkHandlerTable _ai_chunk_handlers;
244 	extern const ChunkHandlerTable _game_chunk_handlers;
245 	extern const ChunkHandlerTable _animated_tile_chunk_handlers;
246 	extern const ChunkHandlerTable _newgrf_chunk_handlers;
247 	extern const ChunkHandlerTable _group_chunk_handlers;
248 	extern const ChunkHandlerTable _cargopacket_chunk_handlers;
249 	extern const ChunkHandlerTable _autoreplace_chunk_handlers;
250 	extern const ChunkHandlerTable _labelmaps_chunk_handlers;
251 	extern const ChunkHandlerTable _linkgraph_chunk_handlers;
252 	extern const ChunkHandlerTable _airport_chunk_handlers;
253 	extern const ChunkHandlerTable _object_chunk_handlers;
254 	extern const ChunkHandlerTable _persistent_storage_chunk_handlers;
255 
256 	/** List of all chunks in a savegame. */
257 	static const ChunkHandlerTable _chunk_handler_tables[] = {
258 		_gamelog_chunk_handlers,
259 		_map_chunk_handlers,
260 		_misc_chunk_handlers,
261 		_name_chunk_handlers,
262 		_cheat_chunk_handlers,
263 		_setting_chunk_handlers,
264 		_veh_chunk_handlers,
265 		_waypoint_chunk_handlers,
266 		_depot_chunk_handlers,
267 		_order_chunk_handlers,
268 		_industry_chunk_handlers,
269 		_economy_chunk_handlers,
270 		_subsidy_chunk_handlers,
271 		_cargomonitor_chunk_handlers,
272 		_goal_chunk_handlers,
273 		_story_page_chunk_handlers,
274 		_engine_chunk_handlers,
275 		_town_chunk_handlers,
276 		_sign_chunk_handlers,
277 		_station_chunk_handlers,
278 		_company_chunk_handlers,
279 		_ai_chunk_handlers,
280 		_game_chunk_handlers,
281 		_animated_tile_chunk_handlers,
282 		_newgrf_chunk_handlers,
283 		_group_chunk_handlers,
284 		_cargopacket_chunk_handlers,
285 		_autoreplace_chunk_handlers,
286 		_labelmaps_chunk_handlers,
287 		_linkgraph_chunk_handlers,
288 		_airport_chunk_handlers,
289 		_object_chunk_handlers,
290 		_persistent_storage_chunk_handlers,
291 	};
292 
293 	static std::vector<ChunkHandlerRef> _chunk_handlers;
294 
295 	if (_chunk_handlers.empty()) {
296 		for (auto &chunk_handler_table : _chunk_handler_tables) {
297 			for (auto &chunk_handler : chunk_handler_table) {
298 				_chunk_handlers.push_back(chunk_handler);
299 			}
300 		}
301 	}
302 
303 	return _chunk_handlers;
304 }
305 
306 /** Null all pointers (convert index -> nullptr) */
SlNullPointers()307 static void SlNullPointers()
308 {
309 	_sl.action = SLA_NULL;
310 
311 	/* We don't want any savegame conversion code to run
312 	 * during NULLing; especially those that try to get
313 	 * pointers from other pools. */
314 	_sl_version = SAVEGAME_VERSION;
315 
316 	for (const ChunkHandler &ch : ChunkHandlers()) {
317 		Debug(sl, 3, "Nulling pointers for {:c}{:c}{:c}{:c}", ch.id >> 24, ch.id >> 16, ch.id >> 8, ch.id);
318 		ch.FixPointers();
319 	}
320 
321 	assert(_sl.action == SLA_NULL);
322 }
323 
324 /**
325  * Error handler. Sets everything up to show an error message and to clean
326  * up the mess of a partial savegame load.
327  * @param string The translatable error message to show.
328  * @param extra_msg An extra error message coming from one of the APIs.
329  * @note This function does never return as it throws an exception to
330  *       break out of all the saveload code.
331  */
SlError(StringID string,const char * extra_msg)332 void NORETURN SlError(StringID string, const char *extra_msg)
333 {
334 	/* Distinguish between loading into _load_check_data vs. normal save/load. */
335 	if (_sl.action == SLA_LOAD_CHECK) {
336 		_load_check_data.error = string;
337 		free(_load_check_data.error_data);
338 		_load_check_data.error_data = (extra_msg == nullptr) ? nullptr : stredup(extra_msg);
339 	} else {
340 		_sl.error_str = string;
341 		free(_sl.extra_msg);
342 		_sl.extra_msg = (extra_msg == nullptr) ? nullptr : stredup(extra_msg);
343 	}
344 
345 	/* We have to nullptr all pointers here; we might be in a state where
346 	 * the pointers are actually filled with indices, which means that
347 	 * when we access them during cleaning the pool dereferences of
348 	 * those indices will be made with segmentation faults as result. */
349 	if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
350 
351 	/* Logging could be active. */
352 	GamelogStopAnyAction();
353 
354 	throw std::exception();
355 }
356 
357 /**
358  * Error handler for corrupt savegames. Sets everything up to show the
359  * error message and to clean up the mess of a partial savegame load.
360  * @param msg Location the corruption has been spotted.
361  * @note This function does never return as it throws an exception to
362  *       break out of all the saveload code.
363  */
SlErrorCorrupt(const char * msg)364 void NORETURN SlErrorCorrupt(const char *msg)
365 {
366 	SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
367 }
368 
369 /**
370  * Issue an SlErrorCorrupt with a format string.
371  * @param format format string
372  * @param ... arguments to format string
373  * @note This function does never return as it throws an exception to
374  *       break out of all the saveload code.
375  */
SlErrorCorruptFmt(const char * format,...)376 void NORETURN SlErrorCorruptFmt(const char *format, ...)
377 {
378 	va_list ap;
379 	char msg[256];
380 
381 	va_start(ap, format);
382 	vseprintf(msg, lastof(msg), format, ap);
383 	va_end(ap);
384 
385 	SlErrorCorrupt(msg);
386 }
387 
388 
389 typedef void (*AsyncSaveFinishProc)();                      ///< Callback for when the savegame loading is finished.
390 static std::atomic<AsyncSaveFinishProc> _async_save_finish; ///< Callback to call when the savegame loading is finished.
391 static std::thread _save_thread;                            ///< The thread we're using to compress and write a savegame
392 
393 /**
394  * Called by save thread to tell we finished saving.
395  * @param proc The callback to call when saving is done.
396  */
SetAsyncSaveFinish(AsyncSaveFinishProc proc)397 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
398 {
399 	if (_exit_game) return;
400 	while (_async_save_finish.load(std::memory_order_acquire) != nullptr) CSleep(10);
401 
402 	_async_save_finish.store(proc, std::memory_order_release);
403 }
404 
405 /**
406  * Handle async save finishes.
407  */
ProcessAsyncSaveFinish()408 void ProcessAsyncSaveFinish()
409 {
410 	AsyncSaveFinishProc proc = _async_save_finish.exchange(nullptr, std::memory_order_acq_rel);
411 	if (proc == nullptr) return;
412 
413 	proc();
414 
415 	if (_save_thread.joinable()) {
416 		_save_thread.join();
417 	}
418 }
419 
420 /**
421  * Wrapper for reading a byte from the buffer.
422  * @return The read byte.
423  */
SlReadByte()424 byte SlReadByte()
425 {
426 	return _sl.reader->ReadByte();
427 }
428 
429 /**
430  * Wrapper for writing a byte to the dumper.
431  * @param b The byte to write.
432  */
SlWriteByte(byte b)433 void SlWriteByte(byte b)
434 {
435 	_sl.dumper->WriteByte(b);
436 }
437 
SlReadUint16()438 static inline int SlReadUint16()
439 {
440 	int x = SlReadByte() << 8;
441 	return x | SlReadByte();
442 }
443 
SlReadUint32()444 static inline uint32 SlReadUint32()
445 {
446 	uint32 x = SlReadUint16() << 16;
447 	return x | SlReadUint16();
448 }
449 
SlReadUint64()450 static inline uint64 SlReadUint64()
451 {
452 	uint32 x = SlReadUint32();
453 	uint32 y = SlReadUint32();
454 	return (uint64)x << 32 | y;
455 }
456 
SlWriteUint16(uint16 v)457 static inline void SlWriteUint16(uint16 v)
458 {
459 	SlWriteByte(GB(v, 8, 8));
460 	SlWriteByte(GB(v, 0, 8));
461 }
462 
SlWriteUint32(uint32 v)463 static inline void SlWriteUint32(uint32 v)
464 {
465 	SlWriteUint16(GB(v, 16, 16));
466 	SlWriteUint16(GB(v,  0, 16));
467 }
468 
SlWriteUint64(uint64 x)469 static inline void SlWriteUint64(uint64 x)
470 {
471 	SlWriteUint32((uint32)(x >> 32));
472 	SlWriteUint32((uint32)x);
473 }
474 
475 /**
476  * Read in the header descriptor of an object or an array.
477  * If the highest bit is set (7), then the index is bigger than 127
478  * elements, so use the next byte to read in the real value.
479  * The actual value is then both bytes added with the first shifted
480  * 8 bits to the left, and dropping the highest bit (which only indicated a big index).
481  * x = ((x & 0x7F) << 8) + SlReadByte();
482  * @return Return the value of the index
483  */
SlReadSimpleGamma()484 static uint SlReadSimpleGamma()
485 {
486 	uint i = SlReadByte();
487 	if (HasBit(i, 7)) {
488 		i &= ~0x80;
489 		if (HasBit(i, 6)) {
490 			i &= ~0x40;
491 			if (HasBit(i, 5)) {
492 				i &= ~0x20;
493 				if (HasBit(i, 4)) {
494 					i &= ~0x10;
495 					if (HasBit(i, 3)) {
496 						SlErrorCorrupt("Unsupported gamma");
497 					}
498 					i = SlReadByte(); // 32 bits only.
499 				}
500 				i = (i << 8) | SlReadByte();
501 			}
502 			i = (i << 8) | SlReadByte();
503 		}
504 		i = (i << 8) | SlReadByte();
505 	}
506 	return i;
507 }
508 
509 /**
510  * Write the header descriptor of an object or an array.
511  * If the element is bigger than 127, use 2 bytes for saving
512  * and use the highest byte of the first written one as a notice
513  * that the length consists of 2 bytes, etc.. like this:
514  * 0xxxxxxx
515  * 10xxxxxx xxxxxxxx
516  * 110xxxxx xxxxxxxx xxxxxxxx
517  * 1110xxxx xxxxxxxx xxxxxxxx xxxxxxxx
518  * 11110--- xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
519  * We could extend the scheme ad infinum to support arbitrarily
520  * large chunks, but as sizeof(size_t) == 4 is still very common
521  * we don't support anything above 32 bits. That's why in the last
522  * case the 3 most significant bits are unused.
523  * @param i Index being written
524  */
525 
SlWriteSimpleGamma(size_t i)526 static void SlWriteSimpleGamma(size_t i)
527 {
528 	if (i >= (1 << 7)) {
529 		if (i >= (1 << 14)) {
530 			if (i >= (1 << 21)) {
531 				if (i >= (1 << 28)) {
532 					assert(i <= UINT32_MAX); // We can only support 32 bits for now.
533 					SlWriteByte((byte)(0xF0));
534 					SlWriteByte((byte)(i >> 24));
535 				} else {
536 					SlWriteByte((byte)(0xE0 | (i >> 24)));
537 				}
538 				SlWriteByte((byte)(i >> 16));
539 			} else {
540 				SlWriteByte((byte)(0xC0 | (i >> 16)));
541 			}
542 			SlWriteByte((byte)(i >> 8));
543 		} else {
544 			SlWriteByte((byte)(0x80 | (i >> 8)));
545 		}
546 	}
547 	SlWriteByte((byte)i);
548 }
549 
550 /** Return how many bytes used to encode a gamma value */
SlGetGammaLength(size_t i)551 static inline uint SlGetGammaLength(size_t i)
552 {
553 	return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21)) + (i >= (1 << 28));
554 }
555 
SlReadSparseIndex()556 static inline uint SlReadSparseIndex()
557 {
558 	return SlReadSimpleGamma();
559 }
560 
SlWriteSparseIndex(uint index)561 static inline void SlWriteSparseIndex(uint index)
562 {
563 	SlWriteSimpleGamma(index);
564 }
565 
SlReadArrayLength()566 static inline uint SlReadArrayLength()
567 {
568 	return SlReadSimpleGamma();
569 }
570 
SlWriteArrayLength(size_t length)571 static inline void SlWriteArrayLength(size_t length)
572 {
573 	SlWriteSimpleGamma(length);
574 }
575 
SlGetArrayLength(size_t length)576 static inline uint SlGetArrayLength(size_t length)
577 {
578 	return SlGetGammaLength(length);
579 }
580 
581 /**
582  * Return the type as saved/loaded inside the savegame.
583  */
GetSavegameFileType(const SaveLoad & sld)584 static uint8 GetSavegameFileType(const SaveLoad &sld)
585 {
586 	switch (sld.cmd) {
587 		case SL_VAR:
588 			return GetVarFileType(sld.conv); break;
589 
590 		case SL_STR:
591 		case SL_STDSTR:
592 		case SL_ARR:
593 		case SL_VECTOR:
594 		case SL_DEQUE:
595 			return GetVarFileType(sld.conv) | SLE_FILE_HAS_LENGTH_FIELD; break;
596 
597 		case SL_REF:
598 			return IsSavegameVersionBefore(SLV_69) ? SLE_FILE_U16 : SLE_FILE_U32;
599 
600 		case SL_REFLIST:
601 			return (IsSavegameVersionBefore(SLV_69) ? SLE_FILE_U16 : SLE_FILE_U32) | SLE_FILE_HAS_LENGTH_FIELD;
602 
603 		case SL_SAVEBYTE:
604 			return SLE_FILE_U8;
605 
606 		case SL_STRUCT:
607 		case SL_STRUCTLIST:
608 			return SLE_FILE_STRUCT | SLE_FILE_HAS_LENGTH_FIELD;
609 
610 		default: NOT_REACHED();
611 	}
612 }
613 
614 /**
615  * Return the size in bytes of a certain type of normal/atomic variable
616  * as it appears in memory. See VarTypes
617  * @param conv VarType type of variable that is used for calculating the size
618  * @return Return the size of this type in bytes
619  */
SlCalcConvMemLen(VarType conv)620 static inline uint SlCalcConvMemLen(VarType conv)
621 {
622 	static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
623 
624 	switch (GetVarMemType(conv)) {
625 		case SLE_VAR_STRB:
626 		case SLE_VAR_STR:
627 		case SLE_VAR_STRQ:
628 			return SlReadArrayLength();
629 
630 		default:
631 			uint8 type = GetVarMemType(conv) >> 4;
632 			assert(type < lengthof(conv_mem_size));
633 			return conv_mem_size[type];
634 	}
635 }
636 
637 /**
638  * Return the size in bytes of a certain type of normal/atomic variable
639  * as it appears in a saved game. See VarTypes
640  * @param conv VarType type of variable that is used for calculating the size
641  * @return Return the size of this type in bytes
642  */
SlCalcConvFileLen(VarType conv)643 static inline byte SlCalcConvFileLen(VarType conv)
644 {
645 	static const byte conv_file_size[] = {0, 1, 1, 2, 2, 4, 4, 8, 8, 2};
646 
647 	uint8 type = GetVarFileType(conv);
648 	assert(type < lengthof(conv_file_size));
649 	return conv_file_size[type];
650 }
651 
652 /** Return the size in bytes of a reference (pointer) */
SlCalcRefLen()653 static inline size_t SlCalcRefLen()
654 {
655 	return IsSavegameVersionBefore(SLV_69) ? 2 : 4;
656 }
657 
SlSetArrayIndex(uint index)658 void SlSetArrayIndex(uint index)
659 {
660 	_sl.need_length = NL_WANTLENGTH;
661 	_sl.array_index = index;
662 }
663 
664 static size_t _next_offs;
665 
666 /**
667  * Iterate through the elements of an array and read the whole thing
668  * @return The index of the object, or -1 if we have reached the end of current block
669  */
SlIterateArray()670 int SlIterateArray()
671 {
672 	int index;
673 
674 	/* After reading in the whole array inside the loop
675 	 * we must have read in all the data, so we must be at end of current block. */
676 	if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
677 
678 	for (;;) {
679 		uint length = SlReadArrayLength();
680 		if (length == 0) {
681 			assert(!_sl.expect_table_header);
682 			_next_offs = 0;
683 			return -1;
684 		}
685 
686 		_sl.obj_len = --length;
687 		_next_offs = _sl.reader->GetSize() + length;
688 
689 		if (_sl.expect_table_header) {
690 			_sl.expect_table_header = false;
691 			return INT32_MAX;
692 		}
693 
694 		switch (_sl.block_mode) {
695 			case CH_SPARSE_TABLE:
696 			case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
697 			case CH_TABLE:
698 			case CH_ARRAY:        index = _sl.array_index++; break;
699 			default:
700 				Debug(sl, 0, "SlIterateArray error");
701 				return -1; // error
702 		}
703 
704 		if (length != 0) return index;
705 	}
706 }
707 
708 /**
709  * Skip an array or sparse array
710  */
SlSkipArray()711 void SlSkipArray()
712 {
713 	while (SlIterateArray() != -1) {
714 		SlSkipBytes(_next_offs - _sl.reader->GetSize());
715 	}
716 }
717 
718 /**
719  * Sets the length of either a RIFF object or the number of items in an array.
720  * This lets us load an object or an array of arbitrary size
721  * @param length The length of the sought object/array
722  */
SlSetLength(size_t length)723 void SlSetLength(size_t length)
724 {
725 	assert(_sl.action == SLA_SAVE);
726 
727 	switch (_sl.need_length) {
728 		case NL_WANTLENGTH:
729 			_sl.need_length = NL_NONE;
730 			if ((_sl.block_mode == CH_TABLE || _sl.block_mode == CH_SPARSE_TABLE) && _sl.expect_table_header) {
731 				_sl.expect_table_header = false;
732 				SlWriteArrayLength(length + 1);
733 				break;
734 			}
735 
736 			switch (_sl.block_mode) {
737 				case CH_RIFF:
738 					/* Ugly encoding of >16M RIFF chunks
739 					 * The lower 24 bits are normal
740 					 * The uppermost 4 bits are bits 24:27 */
741 					assert(length < (1 << 28));
742 					SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
743 					break;
744 				case CH_TABLE:
745 				case CH_ARRAY:
746 					assert(_sl.last_array_index <= _sl.array_index);
747 					while (++_sl.last_array_index <= _sl.array_index) {
748 						SlWriteArrayLength(1);
749 					}
750 					SlWriteArrayLength(length + 1);
751 					break;
752 				case CH_SPARSE_TABLE:
753 				case CH_SPARSE_ARRAY:
754 					SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index)); // Also include length of sparse index.
755 					SlWriteSparseIndex(_sl.array_index);
756 					break;
757 				default: NOT_REACHED();
758 			}
759 			break;
760 
761 		case NL_CALCLENGTH:
762 			_sl.obj_len += (int)length;
763 			break;
764 
765 		default: NOT_REACHED();
766 	}
767 }
768 
769 /**
770  * Save/Load bytes. These do not need to be converted to Little/Big Endian
771  * so directly write them or read them to/from file
772  * @param ptr The source or destination of the object being manipulated
773  * @param length number of bytes this fast CopyBytes lasts
774  */
SlCopyBytes(void * ptr,size_t length)775 static void SlCopyBytes(void *ptr, size_t length)
776 {
777 	byte *p = (byte *)ptr;
778 
779 	switch (_sl.action) {
780 		case SLA_LOAD_CHECK:
781 		case SLA_LOAD:
782 			for (; length != 0; length--) *p++ = SlReadByte();
783 			break;
784 		case SLA_SAVE:
785 			for (; length != 0; length--) SlWriteByte(*p++);
786 			break;
787 		default: NOT_REACHED();
788 	}
789 }
790 
791 /** Get the length of the current object */
SlGetFieldLength()792 size_t SlGetFieldLength()
793 {
794 	return _sl.obj_len;
795 }
796 
797 /**
798  * Return a signed-long version of the value of a setting
799  * @param ptr pointer to the variable
800  * @param conv type of variable, can be a non-clean
801  * type, eg one with other flags because it is parsed
802  * @return returns the value of the pointer-setting
803  */
ReadValue(const void * ptr,VarType conv)804 int64 ReadValue(const void *ptr, VarType conv)
805 {
806 	switch (GetVarMemType(conv)) {
807 		case SLE_VAR_BL:  return (*(const bool *)ptr != 0);
808 		case SLE_VAR_I8:  return *(const int8  *)ptr;
809 		case SLE_VAR_U8:  return *(const byte  *)ptr;
810 		case SLE_VAR_I16: return *(const int16 *)ptr;
811 		case SLE_VAR_U16: return *(const uint16*)ptr;
812 		case SLE_VAR_I32: return *(const int32 *)ptr;
813 		case SLE_VAR_U32: return *(const uint32*)ptr;
814 		case SLE_VAR_I64: return *(const int64 *)ptr;
815 		case SLE_VAR_U64: return *(const uint64*)ptr;
816 		case SLE_VAR_NULL:return 0;
817 		default: NOT_REACHED();
818 	}
819 }
820 
821 /**
822  * Write the value of a setting
823  * @param ptr pointer to the variable
824  * @param conv type of variable, can be a non-clean type, eg
825  *             with other flags. It is parsed upon read
826  * @param val the new value being given to the variable
827  */
WriteValue(void * ptr,VarType conv,int64 val)828 void WriteValue(void *ptr, VarType conv, int64 val)
829 {
830 	switch (GetVarMemType(conv)) {
831 		case SLE_VAR_BL:  *(bool  *)ptr = (val != 0);  break;
832 		case SLE_VAR_I8:  *(int8  *)ptr = val; break;
833 		case SLE_VAR_U8:  *(byte  *)ptr = val; break;
834 		case SLE_VAR_I16: *(int16 *)ptr = val; break;
835 		case SLE_VAR_U16: *(uint16*)ptr = val; break;
836 		case SLE_VAR_I32: *(int32 *)ptr = val; break;
837 		case SLE_VAR_U32: *(uint32*)ptr = val; break;
838 		case SLE_VAR_I64: *(int64 *)ptr = val; break;
839 		case SLE_VAR_U64: *(uint64*)ptr = val; break;
840 		case SLE_VAR_NAME: *reinterpret_cast<std::string *>(ptr) = CopyFromOldName(val); break;
841 		case SLE_VAR_NULL: break;
842 		default: NOT_REACHED();
843 	}
844 }
845 
846 /**
847  * Handle all conversion and typechecking of variables here.
848  * In the case of saving, read in the actual value from the struct
849  * and then write them to file, endian safely. Loading a value
850  * goes exactly the opposite way
851  * @param ptr The object being filled/read
852  * @param conv VarType type of the current element of the struct
853  */
SlSaveLoadConv(void * ptr,VarType conv)854 static void SlSaveLoadConv(void *ptr, VarType conv)
855 {
856 	switch (_sl.action) {
857 		case SLA_SAVE: {
858 			int64 x = ReadValue(ptr, conv);
859 
860 			/* Write the value to the file and check if its value is in the desired range */
861 			switch (GetVarFileType(conv)) {
862 				case SLE_FILE_I8: assert(x >= -128 && x <= 127);     SlWriteByte(x);break;
863 				case SLE_FILE_U8: assert(x >= 0 && x <= 255);        SlWriteByte(x);break;
864 				case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
865 				case SLE_FILE_STRINGID:
866 				case SLE_FILE_U16:assert(x >= 0 && x <= 65535);      SlWriteUint16(x);break;
867 				case SLE_FILE_I32:
868 				case SLE_FILE_U32:                                   SlWriteUint32((uint32)x);break;
869 				case SLE_FILE_I64:
870 				case SLE_FILE_U64:                                   SlWriteUint64(x);break;
871 				default: NOT_REACHED();
872 			}
873 			break;
874 		}
875 		case SLA_LOAD_CHECK:
876 		case SLA_LOAD: {
877 			int64 x;
878 			/* Read a value from the file */
879 			switch (GetVarFileType(conv)) {
880 				case SLE_FILE_I8:  x = (int8  )SlReadByte();   break;
881 				case SLE_FILE_U8:  x = (byte  )SlReadByte();   break;
882 				case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
883 				case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
884 				case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
885 				case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
886 				case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
887 				case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
888 				case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
889 				default: NOT_REACHED();
890 			}
891 
892 			/* Write The value to the struct. These ARE endian safe. */
893 			WriteValue(ptr, conv, x);
894 			break;
895 		}
896 		case SLA_PTRS: break;
897 		case SLA_NULL: break;
898 		default: NOT_REACHED();
899 	}
900 }
901 
902 /**
903  * Calculate the net length of a string. This is in almost all cases
904  * just strlen(), but if the string is not properly terminated, we'll
905  * resort to the maximum length of the buffer.
906  * @param ptr pointer to the stringbuffer
907  * @param length maximum length of the string (buffer). If -1 we don't care
908  * about a maximum length, but take string length as it is.
909  * @return return the net length of the string
910  */
SlCalcNetStringLen(const char * ptr,size_t length)911 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
912 {
913 	if (ptr == nullptr) return 0;
914 	return std::min(strlen(ptr), length - 1);
915 }
916 
917 /**
918  * Calculate the gross length of the string that it
919  * will occupy in the savegame. This includes the real length, returned
920  * by SlCalcNetStringLen and the length that the index will occupy.
921  * @param ptr pointer to the stringbuffer
922  * @param length maximum length of the string (buffer size, etc.)
923  * @param conv type of data been used
924  * @return return the gross length of the string
925  */
SlCalcStringLen(const void * ptr,size_t length,VarType conv)926 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
927 {
928 	size_t len;
929 	const char *str;
930 
931 	switch (GetVarMemType(conv)) {
932 		default: NOT_REACHED();
933 		case SLE_VAR_STR:
934 		case SLE_VAR_STRQ:
935 			str = *(const char * const *)ptr;
936 			len = SIZE_MAX;
937 			break;
938 		case SLE_VAR_STRB:
939 			str = (const char *)ptr;
940 			len = length;
941 			break;
942 	}
943 
944 	len = SlCalcNetStringLen(str, len);
945 	return len + SlGetArrayLength(len); // also include the length of the index
946 }
947 
948 /**
949  * Calculate the gross length of the string that it
950  * will occupy in the savegame. This includes the real length, returned
951  * by SlCalcNetStringLen and the length that the index will occupy.
952  * @param ptr Pointer to the \c std::string.
953  * @return The gross length of the string.
954  */
SlCalcStdStringLen(const void * ptr)955 static inline size_t SlCalcStdStringLen(const void *ptr)
956 {
957 	const std::string *str = reinterpret_cast<const std::string *>(ptr);
958 
959 	size_t len = str->length();
960 	return len + SlGetArrayLength(len); // also include the length of the index
961 }
962 
963 /**
964  * Save/Load a string.
965  * @param ptr the string being manipulated
966  * @param length of the string (full length)
967  * @param conv must be SLE_FILE_STRING
968  */
SlString(void * ptr,size_t length,VarType conv)969 static void SlString(void *ptr, size_t length, VarType conv)
970 {
971 	switch (_sl.action) {
972 		case SLA_SAVE: {
973 			size_t len;
974 			switch (GetVarMemType(conv)) {
975 				default: NOT_REACHED();
976 				case SLE_VAR_STRB:
977 					len = SlCalcNetStringLen((char *)ptr, length);
978 					break;
979 				case SLE_VAR_STR:
980 				case SLE_VAR_STRQ:
981 					ptr = *(char **)ptr;
982 					len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
983 					break;
984 			}
985 
986 			SlWriteArrayLength(len);
987 			SlCopyBytes(ptr, len);
988 			break;
989 		}
990 		case SLA_LOAD_CHECK:
991 		case SLA_LOAD: {
992 			size_t len = SlReadArrayLength();
993 
994 			switch (GetVarMemType(conv)) {
995 				default: NOT_REACHED();
996 				case SLE_VAR_NULL:
997 					SlSkipBytes(len);
998 					return;
999 				case SLE_VAR_STRB:
1000 					if (len >= length) {
1001 						Debug(sl, 1, "String length in savegame is bigger than buffer, truncating");
1002 						SlCopyBytes(ptr, length);
1003 						SlSkipBytes(len - length);
1004 						len = length - 1;
1005 					} else {
1006 						SlCopyBytes(ptr, len);
1007 					}
1008 					break;
1009 				case SLE_VAR_STR:
1010 				case SLE_VAR_STRQ: // Malloc'd string, free previous incarnation, and allocate
1011 					free(*(char **)ptr);
1012 					if (len == 0) {
1013 						*(char **)ptr = nullptr;
1014 						return;
1015 					} else {
1016 						*(char **)ptr = MallocT<char>(len + 1); // terminating '\0'
1017 						ptr = *(char **)ptr;
1018 						SlCopyBytes(ptr, len);
1019 					}
1020 					break;
1021 			}
1022 
1023 			((char *)ptr)[len] = '\0'; // properly terminate the string
1024 			StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
1025 			if ((conv & SLF_ALLOW_CONTROL) != 0) {
1026 				settings = settings | SVS_ALLOW_CONTROL_CODE;
1027 				if (IsSavegameVersionBefore(SLV_169)) {
1028 					str_fix_scc_encoded((char *)ptr, (char *)ptr + len);
1029 				}
1030 			}
1031 			if ((conv & SLF_ALLOW_NEWLINE) != 0) {
1032 				settings = settings | SVS_ALLOW_NEWLINE;
1033 			}
1034 			StrMakeValidInPlace((char *)ptr, (char *)ptr + len, settings);
1035 			break;
1036 		}
1037 		case SLA_PTRS: break;
1038 		case SLA_NULL: break;
1039 		default: NOT_REACHED();
1040 	}
1041 }
1042 
1043 /**
1044  * Save/Load a \c std::string.
1045  * @param ptr the string being manipulated
1046  * @param conv must be SLE_FILE_STRING
1047  */
SlStdString(void * ptr,VarType conv)1048 static void SlStdString(void *ptr, VarType conv)
1049 {
1050 	std::string *str = reinterpret_cast<std::string *>(ptr);
1051 
1052 	switch (_sl.action) {
1053 		case SLA_SAVE: {
1054 			size_t len = str->length();
1055 			SlWriteArrayLength(len);
1056 			SlCopyBytes(const_cast<void *>(static_cast<const void *>(str->c_str())), len);
1057 			break;
1058 		}
1059 
1060 		case SLA_LOAD_CHECK:
1061 		case SLA_LOAD: {
1062 			size_t len = SlReadArrayLength();
1063 			if (GetVarMemType(conv) == SLE_VAR_NULL) {
1064 				SlSkipBytes(len);
1065 				return;
1066 			}
1067 
1068 			char *buf = AllocaM(char, len + 1);
1069 			SlCopyBytes(buf, len);
1070 			buf[len] = '\0'; // properly terminate the string
1071 
1072 			StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
1073 			if ((conv & SLF_ALLOW_CONTROL) != 0) {
1074 				settings = settings | SVS_ALLOW_CONTROL_CODE;
1075 				if (IsSavegameVersionBefore(SLV_169)) {
1076 					str_fix_scc_encoded(buf, buf + len);
1077 				}
1078 			}
1079 			if ((conv & SLF_ALLOW_NEWLINE) != 0) {
1080 				settings = settings | SVS_ALLOW_NEWLINE;
1081 			}
1082 			StrMakeValidInPlace(buf, buf + len, settings);
1083 
1084 			// Store sanitized string.
1085 			str->assign(buf);
1086 		}
1087 
1088 		case SLA_PTRS: break;
1089 		case SLA_NULL: break;
1090 		default: NOT_REACHED();
1091 	}
1092 }
1093 
1094 /**
1095  * Internal function to save/Load a list of SL_VARs.
1096  * SlCopy() and SlArray() are very similar, with the exception of the header.
1097  * This function represents the common part.
1098  * @param object The object being manipulated.
1099  * @param length The length of the object in elements
1100  * @param conv VarType type of the items.
1101  */
SlCopyInternal(void * object,size_t length,VarType conv)1102 static void SlCopyInternal(void *object, size_t length, VarType conv)
1103 {
1104 	if (GetVarMemType(conv) == SLE_VAR_NULL) {
1105 		assert(_sl.action != SLA_SAVE); // Use SL_NULL if you want to write null-bytes
1106 		SlSkipBytes(length * SlCalcConvFileLen(conv));
1107 		return;
1108 	}
1109 
1110 	/* NOTICE - handle some buggy stuff, in really old versions everything was saved
1111 	 * as a byte-type. So detect this, and adjust object size accordingly */
1112 	if (_sl.action != SLA_SAVE && _sl_version == 0) {
1113 		/* all objects except difficulty settings */
1114 		if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
1115 				conv == SLE_INT32 || conv == SLE_UINT32) {
1116 			SlCopyBytes(object, length * SlCalcConvFileLen(conv));
1117 			return;
1118 		}
1119 		/* used for conversion of Money 32bit->64bit */
1120 		if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
1121 			for (uint i = 0; i < length; i++) {
1122 				((int64*)object)[i] = (int32)BSWAP32(SlReadUint32());
1123 			}
1124 			return;
1125 		}
1126 	}
1127 
1128 	/* If the size of elements is 1 byte both in file and memory, no special
1129 	 * conversion is needed, use specialized copy-copy function to speed up things */
1130 	if (conv == SLE_INT8 || conv == SLE_UINT8) {
1131 		SlCopyBytes(object, length);
1132 	} else {
1133 		byte *a = (byte*)object;
1134 		byte mem_size = SlCalcConvMemLen(conv);
1135 
1136 		for (; length != 0; length --) {
1137 			SlSaveLoadConv(a, conv);
1138 			a += mem_size; // get size
1139 		}
1140 	}
1141 }
1142 
1143 /**
1144  * Copy a list of SL_VARs to/from a savegame.
1145  * These entries are copied as-is, and you as caller have to make sure things
1146  * like length-fields are calculated correctly.
1147  * @param object The object being manipulated.
1148  * @param length The length of the object in elements
1149  * @param conv VarType type of the items.
1150  */
SlCopy(void * object,size_t length,VarType conv)1151 void SlCopy(void *object, size_t length, VarType conv)
1152 {
1153 	if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
1154 
1155 	/* Automatically calculate the length? */
1156 	if (_sl.need_length != NL_NONE) {
1157 		SlSetLength(length * SlCalcConvFileLen(conv));
1158 		/* Determine length only? */
1159 		if (_sl.need_length == NL_CALCLENGTH) return;
1160 	}
1161 
1162 	SlCopyInternal(object, length, conv);
1163 }
1164 
1165 /**
1166  * Return the size in bytes of a certain type of atomic array
1167  * @param length The length of the array counted in elements
1168  * @param conv VarType type of the variable that is used in calculating the size
1169  */
SlCalcArrayLen(size_t length,VarType conv)1170 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
1171 {
1172 	return SlCalcConvFileLen(conv) * length + SlGetArrayLength(length);
1173 }
1174 
1175 /**
1176  * Save/Load the length of the array followed by the array of SL_VAR elements.
1177  * @param array The array being manipulated
1178  * @param length The length of the array in elements
1179  * @param conv VarType type of the atomic array (int, byte, uint64, etc.)
1180  */
SlArray(void * array,size_t length,VarType conv)1181 static void SlArray(void *array, size_t length, VarType conv)
1182 {
1183 	switch (_sl.action) {
1184 		case SLA_SAVE:
1185 			SlWriteArrayLength(length);
1186 			SlCopyInternal(array, length, conv);
1187 			return;
1188 
1189 		case SLA_LOAD_CHECK:
1190 		case SLA_LOAD: {
1191 			if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) {
1192 				size_t sv_length = SlReadArrayLength();
1193 				if (GetVarMemType(conv) == SLE_VAR_NULL) {
1194 					/* We don't know this field, so we assume the length in the savegame is correct. */
1195 					length = sv_length;
1196 				} else if (sv_length != length) {
1197 					/* If the SLE_ARR changes size, a savegame bump is required
1198 					 * and the developer should have written conversion lines.
1199 					 * Error out to make this more visible. */
1200 					SlErrorCorrupt("Fixed-length array is of wrong length");
1201 				}
1202 			}
1203 
1204 			SlCopyInternal(array, length, conv);
1205 			return;
1206 		}
1207 
1208 		case SLA_PTRS:
1209 		case SLA_NULL:
1210 			return;
1211 
1212 		default:
1213 			NOT_REACHED();
1214 	}
1215 }
1216 
1217 /**
1218  * Pointers cannot be saved to a savegame, so this functions gets
1219  * the index of the item, and if not available, it hussles with
1220  * pointers (looks really bad :()
1221  * Remember that a nullptr item has value 0, and all
1222  * indices have +1, so vehicle 0 is saved as index 1.
1223  * @param obj The object that we want to get the index of
1224  * @param rt SLRefType type of the object the index is being sought of
1225  * @return Return the pointer converted to an index of the type pointed to
1226  */
ReferenceToInt(const void * obj,SLRefType rt)1227 static size_t ReferenceToInt(const void *obj, SLRefType rt)
1228 {
1229 	assert(_sl.action == SLA_SAVE);
1230 
1231 	if (obj == nullptr) return 0;
1232 
1233 	switch (rt) {
1234 		case REF_VEHICLE_OLD: // Old vehicles we save as new ones
1235 		case REF_VEHICLE:   return ((const  Vehicle*)obj)->index + 1;
1236 		case REF_STATION:   return ((const  Station*)obj)->index + 1;
1237 		case REF_TOWN:      return ((const     Town*)obj)->index + 1;
1238 		case REF_ORDER:     return ((const    Order*)obj)->index + 1;
1239 		case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
1240 		case REF_ENGINE_RENEWS:  return ((const       EngineRenew*)obj)->index + 1;
1241 		case REF_CARGO_PACKET:   return ((const       CargoPacket*)obj)->index + 1;
1242 		case REF_ORDERLIST:      return ((const         OrderList*)obj)->index + 1;
1243 		case REF_STORAGE:        return ((const PersistentStorage*)obj)->index + 1;
1244 		case REF_LINK_GRAPH:     return ((const         LinkGraph*)obj)->index + 1;
1245 		case REF_LINK_GRAPH_JOB: return ((const      LinkGraphJob*)obj)->index + 1;
1246 		default: NOT_REACHED();
1247 	}
1248 }
1249 
1250 /**
1251  * Pointers cannot be loaded from a savegame, so this function
1252  * gets the index from the savegame and returns the appropriate
1253  * pointer from the already loaded base.
1254  * Remember that an index of 0 is a nullptr pointer so all indices
1255  * are +1 so vehicle 0 is saved as 1.
1256  * @param index The index that is being converted to a pointer
1257  * @param rt SLRefType type of the object the pointer is sought of
1258  * @return Return the index converted to a pointer of any type
1259  */
IntToReference(size_t index,SLRefType rt)1260 static void *IntToReference(size_t index, SLRefType rt)
1261 {
1262 	static_assert(sizeof(size_t) <= sizeof(void *));
1263 
1264 	assert(_sl.action == SLA_PTRS);
1265 
1266 	/* After version 4.3 REF_VEHICLE_OLD is saved as REF_VEHICLE,
1267 	 * and should be loaded like that */
1268 	if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(SLV_4, 4)) {
1269 		rt = REF_VEHICLE;
1270 	}
1271 
1272 	/* No need to look up nullptr pointers, just return immediately */
1273 	if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return nullptr;
1274 
1275 	/* Correct index. Old vehicles were saved differently:
1276 	 * invalid vehicle was 0xFFFF, now we use 0x0000 for everything invalid. */
1277 	if (rt != REF_VEHICLE_OLD) index--;
1278 
1279 	switch (rt) {
1280 		case REF_ORDERLIST:
1281 			if (OrderList::IsValidID(index)) return OrderList::Get(index);
1282 			SlErrorCorrupt("Referencing invalid OrderList");
1283 
1284 		case REF_ORDER:
1285 			if (Order::IsValidID(index)) return Order::Get(index);
1286 			/* in old versions, invalid order was used to mark end of order list */
1287 			if (IsSavegameVersionBefore(SLV_5, 2)) return nullptr;
1288 			SlErrorCorrupt("Referencing invalid Order");
1289 
1290 		case REF_VEHICLE_OLD:
1291 		case REF_VEHICLE:
1292 			if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
1293 			SlErrorCorrupt("Referencing invalid Vehicle");
1294 
1295 		case REF_STATION:
1296 			if (Station::IsValidID(index)) return Station::Get(index);
1297 			SlErrorCorrupt("Referencing invalid Station");
1298 
1299 		case REF_TOWN:
1300 			if (Town::IsValidID(index)) return Town::Get(index);
1301 			SlErrorCorrupt("Referencing invalid Town");
1302 
1303 		case REF_ROADSTOPS:
1304 			if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
1305 			SlErrorCorrupt("Referencing invalid RoadStop");
1306 
1307 		case REF_ENGINE_RENEWS:
1308 			if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
1309 			SlErrorCorrupt("Referencing invalid EngineRenew");
1310 
1311 		case REF_CARGO_PACKET:
1312 			if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
1313 			SlErrorCorrupt("Referencing invalid CargoPacket");
1314 
1315 		case REF_STORAGE:
1316 			if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index);
1317 			SlErrorCorrupt("Referencing invalid PersistentStorage");
1318 
1319 		case REF_LINK_GRAPH:
1320 			if (LinkGraph::IsValidID(index)) return LinkGraph::Get(index);
1321 			SlErrorCorrupt("Referencing invalid LinkGraph");
1322 
1323 		case REF_LINK_GRAPH_JOB:
1324 			if (LinkGraphJob::IsValidID(index)) return LinkGraphJob::Get(index);
1325 			SlErrorCorrupt("Referencing invalid LinkGraphJob");
1326 
1327 		default: NOT_REACHED();
1328 	}
1329 }
1330 
1331 /**
1332  * Handle conversion for references.
1333  * @param ptr The object being filled/read.
1334  * @param conv VarType type of the current element of the struct.
1335  */
SlSaveLoadRef(void * ptr,VarType conv)1336 void SlSaveLoadRef(void *ptr, VarType conv)
1337 {
1338 	switch (_sl.action) {
1339 		case SLA_SAVE:
1340 			SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
1341 			break;
1342 		case SLA_LOAD_CHECK:
1343 		case SLA_LOAD:
1344 			*(size_t *)ptr = IsSavegameVersionBefore(SLV_69) ? SlReadUint16() : SlReadUint32();
1345 			break;
1346 		case SLA_PTRS:
1347 			*(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
1348 			break;
1349 		case SLA_NULL:
1350 			*(void **)ptr = nullptr;
1351 			break;
1352 		default: NOT_REACHED();
1353 	}
1354 }
1355 
1356 /**
1357  * Template class to help with list-like types.
1358  */
1359 template <template<typename, typename> typename Tstorage, typename Tvar, typename Tallocator = std::allocator<Tvar>>
1360 class SlStorageHelper {
1361 	typedef Tstorage<Tvar, Tallocator> SlStorageT;
1362 public:
1363 	/**
1364 	 * Internal templated helper to return the size in bytes of a list-like type.
1365 	 * @param storage The storage to find the size of
1366 	 * @param conv VarType type of variable that is used for calculating the size
1367 	 * @param cmd The SaveLoadType ware are saving/loading.
1368 	 */
SlCalcLen(const void * storage,VarType conv,SaveLoadType cmd=SL_VAR)1369 	static size_t SlCalcLen(const void *storage, VarType conv, SaveLoadType cmd = SL_VAR)
1370 	{
1371 		assert(cmd == SL_VAR || cmd == SL_REF);
1372 
1373 		const SlStorageT *list = static_cast<const SlStorageT *>(storage);
1374 
1375 		int type_size = SlGetArrayLength(list->size());
1376 		int item_size = SlCalcConvFileLen(cmd == SL_VAR ? conv : (VarType)SLE_FILE_U32);
1377 		return list->size() * item_size + type_size;
1378 	}
1379 
SlSaveLoadMember(SaveLoadType cmd,Tvar * item,VarType conv)1380 	static void SlSaveLoadMember(SaveLoadType cmd, Tvar *item, VarType conv)
1381 	{
1382 		switch (cmd) {
1383 			case SL_VAR: SlSaveLoadConv(item, conv); break;
1384 			case SL_REF: SlSaveLoadRef(item, conv); break;
1385 			default:
1386 				NOT_REACHED();
1387 		}
1388 	}
1389 
1390 	/**
1391 	 * Internal templated helper to save/load a list-like type.
1392 	 * @param storage The storage being manipulated.
1393 	 * @param conv VarType type of variable that is used for calculating the size.
1394 	 * @param cmd The SaveLoadType ware are saving/loading.
1395 	 */
SlSaveLoad(void * storage,VarType conv,SaveLoadType cmd=SL_VAR)1396 	static void SlSaveLoad(void *storage, VarType conv, SaveLoadType cmd = SL_VAR)
1397 	{
1398 		assert(cmd == SL_VAR || cmd == SL_REF);
1399 
1400 		SlStorageT *list = static_cast<SlStorageT *>(storage);
1401 
1402 		switch (_sl.action) {
1403 			case SLA_SAVE:
1404 				SlWriteArrayLength(list->size());
1405 
1406 				for (auto &item : *list) {
1407 					SlSaveLoadMember(cmd, &item, conv);
1408 				}
1409 				break;
1410 
1411 			case SLA_LOAD_CHECK:
1412 			case SLA_LOAD: {
1413 				size_t length;
1414 				switch (cmd) {
1415 					case SL_VAR: length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? SlReadUint32() : SlReadArrayLength(); break;
1416 					case SL_REF: length = IsSavegameVersionBefore(SLV_69) ? SlReadUint16() : IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? SlReadUint32() : SlReadArrayLength(); break;
1417 					default: NOT_REACHED();
1418 				}
1419 
1420 				/* Load each value and push to the end of the storage. */
1421 				for (size_t i = 0; i < length; i++) {
1422 					Tvar &data = list->emplace_back();
1423 					SlSaveLoadMember(cmd, &data, conv);
1424 				}
1425 				break;
1426 			}
1427 
1428 			case SLA_PTRS:
1429 				for (auto &item : *list) {
1430 					SlSaveLoadMember(cmd, &item, conv);
1431 				}
1432 				break;
1433 
1434 			case SLA_NULL:
1435 				list->clear();
1436 				break;
1437 
1438 			default: NOT_REACHED();
1439 		}
1440 	}
1441 };
1442 
1443 /**
1444  * Return the size in bytes of a list.
1445  * @param list The std::list to find the size of.
1446  * @param conv VarType type of variable that is used for calculating the size.
1447  */
SlCalcRefListLen(const void * list,VarType conv)1448 static inline size_t SlCalcRefListLen(const void *list, VarType conv)
1449 {
1450 	return SlStorageHelper<std::list, void *>::SlCalcLen(list, conv, SL_REF);
1451 }
1452 
1453 /**
1454  * Save/Load a list.
1455  * @param list The list being manipulated.
1456  * @param conv VarType type of variable that is used for calculating the size.
1457  */
SlRefList(void * list,VarType conv)1458 static void SlRefList(void *list, VarType conv)
1459 {
1460 	/* Automatically calculate the length? */
1461 	if (_sl.need_length != NL_NONE) {
1462 		SlSetLength(SlCalcRefListLen(list, conv));
1463 		/* Determine length only? */
1464 		if (_sl.need_length == NL_CALCLENGTH) return;
1465 	}
1466 
1467 	SlStorageHelper<std::list, void *>::SlSaveLoad(list, conv, SL_REF);
1468 }
1469 
1470 /**
1471  * Return the size in bytes of a std::deque.
1472  * @param deque The std::deque to find the size of
1473  * @param conv VarType type of variable that is used for calculating the size
1474  */
SlCalcDequeLen(const void * deque,VarType conv)1475 static inline size_t SlCalcDequeLen(const void *deque, VarType conv)
1476 {
1477 	switch (GetVarMemType(conv)) {
1478 		case SLE_VAR_BL: return SlStorageHelper<std::deque, bool>::SlCalcLen(deque, conv);
1479 		case SLE_VAR_I8: return SlStorageHelper<std::deque, int8>::SlCalcLen(deque, conv);
1480 		case SLE_VAR_U8: return SlStorageHelper<std::deque, uint8>::SlCalcLen(deque, conv);
1481 		case SLE_VAR_I16: return SlStorageHelper<std::deque, int16>::SlCalcLen(deque, conv);
1482 		case SLE_VAR_U16: return SlStorageHelper<std::deque, uint16>::SlCalcLen(deque, conv);
1483 		case SLE_VAR_I32: return SlStorageHelper<std::deque, int32>::SlCalcLen(deque, conv);
1484 		case SLE_VAR_U32: return SlStorageHelper<std::deque, uint32>::SlCalcLen(deque, conv);
1485 		case SLE_VAR_I64: return SlStorageHelper<std::deque, int64>::SlCalcLen(deque, conv);
1486 		case SLE_VAR_U64: return SlStorageHelper<std::deque, uint64>::SlCalcLen(deque, conv);
1487 		default: NOT_REACHED();
1488 	}
1489 }
1490 
1491 /**
1492  * Save/load a std::deque.
1493  * @param deque The std::deque being manipulated
1494  * @param conv VarType type of variable that is used for calculating the size
1495  */
SlDeque(void * deque,VarType conv)1496 static void SlDeque(void *deque, VarType conv)
1497 {
1498 	switch (GetVarMemType(conv)) {
1499 		case SLE_VAR_BL: SlStorageHelper<std::deque, bool>::SlSaveLoad(deque, conv); break;
1500 		case SLE_VAR_I8: SlStorageHelper<std::deque, int8>::SlSaveLoad(deque, conv); break;
1501 		case SLE_VAR_U8: SlStorageHelper<std::deque, uint8>::SlSaveLoad(deque, conv); break;
1502 		case SLE_VAR_I16: SlStorageHelper<std::deque, int16>::SlSaveLoad(deque, conv); break;
1503 		case SLE_VAR_U16: SlStorageHelper<std::deque, uint16>::SlSaveLoad(deque, conv); break;
1504 		case SLE_VAR_I32: SlStorageHelper<std::deque, int32>::SlSaveLoad(deque, conv); break;
1505 		case SLE_VAR_U32: SlStorageHelper<std::deque, uint32>::SlSaveLoad(deque, conv); break;
1506 		case SLE_VAR_I64: SlStorageHelper<std::deque, int64>::SlSaveLoad(deque, conv); break;
1507 		case SLE_VAR_U64: SlStorageHelper<std::deque, uint64>::SlSaveLoad(deque, conv); break;
1508 		default: NOT_REACHED();
1509 	}
1510 }
1511 
1512 /**
1513  * Return the size in bytes of a std::vector.
1514  * @param vector The std::vector to find the size of
1515  * @param conv VarType type of variable that is used for calculating the size
1516  */
SlCalcVectorLen(const void * vector,VarType conv)1517 static inline size_t SlCalcVectorLen(const void *vector, VarType conv)
1518 {
1519 	switch (GetVarMemType(conv)) {
1520 		case SLE_VAR_BL: NOT_REACHED(); // Not supported
1521 		case SLE_VAR_I8: return SlStorageHelper<std::vector, int8>::SlCalcLen(vector, conv);
1522 		case SLE_VAR_U8: return SlStorageHelper<std::vector, uint8>::SlCalcLen(vector, conv);
1523 		case SLE_VAR_I16: return SlStorageHelper<std::vector, int16>::SlCalcLen(vector, conv);
1524 		case SLE_VAR_U16: return SlStorageHelper<std::vector, uint16>::SlCalcLen(vector, conv);
1525 		case SLE_VAR_I32: return SlStorageHelper<std::vector, int32>::SlCalcLen(vector, conv);
1526 		case SLE_VAR_U32: return SlStorageHelper<std::vector, uint32>::SlCalcLen(vector, conv);
1527 		case SLE_VAR_I64: return SlStorageHelper<std::vector, int64>::SlCalcLen(vector, conv);
1528 		case SLE_VAR_U64: return SlStorageHelper<std::vector, uint64>::SlCalcLen(vector, conv);
1529 		default: NOT_REACHED();
1530 	}
1531 }
1532 
1533 /**
1534  * Save/load a std::vector.
1535  * @param vector The std::vector being manipulated
1536  * @param conv VarType type of variable that is used for calculating the size
1537  */
SlVector(void * vector,VarType conv)1538 static void SlVector(void *vector, VarType conv)
1539 {
1540 	switch (GetVarMemType(conv)) {
1541 		case SLE_VAR_BL: NOT_REACHED(); // Not supported
1542 		case SLE_VAR_I8: SlStorageHelper<std::vector, int8>::SlSaveLoad(vector, conv); break;
1543 		case SLE_VAR_U8: SlStorageHelper<std::vector, uint8>::SlSaveLoad(vector, conv); break;
1544 		case SLE_VAR_I16: SlStorageHelper<std::vector, int16>::SlSaveLoad(vector, conv); break;
1545 		case SLE_VAR_U16: SlStorageHelper<std::vector, uint16>::SlSaveLoad(vector, conv); break;
1546 		case SLE_VAR_I32: SlStorageHelper<std::vector, int32>::SlSaveLoad(vector, conv); break;
1547 		case SLE_VAR_U32: SlStorageHelper<std::vector, uint32>::SlSaveLoad(vector, conv); break;
1548 		case SLE_VAR_I64: SlStorageHelper<std::vector, int64>::SlSaveLoad(vector, conv); break;
1549 		case SLE_VAR_U64: SlStorageHelper<std::vector, uint64>::SlSaveLoad(vector, conv); break;
1550 		default: NOT_REACHED();
1551 	}
1552 }
1553 
1554 /** Are we going to save this object or not? */
SlIsObjectValidInSavegame(const SaveLoad & sld)1555 static inline bool SlIsObjectValidInSavegame(const SaveLoad &sld)
1556 {
1557 	return (_sl_version >= sld.version_from && _sl_version < sld.version_to);
1558 }
1559 
1560 /**
1561  * Calculate the size of the table header.
1562  * @param slt The SaveLoad table with objects to save/load.
1563  * @return size of given object.
1564  */
SlCalcTableHeader(const SaveLoadTable & slt)1565 static size_t SlCalcTableHeader(const SaveLoadTable &slt)
1566 {
1567 	size_t length = 0;
1568 
1569 	for (auto &sld : slt) {
1570 		if (!SlIsObjectValidInSavegame(sld)) continue;
1571 
1572 		length += SlCalcConvFileLen(SLE_UINT8);
1573 		length += SlCalcStdStringLen(&sld.name);
1574 	}
1575 
1576 	length += SlCalcConvFileLen(SLE_UINT8); // End-of-list entry.
1577 
1578 	for (auto &sld : slt) {
1579 		if (!SlIsObjectValidInSavegame(sld)) continue;
1580 		if (sld.cmd == SL_STRUCTLIST || sld.cmd == SL_STRUCT) {
1581 			length += SlCalcTableHeader(sld.handler->GetDescription());
1582 		}
1583 	}
1584 
1585 	return length;
1586 }
1587 
1588 /**
1589  * Calculate the size of an object.
1590  * @param object to be measured.
1591  * @param slt The SaveLoad table with objects to save/load.
1592  * @return size of given object.
1593  */
SlCalcObjLength(const void * object,const SaveLoadTable & slt)1594 size_t SlCalcObjLength(const void *object, const SaveLoadTable &slt)
1595 {
1596 	size_t length = 0;
1597 
1598 	/* Need to determine the length and write a length tag. */
1599 	for (auto &sld : slt) {
1600 		length += SlCalcObjMemberLength(object, sld);
1601 	}
1602 	return length;
1603 }
1604 
SlCalcObjMemberLength(const void * object,const SaveLoad & sld)1605 size_t SlCalcObjMemberLength(const void *object, const SaveLoad &sld)
1606 {
1607 	assert(_sl.action == SLA_SAVE);
1608 
1609 	if (!SlIsObjectValidInSavegame(sld)) return 0;
1610 
1611 	switch (sld.cmd) {
1612 		case SL_VAR: return SlCalcConvFileLen(sld.conv);
1613 		case SL_REF: return SlCalcRefLen();
1614 		case SL_ARR: return SlCalcArrayLen(sld.length, sld.conv);
1615 		case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld.length, sld.conv);
1616 		case SL_REFLIST: return SlCalcRefListLen(GetVariableAddress(object, sld), sld.conv);
1617 		case SL_DEQUE: return SlCalcDequeLen(GetVariableAddress(object, sld), sld.conv);
1618 		case SL_VECTOR: return SlCalcVectorLen(GetVariableAddress(object, sld), sld.conv);
1619 		case SL_STDSTR: return SlCalcStdStringLen(GetVariableAddress(object, sld));
1620 		case SL_SAVEBYTE: return 1; // a byte is logically of size 1
1621 		case SL_NULL: return SlCalcConvFileLen(sld.conv) * sld.length;
1622 
1623 		case SL_STRUCT:
1624 		case SL_STRUCTLIST: {
1625 			NeedLength old_need_length = _sl.need_length;
1626 			size_t old_obj_len = _sl.obj_len;
1627 
1628 			_sl.need_length = NL_CALCLENGTH;
1629 			_sl.obj_len = 0;
1630 
1631 			/* Pretend that we are saving to collect the object size. Other
1632 			 * means are difficult, as we don't know the length of the list we
1633 			 * are about to store. */
1634 			sld.handler->Save(const_cast<void *>(object));
1635 			size_t length = _sl.obj_len;
1636 
1637 			_sl.obj_len = old_obj_len;
1638 			_sl.need_length = old_need_length;
1639 
1640 			if (sld.cmd == SL_STRUCT) {
1641 				length += SlGetArrayLength(1);
1642 			}
1643 
1644 			return length;
1645 		}
1646 
1647 		default: NOT_REACHED();
1648 	}
1649 	return 0;
1650 }
1651 
1652 /**
1653  * Check whether the variable size of the variable in the saveload configuration
1654  * matches with the actual variable size.
1655  * @param sld The saveload configuration to test.
1656  */
IsVariableSizeRight(const SaveLoad & sld)1657 [[maybe_unused]] static bool IsVariableSizeRight(const SaveLoad &sld)
1658 {
1659 	if (GetVarMemType(sld.conv) == SLE_VAR_NULL) return true;
1660 
1661 	switch (sld.cmd) {
1662 		case SL_VAR:
1663 			switch (GetVarMemType(sld.conv)) {
1664 				case SLE_VAR_BL:
1665 					return sld.size == sizeof(bool);
1666 				case SLE_VAR_I8:
1667 				case SLE_VAR_U8:
1668 					return sld.size == sizeof(int8);
1669 				case SLE_VAR_I16:
1670 				case SLE_VAR_U16:
1671 					return sld.size == sizeof(int16);
1672 				case SLE_VAR_I32:
1673 				case SLE_VAR_U32:
1674 					return sld.size == sizeof(int32);
1675 				case SLE_VAR_I64:
1676 				case SLE_VAR_U64:
1677 					return sld.size == sizeof(int64);
1678 				case SLE_VAR_NAME:
1679 					return sld.size == sizeof(std::string);
1680 				default:
1681 					return sld.size == sizeof(void *);
1682 			}
1683 		case SL_REF:
1684 			/* These should all be pointer sized. */
1685 			return sld.size == sizeof(void *);
1686 
1687 		case SL_STR:
1688 			/* These should be pointer sized, or fixed array. */
1689 			return sld.size == sizeof(void *) || sld.size == sld.length;
1690 
1691 		case SL_STDSTR:
1692 			/* These should be all pointers to std::string. */
1693 			return sld.size == sizeof(std::string);
1694 
1695 		default:
1696 			return true;
1697 	}
1698 }
1699 
SlObjectMember(void * object,const SaveLoad & sld)1700 static bool SlObjectMember(void *object, const SaveLoad &sld)
1701 {
1702 	assert(IsVariableSizeRight(sld));
1703 
1704 	if (!SlIsObjectValidInSavegame(sld)) return false;
1705 
1706 	VarType conv = GB(sld.conv, 0, 8);
1707 	switch (sld.cmd) {
1708 		case SL_VAR:
1709 		case SL_REF:
1710 		case SL_ARR:
1711 		case SL_STR:
1712 		case SL_REFLIST:
1713 		case SL_DEQUE:
1714 		case SL_VECTOR:
1715 		case SL_STDSTR: {
1716 			void *ptr = GetVariableAddress(object, sld);
1717 
1718 			switch (sld.cmd) {
1719 				case SL_VAR: SlSaveLoadConv(ptr, conv); break;
1720 				case SL_REF: SlSaveLoadRef(ptr, conv); break;
1721 				case SL_ARR: SlArray(ptr, sld.length, conv); break;
1722 				case SL_STR: SlString(ptr, sld.length, sld.conv); break;
1723 				case SL_REFLIST: SlRefList(ptr, conv); break;
1724 				case SL_DEQUE: SlDeque(ptr, conv); break;
1725 				case SL_VECTOR: SlVector(ptr, conv); break;
1726 				case SL_STDSTR: SlStdString(ptr, sld.conv); break;
1727 				default: NOT_REACHED();
1728 			}
1729 			break;
1730 		}
1731 
1732 		/* SL_SAVEBYTE writes a value to the savegame to identify the type of an object.
1733 		 * When loading, the value is read explicitly with SlReadByte() to determine which
1734 		 * object description to use. */
1735 		case SL_SAVEBYTE: {
1736 			void *ptr = GetVariableAddress(object, sld);
1737 
1738 			switch (_sl.action) {
1739 				case SLA_SAVE: SlWriteByte(*(uint8 *)ptr); break;
1740 				case SLA_LOAD_CHECK:
1741 				case SLA_LOAD:
1742 				case SLA_PTRS:
1743 				case SLA_NULL: break;
1744 				default: NOT_REACHED();
1745 			}
1746 			break;
1747 		}
1748 
1749 		case SL_NULL: {
1750 			assert(GetVarMemType(sld.conv) == SLE_VAR_NULL);
1751 
1752 			switch (_sl.action) {
1753 				case SLA_LOAD_CHECK:
1754 				case SLA_LOAD: SlSkipBytes(SlCalcConvFileLen(sld.conv) * sld.length); break;
1755 				case SLA_SAVE: for (int i = 0; i < SlCalcConvFileLen(sld.conv) * sld.length; i++) SlWriteByte(0); break;
1756 				case SLA_PTRS:
1757 				case SLA_NULL: break;
1758 				default: NOT_REACHED();
1759 			}
1760 			break;
1761 		}
1762 
1763 		case SL_STRUCT:
1764 		case SL_STRUCTLIST:
1765 			switch (_sl.action) {
1766 				case SLA_SAVE: {
1767 					if (sld.cmd == SL_STRUCT) {
1768 						/* Store in the savegame if this struct was written or not. */
1769 						SlSetStructListLength(SlCalcObjMemberLength(object, sld) > SlGetArrayLength(1) ? 1 : 0);
1770 					}
1771 					sld.handler->Save(object);
1772 					break;
1773 				}
1774 
1775 				case SLA_LOAD_CHECK: {
1776 					if (sld.cmd == SL_STRUCT && !IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) {
1777 						SlGetStructListLength(1);
1778 					}
1779 					sld.handler->LoadCheck(object);
1780 					break;
1781 				}
1782 
1783 				case SLA_LOAD: {
1784 					if (sld.cmd == SL_STRUCT && !IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) {
1785 						SlGetStructListLength(1);
1786 					}
1787 					sld.handler->Load(object);
1788 					break;
1789 				}
1790 
1791 				case SLA_PTRS:
1792 					sld.handler->FixPointers(object);
1793 					break;
1794 
1795 				case SLA_NULL: break;
1796 				default: NOT_REACHED();
1797 			}
1798 			break;
1799 
1800 		default: NOT_REACHED();
1801 	}
1802 	return true;
1803 }
1804 
1805 /**
1806  * Set the length of this list.
1807  * @param The length of the list.
1808  */
SlSetStructListLength(size_t length)1809 void SlSetStructListLength(size_t length)
1810 {
1811 	/* Automatically calculate the length? */
1812 	if (_sl.need_length != NL_NONE) {
1813 		SlSetLength(SlGetArrayLength(length));
1814 		if (_sl.need_length == NL_CALCLENGTH) return;
1815 	}
1816 
1817 	SlWriteArrayLength(length);
1818 }
1819 
1820 /**
1821  * Get the length of this list; if it exceeds the limit, error out.
1822  * @param limit The maximum size the list can be.
1823  * @return The length of the list.
1824  */
SlGetStructListLength(size_t limit)1825 size_t SlGetStructListLength(size_t limit)
1826 {
1827 	size_t length = SlReadArrayLength();
1828 	if (length > limit) SlErrorCorrupt("List exceeds storage size");
1829 
1830 	return length;
1831 }
1832 
1833 /**
1834  * Main SaveLoad function.
1835  * @param object The object that is being saved or loaded.
1836  * @param slt The SaveLoad table with objects to save/load.
1837  */
SlObject(void * object,const SaveLoadTable & slt)1838 void SlObject(void *object, const SaveLoadTable &slt)
1839 {
1840 	/* Automatically calculate the length? */
1841 	if (_sl.need_length != NL_NONE) {
1842 		SlSetLength(SlCalcObjLength(object, slt));
1843 		if (_sl.need_length == NL_CALCLENGTH) return;
1844 	}
1845 
1846 	for (auto &sld : slt) {
1847 		SlObjectMember(object, sld);
1848 	}
1849 }
1850 
1851 /**
1852  * Handler that is assigned when there is a struct read in the savegame which
1853  * is not known to the code. This means we are going to skip it.
1854  */
1855 class SlSkipHandler : public SaveLoadHandler {
Save(void * object) const1856 	void Save(void *object) const override
1857 	{
1858 		NOT_REACHED();
1859 	}
1860 
Load(void * object) const1861 	void Load(void *object) const override
1862 	{
1863 		size_t length = SlGetStructListLength(UINT32_MAX);
1864 		for (; length > 0; length--) {
1865 			SlObject(object, this->GetLoadDescription());
1866 		}
1867 	}
1868 
LoadCheck(void * object) const1869 	void LoadCheck(void *object) const override
1870 	{
1871 		this->Load(object);
1872 	}
1873 
GetDescription() const1874 	virtual SaveLoadTable GetDescription() const override
1875 	{
1876 		return {};
1877 	}
1878 
GetCompatDescription() const1879 	virtual SaveLoadCompatTable GetCompatDescription() const override
1880 	{
1881 		NOT_REACHED();
1882 	}
1883 };
1884 
1885 /**
1886  * Save or Load a table header.
1887  * @note a table-header can never contain more than 65535 fields.
1888  * @param slt The SaveLoad table with objects to save/load.
1889  * @return When loading, the ordered SaveLoad array to use; otherwise an empty list.
1890  */
SlTableHeader(const SaveLoadTable & slt)1891 std::vector<SaveLoad> SlTableHeader(const SaveLoadTable &slt)
1892 {
1893 	/* You can only use SlTableHeader if you are a CH_TABLE. */
1894 	assert(_sl.block_mode == CH_TABLE || _sl.block_mode == CH_SPARSE_TABLE);
1895 
1896 	switch (_sl.action) {
1897 		case SLA_LOAD_CHECK:
1898 		case SLA_LOAD: {
1899 			std::vector<SaveLoad> saveloads;
1900 
1901 			/* Build a key lookup mapping based on the available fields. */
1902 			std::map<std::string, const SaveLoad *> key_lookup;
1903 			for (auto &sld : slt) {
1904 				if (!SlIsObjectValidInSavegame(sld)) continue;
1905 
1906 				/* Check that there is only one active SaveLoad for a given name. */
1907 				assert(key_lookup.find(sld.name) == key_lookup.end());
1908 				key_lookup[sld.name] = &sld;
1909 			}
1910 
1911 			while (true) {
1912 				uint8 type;
1913 				SlSaveLoadConv(&type, SLE_UINT8);
1914 				if (type == SLE_FILE_END) break;
1915 
1916 				std::string key;
1917 				SlStdString(&key, SLE_STR);
1918 
1919 				auto sld_it = key_lookup.find(key);
1920 				if (sld_it == key_lookup.end()) {
1921 					/* SLA_LOADCHECK triggers this debug statement a lot and is perfectly normal. */
1922 					Debug(sl, _sl.action == SLA_LOAD ? 2 : 6, "Field '{}' of type 0x{:02x} not found, skipping", key, type);
1923 
1924 					std::shared_ptr<SaveLoadHandler> handler = nullptr;
1925 					SaveLoadType slt;
1926 					switch (type & SLE_FILE_TYPE_MASK) {
1927 						case SLE_FILE_STRING:
1928 							/* Strings are always marked with SLE_FILE_HAS_LENGTH_FIELD, as they are a list of chars. */
1929 							slt = SL_STR;
1930 							break;
1931 
1932 						case SLE_FILE_STRUCT:
1933 							/* Structs are always marked with SLE_FILE_HAS_LENGTH_FIELD as SL_STRUCT is seen as a list of 0/1 in length. */
1934 							slt = SL_STRUCTLIST;
1935 							handler = std::make_shared<SlSkipHandler>();
1936 							break;
1937 
1938 						default:
1939 							slt = (type & SLE_FILE_HAS_LENGTH_FIELD) ? SL_ARR : SL_VAR;
1940 							break;
1941 					}
1942 
1943 					/* We don't know this field, so read to nothing. */
1944 					saveloads.push_back({key, slt, ((VarType)type & SLE_FILE_TYPE_MASK) | SLE_VAR_NULL, 1, SL_MIN_VERSION, SL_MAX_VERSION, 0, nullptr, 0, handler});
1945 					continue;
1946 				}
1947 
1948 				/* Validate the type of the field. If it is changed, the
1949 				 * savegame should have been bumped so we know how to do the
1950 				 * conversion. If this error triggers, that clearly didn't
1951 				 * happen and this is a friendly poke to the developer to bump
1952 				 * the savegame version and add conversion code. */
1953 				uint8 correct_type = GetSavegameFileType(*sld_it->second);
1954 				if (correct_type != type) {
1955 					Debug(sl, 1, "Field type for '{}' was expected to be 0x{:02x} but 0x{:02x} was found", key, correct_type, type);
1956 					SlErrorCorrupt("Field type is different than expected");
1957 				}
1958 				saveloads.push_back(*sld_it->second);
1959 			}
1960 
1961 			for (auto &sld : saveloads) {
1962 				if (sld.cmd == SL_STRUCTLIST || sld.cmd == SL_STRUCT) {
1963 					sld.handler->load_description = SlTableHeader(sld.handler->GetDescription());
1964 				}
1965 			}
1966 
1967 			return saveloads;
1968 		}
1969 
1970 		case SLA_SAVE: {
1971 			/* Automatically calculate the length? */
1972 			if (_sl.need_length != NL_NONE) {
1973 				SlSetLength(SlCalcTableHeader(slt));
1974 				if (_sl.need_length == NL_CALCLENGTH) break;
1975 			}
1976 
1977 			for (auto &sld : slt) {
1978 				if (!SlIsObjectValidInSavegame(sld)) continue;
1979 				/* Make sure we are not storing empty keys. */
1980 				assert(!sld.name.empty());
1981 
1982 				uint8 type = GetSavegameFileType(sld);
1983 				assert(type != SLE_FILE_END);
1984 
1985 				SlSaveLoadConv(&type, SLE_UINT8);
1986 				SlStdString(const_cast<std::string *>(&sld.name), SLE_STR);
1987 			}
1988 
1989 			/* Add an end-of-header marker. */
1990 			uint8 type = SLE_FILE_END;
1991 			SlSaveLoadConv(&type, SLE_UINT8);
1992 
1993 			/* After the table, write down any sub-tables we might have. */
1994 			for (auto &sld : slt) {
1995 				if (!SlIsObjectValidInSavegame(sld)) continue;
1996 				if (sld.cmd == SL_STRUCTLIST || sld.cmd == SL_STRUCT) {
1997 					/* SlCalcTableHeader already looks in sub-lists, so avoid the length being added twice. */
1998 					NeedLength old_need_length = _sl.need_length;
1999 					_sl.need_length = NL_NONE;
2000 
2001 					SlTableHeader(sld.handler->GetDescription());
2002 
2003 					_sl.need_length = old_need_length;
2004 				}
2005 			}
2006 
2007 			break;
2008 		}
2009 
2010 		default: NOT_REACHED();
2011 	}
2012 
2013 	return std::vector<SaveLoad>();
2014 }
2015 
2016 /**
2017  * Load a table header in a savegame compatible way. If the savegame was made
2018  * before table headers were added, it will fall back to the
2019  * SaveLoadCompatTable for the order of fields while loading.
2020  *
2021  * @note You only have to call this function if the chunk existed as a
2022  * non-table type before converting it to a table. New chunks created as
2023  * table can call SlTableHeader() directly.
2024  *
2025  * @param slt The SaveLoad table with objects to save/load.
2026  * @param slct The SaveLoadCompat table the original order of the fields.
2027  * @return When loading, the ordered SaveLoad array to use; otherwise an empty list.
2028  */
SlCompatTableHeader(const SaveLoadTable & slt,const SaveLoadCompatTable & slct)2029 std::vector<SaveLoad> SlCompatTableHeader(const SaveLoadTable &slt, const SaveLoadCompatTable &slct)
2030 {
2031 	assert(_sl.action == SLA_LOAD || _sl.action == SLA_LOAD_CHECK);
2032 	/* CH_TABLE / CH_SPARSE_TABLE always have a header. */
2033 	if (_sl.block_mode == CH_TABLE || _sl.block_mode == CH_SPARSE_TABLE) return SlTableHeader(slt);
2034 
2035 	std::vector<SaveLoad> saveloads;
2036 
2037 	/* Build a key lookup mapping based on the available fields. */
2038 	std::map<std::string, std::vector<const SaveLoad *>> key_lookup;
2039 	for (auto &sld : slt) {
2040 		/* All entries should have a name; otherwise the entry should just be removed. */
2041 		assert(!sld.name.empty());
2042 
2043 		key_lookup[sld.name].push_back(&sld);
2044 	}
2045 
2046 	for (auto &slc : slct) {
2047 		if (slc.name.empty()) {
2048 			/* In old savegames there can be data we no longer care for. We
2049 			 * skip this by simply reading the amount of bytes indicated and
2050 			 * send those to /dev/null. */
2051 			saveloads.push_back({"", SL_NULL, SLE_FILE_U8 | SLE_VAR_NULL, slc.length, slc.version_from, slc.version_to, 0, nullptr, 0, nullptr});
2052 		} else {
2053 			auto sld_it = key_lookup.find(slc.name);
2054 			/* If this branch triggers, it means that an entry in the
2055 			 * SaveLoadCompat list is not mentioned in the SaveLoad list. Did
2056 			 * you rename a field in one and not in the other? */
2057 			if (sld_it == key_lookup.end()) {
2058 				/* This isn't an assert, as that leaves no information what
2059 				 * field was to blame. This way at least we have breadcrumbs. */
2060 				Debug(sl, 0, "internal error: saveload compatibility field '{}' not found", slc.name);
2061 				SlErrorCorrupt("Internal error with savegame compatibility");
2062 			}
2063 			for (auto &sld : sld_it->second) {
2064 				saveloads.push_back(*sld);
2065 			}
2066 		}
2067 	}
2068 
2069 	for (auto &sld : saveloads) {
2070 		if (!SlIsObjectValidInSavegame(sld)) continue;
2071 		if (sld.cmd == SL_STRUCTLIST || sld.cmd == SL_STRUCT) {
2072 			sld.handler->load_description = SlCompatTableHeader(sld.handler->GetDescription(), sld.handler->GetCompatDescription());
2073 		}
2074 	}
2075 
2076 	return saveloads;
2077 }
2078 
2079 /**
2080  * Save or Load (a list of) global variables.
2081  * @param slt The SaveLoad table with objects to save/load.
2082  */
SlGlobList(const SaveLoadTable & slt)2083 void SlGlobList(const SaveLoadTable &slt)
2084 {
2085 	SlObject(nullptr, slt);
2086 }
2087 
2088 /**
2089  * Do something of which I have no idea what it is :P
2090  * @param proc The callback procedure that is called
2091  * @param arg The variable that will be used for the callback procedure
2092  */
SlAutolength(AutolengthProc * proc,void * arg)2093 void SlAutolength(AutolengthProc *proc, void *arg)
2094 {
2095 	size_t offs;
2096 
2097 	assert(_sl.action == SLA_SAVE);
2098 
2099 	/* Tell it to calculate the length */
2100 	_sl.need_length = NL_CALCLENGTH;
2101 	_sl.obj_len = 0;
2102 	proc(arg);
2103 
2104 	/* Setup length */
2105 	_sl.need_length = NL_WANTLENGTH;
2106 	SlSetLength(_sl.obj_len);
2107 
2108 	offs = _sl.dumper->GetSize() + _sl.obj_len;
2109 
2110 	/* And write the stuff */
2111 	proc(arg);
2112 
2113 	if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
2114 }
2115 
LoadCheck(size_t len) const2116 void ChunkHandler::LoadCheck(size_t len) const
2117 {
2118 	switch (_sl.block_mode) {
2119 		case CH_TABLE:
2120 		case CH_SPARSE_TABLE:
2121 			SlTableHeader({});
2122 			FALLTHROUGH;
2123 		case CH_ARRAY:
2124 		case CH_SPARSE_ARRAY:
2125 			SlSkipArray();
2126 			break;
2127 		case CH_RIFF:
2128 			SlSkipBytes(len);
2129 			break;
2130 		default:
2131 			NOT_REACHED();
2132 	}
2133 }
2134 
2135 /**
2136  * Load a chunk of data (eg vehicles, stations, etc.)
2137  * @param ch The chunkhandler that will be used for the operation
2138  */
SlLoadChunk(const ChunkHandler & ch)2139 static void SlLoadChunk(const ChunkHandler &ch)
2140 {
2141 	byte m = SlReadByte();
2142 	size_t len;
2143 	size_t endoffs;
2144 
2145 	_sl.block_mode = m & CH_TYPE_MASK;
2146 	_sl.obj_len = 0;
2147 	_sl.expect_table_header = (_sl.block_mode == CH_TABLE || _sl.block_mode == CH_SPARSE_TABLE);
2148 
2149 	/* The header should always be at the start. Read the length; the
2150 	 * Load() should as first action process the header. */
2151 	if (_sl.expect_table_header) {
2152 		SlIterateArray();
2153 	}
2154 
2155 	switch (_sl.block_mode) {
2156 		case CH_TABLE:
2157 		case CH_ARRAY:
2158 			_sl.array_index = 0;
2159 			ch.Load();
2160 			if (_next_offs != 0) SlErrorCorrupt("Invalid array length");
2161 			break;
2162 		case CH_SPARSE_TABLE:
2163 		case CH_SPARSE_ARRAY:
2164 			ch.Load();
2165 			if (_next_offs != 0) SlErrorCorrupt("Invalid array length");
2166 			break;
2167 		case CH_RIFF:
2168 			/* Read length */
2169 			len = (SlReadByte() << 16) | ((m >> 4) << 24);
2170 			len += SlReadUint16();
2171 			_sl.obj_len = len;
2172 			endoffs = _sl.reader->GetSize() + len;
2173 			ch.Load();
2174 			if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
2175 			break;
2176 		default:
2177 			SlErrorCorrupt("Invalid chunk type");
2178 			break;
2179 	}
2180 
2181 	if (_sl.expect_table_header) SlErrorCorrupt("Table chunk without header");
2182 }
2183 
2184 /**
2185  * Load a chunk of data for checking savegames.
2186  * If the chunkhandler is nullptr, the chunk is skipped.
2187  * @param ch The chunkhandler that will be used for the operation
2188  */
SlLoadCheckChunk(const ChunkHandler & ch)2189 static void SlLoadCheckChunk(const ChunkHandler &ch)
2190 {
2191 	byte m = SlReadByte();
2192 	size_t len;
2193 	size_t endoffs;
2194 
2195 	_sl.block_mode = m & CH_TYPE_MASK;
2196 	_sl.obj_len = 0;
2197 	_sl.expect_table_header = (_sl.block_mode == CH_TABLE || _sl.block_mode == CH_SPARSE_TABLE);
2198 
2199 	/* The header should always be at the start. Read the length; the
2200 	 * LoadCheck() should as first action process the header. */
2201 	if (_sl.expect_table_header) {
2202 		SlIterateArray();
2203 	}
2204 
2205 	switch (_sl.block_mode) {
2206 		case CH_TABLE:
2207 		case CH_ARRAY:
2208 			_sl.array_index = 0;
2209 			ch.LoadCheck();
2210 			break;
2211 		case CH_SPARSE_TABLE:
2212 		case CH_SPARSE_ARRAY:
2213 			ch.LoadCheck();
2214 			break;
2215 		case CH_RIFF:
2216 			/* Read length */
2217 			len = (SlReadByte() << 16) | ((m >> 4) << 24);
2218 			len += SlReadUint16();
2219 			_sl.obj_len = len;
2220 			endoffs = _sl.reader->GetSize() + len;
2221 			ch.LoadCheck(len);
2222 			if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
2223 			break;
2224 		default:
2225 			SlErrorCorrupt("Invalid chunk type");
2226 			break;
2227 	}
2228 
2229 	if (_sl.expect_table_header) SlErrorCorrupt("Table chunk without header");
2230 }
2231 
2232 /**
2233  * Save a chunk of data (eg. vehicles, stations, etc.). Each chunk is
2234  * prefixed by an ID identifying it, followed by data, and terminator where appropriate
2235  * @param ch The chunkhandler that will be used for the operation
2236  */
SlSaveChunk(const ChunkHandler & ch)2237 static void SlSaveChunk(const ChunkHandler &ch)
2238 {
2239 	if (ch.type == CH_READONLY) return;
2240 
2241 	SlWriteUint32(ch.id);
2242 	Debug(sl, 2, "Saving chunk {:c}{:c}{:c}{:c}", ch.id >> 24, ch.id >> 16, ch.id >> 8, ch.id);
2243 
2244 	_sl.block_mode = ch.type;
2245 	_sl.expect_table_header = (_sl.block_mode == CH_TABLE || _sl.block_mode == CH_SPARSE_TABLE);
2246 
2247 	_sl.need_length = (_sl.expect_table_header || _sl.block_mode == CH_RIFF) ? NL_WANTLENGTH : NL_NONE;
2248 
2249 	switch (_sl.block_mode) {
2250 		case CH_RIFF:
2251 			ch.Save();
2252 			break;
2253 		case CH_TABLE:
2254 		case CH_ARRAY:
2255 			_sl.last_array_index = 0;
2256 			SlWriteByte(_sl.block_mode);
2257 			ch.Save();
2258 			SlWriteArrayLength(0); // Terminate arrays
2259 			break;
2260 		case CH_SPARSE_TABLE:
2261 		case CH_SPARSE_ARRAY:
2262 			SlWriteByte(_sl.block_mode);
2263 			ch.Save();
2264 			SlWriteArrayLength(0); // Terminate arrays
2265 			break;
2266 		default: NOT_REACHED();
2267 	}
2268 
2269 	if (_sl.expect_table_header) SlErrorCorrupt("Table chunk without header");
2270 }
2271 
2272 /** Save all chunks */
SlSaveChunks()2273 static void SlSaveChunks()
2274 {
2275 	for (auto &ch : ChunkHandlers()) {
2276 		SlSaveChunk(ch);
2277 	}
2278 
2279 	/* Terminator */
2280 	SlWriteUint32(0);
2281 }
2282 
2283 /**
2284  * Find the ChunkHandler that will be used for processing the found
2285  * chunk in the savegame or in memory
2286  * @param id the chunk in question
2287  * @return returns the appropriate chunkhandler
2288  */
SlFindChunkHandler(uint32 id)2289 static const ChunkHandler *SlFindChunkHandler(uint32 id)
2290 {
2291 	for (const ChunkHandler &ch : ChunkHandlers()) if (ch.id == id) return &ch;
2292 	return nullptr;
2293 }
2294 
2295 /** Load all chunks */
SlLoadChunks()2296 static void SlLoadChunks()
2297 {
2298 	uint32 id;
2299 	const ChunkHandler *ch;
2300 
2301 	for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
2302 		Debug(sl, 2, "Loading chunk {:c}{:c}{:c}{:c}", id >> 24, id >> 16, id >> 8, id);
2303 
2304 		ch = SlFindChunkHandler(id);
2305 		if (ch == nullptr) SlErrorCorrupt("Unknown chunk type");
2306 		SlLoadChunk(*ch);
2307 	}
2308 }
2309 
2310 /** Load all chunks for savegame checking */
SlLoadCheckChunks()2311 static void SlLoadCheckChunks()
2312 {
2313 	uint32 id;
2314 	const ChunkHandler *ch;
2315 
2316 	for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
2317 		Debug(sl, 2, "Loading chunk {:c}{:c}{:c}{:c}", id >> 24, id >> 16, id >> 8, id);
2318 
2319 		ch = SlFindChunkHandler(id);
2320 		if (ch == nullptr) SlErrorCorrupt("Unknown chunk type");
2321 		SlLoadCheckChunk(*ch);
2322 	}
2323 }
2324 
2325 /** Fix all pointers (convert index -> pointer) */
SlFixPointers()2326 static void SlFixPointers()
2327 {
2328 	_sl.action = SLA_PTRS;
2329 
2330 	for (const ChunkHandler &ch : ChunkHandlers()) {
2331 		Debug(sl, 3, "Fixing pointers for {:c}{:c}{:c}{:c}", ch.id >> 24, ch.id >> 16, ch.id >> 8, ch.id);
2332 		ch.FixPointers();
2333 	}
2334 
2335 	assert(_sl.action == SLA_PTRS);
2336 }
2337 
2338 
2339 /** Yes, simply reading from a file. */
2340 struct FileReader : LoadFilter {
2341 	FILE *file; ///< The file to read from.
2342 	long begin; ///< The begin of the file.
2343 
2344 	/**
2345 	 * Create the file reader, so it reads from a specific file.
2346 	 * @param file The file to read from.
2347 	 */
FileReaderFileReader2348 	FileReader(FILE *file) : LoadFilter(nullptr), file(file), begin(ftell(file))
2349 	{
2350 	}
2351 
2352 	/** Make sure everything is cleaned up. */
~FileReaderFileReader2353 	~FileReader()
2354 	{
2355 		if (this->file != nullptr) fclose(this->file);
2356 		this->file = nullptr;
2357 
2358 		/* Make sure we don't double free. */
2359 		_sl.sf = nullptr;
2360 	}
2361 
ReadFileReader2362 	size_t Read(byte *buf, size_t size) override
2363 	{
2364 		/* We're in the process of shutting down, i.e. in "failure" mode. */
2365 		if (this->file == nullptr) return 0;
2366 
2367 		return fread(buf, 1, size, this->file);
2368 	}
2369 
ResetFileReader2370 	void Reset() override
2371 	{
2372 		clearerr(this->file);
2373 		if (fseek(this->file, this->begin, SEEK_SET)) {
2374 			Debug(sl, 1, "Could not reset the file reading");
2375 		}
2376 	}
2377 };
2378 
2379 /** Yes, simply writing to a file. */
2380 struct FileWriter : SaveFilter {
2381 	FILE *file; ///< The file to write to.
2382 
2383 	/**
2384 	 * Create the file writer, so it writes to a specific file.
2385 	 * @param file The file to write to.
2386 	 */
FileWriterFileWriter2387 	FileWriter(FILE *file) : SaveFilter(nullptr), file(file)
2388 	{
2389 	}
2390 
2391 	/** Make sure everything is cleaned up. */
~FileWriterFileWriter2392 	~FileWriter()
2393 	{
2394 		this->Finish();
2395 
2396 		/* Make sure we don't double free. */
2397 		_sl.sf = nullptr;
2398 	}
2399 
WriteFileWriter2400 	void Write(byte *buf, size_t size) override
2401 	{
2402 		/* We're in the process of shutting down, i.e. in "failure" mode. */
2403 		if (this->file == nullptr) return;
2404 
2405 		if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
2406 	}
2407 
FinishFileWriter2408 	void Finish() override
2409 	{
2410 		if (this->file != nullptr) fclose(this->file);
2411 		this->file = nullptr;
2412 	}
2413 };
2414 
2415 /*******************************************
2416  ********** START OF LZO CODE **************
2417  *******************************************/
2418 
2419 #ifdef WITH_LZO
2420 #include <lzo/lzo1x.h>
2421 
2422 /** Buffer size for the LZO compressor */
2423 static const uint LZO_BUFFER_SIZE = 8192;
2424 
2425 /** Filter using LZO compression. */
2426 struct LZOLoadFilter : LoadFilter {
2427 	/**
2428 	 * Initialise this filter.
2429 	 * @param chain The next filter in this chain.
2430 	 */
LZOLoadFilterLZOLoadFilter2431 	LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
2432 	{
2433 		if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
2434 	}
2435 
ReadLZOLoadFilter2436 	size_t Read(byte *buf, size_t ssize) override
2437 	{
2438 		assert(ssize >= LZO_BUFFER_SIZE);
2439 
2440 		/* Buffer size is from the LZO docs plus the chunk header size. */
2441 		byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
2442 		uint32 tmp[2];
2443 		uint32 size;
2444 		lzo_uint len = ssize;
2445 
2446 		/* Read header*/
2447 		if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
2448 
2449 		/* Check if size is bad */
2450 		((uint32*)out)[0] = size = tmp[1];
2451 
2452 		if (_sl_version != SL_MIN_VERSION) {
2453 			tmp[0] = TO_BE32(tmp[0]);
2454 			size = TO_BE32(size);
2455 		}
2456 
2457 		if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
2458 
2459 		/* Read block */
2460 		if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
2461 
2462 		/* Verify checksum */
2463 		if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
2464 
2465 		/* Decompress */
2466 		int ret = lzo1x_decompress_safe(out + sizeof(uint32) * 1, size, buf, &len, nullptr);
2467 		if (ret != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
2468 		return len;
2469 	}
2470 };
2471 
2472 /** Filter using LZO compression. */
2473 struct LZOSaveFilter : SaveFilter {
2474 	/**
2475 	 * Initialise this filter.
2476 	 * @param chain             The next filter in this chain.
2477 	 * @param compression_level The requested level of compression.
2478 	 */
LZOSaveFilterLZOSaveFilter2479 	LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
2480 	{
2481 		if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
2482 	}
2483 
WriteLZOSaveFilter2484 	void Write(byte *buf, size_t size) override
2485 	{
2486 		const lzo_bytep in = buf;
2487 		/* Buffer size is from the LZO docs plus the chunk header size. */
2488 		byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
2489 		byte wrkmem[LZO1X_1_MEM_COMPRESS];
2490 		lzo_uint outlen;
2491 
2492 		do {
2493 			/* Compress up to LZO_BUFFER_SIZE bytes at once. */
2494 			lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
2495 			lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
2496 			((uint32*)out)[1] = TO_BE32((uint32)outlen);
2497 			((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
2498 			this->chain->Write(out, outlen + sizeof(uint32) * 2);
2499 
2500 			/* Move to next data chunk. */
2501 			size -= len;
2502 			in += len;
2503 		} while (size > 0);
2504 	}
2505 };
2506 
2507 #endif /* WITH_LZO */
2508 
2509 /*********************************************
2510  ******** START OF NOCOMP CODE (uncompressed)*
2511  *********************************************/
2512 
2513 /** Filter without any compression. */
2514 struct NoCompLoadFilter : LoadFilter {
2515 	/**
2516 	 * Initialise this filter.
2517 	 * @param chain The next filter in this chain.
2518 	 */
NoCompLoadFilterNoCompLoadFilter2519 	NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
2520 	{
2521 	}
2522 
ReadNoCompLoadFilter2523 	size_t Read(byte *buf, size_t size) override
2524 	{
2525 		return this->chain->Read(buf, size);
2526 	}
2527 };
2528 
2529 /** Filter without any compression. */
2530 struct NoCompSaveFilter : SaveFilter {
2531 	/**
2532 	 * Initialise this filter.
2533 	 * @param chain             The next filter in this chain.
2534 	 * @param compression_level The requested level of compression.
2535 	 */
NoCompSaveFilterNoCompSaveFilter2536 	NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
2537 	{
2538 	}
2539 
WriteNoCompSaveFilter2540 	void Write(byte *buf, size_t size) override
2541 	{
2542 		this->chain->Write(buf, size);
2543 	}
2544 };
2545 
2546 /********************************************
2547  ********** START OF ZLIB CODE **************
2548  ********************************************/
2549 
2550 #if defined(WITH_ZLIB)
2551 #include <zlib.h>
2552 
2553 /** Filter using Zlib compression. */
2554 struct ZlibLoadFilter : LoadFilter {
2555 	z_stream z;                        ///< Stream state we are reading from.
2556 	byte fread_buf[MEMORY_CHUNK_SIZE]; ///< Buffer for reading from the file.
2557 
2558 	/**
2559 	 * Initialise this filter.
2560 	 * @param chain The next filter in this chain.
2561 	 */
ZlibLoadFilterZlibLoadFilter2562 	ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
2563 	{
2564 		memset(&this->z, 0, sizeof(this->z));
2565 		if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
2566 	}
2567 
2568 	/** Clean everything up. */
~ZlibLoadFilterZlibLoadFilter2569 	~ZlibLoadFilter()
2570 	{
2571 		inflateEnd(&this->z);
2572 	}
2573 
ReadZlibLoadFilter2574 	size_t Read(byte *buf, size_t size) override
2575 	{
2576 		this->z.next_out  = buf;
2577 		this->z.avail_out = (uint)size;
2578 
2579 		do {
2580 			/* read more bytes from the file? */
2581 			if (this->z.avail_in == 0) {
2582 				this->z.next_in = this->fread_buf;
2583 				this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
2584 			}
2585 
2586 			/* inflate the data */
2587 			int r = inflate(&this->z, 0);
2588 			if (r == Z_STREAM_END) break;
2589 
2590 			if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
2591 		} while (this->z.avail_out != 0);
2592 
2593 		return size - this->z.avail_out;
2594 	}
2595 };
2596 
2597 /** Filter using Zlib compression. */
2598 struct ZlibSaveFilter : SaveFilter {
2599 	z_stream z; ///< Stream state we are writing to.
2600 
2601 	/**
2602 	 * Initialise this filter.
2603 	 * @param chain             The next filter in this chain.
2604 	 * @param compression_level The requested level of compression.
2605 	 */
ZlibSaveFilterZlibSaveFilter2606 	ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
2607 	{
2608 		memset(&this->z, 0, sizeof(this->z));
2609 		if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
2610 	}
2611 
2612 	/** Clean up what we allocated. */
~ZlibSaveFilterZlibSaveFilter2613 	~ZlibSaveFilter()
2614 	{
2615 		deflateEnd(&this->z);
2616 	}
2617 
2618 	/**
2619 	 * Helper loop for writing the data.
2620 	 * @param p    The bytes to write.
2621 	 * @param len  Amount of bytes to write.
2622 	 * @param mode Mode for deflate.
2623 	 */
WriteLoopZlibSaveFilter2624 	void WriteLoop(byte *p, size_t len, int mode)
2625 	{
2626 		byte buf[MEMORY_CHUNK_SIZE]; // output buffer
2627 		uint n;
2628 		this->z.next_in = p;
2629 		this->z.avail_in = (uInt)len;
2630 		do {
2631 			this->z.next_out = buf;
2632 			this->z.avail_out = sizeof(buf);
2633 
2634 			/**
2635 			 * For the poor next soul who sees many valgrind warnings of the
2636 			 * "Conditional jump or move depends on uninitialised value(s)" kind:
2637 			 * According to the author of zlib it is not a bug and it won't be fixed.
2638 			 * http://groups.google.com/group/comp.compression/browse_thread/thread/b154b8def8c2a3ef/cdf9b8729ce17ee2
2639 			 * [Mark Adler, Feb 24 2004, 'zlib-1.2.1 valgrind warnings' in the newsgroup comp.compression]
2640 			 */
2641 			int r = deflate(&this->z, mode);
2642 
2643 			/* bytes were emitted? */
2644 			if ((n = sizeof(buf) - this->z.avail_out) != 0) {
2645 				this->chain->Write(buf, n);
2646 			}
2647 			if (r == Z_STREAM_END) break;
2648 
2649 			if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
2650 		} while (this->z.avail_in || !this->z.avail_out);
2651 	}
2652 
WriteZlibSaveFilter2653 	void Write(byte *buf, size_t size) override
2654 	{
2655 		this->WriteLoop(buf, size, 0);
2656 	}
2657 
FinishZlibSaveFilter2658 	void Finish() override
2659 	{
2660 		this->WriteLoop(nullptr, 0, Z_FINISH);
2661 		this->chain->Finish();
2662 	}
2663 };
2664 
2665 #endif /* WITH_ZLIB */
2666 
2667 /********************************************
2668  ********** START OF LZMA CODE **************
2669  ********************************************/
2670 
2671 #if defined(WITH_LIBLZMA)
2672 #include <lzma.h>
2673 
2674 /**
2675  * Have a copy of an initialised LZMA stream. We need this as it's
2676  * impossible to "re"-assign LZMA_STREAM_INIT to a variable in some
2677  * compilers, i.e. LZMA_STREAM_INIT can't be used to set something.
2678  * This var has to be used instead.
2679  */
2680 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
2681 
2682 /** Filter without any compression. */
2683 struct LZMALoadFilter : LoadFilter {
2684 	lzma_stream lzma;                  ///< Stream state that we are reading from.
2685 	byte fread_buf[MEMORY_CHUNK_SIZE]; ///< Buffer for reading from the file.
2686 
2687 	/**
2688 	 * Initialise this filter.
2689 	 * @param chain The next filter in this chain.
2690 	 */
LZMALoadFilterLZMALoadFilter2691 	LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
2692 	{
2693 		/* Allow saves up to 256 MB uncompressed */
2694 		if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
2695 	}
2696 
2697 	/** Clean everything up. */
~LZMALoadFilterLZMALoadFilter2698 	~LZMALoadFilter()
2699 	{
2700 		lzma_end(&this->lzma);
2701 	}
2702 
ReadLZMALoadFilter2703 	size_t Read(byte *buf, size_t size) override
2704 	{
2705 		this->lzma.next_out  = buf;
2706 		this->lzma.avail_out = size;
2707 
2708 		do {
2709 			/* read more bytes from the file? */
2710 			if (this->lzma.avail_in == 0) {
2711 				this->lzma.next_in  = this->fread_buf;
2712 				this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
2713 			}
2714 
2715 			/* inflate the data */
2716 			lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
2717 			if (r == LZMA_STREAM_END) break;
2718 			if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
2719 		} while (this->lzma.avail_out != 0);
2720 
2721 		return size - this->lzma.avail_out;
2722 	}
2723 };
2724 
2725 /** Filter using LZMA compression. */
2726 struct LZMASaveFilter : SaveFilter {
2727 	lzma_stream lzma; ///< Stream state that we are writing to.
2728 
2729 	/**
2730 	 * Initialise this filter.
2731 	 * @param chain             The next filter in this chain.
2732 	 * @param compression_level The requested level of compression.
2733 	 */
LZMASaveFilterLZMASaveFilter2734 	LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
2735 	{
2736 		if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
2737 	}
2738 
2739 	/** Clean up what we allocated. */
~LZMASaveFilterLZMASaveFilter2740 	~LZMASaveFilter()
2741 	{
2742 		lzma_end(&this->lzma);
2743 	}
2744 
2745 	/**
2746 	 * Helper loop for writing the data.
2747 	 * @param p      The bytes to write.
2748 	 * @param len    Amount of bytes to write.
2749 	 * @param action Action for lzma_code.
2750 	 */
WriteLoopLZMASaveFilter2751 	void WriteLoop(byte *p, size_t len, lzma_action action)
2752 	{
2753 		byte buf[MEMORY_CHUNK_SIZE]; // output buffer
2754 		size_t n;
2755 		this->lzma.next_in = p;
2756 		this->lzma.avail_in = len;
2757 		do {
2758 			this->lzma.next_out = buf;
2759 			this->lzma.avail_out = sizeof(buf);
2760 
2761 			lzma_ret r = lzma_code(&this->lzma, action);
2762 
2763 			/* bytes were emitted? */
2764 			if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
2765 				this->chain->Write(buf, n);
2766 			}
2767 			if (r == LZMA_STREAM_END) break;
2768 			if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
2769 		} while (this->lzma.avail_in || !this->lzma.avail_out);
2770 	}
2771 
WriteLZMASaveFilter2772 	void Write(byte *buf, size_t size) override
2773 	{
2774 		this->WriteLoop(buf, size, LZMA_RUN);
2775 	}
2776 
FinishLZMASaveFilter2777 	void Finish() override
2778 	{
2779 		this->WriteLoop(nullptr, 0, LZMA_FINISH);
2780 		this->chain->Finish();
2781 	}
2782 };
2783 
2784 #endif /* WITH_LIBLZMA */
2785 
2786 /*******************************************
2787  ************* END OF CODE *****************
2788  *******************************************/
2789 
2790 /** The format for a reader/writer type of a savegame */
2791 struct SaveLoadFormat {
2792 	const char *name;                     ///< name of the compressor/decompressor (debug-only)
2793 	uint32 tag;                           ///< the 4-letter tag by which it is identified in the savegame
2794 
2795 	LoadFilter *(*init_load)(LoadFilter *chain);                    ///< Constructor for the load filter.
2796 	SaveFilter *(*init_write)(SaveFilter *chain, byte compression); ///< Constructor for the save filter.
2797 
2798 	byte min_compression;                 ///< the minimum compression level of this format
2799 	byte default_compression;             ///< the default compression level of this format
2800 	byte max_compression;                 ///< the maximum compression level of this format
2801 };
2802 
2803 /** The different saveload formats known/understood by OpenTTD. */
2804 static const SaveLoadFormat _saveload_formats[] = {
2805 #if defined(WITH_LZO)
2806 	/* Roughly 75% larger than zlib level 6 at only ~7% of the CPU usage. */
2807 	{"lzo",    TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>,    CreateSaveFilter<LZOSaveFilter>,    0, 0, 0},
2808 #else
2809 	{"lzo",    TO_BE32X('OTTD'), nullptr,                            nullptr,                            0, 0, 0},
2810 #endif
2811 	/* Roughly 5 times larger at only 1% of the CPU usage over zlib level 6. */
2812 	{"none",   TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
2813 #if defined(WITH_ZLIB)
2814 	/* After level 6 the speed reduction is significant (1.5x to 2.5x slower per level), but the reduction in filesize is
2815 	 * fairly insignificant (~1% for each step). Lower levels become ~5-10% bigger by each level than level 6 while level
2816 	 * 1 is "only" 3 times as fast. Level 0 results in uncompressed savegames at about 8 times the cost of "none". */
2817 	{"zlib",   TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>,   CreateSaveFilter<ZlibSaveFilter>,   0, 6, 9},
2818 #else
2819 	{"zlib",   TO_BE32X('OTTZ'), nullptr,                            nullptr,                            0, 0, 0},
2820 #endif
2821 #if defined(WITH_LIBLZMA)
2822 	/* Level 2 compression is speed wise as fast as zlib level 6 compression (old default), but results in ~10% smaller saves.
2823 	 * Higher compression levels are possible, and might improve savegame size by up to 25%, but are also up to 10 times slower.
2824 	 * The next significant reduction in file size is at level 4, but that is already 4 times slower. Level 3 is primarily 50%
2825 	 * slower while not improving the filesize, while level 0 and 1 are faster, but don't reduce savegame size much.
2826 	 * It's OTTX and not e.g. OTTL because liblzma is part of xz-utils and .tar.xz is preferred over .tar.lzma. */
2827 	{"lzma",   TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>,   CreateSaveFilter<LZMASaveFilter>,   0, 2, 9},
2828 #else
2829 	{"lzma",   TO_BE32X('OTTX'), nullptr,                            nullptr,                            0, 0, 0},
2830 #endif
2831 };
2832 
2833 /**
2834  * Return the savegameformat of the game. Whether it was created with ZLIB compression
2835  * uncompressed, or another type
2836  * @param full_name Name of the savegame format. If empty it picks the first available one
2837  * @param compression_level Output for telling what compression level we want.
2838  * @return Pointer to SaveLoadFormat struct giving all characteristics of this type of savegame
2839  */
GetSavegameFormat(const std::string & full_name,byte * compression_level)2840 static const SaveLoadFormat *GetSavegameFormat(const std::string &full_name, byte *compression_level)
2841 {
2842 	const SaveLoadFormat *def = lastof(_saveload_formats);
2843 
2844 	/* find default savegame format, the highest one with which files can be written */
2845 	while (!def->init_write) def--;
2846 
2847 	if (!full_name.empty()) {
2848 		/* Get the ":..." of the compression level out of the way */
2849 		size_t separator = full_name.find(':');
2850 		bool has_comp_level = separator != std::string::npos;
2851 		const std::string name(full_name, 0, has_comp_level ? separator : full_name.size());
2852 
2853 		for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
2854 			if (slf->init_write != nullptr && name.compare(slf->name) == 0) {
2855 				*compression_level = slf->default_compression;
2856 				if (has_comp_level) {
2857 					const std::string complevel(full_name, separator + 1);
2858 
2859 					/* Get the level and determine whether all went fine. */
2860 					size_t processed;
2861 					long level = std::stol(complevel, &processed, 10);
2862 					if (processed == 0 || level != Clamp(level, slf->min_compression, slf->max_compression)) {
2863 						SetDParamStr(0, complevel);
2864 						ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL);
2865 					} else {
2866 						*compression_level = level;
2867 					}
2868 				}
2869 				return slf;
2870 			}
2871 		}
2872 
2873 		SetDParamStr(0, name);
2874 		SetDParamStr(1, def->name);
2875 		ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL);
2876 	}
2877 	*compression_level = def->default_compression;
2878 	return def;
2879 }
2880 
2881 /* actual loader/saver function */
2882 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
2883 extern bool AfterLoadGame();
2884 extern bool LoadOldSaveGame(const std::string &file);
2885 
2886 /**
2887  * Clear temporary data that is passed between various saveload phases.
2888  */
ResetSaveloadData()2889 static void ResetSaveloadData()
2890 {
2891 	ResetTempEngineData();
2892 	ResetLabelMaps();
2893 	ResetOldWaypoints();
2894 }
2895 
2896 /**
2897  * Clear/free saveload state.
2898  */
ClearSaveLoadState()2899 static inline void ClearSaveLoadState()
2900 {
2901 	delete _sl.dumper;
2902 	_sl.dumper = nullptr;
2903 
2904 	delete _sl.sf;
2905 	_sl.sf = nullptr;
2906 
2907 	delete _sl.reader;
2908 	_sl.reader = nullptr;
2909 
2910 	delete _sl.lf;
2911 	_sl.lf = nullptr;
2912 }
2913 
2914 /**
2915  * Update the gui accordingly when starting saving
2916  * and set locks on saveload. Also turn off fast-forward cause with that
2917  * saving takes Aaaaages
2918  */
SaveFileStart()2919 static void SaveFileStart()
2920 {
2921 	_sl.game_speed = _game_speed;
2922 	_game_speed = 100;
2923 	SetMouseCursorBusy(true);
2924 
2925 	InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
2926 	_sl.saveinprogress = true;
2927 }
2928 
2929 /** Update the gui accordingly when saving is done and release locks on saveload. */
SaveFileDone()2930 static void SaveFileDone()
2931 {
2932 	if (_game_mode != GM_MENU) _game_speed = _sl.game_speed;
2933 	SetMouseCursorBusy(false);
2934 
2935 	InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
2936 	_sl.saveinprogress = false;
2937 
2938 #ifdef __EMSCRIPTEN__
2939 	EM_ASM(if (window["openttd_syncfs"]) openttd_syncfs());
2940 #endif
2941 }
2942 
2943 /** Set the error message from outside of the actual loading/saving of the game (AfterLoadGame and friends) */
SetSaveLoadError(StringID str)2944 void SetSaveLoadError(StringID str)
2945 {
2946 	_sl.error_str = str;
2947 }
2948 
2949 /** Get the string representation of the error message */
GetSaveLoadErrorString()2950 const char *GetSaveLoadErrorString()
2951 {
2952 	SetDParam(0, _sl.error_str);
2953 	SetDParamStr(1, _sl.extra_msg);
2954 
2955 	static char err_str[512];
2956 	GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
2957 	return err_str;
2958 }
2959 
2960 /** Show a gui message when saving has failed */
SaveFileError()2961 static void SaveFileError()
2962 {
2963 	SetDParamStr(0, GetSaveLoadErrorString());
2964 	ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
2965 	SaveFileDone();
2966 }
2967 
2968 /**
2969  * We have written the whole game into memory, _memory_savegame, now find
2970  * and appropriate compressor and start writing to file.
2971  */
SaveFileToDisk(bool threaded)2972 static SaveOrLoadResult SaveFileToDisk(bool threaded)
2973 {
2974 	try {
2975 		byte compression;
2976 		const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
2977 
2978 		/* We have written our stuff to memory, now write it to file! */
2979 		uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
2980 		_sl.sf->Write((byte*)hdr, sizeof(hdr));
2981 
2982 		_sl.sf = fmt->init_write(_sl.sf, compression);
2983 		_sl.dumper->Flush(_sl.sf);
2984 
2985 		ClearSaveLoadState();
2986 
2987 		if (threaded) SetAsyncSaveFinish(SaveFileDone);
2988 
2989 		return SL_OK;
2990 	} catch (...) {
2991 		ClearSaveLoadState();
2992 
2993 		AsyncSaveFinishProc asfp = SaveFileDone;
2994 
2995 		/* We don't want to shout when saving is just
2996 		 * cancelled due to a client disconnecting. */
2997 		if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
2998 			/* Skip the "colour" character */
2999 			Debug(sl, 0, "{}", GetSaveLoadErrorString() + 3);
3000 			asfp = SaveFileError;
3001 		}
3002 
3003 		if (threaded) {
3004 			SetAsyncSaveFinish(asfp);
3005 		} else {
3006 			asfp();
3007 		}
3008 		return SL_ERROR;
3009 	}
3010 }
3011 
WaitTillSaved()3012 void WaitTillSaved()
3013 {
3014 	if (!_save_thread.joinable()) return;
3015 
3016 	_save_thread.join();
3017 
3018 	/* Make sure every other state is handled properly as well. */
3019 	ProcessAsyncSaveFinish();
3020 }
3021 
3022 /**
3023  * Actually perform the saving of the savegame.
3024  * General tactics is to first save the game to memory, then write it to file
3025  * using the writer, either in threaded mode if possible, or single-threaded.
3026  * @param writer   The filter to write the savegame to.
3027  * @param threaded Whether to try to perform the saving asynchronously.
3028  * @return Return the result of the action. #SL_OK or #SL_ERROR
3029  */
DoSave(SaveFilter * writer,bool threaded)3030 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
3031 {
3032 	assert(!_sl.saveinprogress);
3033 
3034 	_sl.dumper = new MemoryDumper();
3035 	_sl.sf = writer;
3036 
3037 	_sl_version = SAVEGAME_VERSION;
3038 
3039 	SaveViewportBeforeSaveGame();
3040 	SlSaveChunks();
3041 
3042 	SaveFileStart();
3043 
3044 	if (!threaded || !StartNewThread(&_save_thread, "ottd:savegame", &SaveFileToDisk, true)) {
3045 		if (threaded) Debug(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
3046 
3047 		SaveOrLoadResult result = SaveFileToDisk(false);
3048 		SaveFileDone();
3049 
3050 		return result;
3051 	}
3052 
3053 	return SL_OK;
3054 }
3055 
3056 /**
3057  * Save the game using a (writer) filter.
3058  * @param writer   The filter to write the savegame to.
3059  * @param threaded Whether to try to perform the saving asynchronously.
3060  * @return Return the result of the action. #SL_OK or #SL_ERROR
3061  */
SaveWithFilter(SaveFilter * writer,bool threaded)3062 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
3063 {
3064 	try {
3065 		_sl.action = SLA_SAVE;
3066 		return DoSave(writer, threaded);
3067 	} catch (...) {
3068 		ClearSaveLoadState();
3069 		return SL_ERROR;
3070 	}
3071 }
3072 
3073 /**
3074  * Actually perform the loading of a "non-old" savegame.
3075  * @param reader     The filter to read the savegame from.
3076  * @param load_check Whether to perform the checking ("preview") or actually load the game.
3077  * @return Return the result of the action. #SL_OK or #SL_REINIT ("unload" the game)
3078  */
DoLoad(LoadFilter * reader,bool load_check)3079 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
3080 {
3081 	_sl.lf = reader;
3082 
3083 	if (load_check) {
3084 		/* Clear previous check data */
3085 		_load_check_data.Clear();
3086 		/* Mark SL_LOAD_CHECK as supported for this savegame. */
3087 		_load_check_data.checkable = true;
3088 	}
3089 
3090 	uint32 hdr[2];
3091 	if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
3092 
3093 	/* see if we have any loader for this type. */
3094 	const SaveLoadFormat *fmt = _saveload_formats;
3095 	for (;;) {
3096 		/* No loader found, treat as version 0 and use LZO format */
3097 		if (fmt == endof(_saveload_formats)) {
3098 			Debug(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
3099 			_sl.lf->Reset();
3100 			_sl_version = SL_MIN_VERSION;
3101 			_sl_minor_version = 0;
3102 
3103 			/* Try to find the LZO savegame format; it uses 'OTTD' as tag. */
3104 			fmt = _saveload_formats;
3105 			for (;;) {
3106 				if (fmt == endof(_saveload_formats)) {
3107 					/* Who removed LZO support? */
3108 					NOT_REACHED();
3109 				}
3110 				if (fmt->tag == TO_BE32X('OTTD')) break;
3111 				fmt++;
3112 			}
3113 			break;
3114 		}
3115 
3116 		if (fmt->tag == hdr[0]) {
3117 			/* check version number */
3118 			_sl_version = (SaveLoadVersion)(TO_BE32(hdr[1]) >> 16);
3119 			/* Minor is not used anymore from version 18.0, but it is still needed
3120 			 * in versions before that (4 cases) which can't be removed easy.
3121 			 * Therefore it is loaded, but never saved (or, it saves a 0 in any scenario). */
3122 			_sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
3123 
3124 			Debug(sl, 1, "Loading savegame version {}", _sl_version);
3125 
3126 			/* Is the version higher than the current? */
3127 			if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
3128 			if (_sl_version >= SLV_START_PATCHPACKS && _sl_version <= SLV_END_PATCHPACKS) SlError(STR_GAME_SAVELOAD_ERROR_PATCHPACK);
3129 			break;
3130 		}
3131 
3132 		fmt++;
3133 	}
3134 
3135 	/* loader for this savegame type is not implemented? */
3136 	if (fmt->init_load == nullptr) {
3137 		char err_str[64];
3138 		seprintf(err_str, lastof(err_str), "Loader for '%s' is not available.", fmt->name);
3139 		SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
3140 	}
3141 
3142 	_sl.lf = fmt->init_load(_sl.lf);
3143 	_sl.reader = new ReadBuffer(_sl.lf);
3144 	_next_offs = 0;
3145 
3146 	if (!load_check) {
3147 		ResetSaveloadData();
3148 
3149 		/* Old maps were hardcoded to 256x256 and thus did not contain
3150 		 * any mapsize information. Pre-initialize to 256x256 to not to
3151 		 * confuse old games */
3152 		InitializeGame(256, 256, true, true);
3153 
3154 		GamelogReset();
3155 
3156 		if (IsSavegameVersionBefore(SLV_4)) {
3157 			/*
3158 			 * NewGRFs were introduced between 0.3,4 and 0.3.5, which both
3159 			 * shared savegame version 4. Anything before that 'obviously'
3160 			 * does not have any NewGRFs. Between the introduction and
3161 			 * savegame version 41 (just before 0.5) the NewGRF settings
3162 			 * were not stored in the savegame and they were loaded by
3163 			 * using the settings from the main menu.
3164 			 * So, to recap:
3165 			 * - savegame version  <  4:  do not load any NewGRFs.
3166 			 * - savegame version >= 41:  load NewGRFs from savegame, which is
3167 			 *                            already done at this stage by
3168 			 *                            overwriting the main menu settings.
3169 			 * - other savegame versions: use main menu settings.
3170 			 *
3171 			 * This means that users *can* crash savegame version 4..40
3172 			 * savegames if they set incompatible NewGRFs in the main menu,
3173 			 * but can't crash anymore for savegame version < 4 savegames.
3174 			 *
3175 			 * Note: this is done here because AfterLoadGame is also called
3176 			 * for TTO/TTD/TTDP savegames which have their own NewGRF logic.
3177 			 */
3178 			ClearGRFConfigList(&_grfconfig);
3179 		}
3180 	}
3181 
3182 	if (load_check) {
3183 		/* Load chunks into _load_check_data.
3184 		 * No pools are loaded. References are not possible, and thus do not need resolving. */
3185 		SlLoadCheckChunks();
3186 	} else {
3187 		/* Load chunks and resolve references */
3188 		SlLoadChunks();
3189 		SlFixPointers();
3190 	}
3191 
3192 	ClearSaveLoadState();
3193 
3194 	_savegame_type = SGT_OTTD;
3195 
3196 	if (load_check) {
3197 		/* The only part from AfterLoadGame() we need */
3198 		_load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
3199 	} else {
3200 		GamelogStartAction(GLAT_LOAD);
3201 
3202 		/* After loading fix up savegame for any internal changes that
3203 		 * might have occurred since then. If it fails, load back the old game. */
3204 		if (!AfterLoadGame()) {
3205 			GamelogStopAction();
3206 			return SL_REINIT;
3207 		}
3208 
3209 		GamelogStopAction();
3210 	}
3211 
3212 	return SL_OK;
3213 }
3214 
3215 /**
3216  * Load the game using a (reader) filter.
3217  * @param reader   The filter to read the savegame from.
3218  * @return Return the result of the action. #SL_OK or #SL_REINIT ("unload" the game)
3219  */
LoadWithFilter(LoadFilter * reader)3220 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
3221 {
3222 	try {
3223 		_sl.action = SLA_LOAD;
3224 		return DoLoad(reader, false);
3225 	} catch (...) {
3226 		ClearSaveLoadState();
3227 		return SL_REINIT;
3228 	}
3229 }
3230 
3231 /**
3232  * Main Save or Load function where the high-level saveload functions are
3233  * handled. It opens the savegame, selects format and checks versions
3234  * @param filename The name of the savegame being created/loaded
3235  * @param fop Save or load mode. Load can also be a TTD(Patch) game.
3236  * @param sb The sub directory to save the savegame in
3237  * @param threaded True when threaded saving is allowed
3238  * @return Return the result of the action. #SL_OK, #SL_ERROR, or #SL_REINIT ("unload" the game)
3239  */
SaveOrLoad(const std::string & filename,SaveLoadOperation fop,DetailedFileType dft,Subdirectory sb,bool threaded)3240 SaveOrLoadResult SaveOrLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileType dft, Subdirectory sb, bool threaded)
3241 {
3242 	/* An instance of saving is already active, so don't go saving again */
3243 	if (_sl.saveinprogress && fop == SLO_SAVE && dft == DFT_GAME_FILE && threaded) {
3244 		/* if not an autosave, but a user action, show error message */
3245 		if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
3246 		return SL_OK;
3247 	}
3248 	WaitTillSaved();
3249 
3250 	try {
3251 		/* Load a TTDLX or TTDPatch game */
3252 		if (fop == SLO_LOAD && dft == DFT_OLD_GAME_FILE) {
3253 			ResetSaveloadData();
3254 
3255 			InitializeGame(256, 256, true, true); // set a mapsize of 256x256 for TTDPatch games or it might get confused
3256 
3257 			/* TTD/TTO savegames have no NewGRFs, TTDP savegame have them
3258 			 * and if so a new NewGRF list will be made in LoadOldSaveGame.
3259 			 * Note: this is done here because AfterLoadGame is also called
3260 			 * for OTTD savegames which have their own NewGRF logic. */
3261 			ClearGRFConfigList(&_grfconfig);
3262 			GamelogReset();
3263 			if (!LoadOldSaveGame(filename)) return SL_REINIT;
3264 			_sl_version = SL_MIN_VERSION;
3265 			_sl_minor_version = 0;
3266 			GamelogStartAction(GLAT_LOAD);
3267 			if (!AfterLoadGame()) {
3268 				GamelogStopAction();
3269 				return SL_REINIT;
3270 			}
3271 			GamelogStopAction();
3272 			return SL_OK;
3273 		}
3274 
3275 		assert(dft == DFT_GAME_FILE);
3276 		switch (fop) {
3277 			case SLO_CHECK:
3278 				_sl.action = SLA_LOAD_CHECK;
3279 				break;
3280 
3281 			case SLO_LOAD:
3282 				_sl.action = SLA_LOAD;
3283 				break;
3284 
3285 			case SLO_SAVE:
3286 				_sl.action = SLA_SAVE;
3287 				break;
3288 
3289 			default: NOT_REACHED();
3290 		}
3291 
3292 		FILE *fh = (fop == SLO_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
3293 
3294 		/* Make it a little easier to load savegames from the console */
3295 		if (fh == nullptr && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
3296 		if (fh == nullptr && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
3297 		if (fh == nullptr && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
3298 
3299 		if (fh == nullptr) {
3300 			SlError(fop == SLO_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
3301 		}
3302 
3303 		if (fop == SLO_SAVE) { // SAVE game
3304 			Debug(desync, 1, "save: {:08x}; {:02x}; {}", _date, _date_fract, filename);
3305 			if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
3306 
3307 			return DoSave(new FileWriter(fh), threaded);
3308 		}
3309 
3310 		/* LOAD game */
3311 		assert(fop == SLO_LOAD || fop == SLO_CHECK);
3312 		Debug(desync, 1, "load: {}", filename);
3313 		return DoLoad(new FileReader(fh), fop == SLO_CHECK);
3314 	} catch (...) {
3315 		/* This code may be executed both for old and new save games. */
3316 		ClearSaveLoadState();
3317 
3318 		/* Skip the "colour" character */
3319 		if (fop != SLO_CHECK) Debug(sl, 0, "{}", GetSaveLoadErrorString());
3320 
3321 		/* A saver/loader exception!! reinitialize all variables to prevent crash! */
3322 		return (fop == SLO_LOAD) ? SL_REINIT : SL_ERROR;
3323 	}
3324 }
3325 
3326 /**
3327  * Create an autosave or netsave.
3328  * @param counter A reference to the counter variable to be used for rotating the file name.
3329  * @param netsave Indicates if this is a regular autosave or a netsave.
3330  */
DoAutoOrNetsave(FiosNumberedSaveName & counter)3331 void DoAutoOrNetsave(FiosNumberedSaveName &counter)
3332 {
3333 	char buf[MAX_PATH];
3334 
3335 	if (_settings_client.gui.keep_all_autosave) {
3336 		GenerateDefaultSaveName(buf, lastof(buf));
3337 		strecat(buf, counter.Extension().c_str(), lastof(buf));
3338 	} else {
3339 		strecpy(buf, counter.Filename().c_str(), lastof(buf));
3340 	}
3341 
3342 	Debug(sl, 2, "Autosaving to '{}'", buf);
3343 	if (SaveOrLoad(buf, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR) != SL_OK) {
3344 		ShowErrorMessage(STR_ERROR_AUTOSAVE_FAILED, INVALID_STRING_ID, WL_ERROR);
3345 	}
3346 }
3347 
3348 
3349 /** Do a save when exiting the game (_settings_client.gui.autosave_on_exit) */
DoExitSave()3350 void DoExitSave()
3351 {
3352 	SaveOrLoad("exit.sav", SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR);
3353 }
3354 
3355 /**
3356  * Fill the buffer with the default name for a savegame *or* screenshot.
3357  * @param buf the buffer to write to.
3358  * @param last the last element in the buffer.
3359  */
GenerateDefaultSaveName(char * buf,const char * last)3360 void GenerateDefaultSaveName(char *buf, const char *last)
3361 {
3362 	/* Check if we have a name for this map, which is the name of the first
3363 	 * available company. When there's no company available we'll use
3364 	 * 'Spectator' as "company" name. */
3365 	CompanyID cid = _local_company;
3366 	if (!Company::IsValidID(cid)) {
3367 		for (const Company *c : Company::Iterate()) {
3368 			cid = c->index;
3369 			break;
3370 		}
3371 	}
3372 
3373 	SetDParam(0, cid);
3374 
3375 	/* Insert current date */
3376 	switch (_settings_client.gui.date_format_in_default_names) {
3377 		case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
3378 		case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
3379 		case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
3380 		default: NOT_REACHED();
3381 	}
3382 	SetDParam(2, _date);
3383 
3384 	/* Get the correct string (special string for when there's not company) */
3385 	GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
3386 	SanitizeFilename(buf);
3387 }
3388 
3389 /**
3390  * Set the mode and file type of the file to save or load based on the type of file entry at the file system.
3391  * @param ft Type of file entry of the file system.
3392  */
SetMode(FiosType ft)3393 void FileToSaveLoad::SetMode(FiosType ft)
3394 {
3395 	this->SetMode(SLO_LOAD, GetAbstractFileType(ft), GetDetailedFileType(ft));
3396 }
3397 
3398 /**
3399  * Set the mode and file type of the file to save or load.
3400  * @param fop File operation being performed.
3401  * @param aft Abstract file type.
3402  * @param dft Detailed file type.
3403  */
SetMode(SaveLoadOperation fop,AbstractFileType aft,DetailedFileType dft)3404 void FileToSaveLoad::SetMode(SaveLoadOperation fop, AbstractFileType aft, DetailedFileType dft)
3405 {
3406 	if (aft == FT_INVALID || aft == FT_NONE) {
3407 		this->file_op = SLO_INVALID;
3408 		this->detail_ftype = DFT_INVALID;
3409 		this->abstract_ftype = FT_INVALID;
3410 		return;
3411 	}
3412 
3413 	this->file_op = fop;
3414 	this->detail_ftype = dft;
3415 	this->abstract_ftype = aft;
3416 }
3417 
3418 /**
3419  * Set the name of the file.
3420  * @param name Name of the file.
3421  */
SetName(const char * name)3422 void FileToSaveLoad::SetName(const char *name)
3423 {
3424 	this->name = name;
3425 }
3426 
3427 /**
3428  * Set the title of the file.
3429  * @param title Title of the file.
3430  */
SetTitle(const char * title)3431 void FileToSaveLoad::SetTitle(const char *title)
3432 {
3433 	strecpy(this->title, title, lastof(this->title));
3434 }
3435 
GetLoadDescription() const3436 SaveLoadTable SaveLoadHandler::GetLoadDescription() const
3437 {
3438 	assert(this->load_description.has_value());
3439 	return *this->load_description;
3440 }
3441