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 extern const uint16 SAVEGAME_VERSION = 168;
00237
00238 SavegameType _savegame_type;
00239
00240 uint32 _ttdp_version;
00241 uint16 _sl_version;
00242 byte _sl_minor_version;
00243 char _savegame_format[8];
00244 bool _do_autosave;
00245
00247 enum SaveLoadAction {
00248 SLA_LOAD,
00249 SLA_SAVE,
00250 SLA_PTRS,
00251 SLA_NULL,
00252 SLA_LOAD_CHECK,
00253 };
00254
00255 enum NeedLength {
00256 NL_NONE = 0,
00257 NL_WANTLENGTH = 1,
00258 NL_CALCLENGTH = 2,
00259 };
00260
00262 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
00263
00265 struct ReadBuffer {
00266 byte buf[MEMORY_CHUNK_SIZE];
00267 byte *bufp;
00268 byte *bufe;
00269 LoadFilter *reader;
00270 size_t read;
00271
00276 ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
00277 {
00278 }
00279
00280 inline byte ReadByte()
00281 {
00282 if (this->bufp == this->bufe) {
00283 size_t len = this->reader->Read(this->buf, lengthof(this->buf));
00284 if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00285
00286 this->read += len;
00287 this->bufp = this->buf;
00288 this->bufe = this->buf + len;
00289 }
00290
00291 return *this->bufp++;
00292 }
00293
00298 size_t GetSize() const
00299 {
00300 return this->read - (this->bufe - this->bufp);
00301 }
00302 };
00303
00304
00306 struct MemoryDumper {
00307 AutoFreeSmallVector<byte *, 16> blocks;
00308 byte *buf;
00309 byte *bufe;
00310
00312 MemoryDumper() : buf(NULL), bufe(NULL)
00313 {
00314 }
00315
00320 inline void WriteByte(byte b)
00321 {
00322
00323 if (this->buf == this->bufe) {
00324 this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
00325 *this->blocks.Append() = this->buf;
00326 this->bufe = this->buf + MEMORY_CHUNK_SIZE;
00327 }
00328
00329 *this->buf++ = b;
00330 }
00331
00336 void Flush(SaveFilter *writer)
00337 {
00338 uint i = 0;
00339 size_t t = this->GetSize();
00340
00341 while (t > 0) {
00342 size_t to_write = min(MEMORY_CHUNK_SIZE, t);
00343
00344 writer->Write(this->blocks[i++], to_write);
00345 t -= to_write;
00346 }
00347
00348 writer->Finish();
00349 }
00350
00355 size_t GetSize() const
00356 {
00357 return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
00358 }
00359 };
00360
00362 struct SaveLoadParams {
00363 SaveLoadAction action;
00364 NeedLength need_length;
00365 byte block_mode;
00366 bool error;
00367
00368 size_t obj_len;
00369 int array_index, last_array_index;
00370
00371 MemoryDumper *dumper;
00372 SaveFilter *sf;
00373
00374 ReadBuffer *reader;
00375 LoadFilter *lf;
00376
00377 StringID error_str;
00378 char *extra_msg;
00379
00380 byte ff_state;
00381 bool saveinprogress;
00382 };
00383
00384 static SaveLoadParams _sl;
00385
00386
00387 extern const ChunkHandler _gamelog_chunk_handlers[];
00388 extern const ChunkHandler _map_chunk_handlers[];
00389 extern const ChunkHandler _misc_chunk_handlers[];
00390 extern const ChunkHandler _name_chunk_handlers[];
00391 extern const ChunkHandler _cheat_chunk_handlers[] ;
00392 extern const ChunkHandler _setting_chunk_handlers[];
00393 extern const ChunkHandler _company_chunk_handlers[];
00394 extern const ChunkHandler _engine_chunk_handlers[];
00395 extern const ChunkHandler _veh_chunk_handlers[];
00396 extern const ChunkHandler _waypoint_chunk_handlers[];
00397 extern const ChunkHandler _depot_chunk_handlers[];
00398 extern const ChunkHandler _order_chunk_handlers[];
00399 extern const ChunkHandler _town_chunk_handlers[];
00400 extern const ChunkHandler _sign_chunk_handlers[];
00401 extern const ChunkHandler _station_chunk_handlers[];
00402 extern const ChunkHandler _industry_chunk_handlers[];
00403 extern const ChunkHandler _economy_chunk_handlers[];
00404 extern const ChunkHandler _subsidy_chunk_handlers[];
00405 extern const ChunkHandler _goal_chunk_handlers[];
00406 extern const ChunkHandler _ai_chunk_handlers[];
00407 extern const ChunkHandler _game_chunk_handlers[];
00408 extern const ChunkHandler _animated_tile_chunk_handlers[];
00409 extern const ChunkHandler _newgrf_chunk_handlers[];
00410 extern const ChunkHandler _group_chunk_handlers[];
00411 extern const ChunkHandler _cargopacket_chunk_handlers[];
00412 extern const ChunkHandler _autoreplace_chunk_handlers[];
00413 extern const ChunkHandler _labelmaps_chunk_handlers[];
00414 extern const ChunkHandler _airport_chunk_handlers[];
00415 extern const ChunkHandler _object_chunk_handlers[];
00416 extern const ChunkHandler _persistent_storage_chunk_handlers[];
00417
00419 static const ChunkHandler * const _chunk_handlers[] = {
00420 _gamelog_chunk_handlers,
00421 _map_chunk_handlers,
00422 _misc_chunk_handlers,
00423 _name_chunk_handlers,
00424 _cheat_chunk_handlers,
00425 _setting_chunk_handlers,
00426 _veh_chunk_handlers,
00427 _waypoint_chunk_handlers,
00428 _depot_chunk_handlers,
00429 _order_chunk_handlers,
00430 _industry_chunk_handlers,
00431 _economy_chunk_handlers,
00432 _subsidy_chunk_handlers,
00433 _goal_chunk_handlers,
00434 _engine_chunk_handlers,
00435 _town_chunk_handlers,
00436 _sign_chunk_handlers,
00437 _station_chunk_handlers,
00438 _company_chunk_handlers,
00439 _ai_chunk_handlers,
00440 _game_chunk_handlers,
00441 _animated_tile_chunk_handlers,
00442 _newgrf_chunk_handlers,
00443 _group_chunk_handlers,
00444 _cargopacket_chunk_handlers,
00445 _autoreplace_chunk_handlers,
00446 _labelmaps_chunk_handlers,
00447 _airport_chunk_handlers,
00448 _object_chunk_handlers,
00449 _persistent_storage_chunk_handlers,
00450 NULL,
00451 };
00452
00457 #define FOR_ALL_CHUNK_HANDLERS(ch) \
00458 for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \
00459 for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1)
00460
00462 static void SlNullPointers()
00463 {
00464 _sl.action = SLA_NULL;
00465
00466
00467
00468
00469 _sl_version = SAVEGAME_VERSION;
00470
00471 DEBUG(sl, 1, "Nulling pointers");
00472
00473 FOR_ALL_CHUNK_HANDLERS(ch) {
00474 if (ch->ptrs_proc != NULL) {
00475 DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00476 ch->ptrs_proc();
00477 }
00478 }
00479
00480 DEBUG(sl, 1, "All pointers nulled");
00481
00482 assert(_sl.action == SLA_NULL);
00483 }
00484
00493 void NORETURN SlError(StringID string, const char *extra_msg)
00494 {
00495
00496 if (_sl.action == SLA_LOAD_CHECK) {
00497 _load_check_data.error = string;
00498 free(_load_check_data.error_data);
00499 _load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00500 } else {
00501 _sl.error_str = string;
00502 free(_sl.extra_msg);
00503 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00504 }
00505
00506
00507
00508
00509
00510 if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00511 throw std::exception();
00512 }
00513
00521 void NORETURN SlErrorCorrupt(const char *msg)
00522 {
00523 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00524 }
00525
00526
00527 typedef void (*AsyncSaveFinishProc)();
00528 static AsyncSaveFinishProc _async_save_finish = NULL;
00529 static ThreadObject *_save_thread;
00530
00535 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00536 {
00537 if (_exit_game) return;
00538 while (_async_save_finish != NULL) CSleep(10);
00539
00540 _async_save_finish = proc;
00541 }
00542
00546 void ProcessAsyncSaveFinish()
00547 {
00548 if (_async_save_finish == NULL) return;
00549
00550 _async_save_finish();
00551
00552 _async_save_finish = NULL;
00553
00554 if (_save_thread != NULL) {
00555 _save_thread->Join();
00556 delete _save_thread;
00557 _save_thread = NULL;
00558 }
00559 }
00560
00565 byte SlReadByte()
00566 {
00567 return _sl.reader->ReadByte();
00568 }
00569
00574 void SlWriteByte(byte b)
00575 {
00576 _sl.dumper->WriteByte(b);
00577 }
00578
00579 static inline int SlReadUint16()
00580 {
00581 int x = SlReadByte() << 8;
00582 return x | SlReadByte();
00583 }
00584
00585 static inline uint32 SlReadUint32()
00586 {
00587 uint32 x = SlReadUint16() << 16;
00588 return x | SlReadUint16();
00589 }
00590
00591 static inline uint64 SlReadUint64()
00592 {
00593 uint32 x = SlReadUint32();
00594 uint32 y = SlReadUint32();
00595 return (uint64)x << 32 | y;
00596 }
00597
00598 static inline void SlWriteUint16(uint16 v)
00599 {
00600 SlWriteByte(GB(v, 8, 8));
00601 SlWriteByte(GB(v, 0, 8));
00602 }
00603
00604 static inline void SlWriteUint32(uint32 v)
00605 {
00606 SlWriteUint16(GB(v, 16, 16));
00607 SlWriteUint16(GB(v, 0, 16));
00608 }
00609
00610 static inline void SlWriteUint64(uint64 x)
00611 {
00612 SlWriteUint32((uint32)(x >> 32));
00613 SlWriteUint32((uint32)x);
00614 }
00615
00621 static inline void SlSkipBytes(size_t length)
00622 {
00623 for (; length != 0; length--) SlReadByte();
00624 }
00625
00635 static uint SlReadSimpleGamma()
00636 {
00637 uint i = SlReadByte();
00638 if (HasBit(i, 7)) {
00639 i &= ~0x80;
00640 if (HasBit(i, 6)) {
00641 i &= ~0x40;
00642 if (HasBit(i, 5)) {
00643 i &= ~0x20;
00644 if (HasBit(i, 4)) {
00645 SlErrorCorrupt("Unsupported gamma");
00646 }
00647 i = (i << 8) | SlReadByte();
00648 }
00649 i = (i << 8) | SlReadByte();
00650 }
00651 i = (i << 8) | SlReadByte();
00652 }
00653 return i;
00654 }
00655
00668 static void SlWriteSimpleGamma(size_t i)
00669 {
00670 if (i >= (1 << 7)) {
00671 if (i >= (1 << 14)) {
00672 if (i >= (1 << 21)) {
00673 assert(i < (1 << 28));
00674 SlWriteByte((byte)(0xE0 | (i >> 24)));
00675 SlWriteByte((byte)(i >> 16));
00676 } else {
00677 SlWriteByte((byte)(0xC0 | (i >> 16)));
00678 }
00679 SlWriteByte((byte)(i >> 8));
00680 } else {
00681 SlWriteByte((byte)(0x80 | (i >> 8)));
00682 }
00683 }
00684 SlWriteByte((byte)i);
00685 }
00686
00688 static inline uint SlGetGammaLength(size_t i)
00689 {
00690 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00691 }
00692
00693 static inline uint SlReadSparseIndex()
00694 {
00695 return SlReadSimpleGamma();
00696 }
00697
00698 static inline void SlWriteSparseIndex(uint index)
00699 {
00700 SlWriteSimpleGamma(index);
00701 }
00702
00703 static inline uint SlReadArrayLength()
00704 {
00705 return SlReadSimpleGamma();
00706 }
00707
00708 static inline void SlWriteArrayLength(size_t length)
00709 {
00710 SlWriteSimpleGamma(length);
00711 }
00712
00713 static inline uint SlGetArrayLength(size_t length)
00714 {
00715 return SlGetGammaLength(length);
00716 }
00717
00724 static inline uint SlCalcConvMemLen(VarType conv)
00725 {
00726 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00727 byte length = GB(conv, 4, 4);
00728
00729 switch (length << 4) {
00730 case SLE_VAR_STRB:
00731 case SLE_VAR_STRBQ:
00732 case SLE_VAR_STR:
00733 case SLE_VAR_STRQ:
00734 return SlReadArrayLength();
00735
00736 default:
00737 assert(length < lengthof(conv_mem_size));
00738 return conv_mem_size[length];
00739 }
00740 }
00741
00748 static inline byte SlCalcConvFileLen(VarType conv)
00749 {
00750 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00751 byte length = GB(conv, 0, 4);
00752 assert(length < lengthof(conv_file_size));
00753 return conv_file_size[length];
00754 }
00755
00757 static inline size_t SlCalcRefLen()
00758 {
00759 return IsSavegameVersionBefore(69) ? 2 : 4;
00760 }
00761
00762 void SlSetArrayIndex(uint index)
00763 {
00764 _sl.need_length = NL_WANTLENGTH;
00765 _sl.array_index = index;
00766 }
00767
00768 static size_t _next_offs;
00769
00774 int SlIterateArray()
00775 {
00776 int index;
00777
00778
00779
00780 if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00781
00782 for (;;) {
00783 uint length = SlReadArrayLength();
00784 if (length == 0) {
00785 _next_offs = 0;
00786 return -1;
00787 }
00788
00789 _sl.obj_len = --length;
00790 _next_offs = _sl.reader->GetSize() + length;
00791
00792 switch (_sl.block_mode) {
00793 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00794 case CH_ARRAY: index = _sl.array_index++; break;
00795 default:
00796 DEBUG(sl, 0, "SlIterateArray error");
00797 return -1;
00798 }
00799
00800 if (length != 0) return index;
00801 }
00802 }
00803
00807 void SlSkipArray()
00808 {
00809 while (SlIterateArray() != -1) {
00810 SlSkipBytes(_next_offs - _sl.reader->GetSize());
00811 }
00812 }
00813
00819 void SlSetLength(size_t length)
00820 {
00821 assert(_sl.action == SLA_SAVE);
00822
00823 switch (_sl.need_length) {
00824 case NL_WANTLENGTH:
00825 _sl.need_length = NL_NONE;
00826 switch (_sl.block_mode) {
00827 case CH_RIFF:
00828
00829
00830
00831 assert(length < (1 << 28));
00832 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00833 break;
00834 case CH_ARRAY:
00835 assert(_sl.last_array_index <= _sl.array_index);
00836 while (++_sl.last_array_index <= _sl.array_index) {
00837 SlWriteArrayLength(1);
00838 }
00839 SlWriteArrayLength(length + 1);
00840 break;
00841 case CH_SPARSE_ARRAY:
00842 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00843 SlWriteSparseIndex(_sl.array_index);
00844 break;
00845 default: NOT_REACHED();
00846 }
00847 break;
00848
00849 case NL_CALCLENGTH:
00850 _sl.obj_len += (int)length;
00851 break;
00852
00853 default: NOT_REACHED();
00854 }
00855 }
00856
00863 static void SlCopyBytes(void *ptr, size_t length)
00864 {
00865 byte *p = (byte *)ptr;
00866
00867 switch (_sl.action) {
00868 case SLA_LOAD_CHECK:
00869 case SLA_LOAD:
00870 for (; length != 0; length--) *p++ = SlReadByte();
00871 break;
00872 case SLA_SAVE:
00873 for (; length != 0; length--) SlWriteByte(*p++);
00874 break;
00875 default: NOT_REACHED();
00876 }
00877 }
00878
00880 size_t SlGetFieldLength()
00881 {
00882 return _sl.obj_len;
00883 }
00884
00892 int64 ReadValue(const void *ptr, VarType conv)
00893 {
00894 switch (GetVarMemType(conv)) {
00895 case SLE_VAR_BL: return (*(const bool *)ptr != 0);
00896 case SLE_VAR_I8: return *(const int8 *)ptr;
00897 case SLE_VAR_U8: return *(const byte *)ptr;
00898 case SLE_VAR_I16: return *(const int16 *)ptr;
00899 case SLE_VAR_U16: return *(const uint16*)ptr;
00900 case SLE_VAR_I32: return *(const int32 *)ptr;
00901 case SLE_VAR_U32: return *(const uint32*)ptr;
00902 case SLE_VAR_I64: return *(const int64 *)ptr;
00903 case SLE_VAR_U64: return *(const uint64*)ptr;
00904 case SLE_VAR_NULL:return 0;
00905 default: NOT_REACHED();
00906 }
00907 }
00908
00916 void WriteValue(void *ptr, VarType conv, int64 val)
00917 {
00918 switch (GetVarMemType(conv)) {
00919 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00920 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00921 case SLE_VAR_U8: *(byte *)ptr = val; break;
00922 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00923 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00924 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00925 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00926 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00927 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00928 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00929 case SLE_VAR_NULL: break;
00930 default: NOT_REACHED();
00931 }
00932 }
00933
00942 static void SlSaveLoadConv(void *ptr, VarType conv)
00943 {
00944 switch (_sl.action) {
00945 case SLA_SAVE: {
00946 int64 x = ReadValue(ptr, conv);
00947
00948
00949 switch (GetVarFileType(conv)) {
00950 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00951 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00952 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00953 case SLE_FILE_STRINGID:
00954 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00955 case SLE_FILE_I32:
00956 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00957 case SLE_FILE_I64:
00958 case SLE_FILE_U64: SlWriteUint64(x);break;
00959 default: NOT_REACHED();
00960 }
00961 break;
00962 }
00963 case SLA_LOAD_CHECK:
00964 case SLA_LOAD: {
00965 int64 x;
00966
00967 switch (GetVarFileType(conv)) {
00968 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00969 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00970 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00971 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00972 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00973 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00974 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00975 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00976 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00977 default: NOT_REACHED();
00978 }
00979
00980
00981 WriteValue(ptr, conv, x);
00982 break;
00983 }
00984 case SLA_PTRS: break;
00985 case SLA_NULL: break;
00986 default: NOT_REACHED();
00987 }
00988 }
00989
00999 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
01000 {
01001 if (ptr == NULL) return 0;
01002 return min(strlen(ptr), length - 1);
01003 }
01004
01014 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
01015 {
01016 size_t len;
01017 const char *str;
01018
01019 switch (GetVarMemType(conv)) {
01020 default: NOT_REACHED();
01021 case SLE_VAR_STR:
01022 case SLE_VAR_STRQ:
01023 str = *(const char * const *)ptr;
01024 len = SIZE_MAX;
01025 break;
01026 case SLE_VAR_STRB:
01027 case SLE_VAR_STRBQ:
01028 str = (const char *)ptr;
01029 len = length;
01030 break;
01031 }
01032
01033 len = SlCalcNetStringLen(str, len);
01034 return len + SlGetArrayLength(len);
01035 }
01036
01043 static void SlString(void *ptr, size_t length, VarType conv)
01044 {
01045 switch (_sl.action) {
01046 case SLA_SAVE: {
01047 size_t len;
01048 switch (GetVarMemType(conv)) {
01049 default: NOT_REACHED();
01050 case SLE_VAR_STRB:
01051 case SLE_VAR_STRBQ:
01052 len = SlCalcNetStringLen((char *)ptr, length);
01053 break;
01054 case SLE_VAR_STR:
01055 case SLE_VAR_STRQ:
01056 ptr = *(char **)ptr;
01057 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01058 break;
01059 }
01060
01061 SlWriteArrayLength(len);
01062 SlCopyBytes(ptr, len);
01063 break;
01064 }
01065 case SLA_LOAD_CHECK:
01066 case SLA_LOAD: {
01067 size_t len = SlReadArrayLength();
01068
01069 switch (GetVarMemType(conv)) {
01070 default: NOT_REACHED();
01071 case SLE_VAR_STRB:
01072 case SLE_VAR_STRBQ:
01073 if (len >= length) {
01074 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01075 SlCopyBytes(ptr, length);
01076 SlSkipBytes(len - length);
01077 len = length - 1;
01078 } else {
01079 SlCopyBytes(ptr, len);
01080 }
01081 break;
01082 case SLE_VAR_STR:
01083 case SLE_VAR_STRQ:
01084 free(*(char **)ptr);
01085 if (len == 0) {
01086 *(char **)ptr = NULL;
01087 } else {
01088 *(char **)ptr = MallocT<char>(len + 1);
01089 ptr = *(char **)ptr;
01090 SlCopyBytes(ptr, len);
01091 }
01092 break;
01093 }
01094
01095 ((char *)ptr)[len] = '\0';
01096 StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
01097 if ((conv & SLF_ALLOW_CONTROL) != 0) {
01098 settings = settings | SVS_ALLOW_CONTROL_CODE;
01099 }
01100 if ((conv & SLF_ALLOW_NEWLINE) != 0) {
01101 settings = settings | SVS_ALLOW_NEWLINE;
01102 }
01103 str_validate((char *)ptr, (char *)ptr + len, settings);
01104 break;
01105 }
01106 case SLA_PTRS: break;
01107 case SLA_NULL: break;
01108 default: NOT_REACHED();
01109 }
01110 }
01111
01117 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01118 {
01119 return SlCalcConvFileLen(conv) * length;
01120 }
01121
01128 void SlArray(void *array, size_t length, VarType conv)
01129 {
01130 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01131
01132
01133 if (_sl.need_length != NL_NONE) {
01134 SlSetLength(SlCalcArrayLen(length, conv));
01135
01136 if (_sl.need_length == NL_CALCLENGTH) return;
01137 }
01138
01139
01140
01141 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01142
01143 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01144 conv == SLE_INT32 || conv == SLE_UINT32) {
01145 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01146 return;
01147 }
01148
01149 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01150 for (uint i = 0; i < length; i++) {
01151 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01152 }
01153 return;
01154 }
01155 }
01156
01157
01158
01159 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01160 SlCopyBytes(array, length);
01161 } else {
01162 byte *a = (byte*)array;
01163 byte mem_size = SlCalcConvMemLen(conv);
01164
01165 for (; length != 0; length --) {
01166 SlSaveLoadConv(a, conv);
01167 a += mem_size;
01168 }
01169 }
01170 }
01171
01172
01183 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01184 {
01185 assert(_sl.action == SLA_SAVE);
01186
01187 if (obj == NULL) return 0;
01188
01189 switch (rt) {
01190 case REF_VEHICLE_OLD:
01191 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01192 case REF_STATION: return ((const Station*)obj)->index + 1;
01193 case REF_TOWN: return ((const Town*)obj)->index + 1;
01194 case REF_ORDER: return ((const Order*)obj)->index + 1;
01195 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01196 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01197 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01198 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01199 case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
01200 default: NOT_REACHED();
01201 }
01202 }
01203
01214 static void *IntToReference(size_t index, SLRefType rt)
01215 {
01216 assert_compile(sizeof(size_t) <= sizeof(void *));
01217
01218 assert(_sl.action == SLA_PTRS);
01219
01220
01221
01222 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01223 rt = REF_VEHICLE;
01224 }
01225
01226
01227 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01228
01229
01230
01231 if (rt != REF_VEHICLE_OLD) index--;
01232
01233 switch (rt) {
01234 case REF_ORDERLIST:
01235 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01236 SlErrorCorrupt("Referencing invalid OrderList");
01237
01238 case REF_ORDER:
01239 if (Order::IsValidID(index)) return Order::Get(index);
01240
01241 if (IsSavegameVersionBefore(5, 2)) return NULL;
01242 SlErrorCorrupt("Referencing invalid Order");
01243
01244 case REF_VEHICLE_OLD:
01245 case REF_VEHICLE:
01246 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01247 SlErrorCorrupt("Referencing invalid Vehicle");
01248
01249 case REF_STATION:
01250 if (Station::IsValidID(index)) return Station::Get(index);
01251 SlErrorCorrupt("Referencing invalid Station");
01252
01253 case REF_TOWN:
01254 if (Town::IsValidID(index)) return Town::Get(index);
01255 SlErrorCorrupt("Referencing invalid Town");
01256
01257 case REF_ROADSTOPS:
01258 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01259 SlErrorCorrupt("Referencing invalid RoadStop");
01260
01261 case REF_ENGINE_RENEWS:
01262 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01263 SlErrorCorrupt("Referencing invalid EngineRenew");
01264
01265 case REF_CARGO_PACKET:
01266 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01267 SlErrorCorrupt("Referencing invalid CargoPacket");
01268
01269 case REF_STORAGE:
01270 if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index);
01271 SlErrorCorrupt("Referencing invalid PersistentStorage");
01272
01273 default: NOT_REACHED();
01274 }
01275 }
01276
01281 static inline size_t SlCalcListLen(const void *list)
01282 {
01283 const std::list<void *> *l = (const std::list<void *> *) list;
01284
01285 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01286
01287
01288 return l->size() * type_size + type_size;
01289 }
01290
01291
01297 static void SlList(void *list, SLRefType conv)
01298 {
01299
01300 if (_sl.need_length != NL_NONE) {
01301 SlSetLength(SlCalcListLen(list));
01302
01303 if (_sl.need_length == NL_CALCLENGTH) return;
01304 }
01305
01306 typedef std::list<void *> PtrList;
01307 PtrList *l = (PtrList *)list;
01308
01309 switch (_sl.action) {
01310 case SLA_SAVE: {
01311 SlWriteUint32((uint32)l->size());
01312
01313 PtrList::iterator iter;
01314 for (iter = l->begin(); iter != l->end(); ++iter) {
01315 void *ptr = *iter;
01316 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01317 }
01318 break;
01319 }
01320 case SLA_LOAD_CHECK:
01321 case SLA_LOAD: {
01322 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01323
01324
01325 for (size_t i = 0; i < length; i++) {
01326 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01327 l->push_back((void *)data);
01328 }
01329 break;
01330 }
01331 case SLA_PTRS: {
01332 PtrList temp = *l;
01333
01334 l->clear();
01335 PtrList::iterator iter;
01336 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01337 void *ptr = IntToReference((size_t)*iter, conv);
01338 l->push_back(ptr);
01339 }
01340 break;
01341 }
01342 case SLA_NULL:
01343 l->clear();
01344 break;
01345 default: NOT_REACHED();
01346 }
01347 }
01348
01349
01351 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01352 {
01353 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01354 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01355
01356 return true;
01357 }
01358
01364 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01365 {
01366 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01367 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01368 return true;
01369 }
01370
01371 return false;
01372 }
01373
01380 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01381 {
01382 size_t length = 0;
01383
01384
01385 for (; sld->cmd != SL_END; sld++) {
01386 length += SlCalcObjMemberLength(object, sld);
01387 }
01388 return length;
01389 }
01390
01391 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01392 {
01393 assert(_sl.action == SLA_SAVE);
01394
01395 switch (sld->cmd) {
01396 case SL_VAR:
01397 case SL_REF:
01398 case SL_ARR:
01399 case SL_STR:
01400 case SL_LST:
01401
01402 if (!SlIsObjectValidInSavegame(sld)) break;
01403
01404 switch (sld->cmd) {
01405 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01406 case SL_REF: return SlCalcRefLen();
01407 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01408 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01409 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01410 default: NOT_REACHED();
01411 }
01412 break;
01413 case SL_WRITEBYTE: return 1;
01414 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01415 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01416 default: NOT_REACHED();
01417 }
01418 return 0;
01419 }
01420
01421
01422 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01423 {
01424 VarType conv = GB(sld->conv, 0, 8);
01425 switch (sld->cmd) {
01426 case SL_VAR:
01427 case SL_REF:
01428 case SL_ARR:
01429 case SL_STR:
01430 case SL_LST:
01431
01432 if (!SlIsObjectValidInSavegame(sld)) return false;
01433 if (SlSkipVariableOnLoad(sld)) return false;
01434
01435 switch (sld->cmd) {
01436 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01437 case SL_REF:
01438 switch (_sl.action) {
01439 case SLA_SAVE:
01440 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01441 break;
01442 case SLA_LOAD_CHECK:
01443 case SLA_LOAD:
01444 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01445 break;
01446 case SLA_PTRS:
01447 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01448 break;
01449 case SLA_NULL:
01450 *(void **)ptr = NULL;
01451 break;
01452 default: NOT_REACHED();
01453 }
01454 break;
01455 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01456 case SL_STR: SlString(ptr, sld->length, sld->conv); break;
01457 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01458 default: NOT_REACHED();
01459 }
01460 break;
01461
01462
01463
01464
01465
01466
01467 case SL_WRITEBYTE:
01468 switch (_sl.action) {
01469 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01470 case SLA_LOAD_CHECK:
01471 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01472 case SLA_PTRS: break;
01473 case SLA_NULL: break;
01474 default: NOT_REACHED();
01475 }
01476 break;
01477
01478
01479 case SL_VEH_INCLUDE:
01480 SlObject(ptr, GetVehicleDescription(VEH_END));
01481 break;
01482
01483 case SL_ST_INCLUDE:
01484 SlObject(ptr, GetBaseStationDescription());
01485 break;
01486
01487 default: NOT_REACHED();
01488 }
01489 return true;
01490 }
01491
01497 void SlObject(void *object, const SaveLoad *sld)
01498 {
01499
01500 if (_sl.need_length != NL_NONE) {
01501 SlSetLength(SlCalcObjLength(object, sld));
01502 if (_sl.need_length == NL_CALCLENGTH) return;
01503 }
01504
01505 for (; sld->cmd != SL_END; sld++) {
01506 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01507 SlObjectMember(ptr, sld);
01508 }
01509 }
01510
01515 void SlGlobList(const SaveLoadGlobVarList *sldg)
01516 {
01517 SlObject(NULL, (const SaveLoad*)sldg);
01518 }
01519
01525 void SlAutolength(AutolengthProc *proc, void *arg)
01526 {
01527 size_t offs;
01528
01529 assert(_sl.action == SLA_SAVE);
01530
01531
01532 _sl.need_length = NL_CALCLENGTH;
01533 _sl.obj_len = 0;
01534 proc(arg);
01535
01536
01537 _sl.need_length = NL_WANTLENGTH;
01538 SlSetLength(_sl.obj_len);
01539
01540 offs = _sl.dumper->GetSize() + _sl.obj_len;
01541
01542
01543 proc(arg);
01544
01545 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01546 }
01547
01552 static void SlLoadChunk(const ChunkHandler *ch)
01553 {
01554 byte m = SlReadByte();
01555 size_t len;
01556 size_t endoffs;
01557
01558 _sl.block_mode = m;
01559 _sl.obj_len = 0;
01560
01561 switch (m) {
01562 case CH_ARRAY:
01563 _sl.array_index = 0;
01564 ch->load_proc();
01565 break;
01566 case CH_SPARSE_ARRAY:
01567 ch->load_proc();
01568 break;
01569 default:
01570 if ((m & 0xF) == CH_RIFF) {
01571
01572 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01573 len += SlReadUint16();
01574 _sl.obj_len = len;
01575 endoffs = _sl.reader->GetSize() + len;
01576 ch->load_proc();
01577 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01578 } else {
01579 SlErrorCorrupt("Invalid chunk type");
01580 }
01581 break;
01582 }
01583 }
01584
01590 static void SlLoadCheckChunk(const ChunkHandler *ch)
01591 {
01592 byte m = SlReadByte();
01593 size_t len;
01594 size_t endoffs;
01595
01596 _sl.block_mode = m;
01597 _sl.obj_len = 0;
01598
01599 switch (m) {
01600 case CH_ARRAY:
01601 _sl.array_index = 0;
01602 if (ch->load_check_proc) {
01603 ch->load_check_proc();
01604 } else {
01605 SlSkipArray();
01606 }
01607 break;
01608 case CH_SPARSE_ARRAY:
01609 if (ch->load_check_proc) {
01610 ch->load_check_proc();
01611 } else {
01612 SlSkipArray();
01613 }
01614 break;
01615 default:
01616 if ((m & 0xF) == CH_RIFF) {
01617
01618 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01619 len += SlReadUint16();
01620 _sl.obj_len = len;
01621 endoffs = _sl.reader->GetSize() + len;
01622 if (ch->load_check_proc) {
01623 ch->load_check_proc();
01624 } else {
01625 SlSkipBytes(len);
01626 }
01627 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01628 } else {
01629 SlErrorCorrupt("Invalid chunk type");
01630 }
01631 break;
01632 }
01633 }
01634
01639 static ChunkSaveLoadProc *_stub_save_proc;
01640
01646 static inline void SlStubSaveProc2(void *arg)
01647 {
01648 _stub_save_proc();
01649 }
01650
01656 static void SlStubSaveProc()
01657 {
01658 SlAutolength(SlStubSaveProc2, NULL);
01659 }
01660
01666 static void SlSaveChunk(const ChunkHandler *ch)
01667 {
01668 ChunkSaveLoadProc *proc = ch->save_proc;
01669
01670
01671 if (proc == NULL) return;
01672
01673 SlWriteUint32(ch->id);
01674 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01675
01676 if (ch->flags & CH_AUTO_LENGTH) {
01677
01678 _stub_save_proc = proc;
01679 proc = SlStubSaveProc;
01680 }
01681
01682 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01683 switch (ch->flags & CH_TYPE_MASK) {
01684 case CH_RIFF:
01685 _sl.need_length = NL_WANTLENGTH;
01686 proc();
01687 break;
01688 case CH_ARRAY:
01689 _sl.last_array_index = 0;
01690 SlWriteByte(CH_ARRAY);
01691 proc();
01692 SlWriteArrayLength(0);
01693 break;
01694 case CH_SPARSE_ARRAY:
01695 SlWriteByte(CH_SPARSE_ARRAY);
01696 proc();
01697 SlWriteArrayLength(0);
01698 break;
01699 default: NOT_REACHED();
01700 }
01701 }
01702
01704 static void SlSaveChunks()
01705 {
01706 FOR_ALL_CHUNK_HANDLERS(ch) {
01707 SlSaveChunk(ch);
01708 }
01709
01710
01711 SlWriteUint32(0);
01712 }
01713
01720 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01721 {
01722 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01723 return NULL;
01724 }
01725
01727 static void SlLoadChunks()
01728 {
01729 uint32 id;
01730 const ChunkHandler *ch;
01731
01732 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01733 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01734
01735 ch = SlFindChunkHandler(id);
01736 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01737 SlLoadChunk(ch);
01738 }
01739 }
01740
01742 static void SlLoadCheckChunks()
01743 {
01744 uint32 id;
01745 const ChunkHandler *ch;
01746
01747 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01748 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01749
01750 ch = SlFindChunkHandler(id);
01751 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01752 SlLoadCheckChunk(ch);
01753 }
01754 }
01755
01757 static void SlFixPointers()
01758 {
01759 _sl.action = SLA_PTRS;
01760
01761 DEBUG(sl, 1, "Fixing pointers");
01762
01763 FOR_ALL_CHUNK_HANDLERS(ch) {
01764 if (ch->ptrs_proc != NULL) {
01765 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01766 ch->ptrs_proc();
01767 }
01768 }
01769
01770 DEBUG(sl, 1, "All pointers fixed");
01771
01772 assert(_sl.action == SLA_PTRS);
01773 }
01774
01775
01777 struct FileReader : LoadFilter {
01778 FILE *file;
01779 long begin;
01780
01785 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01786 {
01787 }
01788
01790 ~FileReader()
01791 {
01792 if (this->file != NULL) fclose(this->file);
01793 this->file = NULL;
01794
01795
01796 _sl.sf = NULL;
01797 }
01798
01799 size_t Read(byte *buf, size_t size)
01800 {
01801
01802 if (this->file == NULL) return 0;
01803
01804 return fread(buf, 1, size, this->file);
01805 }
01806
01807 void Reset()
01808 {
01809 clearerr(this->file);
01810 fseek(this->file, this->begin, SEEK_SET);
01811 }
01812 };
01813
01815 struct FileWriter : SaveFilter {
01816 FILE *file;
01817
01822 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01823 {
01824 }
01825
01827 ~FileWriter()
01828 {
01829 this->Finish();
01830
01831
01832 _sl.sf = NULL;
01833 }
01834
01835 void Write(byte *buf, size_t size)
01836 {
01837
01838 if (this->file == NULL) return;
01839
01840 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01841 }
01842
01843 void Finish()
01844 {
01845 if (this->file != NULL) fclose(this->file);
01846 this->file = NULL;
01847 }
01848 };
01849
01850
01851
01852
01853
01854 #ifdef WITH_LZO
01855 #include <lzo/lzo1x.h>
01856
01858 static const uint LZO_BUFFER_SIZE = 8192;
01859
01861 struct LZOLoadFilter : LoadFilter {
01866 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01867 {
01868 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01869 }
01870
01871 size_t Read(byte *buf, size_t ssize)
01872 {
01873 assert(ssize >= LZO_BUFFER_SIZE);
01874
01875
01876 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01877 uint32 tmp[2];
01878 uint32 size;
01879 lzo_uint len;
01880
01881
01882 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01883
01884
01885 ((uint32*)out)[0] = size = tmp[1];
01886
01887 if (_sl_version != 0) {
01888 tmp[0] = TO_BE32(tmp[0]);
01889 size = TO_BE32(size);
01890 }
01891
01892 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01893
01894
01895 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01896
01897
01898 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01899
01900
01901 lzo1x_decompress(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01902 return len;
01903 }
01904 };
01905
01907 struct LZOSaveFilter : SaveFilter {
01913 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01914 {
01915 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01916 }
01917
01918 void Write(byte *buf, size_t size)
01919 {
01920 const lzo_bytep in = buf;
01921
01922 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01923 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01924 lzo_uint outlen;
01925
01926 do {
01927
01928 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01929 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01930 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01931 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01932 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01933
01934
01935 size -= len;
01936 in += len;
01937 } while (size > 0);
01938 }
01939 };
01940
01941 #endif
01942
01943
01944
01945
01946
01948 struct NoCompLoadFilter : LoadFilter {
01953 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01954 {
01955 }
01956
01957 size_t Read(byte *buf, size_t size)
01958 {
01959 return this->chain->Read(buf, size);
01960 }
01961 };
01962
01964 struct NoCompSaveFilter : SaveFilter {
01970 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01971 {
01972 }
01973
01974 void Write(byte *buf, size_t size)
01975 {
01976 this->chain->Write(buf, size);
01977 }
01978 };
01979
01980
01981
01982
01983
01984 #if defined(WITH_ZLIB)
01985 #include <zlib.h>
01986
01988 struct ZlibLoadFilter : LoadFilter {
01989 z_stream z;
01990 byte fread_buf[MEMORY_CHUNK_SIZE];
01991
01996 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01997 {
01998 memset(&this->z, 0, sizeof(this->z));
01999 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02000 }
02001
02003 ~ZlibLoadFilter()
02004 {
02005 inflateEnd(&this->z);
02006 }
02007
02008 size_t Read(byte *buf, size_t size)
02009 {
02010 this->z.next_out = buf;
02011 this->z.avail_out = (uint)size;
02012
02013 do {
02014
02015 if (this->z.avail_in == 0) {
02016 this->z.next_in = this->fread_buf;
02017 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02018 }
02019
02020
02021 int r = inflate(&this->z, 0);
02022 if (r == Z_STREAM_END) break;
02023
02024 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02025 } while (this->z.avail_out != 0);
02026
02027 return size - this->z.avail_out;
02028 }
02029 };
02030
02032 struct ZlibSaveFilter : SaveFilter {
02033 z_stream z;
02034
02040 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02041 {
02042 memset(&this->z, 0, sizeof(this->z));
02043 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02044 }
02045
02047 ~ZlibSaveFilter()
02048 {
02049 deflateEnd(&this->z);
02050 }
02051
02058 void WriteLoop(byte *p, size_t len, int mode)
02059 {
02060 byte buf[MEMORY_CHUNK_SIZE];
02061 uint n;
02062 this->z.next_in = p;
02063 this->z.avail_in = (uInt)len;
02064 do {
02065 this->z.next_out = buf;
02066 this->z.avail_out = sizeof(buf);
02067
02075 int r = deflate(&this->z, mode);
02076
02077
02078 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02079 this->chain->Write(buf, n);
02080 }
02081 if (r == Z_STREAM_END) break;
02082
02083 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02084 } while (this->z.avail_in || !this->z.avail_out);
02085 }
02086
02087 void Write(byte *buf, size_t size)
02088 {
02089 this->WriteLoop(buf, size, 0);
02090 }
02091
02092 void Finish()
02093 {
02094 this->WriteLoop(NULL, 0, Z_FINISH);
02095 this->chain->Finish();
02096 }
02097 };
02098
02099 #endif
02100
02101
02102
02103
02104
02105 #if defined(WITH_LZMA)
02106 #include <lzma.h>
02107
02114 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02115
02117 struct LZMALoadFilter : LoadFilter {
02118 lzma_stream lzma;
02119 byte fread_buf[MEMORY_CHUNK_SIZE];
02120
02125 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02126 {
02127
02128 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02129 }
02130
02132 ~LZMALoadFilter()
02133 {
02134 lzma_end(&this->lzma);
02135 }
02136
02137 size_t Read(byte *buf, size_t size)
02138 {
02139 this->lzma.next_out = buf;
02140 this->lzma.avail_out = size;
02141
02142 do {
02143
02144 if (this->lzma.avail_in == 0) {
02145 this->lzma.next_in = this->fread_buf;
02146 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02147 }
02148
02149
02150 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02151 if (r == LZMA_STREAM_END) break;
02152 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02153 } while (this->lzma.avail_out != 0);
02154
02155 return size - this->lzma.avail_out;
02156 }
02157 };
02158
02160 struct LZMASaveFilter : SaveFilter {
02161 lzma_stream lzma;
02162
02168 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02169 {
02170 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02171 }
02172
02174 ~LZMASaveFilter()
02175 {
02176 lzma_end(&this->lzma);
02177 }
02178
02185 void WriteLoop(byte *p, size_t len, lzma_action action)
02186 {
02187 byte buf[MEMORY_CHUNK_SIZE];
02188 size_t n;
02189 this->lzma.next_in = p;
02190 this->lzma.avail_in = len;
02191 do {
02192 this->lzma.next_out = buf;
02193 this->lzma.avail_out = sizeof(buf);
02194
02195 lzma_ret r = lzma_code(&this->lzma, action);
02196
02197
02198 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02199 this->chain->Write(buf, n);
02200 }
02201 if (r == LZMA_STREAM_END) break;
02202 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02203 } while (this->lzma.avail_in || !this->lzma.avail_out);
02204 }
02205
02206 void Write(byte *buf, size_t size)
02207 {
02208 this->WriteLoop(buf, size, LZMA_RUN);
02209 }
02210
02211 void Finish()
02212 {
02213 this->WriteLoop(NULL, 0, LZMA_FINISH);
02214 this->chain->Finish();
02215 }
02216 };
02217
02218 #endif
02219
02220
02221
02222
02223
02225 struct SaveLoadFormat {
02226 const char *name;
02227 uint32 tag;
02228
02229 LoadFilter *(*init_load)(LoadFilter *chain);
02230 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02231
02232 byte min_compression;
02233 byte default_compression;
02234 byte max_compression;
02235 };
02236
02238 static const SaveLoadFormat _saveload_formats[] = {
02239 #if defined(WITH_LZO)
02240
02241 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02242 #else
02243 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02244 #endif
02245
02246 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02247 #if defined(WITH_ZLIB)
02248
02249
02250
02251 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02252 #else
02253 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02254 #endif
02255 #if defined(WITH_LZMA)
02256
02257
02258
02259
02260
02261 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02262 #else
02263 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02264 #endif
02265 };
02266
02274 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02275 {
02276 const SaveLoadFormat *def = lastof(_saveload_formats);
02277
02278
02279 while (!def->init_write) def--;
02280
02281 if (!StrEmpty(s)) {
02282
02283 char *complevel = strrchr(s, ':');
02284 if (complevel != NULL) *complevel = '\0';
02285
02286 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02287 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02288 *compression_level = slf->default_compression;
02289 if (complevel != NULL) {
02290
02291
02292
02293 *complevel = ':';
02294 complevel++;
02295
02296
02297 char *end;
02298 long level = strtol(complevel, &end, 10);
02299 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02300 SetDParamStr(0, complevel);
02301 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL);
02302 } else {
02303 *compression_level = level;
02304 }
02305 }
02306 return slf;
02307 }
02308 }
02309
02310 SetDParamStr(0, s);
02311 SetDParamStr(1, def->name);
02312 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL);
02313
02314
02315 if (complevel != NULL) *complevel = ':';
02316 }
02317 *compression_level = def->default_compression;
02318 return def;
02319 }
02320
02321
02322 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02323 extern bool AfterLoadGame();
02324 extern bool LoadOldSaveGame(const char *file);
02325
02329 static inline void ClearSaveLoadState()
02330 {
02331 delete _sl.dumper;
02332 _sl.dumper = NULL;
02333
02334 delete _sl.sf;
02335 _sl.sf = NULL;
02336
02337 delete _sl.reader;
02338 _sl.reader = NULL;
02339
02340 delete _sl.lf;
02341 _sl.lf = NULL;
02342 }
02343
02349 static void SaveFileStart()
02350 {
02351 _sl.ff_state = _fast_forward;
02352 _fast_forward = 0;
02353 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02354
02355 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02356 _sl.saveinprogress = true;
02357 }
02358
02360 static void SaveFileDone()
02361 {
02362 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02363 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02364
02365 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02366 _sl.saveinprogress = false;
02367 }
02368
02370 void SetSaveLoadError(StringID str)
02371 {
02372 _sl.error_str = str;
02373 }
02374
02376 const char *GetSaveLoadErrorString()
02377 {
02378 SetDParam(0, _sl.error_str);
02379 SetDParamStr(1, _sl.extra_msg);
02380
02381 static char err_str[512];
02382 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02383 return err_str;
02384 }
02385
02387 static void SaveFileError()
02388 {
02389 SetDParamStr(0, GetSaveLoadErrorString());
02390 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02391 SaveFileDone();
02392 }
02393
02398 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02399 {
02400 try {
02401 byte compression;
02402 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02403
02404
02405 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02406 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02407
02408 _sl.sf = fmt->init_write(_sl.sf, compression);
02409 _sl.dumper->Flush(_sl.sf);
02410
02411 ClearSaveLoadState();
02412
02413 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02414
02415 return SL_OK;
02416 } catch (...) {
02417 ClearSaveLoadState();
02418
02419 AsyncSaveFinishProc asfp = SaveFileDone;
02420
02421
02422
02423 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02424
02425 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02426 asfp = SaveFileError;
02427 }
02428
02429 if (threaded) {
02430 SetAsyncSaveFinish(asfp);
02431 } else {
02432 asfp();
02433 }
02434 return SL_ERROR;
02435 }
02436 }
02437
02439 static void SaveFileToDiskThread(void *arg)
02440 {
02441 SaveFileToDisk(true);
02442 }
02443
02444 void WaitTillSaved()
02445 {
02446 if (_save_thread == NULL) return;
02447
02448 _save_thread->Join();
02449 delete _save_thread;
02450 _save_thread = NULL;
02451
02452
02453 ProcessAsyncSaveFinish();
02454 }
02455
02464 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02465 {
02466 assert(!_sl.saveinprogress);
02467
02468 _sl.dumper = new MemoryDumper();
02469 _sl.sf = writer;
02470
02471 _sl_version = SAVEGAME_VERSION;
02472
02473 SaveViewportBeforeSaveGame();
02474 SlSaveChunks();
02475
02476 SaveFileStart();
02477 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02478 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02479
02480 SaveOrLoadResult result = SaveFileToDisk(false);
02481 SaveFileDone();
02482
02483 return result;
02484 }
02485
02486 return SL_OK;
02487 }
02488
02495 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02496 {
02497 try {
02498 _sl.action = SLA_SAVE;
02499 return DoSave(writer, threaded);
02500 } catch (...) {
02501 ClearSaveLoadState();
02502 return SL_ERROR;
02503 }
02504 }
02505
02512 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02513 {
02514 _sl.lf = reader;
02515
02516 if (load_check) {
02517
02518 _load_check_data.Clear();
02519
02520 _load_check_data.checkable = true;
02521 }
02522
02523 uint32 hdr[2];
02524 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02525
02526
02527 const SaveLoadFormat *fmt = _saveload_formats;
02528 for (;;) {
02529
02530 if (fmt == endof(_saveload_formats)) {
02531 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02532 _sl.lf->Reset();
02533 _sl_version = 0;
02534 _sl_minor_version = 0;
02535
02536
02537 fmt = _saveload_formats;
02538 for (;;) {
02539 if (fmt == endof(_saveload_formats)) {
02540
02541 NOT_REACHED();
02542 }
02543 if (fmt->tag == TO_BE32X('OTTD')) break;
02544 fmt++;
02545 }
02546 break;
02547 }
02548
02549 if (fmt->tag == hdr[0]) {
02550
02551 _sl_version = TO_BE32(hdr[1]) >> 16;
02552
02553
02554
02555 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02556
02557 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02558
02559
02560 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02561 break;
02562 }
02563
02564 fmt++;
02565 }
02566
02567
02568 if (fmt->init_load == NULL) {
02569 char err_str[64];
02570 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02571 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02572 }
02573
02574 _sl.lf = fmt->init_load(_sl.lf);
02575 _sl.reader = new ReadBuffer(_sl.lf);
02576 _next_offs = 0;
02577
02578 if (!load_check) {
02579
02580
02581
02582 InitializeGame(256, 256, true, true);
02583
02584 GamelogReset();
02585
02586 if (IsSavegameVersionBefore(4)) {
02587
02588
02589
02590
02591
02592
02593
02594
02595
02596
02597
02598
02599
02600
02601
02602
02603
02604
02605
02606
02607
02608 ClearGRFConfigList(&_grfconfig);
02609 }
02610 }
02611
02612 if (load_check) {
02613
02614
02615 SlLoadCheckChunks();
02616 } else {
02617
02618 SlLoadChunks();
02619 SlFixPointers();
02620 }
02621
02622 ClearSaveLoadState();
02623
02624 _savegame_type = SGT_OTTD;
02625
02626 if (load_check) {
02627
02628 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02629 } else {
02630 GamelogStartAction(GLAT_LOAD);
02631
02632
02633
02634 if (!AfterLoadGame()) {
02635 GamelogStopAction();
02636 return SL_REINIT;
02637 }
02638
02639 GamelogStopAction();
02640 }
02641
02642 return SL_OK;
02643 }
02644
02650 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02651 {
02652 try {
02653 _sl.action = SLA_LOAD;
02654 return DoLoad(reader, false);
02655 } catch (...) {
02656 ClearSaveLoadState();
02657 return SL_REINIT;
02658 }
02659 }
02660
02670 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02671 {
02672
02673 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02674
02675 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02676 return SL_OK;
02677 }
02678 WaitTillSaved();
02679
02680
02681 if (mode == SL_OLD_LOAD) {
02682 InitializeGame(256, 256, true, true);
02683
02684
02685
02686
02687
02688 ClearGRFConfigList(&_grfconfig);
02689 GamelogReset();
02690 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02691 _sl_version = 0;
02692 _sl_minor_version = 0;
02693 GamelogStartAction(GLAT_LOAD);
02694 if (!AfterLoadGame()) {
02695 GamelogStopAction();
02696 return SL_REINIT;
02697 }
02698 GamelogStopAction();
02699 return SL_OK;
02700 }
02701
02702 switch (mode) {
02703 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02704 case SL_LOAD: _sl.action = SLA_LOAD; break;
02705 case SL_SAVE: _sl.action = SLA_SAVE; break;
02706 default: NOT_REACHED();
02707 }
02708
02709 try {
02710 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02711
02712
02713 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02714 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02715 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
02716
02717 if (fh == NULL) {
02718 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02719 }
02720
02721 if (mode == SL_SAVE) {
02722 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02723 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02724
02725 return DoSave(new FileWriter(fh), threaded);
02726 }
02727
02728
02729 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02730 DEBUG(desync, 1, "load: %s", filename);
02731 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02732 } catch (...) {
02733 ClearSaveLoadState();
02734
02735
02736 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02737
02738
02739 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02740 }
02741 }
02742
02744 void DoExitSave()
02745 {
02746 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02747 }
02748
02754 void GenerateDefaultSaveName(char *buf, const char *last)
02755 {
02756
02757
02758
02759 CompanyID cid = _local_company;
02760 if (!Company::IsValidID(cid)) {
02761 const Company *c;
02762 FOR_ALL_COMPANIES(c) {
02763 cid = c->index;
02764 break;
02765 }
02766 }
02767
02768 SetDParam(0, cid);
02769
02770
02771 switch (_settings_client.gui.date_format_in_default_names) {
02772 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02773 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02774 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02775 default: NOT_REACHED();
02776 }
02777 SetDParam(2, _date);
02778
02779
02780 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02781 SanitizeFilename(buf);
02782 }
02783
02784 #if 0
02785
02791 int GetSavegameType(char *file)
02792 {
02793 const SaveLoadFormat *fmt;
02794 uint32 hdr;
02795 FILE *f;
02796 int mode = SL_OLD_LOAD;
02797
02798 f = fopen(file, "rb");
02799 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02800 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02801 mode = SL_LOAD;
02802 } else {
02803
02804 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02805 if (fmt->tag == hdr) {
02806 mode = SL_LOAD;
02807 break;
02808 }
02809 }
02810 }
02811
02812 fclose(f);
02813 return mode;
02814 }
02815 #endif