00001
00002
00003
00004
00005
00006
00007
00008
00009
00024 #include "../stdafx.h"
00025 #include "../debug.h"
00026 #include "../station_base.h"
00027 #include "../thread/thread.h"
00028 #include "../town.h"
00029 #include "../network/network.h"
00030 #include "../window_func.h"
00031 #include "../strings_func.h"
00032 #include "../core/endian_func.hpp"
00033 #include "../vehicle_base.h"
00034 #include "../company_func.h"
00035 #include "../date_func.h"
00036 #include "../autoreplace_base.h"
00037 #include "../roadstop_base.h"
00038 #include "../statusbar_gui.h"
00039 #include "../fileio_func.h"
00040 #include "../gamelog.h"
00041 #include "../string_func.h"
00042 #include "../fios.h"
00043 #include "../error.h"
00044
00045 #include "table/strings.h"
00046
00047 #include "saveload_internal.h"
00048 #include "saveload_filter.h"
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236 extern const uint16 SAVEGAME_VERSION = SL_EXT_RATING;
00237
00238 SavegameType _savegame_type;
00239
00240 uint32 _ttdp_version;
00241 uint16 _sl_version;
00242 byte _sl_minor_version;
00243 char _savegame_format[8];
00244 bool _do_autosave;
00245
00247 enum SaveLoadAction {
00248 SLA_LOAD,
00249 SLA_SAVE,
00250 SLA_PTRS,
00251 SLA_NULL,
00252 SLA_LOAD_CHECK,
00253 };
00254
00255 enum NeedLength {
00256 NL_NONE = 0,
00257 NL_WANTLENGTH = 1,
00258 NL_CALCLENGTH = 2,
00259 };
00260
00262 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
00263
00265 struct ReadBuffer {
00266 byte buf[MEMORY_CHUNK_SIZE];
00267 byte *bufp;
00268 byte *bufe;
00269 LoadFilter *reader;
00270 size_t read;
00271
00276 ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
00277 {
00278 }
00279
00280 inline byte ReadByte()
00281 {
00282 if (this->bufp == this->bufe) {
00283 size_t len = this->reader->Read(this->buf, lengthof(this->buf));
00284 if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00285
00286 this->read += len;
00287 this->bufp = this->buf;
00288 this->bufe = this->buf + len;
00289 }
00290
00291 return *this->bufp++;
00292 }
00293
00298 size_t GetSize() const
00299 {
00300 return this->read - (this->bufe - this->bufp);
00301 }
00302 };
00303
00304
00306 struct MemoryDumper {
00307 AutoFreeSmallVector<byte *, 16> blocks;
00308 byte *buf;
00309 byte *bufe;
00310
00312 MemoryDumper() : buf(NULL), bufe(NULL)
00313 {
00314 }
00315
00320 inline void WriteByte(byte b)
00321 {
00322
00323 if (this->buf == this->bufe) {
00324 this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
00325 *this->blocks.Append() = this->buf;
00326 this->bufe = this->buf + MEMORY_CHUNK_SIZE;
00327 }
00328
00329 *this->buf++ = b;
00330 }
00331
00336 void Flush(SaveFilter *writer)
00337 {
00338 uint i = 0;
00339 size_t t = this->GetSize();
00340
00341 while (t > 0) {
00342 size_t to_write = min(MEMORY_CHUNK_SIZE, t);
00343
00344 writer->Write(this->blocks[i++], to_write);
00345 t -= to_write;
00346 }
00347
00348 writer->Finish();
00349 }
00350
00355 size_t GetSize() const
00356 {
00357 return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
00358 }
00359 };
00360
00362 struct SaveLoadParams {
00363 SaveLoadAction action;
00364 NeedLength need_length;
00365 byte block_mode;
00366 bool error;
00367
00368 size_t obj_len;
00369 int array_index, last_array_index;
00370
00371 MemoryDumper *dumper;
00372 SaveFilter *sf;
00373
00374 ReadBuffer *reader;
00375 LoadFilter *lf;
00376
00377 StringID error_str;
00378 char *extra_msg;
00379
00380 byte ff_state;
00381 bool saveinprogress;
00382 };
00383
00384 static SaveLoadParams _sl;
00385
00386
00387 extern const ChunkHandler _gamelog_chunk_handlers[];
00388 extern const ChunkHandler _map_chunk_handlers[];
00389 extern const ChunkHandler _misc_chunk_handlers[];
00390 extern const ChunkHandler _name_chunk_handlers[];
00391 extern const ChunkHandler _cheat_chunk_handlers[] ;
00392 extern const ChunkHandler _setting_chunk_handlers[];
00393 extern const ChunkHandler _company_chunk_handlers[];
00394 extern const ChunkHandler _engine_chunk_handlers[];
00395 extern const ChunkHandler _veh_chunk_handlers[];
00396 extern const ChunkHandler _waypoint_chunk_handlers[];
00397 extern const ChunkHandler _depot_chunk_handlers[];
00398 extern const ChunkHandler _order_chunk_handlers[];
00399 extern const ChunkHandler _town_chunk_handlers[];
00400 extern const ChunkHandler _sign_chunk_handlers[];
00401 extern const ChunkHandler _station_chunk_handlers[];
00402 extern const ChunkHandler _industry_chunk_handlers[];
00403 extern const ChunkHandler _economy_chunk_handlers[];
00404 extern const ChunkHandler _subsidy_chunk_handlers[];
00405 extern const ChunkHandler _goal_chunk_handlers[];
00406 extern const ChunkHandler _ai_chunk_handlers[];
00407 extern const ChunkHandler _game_chunk_handlers[];
00408 extern const ChunkHandler _animated_tile_chunk_handlers[];
00409 extern const ChunkHandler _newgrf_chunk_handlers[];
00410 extern const ChunkHandler _group_chunk_handlers[];
00411 extern const ChunkHandler _cargopacket_chunk_handlers[];
00412 extern const ChunkHandler _autoreplace_chunk_handlers[];
00413 extern const ChunkHandler _labelmaps_chunk_handlers[];
00414 extern const ChunkHandler _linkgraph_chunk_handlers[];
00415 extern const ChunkHandler _airport_chunk_handlers[];
00416 extern const ChunkHandler _object_chunk_handlers[];
00417 extern const ChunkHandler _persistent_storage_chunk_handlers[];
00418
00420 static const ChunkHandler * const _chunk_handlers[] = {
00421 _gamelog_chunk_handlers,
00422 _map_chunk_handlers,
00423 _misc_chunk_handlers,
00424 _name_chunk_handlers,
00425 _cheat_chunk_handlers,
00426 _setting_chunk_handlers,
00427 _veh_chunk_handlers,
00428 _waypoint_chunk_handlers,
00429 _depot_chunk_handlers,
00430 _order_chunk_handlers,
00431 _industry_chunk_handlers,
00432 _economy_chunk_handlers,
00433 _subsidy_chunk_handlers,
00434 _goal_chunk_handlers,
00435 _engine_chunk_handlers,
00436 _town_chunk_handlers,
00437 _sign_chunk_handlers,
00438 _station_chunk_handlers,
00439 _company_chunk_handlers,
00440 _ai_chunk_handlers,
00441 _game_chunk_handlers,
00442 _animated_tile_chunk_handlers,
00443 _newgrf_chunk_handlers,
00444 _group_chunk_handlers,
00445 _cargopacket_chunk_handlers,
00446 _autoreplace_chunk_handlers,
00447 _labelmaps_chunk_handlers,
00448 _linkgraph_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 } else {
01090 *(char **)ptr = MallocT<char>(len + 1);
01091 ptr = *(char **)ptr;
01092 SlCopyBytes(ptr, len);
01093 }
01094 break;
01095 }
01096
01097 ((char *)ptr)[len] = '\0';
01098 StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
01099 if ((conv & SLF_ALLOW_CONTROL) != 0) {
01100 settings = settings | SVS_ALLOW_CONTROL_CODE;
01101 }
01102 if ((conv & SLF_ALLOW_NEWLINE) != 0) {
01103 settings = settings | SVS_ALLOW_NEWLINE;
01104 }
01105 str_validate((char *)ptr, (char *)ptr + len, settings);
01106 break;
01107 }
01108 case SLA_PTRS: break;
01109 case SLA_NULL: break;
01110 default: NOT_REACHED();
01111 }
01112 }
01113
01119 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01120 {
01121 return SlCalcConvFileLen(conv) * length;
01122 }
01123
01130 void SlArray(void *array, size_t length, VarType conv)
01131 {
01132 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01133
01134
01135 if (_sl.need_length != NL_NONE) {
01136 SlSetLength(SlCalcArrayLen(length, conv));
01137
01138 if (_sl.need_length == NL_CALCLENGTH) return;
01139 }
01140
01141
01142
01143 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01144
01145 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01146 conv == SLE_INT32 || conv == SLE_UINT32) {
01147 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01148 return;
01149 }
01150
01151 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01152 for (uint i = 0; i < length; i++) {
01153 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01154 }
01155 return;
01156 }
01157 }
01158
01159
01160
01161 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01162 SlCopyBytes(array, length);
01163 } else {
01164 byte *a = (byte*)array;
01165 byte mem_size = SlCalcConvMemLen(conv);
01166
01167 for (; length != 0; length --) {
01168 SlSaveLoadConv(a, conv);
01169 a += mem_size;
01170 }
01171 }
01172 }
01173
01174
01185 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01186 {
01187 assert(_sl.action == SLA_SAVE);
01188
01189 if (obj == NULL) return 0;
01190
01191 switch (rt) {
01192 case REF_VEHICLE_OLD:
01193 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01194 case REF_STATION: return ((const Station*)obj)->index + 1;
01195 case REF_TOWN: return ((const Town*)obj)->index + 1;
01196 case REF_ORDER: return ((const Order*)obj)->index + 1;
01197 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01198 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01199 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01200 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01201 case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
01202 default: NOT_REACHED();
01203 }
01204 }
01205
01216 static void *IntToReference(size_t index, SLRefType rt)
01217 {
01218 assert_compile(sizeof(size_t) <= sizeof(void *));
01219
01220 assert(_sl.action == SLA_PTRS);
01221
01222
01223
01224 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01225 rt = REF_VEHICLE;
01226 }
01227
01228
01229 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01230
01231
01232
01233 if (rt != REF_VEHICLE_OLD) index--;
01234
01235 switch (rt) {
01236 case REF_ORDERLIST:
01237 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01238 SlErrorCorrupt("Referencing invalid OrderList");
01239
01240 case REF_ORDER:
01241 if (Order::IsValidID(index)) return Order::Get(index);
01242
01243 if (IsSavegameVersionBefore(5, 2)) return NULL;
01244 SlErrorCorrupt("Referencing invalid Order");
01245
01246 case REF_VEHICLE_OLD:
01247 case REF_VEHICLE:
01248 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01249 SlErrorCorrupt("Referencing invalid Vehicle");
01250
01251 case REF_STATION:
01252 if (Station::IsValidID(index)) return Station::Get(index);
01253 SlErrorCorrupt("Referencing invalid Station");
01254
01255 case REF_TOWN:
01256 if (Town::IsValidID(index)) return Town::Get(index);
01257 SlErrorCorrupt("Referencing invalid Town");
01258
01259 case REF_ROADSTOPS:
01260 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01261 SlErrorCorrupt("Referencing invalid RoadStop");
01262
01263 case REF_ENGINE_RENEWS:
01264 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01265 SlErrorCorrupt("Referencing invalid EngineRenew");
01266
01267 case REF_CARGO_PACKET:
01268 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01269 SlErrorCorrupt("Referencing invalid CargoPacket");
01270
01271 case REF_STORAGE:
01272 if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index);
01273 SlErrorCorrupt("Referencing invalid PersistentStorage");
01274
01275 default: NOT_REACHED();
01276 }
01277 }
01278
01283 static inline size_t SlCalcListLen(const void *list)
01284 {
01285 const std::list<void *> *l = (const std::list<void *> *) list;
01286
01287 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01288
01289
01290 return l->size() * type_size + type_size;
01291 }
01292
01293
01299 static void SlList(void *list, SLRefType conv)
01300 {
01301
01302 if (_sl.need_length != NL_NONE) {
01303 SlSetLength(SlCalcListLen(list));
01304
01305 if (_sl.need_length == NL_CALCLENGTH) return;
01306 }
01307
01308 typedef std::list<void *> PtrList;
01309 PtrList *l = (PtrList *)list;
01310
01311 switch (_sl.action) {
01312 case SLA_SAVE: {
01313 SlWriteUint32((uint32)l->size());
01314
01315 PtrList::iterator iter;
01316 for (iter = l->begin(); iter != l->end(); ++iter) {
01317 void *ptr = *iter;
01318 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01319 }
01320 break;
01321 }
01322 case SLA_LOAD_CHECK:
01323 case SLA_LOAD: {
01324 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01325
01326
01327 for (size_t i = 0; i < length; i++) {
01328 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01329 l->push_back((void *)data);
01330 }
01331 break;
01332 }
01333 case SLA_PTRS: {
01334 PtrList temp = *l;
01335
01336 l->clear();
01337 PtrList::iterator iter;
01338 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01339 void *ptr = IntToReference((size_t)*iter, conv);
01340 l->push_back(ptr);
01341 }
01342 break;
01343 }
01344 case SLA_NULL:
01345 l->clear();
01346 break;
01347 default: NOT_REACHED();
01348 }
01349 }
01350
01351
01353 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01354 {
01355 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01356 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01357
01358 return true;
01359 }
01360
01366 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01367 {
01368 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01369 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01370 return true;
01371 }
01372
01373 return false;
01374 }
01375
01382 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01383 {
01384 size_t length = 0;
01385
01386
01387 for (; sld->cmd != SL_END; sld++) {
01388 length += SlCalcObjMemberLength(object, sld);
01389 }
01390 return length;
01391 }
01392
01393 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01394 {
01395 assert(_sl.action == SLA_SAVE);
01396
01397 switch (sld->cmd) {
01398 case SL_VAR:
01399 case SL_REF:
01400 case SL_ARR:
01401 case SL_STR:
01402 case SL_LST:
01403
01404 if (!SlIsObjectValidInSavegame(sld)) break;
01405
01406 switch (sld->cmd) {
01407 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01408 case SL_REF: return SlCalcRefLen();
01409 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01410 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01411 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01412 default: NOT_REACHED();
01413 }
01414 break;
01415 case SL_WRITEBYTE: return 1;
01416 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01417 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01418 default: NOT_REACHED();
01419 }
01420 return 0;
01421 }
01422
01423
01424 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01425 {
01426 VarType conv = GB(sld->conv, 0, 8);
01427 switch (sld->cmd) {
01428 case SL_VAR:
01429 case SL_REF:
01430 case SL_ARR:
01431 case SL_STR:
01432 case SL_LST:
01433
01434 if (!SlIsObjectValidInSavegame(sld)) return false;
01435 if (SlSkipVariableOnLoad(sld)) return false;
01436
01437 switch (sld->cmd) {
01438 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01439 case SL_REF:
01440 switch (_sl.action) {
01441 case SLA_SAVE:
01442 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01443 break;
01444 case SLA_LOAD_CHECK:
01445 case SLA_LOAD:
01446 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01447 break;
01448 case SLA_PTRS:
01449 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01450 break;
01451 case SLA_NULL:
01452 *(void **)ptr = NULL;
01453 break;
01454 default: NOT_REACHED();
01455 }
01456 break;
01457 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01458 case SL_STR: SlString(ptr, sld->length, sld->conv); break;
01459 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01460 default: NOT_REACHED();
01461 }
01462 break;
01463
01464
01465
01466
01467
01468
01469 case SL_WRITEBYTE:
01470 switch (_sl.action) {
01471 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01472 case SLA_LOAD_CHECK:
01473 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01474 case SLA_PTRS: break;
01475 case SLA_NULL: break;
01476 default: NOT_REACHED();
01477 }
01478 break;
01479
01480
01481 case SL_VEH_INCLUDE:
01482 SlObject(ptr, GetVehicleDescription(VEH_END));
01483 break;
01484
01485 case SL_ST_INCLUDE:
01486 SlObject(ptr, GetBaseStationDescription());
01487 break;
01488
01489 default: NOT_REACHED();
01490 }
01491 return true;
01492 }
01493
01499 void SlObject(void *object, const SaveLoad *sld)
01500 {
01501
01502 if (_sl.need_length != NL_NONE) {
01503 SlSetLength(SlCalcObjLength(object, sld));
01504 if (_sl.need_length == NL_CALCLENGTH) return;
01505 }
01506
01507 for (; sld->cmd != SL_END; sld++) {
01508 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01509 SlObjectMember(ptr, sld);
01510 }
01511 }
01512
01517 void SlGlobList(const SaveLoadGlobVarList *sldg)
01518 {
01519 SlObject(NULL, (const SaveLoad*)sldg);
01520 }
01521
01527 void SlAutolength(AutolengthProc *proc, void *arg)
01528 {
01529 size_t offs;
01530
01531 assert(_sl.action == SLA_SAVE);
01532
01533
01534 _sl.need_length = NL_CALCLENGTH;
01535 _sl.obj_len = 0;
01536 proc(arg);
01537
01538
01539 _sl.need_length = NL_WANTLENGTH;
01540 SlSetLength(_sl.obj_len);
01541
01542 offs = _sl.dumper->GetSize() + _sl.obj_len;
01543
01544
01545 proc(arg);
01546
01547 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01548 }
01549
01554 static void SlLoadChunk(const ChunkHandler *ch)
01555 {
01556 byte m = SlReadByte();
01557 size_t len;
01558 size_t endoffs;
01559
01560 _sl.block_mode = m;
01561 _sl.obj_len = 0;
01562
01563 switch (m) {
01564 case CH_ARRAY:
01565 _sl.array_index = 0;
01566 ch->load_proc();
01567 break;
01568 case CH_SPARSE_ARRAY:
01569 ch->load_proc();
01570 break;
01571 default:
01572 if ((m & 0xF) == CH_RIFF) {
01573
01574 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01575 len += SlReadUint16();
01576 _sl.obj_len = len;
01577 endoffs = _sl.reader->GetSize() + len;
01578 ch->load_proc();
01579 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01580 } else {
01581 SlErrorCorrupt("Invalid chunk type");
01582 }
01583 break;
01584 }
01585 }
01586
01592 static void SlLoadCheckChunk(const ChunkHandler *ch)
01593 {
01594 byte m = SlReadByte();
01595 size_t len;
01596 size_t endoffs;
01597
01598 _sl.block_mode = m;
01599 _sl.obj_len = 0;
01600
01601 switch (m) {
01602 case CH_ARRAY:
01603 _sl.array_index = 0;
01604 if (ch->load_check_proc) {
01605 ch->load_check_proc();
01606 } else {
01607 SlSkipArray();
01608 }
01609 break;
01610 case CH_SPARSE_ARRAY:
01611 if (ch->load_check_proc) {
01612 ch->load_check_proc();
01613 } else {
01614 SlSkipArray();
01615 }
01616 break;
01617 default:
01618 if ((m & 0xF) == CH_RIFF) {
01619
01620 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01621 len += SlReadUint16();
01622 _sl.obj_len = len;
01623 endoffs = _sl.reader->GetSize() + len;
01624 if (ch->load_check_proc) {
01625 ch->load_check_proc();
01626 } else {
01627 SlSkipBytes(len);
01628 }
01629 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01630 } else {
01631 SlErrorCorrupt("Invalid chunk type");
01632 }
01633 break;
01634 }
01635 }
01636
01641 static ChunkSaveLoadProc *_stub_save_proc;
01642
01648 static inline void SlStubSaveProc2(void *arg)
01649 {
01650 _stub_save_proc();
01651 }
01652
01658 static void SlStubSaveProc()
01659 {
01660 SlAutolength(SlStubSaveProc2, NULL);
01661 }
01662
01668 static void SlSaveChunk(const ChunkHandler *ch)
01669 {
01670 ChunkSaveLoadProc *proc = ch->save_proc;
01671
01672
01673 if (proc == NULL) return;
01674
01675 SlWriteUint32(ch->id);
01676 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01677
01678 if (ch->flags & CH_AUTO_LENGTH) {
01679
01680 _stub_save_proc = proc;
01681 proc = SlStubSaveProc;
01682 }
01683
01684 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01685 switch (ch->flags & CH_TYPE_MASK) {
01686 case CH_RIFF:
01687 _sl.need_length = NL_WANTLENGTH;
01688 proc();
01689 break;
01690 case CH_ARRAY:
01691 _sl.last_array_index = 0;
01692 SlWriteByte(CH_ARRAY);
01693 proc();
01694 SlWriteArrayLength(0);
01695 break;
01696 case CH_SPARSE_ARRAY:
01697 SlWriteByte(CH_SPARSE_ARRAY);
01698 proc();
01699 SlWriteArrayLength(0);
01700 break;
01701 default: NOT_REACHED();
01702 }
01703 }
01704
01706 static void SlSaveChunks()
01707 {
01708 FOR_ALL_CHUNK_HANDLERS(ch) {
01709 SlSaveChunk(ch);
01710 }
01711
01712
01713 SlWriteUint32(0);
01714 }
01715
01722 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01723 {
01724 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01725 return NULL;
01726 }
01727
01729 static void SlLoadChunks()
01730 {
01731 uint32 id;
01732 const ChunkHandler *ch;
01733
01734 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01735 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01736
01737 ch = SlFindChunkHandler(id);
01738 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01739 SlLoadChunk(ch);
01740 }
01741 }
01742
01744 static void SlLoadCheckChunks()
01745 {
01746 uint32 id;
01747 const ChunkHandler *ch;
01748
01749 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01750 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01751
01752 ch = SlFindChunkHandler(id);
01753 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01754 SlLoadCheckChunk(ch);
01755 }
01756 }
01757
01759 static void SlFixPointers()
01760 {
01761 _sl.action = SLA_PTRS;
01762
01763 DEBUG(sl, 1, "Fixing pointers");
01764
01765 FOR_ALL_CHUNK_HANDLERS(ch) {
01766 if (ch->ptrs_proc != NULL) {
01767 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01768 ch->ptrs_proc();
01769 }
01770 }
01771
01772 DEBUG(sl, 1, "All pointers fixed");
01773
01774 assert(_sl.action == SLA_PTRS);
01775 }
01776
01777
01779 struct FileReader : LoadFilter {
01780 FILE *file;
01781 long begin;
01782
01787 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01788 {
01789 }
01790
01792 ~FileReader()
01793 {
01794 if (this->file != NULL) fclose(this->file);
01795 this->file = NULL;
01796
01797
01798 _sl.sf = NULL;
01799 }
01800
01801 size_t Read(byte *buf, size_t size)
01802 {
01803
01804 if (this->file == NULL) return 0;
01805
01806 return fread(buf, 1, size, this->file);
01807 }
01808
01809 void Reset()
01810 {
01811 clearerr(this->file);
01812 fseek(this->file, this->begin, SEEK_SET);
01813 }
01814 };
01815
01817 struct FileWriter : SaveFilter {
01818 FILE *file;
01819
01824 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01825 {
01826 }
01827
01829 ~FileWriter()
01830 {
01831 this->Finish();
01832
01833
01834 _sl.sf = NULL;
01835 }
01836
01837 void Write(byte *buf, size_t size)
01838 {
01839
01840 if (this->file == NULL) return;
01841
01842 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01843 }
01844
01845 void Finish()
01846 {
01847 if (this->file != NULL) fclose(this->file);
01848 this->file = NULL;
01849 }
01850 };
01851
01852
01853
01854
01855
01856 #ifdef WITH_LZO
01857 #include <lzo/lzo1x.h>
01858
01860 static const uint LZO_BUFFER_SIZE = 8192;
01861
01863 struct LZOLoadFilter : LoadFilter {
01868 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01869 {
01870 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01871 }
01872
01873 size_t Read(byte *buf, size_t ssize)
01874 {
01875 assert(ssize >= LZO_BUFFER_SIZE);
01876
01877
01878 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01879 uint32 tmp[2];
01880 uint32 size;
01881 lzo_uint len;
01882
01883
01884 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01885
01886
01887 ((uint32*)out)[0] = size = tmp[1];
01888
01889 if (_sl_version != 0) {
01890 tmp[0] = TO_BE32(tmp[0]);
01891 size = TO_BE32(size);
01892 }
01893
01894 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01895
01896
01897 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01898
01899
01900 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01901
01902
01903 lzo1x_decompress(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01904 return len;
01905 }
01906 };
01907
01909 struct LZOSaveFilter : SaveFilter {
01915 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01916 {
01917 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01918 }
01919
01920 void Write(byte *buf, size_t size)
01921 {
01922 const lzo_bytep in = buf;
01923
01924 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01925 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01926 lzo_uint outlen;
01927
01928 do {
01929
01930 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01931 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01932 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01933 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01934 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01935
01936
01937 size -= len;
01938 in += len;
01939 } while (size > 0);
01940 }
01941 };
01942
01943 #endif
01944
01945
01946
01947
01948
01950 struct NoCompLoadFilter : LoadFilter {
01955 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01956 {
01957 }
01958
01959 size_t Read(byte *buf, size_t size)
01960 {
01961 return this->chain->Read(buf, size);
01962 }
01963 };
01964
01966 struct NoCompSaveFilter : SaveFilter {
01972 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01973 {
01974 }
01975
01976 void Write(byte *buf, size_t size)
01977 {
01978 this->chain->Write(buf, size);
01979 }
01980 };
01981
01982
01983
01984
01985
01986 #if defined(WITH_ZLIB)
01987 #include <zlib.h>
01988
01990 struct ZlibLoadFilter : LoadFilter {
01991 z_stream z;
01992 byte fread_buf[MEMORY_CHUNK_SIZE];
01993
01998 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01999 {
02000 memset(&this->z, 0, sizeof(this->z));
02001 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02002 }
02003
02005 ~ZlibLoadFilter()
02006 {
02007 inflateEnd(&this->z);
02008 }
02009
02010 size_t Read(byte *buf, size_t size)
02011 {
02012 this->z.next_out = buf;
02013 this->z.avail_out = (uint)size;
02014
02015 do {
02016
02017 if (this->z.avail_in == 0) {
02018 this->z.next_in = this->fread_buf;
02019 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02020 }
02021
02022
02023 int r = inflate(&this->z, 0);
02024 if (r == Z_STREAM_END) break;
02025
02026 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02027 } while (this->z.avail_out != 0);
02028
02029 return size - this->z.avail_out;
02030 }
02031 };
02032
02034 struct ZlibSaveFilter : SaveFilter {
02035 z_stream z;
02036
02042 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02043 {
02044 memset(&this->z, 0, sizeof(this->z));
02045 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02046 }
02047
02049 ~ZlibSaveFilter()
02050 {
02051 deflateEnd(&this->z);
02052 }
02053
02060 void WriteLoop(byte *p, size_t len, int mode)
02061 {
02062 byte buf[MEMORY_CHUNK_SIZE];
02063 uint n;
02064 this->z.next_in = p;
02065 this->z.avail_in = (uInt)len;
02066 do {
02067 this->z.next_out = buf;
02068 this->z.avail_out = sizeof(buf);
02069
02077 int r = deflate(&this->z, mode);
02078
02079
02080 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02081 this->chain->Write(buf, n);
02082 }
02083 if (r == Z_STREAM_END) break;
02084
02085 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02086 } while (this->z.avail_in || !this->z.avail_out);
02087 }
02088
02089 void Write(byte *buf, size_t size)
02090 {
02091 this->WriteLoop(buf, size, 0);
02092 }
02093
02094 void Finish()
02095 {
02096 this->WriteLoop(NULL, 0, Z_FINISH);
02097 this->chain->Finish();
02098 }
02099 };
02100
02101 #endif
02102
02103
02104
02105
02106
02107 #if defined(WITH_LZMA)
02108 #include <lzma.h>
02109
02116 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02117
02119 struct LZMALoadFilter : LoadFilter {
02120 lzma_stream lzma;
02121 byte fread_buf[MEMORY_CHUNK_SIZE];
02122
02127 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02128 {
02129
02130 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02131 }
02132
02134 ~LZMALoadFilter()
02135 {
02136 lzma_end(&this->lzma);
02137 }
02138
02139 size_t Read(byte *buf, size_t size)
02140 {
02141 this->lzma.next_out = buf;
02142 this->lzma.avail_out = size;
02143
02144 do {
02145
02146 if (this->lzma.avail_in == 0) {
02147 this->lzma.next_in = this->fread_buf;
02148 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02149 }
02150
02151
02152 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02153 if (r == LZMA_STREAM_END) break;
02154 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02155 } while (this->lzma.avail_out != 0);
02156
02157 return size - this->lzma.avail_out;
02158 }
02159 };
02160
02162 struct LZMASaveFilter : SaveFilter {
02163 lzma_stream lzma;
02164
02170 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02171 {
02172 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02173 }
02174
02176 ~LZMASaveFilter()
02177 {
02178 lzma_end(&this->lzma);
02179 }
02180
02187 void WriteLoop(byte *p, size_t len, lzma_action action)
02188 {
02189 byte buf[MEMORY_CHUNK_SIZE];
02190 size_t n;
02191 this->lzma.next_in = p;
02192 this->lzma.avail_in = len;
02193 do {
02194 this->lzma.next_out = buf;
02195 this->lzma.avail_out = sizeof(buf);
02196
02197 lzma_ret r = lzma_code(&this->lzma, action);
02198
02199
02200 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02201 this->chain->Write(buf, n);
02202 }
02203 if (r == LZMA_STREAM_END) break;
02204 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02205 } while (this->lzma.avail_in || !this->lzma.avail_out);
02206 }
02207
02208 void Write(byte *buf, size_t size)
02209 {
02210 this->WriteLoop(buf, size, LZMA_RUN);
02211 }
02212
02213 void Finish()
02214 {
02215 this->WriteLoop(NULL, 0, LZMA_FINISH);
02216 this->chain->Finish();
02217 }
02218 };
02219
02220 #endif
02221
02222
02223
02224
02225
02227 struct SaveLoadFormat {
02228 const char *name;
02229 uint32 tag;
02230
02231 LoadFilter *(*init_load)(LoadFilter *chain);
02232 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02233
02234 byte min_compression;
02235 byte default_compression;
02236 byte max_compression;
02237 };
02238
02240 static const SaveLoadFormat _saveload_formats[] = {
02241 #if defined(WITH_LZO)
02242
02243 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02244 #else
02245 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02246 #endif
02247
02248 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02249 #if defined(WITH_ZLIB)
02250
02251
02252
02253 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02254 #else
02255 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02256 #endif
02257 #if defined(WITH_LZMA)
02258
02259
02260
02261
02262
02263 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02264 #else
02265 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02266 #endif
02267 };
02268
02276 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02277 {
02278 const SaveLoadFormat *def = lastof(_saveload_formats);
02279
02280
02281 while (!def->init_write) def--;
02282
02283 if (!StrEmpty(s)) {
02284
02285 char *complevel = strrchr(s, ':');
02286 if (complevel != NULL) *complevel = '\0';
02287
02288 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02289 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02290 *compression_level = slf->default_compression;
02291 if (complevel != NULL) {
02292
02293
02294
02295 *complevel = ':';
02296 complevel++;
02297
02298
02299 char *end;
02300 long level = strtol(complevel, &end, 10);
02301 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02302 SetDParamStr(0, complevel);
02303 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL);
02304 } else {
02305 *compression_level = level;
02306 }
02307 }
02308 return slf;
02309 }
02310 }
02311
02312 SetDParamStr(0, s);
02313 SetDParamStr(1, def->name);
02314 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL);
02315
02316
02317 if (complevel != NULL) *complevel = ':';
02318 }
02319 *compression_level = def->default_compression;
02320 return def;
02321 }
02322
02323
02324 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02325 extern bool AfterLoadGame();
02326 extern bool LoadOldSaveGame(const char *file);
02327
02331 static inline void ClearSaveLoadState()
02332 {
02333 delete _sl.dumper;
02334 _sl.dumper = NULL;
02335
02336 delete _sl.sf;
02337 _sl.sf = NULL;
02338
02339 delete _sl.reader;
02340 _sl.reader = NULL;
02341
02342 delete _sl.lf;
02343 _sl.lf = NULL;
02344 }
02345
02351 static void SaveFileStart()
02352 {
02353 _sl.ff_state = _fast_forward;
02354 _fast_forward = 0;
02355 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02356
02357 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02358 _sl.saveinprogress = true;
02359 }
02360
02362 static void SaveFileDone()
02363 {
02364 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02365 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02366
02367 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02368 _sl.saveinprogress = false;
02369 }
02370
02372 void SetSaveLoadError(StringID str)
02373 {
02374 _sl.error_str = str;
02375 }
02376
02378 const char *GetSaveLoadErrorString()
02379 {
02380 SetDParam(0, _sl.error_str);
02381 SetDParamStr(1, _sl.extra_msg);
02382
02383 static char err_str[512];
02384 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02385 return err_str;
02386 }
02387
02389 static void SaveFileError()
02390 {
02391 SetDParamStr(0, GetSaveLoadErrorString());
02392 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02393 SaveFileDone();
02394 }
02395
02400 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02401 {
02402 try {
02403 byte compression;
02404 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02405
02406
02407 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02408 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02409
02410 _sl.sf = fmt->init_write(_sl.sf, compression);
02411 _sl.dumper->Flush(_sl.sf);
02412
02413 ClearSaveLoadState();
02414
02415 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02416
02417 return SL_OK;
02418 } catch (...) {
02419 ClearSaveLoadState();
02420
02421 AsyncSaveFinishProc asfp = SaveFileDone;
02422
02423
02424
02425 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02426
02427 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02428 asfp = SaveFileError;
02429 }
02430
02431 if (threaded) {
02432 SetAsyncSaveFinish(asfp);
02433 } else {
02434 asfp();
02435 }
02436 return SL_ERROR;
02437 }
02438 }
02439
02441 static void SaveFileToDiskThread(void *arg)
02442 {
02443 SaveFileToDisk(true);
02444 }
02445
02446 void WaitTillSaved()
02447 {
02448 if (_save_thread == NULL) return;
02449
02450 _save_thread->Join();
02451 delete _save_thread;
02452 _save_thread = NULL;
02453
02454
02455 ProcessAsyncSaveFinish();
02456 }
02457
02466 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02467 {
02468 assert(!_sl.saveinprogress);
02469
02470 _sl.dumper = new MemoryDumper();
02471 _sl.sf = writer;
02472
02473 _sl_version = SAVEGAME_VERSION;
02474
02475 SaveViewportBeforeSaveGame();
02476 SlSaveChunks();
02477
02478 SaveFileStart();
02479 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02480 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02481
02482 SaveOrLoadResult result = SaveFileToDisk(false);
02483 SaveFileDone();
02484
02485 return result;
02486 }
02487
02488 return SL_OK;
02489 }
02490
02497 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02498 {
02499 try {
02500 _sl.action = SLA_SAVE;
02501 return DoSave(writer, threaded);
02502 } catch (...) {
02503 ClearSaveLoadState();
02504 return SL_ERROR;
02505 }
02506 }
02507
02514 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02515 {
02516 _sl.lf = reader;
02517
02518 if (load_check) {
02519
02520 _load_check_data.Clear();
02521
02522 _load_check_data.checkable = true;
02523 }
02524
02525 uint32 hdr[2];
02526 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02527
02528
02529 const SaveLoadFormat *fmt = _saveload_formats;
02530 for (;;) {
02531
02532 if (fmt == endof(_saveload_formats)) {
02533 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02534 _sl.lf->Reset();
02535 _sl_version = 0;
02536 _sl_minor_version = 0;
02537
02538
02539 fmt = _saveload_formats;
02540 for (;;) {
02541 if (fmt == endof(_saveload_formats)) {
02542
02543 NOT_REACHED();
02544 }
02545 if (fmt->tag == TO_BE32X('OTTD')) break;
02546 fmt++;
02547 }
02548 break;
02549 }
02550
02551 if (fmt->tag == hdr[0]) {
02552
02553 _sl_version = TO_BE32(hdr[1]) >> 16;
02554
02555
02556
02557 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02558
02559 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02560
02561
02562 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02563 break;
02564 }
02565
02566 fmt++;
02567 }
02568
02569
02570 if (fmt->init_load == NULL) {
02571 char err_str[64];
02572 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02573 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02574 }
02575
02576 _sl.lf = fmt->init_load(_sl.lf);
02577 _sl.reader = new ReadBuffer(_sl.lf);
02578 _next_offs = 0;
02579
02580 if (!load_check) {
02581
02582
02583
02584 InitializeGame(256, 256, true, true);
02585
02586 GamelogReset();
02587
02588 if (IsSavegameVersionBefore(4)) {
02589
02590
02591
02592
02593
02594
02595
02596
02597
02598
02599
02600
02601
02602
02603
02604
02605
02606
02607
02608
02609
02610 ClearGRFConfigList(&_grfconfig);
02611 }
02612 }
02613
02614 if (load_check) {
02615
02616
02617 SlLoadCheckChunks();
02618 } else {
02619
02620 SlLoadChunks();
02621 SlFixPointers();
02622 }
02623
02624 ClearSaveLoadState();
02625
02626 _savegame_type = SGT_OTTD;
02627
02628 if (load_check) {
02629
02630 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02631 } else {
02632 GamelogStartAction(GLAT_LOAD);
02633
02634
02635
02636 if (!AfterLoadGame()) {
02637 GamelogStopAction();
02638 return SL_REINIT;
02639 }
02640
02641 GamelogStopAction();
02642 }
02643
02644 return SL_OK;
02645 }
02646
02652 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02653 {
02654 try {
02655 _sl.action = SLA_LOAD;
02656 return DoLoad(reader, false);
02657 } catch (...) {
02658 ClearSaveLoadState();
02659 return SL_REINIT;
02660 }
02661 }
02662
02672 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02673 {
02674
02675 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02676
02677 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02678 return SL_OK;
02679 }
02680 WaitTillSaved();
02681
02682
02683 if (mode == SL_OLD_LOAD) {
02684 InitializeGame(256, 256, true, true);
02685
02686
02687
02688
02689
02690 ClearGRFConfigList(&_grfconfig);
02691 GamelogReset();
02692 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02693 _sl_version = 0;
02694 _sl_minor_version = 0;
02695 GamelogStartAction(GLAT_LOAD);
02696 if (!AfterLoadGame()) {
02697 GamelogStopAction();
02698 return SL_REINIT;
02699 }
02700 GamelogStopAction();
02701 return SL_OK;
02702 }
02703
02704 switch (mode) {
02705 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02706 case SL_LOAD: _sl.action = SLA_LOAD; break;
02707 case SL_SAVE: _sl.action = SLA_SAVE; break;
02708 default: NOT_REACHED();
02709 }
02710
02711 try {
02712 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02713
02714
02715 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02716 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02717 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
02718
02719 if (fh == NULL) {
02720 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02721 }
02722
02723 if (mode == SL_SAVE) {
02724 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02725 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02726
02727 return DoSave(new FileWriter(fh), threaded);
02728 }
02729
02730
02731 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02732 DEBUG(desync, 1, "load: %s", filename);
02733 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02734 } catch (...) {
02735 ClearSaveLoadState();
02736
02737
02738 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02739
02740
02741 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02742 }
02743 }
02744
02746 void DoExitSave()
02747 {
02748 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02749 }
02750
02756 void GenerateDefaultSaveName(char *buf, const char *last)
02757 {
02758
02759
02760
02761 CompanyID cid = _local_company;
02762 if (!Company::IsValidID(cid)) {
02763 const Company *c;
02764 FOR_ALL_COMPANIES(c) {
02765 cid = c->index;
02766 break;
02767 }
02768 }
02769
02770 SetDParam(0, cid);
02771
02772
02773 switch (_settings_client.gui.date_format_in_default_names) {
02774 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02775 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02776 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02777 default: NOT_REACHED();
02778 }
02779 SetDParam(2, _date);
02780
02781
02782 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02783 SanitizeFilename(buf);
02784 }
02785
02786 #if 0
02787
02793 int GetSavegameType(char *file)
02794 {
02795 const SaveLoadFormat *fmt;
02796 uint32 hdr;
02797 FILE *f;
02798 int mode = SL_OLD_LOAD;
02799
02800 f = fopen(file, "rb");
02801 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02802 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02803 mode = SL_LOAD;
02804 } else {
02805
02806 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02807 if (fmt->tag == hdr) {
02808 mode = SL_LOAD;
02809 break;
02810 }
02811 }
02812 }
02813
02814 fclose(f);
02815 return mode;
02816 }
02817 #endif