00001
00002
00003
00004
00005
00006
00007
00008
00009
00024 #include "../stdafx.h"
00025 #include "../debug.h"
00026 #include "../station_base.h"
00027 #include "../thread/thread.h"
00028 #include "../town.h"
00029 #include "../network/network.h"
00030 #include "../window_func.h"
00031 #include "../strings_func.h"
00032 #include "../core/endian_func.hpp"
00033 #include "../vehicle_base.h"
00034 #include "../company_func.h"
00035 #include "../date_func.h"
00036 #include "../autoreplace_base.h"
00037 #include "../roadstop_base.h"
00038 #include "../statusbar_gui.h"
00039 #include "../fileio_func.h"
00040 #include "../gamelog.h"
00041 #include "../string_func.h"
00042 #include "../fios.h"
00043 #include "../error.h"
00044
00045 #include "table/strings.h"
00046
00047 #include "saveload_internal.h"
00048 #include "saveload_filter.h"
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242 extern const uint16 SAVEGAME_VERSION = SL_EXT_RATING;
00243
00244 SavegameType _savegame_type;
00245
00246 uint32 _ttdp_version;
00247 uint16 _sl_version;
00248 byte _sl_minor_version;
00249 char _savegame_format[8];
00250 bool _do_autosave;
00251
00253 enum SaveLoadAction {
00254 SLA_LOAD,
00255 SLA_SAVE,
00256 SLA_PTRS,
00257 SLA_NULL,
00258 SLA_LOAD_CHECK,
00259 };
00260
00261 enum NeedLength {
00262 NL_NONE = 0,
00263 NL_WANTLENGTH = 1,
00264 NL_CALCLENGTH = 2,
00265 };
00266
00268 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
00269
00271 struct ReadBuffer {
00272 byte buf[MEMORY_CHUNK_SIZE];
00273 byte *bufp;
00274 byte *bufe;
00275 LoadFilter *reader;
00276 size_t read;
00277
00282 ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
00283 {
00284 }
00285
00286 inline byte ReadByte()
00287 {
00288 if (this->bufp == this->bufe) {
00289 size_t len = this->reader->Read(this->buf, lengthof(this->buf));
00290 if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00291
00292 this->read += len;
00293 this->bufp = this->buf;
00294 this->bufe = this->buf + len;
00295 }
00296
00297 return *this->bufp++;
00298 }
00299
00304 size_t GetSize() const
00305 {
00306 return this->read - (this->bufe - this->bufp);
00307 }
00308 };
00309
00310
00312 struct MemoryDumper {
00313 AutoFreeSmallVector<byte *, 16> blocks;
00314 byte *buf;
00315 byte *bufe;
00316
00318 MemoryDumper() : buf(NULL), bufe(NULL)
00319 {
00320 }
00321
00326 inline void WriteByte(byte b)
00327 {
00328
00329 if (this->buf == this->bufe) {
00330 this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
00331 *this->blocks.Append() = this->buf;
00332 this->bufe = this->buf + MEMORY_CHUNK_SIZE;
00333 }
00334
00335 *this->buf++ = b;
00336 }
00337
00342 void Flush(SaveFilter *writer)
00343 {
00344 uint i = 0;
00345 size_t t = this->GetSize();
00346
00347 while (t > 0) {
00348 size_t to_write = min(MEMORY_CHUNK_SIZE, t);
00349
00350 writer->Write(this->blocks[i++], to_write);
00351 t -= to_write;
00352 }
00353
00354 writer->Finish();
00355 }
00356
00361 size_t GetSize() const
00362 {
00363 return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
00364 }
00365 };
00366
00368 struct SaveLoadParams {
00369 SaveLoadAction action;
00370 NeedLength need_length;
00371 byte block_mode;
00372 bool error;
00373
00374 size_t obj_len;
00375 int array_index, last_array_index;
00376
00377 MemoryDumper *dumper;
00378 SaveFilter *sf;
00379
00380 ReadBuffer *reader;
00381 LoadFilter *lf;
00382
00383 StringID error_str;
00384 char *extra_msg;
00385
00386 byte ff_state;
00387 bool saveinprogress;
00388 };
00389
00390 static SaveLoadParams _sl;
00391
00392
00393 extern const ChunkHandler _gamelog_chunk_handlers[];
00394 extern const ChunkHandler _map_chunk_handlers[];
00395 extern const ChunkHandler _misc_chunk_handlers[];
00396 extern const ChunkHandler _name_chunk_handlers[];
00397 extern const ChunkHandler _cheat_chunk_handlers[] ;
00398 extern const ChunkHandler _setting_chunk_handlers[];
00399 extern const ChunkHandler _company_chunk_handlers[];
00400 extern const ChunkHandler _engine_chunk_handlers[];
00401 extern const ChunkHandler _veh_chunk_handlers[];
00402 extern const ChunkHandler _waypoint_chunk_handlers[];
00403 extern const ChunkHandler _depot_chunk_handlers[];
00404 extern const ChunkHandler _order_chunk_handlers[];
00405 extern const ChunkHandler _town_chunk_handlers[];
00406 extern const ChunkHandler _sign_chunk_handlers[];
00407 extern const ChunkHandler _station_chunk_handlers[];
00408 extern const ChunkHandler _industry_chunk_handlers[];
00409 extern const ChunkHandler _economy_chunk_handlers[];
00410 extern const ChunkHandler _subsidy_chunk_handlers[];
00411 extern const ChunkHandler _goal_chunk_handlers[];
00412 extern const ChunkHandler _ai_chunk_handlers[];
00413 extern const ChunkHandler _game_chunk_handlers[];
00414 extern const ChunkHandler _animated_tile_chunk_handlers[];
00415 extern const ChunkHandler _newgrf_chunk_handlers[];
00416 extern const ChunkHandler _group_chunk_handlers[];
00417 extern const ChunkHandler _cargopacket_chunk_handlers[];
00418 extern const ChunkHandler _autoreplace_chunk_handlers[];
00419 extern const ChunkHandler _labelmaps_chunk_handlers[];
00420 extern const ChunkHandler _linkgraph_chunk_handlers[];
00421 extern const ChunkHandler _airport_chunk_handlers[];
00422 extern const ChunkHandler _object_chunk_handlers[];
00423 extern const ChunkHandler _persistent_storage_chunk_handlers[];
00424
00426 static const ChunkHandler * const _chunk_handlers[] = {
00427 _gamelog_chunk_handlers,
00428 _map_chunk_handlers,
00429 _misc_chunk_handlers,
00430 _name_chunk_handlers,
00431 _cheat_chunk_handlers,
00432 _setting_chunk_handlers,
00433 _veh_chunk_handlers,
00434 _waypoint_chunk_handlers,
00435 _depot_chunk_handlers,
00436 _order_chunk_handlers,
00437 _industry_chunk_handlers,
00438 _economy_chunk_handlers,
00439 _subsidy_chunk_handlers,
00440 _goal_chunk_handlers,
00441 _engine_chunk_handlers,
00442 _town_chunk_handlers,
00443 _sign_chunk_handlers,
00444 _station_chunk_handlers,
00445 _company_chunk_handlers,
00446 _ai_chunk_handlers,
00447 _game_chunk_handlers,
00448 _animated_tile_chunk_handlers,
00449 _newgrf_chunk_handlers,
00450 _group_chunk_handlers,
00451 _cargopacket_chunk_handlers,
00452 _autoreplace_chunk_handlers,
00453 _labelmaps_chunk_handlers,
00454 _linkgraph_chunk_handlers,
00455 _airport_chunk_handlers,
00456 _object_chunk_handlers,
00457 _persistent_storage_chunk_handlers,
00458 NULL,
00459 };
00460
00465 #define FOR_ALL_CHUNK_HANDLERS(ch) \
00466 for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \
00467 for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1)
00468
00470 static void SlNullPointers()
00471 {
00472 _sl.action = SLA_NULL;
00473
00474
00475
00476
00477 _sl_version = SAVEGAME_VERSION;
00478
00479 DEBUG(sl, 1, "Nulling pointers");
00480
00481 FOR_ALL_CHUNK_HANDLERS(ch) {
00482 if (ch->ptrs_proc != NULL) {
00483 DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00484 ch->ptrs_proc();
00485 }
00486 }
00487
00488 DEBUG(sl, 1, "All pointers nulled");
00489
00490 assert(_sl.action == SLA_NULL);
00491 }
00492
00501 void NORETURN SlError(StringID string, const char *extra_msg)
00502 {
00503
00504 if (_sl.action == SLA_LOAD_CHECK) {
00505 _load_check_data.error = string;
00506 free(_load_check_data.error_data);
00507 _load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00508 } else {
00509 _sl.error_str = string;
00510 free(_sl.extra_msg);
00511 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00512 }
00513
00514
00515
00516
00517
00518 if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00519 throw std::exception();
00520 }
00521
00529 void NORETURN SlErrorCorrupt(const char *msg)
00530 {
00531 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00532 }
00533
00534
00535 typedef void (*AsyncSaveFinishProc)();
00536 static AsyncSaveFinishProc _async_save_finish = NULL;
00537 static ThreadObject *_save_thread;
00538
00543 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00544 {
00545 if (_exit_game) return;
00546 while (_async_save_finish != NULL) CSleep(10);
00547
00548 _async_save_finish = proc;
00549 }
00550
00554 void ProcessAsyncSaveFinish()
00555 {
00556 if (_async_save_finish == NULL) return;
00557
00558 _async_save_finish();
00559
00560 _async_save_finish = NULL;
00561
00562 if (_save_thread != NULL) {
00563 _save_thread->Join();
00564 delete _save_thread;
00565 _save_thread = NULL;
00566 }
00567 }
00568
00573 byte SlReadByte()
00574 {
00575 return _sl.reader->ReadByte();
00576 }
00577
00582 void SlWriteByte(byte b)
00583 {
00584 _sl.dumper->WriteByte(b);
00585 }
00586
00587 static inline int SlReadUint16()
00588 {
00589 int x = SlReadByte() << 8;
00590 return x | SlReadByte();
00591 }
00592
00593 static inline uint32 SlReadUint32()
00594 {
00595 uint32 x = SlReadUint16() << 16;
00596 return x | SlReadUint16();
00597 }
00598
00599 static inline uint64 SlReadUint64()
00600 {
00601 uint32 x = SlReadUint32();
00602 uint32 y = SlReadUint32();
00603 return (uint64)x << 32 | y;
00604 }
00605
00606 static inline void SlWriteUint16(uint16 v)
00607 {
00608 SlWriteByte(GB(v, 8, 8));
00609 SlWriteByte(GB(v, 0, 8));
00610 }
00611
00612 static inline void SlWriteUint32(uint32 v)
00613 {
00614 SlWriteUint16(GB(v, 16, 16));
00615 SlWriteUint16(GB(v, 0, 16));
00616 }
00617
00618 static inline void SlWriteUint64(uint64 x)
00619 {
00620 SlWriteUint32((uint32)(x >> 32));
00621 SlWriteUint32((uint32)x);
00622 }
00623
00629 static inline void SlSkipBytes(size_t length)
00630 {
00631 for (; length != 0; length--) SlReadByte();
00632 }
00633
00643 static uint SlReadSimpleGamma()
00644 {
00645 uint i = SlReadByte();
00646 if (HasBit(i, 7)) {
00647 i &= ~0x80;
00648 if (HasBit(i, 6)) {
00649 i &= ~0x40;
00650 if (HasBit(i, 5)) {
00651 i &= ~0x20;
00652 if (HasBit(i, 4)) {
00653 SlErrorCorrupt("Unsupported gamma");
00654 }
00655 i = (i << 8) | SlReadByte();
00656 }
00657 i = (i << 8) | SlReadByte();
00658 }
00659 i = (i << 8) | SlReadByte();
00660 }
00661 return i;
00662 }
00663
00676 static void SlWriteSimpleGamma(size_t i)
00677 {
00678 if (i >= (1 << 7)) {
00679 if (i >= (1 << 14)) {
00680 if (i >= (1 << 21)) {
00681 assert(i < (1 << 28));
00682 SlWriteByte((byte)(0xE0 | (i >> 24)));
00683 SlWriteByte((byte)(i >> 16));
00684 } else {
00685 SlWriteByte((byte)(0xC0 | (i >> 16)));
00686 }
00687 SlWriteByte((byte)(i >> 8));
00688 } else {
00689 SlWriteByte((byte)(0x80 | (i >> 8)));
00690 }
00691 }
00692 SlWriteByte((byte)i);
00693 }
00694
00696 static inline uint SlGetGammaLength(size_t i)
00697 {
00698 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00699 }
00700
00701 static inline uint SlReadSparseIndex()
00702 {
00703 return SlReadSimpleGamma();
00704 }
00705
00706 static inline void SlWriteSparseIndex(uint index)
00707 {
00708 SlWriteSimpleGamma(index);
00709 }
00710
00711 static inline uint SlReadArrayLength()
00712 {
00713 return SlReadSimpleGamma();
00714 }
00715
00716 static inline void SlWriteArrayLength(size_t length)
00717 {
00718 SlWriteSimpleGamma(length);
00719 }
00720
00721 static inline uint SlGetArrayLength(size_t length)
00722 {
00723 return SlGetGammaLength(length);
00724 }
00725
00732 static inline uint SlCalcConvMemLen(VarType conv)
00733 {
00734 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00735 byte length = GB(conv, 4, 4);
00736
00737 switch (length << 4) {
00738 case SLE_VAR_STRB:
00739 case SLE_VAR_STRBQ:
00740 case SLE_VAR_STR:
00741 case SLE_VAR_STRQ:
00742 return SlReadArrayLength();
00743
00744 default:
00745 assert(length < lengthof(conv_mem_size));
00746 return conv_mem_size[length];
00747 }
00748 }
00749
00756 static inline byte SlCalcConvFileLen(VarType conv)
00757 {
00758 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00759 byte length = GB(conv, 0, 4);
00760 assert(length < lengthof(conv_file_size));
00761 return conv_file_size[length];
00762 }
00763
00765 static inline size_t SlCalcRefLen()
00766 {
00767 return IsSavegameVersionBefore(69) ? 2 : 4;
00768 }
00769
00770 void SlSetArrayIndex(uint index)
00771 {
00772 _sl.need_length = NL_WANTLENGTH;
00773 _sl.array_index = index;
00774 }
00775
00776 static size_t _next_offs;
00777
00782 int SlIterateArray()
00783 {
00784 int index;
00785
00786
00787
00788 if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00789
00790 for (;;) {
00791 uint length = SlReadArrayLength();
00792 if (length == 0) {
00793 _next_offs = 0;
00794 return -1;
00795 }
00796
00797 _sl.obj_len = --length;
00798 _next_offs = _sl.reader->GetSize() + length;
00799
00800 switch (_sl.block_mode) {
00801 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00802 case CH_ARRAY: index = _sl.array_index++; break;
00803 default:
00804 DEBUG(sl, 0, "SlIterateArray error");
00805 return -1;
00806 }
00807
00808 if (length != 0) return index;
00809 }
00810 }
00811
00815 void SlSkipArray()
00816 {
00817 while (SlIterateArray() != -1) {
00818 SlSkipBytes(_next_offs - _sl.reader->GetSize());
00819 }
00820 }
00821
00827 void SlSetLength(size_t length)
00828 {
00829 assert(_sl.action == SLA_SAVE);
00830
00831 switch (_sl.need_length) {
00832 case NL_WANTLENGTH:
00833 _sl.need_length = NL_NONE;
00834 switch (_sl.block_mode) {
00835 case CH_RIFF:
00836
00837
00838
00839 assert(length < (1 << 28));
00840 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00841 break;
00842 case CH_ARRAY:
00843 assert(_sl.last_array_index <= _sl.array_index);
00844 while (++_sl.last_array_index <= _sl.array_index) {
00845 SlWriteArrayLength(1);
00846 }
00847 SlWriteArrayLength(length + 1);
00848 break;
00849 case CH_SPARSE_ARRAY:
00850 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00851 SlWriteSparseIndex(_sl.array_index);
00852 break;
00853 default: NOT_REACHED();
00854 }
00855 break;
00856
00857 case NL_CALCLENGTH:
00858 _sl.obj_len += (int)length;
00859 break;
00860
00861 default: NOT_REACHED();
00862 }
00863 }
00864
00871 static void SlCopyBytes(void *ptr, size_t length)
00872 {
00873 byte *p = (byte *)ptr;
00874
00875 switch (_sl.action) {
00876 case SLA_LOAD_CHECK:
00877 case SLA_LOAD:
00878 for (; length != 0; length--) *p++ = SlReadByte();
00879 break;
00880 case SLA_SAVE:
00881 for (; length != 0; length--) SlWriteByte(*p++);
00882 break;
00883 default: NOT_REACHED();
00884 }
00885 }
00886
00888 size_t SlGetFieldLength()
00889 {
00890 return _sl.obj_len;
00891 }
00892
00900 int64 ReadValue(const void *ptr, VarType conv)
00901 {
00902 switch (GetVarMemType(conv)) {
00903 case SLE_VAR_BL: return (*(const bool *)ptr != 0);
00904 case SLE_VAR_I8: return *(const int8 *)ptr;
00905 case SLE_VAR_U8: return *(const byte *)ptr;
00906 case SLE_VAR_I16: return *(const int16 *)ptr;
00907 case SLE_VAR_U16: return *(const uint16*)ptr;
00908 case SLE_VAR_I32: return *(const int32 *)ptr;
00909 case SLE_VAR_U32: return *(const uint32*)ptr;
00910 case SLE_VAR_I64: return *(const int64 *)ptr;
00911 case SLE_VAR_U64: return *(const uint64*)ptr;
00912 case SLE_VAR_NULL:return 0;
00913 default: NOT_REACHED();
00914 }
00915 }
00916
00924 void WriteValue(void *ptr, VarType conv, int64 val)
00925 {
00926 switch (GetVarMemType(conv)) {
00927 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00928 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00929 case SLE_VAR_U8: *(byte *)ptr = val; break;
00930 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00931 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00932 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00933 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00934 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00935 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00936 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00937 case SLE_VAR_NULL: break;
00938 default: NOT_REACHED();
00939 }
00940 }
00941
00950 static void SlSaveLoadConv(void *ptr, VarType conv)
00951 {
00952 switch (_sl.action) {
00953 case SLA_SAVE: {
00954 int64 x = ReadValue(ptr, conv);
00955
00956
00957 switch (GetVarFileType(conv)) {
00958 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00959 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00960 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00961 case SLE_FILE_STRINGID:
00962 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00963 case SLE_FILE_I32:
00964 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00965 case SLE_FILE_I64:
00966 case SLE_FILE_U64: SlWriteUint64(x);break;
00967 default: NOT_REACHED();
00968 }
00969 break;
00970 }
00971 case SLA_LOAD_CHECK:
00972 case SLA_LOAD: {
00973 int64 x;
00974
00975 switch (GetVarFileType(conv)) {
00976 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00977 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00978 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00979 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00980 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00981 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00982 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00983 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00984 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00985 default: NOT_REACHED();
00986 }
00987
00988
00989 WriteValue(ptr, conv, x);
00990 break;
00991 }
00992 case SLA_PTRS: break;
00993 case SLA_NULL: break;
00994 default: NOT_REACHED();
00995 }
00996 }
00997
01007 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
01008 {
01009 if (ptr == NULL) return 0;
01010 return min(strlen(ptr), length - 1);
01011 }
01012
01022 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
01023 {
01024 size_t len;
01025 const char *str;
01026
01027 switch (GetVarMemType(conv)) {
01028 default: NOT_REACHED();
01029 case SLE_VAR_STR:
01030 case SLE_VAR_STRQ:
01031 str = *(const char * const *)ptr;
01032 len = SIZE_MAX;
01033 break;
01034 case SLE_VAR_STRB:
01035 case SLE_VAR_STRBQ:
01036 str = (const char *)ptr;
01037 len = length;
01038 break;
01039 }
01040
01041 len = SlCalcNetStringLen(str, len);
01042 return len + SlGetArrayLength(len);
01043 }
01044
01051 static void SlString(void *ptr, size_t length, VarType conv)
01052 {
01053 switch (_sl.action) {
01054 case SLA_SAVE: {
01055 size_t len;
01056 switch (GetVarMemType(conv)) {
01057 default: NOT_REACHED();
01058 case SLE_VAR_STRB:
01059 case SLE_VAR_STRBQ:
01060 len = SlCalcNetStringLen((char *)ptr, length);
01061 break;
01062 case SLE_VAR_STR:
01063 case SLE_VAR_STRQ:
01064 ptr = *(char **)ptr;
01065 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01066 break;
01067 }
01068
01069 SlWriteArrayLength(len);
01070 SlCopyBytes(ptr, len);
01071 break;
01072 }
01073 case SLA_LOAD_CHECK:
01074 case SLA_LOAD: {
01075 size_t len = SlReadArrayLength();
01076
01077 switch (GetVarMemType(conv)) {
01078 default: NOT_REACHED();
01079 case SLE_VAR_STRB:
01080 case SLE_VAR_STRBQ:
01081 if (len >= length) {
01082 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01083 SlCopyBytes(ptr, length);
01084 SlSkipBytes(len - length);
01085 len = length - 1;
01086 } else {
01087 SlCopyBytes(ptr, len);
01088 }
01089 break;
01090 case SLE_VAR_STR:
01091 case SLE_VAR_STRQ:
01092 free(*(char **)ptr);
01093 if (len == 0) {
01094 *(char **)ptr = NULL;
01095 return;
01096 } else {
01097 *(char **)ptr = MallocT<char>(len + 1);
01098 ptr = *(char **)ptr;
01099 SlCopyBytes(ptr, len);
01100 }
01101 break;
01102 }
01103
01104 ((char *)ptr)[len] = '\0';
01105 StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
01106 if ((conv & SLF_ALLOW_CONTROL) != 0) {
01107 settings = settings | SVS_ALLOW_CONTROL_CODE;
01108 if (IsSavegameVersionBefore(169)) {
01109 str_fix_scc_encoded((char *)ptr, (char *)ptr + len);
01110 }
01111 }
01112 if ((conv & SLF_ALLOW_NEWLINE) != 0) {
01113 settings = settings | SVS_ALLOW_NEWLINE;
01114 }
01115 str_validate((char *)ptr, (char *)ptr + len, settings);
01116 break;
01117 }
01118 case SLA_PTRS: break;
01119 case SLA_NULL: break;
01120 default: NOT_REACHED();
01121 }
01122 }
01123
01129 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01130 {
01131 return SlCalcConvFileLen(conv) * length;
01132 }
01133
01140 void SlArray(void *array, size_t length, VarType conv)
01141 {
01142 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01143
01144
01145 if (_sl.need_length != NL_NONE) {
01146 SlSetLength(SlCalcArrayLen(length, conv));
01147
01148 if (_sl.need_length == NL_CALCLENGTH) return;
01149 }
01150
01151
01152
01153 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01154
01155 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01156 conv == SLE_INT32 || conv == SLE_UINT32) {
01157 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01158 return;
01159 }
01160
01161 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01162 for (uint i = 0; i < length; i++) {
01163 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01164 }
01165 return;
01166 }
01167 }
01168
01169
01170
01171 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01172 SlCopyBytes(array, length);
01173 } else {
01174 byte *a = (byte*)array;
01175 byte mem_size = SlCalcConvMemLen(conv);
01176
01177 for (; length != 0; length --) {
01178 SlSaveLoadConv(a, conv);
01179 a += mem_size;
01180 }
01181 }
01182 }
01183
01184
01195 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01196 {
01197 assert(_sl.action == SLA_SAVE);
01198
01199 if (obj == NULL) return 0;
01200
01201 switch (rt) {
01202 case REF_VEHICLE_OLD:
01203 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01204 case REF_STATION: return ((const Station*)obj)->index + 1;
01205 case REF_TOWN: return ((const Town*)obj)->index + 1;
01206 case REF_ORDER: return ((const Order*)obj)->index + 1;
01207 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01208 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01209 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01210 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01211 case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
01212 default: NOT_REACHED();
01213 }
01214 }
01215
01226 static void *IntToReference(size_t index, SLRefType rt)
01227 {
01228 assert_compile(sizeof(size_t) <= sizeof(void *));
01229
01230 assert(_sl.action == SLA_PTRS);
01231
01232
01233
01234 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01235 rt = REF_VEHICLE;
01236 }
01237
01238
01239 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01240
01241
01242
01243 if (rt != REF_VEHICLE_OLD) index--;
01244
01245 switch (rt) {
01246 case REF_ORDERLIST:
01247 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01248 SlErrorCorrupt("Referencing invalid OrderList");
01249
01250 case REF_ORDER:
01251 if (Order::IsValidID(index)) return Order::Get(index);
01252
01253 if (IsSavegameVersionBefore(5, 2)) return NULL;
01254 SlErrorCorrupt("Referencing invalid Order");
01255
01256 case REF_VEHICLE_OLD:
01257 case REF_VEHICLE:
01258 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01259 SlErrorCorrupt("Referencing invalid Vehicle");
01260
01261 case REF_STATION:
01262 if (Station::IsValidID(index)) return Station::Get(index);
01263 SlErrorCorrupt("Referencing invalid Station");
01264
01265 case REF_TOWN:
01266 if (Town::IsValidID(index)) return Town::Get(index);
01267 SlErrorCorrupt("Referencing invalid Town");
01268
01269 case REF_ROADSTOPS:
01270 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01271 SlErrorCorrupt("Referencing invalid RoadStop");
01272
01273 case REF_ENGINE_RENEWS:
01274 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01275 SlErrorCorrupt("Referencing invalid EngineRenew");
01276
01277 case REF_CARGO_PACKET:
01278 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01279 SlErrorCorrupt("Referencing invalid CargoPacket");
01280
01281 case REF_STORAGE:
01282 if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index);
01283 SlErrorCorrupt("Referencing invalid PersistentStorage");
01284
01285 default: NOT_REACHED();
01286 }
01287 }
01288
01293 static inline size_t SlCalcListLen(const void *list)
01294 {
01295 const std::list<void *> *l = (const std::list<void *> *) list;
01296
01297 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01298
01299
01300 return l->size() * type_size + type_size;
01301 }
01302
01303
01309 static void SlList(void *list, SLRefType conv)
01310 {
01311
01312 if (_sl.need_length != NL_NONE) {
01313 SlSetLength(SlCalcListLen(list));
01314
01315 if (_sl.need_length == NL_CALCLENGTH) return;
01316 }
01317
01318 typedef std::list<void *> PtrList;
01319 PtrList *l = (PtrList *)list;
01320
01321 switch (_sl.action) {
01322 case SLA_SAVE: {
01323 SlWriteUint32((uint32)l->size());
01324
01325 PtrList::iterator iter;
01326 for (iter = l->begin(); iter != l->end(); ++iter) {
01327 void *ptr = *iter;
01328 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01329 }
01330 break;
01331 }
01332 case SLA_LOAD_CHECK:
01333 case SLA_LOAD: {
01334 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01335
01336
01337 for (size_t i = 0; i < length; i++) {
01338 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01339 l->push_back((void *)data);
01340 }
01341 break;
01342 }
01343 case SLA_PTRS: {
01344 PtrList temp = *l;
01345
01346 l->clear();
01347 PtrList::iterator iter;
01348 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01349 void *ptr = IntToReference((size_t)*iter, conv);
01350 l->push_back(ptr);
01351 }
01352 break;
01353 }
01354 case SLA_NULL:
01355 l->clear();
01356 break;
01357 default: NOT_REACHED();
01358 }
01359 }
01360
01361
01363 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01364 {
01365 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01366 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01367
01368 return true;
01369 }
01370
01376 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01377 {
01378 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01379 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01380 return true;
01381 }
01382
01383 return false;
01384 }
01385
01392 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01393 {
01394 size_t length = 0;
01395
01396
01397 for (; sld->cmd != SL_END; sld++) {
01398 length += SlCalcObjMemberLength(object, sld);
01399 }
01400 return length;
01401 }
01402
01403 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01404 {
01405 assert(_sl.action == SLA_SAVE);
01406
01407 switch (sld->cmd) {
01408 case SL_VAR:
01409 case SL_REF:
01410 case SL_ARR:
01411 case SL_STR:
01412 case SL_LST:
01413
01414 if (!SlIsObjectValidInSavegame(sld)) break;
01415
01416 switch (sld->cmd) {
01417 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01418 case SL_REF: return SlCalcRefLen();
01419 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01420 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01421 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01422 default: NOT_REACHED();
01423 }
01424 break;
01425 case SL_WRITEBYTE: return 1;
01426 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01427 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01428 default: NOT_REACHED();
01429 }
01430 return 0;
01431 }
01432
01433
01434 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01435 {
01436 VarType conv = GB(sld->conv, 0, 8);
01437 switch (sld->cmd) {
01438 case SL_VAR:
01439 case SL_REF:
01440 case SL_ARR:
01441 case SL_STR:
01442 case SL_LST:
01443
01444 if (!SlIsObjectValidInSavegame(sld)) return false;
01445 if (SlSkipVariableOnLoad(sld)) return false;
01446
01447 switch (sld->cmd) {
01448 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01449 case SL_REF:
01450 switch (_sl.action) {
01451 case SLA_SAVE:
01452 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01453 break;
01454 case SLA_LOAD_CHECK:
01455 case SLA_LOAD:
01456 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01457 break;
01458 case SLA_PTRS:
01459 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01460 break;
01461 case SLA_NULL:
01462 *(void **)ptr = NULL;
01463 break;
01464 default: NOT_REACHED();
01465 }
01466 break;
01467 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01468 case SL_STR: SlString(ptr, sld->length, sld->conv); break;
01469 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01470 default: NOT_REACHED();
01471 }
01472 break;
01473
01474
01475
01476
01477
01478
01479 case SL_WRITEBYTE:
01480 switch (_sl.action) {
01481 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01482 case SLA_LOAD_CHECK:
01483 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01484 case SLA_PTRS: break;
01485 case SLA_NULL: break;
01486 default: NOT_REACHED();
01487 }
01488 break;
01489
01490
01491 case SL_VEH_INCLUDE:
01492 SlObject(ptr, GetVehicleDescription(VEH_END));
01493 break;
01494
01495 case SL_ST_INCLUDE:
01496 SlObject(ptr, GetBaseStationDescription());
01497 break;
01498
01499 default: NOT_REACHED();
01500 }
01501 return true;
01502 }
01503
01509 void SlObject(void *object, const SaveLoad *sld)
01510 {
01511
01512 if (_sl.need_length != NL_NONE) {
01513 SlSetLength(SlCalcObjLength(object, sld));
01514 if (_sl.need_length == NL_CALCLENGTH) return;
01515 }
01516
01517 for (; sld->cmd != SL_END; sld++) {
01518 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01519 SlObjectMember(ptr, sld);
01520 }
01521 }
01522
01527 void SlGlobList(const SaveLoadGlobVarList *sldg)
01528 {
01529 SlObject(NULL, (const SaveLoad*)sldg);
01530 }
01531
01537 void SlAutolength(AutolengthProc *proc, void *arg)
01538 {
01539 size_t offs;
01540
01541 assert(_sl.action == SLA_SAVE);
01542
01543
01544 _sl.need_length = NL_CALCLENGTH;
01545 _sl.obj_len = 0;
01546 proc(arg);
01547
01548
01549 _sl.need_length = NL_WANTLENGTH;
01550 SlSetLength(_sl.obj_len);
01551
01552 offs = _sl.dumper->GetSize() + _sl.obj_len;
01553
01554
01555 proc(arg);
01556
01557 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01558 }
01559
01564 static void SlLoadChunk(const ChunkHandler *ch)
01565 {
01566 byte m = SlReadByte();
01567 size_t len;
01568 size_t endoffs;
01569
01570 _sl.block_mode = m;
01571 _sl.obj_len = 0;
01572
01573 switch (m) {
01574 case CH_ARRAY:
01575 _sl.array_index = 0;
01576 ch->load_proc();
01577 break;
01578 case CH_SPARSE_ARRAY:
01579 ch->load_proc();
01580 break;
01581 default:
01582 if ((m & 0xF) == CH_RIFF) {
01583
01584 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01585 len += SlReadUint16();
01586 _sl.obj_len = len;
01587 endoffs = _sl.reader->GetSize() + len;
01588 ch->load_proc();
01589 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01590 } else {
01591 SlErrorCorrupt("Invalid chunk type");
01592 }
01593 break;
01594 }
01595 }
01596
01602 static void SlLoadCheckChunk(const ChunkHandler *ch)
01603 {
01604 byte m = SlReadByte();
01605 size_t len;
01606 size_t endoffs;
01607
01608 _sl.block_mode = m;
01609 _sl.obj_len = 0;
01610
01611 switch (m) {
01612 case CH_ARRAY:
01613 _sl.array_index = 0;
01614 if (ch->load_check_proc) {
01615 ch->load_check_proc();
01616 } else {
01617 SlSkipArray();
01618 }
01619 break;
01620 case CH_SPARSE_ARRAY:
01621 if (ch->load_check_proc) {
01622 ch->load_check_proc();
01623 } else {
01624 SlSkipArray();
01625 }
01626 break;
01627 default:
01628 if ((m & 0xF) == CH_RIFF) {
01629
01630 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01631 len += SlReadUint16();
01632 _sl.obj_len = len;
01633 endoffs = _sl.reader->GetSize() + len;
01634 if (ch->load_check_proc) {
01635 ch->load_check_proc();
01636 } else {
01637 SlSkipBytes(len);
01638 }
01639 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01640 } else {
01641 SlErrorCorrupt("Invalid chunk type");
01642 }
01643 break;
01644 }
01645 }
01646
01651 static ChunkSaveLoadProc *_stub_save_proc;
01652
01658 static inline void SlStubSaveProc2(void *arg)
01659 {
01660 _stub_save_proc();
01661 }
01662
01668 static void SlStubSaveProc()
01669 {
01670 SlAutolength(SlStubSaveProc2, NULL);
01671 }
01672
01678 static void SlSaveChunk(const ChunkHandler *ch)
01679 {
01680 ChunkSaveLoadProc *proc = ch->save_proc;
01681
01682
01683 if (proc == NULL) return;
01684
01685 SlWriteUint32(ch->id);
01686 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01687
01688 if (ch->flags & CH_AUTO_LENGTH) {
01689
01690 _stub_save_proc = proc;
01691 proc = SlStubSaveProc;
01692 }
01693
01694 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01695 switch (ch->flags & CH_TYPE_MASK) {
01696 case CH_RIFF:
01697 _sl.need_length = NL_WANTLENGTH;
01698 proc();
01699 break;
01700 case CH_ARRAY:
01701 _sl.last_array_index = 0;
01702 SlWriteByte(CH_ARRAY);
01703 proc();
01704 SlWriteArrayLength(0);
01705 break;
01706 case CH_SPARSE_ARRAY:
01707 SlWriteByte(CH_SPARSE_ARRAY);
01708 proc();
01709 SlWriteArrayLength(0);
01710 break;
01711 default: NOT_REACHED();
01712 }
01713 }
01714
01716 static void SlSaveChunks()
01717 {
01718 FOR_ALL_CHUNK_HANDLERS(ch) {
01719 SlSaveChunk(ch);
01720 }
01721
01722
01723 SlWriteUint32(0);
01724 }
01725
01732 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01733 {
01734 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01735 return NULL;
01736 }
01737
01739 static void SlLoadChunks()
01740 {
01741 uint32 id;
01742 const ChunkHandler *ch;
01743
01744 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01745 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01746
01747 ch = SlFindChunkHandler(id);
01748 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01749 SlLoadChunk(ch);
01750 }
01751 }
01752
01754 static void SlLoadCheckChunks()
01755 {
01756 uint32 id;
01757 const ChunkHandler *ch;
01758
01759 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01760 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01761
01762 ch = SlFindChunkHandler(id);
01763 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01764 SlLoadCheckChunk(ch);
01765 }
01766 }
01767
01769 static void SlFixPointers()
01770 {
01771 _sl.action = SLA_PTRS;
01772
01773 DEBUG(sl, 1, "Fixing pointers");
01774
01775 FOR_ALL_CHUNK_HANDLERS(ch) {
01776 if (ch->ptrs_proc != NULL) {
01777 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01778 ch->ptrs_proc();
01779 }
01780 }
01781
01782 DEBUG(sl, 1, "All pointers fixed");
01783
01784 assert(_sl.action == SLA_PTRS);
01785 }
01786
01787
01789 struct FileReader : LoadFilter {
01790 FILE *file;
01791 long begin;
01792
01797 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01798 {
01799 }
01800
01802 ~FileReader()
01803 {
01804 if (this->file != NULL) fclose(this->file);
01805 this->file = NULL;
01806
01807
01808 _sl.sf = NULL;
01809 }
01810
01811 size_t Read(byte *buf, size_t size)
01812 {
01813
01814 if (this->file == NULL) return 0;
01815
01816 return fread(buf, 1, size, this->file);
01817 }
01818
01819 void Reset()
01820 {
01821 clearerr(this->file);
01822 fseek(this->file, this->begin, SEEK_SET);
01823 }
01824 };
01825
01827 struct FileWriter : SaveFilter {
01828 FILE *file;
01829
01834 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01835 {
01836 }
01837
01839 ~FileWriter()
01840 {
01841 this->Finish();
01842
01843
01844 _sl.sf = NULL;
01845 }
01846
01847 void Write(byte *buf, size_t size)
01848 {
01849
01850 if (this->file == NULL) return;
01851
01852 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01853 }
01854
01855 void Finish()
01856 {
01857 if (this->file != NULL) fclose(this->file);
01858 this->file = NULL;
01859 }
01860 };
01861
01862
01863
01864
01865
01866 #ifdef WITH_LZO
01867 #include <lzo/lzo1x.h>
01868
01870 static const uint LZO_BUFFER_SIZE = 8192;
01871
01873 struct LZOLoadFilter : LoadFilter {
01878 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01879 {
01880 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01881 }
01882
01883 size_t Read(byte *buf, size_t ssize)
01884 {
01885 assert(ssize >= LZO_BUFFER_SIZE);
01886
01887
01888 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01889 uint32 tmp[2];
01890 uint32 size;
01891 lzo_uint len;
01892
01893
01894 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01895
01896
01897 ((uint32*)out)[0] = size = tmp[1];
01898
01899 if (_sl_version != 0) {
01900 tmp[0] = TO_BE32(tmp[0]);
01901 size = TO_BE32(size);
01902 }
01903
01904 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01905
01906
01907 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01908
01909
01910 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01911
01912
01913 lzo1x_decompress(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01914 return len;
01915 }
01916 };
01917
01919 struct LZOSaveFilter : SaveFilter {
01925 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01926 {
01927 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01928 }
01929
01930 void Write(byte *buf, size_t size)
01931 {
01932 const lzo_bytep in = buf;
01933
01934 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01935 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01936 lzo_uint outlen;
01937
01938 do {
01939
01940 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01941 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01942 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01943 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01944 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01945
01946
01947 size -= len;
01948 in += len;
01949 } while (size > 0);
01950 }
01951 };
01952
01953 #endif
01954
01955
01956
01957
01958
01960 struct NoCompLoadFilter : LoadFilter {
01965 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01966 {
01967 }
01968
01969 size_t Read(byte *buf, size_t size)
01970 {
01971 return this->chain->Read(buf, size);
01972 }
01973 };
01974
01976 struct NoCompSaveFilter : SaveFilter {
01982 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01983 {
01984 }
01985
01986 void Write(byte *buf, size_t size)
01987 {
01988 this->chain->Write(buf, size);
01989 }
01990 };
01991
01992
01993
01994
01995
01996 #if defined(WITH_ZLIB)
01997 #include <zlib.h>
01998
02000 struct ZlibLoadFilter : LoadFilter {
02001 z_stream z;
02002 byte fread_buf[MEMORY_CHUNK_SIZE];
02003
02008 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
02009 {
02010 memset(&this->z, 0, sizeof(this->z));
02011 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02012 }
02013
02015 ~ZlibLoadFilter()
02016 {
02017 inflateEnd(&this->z);
02018 }
02019
02020 size_t Read(byte *buf, size_t size)
02021 {
02022 this->z.next_out = buf;
02023 this->z.avail_out = (uint)size;
02024
02025 do {
02026
02027 if (this->z.avail_in == 0) {
02028 this->z.next_in = this->fread_buf;
02029 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02030 }
02031
02032
02033 int r = inflate(&this->z, 0);
02034 if (r == Z_STREAM_END) break;
02035
02036 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02037 } while (this->z.avail_out != 0);
02038
02039 return size - this->z.avail_out;
02040 }
02041 };
02042
02044 struct ZlibSaveFilter : SaveFilter {
02045 z_stream z;
02046
02052 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02053 {
02054 memset(&this->z, 0, sizeof(this->z));
02055 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02056 }
02057
02059 ~ZlibSaveFilter()
02060 {
02061 deflateEnd(&this->z);
02062 }
02063
02070 void WriteLoop(byte *p, size_t len, int mode)
02071 {
02072 byte buf[MEMORY_CHUNK_SIZE];
02073 uint n;
02074 this->z.next_in = p;
02075 this->z.avail_in = (uInt)len;
02076 do {
02077 this->z.next_out = buf;
02078 this->z.avail_out = sizeof(buf);
02079
02087 int r = deflate(&this->z, mode);
02088
02089
02090 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02091 this->chain->Write(buf, n);
02092 }
02093 if (r == Z_STREAM_END) break;
02094
02095 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02096 } while (this->z.avail_in || !this->z.avail_out);
02097 }
02098
02099 void Write(byte *buf, size_t size)
02100 {
02101 this->WriteLoop(buf, size, 0);
02102 }
02103
02104 void Finish()
02105 {
02106 this->WriteLoop(NULL, 0, Z_FINISH);
02107 this->chain->Finish();
02108 }
02109 };
02110
02111 #endif
02112
02113
02114
02115
02116
02117 #if defined(WITH_LZMA)
02118 #include <lzma.h>
02119
02126 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02127
02129 struct LZMALoadFilter : LoadFilter {
02130 lzma_stream lzma;
02131 byte fread_buf[MEMORY_CHUNK_SIZE];
02132
02137 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02138 {
02139
02140 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02141 }
02142
02144 ~LZMALoadFilter()
02145 {
02146 lzma_end(&this->lzma);
02147 }
02148
02149 size_t Read(byte *buf, size_t size)
02150 {
02151 this->lzma.next_out = buf;
02152 this->lzma.avail_out = size;
02153
02154 do {
02155
02156 if (this->lzma.avail_in == 0) {
02157 this->lzma.next_in = this->fread_buf;
02158 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02159 }
02160
02161
02162 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02163 if (r == LZMA_STREAM_END) break;
02164 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02165 } while (this->lzma.avail_out != 0);
02166
02167 return size - this->lzma.avail_out;
02168 }
02169 };
02170
02172 struct LZMASaveFilter : SaveFilter {
02173 lzma_stream lzma;
02174
02180 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02181 {
02182 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02183 }
02184
02186 ~LZMASaveFilter()
02187 {
02188 lzma_end(&this->lzma);
02189 }
02190
02197 void WriteLoop(byte *p, size_t len, lzma_action action)
02198 {
02199 byte buf[MEMORY_CHUNK_SIZE];
02200 size_t n;
02201 this->lzma.next_in = p;
02202 this->lzma.avail_in = len;
02203 do {
02204 this->lzma.next_out = buf;
02205 this->lzma.avail_out = sizeof(buf);
02206
02207 lzma_ret r = lzma_code(&this->lzma, action);
02208
02209
02210 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02211 this->chain->Write(buf, n);
02212 }
02213 if (r == LZMA_STREAM_END) break;
02214 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02215 } while (this->lzma.avail_in || !this->lzma.avail_out);
02216 }
02217
02218 void Write(byte *buf, size_t size)
02219 {
02220 this->WriteLoop(buf, size, LZMA_RUN);
02221 }
02222
02223 void Finish()
02224 {
02225 this->WriteLoop(NULL, 0, LZMA_FINISH);
02226 this->chain->Finish();
02227 }
02228 };
02229
02230 #endif
02231
02232
02233
02234
02235
02237 struct SaveLoadFormat {
02238 const char *name;
02239 uint32 tag;
02240
02241 LoadFilter *(*init_load)(LoadFilter *chain);
02242 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02243
02244 byte min_compression;
02245 byte default_compression;
02246 byte max_compression;
02247 };
02248
02250 static const SaveLoadFormat _saveload_formats[] = {
02251 #if defined(WITH_LZO)
02252
02253 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02254 #else
02255 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02256 #endif
02257
02258 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02259 #if defined(WITH_ZLIB)
02260
02261
02262
02263 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02264 #else
02265 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02266 #endif
02267 #if defined(WITH_LZMA)
02268
02269
02270
02271
02272
02273 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02274 #else
02275 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02276 #endif
02277 };
02278
02286 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02287 {
02288 const SaveLoadFormat *def = lastof(_saveload_formats);
02289
02290
02291 while (!def->init_write) def--;
02292
02293 if (!StrEmpty(s)) {
02294
02295 char *complevel = strrchr(s, ':');
02296 if (complevel != NULL) *complevel = '\0';
02297
02298 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02299 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02300 *compression_level = slf->default_compression;
02301 if (complevel != NULL) {
02302
02303
02304
02305 *complevel = ':';
02306 complevel++;
02307
02308
02309 char *end;
02310 long level = strtol(complevel, &end, 10);
02311 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02312 SetDParamStr(0, complevel);
02313 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL);
02314 } else {
02315 *compression_level = level;
02316 }
02317 }
02318 return slf;
02319 }
02320 }
02321
02322 SetDParamStr(0, s);
02323 SetDParamStr(1, def->name);
02324 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL);
02325
02326
02327 if (complevel != NULL) *complevel = ':';
02328 }
02329 *compression_level = def->default_compression;
02330 return def;
02331 }
02332
02333
02334 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02335 extern bool AfterLoadGame();
02336 extern bool LoadOldSaveGame(const char *file);
02337
02341 static inline void ClearSaveLoadState()
02342 {
02343 delete _sl.dumper;
02344 _sl.dumper = NULL;
02345
02346 delete _sl.sf;
02347 _sl.sf = NULL;
02348
02349 delete _sl.reader;
02350 _sl.reader = NULL;
02351
02352 delete _sl.lf;
02353 _sl.lf = NULL;
02354 }
02355
02361 static void SaveFileStart()
02362 {
02363 _sl.ff_state = _fast_forward;
02364 _fast_forward = 0;
02365 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02366
02367 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02368 _sl.saveinprogress = true;
02369 }
02370
02372 static void SaveFileDone()
02373 {
02374 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02375 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02376
02377 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02378 _sl.saveinprogress = false;
02379 }
02380
02382 void SetSaveLoadError(StringID str)
02383 {
02384 _sl.error_str = str;
02385 }
02386
02388 const char *GetSaveLoadErrorString()
02389 {
02390 SetDParam(0, _sl.error_str);
02391 SetDParamStr(1, _sl.extra_msg);
02392
02393 static char err_str[512];
02394 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02395 return err_str;
02396 }
02397
02399 static void SaveFileError()
02400 {
02401 SetDParamStr(0, GetSaveLoadErrorString());
02402 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02403 SaveFileDone();
02404 }
02405
02410 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02411 {
02412 try {
02413 byte compression;
02414 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02415
02416
02417 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02418 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02419
02420 _sl.sf = fmt->init_write(_sl.sf, compression);
02421 _sl.dumper->Flush(_sl.sf);
02422
02423 ClearSaveLoadState();
02424
02425 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02426
02427 return SL_OK;
02428 } catch (...) {
02429 ClearSaveLoadState();
02430
02431 AsyncSaveFinishProc asfp = SaveFileDone;
02432
02433
02434
02435 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02436
02437 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02438 asfp = SaveFileError;
02439 }
02440
02441 if (threaded) {
02442 SetAsyncSaveFinish(asfp);
02443 } else {
02444 asfp();
02445 }
02446 return SL_ERROR;
02447 }
02448 }
02449
02451 static void SaveFileToDiskThread(void *arg)
02452 {
02453 SaveFileToDisk(true);
02454 }
02455
02456 void WaitTillSaved()
02457 {
02458 if (_save_thread == NULL) return;
02459
02460 _save_thread->Join();
02461 delete _save_thread;
02462 _save_thread = NULL;
02463
02464
02465 ProcessAsyncSaveFinish();
02466 }
02467
02476 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02477 {
02478 assert(!_sl.saveinprogress);
02479
02480 _sl.dumper = new MemoryDumper();
02481 _sl.sf = writer;
02482
02483 _sl_version = SAVEGAME_VERSION;
02484
02485 SaveViewportBeforeSaveGame();
02486 SlSaveChunks();
02487
02488 SaveFileStart();
02489 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02490 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02491
02492 SaveOrLoadResult result = SaveFileToDisk(false);
02493 SaveFileDone();
02494
02495 return result;
02496 }
02497
02498 return SL_OK;
02499 }
02500
02507 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02508 {
02509 try {
02510 _sl.action = SLA_SAVE;
02511 return DoSave(writer, threaded);
02512 } catch (...) {
02513 ClearSaveLoadState();
02514 return SL_ERROR;
02515 }
02516 }
02517
02524 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02525 {
02526 _sl.lf = reader;
02527
02528 if (load_check) {
02529
02530 _load_check_data.Clear();
02531
02532 _load_check_data.checkable = true;
02533 }
02534
02535 uint32 hdr[2];
02536 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02537
02538
02539 const SaveLoadFormat *fmt = _saveload_formats;
02540 for (;;) {
02541
02542 if (fmt == endof(_saveload_formats)) {
02543 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02544 _sl.lf->Reset();
02545 _sl_version = 0;
02546 _sl_minor_version = 0;
02547
02548
02549 fmt = _saveload_formats;
02550 for (;;) {
02551 if (fmt == endof(_saveload_formats)) {
02552
02553 NOT_REACHED();
02554 }
02555 if (fmt->tag == TO_BE32X('OTTD')) break;
02556 fmt++;
02557 }
02558 break;
02559 }
02560
02561 if (fmt->tag == hdr[0]) {
02562
02563 _sl_version = TO_BE32(hdr[1]) >> 16;
02564
02565
02566
02567 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02568
02569 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02570
02571
02572 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02573 break;
02574 }
02575
02576 fmt++;
02577 }
02578
02579
02580 if (fmt->init_load == NULL) {
02581 char err_str[64];
02582 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02583 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02584 }
02585
02586 _sl.lf = fmt->init_load(_sl.lf);
02587 _sl.reader = new ReadBuffer(_sl.lf);
02588 _next_offs = 0;
02589
02590 if (!load_check) {
02591
02592
02593
02594 InitializeGame(256, 256, true, true);
02595
02596 GamelogReset();
02597
02598 if (IsSavegameVersionBefore(4)) {
02599
02600
02601
02602
02603
02604
02605
02606
02607
02608
02609
02610
02611
02612
02613
02614
02615
02616
02617
02618
02619
02620 ClearGRFConfigList(&_grfconfig);
02621 }
02622 }
02623
02624 if (load_check) {
02625
02626
02627 SlLoadCheckChunks();
02628 } else {
02629
02630 SlLoadChunks();
02631 SlFixPointers();
02632 }
02633
02634 ClearSaveLoadState();
02635
02636 _savegame_type = SGT_OTTD;
02637
02638 if (load_check) {
02639
02640 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02641 } else {
02642 GamelogStartAction(GLAT_LOAD);
02643
02644
02645
02646 if (!AfterLoadGame()) {
02647 GamelogStopAction();
02648 return SL_REINIT;
02649 }
02650
02651 GamelogStopAction();
02652 }
02653
02654 return SL_OK;
02655 }
02656
02662 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02663 {
02664 try {
02665 _sl.action = SLA_LOAD;
02666 return DoLoad(reader, false);
02667 } catch (...) {
02668 ClearSaveLoadState();
02669 return SL_REINIT;
02670 }
02671 }
02672
02682 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02683 {
02684
02685 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02686
02687 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02688 return SL_OK;
02689 }
02690 WaitTillSaved();
02691
02692
02693 if (mode == SL_OLD_LOAD) {
02694 InitializeGame(256, 256, true, true);
02695
02696
02697
02698
02699
02700 ClearGRFConfigList(&_grfconfig);
02701 GamelogReset();
02702 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02703 _sl_version = 0;
02704 _sl_minor_version = 0;
02705 GamelogStartAction(GLAT_LOAD);
02706 if (!AfterLoadGame()) {
02707 GamelogStopAction();
02708 return SL_REINIT;
02709 }
02710 GamelogStopAction();
02711 return SL_OK;
02712 }
02713
02714 switch (mode) {
02715 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02716 case SL_LOAD: _sl.action = SLA_LOAD; break;
02717 case SL_SAVE: _sl.action = SLA_SAVE; break;
02718 default: NOT_REACHED();
02719 }
02720
02721 try {
02722 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02723
02724
02725 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02726 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02727 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
02728
02729 if (fh == NULL) {
02730 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02731 }
02732
02733 if (mode == SL_SAVE) {
02734 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02735 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02736
02737 return DoSave(new FileWriter(fh), threaded);
02738 }
02739
02740
02741 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02742 DEBUG(desync, 1, "load: %s", filename);
02743 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02744 } catch (...) {
02745 ClearSaveLoadState();
02746
02747
02748 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02749
02750
02751 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02752 }
02753 }
02754
02756 void DoExitSave()
02757 {
02758 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02759 }
02760
02766 void GenerateDefaultSaveName(char *buf, const char *last)
02767 {
02768
02769
02770
02771 CompanyID cid = _local_company;
02772 if (!Company::IsValidID(cid)) {
02773 const Company *c;
02774 FOR_ALL_COMPANIES(c) {
02775 cid = c->index;
02776 break;
02777 }
02778 }
02779
02780 SetDParam(0, cid);
02781
02782
02783 switch (_settings_client.gui.date_format_in_default_names) {
02784 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02785 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02786 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02787 default: NOT_REACHED();
02788 }
02789 SetDParam(2, _date);
02790
02791
02792 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02793 SanitizeFilename(buf);
02794 }
02795
02796 #if 0
02797
02803 int GetSavegameType(char *file)
02804 {
02805 const SaveLoadFormat *fmt;
02806 uint32 hdr;
02807 FILE *f;
02808 int mode = SL_OLD_LOAD;
02809
02810 f = fopen(file, "rb");
02811 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02812 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02813 mode = SL_LOAD;
02814 } else {
02815
02816 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02817 if (fmt->tag == hdr) {
02818 mode = SL_LOAD;
02819 break;
02820 }
02821 }
02822 }
02823
02824 fclose(f);
02825 return mode;
02826 }
02827 #endif