~ubuntu-branches/debian/squeeze/openttd/squeeze

« back to all changes in this revision

Viewing changes to src/saveload.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jordi Mallach, Matthijs Kooijman, Jordi Mallach
  • Date: 2009-04-15 18:22:10 UTC
  • mfrom: (1.1.6 upstream) (2.1.3 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090415182210-22ktb8kdbp2tf3bm
[ Matthijs Kooijman ]
* New upstream release.
* Remove Debian specific desktop file, upstream provides one now. 
* Add debian/watch file.

[ Jordi Mallach ]
* Bump Standards-Version to 3.8.1, with no changes required.
* Move to debhelper compat 7. Bump Build-Depends accordingly.
* Use dh_prep.
* Add "set -e" to config script.
* Remove a few extra doc files that get installed by upstream Makefile.
* Add more complete copyright information.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: saveload.cpp 13685 2008-07-09 18:59:39Z rubidium $ */
2
 
 
3
 
/** @file saveload.cpp
4
 
 * All actions handling saving and loading goes on in this file. The general actions
5
 
 * are as follows for saving a game (loading is analogous):
6
 
 * <ol>
7
 
 * <li>initialize the writer by creating a temporary memory-buffer for it
8
 
 * <li>go through all to-be saved elements, each 'chunk' (ChunkHandler) prefixed by a label
9
 
 * <li>use their description array (SaveLoad) to know what elements to save and in what version
10
 
 *    of the game it was active (used when loading)
11
 
 * <li>write all data byte-by-byte to the temporary buffer so it is endian-safe
12
 
 * <li>when the buffer is full; flush it to the output (eg save to file) (_sl.buf, _sl.bufp, _sl.bufe)
13
 
 * <li>repeat this until everything is done, and flush any remaining output to file
14
 
 * </ol>
15
 
 */
16
 
#include "stdafx.h"
17
 
#include "openttd.h"
18
 
#include "debug.h"
19
 
#include "station.h"
20
 
#include "thread.h"
21
 
#include "town.h"
22
 
#include "saveload.h"
23
 
#include "network/network.h"
24
 
#include "variables.h"
25
 
#include "window_func.h"
26
 
#include "strings_func.h"
27
 
#include "gfx_func.h"
28
 
#include "core/alloc_func.hpp"
29
 
#include "functions.h"
30
 
#include "core/endian_func.hpp"
31
 
#include "vehicle_base.h"
32
 
#include "autoreplace_base.h"
33
 
#include <list>
34
 
 
35
 
#include "table/strings.h"
36
 
 
37
 
extern const uint16 SAVEGAME_VERSION = 92;
38
 
uint16 _sl_version;       ///< the major savegame version identifier
39
 
byte   _sl_minor_version; ///< the minor savegame version, DO NOT USE!
40
 
 
41
 
typedef void WriterProc(uint len);
42
 
typedef uint ReaderProc();
43
 
 
44
 
/** The saveload struct, containing reader-writer functions, bufffer, version, etc. */
45
 
static struct {
46
 
        bool save;                           ///< are we doing a save or a load atm. True when saving
47
 
        byte need_length;                    ///< ???
48
 
        byte block_mode;                     ///< ???
49
 
        bool error;                          ///< did an error occur or not
50
 
 
51
 
        int obj_len;                         ///< the length of the current object we are busy with
52
 
        int array_index, last_array_index;   ///< in the case of an array, the current and last positions
53
 
 
54
 
        uint32 offs_base;                    ///< the offset in number of bytes since we started writing data (eg uncompressed savegame size)
55
 
 
56
 
        WriterProc *write_bytes;             ///< savegame writer function
57
 
        ReaderProc *read_bytes;              ///< savegame loader function
58
 
 
59
 
        const ChunkHandler* const *chs;      ///< the chunk of data that is being processed atm (vehicles, signs, etc.)
60
 
 
61
 
        /* When saving/loading savegames, they are always saved to a temporary memory-place
62
 
         * to be flushed to file (save) or to final place (load) when full. */
63
 
        byte *bufp, *bufe;                   ///< bufp(ointer) gives the current position in the buffer bufe(nd) gives the end of the buffer
64
 
 
65
 
        /* these 3 may be used by compressor/decompressors. */
66
 
        byte *buf;                           ///< pointer to temporary memory to read/write, initialized by SaveLoadFormat->initread/write
67
 
        byte *buf_ori;                       ///< pointer to the original memory location of buf, used to free it afterwards
68
 
        uint bufsize;                        ///< the size of the temporary memory *buf
69
 
        FILE *fh;                            ///< the file from which is read or written to
70
 
 
71
 
        void (*excpt_uninit)();              ///< the function to execute on any encountered error
72
 
        StringID error_str;                  ///< the translateable error message to show
73
 
        char *extra_msg;                     ///< the error message
74
 
} _sl;
75
 
 
76
 
 
77
 
enum NeedLengthValues {NL_NONE = 0, NL_WANTLENGTH = 1, NL_CALCLENGTH = 2};
78
 
 
79
 
/** Error handler, calls longjmp to simulate an exception.
80
 
 * @todo this was used to have a central place to handle errors, but it is
81
 
 * pretty ugly, and seriously interferes with any multithreaded approaches */
82
 
static void NORETURN SlError(StringID string, const char *extra_msg = NULL)
83
 
{
84
 
        _sl.error_str = string;
85
 
        free(_sl.extra_msg);
86
 
        _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
87
 
        throw std::exception();
88
 
}
89
 
 
90
 
/**
91
 
 * Fill the input buffer by reading from the file with the given reader
92
 
 */
93
 
static void SlReadFill()
94
 
{
95
 
        uint len = _sl.read_bytes();
96
 
        if (len == 0) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected end of chunk");
97
 
 
98
 
        _sl.bufp = _sl.buf;
99
 
        _sl.bufe = _sl.buf + len;
100
 
        _sl.offs_base += len;
101
 
}
102
 
 
103
 
static inline uint32 SlGetOffs() {return _sl.offs_base - (_sl.bufe - _sl.bufp);}
104
 
 
105
 
/** Return the size in bytes of a certain type of normal/atomic variable
106
 
 * as it appears in memory. See VarTypes
107
 
 * @param conv VarType type of variable that is used for calculating the size
108
 
 * @return Return the size of this type in bytes */
109
 
static inline byte SlCalcConvMemLen(VarType conv)
110
 
{
111
 
        static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
112
 
        byte length = GB(conv, 4, 4);
113
 
        assert(length < lengthof(conv_mem_size));
114
 
        return conv_mem_size[length];
115
 
}
116
 
 
117
 
/** Return the size in bytes of a certain type of normal/atomic variable
118
 
 * as it appears in a saved game. See VarTypes
119
 
 * @param conv VarType type of variable that is used for calculating the size
120
 
 * @return Return the size of this type in bytes */
121
 
static inline byte SlCalcConvFileLen(VarType conv)
122
 
{
123
 
        static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
124
 
        byte length = GB(conv, 0, 4);
125
 
        assert(length < lengthof(conv_file_size));
126
 
        return conv_file_size[length];
127
 
}
128
 
 
129
 
/** Return the size in bytes of a reference (pointer) */
130
 
static inline size_t SlCalcRefLen() {return CheckSavegameVersion(69) ? 2 : 4;}
131
 
 
132
 
/** Flush the output buffer by writing to disk with the given reader.
133
 
 * If the buffer pointer has not yet been set up, set it up now. Usually
134
 
 * only called when the buffer is full, or there is no more data to be processed
135
 
 */
136
 
static void SlWriteFill()
137
 
{
138
 
        /* flush the buffer to disk (the writer) */
139
 
        if (_sl.bufp != NULL) {
140
 
                uint len = _sl.bufp - _sl.buf;
141
 
                _sl.offs_base += len;
142
 
                if (len) _sl.write_bytes(len);
143
 
        }
144
 
 
145
 
        /* All the data from the buffer has been written away, rewind to the beginning
146
 
         * to start reading in more data */
147
 
        _sl.bufp = _sl.buf;
148
 
        _sl.bufe = _sl.buf + _sl.bufsize;
149
 
}
150
 
 
151
 
/** Read in a single byte from file. If the temporary buffer is full,
152
 
 * flush it to its final destination
153
 
 * @return return the read byte from file
154
 
 */
155
 
static inline byte SlReadByteInternal()
156
 
{
157
 
        if (_sl.bufp == _sl.bufe) SlReadFill();
158
 
        return *_sl.bufp++;
159
 
}
160
 
 
161
 
/** Wrapper for SlReadByteInternal */
162
 
byte SlReadByte() {return SlReadByteInternal();}
163
 
 
164
 
/** Write away a single byte from memory. If the temporary buffer is full,
165
 
 * flush it to its destination (file)
166
 
 * @param b the byte that is currently written
167
 
 */
168
 
static inline void SlWriteByteInternal(byte b)
169
 
{
170
 
        if (_sl.bufp == _sl.bufe) SlWriteFill();
171
 
        *_sl.bufp++ = b;
172
 
}
173
 
 
174
 
/** Wrapper for SlWriteByteInternal */
175
 
void SlWriteByte(byte b) {SlWriteByteInternal(b);}
176
 
 
177
 
static inline int SlReadUint16()
178
 
{
179
 
        int x = SlReadByte() << 8;
180
 
        return x | SlReadByte();
181
 
}
182
 
 
183
 
static inline uint32 SlReadUint32()
184
 
{
185
 
        uint32 x = SlReadUint16() << 16;
186
 
        return x | SlReadUint16();
187
 
}
188
 
 
189
 
static inline uint64 SlReadUint64()
190
 
{
191
 
        uint32 x = SlReadUint32();
192
 
        uint32 y = SlReadUint32();
193
 
        return (uint64)x << 32 | y;
194
 
}
195
 
 
196
 
static inline void SlWriteUint16(uint16 v)
197
 
{
198
 
        SlWriteByte(GB(v, 8, 8));
199
 
        SlWriteByte(GB(v, 0, 8));
200
 
}
201
 
 
202
 
static inline void SlWriteUint32(uint32 v)
203
 
{
204
 
        SlWriteUint16(GB(v, 16, 16));
205
 
        SlWriteUint16(GB(v,  0, 16));
206
 
}
207
 
 
208
 
static inline void SlWriteUint64(uint64 x)
209
 
{
210
 
        SlWriteUint32((uint32)(x >> 32));
211
 
        SlWriteUint32((uint32)x);
212
 
}
213
 
 
214
 
/**
215
 
 * Read in the header descriptor of an object or an array.
216
 
 * If the highest bit is set (7), then the index is bigger than 127
217
 
 * elements, so use the next byte to read in the real value.
218
 
 * The actual value is then both bytes added with the first shifted
219
 
 * 8 bits to the left, and dropping the highest bit (which only indicated a big index).
220
 
 * x = ((x & 0x7F) << 8) + SlReadByte();
221
 
 * @return Return the value of the index
222
 
 */
223
 
static uint SlReadSimpleGamma()
224
 
{
225
 
        uint i = SlReadByte();
226
 
        if (HasBit(i, 7)) {
227
 
                i &= ~0x80;
228
 
                if (HasBit(i, 6)) {
229
 
                        i &= ~0x40;
230
 
                        if (HasBit(i, 5)) {
231
 
                                i &= ~0x20;
232
 
                                if (HasBit(i, 4))
233
 
                                        SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unsupported gamma");
234
 
                                i = (i << 8) | SlReadByte();
235
 
                        }
236
 
                        i = (i << 8) | SlReadByte();
237
 
                }
238
 
                i = (i << 8) | SlReadByte();
239
 
        }
240
 
        return i;
241
 
}
242
 
 
243
 
/**
244
 
 * Write the header descriptor of an object or an array.
245
 
 * If the element is bigger than 127, use 2 bytes for saving
246
 
 * and use the highest byte of the first written one as a notice
247
 
 * that the length consists of 2 bytes, etc.. like this:
248
 
 * 0xxxxxxx
249
 
 * 10xxxxxx xxxxxxxx
250
 
 * 110xxxxx xxxxxxxx xxxxxxxx
251
 
 * 1110xxxx xxxxxxxx xxxxxxxx xxxxxxxx
252
 
 * @param i Index being written
253
 
 */
254
 
 
255
 
static void SlWriteSimpleGamma(uint i)
256
 
{
257
 
        if (i >= (1 << 7)) {
258
 
                if (i >= (1 << 14)) {
259
 
                        if (i >= (1 << 21)) {
260
 
                                assert(i < (1 << 28));
261
 
                                SlWriteByte((byte)0xE0 | (i >> 24));
262
 
                                SlWriteByte((byte)(i >> 16));
263
 
                        } else {
264
 
                                SlWriteByte((byte)0xC0 | (i >> 16));
265
 
                        }
266
 
                        SlWriteByte((byte)(i >> 8));
267
 
                } else {
268
 
                        SlWriteByte((byte)(0x80 | (i >> 8)));
269
 
                }
270
 
        }
271
 
        SlWriteByte(i);
272
 
}
273
 
 
274
 
/** Return how many bytes used to encode a gamma value */
275
 
static inline uint SlGetGammaLength(uint i)
276
 
{
277
 
        return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
278
 
}
279
 
 
280
 
static inline uint SlReadSparseIndex() {return SlReadSimpleGamma();}
281
 
static inline void SlWriteSparseIndex(uint index) {SlWriteSimpleGamma(index);}
282
 
 
283
 
static inline uint SlReadArrayLength() {return SlReadSimpleGamma();}
284
 
static inline void SlWriteArrayLength(uint length) {SlWriteSimpleGamma(length);}
285
 
static inline uint SlGetArrayLength(uint length) {return SlGetGammaLength(length);}
286
 
 
287
 
void SlSetArrayIndex(uint index)
288
 
{
289
 
        _sl.need_length = NL_WANTLENGTH;
290
 
        _sl.array_index = index;
291
 
}
292
 
 
293
 
static uint32 _next_offs;
294
 
 
295
 
/**
296
 
 * Iterate through the elements of an array and read the whole thing
297
 
 * @return The index of the object, or -1 if we have reached the end of current block
298
 
 */
299
 
int SlIterateArray()
300
 
{
301
 
        int index;
302
 
 
303
 
        /* After reading in the whole array inside the loop
304
 
         * we must have read in all the data, so we must be at end of current block. */
305
 
        if (_next_offs != 0 && SlGetOffs() != _next_offs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
306
 
 
307
 
        while (true) {
308
 
                uint length = SlReadArrayLength();
309
 
                if (length == 0) {
310
 
                        _next_offs = 0;
311
 
                        return -1;
312
 
                }
313
 
 
314
 
                _sl.obj_len = --length;
315
 
                _next_offs = SlGetOffs() + length;
316
 
 
317
 
                switch (_sl.block_mode) {
318
 
                case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
319
 
                case CH_ARRAY:        index = _sl.array_index++; break;
320
 
                default:
321
 
                        DEBUG(sl, 0, "SlIterateArray error");
322
 
                        return -1; // error
323
 
                }
324
 
 
325
 
                if (length != 0) return index;
326
 
        }
327
 
}
328
 
 
329
 
/**
330
 
 * Sets the length of either a RIFF object or the number of items in an array.
331
 
 * This lets us load an object or an array of arbitrary size
332
 
 * @param length The length of the sought object/array
333
 
 */
334
 
void SlSetLength(size_t length)
335
 
{
336
 
        assert(_sl.save);
337
 
 
338
 
        switch (_sl.need_length) {
339
 
        case NL_WANTLENGTH:
340
 
                _sl.need_length = NL_NONE;
341
 
                switch (_sl.block_mode) {
342
 
                case CH_RIFF:
343
 
                        /* Ugly encoding of >16M RIFF chunks
344
 
                         * The lower 24 bits are normal
345
 
                         * The uppermost 4 bits are bits 24:27 */
346
 
                        assert(length < (1<<28));
347
 
                        SlWriteUint32((length & 0xFFFFFF) | ((length >> 24) << 28));
348
 
                        break;
349
 
                case CH_ARRAY:
350
 
                        assert(_sl.last_array_index <= _sl.array_index);
351
 
                        while (++_sl.last_array_index <= _sl.array_index)
352
 
                                SlWriteArrayLength(1);
353
 
                        SlWriteArrayLength(length + 1);
354
 
                        break;
355
 
                case CH_SPARSE_ARRAY:
356
 
                        SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index)); // Also include length of sparse index.
357
 
                        SlWriteSparseIndex(_sl.array_index);
358
 
                        break;
359
 
                default: NOT_REACHED();
360
 
                } break;
361
 
        case NL_CALCLENGTH:
362
 
                _sl.obj_len += length;
363
 
                break;
364
 
        }
365
 
}
366
 
 
367
 
/**
368
 
 * Save/Load bytes. These do not need to be converted to Little/Big Endian
369
 
 * so directly write them or read them to/from file
370
 
 * @param ptr The source or destination of the object being manipulated
371
 
 * @param length number of bytes this fast CopyBytes lasts
372
 
 */
373
 
static void SlCopyBytes(void *ptr, size_t length)
374
 
{
375
 
        byte *p = (byte*)ptr;
376
 
 
377
 
        if (_sl.save) {
378
 
                for (; length != 0; length--) {SlWriteByteInternal(*p++);}
379
 
        } else {
380
 
                for (; length != 0; length--) {*p++ = SlReadByteInternal();}
381
 
        }
382
 
}
383
 
 
384
 
/** Read in bytes from the file/data structure but don't do
385
 
 * anything with them, discarding them in effect
386
 
 * @param length The amount of bytes that is being treated this way
387
 
 */
388
 
static inline void SlSkipBytes(size_t length)
389
 
{
390
 
        for (; length != 0; length--) SlReadByte();
391
 
}
392
 
 
393
 
/* Get the length of the current object */
394
 
uint SlGetFieldLength() {return _sl.obj_len;}
395
 
 
396
 
/** Return a signed-long version of the value of a setting
397
 
 * @param ptr pointer to the variable
398
 
 * @param conv type of variable, can be a non-clean
399
 
 * type, eg one with other flags because it is parsed
400
 
 * @return returns the value of the pointer-setting */
401
 
int64 ReadValue(const void *ptr, VarType conv)
402
 
{
403
 
        switch (GetVarMemType(conv)) {
404
 
        case SLE_VAR_BL:  return (*(bool*)ptr != 0);
405
 
        case SLE_VAR_I8:  return *(int8*  )ptr;
406
 
        case SLE_VAR_U8:  return *(byte*  )ptr;
407
 
        case SLE_VAR_I16: return *(int16* )ptr;
408
 
        case SLE_VAR_U16: return *(uint16*)ptr;
409
 
        case SLE_VAR_I32: return *(int32* )ptr;
410
 
        case SLE_VAR_U32: return *(uint32*)ptr;
411
 
        case SLE_VAR_I64: return *(int64* )ptr;
412
 
        case SLE_VAR_U64: return *(uint64*)ptr;
413
 
        case SLE_VAR_NULL:return 0;
414
 
        default: NOT_REACHED();
415
 
        }
416
 
 
417
 
        /* useless, but avoids compiler warning this way */
418
 
        return 0;
419
 
}
420
 
 
421
 
/** Write the value of a setting
422
 
 * @param ptr pointer to the variable
423
 
 * @param conv type of variable, can be a non-clean type, eg
424
 
 *             with other flags. It is parsed upon read
425
 
 * @param val the new value being given to the variable */
426
 
void WriteValue(void *ptr, VarType conv, int64 val)
427
 
{
428
 
        switch (GetVarMemType(conv)) {
429
 
        case SLE_VAR_BL:  *(bool  *)ptr = (val != 0);  break;
430
 
        case SLE_VAR_I8:  *(int8  *)ptr = val; break;
431
 
        case SLE_VAR_U8:  *(byte  *)ptr = val; break;
432
 
        case SLE_VAR_I16: *(int16 *)ptr = val; break;
433
 
        case SLE_VAR_U16: *(uint16*)ptr = val; break;
434
 
        case SLE_VAR_I32: *(int32 *)ptr = val; break;
435
 
        case SLE_VAR_U32: *(uint32*)ptr = val; break;
436
 
        case SLE_VAR_I64: *(int64 *)ptr = val; break;
437
 
        case SLE_VAR_U64: *(uint64*)ptr = val; break;
438
 
        case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
439
 
        case SLE_VAR_NULL: break;
440
 
        default: NOT_REACHED();
441
 
        }
442
 
}
443
 
 
444
 
/**
445
 
 * Handle all conversion and typechecking of variables here.
446
 
 * In the case of saving, read in the actual value from the struct
447
 
 * and then write them to file, endian safely. Loading a value
448
 
 * goes exactly the opposite way
449
 
 * @param ptr The object being filled/read
450
 
 * @param conv VarType type of the current element of the struct
451
 
 */
452
 
static void SlSaveLoadConv(void *ptr, VarType conv)
453
 
{
454
 
        int64 x = 0;
455
 
 
456
 
        if (_sl.save) { // SAVE values
457
 
                /* Read a value from the struct. These ARE endian safe. */
458
 
                x = ReadValue(ptr, conv);
459
 
 
460
 
                /* Write the value to the file and check if its value is in the desired range */
461
 
                switch (GetVarFileType(conv)) {
462
 
                case SLE_FILE_I8: assert(x >= -128 && x <= 127);     SlWriteByte(x);break;
463
 
                case SLE_FILE_U8: assert(x >= 0 && x <= 255);        SlWriteByte(x);break;
464
 
                case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
465
 
                case SLE_FILE_STRINGID:
466
 
                case SLE_FILE_U16:assert(x >= 0 && x <= 65535);      SlWriteUint16(x);break;
467
 
                case SLE_FILE_I32:
468
 
                case SLE_FILE_U32:                                   SlWriteUint32((uint32)x);break;
469
 
                case SLE_FILE_I64:
470
 
                case SLE_FILE_U64:                                   SlWriteUint64(x);break;
471
 
                default: NOT_REACHED();
472
 
                }
473
 
        } else { // LOAD values
474
 
 
475
 
                /* Read a value from the file */
476
 
                switch (GetVarFileType(conv)) {
477
 
                case SLE_FILE_I8:  x = (int8  )SlReadByte();   break;
478
 
                case SLE_FILE_U8:  x = (byte  )SlReadByte();   break;
479
 
                case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
480
 
                case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
481
 
                case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
482
 
                case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
483
 
                case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
484
 
                case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
485
 
                case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
486
 
                default: NOT_REACHED();
487
 
                }
488
 
 
489
 
                /* Write The value to the struct. These ARE endian safe. */
490
 
                WriteValue(ptr, conv, x);
491
 
        }
492
 
}
493
 
 
494
 
/** Calculate the net length of a string. This is in almost all cases
495
 
 * just strlen(), but if the string is not properly terminated, we'll
496
 
 * resort to the maximum length of the buffer.
497
 
 * @param ptr pointer to the stringbuffer
498
 
 * @param length maximum length of the string (buffer). If -1 we don't care
499
 
 * about a maximum length, but take string length as it is.
500
 
 * @return return the net length of the string */
501
 
static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
502
 
{
503
 
        if (ptr == NULL) return 0;
504
 
        return minu(strlen(ptr), length - 1);
505
 
}
506
 
 
507
 
/** Calculate the gross length of the string that it
508
 
 * will occupy in the savegame. This includes the real length, returned
509
 
 * by SlCalcNetStringLen and the length that the index will occupy.
510
 
 * @param ptr pointer to the stringbuffer
511
 
 * @param length maximum length of the string (buffer size, etc.)
512
 
 * @param conv type of data been used
513
 
 * @return return the gross length of the string */
514
 
static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
515
 
{
516
 
        size_t len;
517
 
        const char *str;
518
 
 
519
 
        switch (GetVarMemType(conv)) {
520
 
                default: NOT_REACHED();
521
 
                case SLE_VAR_STR:
522
 
                case SLE_VAR_STRQ:
523
 
                        str = *(const char**)ptr;
524
 
                        len = SIZE_MAX;
525
 
                        break;
526
 
                case SLE_VAR_STRB:
527
 
                case SLE_VAR_STRBQ:
528
 
                        str = (const char*)ptr;
529
 
                        len = length;
530
 
                        break;
531
 
        }
532
 
 
533
 
        len = SlCalcNetStringLen(str, len);
534
 
        return len + SlGetArrayLength(len); // also include the length of the index
535
 
}
536
 
 
537
 
/**
538
 
 * Save/Load a string.
539
 
 * @param ptr the string being manipulated
540
 
 * @param length of the string (full length)
541
 
 * @param conv must be SLE_FILE_STRING */
542
 
static void SlString(void *ptr, size_t length, VarType conv)
543
 
{
544
 
        size_t len;
545
 
 
546
 
        if (_sl.save) { // SAVE string
547
 
                switch (GetVarMemType(conv)) {
548
 
                        default: NOT_REACHED();
549
 
                        case SLE_VAR_STRB:
550
 
                        case SLE_VAR_STRBQ:
551
 
                                len = SlCalcNetStringLen((char*)ptr, length);
552
 
                                break;
553
 
                        case SLE_VAR_STR:
554
 
                        case SLE_VAR_STRQ:
555
 
                                ptr = *(char**)ptr;
556
 
                                len = SlCalcNetStringLen((char*)ptr, SIZE_MAX);
557
 
                                break;
558
 
                }
559
 
 
560
 
                SlWriteArrayLength(len);
561
 
                SlCopyBytes(ptr, len);
562
 
        } else { // LOAD string
563
 
                len = SlReadArrayLength();
564
 
 
565
 
                switch (GetVarMemType(conv)) {
566
 
                        default: NOT_REACHED();
567
 
                        case SLE_VAR_STRB:
568
 
                        case SLE_VAR_STRBQ:
569
 
                                if (len >= length) {
570
 
                                        DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
571
 
                                        SlCopyBytes(ptr, length);
572
 
                                        SlSkipBytes(len - length);
573
 
                                        len = length - 1;
574
 
                                } else {
575
 
                                        SlCopyBytes(ptr, len);
576
 
                                }
577
 
                                break;
578
 
                        case SLE_VAR_STR:
579
 
                        case SLE_VAR_STRQ: // Malloc'd string, free previous incarnation, and allocate
580
 
                                free(*(char**)ptr);
581
 
                                if (len == 0) {
582
 
                                        *(char**)ptr = NULL;
583
 
                                } else {
584
 
                                        *(char**)ptr = MallocT<char>(len + 1); // terminating '\0'
585
 
                                        ptr = *(char**)ptr;
586
 
                                        SlCopyBytes(ptr, len);
587
 
                                }
588
 
                                break;
589
 
                }
590
 
 
591
 
                ((char*)ptr)[len] = '\0'; // properly terminate the string
592
 
        }
593
 
}
594
 
 
595
 
/**
596
 
 * Return the size in bytes of a certain type of atomic array
597
 
 * @param length The length of the array counted in elements
598
 
 * @param conv VarType type of the variable that is used in calculating the size
599
 
 */
600
 
static inline size_t SlCalcArrayLen(uint length, VarType conv)
601
 
{
602
 
        return SlCalcConvFileLen(conv) * length;
603
 
}
604
 
 
605
 
/**
606
 
 * Save/Load an array.
607
 
 * @param array The array being manipulated
608
 
 * @param length The length of the array in elements
609
 
 * @param conv VarType type of the atomic array (int, byte, uint64, etc.)
610
 
 */
611
 
void SlArray(void *array, uint length, VarType conv)
612
 
{
613
 
        /* Automatically calculate the length? */
614
 
        if (_sl.need_length != NL_NONE) {
615
 
                SlSetLength(SlCalcArrayLen(length, conv));
616
 
                /* Determine length only? */
617
 
                if (_sl.need_length == NL_CALCLENGTH) return;
618
 
        }
619
 
 
620
 
        /* NOTICE - handle some buggy stuff, in really old versions everything was saved
621
 
         * as a byte-type. So detect this, and adjust array size accordingly */
622
 
        if (!_sl.save && _sl_version == 0) {
623
 
                /* all arrays except difficulty settings */
624
 
                if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
625
 
                                conv == SLE_INT32 || conv == SLE_UINT32) {
626
 
                        SlCopyBytes(array, length * SlCalcConvFileLen(conv));
627
 
                        return;
628
 
                }
629
 
                /* used for conversion of Money 32bit->64bit */
630
 
                if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
631
 
                        for (uint i = 0; i < length; i++) {
632
 
                                ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
633
 
                        }
634
 
                        return;
635
 
                }
636
 
        }
637
 
 
638
 
        /* If the size of elements is 1 byte both in file and memory, no special
639
 
         * conversion is needed, use specialized copy-copy function to speed up things */
640
 
        if (conv == SLE_INT8 || conv == SLE_UINT8) {
641
 
                SlCopyBytes(array, length);
642
 
        } else {
643
 
                byte *a = (byte*)array;
644
 
                byte mem_size = SlCalcConvMemLen(conv);
645
 
 
646
 
                for (; length != 0; length --) {
647
 
                        SlSaveLoadConv(a, conv);
648
 
                        a += mem_size; // get size
649
 
                }
650
 
        }
651
 
}
652
 
 
653
 
 
654
 
static uint ReferenceToInt(const void* obj, SLRefType rt);
655
 
static void* IntToReference(uint index, SLRefType rt);
656
 
 
657
 
 
658
 
/**
659
 
 * Return the size in bytes of a list
660
 
 * @param list The std::list to find the size of
661
 
 */
662
 
static inline size_t SlCalcListLen(const void *list)
663
 
{
664
 
        std::list<void *> *l = (std::list<void *> *) list;
665
 
 
666
 
        int type_size = CheckSavegameVersion(69) ? 2 : 4;
667
 
        /* Each entry is saved as type_size bytes, plus type_size bytes are used for the length
668
 
         * of the list */
669
 
        return l->size() * type_size + type_size;
670
 
}
671
 
 
672
 
 
673
 
/**
674
 
 * Save/Load a list.
675
 
 * @param list The list being manipulated
676
 
 * @param conv SLRefType type of the list (Vehicle *, Station *, etc)
677
 
 */
678
 
void SlList(void *list, SLRefType conv)
679
 
{
680
 
        /* Automatically calculate the length? */
681
 
        if (_sl.need_length != NL_NONE) {
682
 
                SlSetLength(SlCalcListLen(list));
683
 
                /* Determine length only? */
684
 
                if (_sl.need_length == NL_CALCLENGTH) return;
685
 
        }
686
 
 
687
 
        std::list<void *> *l = (std::list<void *> *) list;
688
 
 
689
 
        if (_sl.save) {
690
 
                SlWriteUint32(l->size());
691
 
 
692
 
                std::list<void *>::iterator iter;
693
 
                for (iter = l->begin(); iter != l->end(); ++iter) {
694
 
                        void *ptr = *iter;
695
 
                        SlWriteUint32(ReferenceToInt(ptr, conv));
696
 
                }
697
 
        } else {
698
 
                uint length = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
699
 
 
700
 
                /* Load each reference and push to the end of the list */
701
 
                for (uint i = 0; i < length; i++) {
702
 
                        void *ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), conv);
703
 
                        l->push_back(ptr);
704
 
                }
705
 
        }
706
 
}
707
 
 
708
 
 
709
 
/** Are we going to save this object or not? */
710
 
static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
711
 
{
712
 
        if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
713
 
        if (sld->conv & SLF_SAVE_NO) return false;
714
 
 
715
 
        return true;
716
 
}
717
 
 
718
 
/** Are we going to load this variable when loading a savegame or not?
719
 
 * @note If the variable is skipped it is skipped in the savegame
720
 
 * bytestream itself as well, so there is no need to skip it somewhere else */
721
 
static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
722
 
{
723
 
        if ((sld->conv & SLF_NETWORK_NO) && !_sl.save && _networking && !_network_server) {
724
 
                SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
725
 
                return true;
726
 
        }
727
 
 
728
 
        return false;
729
 
}
730
 
 
731
 
/**
732
 
 * Calculate the size of an object.
733
 
 * @param object to be measured
734
 
 * @param sld The SaveLoad description of the object so we know how to manipulate it
735
 
 * @return size of given objetc
736
 
 */
737
 
static size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
738
 
{
739
 
        size_t length = 0;
740
 
 
741
 
        /* Need to determine the length and write a length tag. */
742
 
        for (; sld->cmd != SL_END; sld++) {
743
 
                length += SlCalcObjMemberLength(object, sld);
744
 
        }
745
 
        return length;
746
 
}
747
 
 
748
 
size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
749
 
{
750
 
        assert(_sl.save);
751
 
 
752
 
        switch (sld->cmd) {
753
 
                case SL_VAR:
754
 
                case SL_REF:
755
 
                case SL_ARR:
756
 
                case SL_STR:
757
 
                case SL_LST:
758
 
                        /* CONDITIONAL saveload types depend on the savegame version */
759
 
                        if (!SlIsObjectValidInSavegame(sld)) break;
760
 
 
761
 
                        switch (sld->cmd) {
762
 
                        case SL_VAR: return SlCalcConvFileLen(sld->conv);
763
 
                        case SL_REF: return SlCalcRefLen();
764
 
                        case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
765
 
                        case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
766
 
                        case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
767
 
                        default: NOT_REACHED();
768
 
                        }
769
 
                        break;
770
 
                case SL_WRITEBYTE: return 1; // a byte is logically of size 1
771
 
                case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
772
 
                default: NOT_REACHED();
773
 
        }
774
 
        return 0;
775
 
}
776
 
 
777
 
 
778
 
bool SlObjectMember(void *ptr, const SaveLoad *sld)
779
 
{
780
 
        VarType conv = GB(sld->conv, 0, 8);
781
 
        switch (sld->cmd) {
782
 
        case SL_VAR:
783
 
        case SL_REF:
784
 
        case SL_ARR:
785
 
        case SL_STR:
786
 
        case SL_LST:
787
 
                /* CONDITIONAL saveload types depend on the savegame version */
788
 
                if (!SlIsObjectValidInSavegame(sld)) return false;
789
 
                if (SlSkipVariableOnLoad(sld)) return false;
790
 
 
791
 
                switch (sld->cmd) {
792
 
                case SL_VAR: SlSaveLoadConv(ptr, conv); break;
793
 
                case SL_REF: // Reference variable, translate
794
 
                        if (_sl.save) {
795
 
                                SlWriteUint32(ReferenceToInt(*(void**)ptr, (SLRefType)conv));
796
 
                        } else {
797
 
                                *(void**)ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), (SLRefType)conv);
798
 
                        }
799
 
                        break;
800
 
                case SL_ARR: SlArray(ptr, sld->length, conv); break;
801
 
                case SL_STR: SlString(ptr, sld->length, conv); break;
802
 
                case SL_LST: SlList(ptr, (SLRefType)conv); break;
803
 
                default: NOT_REACHED();
804
 
                }
805
 
                break;
806
 
 
807
 
        /* SL_WRITEBYTE translates a value of a variable to another one upon
808
 
         * saving or loading.
809
 
         * XXX - variable renaming abuse
810
 
         * game_value: the value of the variable ingame is abused by sld->version_from
811
 
         * file_value: the value of the variable in the savegame is abused by sld->version_to */
812
 
        case SL_WRITEBYTE:
813
 
                if (_sl.save) {
814
 
                        SlWriteByte(sld->version_to);
815
 
                } else {
816
 
                        *(byte*)ptr = sld->version_from;
817
 
                }
818
 
                break;
819
 
 
820
 
        /* SL_VEH_INCLUDE loads common code for vehicles */
821
 
        case SL_VEH_INCLUDE:
822
 
                SlObject(ptr, GetVehicleDescription(VEH_END));
823
 
                break;
824
 
        default: NOT_REACHED();
825
 
        }
826
 
        return true;
827
 
}
828
 
 
829
 
/**
830
 
 * Main SaveLoad function.
831
 
 * @param object The object that is being saved or loaded
832
 
 * @param sld The SaveLoad description of the object so we know how to manipulate it
833
 
 */
834
 
void SlObject(void *object, const SaveLoad *sld)
835
 
{
836
 
        /* Automatically calculate the length? */
837
 
        if (_sl.need_length != NL_NONE) {
838
 
                SlSetLength(SlCalcObjLength(object, sld));
839
 
                if (_sl.need_length == NL_CALCLENGTH) return;
840
 
        }
841
 
 
842
 
        for (; sld->cmd != SL_END; sld++) {
843
 
                void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
844
 
                SlObjectMember(ptr, sld);
845
 
        }
846
 
}
847
 
 
848
 
/**
849
 
 * Save or Load (a list of) global variables
850
 
 * @param sldg The global variable that is being loaded or saved
851
 
 */
852
 
void SlGlobList(const SaveLoadGlobVarList *sldg)
853
 
{
854
 
        SlObject(NULL, (const SaveLoad*)sldg);
855
 
}
856
 
 
857
 
/**
858
 
 * Do something of which I have no idea what it is :P
859
 
 * @param proc The callback procedure that is called
860
 
 * @param arg The variable that will be used for the callback procedure
861
 
 */
862
 
void SlAutolength(AutolengthProc *proc, void *arg)
863
 
{
864
 
        uint32 offs;
865
 
 
866
 
        assert(_sl.save);
867
 
 
868
 
        /* Tell it to calculate the length */
869
 
        _sl.need_length = NL_CALCLENGTH;
870
 
        _sl.obj_len = 0;
871
 
        proc(arg);
872
 
 
873
 
        /* Setup length */
874
 
        _sl.need_length = NL_WANTLENGTH;
875
 
        SlSetLength(_sl.obj_len);
876
 
 
877
 
        offs = SlGetOffs() + _sl.obj_len;
878
 
 
879
 
        /* And write the stuff */
880
 
        proc(arg);
881
 
 
882
 
        if (offs != SlGetOffs()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
883
 
}
884
 
 
885
 
/**
886
 
 * Load a chunk of data (eg vehicles, stations, etc.)
887
 
 * @param ch The chunkhandler that will be used for the operation
888
 
 */
889
 
static void SlLoadChunk(const ChunkHandler *ch)
890
 
{
891
 
        byte m = SlReadByte();
892
 
        size_t len;
893
 
        uint32 endoffs;
894
 
 
895
 
        _sl.block_mode = m;
896
 
        _sl.obj_len = 0;
897
 
 
898
 
        switch (m) {
899
 
        case CH_ARRAY:
900
 
                _sl.array_index = 0;
901
 
                ch->load_proc();
902
 
                break;
903
 
        case CH_SPARSE_ARRAY:
904
 
                ch->load_proc();
905
 
                break;
906
 
        default:
907
 
                if ((m & 0xF) == CH_RIFF) {
908
 
                        /* Read length */
909
 
                        len = (SlReadByte() << 16) | ((m >> 4) << 24);
910
 
                        len += SlReadUint16();
911
 
                        _sl.obj_len = len;
912
 
                        endoffs = SlGetOffs() + len;
913
 
                        ch->load_proc();
914
 
                        if (SlGetOffs() != endoffs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
915
 
                } else {
916
 
                        SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk type");
917
 
                }
918
 
                break;
919
 
        }
920
 
}
921
 
 
922
 
/* Stub Chunk handlers to only calculate length and do nothing else */
923
 
static ChunkSaveLoadProc *_tmp_proc_1;
924
 
static inline void SlStubSaveProc2(void *arg) {_tmp_proc_1();}
925
 
static void SlStubSaveProc() {SlAutolength(SlStubSaveProc2, NULL);}
926
 
 
927
 
/** Save a chunk of data (eg. vehicles, stations, etc.). Each chunk is
928
 
 * prefixed by an ID identifying it, followed by data, and terminator where appropiate
929
 
 * @param ch The chunkhandler that will be used for the operation
930
 
 */
931
 
static void SlSaveChunk(const ChunkHandler *ch)
932
 
{
933
 
        ChunkSaveLoadProc *proc = ch->save_proc;
934
 
 
935
 
        /* Don't save any chunk information if there is no save handler. */
936
 
        if (proc == NULL) return;
937
 
 
938
 
        SlWriteUint32(ch->id);
939
 
        DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
940
 
 
941
 
        if (ch->flags & CH_AUTO_LENGTH) {
942
 
                /* Need to calculate the length. Solve that by calling SlAutoLength in the save_proc. */
943
 
                _tmp_proc_1 = proc;
944
 
                proc = SlStubSaveProc;
945
 
        }
946
 
 
947
 
        _sl.block_mode = ch->flags & CH_TYPE_MASK;
948
 
        switch (ch->flags & CH_TYPE_MASK) {
949
 
        case CH_RIFF:
950
 
                _sl.need_length = NL_WANTLENGTH;
951
 
                proc();
952
 
                break;
953
 
        case CH_ARRAY:
954
 
                _sl.last_array_index = 0;
955
 
                SlWriteByte(CH_ARRAY);
956
 
                proc();
957
 
                SlWriteArrayLength(0); // Terminate arrays
958
 
                break;
959
 
        case CH_SPARSE_ARRAY:
960
 
                SlWriteByte(CH_SPARSE_ARRAY);
961
 
                proc();
962
 
                SlWriteArrayLength(0); // Terminate arrays
963
 
                break;
964
 
        default: NOT_REACHED();
965
 
        }
966
 
}
967
 
 
968
 
/** Save all chunks */
969
 
static void SlSaveChunks()
970
 
{
971
 
        const ChunkHandler *ch;
972
 
        const ChunkHandler* const *chsc;
973
 
        uint p;
974
 
 
975
 
        for (p = 0; p != CH_NUM_PRI_LEVELS; p++) {
976
 
                for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
977
 
                        while (true) {
978
 
                                if (((ch->flags >> CH_PRI_SHL) & (CH_NUM_PRI_LEVELS - 1)) == p)
979
 
                                        SlSaveChunk(ch);
980
 
                                if (ch->flags & CH_LAST)
981
 
                                        break;
982
 
                                ch++;
983
 
                        }
984
 
                }
985
 
        }
986
 
 
987
 
        /* Terminator */
988
 
        SlWriteUint32(0);
989
 
}
990
 
 
991
 
/** Find the ChunkHandler that will be used for processing the found
992
 
 * chunk in the savegame or in memory
993
 
 * @param id the chunk in question
994
 
 * @return returns the appropiate chunkhandler
995
 
 */
996
 
static const ChunkHandler *SlFindChunkHandler(uint32 id)
997
 
{
998
 
        const ChunkHandler *ch;
999
 
        const ChunkHandler *const *chsc;
1000
 
        for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
1001
 
                for (;;) {
1002
 
                        if (ch->id == id) return ch;
1003
 
                        if (ch->flags & CH_LAST) break;
1004
 
                        ch++;
1005
 
                }
1006
 
        }
1007
 
        return NULL;
1008
 
}
1009
 
 
1010
 
/** Load all chunks */
1011
 
static void SlLoadChunks()
1012
 
{
1013
 
        uint32 id;
1014
 
        const ChunkHandler *ch;
1015
 
 
1016
 
        for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
1017
 
                DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
1018
 
 
1019
 
                ch = SlFindChunkHandler(id);
1020
 
                if (ch == NULL) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unknown chunk type");
1021
 
                SlLoadChunk(ch);
1022
 
        }
1023
 
}
1024
 
 
1025
 
/*******************************************
1026
 
 ********** START OF LZO CODE **************
1027
 
 *******************************************/
1028
 
#define LZO_SIZE 8192
1029
 
 
1030
 
#include "minilzo.h"
1031
 
 
1032
 
static uint ReadLZO()
1033
 
{
1034
 
        byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
1035
 
        uint32 tmp[2];
1036
 
        uint32 size;
1037
 
        uint len;
1038
 
 
1039
 
        /* Read header*/
1040
 
        if (fread(tmp, sizeof(tmp), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
1041
 
 
1042
 
        /* Check if size is bad */
1043
 
        ((uint32*)out)[0] = size = tmp[1];
1044
 
 
1045
 
        if (_sl_version != 0) {
1046
 
                tmp[0] = TO_BE32(tmp[0]);
1047
 
                size = TO_BE32(size);
1048
 
        }
1049
 
 
1050
 
        if (size >= sizeof(out)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Inconsistent size");
1051
 
 
1052
 
        /* Read block */
1053
 
        if (fread(out + sizeof(uint32), size, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
1054
 
 
1055
 
        /* Verify checksum */
1056
 
        if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Bad checksum");
1057
 
 
1058
 
        /* Decompress */
1059
 
        lzo1x_decompress(out + sizeof(uint32)*1, size, _sl.buf, &len, NULL);
1060
 
        return len;
1061
 
}
1062
 
 
1063
 
/* p contains the pointer to the buffer, len contains the pointer to the length.
1064
 
 * len bytes will be written, p and l will be updated to reflect the next buffer. */
1065
 
static void WriteLZO(uint size)
1066
 
{
1067
 
        byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
1068
 
        byte wrkmem[sizeof(byte*)*4096];
1069
 
        uint outlen;
1070
 
 
1071
 
        lzo1x_1_compress(_sl.buf, size, out + sizeof(uint32)*2, &outlen, wrkmem);
1072
 
        ((uint32*)out)[1] = TO_BE32(outlen);
1073
 
        ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
1074
 
        if (fwrite(out, outlen + sizeof(uint32)*2, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
1075
 
}
1076
 
 
1077
 
static bool InitLZO()
1078
 
{
1079
 
        _sl.bufsize = LZO_SIZE;
1080
 
        _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
1081
 
        return true;
1082
 
}
1083
 
 
1084
 
static void UninitLZO()
1085
 
{
1086
 
        free(_sl.buf_ori);
1087
 
}
1088
 
 
1089
 
/*********************************************
1090
 
 ******** START OF NOCOMP CODE (uncompressed)*
1091
 
 *********************************************/
1092
 
static uint ReadNoComp()
1093
 
{
1094
 
        return fread(_sl.buf, 1, LZO_SIZE, _sl.fh);
1095
 
}
1096
 
 
1097
 
static void WriteNoComp(uint size)
1098
 
{
1099
 
        fwrite(_sl.buf, 1, size, _sl.fh);
1100
 
}
1101
 
 
1102
 
static bool InitNoComp()
1103
 
{
1104
 
        _sl.bufsize = LZO_SIZE;
1105
 
        _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
1106
 
        return true;
1107
 
}
1108
 
 
1109
 
static void UninitNoComp()
1110
 
{
1111
 
        free(_sl.buf_ori);
1112
 
}
1113
 
 
1114
 
/********************************************
1115
 
 ********** START OF MEMORY CODE (in ram)****
1116
 
 ********************************************/
1117
 
 
1118
 
#include "table/sprites.h"
1119
 
#include "gui.h"
1120
 
 
1121
 
struct ThreadedSave {
1122
 
        uint count;
1123
 
        byte ff_state;
1124
 
        bool saveinprogress;
1125
 
        CursorID cursor;
1126
 
};
1127
 
 
1128
 
/* A maximum size of of 128K * 500 = 64.000KB savegames */
1129
 
STATIC_OLD_POOL(Savegame, byte, 17, 500, NULL, NULL)
1130
 
static ThreadedSave _ts;
1131
 
 
1132
 
static bool InitMem()
1133
 
{
1134
 
        _ts.count = 0;
1135
 
 
1136
 
        _Savegame_pool.CleanPool();
1137
 
        _Savegame_pool.AddBlockToPool();
1138
 
 
1139
 
        /* A block from the pool is a contigious area of memory, so it is safe to write to it sequentially */
1140
 
        _sl.bufsize = GetSavegamePoolSize();
1141
 
        _sl.buf = GetSavegame(_ts.count);
1142
 
        return true;
1143
 
}
1144
 
 
1145
 
static void UnInitMem()
1146
 
{
1147
 
        _Savegame_pool.CleanPool();
1148
 
}
1149
 
 
1150
 
static void WriteMem(uint size)
1151
 
{
1152
 
        _ts.count += size;
1153
 
        /* Allocate new block and new buffer-pointer */
1154
 
        _Savegame_pool.AddBlockIfNeeded(_ts.count);
1155
 
        _sl.buf = GetSavegame(_ts.count);
1156
 
}
1157
 
 
1158
 
/********************************************
1159
 
 ********** START OF ZLIB CODE **************
1160
 
 ********************************************/
1161
 
 
1162
 
#if defined(WITH_ZLIB)
1163
 
#include <zlib.h>
1164
 
 
1165
 
static z_stream _z;
1166
 
 
1167
 
static bool InitReadZlib()
1168
 
{
1169
 
        memset(&_z, 0, sizeof(_z));
1170
 
        if (inflateInit(&_z) != Z_OK) return false;
1171
 
 
1172
 
        _sl.bufsize = 4096;
1173
 
        _sl.buf = _sl.buf_ori = MallocT<byte>(4096 + 4096); // also contains fread buffer
1174
 
        return true;
1175
 
}
1176
 
 
1177
 
static uint ReadZlib()
1178
 
{
1179
 
        int r;
1180
 
 
1181
 
        _z.next_out = _sl.buf;
1182
 
        _z.avail_out = 4096;
1183
 
 
1184
 
        do {
1185
 
                /* read more bytes from the file?*/
1186
 
                if (_z.avail_in == 0) {
1187
 
                        _z.avail_in = fread(_z.next_in = _sl.buf + 4096, 1, 4096, _sl.fh);
1188
 
                }
1189
 
 
1190
 
                /* inflate the data */
1191
 
                r = inflate(&_z, 0);
1192
 
                if (r == Z_STREAM_END)
1193
 
                        break;
1194
 
 
1195
 
                if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
1196
 
        } while (_z.avail_out);
1197
 
 
1198
 
        return 4096 - _z.avail_out;
1199
 
}
1200
 
 
1201
 
static void UninitReadZlib()
1202
 
{
1203
 
        inflateEnd(&_z);
1204
 
        free(_sl.buf_ori);
1205
 
}
1206
 
 
1207
 
static bool InitWriteZlib()
1208
 
{
1209
 
        memset(&_z, 0, sizeof(_z));
1210
 
        if (deflateInit(&_z, 6) != Z_OK) return false;
1211
 
 
1212
 
        _sl.bufsize = 4096;
1213
 
        _sl.buf = _sl.buf_ori = MallocT<byte>(4096); // also contains fread buffer
1214
 
        return true;
1215
 
}
1216
 
 
1217
 
static void WriteZlibLoop(z_streamp z, byte *p, uint len, int mode)
1218
 
{
1219
 
        byte buf[1024]; // output buffer
1220
 
        int r;
1221
 
        uint n;
1222
 
        z->next_in = p;
1223
 
        z->avail_in = len;
1224
 
        do {
1225
 
                z->next_out = buf;
1226
 
                z->avail_out = sizeof(buf);
1227
 
                r = deflate(z, mode);
1228
 
                        /* bytes were emitted? */
1229
 
                if ((n=sizeof(buf) - z->avail_out) != 0) {
1230
 
                        if (fwrite(buf, n, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
1231
 
                }
1232
 
                if (r == Z_STREAM_END)
1233
 
                        break;
1234
 
                if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
1235
 
        } while (z->avail_in || !z->avail_out);
1236
 
}
1237
 
 
1238
 
static void WriteZlib(uint len)
1239
 
{
1240
 
        WriteZlibLoop(&_z, _sl.buf, len, 0);
1241
 
}
1242
 
 
1243
 
static void UninitWriteZlib()
1244
 
{
1245
 
        /* flush any pending output. */
1246
 
        if (_sl.fh) WriteZlibLoop(&_z, NULL, 0, Z_FINISH);
1247
 
        deflateEnd(&_z);
1248
 
        free(_sl.buf_ori);
1249
 
}
1250
 
 
1251
 
#endif /* WITH_ZLIB */
1252
 
 
1253
 
/*******************************************
1254
 
 ************* END OF CODE *****************
1255
 
 *******************************************/
1256
 
 
1257
 
/* these define the chunks */
1258
 
extern const ChunkHandler _misc_chunk_handlers[];
1259
 
extern const ChunkHandler _setting_chunk_handlers[];
1260
 
extern const ChunkHandler _player_chunk_handlers[];
1261
 
extern const ChunkHandler _engine_chunk_handlers[];
1262
 
extern const ChunkHandler _veh_chunk_handlers[];
1263
 
extern const ChunkHandler _waypoint_chunk_handlers[];
1264
 
extern const ChunkHandler _depot_chunk_handlers[];
1265
 
extern const ChunkHandler _order_chunk_handlers[];
1266
 
extern const ChunkHandler _town_chunk_handlers[];
1267
 
extern const ChunkHandler _sign_chunk_handlers[];
1268
 
extern const ChunkHandler _station_chunk_handlers[];
1269
 
extern const ChunkHandler _industry_chunk_handlers[];
1270
 
extern const ChunkHandler _economy_chunk_handlers[];
1271
 
extern const ChunkHandler _animated_tile_chunk_handlers[];
1272
 
extern const ChunkHandler _newgrf_chunk_handlers[];
1273
 
extern const ChunkHandler _group_chunk_handlers[];
1274
 
extern const ChunkHandler _cargopacket_chunk_handlers[];
1275
 
 
1276
 
static const ChunkHandler * const _chunk_handlers[] = {
1277
 
        _misc_chunk_handlers,
1278
 
        _setting_chunk_handlers,
1279
 
        _veh_chunk_handlers,
1280
 
        _waypoint_chunk_handlers,
1281
 
        _depot_chunk_handlers,
1282
 
        _order_chunk_handlers,
1283
 
        _industry_chunk_handlers,
1284
 
        _economy_chunk_handlers,
1285
 
        _engine_chunk_handlers,
1286
 
        _town_chunk_handlers,
1287
 
        _sign_chunk_handlers,
1288
 
        _station_chunk_handlers,
1289
 
        _player_chunk_handlers,
1290
 
        _animated_tile_chunk_handlers,
1291
 
        _newgrf_chunk_handlers,
1292
 
        _group_chunk_handlers,
1293
 
        _cargopacket_chunk_handlers,
1294
 
        NULL,
1295
 
};
1296
 
 
1297
 
/**
1298
 
 * Pointers cannot be saved to a savegame, so this functions gets
1299
 
 * the index of the item, and if not available, it hussles with
1300
 
 * pointers (looks really bad :()
1301
 
 * Remember that a NULL item has value 0, and all
1302
 
 * indeces have +1, so vehicle 0 is saved as index 1.
1303
 
 * @param obj The object that we want to get the index of
1304
 
 * @param rt SLRefType type of the object the index is being sought of
1305
 
 * @return Return the pointer converted to an index of the type pointed to
1306
 
 */
1307
 
static uint ReferenceToInt(const void *obj, SLRefType rt)
1308
 
{
1309
 
        if (obj == NULL) return 0;
1310
 
 
1311
 
        switch (rt) {
1312
 
                case REF_VEHICLE_OLD: // Old vehicles we save as new onces
1313
 
                case REF_VEHICLE:   return ((const  Vehicle*)obj)->index + 1;
1314
 
                case REF_STATION:   return ((const  Station*)obj)->index + 1;
1315
 
                case REF_TOWN:      return ((const     Town*)obj)->index + 1;
1316
 
                case REF_ORDER:     return ((const    Order*)obj)->index + 1;
1317
 
                case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
1318
 
                case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
1319
 
                case REF_CARGO_PACKET:  return ((const CargoPacket*)obj)->index + 1;
1320
 
                default: NOT_REACHED();
1321
 
        }
1322
 
 
1323
 
        return 0; // avoid compiler warning
1324
 
}
1325
 
 
1326
 
/**
1327
 
 * Pointers cannot be loaded from a savegame, so this function
1328
 
 * gets the index from the savegame and returns the appropiate
1329
 
 * pointer from the already loaded base.
1330
 
 * Remember that an index of 0 is a NULL pointer so all indeces
1331
 
 * are +1 so vehicle 0 is saved as 1.
1332
 
 * @param index The index that is being converted to a pointer
1333
 
 * @param rt SLRefType type of the object the pointer is sought of
1334
 
 * @return Return the index converted to a pointer of any type
1335
 
 */
1336
 
static void *IntToReference(uint index, SLRefType rt)
1337
 
{
1338
 
        /* After version 4.3 REF_VEHICLE_OLD is saved as REF_VEHICLE,
1339
 
         * and should be loaded like that */
1340
 
        if (rt == REF_VEHICLE_OLD && !CheckSavegameVersionOldStyle(4, 4)) {
1341
 
                rt = REF_VEHICLE;
1342
 
        }
1343
 
 
1344
 
        /* No need to look up NULL pointers, just return immediately */
1345
 
        if (rt != REF_VEHICLE_OLD && index == 0) {
1346
 
                return NULL;
1347
 
        }
1348
 
 
1349
 
        index--; // correct for the NULL index
1350
 
 
1351
 
        switch (rt) {
1352
 
                case REF_ORDER:
1353
 
                        if (_Order_pool.AddBlockIfNeeded(index)) return GetOrder(index);
1354
 
                        error("Orders: failed loading savegame: too many orders");
1355
 
 
1356
 
                case REF_VEHICLE:
1357
 
                        if (_Vehicle_pool.AddBlockIfNeeded(index)) return GetVehicle(index);
1358
 
                        error("Vehicles: failed loading savegame: too many vehicles");
1359
 
 
1360
 
                case REF_STATION:
1361
 
                        if (_Station_pool.AddBlockIfNeeded(index)) return GetStation(index);
1362
 
                        error("Stations: failed loading savegame: too many stations");
1363
 
 
1364
 
                case REF_TOWN:
1365
 
                        if (_Town_pool.AddBlockIfNeeded(index)) return GetTown(index);
1366
 
                        error("Towns: failed loading savegame: too many towns");
1367
 
 
1368
 
                case REF_ROADSTOPS:
1369
 
                        if (_RoadStop_pool.AddBlockIfNeeded(index)) return GetRoadStop(index);
1370
 
                        error("RoadStops: failed loading savegame: too many RoadStops");
1371
 
 
1372
 
                case REF_ENGINE_RENEWS:
1373
 
                        if (_EngineRenew_pool.AddBlockIfNeeded(index)) return GetEngineRenew(index);
1374
 
                        error("EngineRenews: failed loading savegame: too many EngineRenews");
1375
 
 
1376
 
                case REF_CARGO_PACKET:
1377
 
                        if (_CargoPacket_pool.AddBlockIfNeeded(index)) return GetCargoPacket(index);
1378
 
                        error("CargoPackets: failed loading savegame: too many Cargo packets");
1379
 
 
1380
 
                case REF_VEHICLE_OLD:
1381
 
                        /* Old vehicles were saved differently:
1382
 
                         * invalid vehicle was 0xFFFF,
1383
 
                         * and the index was not - 1.. correct for this */
1384
 
                        index++;
1385
 
                        if (index == INVALID_VEHICLE) return NULL;
1386
 
 
1387
 
                        if (_Vehicle_pool.AddBlockIfNeeded(index)) return GetVehicle(index);
1388
 
                        error("Vehicles: failed loading savegame: too many vehicles");
1389
 
 
1390
 
                default: NOT_REACHED();
1391
 
        }
1392
 
 
1393
 
        return NULL;
1394
 
}
1395
 
 
1396
 
/** The format for a reader/writer type of a savegame */
1397
 
struct SaveLoadFormat {
1398
 
        const char *name;           ///< name of the compressor/decompressor (debug-only)
1399
 
        uint32 tag;                 ///< the 4-letter tag by which it is identified in the savegame
1400
 
 
1401
 
        bool (*init_read)();        ///< function executed upon initalization of the loader
1402
 
        ReaderProc *reader;         ///< function that loads the data from the file
1403
 
        void (*uninit_read)();      ///< function executed when reading is finished
1404
 
 
1405
 
        bool (*init_write)();       ///< function executed upon intialization of the saver
1406
 
        WriterProc *writer;         ///< function that saves the data to the file
1407
 
        void (*uninit_write)();     ///< function executed when writing is done
1408
 
};
1409
 
 
1410
 
static const SaveLoadFormat _saveload_formats[] = {
1411
 
        {"memory", 0,                NULL,         NULL,       NULL,           InitMem,       WriteMem,    UnInitMem},
1412
 
        {"lzo",    TO_BE32X('OTTD'), InitLZO,      ReadLZO,    UninitLZO,      InitLZO,       WriteLZO,    UninitLZO},
1413
 
        {"none",   TO_BE32X('OTTN'), InitNoComp,   ReadNoComp, UninitNoComp,   InitNoComp,    WriteNoComp, UninitNoComp},
1414
 
#if defined(WITH_ZLIB)
1415
 
        {"zlib",   TO_BE32X('OTTZ'), InitReadZlib, ReadZlib,   UninitReadZlib, InitWriteZlib, WriteZlib,   UninitWriteZlib},
1416
 
#else
1417
 
        {"zlib",   TO_BE32X('OTTZ'), NULL,         NULL,       NULL,           NULL,          NULL,        NULL},
1418
 
#endif
1419
 
};
1420
 
 
1421
 
/**
1422
 
 * Return the savegameformat of the game. Whether it was create with ZLIB compression
1423
 
 * uncompressed, or another type
1424
 
 * @param s Name of the savegame format. If NULL it picks the first available one
1425
 
 * @return Pointer to SaveLoadFormat struct giving all characteristics of this type of savegame
1426
 
 */
1427
 
static const SaveLoadFormat *GetSavegameFormat(const char *s)
1428
 
{
1429
 
        const SaveLoadFormat *def = endof(_saveload_formats) - 1;
1430
 
 
1431
 
        /* find default savegame format, the highest one with which files can be written */
1432
 
        while (!def->init_write) def--;
1433
 
 
1434
 
        if (s != NULL && s[0] != '\0') {
1435
 
                const SaveLoadFormat *slf;
1436
 
                for (slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
1437
 
                        if (slf->init_write != NULL && strcmp(s, slf->name) == 0)
1438
 
                                return slf;
1439
 
                }
1440
 
 
1441
 
                ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
1442
 
        }
1443
 
        return def;
1444
 
}
1445
 
 
1446
 
/* actual loader/saver function */
1447
 
void InitializeGame(int mode, uint size_x, uint size_y);
1448
 
extern bool AfterLoadGame();
1449
 
extern void BeforeSaveGame();
1450
 
extern bool LoadOldSaveGame(const char *file);
1451
 
 
1452
 
/** Small helper function to close the to be loaded savegame an signal error */
1453
 
static inline SaveOrLoadResult AbortSaveLoad()
1454
 
{
1455
 
        if (_sl.fh != NULL) fclose(_sl.fh);
1456
 
 
1457
 
        _sl.fh = NULL;
1458
 
        return SL_ERROR;
1459
 
}
1460
 
 
1461
 
/** Update the gui accordingly when starting saving
1462
 
 * and set locks on saveload. Also turn off fast-forward cause with that
1463
 
 * saving takes Aaaaages */
1464
 
void SaveFileStart()
1465
 
{
1466
 
        _ts.ff_state = _fast_forward;
1467
 
        _fast_forward = 0;
1468
 
        if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
1469
 
 
1470
 
        SendWindowMessage(WC_STATUS_BAR, 0, true, 0, 0);
1471
 
        _ts.saveinprogress = true;
1472
 
}
1473
 
 
1474
 
/** Update the gui accordingly when saving is done and release locks
1475
 
 * on saveload */
1476
 
void SaveFileDone()
1477
 
{
1478
 
        _fast_forward = _ts.ff_state;
1479
 
        if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
1480
 
 
1481
 
        SendWindowMessage(WC_STATUS_BAR, 0, false, 0, 0);
1482
 
        _ts.saveinprogress = false;
1483
 
}
1484
 
 
1485
 
/** Set the error message from outside of the actual loading/saving of the game (AfterLoadGame and friends) */
1486
 
void SetSaveLoadError(StringID str)
1487
 
{
1488
 
        _sl.error_str = str;
1489
 
}
1490
 
 
1491
 
/** Get the string representation of the error message */
1492
 
const char *GetSaveLoadErrorString()
1493
 
{
1494
 
        SetDParam(0, _sl.error_str);
1495
 
        SetDParamStr(1, _sl.extra_msg);
1496
 
 
1497
 
        static char err_str[512];
1498
 
        GetString(err_str, _sl.save ? STR_4007_GAME_SAVE_FAILED : STR_4009_GAME_LOAD_FAILED, lastof(err_str));
1499
 
        return err_str;
1500
 
}
1501
 
 
1502
 
/** Show a gui message when saving has failed */
1503
 
void SaveFileError()
1504
 
{
1505
 
        SetDParamStr(0, GetSaveLoadErrorString());
1506
 
        ShowErrorMessage(STR_012D, STR_NULL, 0, 0);
1507
 
        SaveFileDone();
1508
 
}
1509
 
 
1510
 
static OTTDThread* save_thread;
1511
 
 
1512
 
/** We have written the whole game into memory, _Savegame_pool, now find
1513
 
 * and appropiate compressor and start writing to file.
1514
 
 */
1515
 
static SaveOrLoadResult SaveFileToDisk(bool threaded)
1516
 
{
1517
 
        const SaveLoadFormat *fmt;
1518
 
        uint32 hdr[2];
1519
 
 
1520
 
        _sl.excpt_uninit = NULL;
1521
 
        try {
1522
 
                fmt = GetSavegameFormat(_savegame_format);
1523
 
 
1524
 
                /* We have written our stuff to memory, now write it to file! */
1525
 
                hdr[0] = fmt->tag;
1526
 
                hdr[1] = TO_BE32(SAVEGAME_VERSION << 16);
1527
 
                if (fwrite(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
1528
 
 
1529
 
                if (!fmt->init_write()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
1530
 
 
1531
 
                {
1532
 
                        uint i;
1533
 
                        uint count = 1 << Savegame_POOL_BLOCK_SIZE_BITS;
1534
 
 
1535
 
                        if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
1536
 
                        for (i = 0; i != _Savegame_pool.GetBlockCount() - 1; i++) {
1537
 
                                _sl.buf = _Savegame_pool.blocks[i];
1538
 
                                fmt->writer(count);
1539
 
                        }
1540
 
 
1541
 
                        /* The last block is (almost) always not fully filled, so only write away
1542
 
                         * as much data as it is in there */
1543
 
                        _sl.buf = _Savegame_pool.blocks[i];
1544
 
                        fmt->writer(_ts.count - (i * count));
1545
 
                }
1546
 
 
1547
 
                fmt->uninit_write();
1548
 
                if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
1549
 
                GetSavegameFormat("memory")->uninit_write(); // clean the memorypool
1550
 
                fclose(_sl.fh);
1551
 
 
1552
 
                if (threaded) OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_DONE);
1553
 
 
1554
 
                return SL_OK;
1555
 
        }
1556
 
        catch (...) {
1557
 
                AbortSaveLoad();
1558
 
                if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
1559
 
 
1560
 
                ShowInfo(GetSaveLoadErrorString());
1561
 
                fprintf(stderr, GetSaveLoadErrorString());
1562
 
 
1563
 
                if (threaded) {
1564
 
                        OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_ERROR);
1565
 
                } else {
1566
 
                        SaveFileError();
1567
 
                }
1568
 
                return SL_ERROR;
1569
 
        }
1570
 
}
1571
 
 
1572
 
static void* SaveFileToDiskThread(void *arg)
1573
 
{
1574
 
        SaveFileToDisk(true);
1575
 
        return NULL;
1576
 
}
1577
 
 
1578
 
void WaitTillSaved()
1579
 
{
1580
 
        OTTDJoinThread(save_thread);
1581
 
        save_thread = NULL;
1582
 
}
1583
 
 
1584
 
/**
1585
 
 * Main Save or Load function where the high-level saveload functions are
1586
 
 * handled. It opens the savegame, selects format and checks versions
1587
 
 * @param filename The name of the savegame being created/loaded
1588
 
 * @param mode Save or load. Load can also be a TTD(Patch) game. Use SL_LOAD, SL_OLD_LOAD or SL_SAVE
1589
 
 * @return Return the results of the action. SL_OK, SL_ERROR or SL_REINIT ("unload" the game)
1590
 
 */
1591
 
SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb)
1592
 
{
1593
 
        uint32 hdr[2];
1594
 
        const SaveLoadFormat *fmt;
1595
 
 
1596
 
        /* An instance of saving is already active, so don't go saving again */
1597
 
        if (_ts.saveinprogress && mode == SL_SAVE) {
1598
 
                /* if not an autosave, but a user action, show error message */
1599
 
                if (!_do_autosave) ShowErrorMessage(INVALID_STRING_ID, STR_SAVE_STILL_IN_PROGRESS, 0, 0);
1600
 
                return SL_OK;
1601
 
        }
1602
 
        WaitTillSaved();
1603
 
 
1604
 
        _next_offs = 0;
1605
 
 
1606
 
        /* Load a TTDLX or TTDPatch game */
1607
 
        if (mode == SL_OLD_LOAD) {
1608
 
                InitializeGame(IG_DATE_RESET, 256, 256); // set a mapsize of 256x256 for TTDPatch games or it might get confused
1609
 
                if (!LoadOldSaveGame(filename)) return SL_REINIT;
1610
 
                _sl_version = 0;
1611
 
                if (!AfterLoadGame()) return SL_REINIT;
1612
 
                return SL_OK;
1613
 
        }
1614
 
 
1615
 
        _sl.excpt_uninit = NULL;
1616
 
        try {
1617
 
                _sl.fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
1618
 
 
1619
 
                /* Make it a little easier to load savegames from the console */
1620
 
                if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", SAVE_DIR);
1621
 
                if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", BASE_DIR);
1622
 
 
1623
 
                if (_sl.fh == NULL) {
1624
 
                        SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
1625
 
                }
1626
 
 
1627
 
                _sl.bufe = _sl.bufp = NULL;
1628
 
                _sl.offs_base = 0;
1629
 
                _sl.save = (mode != 0);
1630
 
                _sl.chs = _chunk_handlers;
1631
 
 
1632
 
                /* General tactic is to first save the game to memory, then use an available writer
1633
 
                 * to write it to file, either in threaded mode if possible, or single-threaded */
1634
 
                if (mode == SL_SAVE) { /* SAVE game */
1635
 
                        fmt = GetSavegameFormat("memory"); // write to memory
1636
 
 
1637
 
                        _sl.write_bytes = fmt->writer;
1638
 
                        _sl.excpt_uninit = fmt->uninit_write;
1639
 
                        if (!fmt->init_write()) {
1640
 
                                DEBUG(sl, 0, "Initializing writer '%s' failed.", fmt->name);
1641
 
                                return AbortSaveLoad();
1642
 
                        }
1643
 
 
1644
 
                        _sl_version = SAVEGAME_VERSION;
1645
 
 
1646
 
                        BeforeSaveGame();
1647
 
                        SlSaveChunks();
1648
 
                        SlWriteFill(); // flush the save buffer
1649
 
 
1650
 
                        SaveFileStart();
1651
 
                        if (_network_server ||
1652
 
                                                (save_thread = OTTDCreateThread(&SaveFileToDiskThread, NULL)) == NULL) {
1653
 
                                if (!_network_server) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
1654
 
 
1655
 
                                SaveOrLoadResult result = SaveFileToDisk(false);
1656
 
                                SaveFileDone();
1657
 
 
1658
 
                                return result;
1659
 
                        }
1660
 
                } else { /* LOAD game */
1661
 
                        assert(mode == SL_LOAD);
1662
 
                        DebugDumpCommands("ddc:load:%s\n", filename);
1663
 
 
1664
 
                        if (fread(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
1665
 
 
1666
 
                        /* see if we have any loader for this type. */
1667
 
                        for (fmt = _saveload_formats; ; fmt++) {
1668
 
                                /* No loader found, treat as version 0 and use LZO format */
1669
 
                                if (fmt == endof(_saveload_formats)) {
1670
 
                                        DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
1671
 
        #if defined(WINCE)
1672
 
                                        /* Of course some system had not to support rewind ;) */
1673
 
                                        fseek(_sl.fh, 0L, SEEK_SET);
1674
 
                                        clearerr(_sl.fh);
1675
 
        #else
1676
 
                                        rewind(_sl.fh);
1677
 
        #endif
1678
 
                                        _sl_version = 0;
1679
 
                                        _sl_minor_version = 0;
1680
 
                                        fmt = _saveload_formats + 1; // LZO
1681
 
                                        break;
1682
 
                                }
1683
 
 
1684
 
                                if (fmt->tag == hdr[0]) {
1685
 
                                        /* check version number */
1686
 
                                        _sl_version = TO_BE32(hdr[1]) >> 16;
1687
 
                                        /* Minor is not used anymore from version 18.0, but it is still needed
1688
 
                                         * in versions before that (4 cases) which can't be removed easy.
1689
 
                                         * Therefor it is loaded, but never saved (or, it saves a 0 in any scenario).
1690
 
                                         * So never EVER use this minor version again. -- TrueLight -- 22-11-2005 */
1691
 
                                        _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
1692
 
 
1693
 
                                        DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
1694
 
 
1695
 
                                        /* Is the version higher than the current? */
1696
 
                                        if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
1697
 
                                        break;
1698
 
                                }
1699
 
                        }
1700
 
 
1701
 
                        _sl.read_bytes = fmt->reader;
1702
 
                        _sl.excpt_uninit = fmt->uninit_read;
1703
 
 
1704
 
                        /* loader for this savegame type is not implemented? */
1705
 
                        if (fmt->init_read == NULL) {
1706
 
                                char err_str[64];
1707
 
                                snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
1708
 
                                SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
1709
 
                        }
1710
 
 
1711
 
                        if (!fmt->init_read()) {
1712
 
                                char err_str[64];
1713
 
                                snprintf(err_str, lengthof(err_str), "Initializing loader '%s' failed", fmt->name);
1714
 
                                SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
1715
 
                        }
1716
 
 
1717
 
                        /* Old maps were hardcoded to 256x256 and thus did not contain
1718
 
                         * any mapsize information. Pre-initialize to 256x256 to not to
1719
 
                         * confuse old games */
1720
 
                        InitializeGame(IG_DATE_RESET, 256, 256);
1721
 
 
1722
 
                        SlLoadChunks();
1723
 
                        fmt->uninit_read();
1724
 
                        fclose(_sl.fh);
1725
 
 
1726
 
                        /* After loading fix up savegame for any internal changes that
1727
 
                         * might've occured since then. If it fails, load back the old game */
1728
 
                        if (!AfterLoadGame()) return SL_REINIT;
1729
 
                }
1730
 
 
1731
 
                return SL_OK;
1732
 
        }
1733
 
        catch (...) {
1734
 
                AbortSaveLoad();
1735
 
 
1736
 
                /* deinitialize compressor. */
1737
 
                if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
1738
 
 
1739
 
                /* Skip the "color" character */
1740
 
                ShowInfoF(GetSaveLoadErrorString() + 3);
1741
 
 
1742
 
                /* A saver/loader exception!! reinitialize all variables to prevent crash! */
1743
 
                return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
1744
 
        }
1745
 
}
1746
 
 
1747
 
/** Do a save when exiting the game (patch option) _patches.autosave_on_exit */
1748
 
void DoExitSave()
1749
 
{
1750
 
        SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
1751
 
}
1752
 
 
1753
 
#if 0
1754
 
/**
1755
 
 * Function to get the type of the savegame by looking at the file header.
1756
 
 * NOTICE: Not used right now, but could be used if extensions of savegames are garbled
1757
 
 * @param file Savegame to be checked
1758
 
 * @return SL_OLD_LOAD or SL_LOAD of the file
1759
 
 */
1760
 
int GetSavegameType(char *file)
1761
 
{
1762
 
        const SaveLoadFormat *fmt;
1763
 
        uint32 hdr;
1764
 
        FILE *f;
1765
 
        int mode = SL_OLD_LOAD;
1766
 
 
1767
 
        f = fopen(file, "rb");
1768
 
        if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
1769
 
                DEBUG(sl, 0, "Savegame is obsolete or invalid format");
1770
 
                mode = SL_LOAD; // don't try to get filename, just show name as it is written
1771
 
        } else {
1772
 
                /* see if we have any loader for this type. */
1773
 
                for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
1774
 
                        if (fmt->tag == hdr) {
1775
 
                                mode = SL_LOAD; // new type of savegame
1776
 
                                break;
1777
 
                        }
1778
 
                }
1779
 
        }
1780
 
 
1781
 
        fclose(f);
1782
 
        return mode;
1783
 
}
1784
 
#endif