00001
00002
00003
00004
00005
00006
00007
00008
00009
00024 #include "../stdafx.h"
00025 #include "../debug.h"
00026 #include "../station_base.h"
00027 #include "../thread/thread.h"
00028 #include "../town.h"
00029 #include "../network/network.h"
00030 #include "../window_func.h"
00031 #include "../strings_func.h"
00032 #include "../core/endian_func.hpp"
00033 #include "../vehicle_base.h"
00034 #include "../company_func.h"
00035 #include "../date_func.h"
00036 #include "../autoreplace_base.h"
00037 #include "../roadstop_base.h"
00038 #include "../statusbar_gui.h"
00039 #include "../fileio_func.h"
00040 #include "../gamelog.h"
00041 #include "../string_func.h"
00042 #include "../engine_base.h"
00043 #include "../fios.h"
00044 #include "../gui.h"
00045
00046 #include "table/strings.h"
00047
00048 #include "saveload_internal.h"
00049 #include "saveload_filter.h"
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235 extern const uint16 SAVEGAME_VERSION = SL_EXT_RATING;
00236
00237 SavegameType _savegame_type;
00238
00239 uint32 _ttdp_version;
00240 uint16 _sl_version;
00241 byte _sl_minor_version;
00242 char _savegame_format[8];
00243 bool _do_autosave;
00244
00246 enum SaveLoadAction {
00247 SLA_LOAD,
00248 SLA_SAVE,
00249 SLA_PTRS,
00250 SLA_NULL,
00251 SLA_LOAD_CHECK,
00252 };
00253
00254 enum NeedLength {
00255 NL_NONE = 0,
00256 NL_WANTLENGTH = 1,
00257 NL_CALCLENGTH = 2,
00258 };
00259
00261 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
00262
00264 struct ReadBuffer {
00265 byte buf[MEMORY_CHUNK_SIZE];
00266 byte *bufp;
00267 byte *bufe;
00268 LoadFilter *reader;
00269 size_t read;
00270
00275 ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
00276 {
00277 }
00278
00279 FORCEINLINE byte ReadByte()
00280 {
00281 if (this->bufp == this->bufe) {
00282 size_t len = this->reader->Read(this->buf, lengthof(this->buf));
00283 if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00284
00285 this->read += len;
00286 this->bufp = this->buf;
00287 this->bufe = this->buf + len;
00288 }
00289
00290 return *this->bufp++;
00291 }
00292
00297 size_t GetSize() const
00298 {
00299 return this->read - (this->bufe - this->bufp);
00300 }
00301 };
00302
00303
00305 struct MemoryDumper {
00306 AutoFreeSmallVector<byte *, 16> blocks;
00307 byte *buf;
00308 byte *bufe;
00309
00311 MemoryDumper() : buf(NULL), bufe(NULL)
00312 {
00313 }
00314
00319 FORCEINLINE void WriteByte(byte b)
00320 {
00321
00322 if (this->buf == this->bufe) {
00323 this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
00324 *this->blocks.Append() = this->buf;
00325 this->bufe = this->buf + MEMORY_CHUNK_SIZE;
00326 }
00327
00328 *this->buf++ = b;
00329 }
00330
00335 void Flush(SaveFilter *writer)
00336 {
00337 uint i = 0;
00338 size_t t = this->GetSize();
00339
00340 while (t > 0) {
00341 size_t to_write = min(MEMORY_CHUNK_SIZE, t);
00342
00343 writer->Write(this->blocks[i++], to_write);
00344 t -= to_write;
00345 }
00346
00347 writer->Finish();
00348 }
00349
00354 size_t GetSize() const
00355 {
00356 return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
00357 }
00358 };
00359
00361 struct SaveLoadParams {
00362 SaveLoadAction action;
00363 NeedLength need_length;
00364 byte block_mode;
00365 bool error;
00366
00367 size_t obj_len;
00368 int array_index, last_array_index;
00369
00370 MemoryDumper *dumper;
00371 SaveFilter *sf;
00372
00373 ReadBuffer *reader;
00374 LoadFilter *lf;
00375
00376 StringID error_str;
00377 char *extra_msg;
00378
00379 byte ff_state;
00380 bool saveinprogress;
00381 };
00382
00383 static SaveLoadParams _sl;
00384
00385
00386 extern const ChunkHandler _gamelog_chunk_handlers[];
00387 extern const ChunkHandler _map_chunk_handlers[];
00388 extern const ChunkHandler _misc_chunk_handlers[];
00389 extern const ChunkHandler _name_chunk_handlers[];
00390 extern const ChunkHandler _cheat_chunk_handlers[] ;
00391 extern const ChunkHandler _setting_chunk_handlers[];
00392 extern const ChunkHandler _company_chunk_handlers[];
00393 extern const ChunkHandler _engine_chunk_handlers[];
00394 extern const ChunkHandler _veh_chunk_handlers[];
00395 extern const ChunkHandler _waypoint_chunk_handlers[];
00396 extern const ChunkHandler _depot_chunk_handlers[];
00397 extern const ChunkHandler _order_chunk_handlers[];
00398 extern const ChunkHandler _town_chunk_handlers[];
00399 extern const ChunkHandler _sign_chunk_handlers[];
00400 extern const ChunkHandler _station_chunk_handlers[];
00401 extern const ChunkHandler _industry_chunk_handlers[];
00402 extern const ChunkHandler _economy_chunk_handlers[];
00403 extern const ChunkHandler _subsidy_chunk_handlers[];
00404 extern const ChunkHandler _ai_chunk_handlers[];
00405 extern const ChunkHandler _animated_tile_chunk_handlers[];
00406 extern const ChunkHandler _newgrf_chunk_handlers[];
00407 extern const ChunkHandler _group_chunk_handlers[];
00408 extern const ChunkHandler _cargopacket_chunk_handlers[];
00409 extern const ChunkHandler _autoreplace_chunk_handlers[];
00410 extern const ChunkHandler _labelmaps_chunk_handlers[];
00411 extern const ChunkHandler _linkgraph_chunk_handlers[];
00412 extern const ChunkHandler _airport_chunk_handlers[];
00413 extern const ChunkHandler _object_chunk_handlers[];
00414 extern const ChunkHandler _persistent_storage_chunk_handlers[];
00415
00417 static const ChunkHandler * const _chunk_handlers[] = {
00418 _gamelog_chunk_handlers,
00419 _map_chunk_handlers,
00420 _misc_chunk_handlers,
00421 _name_chunk_handlers,
00422 _cheat_chunk_handlers,
00423 _setting_chunk_handlers,
00424 _veh_chunk_handlers,
00425 _waypoint_chunk_handlers,
00426 _depot_chunk_handlers,
00427 _order_chunk_handlers,
00428 _industry_chunk_handlers,
00429 _economy_chunk_handlers,
00430 _subsidy_chunk_handlers,
00431 _engine_chunk_handlers,
00432 _town_chunk_handlers,
00433 _sign_chunk_handlers,
00434 _station_chunk_handlers,
00435 _company_chunk_handlers,
00436 _ai_chunk_handlers,
00437 _animated_tile_chunk_handlers,
00438 _newgrf_chunk_handlers,
00439 _group_chunk_handlers,
00440 _cargopacket_chunk_handlers,
00441 _autoreplace_chunk_handlers,
00442 _labelmaps_chunk_handlers,
00443 _linkgraph_chunk_handlers,
00444 _airport_chunk_handlers,
00445 _object_chunk_handlers,
00446 _persistent_storage_chunk_handlers,
00447 NULL,
00448 };
00449
00454 #define FOR_ALL_CHUNK_HANDLERS(ch) \
00455 for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \
00456 for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1)
00457
00459 static void SlNullPointers()
00460 {
00461 _sl.action = SLA_NULL;
00462
00463
00464
00465
00466 _sl_version = SAVEGAME_VERSION;
00467
00468 DEBUG(sl, 1, "Nulling pointers");
00469
00470 FOR_ALL_CHUNK_HANDLERS(ch) {
00471 if (ch->ptrs_proc != NULL) {
00472 DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00473 ch->ptrs_proc();
00474 }
00475 }
00476
00477 DEBUG(sl, 1, "All pointers nulled");
00478
00479 assert(_sl.action == SLA_NULL);
00480 }
00481
00490 void NORETURN SlError(StringID string, const char *extra_msg)
00491 {
00492
00493 if (_sl.action == SLA_LOAD_CHECK) {
00494 _load_check_data.error = string;
00495 free(_load_check_data.error_data);
00496 _load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00497 } else {
00498 _sl.error_str = string;
00499 free(_sl.extra_msg);
00500 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00501 }
00502
00503
00504
00505
00506
00507 if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00508 throw std::exception();
00509 }
00510
00518 void NORETURN SlErrorCorrupt(const char *msg)
00519 {
00520 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00521 }
00522
00523
00524 typedef void (*AsyncSaveFinishProc)();
00525 static AsyncSaveFinishProc _async_save_finish = NULL;
00526 static ThreadObject *_save_thread;
00527
00532 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00533 {
00534 if (_exit_game) return;
00535 while (_async_save_finish != NULL) CSleep(10);
00536
00537 _async_save_finish = proc;
00538 }
00539
00543 void ProcessAsyncSaveFinish()
00544 {
00545 if (_async_save_finish == NULL) return;
00546
00547 _async_save_finish();
00548
00549 _async_save_finish = NULL;
00550
00551 if (_save_thread != NULL) {
00552 _save_thread->Join();
00553 delete _save_thread;
00554 _save_thread = NULL;
00555 }
00556 }
00557
00562 byte SlReadByte()
00563 {
00564 return _sl.reader->ReadByte();
00565 }
00566
00571 void SlWriteByte(byte b)
00572 {
00573 _sl.dumper->WriteByte(b);
00574 }
00575
00576 static inline int SlReadUint16()
00577 {
00578 int x = SlReadByte() << 8;
00579 return x | SlReadByte();
00580 }
00581
00582 static inline uint32 SlReadUint32()
00583 {
00584 uint32 x = SlReadUint16() << 16;
00585 return x | SlReadUint16();
00586 }
00587
00588 static inline uint64 SlReadUint64()
00589 {
00590 uint32 x = SlReadUint32();
00591 uint32 y = SlReadUint32();
00592 return (uint64)x << 32 | y;
00593 }
00594
00595 static inline void SlWriteUint16(uint16 v)
00596 {
00597 SlWriteByte(GB(v, 8, 8));
00598 SlWriteByte(GB(v, 0, 8));
00599 }
00600
00601 static inline void SlWriteUint32(uint32 v)
00602 {
00603 SlWriteUint16(GB(v, 16, 16));
00604 SlWriteUint16(GB(v, 0, 16));
00605 }
00606
00607 static inline void SlWriteUint64(uint64 x)
00608 {
00609 SlWriteUint32((uint32)(x >> 32));
00610 SlWriteUint32((uint32)x);
00611 }
00612
00618 static inline void SlSkipBytes(size_t length)
00619 {
00620 for (; length != 0; length--) SlReadByte();
00621 }
00622
00632 static uint SlReadSimpleGamma()
00633 {
00634 uint i = SlReadByte();
00635 if (HasBit(i, 7)) {
00636 i &= ~0x80;
00637 if (HasBit(i, 6)) {
00638 i &= ~0x40;
00639 if (HasBit(i, 5)) {
00640 i &= ~0x20;
00641 if (HasBit(i, 4)) {
00642 SlErrorCorrupt("Unsupported gamma");
00643 }
00644 i = (i << 8) | SlReadByte();
00645 }
00646 i = (i << 8) | SlReadByte();
00647 }
00648 i = (i << 8) | SlReadByte();
00649 }
00650 return i;
00651 }
00652
00665 static void SlWriteSimpleGamma(size_t i)
00666 {
00667 if (i >= (1 << 7)) {
00668 if (i >= (1 << 14)) {
00669 if (i >= (1 << 21)) {
00670 assert(i < (1 << 28));
00671 SlWriteByte((byte)(0xE0 | (i >> 24)));
00672 SlWriteByte((byte)(i >> 16));
00673 } else {
00674 SlWriteByte((byte)(0xC0 | (i >> 16)));
00675 }
00676 SlWriteByte((byte)(i >> 8));
00677 } else {
00678 SlWriteByte((byte)(0x80 | (i >> 8)));
00679 }
00680 }
00681 SlWriteByte((byte)i);
00682 }
00683
00685 static inline uint SlGetGammaLength(size_t i)
00686 {
00687 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00688 }
00689
00690 static inline uint SlReadSparseIndex()
00691 {
00692 return SlReadSimpleGamma();
00693 }
00694
00695 static inline void SlWriteSparseIndex(uint index)
00696 {
00697 SlWriteSimpleGamma(index);
00698 }
00699
00700 static inline uint SlReadArrayLength()
00701 {
00702 return SlReadSimpleGamma();
00703 }
00704
00705 static inline void SlWriteArrayLength(size_t length)
00706 {
00707 SlWriteSimpleGamma(length);
00708 }
00709
00710 static inline uint SlGetArrayLength(size_t length)
00711 {
00712 return SlGetGammaLength(length);
00713 }
00714
00721 static inline uint SlCalcConvMemLen(VarType conv)
00722 {
00723 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00724 byte length = GB(conv, 4, 4);
00725
00726 switch (length << 4) {
00727 case SLE_VAR_STRB:
00728 case SLE_VAR_STRBQ:
00729 case SLE_VAR_STR:
00730 case SLE_VAR_STRQ:
00731 return SlReadArrayLength();
00732
00733 default:
00734 assert(length < lengthof(conv_mem_size));
00735 return conv_mem_size[length];
00736 }
00737 }
00738
00745 static inline byte SlCalcConvFileLen(VarType conv)
00746 {
00747 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00748 byte length = GB(conv, 0, 4);
00749 assert(length < lengthof(conv_file_size));
00750 return conv_file_size[length];
00751 }
00752
00754 static inline size_t SlCalcRefLen()
00755 {
00756 return IsSavegameVersionBefore(69) ? 2 : 4;
00757 }
00758
00759 void SlSetArrayIndex(uint index)
00760 {
00761 _sl.need_length = NL_WANTLENGTH;
00762 _sl.array_index = index;
00763 }
00764
00765 static size_t _next_offs;
00766
00771 int SlIterateArray()
00772 {
00773 int index;
00774
00775
00776
00777 if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00778
00779 for (;;) {
00780 uint length = SlReadArrayLength();
00781 if (length == 0) {
00782 _next_offs = 0;
00783 return -1;
00784 }
00785
00786 _sl.obj_len = --length;
00787 _next_offs = _sl.reader->GetSize() + length;
00788
00789 switch (_sl.block_mode) {
00790 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00791 case CH_ARRAY: index = _sl.array_index++; break;
00792 default:
00793 DEBUG(sl, 0, "SlIterateArray error");
00794 return -1;
00795 }
00796
00797 if (length != 0) return index;
00798 }
00799 }
00800
00804 void SlSkipArray()
00805 {
00806 while (SlIterateArray() != -1) {
00807 SlSkipBytes(_next_offs - _sl.reader->GetSize());
00808 }
00809 }
00810
00816 void SlSetLength(size_t length)
00817 {
00818 assert(_sl.action == SLA_SAVE);
00819
00820 switch (_sl.need_length) {
00821 case NL_WANTLENGTH:
00822 _sl.need_length = NL_NONE;
00823 switch (_sl.block_mode) {
00824 case CH_RIFF:
00825
00826
00827
00828 assert(length < (1 << 28));
00829 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00830 break;
00831 case CH_ARRAY:
00832 assert(_sl.last_array_index <= _sl.array_index);
00833 while (++_sl.last_array_index <= _sl.array_index) {
00834 SlWriteArrayLength(1);
00835 }
00836 SlWriteArrayLength(length + 1);
00837 break;
00838 case CH_SPARSE_ARRAY:
00839 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00840 SlWriteSparseIndex(_sl.array_index);
00841 break;
00842 default: NOT_REACHED();
00843 }
00844 break;
00845
00846 case NL_CALCLENGTH:
00847 _sl.obj_len += (int)length;
00848 break;
00849
00850 default: NOT_REACHED();
00851 }
00852 }
00853
00860 static void SlCopyBytes(void *ptr, size_t length)
00861 {
00862 byte *p = (byte *)ptr;
00863
00864 switch (_sl.action) {
00865 case SLA_LOAD_CHECK:
00866 case SLA_LOAD:
00867 for (; length != 0; length--) *p++ = SlReadByte();
00868 break;
00869 case SLA_SAVE:
00870 for (; length != 0; length--) SlWriteByte(*p++);
00871 break;
00872 default: NOT_REACHED();
00873 }
00874 }
00875
00877 size_t SlGetFieldLength()
00878 {
00879 return _sl.obj_len;
00880 }
00881
00889 int64 ReadValue(const void *ptr, VarType conv)
00890 {
00891 switch (GetVarMemType(conv)) {
00892 case SLE_VAR_BL: return (*(const bool *)ptr != 0);
00893 case SLE_VAR_I8: return *(const int8 *)ptr;
00894 case SLE_VAR_U8: return *(const byte *)ptr;
00895 case SLE_VAR_I16: return *(const int16 *)ptr;
00896 case SLE_VAR_U16: return *(const uint16*)ptr;
00897 case SLE_VAR_I32: return *(const int32 *)ptr;
00898 case SLE_VAR_U32: return *(const uint32*)ptr;
00899 case SLE_VAR_I64: return *(const int64 *)ptr;
00900 case SLE_VAR_U64: return *(const uint64*)ptr;
00901 case SLE_VAR_NULL:return 0;
00902 default: NOT_REACHED();
00903 }
00904 }
00905
00913 void WriteValue(void *ptr, VarType conv, int64 val)
00914 {
00915 switch (GetVarMemType(conv)) {
00916 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00917 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00918 case SLE_VAR_U8: *(byte *)ptr = val; break;
00919 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00920 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00921 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00922 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00923 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00924 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00925 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00926 case SLE_VAR_NULL: break;
00927 default: NOT_REACHED();
00928 }
00929 }
00930
00939 static void SlSaveLoadConv(void *ptr, VarType conv)
00940 {
00941 switch (_sl.action) {
00942 case SLA_SAVE: {
00943 int64 x = ReadValue(ptr, conv);
00944
00945
00946 switch (GetVarFileType(conv)) {
00947 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00948 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00949 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00950 case SLE_FILE_STRINGID:
00951 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00952 case SLE_FILE_I32:
00953 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00954 case SLE_FILE_I64:
00955 case SLE_FILE_U64: SlWriteUint64(x);break;
00956 default: NOT_REACHED();
00957 }
00958 break;
00959 }
00960 case SLA_LOAD_CHECK:
00961 case SLA_LOAD: {
00962 int64 x;
00963
00964 switch (GetVarFileType(conv)) {
00965 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00966 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00967 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00968 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00969 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00970 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00971 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00972 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00973 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00974 default: NOT_REACHED();
00975 }
00976
00977
00978 WriteValue(ptr, conv, x);
00979 break;
00980 }
00981 case SLA_PTRS: break;
00982 case SLA_NULL: break;
00983 default: NOT_REACHED();
00984 }
00985 }
00986
00996 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
00997 {
00998 if (ptr == NULL) return 0;
00999 return min(strlen(ptr), length - 1);
01000 }
01001
01011 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
01012 {
01013 size_t len;
01014 const char *str;
01015
01016 switch (GetVarMemType(conv)) {
01017 default: NOT_REACHED();
01018 case SLE_VAR_STR:
01019 case SLE_VAR_STRQ:
01020 str = *(const char * const *)ptr;
01021 len = SIZE_MAX;
01022 break;
01023 case SLE_VAR_STRB:
01024 case SLE_VAR_STRBQ:
01025 str = (const char *)ptr;
01026 len = length;
01027 break;
01028 }
01029
01030 len = SlCalcNetStringLen(str, len);
01031 return len + SlGetArrayLength(len);
01032 }
01033
01040 static void SlString(void *ptr, size_t length, VarType conv)
01041 {
01042 switch (_sl.action) {
01043 case SLA_SAVE: {
01044 size_t len;
01045 switch (GetVarMemType(conv)) {
01046 default: NOT_REACHED();
01047 case SLE_VAR_STRB:
01048 case SLE_VAR_STRBQ:
01049 len = SlCalcNetStringLen((char *)ptr, length);
01050 break;
01051 case SLE_VAR_STR:
01052 case SLE_VAR_STRQ:
01053 ptr = *(char **)ptr;
01054 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01055 break;
01056 }
01057
01058 SlWriteArrayLength(len);
01059 SlCopyBytes(ptr, len);
01060 break;
01061 }
01062 case SLA_LOAD_CHECK:
01063 case SLA_LOAD: {
01064 size_t len = SlReadArrayLength();
01065
01066 switch (GetVarMemType(conv)) {
01067 default: NOT_REACHED();
01068 case SLE_VAR_STRB:
01069 case SLE_VAR_STRBQ:
01070 if (len >= length) {
01071 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01072 SlCopyBytes(ptr, length);
01073 SlSkipBytes(len - length);
01074 len = length - 1;
01075 } else {
01076 SlCopyBytes(ptr, len);
01077 }
01078 break;
01079 case SLE_VAR_STR:
01080 case SLE_VAR_STRQ:
01081 free(*(char **)ptr);
01082 if (len == 0) {
01083 *(char **)ptr = NULL;
01084 } else {
01085 *(char **)ptr = MallocT<char>(len + 1);
01086 ptr = *(char **)ptr;
01087 SlCopyBytes(ptr, len);
01088 }
01089 break;
01090 }
01091
01092 ((char *)ptr)[len] = '\0';
01093 str_validate((char *)ptr, (char *)ptr + len);
01094 break;
01095 }
01096 case SLA_PTRS: break;
01097 case SLA_NULL: break;
01098 default: NOT_REACHED();
01099 }
01100 }
01101
01107 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01108 {
01109 return SlCalcConvFileLen(conv) * length;
01110 }
01111
01118 void SlArray(void *array, size_t length, VarType conv)
01119 {
01120 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01121
01122
01123 if (_sl.need_length != NL_NONE) {
01124 SlSetLength(SlCalcArrayLen(length, conv));
01125
01126 if (_sl.need_length == NL_CALCLENGTH) return;
01127 }
01128
01129
01130
01131 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01132
01133 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01134 conv == SLE_INT32 || conv == SLE_UINT32) {
01135 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01136 return;
01137 }
01138
01139 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01140 for (uint i = 0; i < length; i++) {
01141 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01142 }
01143 return;
01144 }
01145 }
01146
01147
01148
01149 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01150 SlCopyBytes(array, length);
01151 } else {
01152 byte *a = (byte*)array;
01153 byte mem_size = SlCalcConvMemLen(conv);
01154
01155 for (; length != 0; length --) {
01156 SlSaveLoadConv(a, conv);
01157 a += mem_size;
01158 }
01159 }
01160 }
01161
01162
01173 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01174 {
01175 assert(_sl.action == SLA_SAVE);
01176
01177 if (obj == NULL) return 0;
01178
01179 switch (rt) {
01180 case REF_VEHICLE_OLD:
01181 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01182 case REF_STATION: return ((const Station*)obj)->index + 1;
01183 case REF_TOWN: return ((const Town*)obj)->index + 1;
01184 case REF_ORDER: return ((const Order*)obj)->index + 1;
01185 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01186 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01187 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01188 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01189 case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
01190 default: NOT_REACHED();
01191 }
01192 }
01193
01204 static void *IntToReference(size_t index, SLRefType rt)
01205 {
01206 assert_compile(sizeof(size_t) <= sizeof(void *));
01207
01208 assert(_sl.action == SLA_PTRS);
01209
01210
01211
01212 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01213 rt = REF_VEHICLE;
01214 }
01215
01216
01217 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01218
01219
01220
01221 if (rt != REF_VEHICLE_OLD) index--;
01222
01223 switch (rt) {
01224 case REF_ORDERLIST:
01225 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01226 SlErrorCorrupt("Referencing invalid OrderList");
01227
01228 case REF_ORDER:
01229 if (Order::IsValidID(index)) return Order::Get(index);
01230
01231 if (IsSavegameVersionBefore(5, 2)) return NULL;
01232 SlErrorCorrupt("Referencing invalid Order");
01233
01234 case REF_VEHICLE_OLD:
01235 case REF_VEHICLE:
01236 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01237 SlErrorCorrupt("Referencing invalid Vehicle");
01238
01239 case REF_STATION:
01240 if (Station::IsValidID(index)) return Station::Get(index);
01241 SlErrorCorrupt("Referencing invalid Station");
01242
01243 case REF_TOWN:
01244 if (Town::IsValidID(index)) return Town::Get(index);
01245 SlErrorCorrupt("Referencing invalid Town");
01246
01247 case REF_ROADSTOPS:
01248 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01249 SlErrorCorrupt("Referencing invalid RoadStop");
01250
01251 case REF_ENGINE_RENEWS:
01252 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01253 SlErrorCorrupt("Referencing invalid EngineRenew");
01254
01255 case REF_CARGO_PACKET:
01256 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01257 SlErrorCorrupt("Referencing invalid CargoPacket");
01258
01259 case REF_STORAGE:
01260 if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index);
01261 SlErrorCorrupt("Referencing invalid PersistentStorage");
01262
01263 default: NOT_REACHED();
01264 }
01265 }
01266
01271 static inline size_t SlCalcListLen(const void *list)
01272 {
01273 const std::list<void *> *l = (const std::list<void *> *) list;
01274
01275 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01276
01277
01278 return l->size() * type_size + type_size;
01279 }
01280
01281
01287 static void SlList(void *list, SLRefType conv)
01288 {
01289
01290 if (_sl.need_length != NL_NONE) {
01291 SlSetLength(SlCalcListLen(list));
01292
01293 if (_sl.need_length == NL_CALCLENGTH) return;
01294 }
01295
01296 typedef std::list<void *> PtrList;
01297 PtrList *l = (PtrList *)list;
01298
01299 switch (_sl.action) {
01300 case SLA_SAVE: {
01301 SlWriteUint32((uint32)l->size());
01302
01303 PtrList::iterator iter;
01304 for (iter = l->begin(); iter != l->end(); ++iter) {
01305 void *ptr = *iter;
01306 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01307 }
01308 break;
01309 }
01310 case SLA_LOAD_CHECK:
01311 case SLA_LOAD: {
01312 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01313
01314
01315 for (size_t i = 0; i < length; i++) {
01316 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01317 l->push_back((void *)data);
01318 }
01319 break;
01320 }
01321 case SLA_PTRS: {
01322 PtrList temp = *l;
01323
01324 l->clear();
01325 PtrList::iterator iter;
01326 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01327 void *ptr = IntToReference((size_t)*iter, conv);
01328 l->push_back(ptr);
01329 }
01330 break;
01331 }
01332 case SLA_NULL:
01333 l->clear();
01334 break;
01335 default: NOT_REACHED();
01336 }
01337 }
01338
01339
01341 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01342 {
01343 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01344 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01345
01346 return true;
01347 }
01348
01354 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01355 {
01356 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01357 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01358 return true;
01359 }
01360
01361 return false;
01362 }
01363
01370 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01371 {
01372 size_t length = 0;
01373
01374
01375 for (; sld->cmd != SL_END; sld++) {
01376 length += SlCalcObjMemberLength(object, sld);
01377 }
01378 return length;
01379 }
01380
01381 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01382 {
01383 assert(_sl.action == SLA_SAVE);
01384
01385 switch (sld->cmd) {
01386 case SL_VAR:
01387 case SL_REF:
01388 case SL_ARR:
01389 case SL_STR:
01390 case SL_LST:
01391
01392 if (!SlIsObjectValidInSavegame(sld)) break;
01393
01394 switch (sld->cmd) {
01395 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01396 case SL_REF: return SlCalcRefLen();
01397 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01398 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01399 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01400 default: NOT_REACHED();
01401 }
01402 break;
01403 case SL_WRITEBYTE: return 1;
01404 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01405 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01406 default: NOT_REACHED();
01407 }
01408 return 0;
01409 }
01410
01411
01412 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01413 {
01414 VarType conv = GB(sld->conv, 0, 8);
01415 switch (sld->cmd) {
01416 case SL_VAR:
01417 case SL_REF:
01418 case SL_ARR:
01419 case SL_STR:
01420 case SL_LST:
01421
01422 if (!SlIsObjectValidInSavegame(sld)) return false;
01423 if (SlSkipVariableOnLoad(sld)) return false;
01424
01425 switch (sld->cmd) {
01426 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01427 case SL_REF:
01428 switch (_sl.action) {
01429 case SLA_SAVE:
01430 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01431 break;
01432 case SLA_LOAD_CHECK:
01433 case SLA_LOAD:
01434 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01435 break;
01436 case SLA_PTRS:
01437 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01438 break;
01439 case SLA_NULL:
01440 *(void **)ptr = NULL;
01441 break;
01442 default: NOT_REACHED();
01443 }
01444 break;
01445 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01446 case SL_STR: SlString(ptr, sld->length, conv); break;
01447 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01448 default: NOT_REACHED();
01449 }
01450 break;
01451
01452
01453
01454
01455
01456
01457 case SL_WRITEBYTE:
01458 switch (_sl.action) {
01459 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01460 case SLA_LOAD_CHECK:
01461 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01462 case SLA_PTRS: break;
01463 case SLA_NULL: break;
01464 default: NOT_REACHED();
01465 }
01466 break;
01467
01468
01469 case SL_VEH_INCLUDE:
01470 SlObject(ptr, GetVehicleDescription(VEH_END));
01471 break;
01472
01473 case SL_ST_INCLUDE:
01474 SlObject(ptr, GetBaseStationDescription());
01475 break;
01476
01477 default: NOT_REACHED();
01478 }
01479 return true;
01480 }
01481
01487 void SlObject(void *object, const SaveLoad *sld)
01488 {
01489
01490 if (_sl.need_length != NL_NONE) {
01491 SlSetLength(SlCalcObjLength(object, sld));
01492 if (_sl.need_length == NL_CALCLENGTH) return;
01493 }
01494
01495 for (; sld->cmd != SL_END; sld++) {
01496 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01497 SlObjectMember(ptr, sld);
01498 }
01499 }
01500
01505 void SlGlobList(const SaveLoadGlobVarList *sldg)
01506 {
01507 SlObject(NULL, (const SaveLoad*)sldg);
01508 }
01509
01515 void SlAutolength(AutolengthProc *proc, void *arg)
01516 {
01517 size_t offs;
01518
01519 assert(_sl.action == SLA_SAVE);
01520
01521
01522 _sl.need_length = NL_CALCLENGTH;
01523 _sl.obj_len = 0;
01524 proc(arg);
01525
01526
01527 _sl.need_length = NL_WANTLENGTH;
01528 SlSetLength(_sl.obj_len);
01529
01530 offs = _sl.dumper->GetSize() + _sl.obj_len;
01531
01532
01533 proc(arg);
01534
01535 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01536 }
01537
01542 static void SlLoadChunk(const ChunkHandler *ch)
01543 {
01544 byte m = SlReadByte();
01545 size_t len;
01546 size_t endoffs;
01547
01548 _sl.block_mode = m;
01549 _sl.obj_len = 0;
01550
01551 switch (m) {
01552 case CH_ARRAY:
01553 _sl.array_index = 0;
01554 ch->load_proc();
01555 break;
01556 case CH_SPARSE_ARRAY:
01557 ch->load_proc();
01558 break;
01559 default:
01560 if ((m & 0xF) == CH_RIFF) {
01561
01562 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01563 len += SlReadUint16();
01564 _sl.obj_len = len;
01565 endoffs = _sl.reader->GetSize() + len;
01566 ch->load_proc();
01567 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01568 } else {
01569 SlErrorCorrupt("Invalid chunk type");
01570 }
01571 break;
01572 }
01573 }
01574
01580 static void SlLoadCheckChunk(const ChunkHandler *ch)
01581 {
01582 byte m = SlReadByte();
01583 size_t len;
01584 size_t endoffs;
01585
01586 _sl.block_mode = m;
01587 _sl.obj_len = 0;
01588
01589 switch (m) {
01590 case CH_ARRAY:
01591 _sl.array_index = 0;
01592 if (ch->load_check_proc) {
01593 ch->load_check_proc();
01594 } else {
01595 SlSkipArray();
01596 }
01597 break;
01598 case CH_SPARSE_ARRAY:
01599 if (ch->load_check_proc) {
01600 ch->load_check_proc();
01601 } else {
01602 SlSkipArray();
01603 }
01604 break;
01605 default:
01606 if ((m & 0xF) == CH_RIFF) {
01607
01608 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01609 len += SlReadUint16();
01610 _sl.obj_len = len;
01611 endoffs = _sl.reader->GetSize() + len;
01612 if (ch->load_check_proc) {
01613 ch->load_check_proc();
01614 } else {
01615 SlSkipBytes(len);
01616 }
01617 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01618 } else {
01619 SlErrorCorrupt("Invalid chunk type");
01620 }
01621 break;
01622 }
01623 }
01624
01629 static ChunkSaveLoadProc *_stub_save_proc;
01630
01636 static inline void SlStubSaveProc2(void *arg)
01637 {
01638 _stub_save_proc();
01639 }
01640
01646 static void SlStubSaveProc()
01647 {
01648 SlAutolength(SlStubSaveProc2, NULL);
01649 }
01650
01656 static void SlSaveChunk(const ChunkHandler *ch)
01657 {
01658 ChunkSaveLoadProc *proc = ch->save_proc;
01659
01660
01661 if (proc == NULL) return;
01662
01663 SlWriteUint32(ch->id);
01664 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01665
01666 if (ch->flags & CH_AUTO_LENGTH) {
01667
01668 _stub_save_proc = proc;
01669 proc = SlStubSaveProc;
01670 }
01671
01672 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01673 switch (ch->flags & CH_TYPE_MASK) {
01674 case CH_RIFF:
01675 _sl.need_length = NL_WANTLENGTH;
01676 proc();
01677 break;
01678 case CH_ARRAY:
01679 _sl.last_array_index = 0;
01680 SlWriteByte(CH_ARRAY);
01681 proc();
01682 SlWriteArrayLength(0);
01683 break;
01684 case CH_SPARSE_ARRAY:
01685 SlWriteByte(CH_SPARSE_ARRAY);
01686 proc();
01687 SlWriteArrayLength(0);
01688 break;
01689 default: NOT_REACHED();
01690 }
01691 }
01692
01694 static void SlSaveChunks()
01695 {
01696 FOR_ALL_CHUNK_HANDLERS(ch) {
01697 SlSaveChunk(ch);
01698 }
01699
01700
01701 SlWriteUint32(0);
01702 }
01703
01710 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01711 {
01712 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01713 return NULL;
01714 }
01715
01717 static void SlLoadChunks()
01718 {
01719 uint32 id;
01720 const ChunkHandler *ch;
01721
01722 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01723 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01724
01725 ch = SlFindChunkHandler(id);
01726 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01727 SlLoadChunk(ch);
01728 }
01729 }
01730
01732 static void SlLoadCheckChunks()
01733 {
01734 uint32 id;
01735 const ChunkHandler *ch;
01736
01737 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01738 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01739
01740 ch = SlFindChunkHandler(id);
01741 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01742 SlLoadCheckChunk(ch);
01743 }
01744 }
01745
01747 static void SlFixPointers()
01748 {
01749 _sl.action = SLA_PTRS;
01750
01751 DEBUG(sl, 1, "Fixing pointers");
01752
01753 FOR_ALL_CHUNK_HANDLERS(ch) {
01754 if (ch->ptrs_proc != NULL) {
01755 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01756 ch->ptrs_proc();
01757 }
01758 }
01759
01760 DEBUG(sl, 1, "All pointers fixed");
01761
01762 assert(_sl.action == SLA_PTRS);
01763 }
01764
01765
01767 struct FileReader : LoadFilter {
01768 FILE *file;
01769 long begin;
01770
01775 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01776 {
01777 }
01778
01780 ~FileReader()
01781 {
01782 if (this->file != NULL) fclose(this->file);
01783 this->file = NULL;
01784
01785
01786 _sl.sf = NULL;
01787 }
01788
01789 size_t Read(byte *buf, size_t size)
01790 {
01791
01792 if (this->file == NULL) return 0;
01793
01794 return fread(buf, 1, size, this->file);
01795 }
01796
01797 void Reset()
01798 {
01799 clearerr(this->file);
01800 fseek(this->file, this->begin, SEEK_SET);
01801 }
01802 };
01803
01805 struct FileWriter : SaveFilter {
01806 FILE *file;
01807
01812 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01813 {
01814 }
01815
01817 ~FileWriter()
01818 {
01819 this->Finish();
01820
01821
01822 _sl.sf = NULL;
01823 }
01824
01825 void Write(byte *buf, size_t size)
01826 {
01827
01828 if (this->file == NULL) return;
01829
01830 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01831 }
01832
01833 void Finish()
01834 {
01835 if (this->file != NULL) fclose(this->file);
01836 this->file = NULL;
01837 }
01838 };
01839
01840
01841
01842
01843
01844 #ifdef WITH_LZO
01845 #include <lzo/lzo1x.h>
01846
01848 static const uint LZO_BUFFER_SIZE = 8192;
01849
01851 struct LZOLoadFilter : LoadFilter {
01856 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01857 {
01858 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01859 }
01860
01861 size_t Read(byte *buf, size_t ssize)
01862 {
01863 assert(ssize >= LZO_BUFFER_SIZE);
01864
01865
01866 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01867 uint32 tmp[2];
01868 uint32 size;
01869 lzo_uint len;
01870
01871
01872 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01873
01874
01875 ((uint32*)out)[0] = size = tmp[1];
01876
01877 if (_sl_version != 0) {
01878 tmp[0] = TO_BE32(tmp[0]);
01879 size = TO_BE32(size);
01880 }
01881
01882 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01883
01884
01885 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01886
01887
01888 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01889
01890
01891 lzo1x_decompress(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01892 return len;
01893 }
01894 };
01895
01897 struct LZOSaveFilter : SaveFilter {
01903 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01904 {
01905 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01906 }
01907
01908 void Write(byte *buf, size_t size)
01909 {
01910 const lzo_bytep in = buf;
01911
01912 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01913 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01914 lzo_uint outlen;
01915
01916 do {
01917
01918 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01919 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01920 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01921 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01922 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01923
01924
01925 size -= len;
01926 in += len;
01927 } while (size > 0);
01928 }
01929 };
01930
01931 #endif
01932
01933
01934
01935
01936
01938 struct NoCompLoadFilter : LoadFilter {
01943 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01944 {
01945 }
01946
01947 size_t Read(byte *buf, size_t size)
01948 {
01949 return this->chain->Read(buf, size);
01950 }
01951 };
01952
01954 struct NoCompSaveFilter : SaveFilter {
01960 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01961 {
01962 }
01963
01964 void Write(byte *buf, size_t size)
01965 {
01966 this->chain->Write(buf, size);
01967 }
01968 };
01969
01970
01971
01972
01973
01974 #if defined(WITH_ZLIB)
01975 #include <zlib.h>
01976
01978 struct ZlibLoadFilter : LoadFilter {
01979 z_stream z;
01980 byte fread_buf[MEMORY_CHUNK_SIZE];
01981
01986 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01987 {
01988 memset(&this->z, 0, sizeof(this->z));
01989 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01990 }
01991
01993 ~ZlibLoadFilter()
01994 {
01995 inflateEnd(&this->z);
01996 }
01997
01998 size_t Read(byte *buf, size_t size)
01999 {
02000 this->z.next_out = buf;
02001 this->z.avail_out = (uint)size;
02002
02003 do {
02004
02005 if (this->z.avail_in == 0) {
02006 this->z.next_in = this->fread_buf;
02007 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02008 }
02009
02010
02011 int r = inflate(&this->z, 0);
02012 if (r == Z_STREAM_END) break;
02013
02014 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02015 } while (this->z.avail_out != 0);
02016
02017 return size - this->z.avail_out;
02018 }
02019 };
02020
02022 struct ZlibSaveFilter : SaveFilter {
02023 z_stream z;
02024
02030 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02031 {
02032 memset(&this->z, 0, sizeof(this->z));
02033 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02034 }
02035
02037 ~ZlibSaveFilter()
02038 {
02039 deflateEnd(&this->z);
02040 }
02041
02048 void WriteLoop(byte *p, size_t len, int mode)
02049 {
02050 byte buf[MEMORY_CHUNK_SIZE];
02051 uint n;
02052 this->z.next_in = p;
02053 this->z.avail_in = (uInt)len;
02054 do {
02055 this->z.next_out = buf;
02056 this->z.avail_out = sizeof(buf);
02057
02065 int r = deflate(&this->z, mode);
02066
02067
02068 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02069 this->chain->Write(buf, n);
02070 }
02071 if (r == Z_STREAM_END) break;
02072
02073 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02074 } while (this->z.avail_in || !this->z.avail_out);
02075 }
02076
02077 void Write(byte *buf, size_t size)
02078 {
02079 this->WriteLoop(buf, size, 0);
02080 }
02081
02082 void Finish()
02083 {
02084 this->WriteLoop(NULL, 0, Z_FINISH);
02085 this->chain->Finish();
02086 }
02087 };
02088
02089 #endif
02090
02091
02092
02093
02094
02095 #if defined(WITH_LZMA)
02096 #include <lzma.h>
02097
02104 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02105
02107 struct LZMALoadFilter : LoadFilter {
02108 lzma_stream lzma;
02109 byte fread_buf[MEMORY_CHUNK_SIZE];
02110
02115 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02116 {
02117
02118 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02119 }
02120
02122 ~LZMALoadFilter()
02123 {
02124 lzma_end(&this->lzma);
02125 }
02126
02127 size_t Read(byte *buf, size_t size)
02128 {
02129 this->lzma.next_out = buf;
02130 this->lzma.avail_out = size;
02131
02132 do {
02133
02134 if (this->lzma.avail_in == 0) {
02135 this->lzma.next_in = this->fread_buf;
02136 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02137 }
02138
02139
02140 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02141 if (r == LZMA_STREAM_END) break;
02142 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02143 } while (this->lzma.avail_out != 0);
02144
02145 return size - this->lzma.avail_out;
02146 }
02147 };
02148
02150 struct LZMASaveFilter : SaveFilter {
02151 lzma_stream lzma;
02152
02158 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02159 {
02160 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02161 }
02162
02164 ~LZMASaveFilter()
02165 {
02166 lzma_end(&this->lzma);
02167 }
02168
02175 void WriteLoop(byte *p, size_t len, lzma_action action)
02176 {
02177 byte buf[MEMORY_CHUNK_SIZE];
02178 size_t n;
02179 this->lzma.next_in = p;
02180 this->lzma.avail_in = len;
02181 do {
02182 this->lzma.next_out = buf;
02183 this->lzma.avail_out = sizeof(buf);
02184
02185 lzma_ret r = lzma_code(&this->lzma, action);
02186
02187
02188 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02189 this->chain->Write(buf, n);
02190 }
02191 if (r == LZMA_STREAM_END) break;
02192 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02193 } while (this->lzma.avail_in || !this->lzma.avail_out);
02194 }
02195
02196 void Write(byte *buf, size_t size)
02197 {
02198 this->WriteLoop(buf, size, LZMA_RUN);
02199 }
02200
02201 void Finish()
02202 {
02203 this->WriteLoop(NULL, 0, LZMA_FINISH);
02204 this->chain->Finish();
02205 }
02206 };
02207
02208 #endif
02209
02210
02211
02212
02213
02215 struct SaveLoadFormat {
02216 const char *name;
02217 uint32 tag;
02218
02219 LoadFilter *(*init_load)(LoadFilter *chain);
02220 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02221
02222 byte min_compression;
02223 byte default_compression;
02224 byte max_compression;
02225 };
02226
02228 static const SaveLoadFormat _saveload_formats[] = {
02229 #if defined(WITH_LZO)
02230
02231 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02232 #else
02233 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02234 #endif
02235
02236 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02237 #if defined(WITH_ZLIB)
02238
02239
02240
02241 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02242 #else
02243 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02244 #endif
02245 #if defined(WITH_LZMA)
02246
02247
02248
02249
02250
02251 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02252 #else
02253 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02254 #endif
02255 };
02256
02264 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02265 {
02266 const SaveLoadFormat *def = lastof(_saveload_formats);
02267
02268
02269 while (!def->init_write) def--;
02270
02271 if (!StrEmpty(s)) {
02272
02273 char *complevel = strrchr(s, ':');
02274 if (complevel != NULL) *complevel = '\0';
02275
02276 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02277 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02278 *compression_level = slf->default_compression;
02279 if (complevel != NULL) {
02280
02281
02282
02283 *complevel = ':';
02284 complevel++;
02285
02286
02287 char *end;
02288 long level = strtol(complevel, &end, 10);
02289 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02290 ShowInfoF("Compression level '%s' is not valid.", complevel);
02291 } else {
02292 *compression_level = level;
02293 }
02294 }
02295 return slf;
02296 }
02297 }
02298
02299 ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
02300
02301
02302 if (complevel != NULL) *complevel = ':';
02303 }
02304 *compression_level = def->default_compression;
02305 return def;
02306 }
02307
02308
02309 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02310 extern bool AfterLoadGame();
02311 extern bool LoadOldSaveGame(const char *file);
02312
02316 static inline void ClearSaveLoadState()
02317 {
02318 delete _sl.dumper;
02319 _sl.dumper = NULL;
02320
02321 delete _sl.sf;
02322 _sl.sf = NULL;
02323
02324 delete _sl.reader;
02325 _sl.reader = NULL;
02326
02327 delete _sl.lf;
02328 _sl.lf = NULL;
02329 }
02330
02336 static void SaveFileStart()
02337 {
02338 _sl.ff_state = _fast_forward;
02339 _fast_forward = 0;
02340 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02341
02342 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02343 _sl.saveinprogress = true;
02344 }
02345
02347 static void SaveFileDone()
02348 {
02349 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02350 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02351
02352 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02353 _sl.saveinprogress = false;
02354 }
02355
02357 void SetSaveLoadError(StringID str)
02358 {
02359 _sl.error_str = str;
02360 }
02361
02363 const char *GetSaveLoadErrorString()
02364 {
02365 SetDParam(0, _sl.error_str);
02366 SetDParamStr(1, _sl.extra_msg);
02367
02368 static char err_str[512];
02369 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02370 return err_str;
02371 }
02372
02374 static void SaveFileError()
02375 {
02376 SetDParamStr(0, GetSaveLoadErrorString());
02377 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02378 SaveFileDone();
02379 }
02380
02385 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02386 {
02387 try {
02388 byte compression;
02389 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02390
02391
02392 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02393 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02394
02395 _sl.sf = fmt->init_write(_sl.sf, compression);
02396 _sl.dumper->Flush(_sl.sf);
02397
02398 ClearSaveLoadState();
02399
02400 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02401
02402 return SL_OK;
02403 } catch (...) {
02404 ClearSaveLoadState();
02405
02406 AsyncSaveFinishProc asfp = SaveFileDone;
02407
02408
02409
02410 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02411
02412 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02413 asfp = SaveFileError;
02414 }
02415
02416 if (threaded) {
02417 SetAsyncSaveFinish(asfp);
02418 } else {
02419 asfp();
02420 }
02421 return SL_ERROR;
02422 }
02423 }
02424
02426 static void SaveFileToDiskThread(void *arg)
02427 {
02428 SaveFileToDisk(true);
02429 }
02430
02431 void WaitTillSaved()
02432 {
02433 if (_save_thread == NULL) return;
02434
02435 _save_thread->Join();
02436 delete _save_thread;
02437 _save_thread = NULL;
02438
02439
02440 ProcessAsyncSaveFinish();
02441 }
02442
02451 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02452 {
02453 assert(!_sl.saveinprogress);
02454
02455 _sl.dumper = new MemoryDumper();
02456 _sl.sf = writer;
02457
02458 _sl_version = SAVEGAME_VERSION;
02459
02460 SaveViewportBeforeSaveGame();
02461 SlSaveChunks();
02462
02463 SaveFileStart();
02464 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02465 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02466
02467 SaveOrLoadResult result = SaveFileToDisk(false);
02468 SaveFileDone();
02469
02470 return result;
02471 }
02472
02473 return SL_OK;
02474 }
02475
02482 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02483 {
02484 try {
02485 _sl.action = SLA_SAVE;
02486 return DoSave(writer, threaded);
02487 } catch (...) {
02488 ClearSaveLoadState();
02489 return SL_ERROR;
02490 }
02491 }
02492
02499 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02500 {
02501 _sl.lf = reader;
02502
02503 if (load_check) {
02504
02505 _load_check_data.Clear();
02506
02507 _load_check_data.checkable = true;
02508 }
02509
02510 uint32 hdr[2];
02511 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02512
02513
02514 const SaveLoadFormat *fmt = _saveload_formats;
02515 for (;;) {
02516
02517 if (fmt == endof(_saveload_formats)) {
02518 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02519 _sl.lf->Reset();
02520 _sl_version = 0;
02521 _sl_minor_version = 0;
02522
02523
02524 fmt = _saveload_formats;
02525 for (;;) {
02526 if (fmt == endof(_saveload_formats)) {
02527
02528 NOT_REACHED();
02529 }
02530 if (fmt->tag == TO_BE32X('OTTD')) break;
02531 fmt++;
02532 }
02533 break;
02534 }
02535
02536 if (fmt->tag == hdr[0]) {
02537
02538 _sl_version = TO_BE32(hdr[1]) >> 16;
02539
02540
02541
02542 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02543
02544 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02545
02546
02547 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02548 break;
02549 }
02550
02551 fmt++;
02552 }
02553
02554
02555 if (fmt->init_load == NULL) {
02556 char err_str[64];
02557 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02558 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02559 }
02560
02561 _sl.lf = fmt->init_load(_sl.lf);
02562 _sl.reader = new ReadBuffer(_sl.lf);
02563 _next_offs = 0;
02564
02565 if (!load_check) {
02566
02567
02568
02569 InitializeGame(256, 256, true, true);
02570
02571 GamelogReset();
02572
02573 if (IsSavegameVersionBefore(4)) {
02574
02575
02576
02577
02578
02579
02580
02581
02582
02583
02584
02585
02586
02587
02588
02589
02590
02591
02592
02593
02594
02595 ClearGRFConfigList(&_grfconfig);
02596 }
02597 }
02598
02599 if (load_check) {
02600
02601
02602 SlLoadCheckChunks();
02603 } else {
02604
02605 SlLoadChunks();
02606 SlFixPointers();
02607 }
02608
02609 ClearSaveLoadState();
02610
02611 _savegame_type = SGT_OTTD;
02612
02613 if (load_check) {
02614
02615 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02616 } else {
02617 GamelogStartAction(GLAT_LOAD);
02618
02619
02620
02621 if (!AfterLoadGame()) {
02622 GamelogStopAction();
02623 return SL_REINIT;
02624 }
02625
02626 GamelogStopAction();
02627 }
02628
02629 return SL_OK;
02630 }
02631
02637 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02638 {
02639 try {
02640 _sl.action = SLA_LOAD;
02641 return DoLoad(reader, false);
02642 } catch (...) {
02643 ClearSaveLoadState();
02644 return SL_REINIT;
02645 }
02646 }
02647
02657 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02658 {
02659
02660 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02661
02662 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02663 return SL_OK;
02664 }
02665 WaitTillSaved();
02666
02667
02668 if (mode == SL_OLD_LOAD) {
02669 InitializeGame(256, 256, true, true);
02670
02671
02672
02673
02674
02675 ClearGRFConfigList(&_grfconfig);
02676 GamelogReset();
02677 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02678 _sl_version = 0;
02679 _sl_minor_version = 0;
02680 GamelogStartAction(GLAT_LOAD);
02681 if (!AfterLoadGame()) {
02682 GamelogStopAction();
02683 return SL_REINIT;
02684 }
02685 GamelogStopAction();
02686 return SL_OK;
02687 }
02688
02689 switch (mode) {
02690 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02691 case SL_LOAD: _sl.action = SLA_LOAD; break;
02692 case SL_SAVE: _sl.action = SLA_SAVE; break;
02693 default: NOT_REACHED();
02694 }
02695
02696 try {
02697 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02698
02699
02700 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02701 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02702
02703 if (fh == NULL) {
02704 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02705 }
02706
02707 if (mode == SL_SAVE) {
02708 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02709 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02710
02711 return DoSave(new FileWriter(fh), threaded);
02712 }
02713
02714
02715 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02716 DEBUG(desync, 1, "load: %s", filename);
02717 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02718 } catch (...) {
02719 ClearSaveLoadState();
02720
02721
02722 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02723
02724
02725 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02726 }
02727 }
02728
02730 void DoExitSave()
02731 {
02732 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02733 }
02734
02740 void GenerateDefaultSaveName(char *buf, const char *last)
02741 {
02742
02743
02744
02745 CompanyID cid = _local_company;
02746 if (!Company::IsValidID(cid)) {
02747 const Company *c;
02748 FOR_ALL_COMPANIES(c) {
02749 cid = c->index;
02750 break;
02751 }
02752 }
02753
02754 SetDParam(0, cid);
02755
02756
02757 switch (_settings_client.gui.date_format_in_default_names) {
02758 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02759 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02760 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02761 default: NOT_REACHED();
02762 }
02763 SetDParam(2, _date);
02764
02765
02766 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02767 SanitizeFilename(buf);
02768 }
02769
02770 #if 0
02771
02777 int GetSavegameType(char *file)
02778 {
02779 const SaveLoadFormat *fmt;
02780 uint32 hdr;
02781 FILE *f;
02782 int mode = SL_OLD_LOAD;
02783
02784 f = fopen(file, "rb");
02785 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02786 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02787 mode = SL_LOAD;
02788 } else {
02789
02790 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02791 if (fmt->tag == hdr) {
02792 mode = SL_LOAD;
02793 break;
02794 }
02795 }
02796 }
02797
02798 fclose(f);
02799 return mode;
02800 }
02801 #endif