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