00001
00002
00003
00004
00005
00006
00007
00008
00009
00024 #include "../stdafx.h"
00025 #include "../debug.h"
00026 #include "../station_base.h"
00027 #include "../thread/thread.h"
00028 #include "../town.h"
00029 #include "../network/network.h"
00030 #include "../window_func.h"
00031 #include "../strings_func.h"
00032 #include "../core/endian_func.hpp"
00033 #include "../vehicle_base.h"
00034 #include "../company_func.h"
00035 #include "../date_func.h"
00036 #include "../autoreplace_base.h"
00037 #include "../roadstop_base.h"
00038 #include "../statusbar_gui.h"
00039 #include "../fileio_func.h"
00040 #include "../gamelog.h"
00041 #include "../string_func.h"
00042 #include "../fios.h"
00043 #include "../error.h"
00044
00045 #include "table/strings.h"
00046
00047 #include "saveload_internal.h"
00048 #include "saveload_filter.h"
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 extern const uint16 SAVEGAME_VERSION = 170;
00239
00240 SavegameType _savegame_type;
00241
00242 uint32 _ttdp_version;
00243 uint16 _sl_version;
00244 byte _sl_minor_version;
00245 char _savegame_format[8];
00246 bool _do_autosave;
00247
00249 enum SaveLoadAction {
00250 SLA_LOAD,
00251 SLA_SAVE,
00252 SLA_PTRS,
00253 SLA_NULL,
00254 SLA_LOAD_CHECK,
00255 };
00256
00257 enum NeedLength {
00258 NL_NONE = 0,
00259 NL_WANTLENGTH = 1,
00260 NL_CALCLENGTH = 2,
00261 };
00262
00264 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
00265
00267 struct ReadBuffer {
00268 byte buf[MEMORY_CHUNK_SIZE];
00269 byte *bufp;
00270 byte *bufe;
00271 LoadFilter *reader;
00272 size_t read;
00273
00278 ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
00279 {
00280 }
00281
00282 inline byte ReadByte()
00283 {
00284 if (this->bufp == this->bufe) {
00285 size_t len = this->reader->Read(this->buf, lengthof(this->buf));
00286 if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00287
00288 this->read += len;
00289 this->bufp = this->buf;
00290 this->bufe = this->buf + len;
00291 }
00292
00293 return *this->bufp++;
00294 }
00295
00300 size_t GetSize() const
00301 {
00302 return this->read - (this->bufe - this->bufp);
00303 }
00304 };
00305
00306
00308 struct MemoryDumper {
00309 AutoFreeSmallVector<byte *, 16> blocks;
00310 byte *buf;
00311 byte *bufe;
00312
00314 MemoryDumper() : buf(NULL), bufe(NULL)
00315 {
00316 }
00317
00322 inline void WriteByte(byte b)
00323 {
00324
00325 if (this->buf == this->bufe) {
00326 this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
00327 *this->blocks.Append() = this->buf;
00328 this->bufe = this->buf + MEMORY_CHUNK_SIZE;
00329 }
00330
00331 *this->buf++ = b;
00332 }
00333
00338 void Flush(SaveFilter *writer)
00339 {
00340 uint i = 0;
00341 size_t t = this->GetSize();
00342
00343 while (t > 0) {
00344 size_t to_write = min(MEMORY_CHUNK_SIZE, t);
00345
00346 writer->Write(this->blocks[i++], to_write);
00347 t -= to_write;
00348 }
00349
00350 writer->Finish();
00351 }
00352
00357 size_t GetSize() const
00358 {
00359 return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
00360 }
00361 };
00362
00364 struct SaveLoadParams {
00365 SaveLoadAction action;
00366 NeedLength need_length;
00367 byte block_mode;
00368 bool error;
00369
00370 size_t obj_len;
00371 int array_index, last_array_index;
00372
00373 MemoryDumper *dumper;
00374 SaveFilter *sf;
00375
00376 ReadBuffer *reader;
00377 LoadFilter *lf;
00378
00379 StringID error_str;
00380 char *extra_msg;
00381
00382 byte ff_state;
00383 bool saveinprogress;
00384 };
00385
00386 static SaveLoadParams _sl;
00387
00388
00389 extern const ChunkHandler _gamelog_chunk_handlers[];
00390 extern const ChunkHandler _map_chunk_handlers[];
00391 extern const ChunkHandler _misc_chunk_handlers[];
00392 extern const ChunkHandler _name_chunk_handlers[];
00393 extern const ChunkHandler _cheat_chunk_handlers[] ;
00394 extern const ChunkHandler _setting_chunk_handlers[];
00395 extern const ChunkHandler _company_chunk_handlers[];
00396 extern const ChunkHandler _engine_chunk_handlers[];
00397 extern const ChunkHandler _veh_chunk_handlers[];
00398 extern const ChunkHandler _waypoint_chunk_handlers[];
00399 extern const ChunkHandler _depot_chunk_handlers[];
00400 extern const ChunkHandler _order_chunk_handlers[];
00401 extern const ChunkHandler _town_chunk_handlers[];
00402 extern const ChunkHandler _sign_chunk_handlers[];
00403 extern const ChunkHandler _station_chunk_handlers[];
00404 extern const ChunkHandler _industry_chunk_handlers[];
00405 extern const ChunkHandler _economy_chunk_handlers[];
00406 extern const ChunkHandler _subsidy_chunk_handlers[];
00407 extern const ChunkHandler _goal_chunk_handlers[];
00408 extern const ChunkHandler _ai_chunk_handlers[];
00409 extern const ChunkHandler _game_chunk_handlers[];
00410 extern const ChunkHandler _animated_tile_chunk_handlers[];
00411 extern const ChunkHandler _newgrf_chunk_handlers[];
00412 extern const ChunkHandler _group_chunk_handlers[];
00413 extern const ChunkHandler _cargopacket_chunk_handlers[];
00414 extern const ChunkHandler _autoreplace_chunk_handlers[];
00415 extern const ChunkHandler _labelmaps_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 _airport_chunk_handlers,
00450 _object_chunk_handlers,
00451 _persistent_storage_chunk_handlers,
00452 NULL,
00453 };
00454
00459 #define FOR_ALL_CHUNK_HANDLERS(ch) \
00460 for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \
00461 for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1)
00462
00464 static void SlNullPointers()
00465 {
00466 _sl.action = SLA_NULL;
00467
00468
00469
00470
00471 _sl_version = SAVEGAME_VERSION;
00472
00473 DEBUG(sl, 1, "Nulling pointers");
00474
00475 FOR_ALL_CHUNK_HANDLERS(ch) {
00476 if (ch->ptrs_proc != NULL) {
00477 DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00478 ch->ptrs_proc();
00479 }
00480 }
00481
00482 DEBUG(sl, 1, "All pointers nulled");
00483
00484 assert(_sl.action == SLA_NULL);
00485 }
00486
00495 void NORETURN SlError(StringID string, const char *extra_msg)
00496 {
00497
00498 if (_sl.action == SLA_LOAD_CHECK) {
00499 _load_check_data.error = string;
00500 free(_load_check_data.error_data);
00501 _load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00502 } else {
00503 _sl.error_str = string;
00504 free(_sl.extra_msg);
00505 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00506 }
00507
00508
00509
00510
00511
00512 if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00513 throw std::exception();
00514 }
00515
00523 void NORETURN SlErrorCorrupt(const char *msg)
00524 {
00525 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00526 }
00527
00528
00529 typedef void (*AsyncSaveFinishProc)();
00530 static AsyncSaveFinishProc _async_save_finish = NULL;
00531 static ThreadObject *_save_thread;
00532
00537 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00538 {
00539 if (_exit_game) return;
00540 while (_async_save_finish != NULL) CSleep(10);
00541
00542 _async_save_finish = proc;
00543 }
00544
00548 void ProcessAsyncSaveFinish()
00549 {
00550 if (_async_save_finish == NULL) return;
00551
00552 _async_save_finish();
00553
00554 _async_save_finish = NULL;
00555
00556 if (_save_thread != NULL) {
00557 _save_thread->Join();
00558 delete _save_thread;
00559 _save_thread = NULL;
00560 }
00561 }
00562
00567 byte SlReadByte()
00568 {
00569 return _sl.reader->ReadByte();
00570 }
00571
00576 void SlWriteByte(byte b)
00577 {
00578 _sl.dumper->WriteByte(b);
00579 }
00580
00581 static inline int SlReadUint16()
00582 {
00583 int x = SlReadByte() << 8;
00584 return x | SlReadByte();
00585 }
00586
00587 static inline uint32 SlReadUint32()
00588 {
00589 uint32 x = SlReadUint16() << 16;
00590 return x | SlReadUint16();
00591 }
00592
00593 static inline uint64 SlReadUint64()
00594 {
00595 uint32 x = SlReadUint32();
00596 uint32 y = SlReadUint32();
00597 return (uint64)x << 32 | y;
00598 }
00599
00600 static inline void SlWriteUint16(uint16 v)
00601 {
00602 SlWriteByte(GB(v, 8, 8));
00603 SlWriteByte(GB(v, 0, 8));
00604 }
00605
00606 static inline void SlWriteUint32(uint32 v)
00607 {
00608 SlWriteUint16(GB(v, 16, 16));
00609 SlWriteUint16(GB(v, 0, 16));
00610 }
00611
00612 static inline void SlWriteUint64(uint64 x)
00613 {
00614 SlWriteUint32((uint32)(x >> 32));
00615 SlWriteUint32((uint32)x);
00616 }
00617
00623 static inline void SlSkipBytes(size_t length)
00624 {
00625 for (; length != 0; length--) SlReadByte();
00626 }
00627
00637 static uint SlReadSimpleGamma()
00638 {
00639 uint i = SlReadByte();
00640 if (HasBit(i, 7)) {
00641 i &= ~0x80;
00642 if (HasBit(i, 6)) {
00643 i &= ~0x40;
00644 if (HasBit(i, 5)) {
00645 i &= ~0x20;
00646 if (HasBit(i, 4)) {
00647 SlErrorCorrupt("Unsupported gamma");
00648 }
00649 i = (i << 8) | SlReadByte();
00650 }
00651 i = (i << 8) | SlReadByte();
00652 }
00653 i = (i << 8) | SlReadByte();
00654 }
00655 return i;
00656 }
00657
00670 static void SlWriteSimpleGamma(size_t i)
00671 {
00672 if (i >= (1 << 7)) {
00673 if (i >= (1 << 14)) {
00674 if (i >= (1 << 21)) {
00675 assert(i < (1 << 28));
00676 SlWriteByte((byte)(0xE0 | (i >> 24)));
00677 SlWriteByte((byte)(i >> 16));
00678 } else {
00679 SlWriteByte((byte)(0xC0 | (i >> 16)));
00680 }
00681 SlWriteByte((byte)(i >> 8));
00682 } else {
00683 SlWriteByte((byte)(0x80 | (i >> 8)));
00684 }
00685 }
00686 SlWriteByte((byte)i);
00687 }
00688
00690 static inline uint SlGetGammaLength(size_t i)
00691 {
00692 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00693 }
00694
00695 static inline uint SlReadSparseIndex()
00696 {
00697 return SlReadSimpleGamma();
00698 }
00699
00700 static inline void SlWriteSparseIndex(uint index)
00701 {
00702 SlWriteSimpleGamma(index);
00703 }
00704
00705 static inline uint SlReadArrayLength()
00706 {
00707 return SlReadSimpleGamma();
00708 }
00709
00710 static inline void SlWriteArrayLength(size_t length)
00711 {
00712 SlWriteSimpleGamma(length);
00713 }
00714
00715 static inline uint SlGetArrayLength(size_t length)
00716 {
00717 return SlGetGammaLength(length);
00718 }
00719
00726 static inline uint SlCalcConvMemLen(VarType conv)
00727 {
00728 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00729 byte length = GB(conv, 4, 4);
00730
00731 switch (length << 4) {
00732 case SLE_VAR_STRB:
00733 case SLE_VAR_STRBQ:
00734 case SLE_VAR_STR:
00735 case SLE_VAR_STRQ:
00736 return SlReadArrayLength();
00737
00738 default:
00739 assert(length < lengthof(conv_mem_size));
00740 return conv_mem_size[length];
00741 }
00742 }
00743
00750 static inline byte SlCalcConvFileLen(VarType conv)
00751 {
00752 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00753 byte length = GB(conv, 0, 4);
00754 assert(length < lengthof(conv_file_size));
00755 return conv_file_size[length];
00756 }
00757
00759 static inline size_t SlCalcRefLen()
00760 {
00761 return IsSavegameVersionBefore(69) ? 2 : 4;
00762 }
00763
00764 void SlSetArrayIndex(uint index)
00765 {
00766 _sl.need_length = NL_WANTLENGTH;
00767 _sl.array_index = index;
00768 }
00769
00770 static size_t _next_offs;
00771
00776 int SlIterateArray()
00777 {
00778 int index;
00779
00780
00781
00782 if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00783
00784 for (;;) {
00785 uint length = SlReadArrayLength();
00786 if (length == 0) {
00787 _next_offs = 0;
00788 return -1;
00789 }
00790
00791 _sl.obj_len = --length;
00792 _next_offs = _sl.reader->GetSize() + length;
00793
00794 switch (_sl.block_mode) {
00795 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00796 case CH_ARRAY: index = _sl.array_index++; break;
00797 default:
00798 DEBUG(sl, 0, "SlIterateArray error");
00799 return -1;
00800 }
00801
00802 if (length != 0) return index;
00803 }
00804 }
00805
00809 void SlSkipArray()
00810 {
00811 while (SlIterateArray() != -1) {
00812 SlSkipBytes(_next_offs - _sl.reader->GetSize());
00813 }
00814 }
00815
00821 void SlSetLength(size_t length)
00822 {
00823 assert(_sl.action == SLA_SAVE);
00824
00825 switch (_sl.need_length) {
00826 case NL_WANTLENGTH:
00827 _sl.need_length = NL_NONE;
00828 switch (_sl.block_mode) {
00829 case CH_RIFF:
00830
00831
00832
00833 assert(length < (1 << 28));
00834 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00835 break;
00836 case CH_ARRAY:
00837 assert(_sl.last_array_index <= _sl.array_index);
00838 while (++_sl.last_array_index <= _sl.array_index) {
00839 SlWriteArrayLength(1);
00840 }
00841 SlWriteArrayLength(length + 1);
00842 break;
00843 case CH_SPARSE_ARRAY:
00844 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00845 SlWriteSparseIndex(_sl.array_index);
00846 break;
00847 default: NOT_REACHED();
00848 }
00849 break;
00850
00851 case NL_CALCLENGTH:
00852 _sl.obj_len += (int)length;
00853 break;
00854
00855 default: NOT_REACHED();
00856 }
00857 }
00858
00865 static void SlCopyBytes(void *ptr, size_t length)
00866 {
00867 byte *p = (byte *)ptr;
00868
00869 switch (_sl.action) {
00870 case SLA_LOAD_CHECK:
00871 case SLA_LOAD:
00872 for (; length != 0; length--) *p++ = SlReadByte();
00873 break;
00874 case SLA_SAVE:
00875 for (; length != 0; length--) SlWriteByte(*p++);
00876 break;
00877 default: NOT_REACHED();
00878 }
00879 }
00880
00882 size_t SlGetFieldLength()
00883 {
00884 return _sl.obj_len;
00885 }
00886
00894 int64 ReadValue(const void *ptr, VarType conv)
00895 {
00896 switch (GetVarMemType(conv)) {
00897 case SLE_VAR_BL: return (*(const bool *)ptr != 0);
00898 case SLE_VAR_I8: return *(const int8 *)ptr;
00899 case SLE_VAR_U8: return *(const byte *)ptr;
00900 case SLE_VAR_I16: return *(const int16 *)ptr;
00901 case SLE_VAR_U16: return *(const uint16*)ptr;
00902 case SLE_VAR_I32: return *(const int32 *)ptr;
00903 case SLE_VAR_U32: return *(const uint32*)ptr;
00904 case SLE_VAR_I64: return *(const int64 *)ptr;
00905 case SLE_VAR_U64: return *(const uint64*)ptr;
00906 case SLE_VAR_NULL:return 0;
00907 default: NOT_REACHED();
00908 }
00909 }
00910
00918 void WriteValue(void *ptr, VarType conv, int64 val)
00919 {
00920 switch (GetVarMemType(conv)) {
00921 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00922 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00923 case SLE_VAR_U8: *(byte *)ptr = val; break;
00924 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00925 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00926 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00927 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00928 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00929 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00930 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00931 case SLE_VAR_NULL: break;
00932 default: NOT_REACHED();
00933 }
00934 }
00935
00944 static void SlSaveLoadConv(void *ptr, VarType conv)
00945 {
00946 switch (_sl.action) {
00947 case SLA_SAVE: {
00948 int64 x = ReadValue(ptr, conv);
00949
00950
00951 switch (GetVarFileType(conv)) {
00952 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00953 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00954 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00955 case SLE_FILE_STRINGID:
00956 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00957 case SLE_FILE_I32:
00958 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00959 case SLE_FILE_I64:
00960 case SLE_FILE_U64: SlWriteUint64(x);break;
00961 default: NOT_REACHED();
00962 }
00963 break;
00964 }
00965 case SLA_LOAD_CHECK:
00966 case SLA_LOAD: {
00967 int64 x;
00968
00969 switch (GetVarFileType(conv)) {
00970 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00971 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00972 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00973 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00974 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00975 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00976 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00977 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00978 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00979 default: NOT_REACHED();
00980 }
00981
00982
00983 WriteValue(ptr, conv, x);
00984 break;
00985 }
00986 case SLA_PTRS: break;
00987 case SLA_NULL: break;
00988 default: NOT_REACHED();
00989 }
00990 }
00991
01001 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
01002 {
01003 if (ptr == NULL) return 0;
01004 return min(strlen(ptr), length - 1);
01005 }
01006
01016 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
01017 {
01018 size_t len;
01019 const char *str;
01020
01021 switch (GetVarMemType(conv)) {
01022 default: NOT_REACHED();
01023 case SLE_VAR_STR:
01024 case SLE_VAR_STRQ:
01025 str = *(const char * const *)ptr;
01026 len = SIZE_MAX;
01027 break;
01028 case SLE_VAR_STRB:
01029 case SLE_VAR_STRBQ:
01030 str = (const char *)ptr;
01031 len = length;
01032 break;
01033 }
01034
01035 len = SlCalcNetStringLen(str, len);
01036 return len + SlGetArrayLength(len);
01037 }
01038
01045 static void SlString(void *ptr, size_t length, VarType conv)
01046 {
01047 switch (_sl.action) {
01048 case SLA_SAVE: {
01049 size_t len;
01050 switch (GetVarMemType(conv)) {
01051 default: NOT_REACHED();
01052 case SLE_VAR_STRB:
01053 case SLE_VAR_STRBQ:
01054 len = SlCalcNetStringLen((char *)ptr, length);
01055 break;
01056 case SLE_VAR_STR:
01057 case SLE_VAR_STRQ:
01058 ptr = *(char **)ptr;
01059 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01060 break;
01061 }
01062
01063 SlWriteArrayLength(len);
01064 SlCopyBytes(ptr, len);
01065 break;
01066 }
01067 case SLA_LOAD_CHECK:
01068 case SLA_LOAD: {
01069 size_t len = SlReadArrayLength();
01070
01071 switch (GetVarMemType(conv)) {
01072 default: NOT_REACHED();
01073 case SLE_VAR_STRB:
01074 case SLE_VAR_STRBQ:
01075 if (len >= length) {
01076 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01077 SlCopyBytes(ptr, length);
01078 SlSkipBytes(len - length);
01079 len = length - 1;
01080 } else {
01081 SlCopyBytes(ptr, len);
01082 }
01083 break;
01084 case SLE_VAR_STR:
01085 case SLE_VAR_STRQ:
01086 free(*(char **)ptr);
01087 if (len == 0) {
01088 *(char **)ptr = NULL;
01089 return;
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 if (IsSavegameVersionBefore(169)) {
01103 str_fix_scc_encoded((char *)ptr, (char *)ptr + len);
01104 }
01105 }
01106 if ((conv & SLF_ALLOW_NEWLINE) != 0) {
01107 settings = settings | SVS_ALLOW_NEWLINE;
01108 }
01109 str_validate((char *)ptr, (char *)ptr + len, settings);
01110 break;
01111 }
01112 case SLA_PTRS: break;
01113 case SLA_NULL: break;
01114 default: NOT_REACHED();
01115 }
01116 }
01117
01123 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01124 {
01125 return SlCalcConvFileLen(conv) * length;
01126 }
01127
01134 void SlArray(void *array, size_t length, VarType conv)
01135 {
01136 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01137
01138
01139 if (_sl.need_length != NL_NONE) {
01140 SlSetLength(SlCalcArrayLen(length, conv));
01141
01142 if (_sl.need_length == NL_CALCLENGTH) return;
01143 }
01144
01145
01146
01147 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01148
01149 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01150 conv == SLE_INT32 || conv == SLE_UINT32) {
01151 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01152 return;
01153 }
01154
01155 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01156 for (uint i = 0; i < length; i++) {
01157 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01158 }
01159 return;
01160 }
01161 }
01162
01163
01164
01165 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01166 SlCopyBytes(array, length);
01167 } else {
01168 byte *a = (byte*)array;
01169 byte mem_size = SlCalcConvMemLen(conv);
01170
01171 for (; length != 0; length --) {
01172 SlSaveLoadConv(a, conv);
01173 a += mem_size;
01174 }
01175 }
01176 }
01177
01178
01189 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01190 {
01191 assert(_sl.action == SLA_SAVE);
01192
01193 if (obj == NULL) return 0;
01194
01195 switch (rt) {
01196 case REF_VEHICLE_OLD:
01197 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01198 case REF_STATION: return ((const Station*)obj)->index + 1;
01199 case REF_TOWN: return ((const Town*)obj)->index + 1;
01200 case REF_ORDER: return ((const Order*)obj)->index + 1;
01201 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01202 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01203 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01204 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01205 case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
01206 default: NOT_REACHED();
01207 }
01208 }
01209
01220 static void *IntToReference(size_t index, SLRefType rt)
01221 {
01222 assert_compile(sizeof(size_t) <= sizeof(void *));
01223
01224 assert(_sl.action == SLA_PTRS);
01225
01226
01227
01228 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01229 rt = REF_VEHICLE;
01230 }
01231
01232
01233 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01234
01235
01236
01237 if (rt != REF_VEHICLE_OLD) index--;
01238
01239 switch (rt) {
01240 case REF_ORDERLIST:
01241 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01242 SlErrorCorrupt("Referencing invalid OrderList");
01243
01244 case REF_ORDER:
01245 if (Order::IsValidID(index)) return Order::Get(index);
01246
01247 if (IsSavegameVersionBefore(5, 2)) return NULL;
01248 SlErrorCorrupt("Referencing invalid Order");
01249
01250 case REF_VEHICLE_OLD:
01251 case REF_VEHICLE:
01252 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01253 SlErrorCorrupt("Referencing invalid Vehicle");
01254
01255 case REF_STATION:
01256 if (Station::IsValidID(index)) return Station::Get(index);
01257 SlErrorCorrupt("Referencing invalid Station");
01258
01259 case REF_TOWN:
01260 if (Town::IsValidID(index)) return Town::Get(index);
01261 SlErrorCorrupt("Referencing invalid Town");
01262
01263 case REF_ROADSTOPS:
01264 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01265 SlErrorCorrupt("Referencing invalid RoadStop");
01266
01267 case REF_ENGINE_RENEWS:
01268 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01269 SlErrorCorrupt("Referencing invalid EngineRenew");
01270
01271 case REF_CARGO_PACKET:
01272 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01273 SlErrorCorrupt("Referencing invalid CargoPacket");
01274
01275 case REF_STORAGE:
01276 if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index);
01277 SlErrorCorrupt("Referencing invalid PersistentStorage");
01278
01279 default: NOT_REACHED();
01280 }
01281 }
01282
01287 static inline size_t SlCalcListLen(const void *list)
01288 {
01289 const std::list<void *> *l = (const std::list<void *> *) list;
01290
01291 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01292
01293
01294 return l->size() * type_size + type_size;
01295 }
01296
01297
01303 static void SlList(void *list, SLRefType conv)
01304 {
01305
01306 if (_sl.need_length != NL_NONE) {
01307 SlSetLength(SlCalcListLen(list));
01308
01309 if (_sl.need_length == NL_CALCLENGTH) return;
01310 }
01311
01312 typedef std::list<void *> PtrList;
01313 PtrList *l = (PtrList *)list;
01314
01315 switch (_sl.action) {
01316 case SLA_SAVE: {
01317 SlWriteUint32((uint32)l->size());
01318
01319 PtrList::iterator iter;
01320 for (iter = l->begin(); iter != l->end(); ++iter) {
01321 void *ptr = *iter;
01322 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01323 }
01324 break;
01325 }
01326 case SLA_LOAD_CHECK:
01327 case SLA_LOAD: {
01328 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01329
01330
01331 for (size_t i = 0; i < length; i++) {
01332 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01333 l->push_back((void *)data);
01334 }
01335 break;
01336 }
01337 case SLA_PTRS: {
01338 PtrList temp = *l;
01339
01340 l->clear();
01341 PtrList::iterator iter;
01342 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01343 void *ptr = IntToReference((size_t)*iter, conv);
01344 l->push_back(ptr);
01345 }
01346 break;
01347 }
01348 case SLA_NULL:
01349 l->clear();
01350 break;
01351 default: NOT_REACHED();
01352 }
01353 }
01354
01355
01357 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01358 {
01359 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01360 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01361
01362 return true;
01363 }
01364
01370 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01371 {
01372 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01373 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01374 return true;
01375 }
01376
01377 return false;
01378 }
01379
01386 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01387 {
01388 size_t length = 0;
01389
01390
01391 for (; sld->cmd != SL_END; sld++) {
01392 length += SlCalcObjMemberLength(object, sld);
01393 }
01394 return length;
01395 }
01396
01397 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01398 {
01399 assert(_sl.action == SLA_SAVE);
01400
01401 switch (sld->cmd) {
01402 case SL_VAR:
01403 case SL_REF:
01404 case SL_ARR:
01405 case SL_STR:
01406 case SL_LST:
01407
01408 if (!SlIsObjectValidInSavegame(sld)) break;
01409
01410 switch (sld->cmd) {
01411 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01412 case SL_REF: return SlCalcRefLen();
01413 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01414 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01415 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01416 default: NOT_REACHED();
01417 }
01418 break;
01419 case SL_WRITEBYTE: return 1;
01420 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01421 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01422 default: NOT_REACHED();
01423 }
01424 return 0;
01425 }
01426
01427
01428 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01429 {
01430 VarType conv = GB(sld->conv, 0, 8);
01431 switch (sld->cmd) {
01432 case SL_VAR:
01433 case SL_REF:
01434 case SL_ARR:
01435 case SL_STR:
01436 case SL_LST:
01437
01438 if (!SlIsObjectValidInSavegame(sld)) return false;
01439 if (SlSkipVariableOnLoad(sld)) return false;
01440
01441 switch (sld->cmd) {
01442 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01443 case SL_REF:
01444 switch (_sl.action) {
01445 case SLA_SAVE:
01446 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01447 break;
01448 case SLA_LOAD_CHECK:
01449 case SLA_LOAD:
01450 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01451 break;
01452 case SLA_PTRS:
01453 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01454 break;
01455 case SLA_NULL:
01456 *(void **)ptr = NULL;
01457 break;
01458 default: NOT_REACHED();
01459 }
01460 break;
01461 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01462 case SL_STR: SlString(ptr, sld->length, sld->conv); break;
01463 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01464 default: NOT_REACHED();
01465 }
01466 break;
01467
01468
01469
01470
01471
01472
01473 case SL_WRITEBYTE:
01474 switch (_sl.action) {
01475 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01476 case SLA_LOAD_CHECK:
01477 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01478 case SLA_PTRS: break;
01479 case SLA_NULL: break;
01480 default: NOT_REACHED();
01481 }
01482 break;
01483
01484
01485 case SL_VEH_INCLUDE:
01486 SlObject(ptr, GetVehicleDescription(VEH_END));
01487 break;
01488
01489 case SL_ST_INCLUDE:
01490 SlObject(ptr, GetBaseStationDescription());
01491 break;
01492
01493 default: NOT_REACHED();
01494 }
01495 return true;
01496 }
01497
01503 void SlObject(void *object, const SaveLoad *sld)
01504 {
01505
01506 if (_sl.need_length != NL_NONE) {
01507 SlSetLength(SlCalcObjLength(object, sld));
01508 if (_sl.need_length == NL_CALCLENGTH) return;
01509 }
01510
01511 for (; sld->cmd != SL_END; sld++) {
01512 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01513 SlObjectMember(ptr, sld);
01514 }
01515 }
01516
01521 void SlGlobList(const SaveLoadGlobVarList *sldg)
01522 {
01523 SlObject(NULL, (const SaveLoad*)sldg);
01524 }
01525
01531 void SlAutolength(AutolengthProc *proc, void *arg)
01532 {
01533 size_t offs;
01534
01535 assert(_sl.action == SLA_SAVE);
01536
01537
01538 _sl.need_length = NL_CALCLENGTH;
01539 _sl.obj_len = 0;
01540 proc(arg);
01541
01542
01543 _sl.need_length = NL_WANTLENGTH;
01544 SlSetLength(_sl.obj_len);
01545
01546 offs = _sl.dumper->GetSize() + _sl.obj_len;
01547
01548
01549 proc(arg);
01550
01551 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01552 }
01553
01558 static void SlLoadChunk(const ChunkHandler *ch)
01559 {
01560 byte m = SlReadByte();
01561 size_t len;
01562 size_t endoffs;
01563
01564 _sl.block_mode = m;
01565 _sl.obj_len = 0;
01566
01567 switch (m) {
01568 case CH_ARRAY:
01569 _sl.array_index = 0;
01570 ch->load_proc();
01571 break;
01572 case CH_SPARSE_ARRAY:
01573 ch->load_proc();
01574 break;
01575 default:
01576 if ((m & 0xF) == CH_RIFF) {
01577
01578 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01579 len += SlReadUint16();
01580 _sl.obj_len = len;
01581 endoffs = _sl.reader->GetSize() + len;
01582 ch->load_proc();
01583 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01584 } else {
01585 SlErrorCorrupt("Invalid chunk type");
01586 }
01587 break;
01588 }
01589 }
01590
01596 static void SlLoadCheckChunk(const ChunkHandler *ch)
01597 {
01598 byte m = SlReadByte();
01599 size_t len;
01600 size_t endoffs;
01601
01602 _sl.block_mode = m;
01603 _sl.obj_len = 0;
01604
01605 switch (m) {
01606 case CH_ARRAY:
01607 _sl.array_index = 0;
01608 if (ch->load_check_proc) {
01609 ch->load_check_proc();
01610 } else {
01611 SlSkipArray();
01612 }
01613 break;
01614 case CH_SPARSE_ARRAY:
01615 if (ch->load_check_proc) {
01616 ch->load_check_proc();
01617 } else {
01618 SlSkipArray();
01619 }
01620 break;
01621 default:
01622 if ((m & 0xF) == CH_RIFF) {
01623
01624 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01625 len += SlReadUint16();
01626 _sl.obj_len = len;
01627 endoffs = _sl.reader->GetSize() + len;
01628 if (ch->load_check_proc) {
01629 ch->load_check_proc();
01630 } else {
01631 SlSkipBytes(len);
01632 }
01633 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01634 } else {
01635 SlErrorCorrupt("Invalid chunk type");
01636 }
01637 break;
01638 }
01639 }
01640
01645 static ChunkSaveLoadProc *_stub_save_proc;
01646
01652 static inline void SlStubSaveProc2(void *arg)
01653 {
01654 _stub_save_proc();
01655 }
01656
01662 static void SlStubSaveProc()
01663 {
01664 SlAutolength(SlStubSaveProc2, NULL);
01665 }
01666
01672 static void SlSaveChunk(const ChunkHandler *ch)
01673 {
01674 ChunkSaveLoadProc *proc = ch->save_proc;
01675
01676
01677 if (proc == NULL) return;
01678
01679 SlWriteUint32(ch->id);
01680 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01681
01682 if (ch->flags & CH_AUTO_LENGTH) {
01683
01684 _stub_save_proc = proc;
01685 proc = SlStubSaveProc;
01686 }
01687
01688 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01689 switch (ch->flags & CH_TYPE_MASK) {
01690 case CH_RIFF:
01691 _sl.need_length = NL_WANTLENGTH;
01692 proc();
01693 break;
01694 case CH_ARRAY:
01695 _sl.last_array_index = 0;
01696 SlWriteByte(CH_ARRAY);
01697 proc();
01698 SlWriteArrayLength(0);
01699 break;
01700 case CH_SPARSE_ARRAY:
01701 SlWriteByte(CH_SPARSE_ARRAY);
01702 proc();
01703 SlWriteArrayLength(0);
01704 break;
01705 default: NOT_REACHED();
01706 }
01707 }
01708
01710 static void SlSaveChunks()
01711 {
01712 FOR_ALL_CHUNK_HANDLERS(ch) {
01713 SlSaveChunk(ch);
01714 }
01715
01716
01717 SlWriteUint32(0);
01718 }
01719
01726 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01727 {
01728 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01729 return NULL;
01730 }
01731
01733 static void SlLoadChunks()
01734 {
01735 uint32 id;
01736 const ChunkHandler *ch;
01737
01738 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01739 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01740
01741 ch = SlFindChunkHandler(id);
01742 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01743 SlLoadChunk(ch);
01744 }
01745 }
01746
01748 static void SlLoadCheckChunks()
01749 {
01750 uint32 id;
01751 const ChunkHandler *ch;
01752
01753 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01754 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01755
01756 ch = SlFindChunkHandler(id);
01757 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01758 SlLoadCheckChunk(ch);
01759 }
01760 }
01761
01763 static void SlFixPointers()
01764 {
01765 _sl.action = SLA_PTRS;
01766
01767 DEBUG(sl, 1, "Fixing pointers");
01768
01769 FOR_ALL_CHUNK_HANDLERS(ch) {
01770 if (ch->ptrs_proc != NULL) {
01771 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01772 ch->ptrs_proc();
01773 }
01774 }
01775
01776 DEBUG(sl, 1, "All pointers fixed");
01777
01778 assert(_sl.action == SLA_PTRS);
01779 }
01780
01781
01783 struct FileReader : LoadFilter {
01784 FILE *file;
01785 long begin;
01786
01791 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01792 {
01793 }
01794
01796 ~FileReader()
01797 {
01798 if (this->file != NULL) fclose(this->file);
01799 this->file = NULL;
01800
01801
01802 _sl.sf = NULL;
01803 }
01804
01805 size_t Read(byte *buf, size_t size)
01806 {
01807
01808 if (this->file == NULL) return 0;
01809
01810 return fread(buf, 1, size, this->file);
01811 }
01812
01813 void Reset()
01814 {
01815 clearerr(this->file);
01816 fseek(this->file, this->begin, SEEK_SET);
01817 }
01818 };
01819
01821 struct FileWriter : SaveFilter {
01822 FILE *file;
01823
01828 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01829 {
01830 }
01831
01833 ~FileWriter()
01834 {
01835 this->Finish();
01836
01837
01838 _sl.sf = NULL;
01839 }
01840
01841 void Write(byte *buf, size_t size)
01842 {
01843
01844 if (this->file == NULL) return;
01845
01846 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01847 }
01848
01849 void Finish()
01850 {
01851 if (this->file != NULL) fclose(this->file);
01852 this->file = NULL;
01853 }
01854 };
01855
01856
01857
01858
01859
01860 #ifdef WITH_LZO
01861 #include <lzo/lzo1x.h>
01862
01864 static const uint LZO_BUFFER_SIZE = 8192;
01865
01867 struct LZOLoadFilter : LoadFilter {
01872 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01873 {
01874 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01875 }
01876
01877 size_t Read(byte *buf, size_t ssize)
01878 {
01879 assert(ssize >= LZO_BUFFER_SIZE);
01880
01881
01882 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01883 uint32 tmp[2];
01884 uint32 size;
01885 lzo_uint len;
01886
01887
01888 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01889
01890
01891 ((uint32*)out)[0] = size = tmp[1];
01892
01893 if (_sl_version != 0) {
01894 tmp[0] = TO_BE32(tmp[0]);
01895 size = TO_BE32(size);
01896 }
01897
01898 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01899
01900
01901 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01902
01903
01904 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01905
01906
01907 lzo1x_decompress(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01908 return len;
01909 }
01910 };
01911
01913 struct LZOSaveFilter : SaveFilter {
01919 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01920 {
01921 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01922 }
01923
01924 void Write(byte *buf, size_t size)
01925 {
01926 const lzo_bytep in = buf;
01927
01928 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01929 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01930 lzo_uint outlen;
01931
01932 do {
01933
01934 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01935 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01936 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01937 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01938 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01939
01940
01941 size -= len;
01942 in += len;
01943 } while (size > 0);
01944 }
01945 };
01946
01947 #endif
01948
01949
01950
01951
01952
01954 struct NoCompLoadFilter : LoadFilter {
01959 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01960 {
01961 }
01962
01963 size_t Read(byte *buf, size_t size)
01964 {
01965 return this->chain->Read(buf, size);
01966 }
01967 };
01968
01970 struct NoCompSaveFilter : SaveFilter {
01976 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01977 {
01978 }
01979
01980 void Write(byte *buf, size_t size)
01981 {
01982 this->chain->Write(buf, size);
01983 }
01984 };
01985
01986
01987
01988
01989
01990 #if defined(WITH_ZLIB)
01991 #include <zlib.h>
01992
01994 struct ZlibLoadFilter : LoadFilter {
01995 z_stream z;
01996 byte fread_buf[MEMORY_CHUNK_SIZE];
01997
02002 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
02003 {
02004 memset(&this->z, 0, sizeof(this->z));
02005 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02006 }
02007
02009 ~ZlibLoadFilter()
02010 {
02011 inflateEnd(&this->z);
02012 }
02013
02014 size_t Read(byte *buf, size_t size)
02015 {
02016 this->z.next_out = buf;
02017 this->z.avail_out = (uint)size;
02018
02019 do {
02020
02021 if (this->z.avail_in == 0) {
02022 this->z.next_in = this->fread_buf;
02023 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02024 }
02025
02026
02027 int r = inflate(&this->z, 0);
02028 if (r == Z_STREAM_END) break;
02029
02030 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02031 } while (this->z.avail_out != 0);
02032
02033 return size - this->z.avail_out;
02034 }
02035 };
02036
02038 struct ZlibSaveFilter : SaveFilter {
02039 z_stream z;
02040
02046 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02047 {
02048 memset(&this->z, 0, sizeof(this->z));
02049 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02050 }
02051
02053 ~ZlibSaveFilter()
02054 {
02055 deflateEnd(&this->z);
02056 }
02057
02064 void WriteLoop(byte *p, size_t len, int mode)
02065 {
02066 byte buf[MEMORY_CHUNK_SIZE];
02067 uint n;
02068 this->z.next_in = p;
02069 this->z.avail_in = (uInt)len;
02070 do {
02071 this->z.next_out = buf;
02072 this->z.avail_out = sizeof(buf);
02073
02081 int r = deflate(&this->z, mode);
02082
02083
02084 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02085 this->chain->Write(buf, n);
02086 }
02087 if (r == Z_STREAM_END) break;
02088
02089 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02090 } while (this->z.avail_in || !this->z.avail_out);
02091 }
02092
02093 void Write(byte *buf, size_t size)
02094 {
02095 this->WriteLoop(buf, size, 0);
02096 }
02097
02098 void Finish()
02099 {
02100 this->WriteLoop(NULL, 0, Z_FINISH);
02101 this->chain->Finish();
02102 }
02103 };
02104
02105 #endif
02106
02107
02108
02109
02110
02111 #if defined(WITH_LZMA)
02112 #include <lzma.h>
02113
02120 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02121
02123 struct LZMALoadFilter : LoadFilter {
02124 lzma_stream lzma;
02125 byte fread_buf[MEMORY_CHUNK_SIZE];
02126
02131 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02132 {
02133
02134 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02135 }
02136
02138 ~LZMALoadFilter()
02139 {
02140 lzma_end(&this->lzma);
02141 }
02142
02143 size_t Read(byte *buf, size_t size)
02144 {
02145 this->lzma.next_out = buf;
02146 this->lzma.avail_out = size;
02147
02148 do {
02149
02150 if (this->lzma.avail_in == 0) {
02151 this->lzma.next_in = this->fread_buf;
02152 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02153 }
02154
02155
02156 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02157 if (r == LZMA_STREAM_END) break;
02158 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02159 } while (this->lzma.avail_out != 0);
02160
02161 return size - this->lzma.avail_out;
02162 }
02163 };
02164
02166 struct LZMASaveFilter : SaveFilter {
02167 lzma_stream lzma;
02168
02174 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02175 {
02176 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02177 }
02178
02180 ~LZMASaveFilter()
02181 {
02182 lzma_end(&this->lzma);
02183 }
02184
02191 void WriteLoop(byte *p, size_t len, lzma_action action)
02192 {
02193 byte buf[MEMORY_CHUNK_SIZE];
02194 size_t n;
02195 this->lzma.next_in = p;
02196 this->lzma.avail_in = len;
02197 do {
02198 this->lzma.next_out = buf;
02199 this->lzma.avail_out = sizeof(buf);
02200
02201 lzma_ret r = lzma_code(&this->lzma, action);
02202
02203
02204 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02205 this->chain->Write(buf, n);
02206 }
02207 if (r == LZMA_STREAM_END) break;
02208 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02209 } while (this->lzma.avail_in || !this->lzma.avail_out);
02210 }
02211
02212 void Write(byte *buf, size_t size)
02213 {
02214 this->WriteLoop(buf, size, LZMA_RUN);
02215 }
02216
02217 void Finish()
02218 {
02219 this->WriteLoop(NULL, 0, LZMA_FINISH);
02220 this->chain->Finish();
02221 }
02222 };
02223
02224 #endif
02225
02226
02227
02228
02229
02231 struct SaveLoadFormat {
02232 const char *name;
02233 uint32 tag;
02234
02235 LoadFilter *(*init_load)(LoadFilter *chain);
02236 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02237
02238 byte min_compression;
02239 byte default_compression;
02240 byte max_compression;
02241 };
02242
02244 static const SaveLoadFormat _saveload_formats[] = {
02245 #if defined(WITH_LZO)
02246
02247 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02248 #else
02249 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02250 #endif
02251
02252 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02253 #if defined(WITH_ZLIB)
02254
02255
02256
02257 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02258 #else
02259 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02260 #endif
02261 #if defined(WITH_LZMA)
02262
02263
02264
02265
02266
02267 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02268 #else
02269 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02270 #endif
02271 };
02272
02280 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02281 {
02282 const SaveLoadFormat *def = lastof(_saveload_formats);
02283
02284
02285 while (!def->init_write) def--;
02286
02287 if (!StrEmpty(s)) {
02288
02289 char *complevel = strrchr(s, ':');
02290 if (complevel != NULL) *complevel = '\0';
02291
02292 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02293 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02294 *compression_level = slf->default_compression;
02295 if (complevel != NULL) {
02296
02297
02298
02299 *complevel = ':';
02300 complevel++;
02301
02302
02303 char *end;
02304 long level = strtol(complevel, &end, 10);
02305 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02306 SetDParamStr(0, complevel);
02307 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL);
02308 } else {
02309 *compression_level = level;
02310 }
02311 }
02312 return slf;
02313 }
02314 }
02315
02316 SetDParamStr(0, s);
02317 SetDParamStr(1, def->name);
02318 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL);
02319
02320
02321 if (complevel != NULL) *complevel = ':';
02322 }
02323 *compression_level = def->default_compression;
02324 return def;
02325 }
02326
02327
02328 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02329 extern bool AfterLoadGame();
02330 extern bool LoadOldSaveGame(const char *file);
02331
02335 static inline void ClearSaveLoadState()
02336 {
02337 delete _sl.dumper;
02338 _sl.dumper = NULL;
02339
02340 delete _sl.sf;
02341 _sl.sf = NULL;
02342
02343 delete _sl.reader;
02344 _sl.reader = NULL;
02345
02346 delete _sl.lf;
02347 _sl.lf = NULL;
02348 }
02349
02355 static void SaveFileStart()
02356 {
02357 _sl.ff_state = _fast_forward;
02358 _fast_forward = 0;
02359 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02360
02361 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02362 _sl.saveinprogress = true;
02363 }
02364
02366 static void SaveFileDone()
02367 {
02368 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02369 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02370
02371 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02372 _sl.saveinprogress = false;
02373 }
02374
02376 void SetSaveLoadError(StringID str)
02377 {
02378 _sl.error_str = str;
02379 }
02380
02382 const char *GetSaveLoadErrorString()
02383 {
02384 SetDParam(0, _sl.error_str);
02385 SetDParamStr(1, _sl.extra_msg);
02386
02387 static char err_str[512];
02388 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02389 return err_str;
02390 }
02391
02393 static void SaveFileError()
02394 {
02395 SetDParamStr(0, GetSaveLoadErrorString());
02396 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02397 SaveFileDone();
02398 }
02399
02404 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02405 {
02406 try {
02407 byte compression;
02408 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02409
02410
02411 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02412 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02413
02414 _sl.sf = fmt->init_write(_sl.sf, compression);
02415 _sl.dumper->Flush(_sl.sf);
02416
02417 ClearSaveLoadState();
02418
02419 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02420
02421 return SL_OK;
02422 } catch (...) {
02423 ClearSaveLoadState();
02424
02425 AsyncSaveFinishProc asfp = SaveFileDone;
02426
02427
02428
02429 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02430
02431 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02432 asfp = SaveFileError;
02433 }
02434
02435 if (threaded) {
02436 SetAsyncSaveFinish(asfp);
02437 } else {
02438 asfp();
02439 }
02440 return SL_ERROR;
02441 }
02442 }
02443
02445 static void SaveFileToDiskThread(void *arg)
02446 {
02447 SaveFileToDisk(true);
02448 }
02449
02450 void WaitTillSaved()
02451 {
02452 if (_save_thread == NULL) return;
02453
02454 _save_thread->Join();
02455 delete _save_thread;
02456 _save_thread = NULL;
02457
02458
02459 ProcessAsyncSaveFinish();
02460 }
02461
02470 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02471 {
02472 assert(!_sl.saveinprogress);
02473
02474 _sl.dumper = new MemoryDumper();
02475 _sl.sf = writer;
02476
02477 _sl_version = SAVEGAME_VERSION;
02478
02479 SaveViewportBeforeSaveGame();
02480 SlSaveChunks();
02481
02482 SaveFileStart();
02483 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02484 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02485
02486 SaveOrLoadResult result = SaveFileToDisk(false);
02487 SaveFileDone();
02488
02489 return result;
02490 }
02491
02492 return SL_OK;
02493 }
02494
02501 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02502 {
02503 try {
02504 _sl.action = SLA_SAVE;
02505 return DoSave(writer, threaded);
02506 } catch (...) {
02507 ClearSaveLoadState();
02508 return SL_ERROR;
02509 }
02510 }
02511
02518 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02519 {
02520 _sl.lf = reader;
02521
02522 if (load_check) {
02523
02524 _load_check_data.Clear();
02525
02526 _load_check_data.checkable = true;
02527 }
02528
02529 uint32 hdr[2];
02530 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02531
02532
02533 const SaveLoadFormat *fmt = _saveload_formats;
02534 for (;;) {
02535
02536 if (fmt == endof(_saveload_formats)) {
02537 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02538 _sl.lf->Reset();
02539 _sl_version = 0;
02540 _sl_minor_version = 0;
02541
02542
02543 fmt = _saveload_formats;
02544 for (;;) {
02545 if (fmt == endof(_saveload_formats)) {
02546
02547 NOT_REACHED();
02548 }
02549 if (fmt->tag == TO_BE32X('OTTD')) break;
02550 fmt++;
02551 }
02552 break;
02553 }
02554
02555 if (fmt->tag == hdr[0]) {
02556
02557 _sl_version = TO_BE32(hdr[1]) >> 16;
02558
02559
02560
02561 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02562
02563 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02564
02565
02566 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02567 break;
02568 }
02569
02570 fmt++;
02571 }
02572
02573
02574 if (fmt->init_load == NULL) {
02575 char err_str[64];
02576 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02577 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02578 }
02579
02580 _sl.lf = fmt->init_load(_sl.lf);
02581 _sl.reader = new ReadBuffer(_sl.lf);
02582 _next_offs = 0;
02583
02584 if (!load_check) {
02585
02586
02587
02588 InitializeGame(256, 256, true, true);
02589
02590 GamelogReset();
02591
02592 if (IsSavegameVersionBefore(4)) {
02593
02594
02595
02596
02597
02598
02599
02600
02601
02602
02603
02604
02605
02606
02607
02608
02609
02610
02611
02612
02613
02614 ClearGRFConfigList(&_grfconfig);
02615 }
02616 }
02617
02618 if (load_check) {
02619
02620
02621 SlLoadCheckChunks();
02622 } else {
02623
02624 SlLoadChunks();
02625 SlFixPointers();
02626 }
02627
02628 ClearSaveLoadState();
02629
02630 _savegame_type = SGT_OTTD;
02631
02632 if (load_check) {
02633
02634 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02635 } else {
02636 GamelogStartAction(GLAT_LOAD);
02637
02638
02639
02640 if (!AfterLoadGame()) {
02641 GamelogStopAction();
02642 return SL_REINIT;
02643 }
02644
02645 GamelogStopAction();
02646 }
02647
02648 return SL_OK;
02649 }
02650
02656 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02657 {
02658 try {
02659 _sl.action = SLA_LOAD;
02660 return DoLoad(reader, false);
02661 } catch (...) {
02662 ClearSaveLoadState();
02663 return SL_REINIT;
02664 }
02665 }
02666
02676 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02677 {
02678
02679 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02680
02681 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02682 return SL_OK;
02683 }
02684 WaitTillSaved();
02685
02686
02687 if (mode == SL_OLD_LOAD) {
02688 InitializeGame(256, 256, true, true);
02689
02690
02691
02692
02693
02694 ClearGRFConfigList(&_grfconfig);
02695 GamelogReset();
02696 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02697 _sl_version = 0;
02698 _sl_minor_version = 0;
02699 GamelogStartAction(GLAT_LOAD);
02700 if (!AfterLoadGame()) {
02701 GamelogStopAction();
02702 return SL_REINIT;
02703 }
02704 GamelogStopAction();
02705 return SL_OK;
02706 }
02707
02708 switch (mode) {
02709 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02710 case SL_LOAD: _sl.action = SLA_LOAD; break;
02711 case SL_SAVE: _sl.action = SLA_SAVE; break;
02712 default: NOT_REACHED();
02713 }
02714
02715 try {
02716 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02717
02718
02719 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02720 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02721 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
02722
02723 if (fh == NULL) {
02724 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02725 }
02726
02727 if (mode == SL_SAVE) {
02728 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02729 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02730
02731 return DoSave(new FileWriter(fh), threaded);
02732 }
02733
02734
02735 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02736 DEBUG(desync, 1, "load: %s", filename);
02737 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02738 } catch (...) {
02739 ClearSaveLoadState();
02740
02741
02742 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02743
02744
02745 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02746 }
02747 }
02748
02750 void DoExitSave()
02751 {
02752 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02753 }
02754
02760 void GenerateDefaultSaveName(char *buf, const char *last)
02761 {
02762
02763
02764
02765 CompanyID cid = _local_company;
02766 if (!Company::IsValidID(cid)) {
02767 const Company *c;
02768 FOR_ALL_COMPANIES(c) {
02769 cid = c->index;
02770 break;
02771 }
02772 }
02773
02774 SetDParam(0, cid);
02775
02776
02777 switch (_settings_client.gui.date_format_in_default_names) {
02778 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02779 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02780 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02781 default: NOT_REACHED();
02782 }
02783 SetDParam(2, _date);
02784
02785
02786 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02787 SanitizeFilename(buf);
02788 }
02789
02790 #if 0
02791
02797 int GetSavegameType(char *file)
02798 {
02799 const SaveLoadFormat *fmt;
02800 uint32 hdr;
02801 FILE *f;
02802 int mode = SL_OLD_LOAD;
02803
02804 f = fopen(file, "rb");
02805 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02806 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02807 mode = SL_LOAD;
02808 } else {
02809
02810 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02811 if (fmt->tag == hdr) {
02812 mode = SL_LOAD;
02813 break;
02814 }
02815 }
02816 }
02817
02818 fclose(f);
02819 return mode;
02820 }
02821 #endif