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 extern const uint16 SAVEGAME_VERSION = SL_EXT_RATING;
00230
00231 SavegameType _savegame_type;
00232
00233 uint32 _ttdp_version;
00234 uint16 _sl_version;
00235 byte _sl_minor_version;
00236 char _savegame_format[8];
00237 bool _do_autosave;
00238
00240 enum SaveLoadAction {
00241 SLA_LOAD,
00242 SLA_SAVE,
00243 SLA_PTRS,
00244 SLA_NULL,
00245 SLA_LOAD_CHECK,
00246 };
00247
00248 enum NeedLength {
00249 NL_NONE = 0,
00250 NL_WANTLENGTH = 1,
00251 NL_CALCLENGTH = 2,
00252 };
00253
00255 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
00256
00258 struct ReadBuffer {
00259 byte buf[MEMORY_CHUNK_SIZE];
00260 byte *bufp;
00261 byte *bufe;
00262 LoadFilter *reader;
00263 size_t read;
00264
00269 ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
00270 {
00271 }
00272
00273 FORCEINLINE byte ReadByte()
00274 {
00275 if (this->bufp == this->bufe) {
00276 size_t len = this->reader->Read(this->buf, lengthof(this->buf));
00277 if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00278
00279 this->read += len;
00280 this->bufp = this->buf;
00281 this->bufe = this->buf + len;
00282 }
00283
00284 return *this->bufp++;
00285 }
00286
00291 size_t GetSize() const
00292 {
00293 return this->read - (this->bufe - this->bufp);
00294 }
00295 };
00296
00297
00299 struct MemoryDumper {
00300 AutoFreeSmallVector<byte *, 16> blocks;
00301 byte *buf;
00302 byte *bufe;
00303
00305 MemoryDumper() : buf(NULL), bufe(NULL)
00306 {
00307 }
00308
00313 FORCEINLINE void WriteByte(byte b)
00314 {
00315
00316 if (this->buf == this->bufe) {
00317 this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
00318 *this->blocks.Append() = this->buf;
00319 this->bufe = this->buf + MEMORY_CHUNK_SIZE;
00320 }
00321
00322 *this->buf++ = b;
00323 }
00324
00329 void Flush(SaveFilter *writer)
00330 {
00331 uint i = 0;
00332 size_t t = this->GetSize();
00333
00334 while (t > 0) {
00335 size_t to_write = min(MEMORY_CHUNK_SIZE, t);
00336
00337 writer->Write(this->blocks[i++], to_write);
00338 t -= to_write;
00339 }
00340
00341 writer->Finish();
00342 }
00343
00348 size_t GetSize() const
00349 {
00350 return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
00351 }
00352 };
00353
00355 struct SaveLoadParams {
00356 SaveLoadAction action;
00357 NeedLength need_length;
00358 byte block_mode;
00359 bool error;
00360
00361 size_t obj_len;
00362 int array_index, last_array_index;
00363
00364 MemoryDumper *dumper;
00365 SaveFilter *sf;
00366
00367 ReadBuffer *reader;
00368 LoadFilter *lf;
00369
00370 StringID error_str;
00371 char *extra_msg;
00372
00373 byte ff_state;
00374 bool saveinprogress;
00375 };
00376
00377 static SaveLoadParams _sl;
00378
00379
00380 extern const ChunkHandler _gamelog_chunk_handlers[];
00381 extern const ChunkHandler _map_chunk_handlers[];
00382 extern const ChunkHandler _misc_chunk_handlers[];
00383 extern const ChunkHandler _name_chunk_handlers[];
00384 extern const ChunkHandler _cheat_chunk_handlers[] ;
00385 extern const ChunkHandler _setting_chunk_handlers[];
00386 extern const ChunkHandler _company_chunk_handlers[];
00387 extern const ChunkHandler _engine_chunk_handlers[];
00388 extern const ChunkHandler _veh_chunk_handlers[];
00389 extern const ChunkHandler _waypoint_chunk_handlers[];
00390 extern const ChunkHandler _depot_chunk_handlers[];
00391 extern const ChunkHandler _order_chunk_handlers[];
00392 extern const ChunkHandler _town_chunk_handlers[];
00393 extern const ChunkHandler _sign_chunk_handlers[];
00394 extern const ChunkHandler _station_chunk_handlers[];
00395 extern const ChunkHandler _industry_chunk_handlers[];
00396 extern const ChunkHandler _economy_chunk_handlers[];
00397 extern const ChunkHandler _subsidy_chunk_handlers[];
00398 extern const ChunkHandler _ai_chunk_handlers[];
00399 extern const ChunkHandler _animated_tile_chunk_handlers[];
00400 extern const ChunkHandler _newgrf_chunk_handlers[];
00401 extern const ChunkHandler _group_chunk_handlers[];
00402 extern const ChunkHandler _cargopacket_chunk_handlers[];
00403 extern const ChunkHandler _autoreplace_chunk_handlers[];
00404 extern const ChunkHandler _labelmaps_chunk_handlers[];
00405 extern const ChunkHandler _linkgraph_chunk_handlers[];
00406 extern const ChunkHandler _airport_chunk_handlers[];
00407 extern const ChunkHandler _object_chunk_handlers[];
00408
00410 static const ChunkHandler * const _chunk_handlers[] = {
00411 _gamelog_chunk_handlers,
00412 _map_chunk_handlers,
00413 _misc_chunk_handlers,
00414 _name_chunk_handlers,
00415 _cheat_chunk_handlers,
00416 _setting_chunk_handlers,
00417 _veh_chunk_handlers,
00418 _waypoint_chunk_handlers,
00419 _depot_chunk_handlers,
00420 _order_chunk_handlers,
00421 _industry_chunk_handlers,
00422 _economy_chunk_handlers,
00423 _subsidy_chunk_handlers,
00424 _engine_chunk_handlers,
00425 _town_chunk_handlers,
00426 _sign_chunk_handlers,
00427 _station_chunk_handlers,
00428 _company_chunk_handlers,
00429 _ai_chunk_handlers,
00430 _animated_tile_chunk_handlers,
00431 _newgrf_chunk_handlers,
00432 _group_chunk_handlers,
00433 _cargopacket_chunk_handlers,
00434 _autoreplace_chunk_handlers,
00435 _labelmaps_chunk_handlers,
00436 _linkgraph_chunk_handlers,
00437 _airport_chunk_handlers,
00438 _object_chunk_handlers,
00439 NULL,
00440 };
00441
00446 #define FOR_ALL_CHUNK_HANDLERS(ch) \
00447 for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \
00448 for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1)
00449
00451 static void SlNullPointers()
00452 {
00453 _sl.action = SLA_NULL;
00454
00455
00456
00457
00458 _sl_version = SAVEGAME_VERSION;
00459
00460 DEBUG(sl, 1, "Nulling pointers");
00461
00462 FOR_ALL_CHUNK_HANDLERS(ch) {
00463 if (ch->ptrs_proc != NULL) {
00464 DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00465 ch->ptrs_proc();
00466 }
00467 }
00468
00469 DEBUG(sl, 1, "All pointers nulled");
00470
00471 assert(_sl.action == SLA_NULL);
00472 }
00473
00482 void NORETURN SlError(StringID string, const char *extra_msg)
00483 {
00484
00485 if (_sl.action == SLA_LOAD_CHECK) {
00486 _load_check_data.error = string;
00487 free(_load_check_data.error_data);
00488 _load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00489 } else {
00490 _sl.error_str = string;
00491 free(_sl.extra_msg);
00492 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00493 }
00494
00495
00496
00497
00498
00499 if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00500 throw std::exception();
00501 }
00502
00510 void NORETURN SlErrorCorrupt(const char *msg)
00511 {
00512 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00513 }
00514
00515
00516 typedef void (*AsyncSaveFinishProc)();
00517 static AsyncSaveFinishProc _async_save_finish = NULL;
00518 static ThreadObject *_save_thread;
00519
00524 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00525 {
00526 if (_exit_game) return;
00527 while (_async_save_finish != NULL) CSleep(10);
00528
00529 _async_save_finish = proc;
00530 }
00531
00535 void ProcessAsyncSaveFinish()
00536 {
00537 if (_async_save_finish == NULL) return;
00538
00539 _async_save_finish();
00540
00541 _async_save_finish = NULL;
00542
00543 if (_save_thread != NULL) {
00544 _save_thread->Join();
00545 delete _save_thread;
00546 _save_thread = NULL;
00547 }
00548 }
00549
00554 byte SlReadByte()
00555 {
00556 return _sl.reader->ReadByte();
00557 }
00558
00563 void SlWriteByte(byte b)
00564 {
00565 _sl.dumper->WriteByte(b);
00566 }
00567
00568 static inline int SlReadUint16()
00569 {
00570 int x = SlReadByte() << 8;
00571 return x | SlReadByte();
00572 }
00573
00574 static inline uint32 SlReadUint32()
00575 {
00576 uint32 x = SlReadUint16() << 16;
00577 return x | SlReadUint16();
00578 }
00579
00580 static inline uint64 SlReadUint64()
00581 {
00582 uint32 x = SlReadUint32();
00583 uint32 y = SlReadUint32();
00584 return (uint64)x << 32 | y;
00585 }
00586
00587 static inline void SlWriteUint16(uint16 v)
00588 {
00589 SlWriteByte(GB(v, 8, 8));
00590 SlWriteByte(GB(v, 0, 8));
00591 }
00592
00593 static inline void SlWriteUint32(uint32 v)
00594 {
00595 SlWriteUint16(GB(v, 16, 16));
00596 SlWriteUint16(GB(v, 0, 16));
00597 }
00598
00599 static inline void SlWriteUint64(uint64 x)
00600 {
00601 SlWriteUint32((uint32)(x >> 32));
00602 SlWriteUint32((uint32)x);
00603 }
00604
00610 static inline void SlSkipBytes(size_t length)
00611 {
00612 for (; length != 0; length--) SlReadByte();
00613 }
00614
00624 static uint SlReadSimpleGamma()
00625 {
00626 uint i = SlReadByte();
00627 if (HasBit(i, 7)) {
00628 i &= ~0x80;
00629 if (HasBit(i, 6)) {
00630 i &= ~0x40;
00631 if (HasBit(i, 5)) {
00632 i &= ~0x20;
00633 if (HasBit(i, 4)) {
00634 SlErrorCorrupt("Unsupported gamma");
00635 }
00636 i = (i << 8) | SlReadByte();
00637 }
00638 i = (i << 8) | SlReadByte();
00639 }
00640 i = (i << 8) | SlReadByte();
00641 }
00642 return i;
00643 }
00644
00657 static void SlWriteSimpleGamma(size_t i)
00658 {
00659 if (i >= (1 << 7)) {
00660 if (i >= (1 << 14)) {
00661 if (i >= (1 << 21)) {
00662 assert(i < (1 << 28));
00663 SlWriteByte((byte)(0xE0 | (i >> 24)));
00664 SlWriteByte((byte)(i >> 16));
00665 } else {
00666 SlWriteByte((byte)(0xC0 | (i >> 16)));
00667 }
00668 SlWriteByte((byte)(i >> 8));
00669 } else {
00670 SlWriteByte((byte)(0x80 | (i >> 8)));
00671 }
00672 }
00673 SlWriteByte((byte)i);
00674 }
00675
00677 static inline uint SlGetGammaLength(size_t i)
00678 {
00679 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00680 }
00681
00682 static inline uint SlReadSparseIndex()
00683 {
00684 return SlReadSimpleGamma();
00685 }
00686
00687 static inline void SlWriteSparseIndex(uint index)
00688 {
00689 SlWriteSimpleGamma(index);
00690 }
00691
00692 static inline uint SlReadArrayLength()
00693 {
00694 return SlReadSimpleGamma();
00695 }
00696
00697 static inline void SlWriteArrayLength(size_t length)
00698 {
00699 SlWriteSimpleGamma(length);
00700 }
00701
00702 static inline uint SlGetArrayLength(size_t length)
00703 {
00704 return SlGetGammaLength(length);
00705 }
00706
00713 static inline uint SlCalcConvMemLen(VarType conv)
00714 {
00715 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00716 byte length = GB(conv, 4, 4);
00717
00718 switch (length << 4) {
00719 case SLE_VAR_STRB:
00720 case SLE_VAR_STRBQ:
00721 case SLE_VAR_STR:
00722 case SLE_VAR_STRQ:
00723 return SlReadArrayLength();
00724
00725 default:
00726 assert(length < lengthof(conv_mem_size));
00727 return conv_mem_size[length];
00728 }
00729 }
00730
00737 static inline byte SlCalcConvFileLen(VarType conv)
00738 {
00739 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00740 byte length = GB(conv, 0, 4);
00741 assert(length < lengthof(conv_file_size));
00742 return conv_file_size[length];
00743 }
00744
00746 static inline size_t SlCalcRefLen()
00747 {
00748 return IsSavegameVersionBefore(69) ? 2 : 4;
00749 }
00750
00751 void SlSetArrayIndex(uint index)
00752 {
00753 _sl.need_length = NL_WANTLENGTH;
00754 _sl.array_index = index;
00755 }
00756
00757 static size_t _next_offs;
00758
00763 int SlIterateArray()
00764 {
00765 int index;
00766
00767
00768
00769 if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00770
00771 for (;;) {
00772 uint length = SlReadArrayLength();
00773 if (length == 0) {
00774 _next_offs = 0;
00775 return -1;
00776 }
00777
00778 _sl.obj_len = --length;
00779 _next_offs = _sl.reader->GetSize() + length;
00780
00781 switch (_sl.block_mode) {
00782 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00783 case CH_ARRAY: index = _sl.array_index++; break;
00784 default:
00785 DEBUG(sl, 0, "SlIterateArray error");
00786 return -1;
00787 }
00788
00789 if (length != 0) return index;
00790 }
00791 }
00792
00796 void SlSkipArray()
00797 {
00798 while (SlIterateArray() != -1) {
00799 SlSkipBytes(_next_offs - _sl.reader->GetSize());
00800 }
00801 }
00802
00808 void SlSetLength(size_t length)
00809 {
00810 assert(_sl.action == SLA_SAVE);
00811
00812 switch (_sl.need_length) {
00813 case NL_WANTLENGTH:
00814 _sl.need_length = NL_NONE;
00815 switch (_sl.block_mode) {
00816 case CH_RIFF:
00817
00818
00819
00820 assert(length < (1 << 28));
00821 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00822 break;
00823 case CH_ARRAY:
00824 assert(_sl.last_array_index <= _sl.array_index);
00825 while (++_sl.last_array_index <= _sl.array_index) {
00826 SlWriteArrayLength(1);
00827 }
00828 SlWriteArrayLength(length + 1);
00829 break;
00830 case CH_SPARSE_ARRAY:
00831 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00832 SlWriteSparseIndex(_sl.array_index);
00833 break;
00834 default: NOT_REACHED();
00835 }
00836 break;
00837
00838 case NL_CALCLENGTH:
00839 _sl.obj_len += (int)length;
00840 break;
00841
00842 default: NOT_REACHED();
00843 }
00844 }
00845
00852 static void SlCopyBytes(void *ptr, size_t length)
00853 {
00854 byte *p = (byte *)ptr;
00855
00856 switch (_sl.action) {
00857 case SLA_LOAD_CHECK:
00858 case SLA_LOAD:
00859 for (; length != 0; length--) *p++ = SlReadByte();
00860 break;
00861 case SLA_SAVE:
00862 for (; length != 0; length--) SlWriteByte(*p++);
00863 break;
00864 default: NOT_REACHED();
00865 }
00866 }
00867
00869 size_t SlGetFieldLength()
00870 {
00871 return _sl.obj_len;
00872 }
00873
00881 int64 ReadValue(const void *ptr, VarType conv)
00882 {
00883 switch (GetVarMemType(conv)) {
00884 case SLE_VAR_BL: return (*(bool *)ptr != 0);
00885 case SLE_VAR_I8: return *(int8 *)ptr;
00886 case SLE_VAR_U8: return *(byte *)ptr;
00887 case SLE_VAR_I16: return *(int16 *)ptr;
00888 case SLE_VAR_U16: return *(uint16*)ptr;
00889 case SLE_VAR_I32: return *(int32 *)ptr;
00890 case SLE_VAR_U32: return *(uint32*)ptr;
00891 case SLE_VAR_I64: return *(int64 *)ptr;
00892 case SLE_VAR_U64: return *(uint64*)ptr;
00893 case SLE_VAR_NULL:return 0;
00894 default: NOT_REACHED();
00895 }
00896 }
00897
00905 void WriteValue(void *ptr, VarType conv, int64 val)
00906 {
00907 switch (GetVarMemType(conv)) {
00908 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00909 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00910 case SLE_VAR_U8: *(byte *)ptr = val; break;
00911 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00912 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00913 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00914 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00915 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00916 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00917 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00918 case SLE_VAR_NULL: break;
00919 default: NOT_REACHED();
00920 }
00921 }
00922
00931 static void SlSaveLoadConv(void *ptr, VarType conv)
00932 {
00933 switch (_sl.action) {
00934 case SLA_SAVE: {
00935 int64 x = ReadValue(ptr, conv);
00936
00937
00938 switch (GetVarFileType(conv)) {
00939 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00940 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00941 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00942 case SLE_FILE_STRINGID:
00943 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00944 case SLE_FILE_I32:
00945 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00946 case SLE_FILE_I64:
00947 case SLE_FILE_U64: SlWriteUint64(x);break;
00948 default: NOT_REACHED();
00949 }
00950 break;
00951 }
00952 case SLA_LOAD_CHECK:
00953 case SLA_LOAD: {
00954 int64 x;
00955
00956 switch (GetVarFileType(conv)) {
00957 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00958 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00959 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00960 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00961 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00962 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00963 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00964 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00965 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00966 default: NOT_REACHED();
00967 }
00968
00969
00970 WriteValue(ptr, conv, x);
00971 break;
00972 }
00973 case SLA_PTRS: break;
00974 case SLA_NULL: break;
00975 default: NOT_REACHED();
00976 }
00977 }
00978
00988 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
00989 {
00990 if (ptr == NULL) return 0;
00991 return min(strlen(ptr), length - 1);
00992 }
00993
01003 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
01004 {
01005 size_t len;
01006 const char *str;
01007
01008 switch (GetVarMemType(conv)) {
01009 default: NOT_REACHED();
01010 case SLE_VAR_STR:
01011 case SLE_VAR_STRQ:
01012 str = *(const char**)ptr;
01013 len = SIZE_MAX;
01014 break;
01015 case SLE_VAR_STRB:
01016 case SLE_VAR_STRBQ:
01017 str = (const char*)ptr;
01018 len = length;
01019 break;
01020 }
01021
01022 len = SlCalcNetStringLen(str, len);
01023 return len + SlGetArrayLength(len);
01024 }
01025
01032 static void SlString(void *ptr, size_t length, VarType conv)
01033 {
01034 switch (_sl.action) {
01035 case SLA_SAVE: {
01036 size_t len;
01037 switch (GetVarMemType(conv)) {
01038 default: NOT_REACHED();
01039 case SLE_VAR_STRB:
01040 case SLE_VAR_STRBQ:
01041 len = SlCalcNetStringLen((char *)ptr, length);
01042 break;
01043 case SLE_VAR_STR:
01044 case SLE_VAR_STRQ:
01045 ptr = *(char **)ptr;
01046 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01047 break;
01048 }
01049
01050 SlWriteArrayLength(len);
01051 SlCopyBytes(ptr, len);
01052 break;
01053 }
01054 case SLA_LOAD_CHECK:
01055 case SLA_LOAD: {
01056 size_t len = SlReadArrayLength();
01057
01058 switch (GetVarMemType(conv)) {
01059 default: NOT_REACHED();
01060 case SLE_VAR_STRB:
01061 case SLE_VAR_STRBQ:
01062 if (len >= length) {
01063 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01064 SlCopyBytes(ptr, length);
01065 SlSkipBytes(len - length);
01066 len = length - 1;
01067 } else {
01068 SlCopyBytes(ptr, len);
01069 }
01070 break;
01071 case SLE_VAR_STR:
01072 case SLE_VAR_STRQ:
01073 free(*(char **)ptr);
01074 if (len == 0) {
01075 *(char **)ptr = NULL;
01076 } else {
01077 *(char **)ptr = MallocT<char>(len + 1);
01078 ptr = *(char **)ptr;
01079 SlCopyBytes(ptr, len);
01080 }
01081 break;
01082 }
01083
01084 ((char *)ptr)[len] = '\0';
01085 str_validate((char *)ptr, (char *)ptr + len);
01086 break;
01087 }
01088 case SLA_PTRS: break;
01089 case SLA_NULL: break;
01090 default: NOT_REACHED();
01091 }
01092 }
01093
01099 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01100 {
01101 return SlCalcConvFileLen(conv) * length;
01102 }
01103
01110 void SlArray(void *array, size_t length, VarType conv)
01111 {
01112 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01113
01114
01115 if (_sl.need_length != NL_NONE) {
01116 SlSetLength(SlCalcArrayLen(length, conv));
01117
01118 if (_sl.need_length == NL_CALCLENGTH) return;
01119 }
01120
01121
01122
01123 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01124
01125 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01126 conv == SLE_INT32 || conv == SLE_UINT32) {
01127 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01128 return;
01129 }
01130
01131 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01132 for (uint i = 0; i < length; i++) {
01133 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01134 }
01135 return;
01136 }
01137 }
01138
01139
01140
01141 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01142 SlCopyBytes(array, length);
01143 } else {
01144 byte *a = (byte*)array;
01145 byte mem_size = SlCalcConvMemLen(conv);
01146
01147 for (; length != 0; length --) {
01148 SlSaveLoadConv(a, conv);
01149 a += mem_size;
01150 }
01151 }
01152 }
01153
01154
01165 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01166 {
01167 assert(_sl.action == SLA_SAVE);
01168
01169 if (obj == NULL) return 0;
01170
01171 switch (rt) {
01172 case REF_VEHICLE_OLD:
01173 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01174 case REF_STATION: return ((const Station*)obj)->index + 1;
01175 case REF_TOWN: return ((const Town*)obj)->index + 1;
01176 case REF_ORDER: return ((const Order*)obj)->index + 1;
01177 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01178 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01179 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01180 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01181 default: NOT_REACHED();
01182 }
01183 }
01184
01195 static void *IntToReference(size_t index, SLRefType rt)
01196 {
01197 assert_compile(sizeof(size_t) <= sizeof(void *));
01198
01199 assert(_sl.action == SLA_PTRS);
01200
01201
01202
01203 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01204 rt = REF_VEHICLE;
01205 }
01206
01207
01208 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01209
01210
01211
01212 if (rt != REF_VEHICLE_OLD) index--;
01213
01214 switch (rt) {
01215 case REF_ORDERLIST:
01216 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01217 SlErrorCorrupt("Referencing invalid OrderList");
01218
01219 case REF_ORDER:
01220 if (Order::IsValidID(index)) return Order::Get(index);
01221
01222 if (IsSavegameVersionBefore(5, 2)) return NULL;
01223 SlErrorCorrupt("Referencing invalid Order");
01224
01225 case REF_VEHICLE_OLD:
01226 case REF_VEHICLE:
01227 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01228 SlErrorCorrupt("Referencing invalid Vehicle");
01229
01230 case REF_STATION:
01231 if (Station::IsValidID(index)) return Station::Get(index);
01232 SlErrorCorrupt("Referencing invalid Station");
01233
01234 case REF_TOWN:
01235 if (Town::IsValidID(index)) return Town::Get(index);
01236 SlErrorCorrupt("Referencing invalid Town");
01237
01238 case REF_ROADSTOPS:
01239 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01240 SlErrorCorrupt("Referencing invalid RoadStop");
01241
01242 case REF_ENGINE_RENEWS:
01243 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01244 SlErrorCorrupt("Referencing invalid EngineRenew");
01245
01246 case REF_CARGO_PACKET:
01247 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01248 SlErrorCorrupt("Referencing invalid CargoPacket");
01249
01250 default: NOT_REACHED();
01251 }
01252 }
01253
01258 static inline size_t SlCalcListLen(const void *list)
01259 {
01260 std::list<void *> *l = (std::list<void *> *) list;
01261
01262 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01263
01264
01265 return l->size() * type_size + type_size;
01266 }
01267
01268
01274 static void SlList(void *list, SLRefType conv)
01275 {
01276
01277 if (_sl.need_length != NL_NONE) {
01278 SlSetLength(SlCalcListLen(list));
01279
01280 if (_sl.need_length == NL_CALCLENGTH) return;
01281 }
01282
01283 typedef std::list<void *> PtrList;
01284 PtrList *l = (PtrList *)list;
01285
01286 switch (_sl.action) {
01287 case SLA_SAVE: {
01288 SlWriteUint32((uint32)l->size());
01289
01290 PtrList::iterator iter;
01291 for (iter = l->begin(); iter != l->end(); ++iter) {
01292 void *ptr = *iter;
01293 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01294 }
01295 break;
01296 }
01297 case SLA_LOAD_CHECK:
01298 case SLA_LOAD: {
01299 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01300
01301
01302 for (size_t i = 0; i < length; i++) {
01303 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01304 l->push_back((void *)data);
01305 }
01306 break;
01307 }
01308 case SLA_PTRS: {
01309 PtrList temp = *l;
01310
01311 l->clear();
01312 PtrList::iterator iter;
01313 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01314 void *ptr = IntToReference((size_t)*iter, conv);
01315 l->push_back(ptr);
01316 }
01317 break;
01318 }
01319 case SLA_NULL:
01320 l->clear();
01321 break;
01322 default: NOT_REACHED();
01323 }
01324 }
01325
01326
01328 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01329 {
01330 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01331 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01332
01333 return true;
01334 }
01335
01341 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01342 {
01343 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01344 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01345 return true;
01346 }
01347
01348 return false;
01349 }
01350
01357 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01358 {
01359 size_t length = 0;
01360
01361
01362 for (; sld->cmd != SL_END; sld++) {
01363 length += SlCalcObjMemberLength(object, sld);
01364 }
01365 return length;
01366 }
01367
01368 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01369 {
01370 assert(_sl.action == SLA_SAVE);
01371
01372 switch (sld->cmd) {
01373 case SL_VAR:
01374 case SL_REF:
01375 case SL_ARR:
01376 case SL_STR:
01377 case SL_LST:
01378
01379 if (!SlIsObjectValidInSavegame(sld)) break;
01380
01381 switch (sld->cmd) {
01382 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01383 case SL_REF: return SlCalcRefLen();
01384 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01385 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01386 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01387 default: NOT_REACHED();
01388 }
01389 break;
01390 case SL_WRITEBYTE: return 1;
01391 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01392 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01393 default: NOT_REACHED();
01394 }
01395 return 0;
01396 }
01397
01398
01399 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01400 {
01401 VarType conv = GB(sld->conv, 0, 8);
01402 switch (sld->cmd) {
01403 case SL_VAR:
01404 case SL_REF:
01405 case SL_ARR:
01406 case SL_STR:
01407 case SL_LST:
01408
01409 if (!SlIsObjectValidInSavegame(sld)) return false;
01410 if (SlSkipVariableOnLoad(sld)) return false;
01411
01412 switch (sld->cmd) {
01413 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01414 case SL_REF:
01415 switch (_sl.action) {
01416 case SLA_SAVE:
01417 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01418 break;
01419 case SLA_LOAD_CHECK:
01420 case SLA_LOAD:
01421 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01422 break;
01423 case SLA_PTRS:
01424 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01425 break;
01426 case SLA_NULL:
01427 *(void **)ptr = NULL;
01428 break;
01429 default: NOT_REACHED();
01430 }
01431 break;
01432 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01433 case SL_STR: SlString(ptr, sld->length, conv); break;
01434 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01435 default: NOT_REACHED();
01436 }
01437 break;
01438
01439
01440
01441
01442
01443
01444 case SL_WRITEBYTE:
01445 switch (_sl.action) {
01446 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01447 case SLA_LOAD_CHECK:
01448 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01449 case SLA_PTRS: break;
01450 case SLA_NULL: break;
01451 default: NOT_REACHED();
01452 }
01453 break;
01454
01455
01456 case SL_VEH_INCLUDE:
01457 SlObject(ptr, GetVehicleDescription(VEH_END));
01458 break;
01459
01460 case SL_ST_INCLUDE:
01461 SlObject(ptr, GetBaseStationDescription());
01462 break;
01463
01464 default: NOT_REACHED();
01465 }
01466 return true;
01467 }
01468
01474 void SlObject(void *object, const SaveLoad *sld)
01475 {
01476
01477 if (_sl.need_length != NL_NONE) {
01478 SlSetLength(SlCalcObjLength(object, sld));
01479 if (_sl.need_length == NL_CALCLENGTH) return;
01480 }
01481
01482 for (; sld->cmd != SL_END; sld++) {
01483 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01484 SlObjectMember(ptr, sld);
01485 }
01486 }
01487
01492 void SlGlobList(const SaveLoadGlobVarList *sldg)
01493 {
01494 SlObject(NULL, (const SaveLoad*)sldg);
01495 }
01496
01502 void SlAutolength(AutolengthProc *proc, void *arg)
01503 {
01504 size_t offs;
01505
01506 assert(_sl.action == SLA_SAVE);
01507
01508
01509 _sl.need_length = NL_CALCLENGTH;
01510 _sl.obj_len = 0;
01511 proc(arg);
01512
01513
01514 _sl.need_length = NL_WANTLENGTH;
01515 SlSetLength(_sl.obj_len);
01516
01517 offs = _sl.dumper->GetSize() + _sl.obj_len;
01518
01519
01520 proc(arg);
01521
01522 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01523 }
01524
01529 static void SlLoadChunk(const ChunkHandler *ch)
01530 {
01531 byte m = SlReadByte();
01532 size_t len;
01533 size_t endoffs;
01534
01535 _sl.block_mode = m;
01536 _sl.obj_len = 0;
01537
01538 switch (m) {
01539 case CH_ARRAY:
01540 _sl.array_index = 0;
01541 ch->load_proc();
01542 break;
01543 case CH_SPARSE_ARRAY:
01544 ch->load_proc();
01545 break;
01546 default:
01547 if ((m & 0xF) == CH_RIFF) {
01548
01549 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01550 len += SlReadUint16();
01551 _sl.obj_len = len;
01552 endoffs = _sl.reader->GetSize() + len;
01553 ch->load_proc();
01554 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01555 } else {
01556 SlErrorCorrupt("Invalid chunk type");
01557 }
01558 break;
01559 }
01560 }
01561
01567 static void SlLoadCheckChunk(const ChunkHandler *ch)
01568 {
01569 byte m = SlReadByte();
01570 size_t len;
01571 size_t endoffs;
01572
01573 _sl.block_mode = m;
01574 _sl.obj_len = 0;
01575
01576 switch (m) {
01577 case CH_ARRAY:
01578 _sl.array_index = 0;
01579 if (ch->load_check_proc) {
01580 ch->load_check_proc();
01581 } else {
01582 SlSkipArray();
01583 }
01584 break;
01585 case CH_SPARSE_ARRAY:
01586 if (ch->load_check_proc) {
01587 ch->load_check_proc();
01588 } else {
01589 SlSkipArray();
01590 }
01591 break;
01592 default:
01593 if ((m & 0xF) == CH_RIFF) {
01594
01595 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01596 len += SlReadUint16();
01597 _sl.obj_len = len;
01598 endoffs = _sl.reader->GetSize() + len;
01599 if (ch->load_check_proc) {
01600 ch->load_check_proc();
01601 } else {
01602 SlSkipBytes(len);
01603 }
01604 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01605 } else {
01606 SlErrorCorrupt("Invalid chunk type");
01607 }
01608 break;
01609 }
01610 }
01611
01616 static ChunkSaveLoadProc *_stub_save_proc;
01617
01623 static inline void SlStubSaveProc2(void *arg)
01624 {
01625 _stub_save_proc();
01626 }
01627
01633 static void SlStubSaveProc()
01634 {
01635 SlAutolength(SlStubSaveProc2, NULL);
01636 }
01637
01643 static void SlSaveChunk(const ChunkHandler *ch)
01644 {
01645 ChunkSaveLoadProc *proc = ch->save_proc;
01646
01647
01648 if (proc == NULL) return;
01649
01650 SlWriteUint32(ch->id);
01651 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01652
01653 if (ch->flags & CH_AUTO_LENGTH) {
01654
01655 _stub_save_proc = proc;
01656 proc = SlStubSaveProc;
01657 }
01658
01659 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01660 switch (ch->flags & CH_TYPE_MASK) {
01661 case CH_RIFF:
01662 _sl.need_length = NL_WANTLENGTH;
01663 proc();
01664 break;
01665 case CH_ARRAY:
01666 _sl.last_array_index = 0;
01667 SlWriteByte(CH_ARRAY);
01668 proc();
01669 SlWriteArrayLength(0);
01670 break;
01671 case CH_SPARSE_ARRAY:
01672 SlWriteByte(CH_SPARSE_ARRAY);
01673 proc();
01674 SlWriteArrayLength(0);
01675 break;
01676 default: NOT_REACHED();
01677 }
01678 }
01679
01681 static void SlSaveChunks()
01682 {
01683 FOR_ALL_CHUNK_HANDLERS(ch) {
01684 SlSaveChunk(ch);
01685 }
01686
01687
01688 SlWriteUint32(0);
01689 }
01690
01697 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01698 {
01699 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01700 return NULL;
01701 }
01702
01704 static void SlLoadChunks()
01705 {
01706 uint32 id;
01707 const ChunkHandler *ch;
01708
01709 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01710 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01711
01712 ch = SlFindChunkHandler(id);
01713 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01714 SlLoadChunk(ch);
01715 }
01716 }
01717
01719 static void SlLoadCheckChunks()
01720 {
01721 uint32 id;
01722 const ChunkHandler *ch;
01723
01724 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01725 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01726
01727 ch = SlFindChunkHandler(id);
01728 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01729 SlLoadCheckChunk(ch);
01730 }
01731 }
01732
01734 static void SlFixPointers()
01735 {
01736 _sl.action = SLA_PTRS;
01737
01738 DEBUG(sl, 1, "Fixing pointers");
01739
01740 FOR_ALL_CHUNK_HANDLERS(ch) {
01741 if (ch->ptrs_proc != NULL) {
01742 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01743 ch->ptrs_proc();
01744 }
01745 }
01746
01747 DEBUG(sl, 1, "All pointers fixed");
01748
01749 assert(_sl.action == SLA_PTRS);
01750 }
01751
01752
01754 struct FileReader : LoadFilter {
01755 FILE *file;
01756 long begin;
01757
01762 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01763 {
01764 }
01765
01767 ~FileReader()
01768 {
01769 if (this->file != NULL) fclose(this->file);
01770 this->file = NULL;
01771
01772
01773 _sl.sf = NULL;
01774 }
01775
01776 size_t Read(byte *buf, size_t size)
01777 {
01778
01779 if (this->file == NULL) return 0;
01780
01781 return fread(buf, 1, size, this->file);
01782 }
01783
01784 void Reset()
01785 {
01786 clearerr(this->file);
01787 fseek(this->file, this->begin, SEEK_SET);
01788 }
01789 };
01790
01792 struct FileWriter : SaveFilter {
01793 FILE *file;
01794
01799 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01800 {
01801 }
01802
01804 ~FileWriter()
01805 {
01806 this->Finish();
01807
01808
01809 _sl.sf = NULL;
01810 }
01811
01812 void Write(byte *buf, size_t size)
01813 {
01814
01815 if (this->file == NULL) return;
01816
01817 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01818 }
01819
01820 void Finish()
01821 {
01822 if (this->file != NULL) fclose(this->file);
01823 this->file = NULL;
01824 }
01825 };
01826
01827
01828
01829
01830
01831 #ifdef WITH_LZO
01832 #include <lzo/lzo1x.h>
01833
01835 static const uint LZO_BUFFER_SIZE = 8192;
01836
01838 struct LZOLoadFilter : LoadFilter {
01843 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01844 {
01845 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01846 }
01847
01848 size_t Read(byte *buf, size_t ssize)
01849 {
01850 assert(ssize >= LZO_BUFFER_SIZE);
01851
01852
01853 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01854 uint32 tmp[2];
01855 uint32 size;
01856 lzo_uint len;
01857
01858
01859 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01860
01861
01862 ((uint32*)out)[0] = size = tmp[1];
01863
01864 if (_sl_version != 0) {
01865 tmp[0] = TO_BE32(tmp[0]);
01866 size = TO_BE32(size);
01867 }
01868
01869 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01870
01871
01872 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01873
01874
01875 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01876
01877
01878 lzo1x_decompress(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01879 return len;
01880 }
01881 };
01882
01884 struct LZOSaveFilter : SaveFilter {
01890 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01891 {
01892 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01893 }
01894
01895 void Write(byte *buf, size_t size)
01896 {
01897 const lzo_bytep in = buf;
01898
01899 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01900 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01901 lzo_uint outlen;
01902
01903 do {
01904
01905 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01906 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01907 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01908 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01909 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01910
01911
01912 size -= len;
01913 in += len;
01914 } while (size > 0);
01915 }
01916 };
01917
01918 #endif
01919
01920
01921
01922
01923
01925 struct NoCompLoadFilter : LoadFilter {
01930 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01931 {
01932 }
01933
01934 size_t Read(byte *buf, size_t size)
01935 {
01936 return this->chain->Read(buf, size);
01937 }
01938 };
01939
01941 struct NoCompSaveFilter : SaveFilter {
01947 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01948 {
01949 }
01950
01951 void Write(byte *buf, size_t size)
01952 {
01953 this->chain->Write(buf, size);
01954 }
01955 };
01956
01957
01958
01959
01960
01961 #if defined(WITH_ZLIB)
01962 #include <zlib.h>
01963
01965 struct ZlibLoadFilter : LoadFilter {
01966 z_stream z;
01967 byte fread_buf[MEMORY_CHUNK_SIZE];
01968
01973 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01974 {
01975 memset(&this->z, 0, sizeof(this->z));
01976 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01977 }
01978
01980 ~ZlibLoadFilter()
01981 {
01982 inflateEnd(&this->z);
01983 }
01984
01985 size_t Read(byte *buf, size_t size)
01986 {
01987 this->z.next_out = buf;
01988 this->z.avail_out = (uint)size;
01989
01990 do {
01991
01992 if (this->z.avail_in == 0) {
01993 this->z.next_in = this->fread_buf;
01994 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
01995 }
01996
01997
01998 int r = inflate(&this->z, 0);
01999 if (r == Z_STREAM_END) break;
02000
02001 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02002 } while (this->z.avail_out != 0);
02003
02004 return size - this->z.avail_out;
02005 }
02006 };
02007
02009 struct ZlibSaveFilter : SaveFilter {
02010 z_stream z;
02011
02017 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02018 {
02019 memset(&this->z, 0, sizeof(this->z));
02020 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02021 }
02022
02024 ~ZlibSaveFilter()
02025 {
02026 deflateEnd(&this->z);
02027 }
02028
02035 void WriteLoop(byte *p, size_t len, int mode)
02036 {
02037 byte buf[MEMORY_CHUNK_SIZE];
02038 uint n;
02039 this->z.next_in = p;
02040 this->z.avail_in = (uInt)len;
02041 do {
02042 this->z.next_out = buf;
02043 this->z.avail_out = sizeof(buf);
02044
02052 int r = deflate(&this->z, mode);
02053
02054
02055 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02056 this->chain->Write(buf, n);
02057 }
02058 if (r == Z_STREAM_END) break;
02059
02060 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02061 } while (this->z.avail_in || !this->z.avail_out);
02062 }
02063
02064 void Write(byte *buf, size_t size)
02065 {
02066 this->WriteLoop(buf, size, 0);
02067 }
02068
02069 void Finish()
02070 {
02071 this->WriteLoop(NULL, 0, Z_FINISH);
02072 this->chain->Finish();
02073 }
02074 };
02075
02076 #endif
02077
02078
02079
02080
02081
02082 #if defined(WITH_LZMA)
02083 #include <lzma.h>
02084
02091 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02092
02094 struct LZMALoadFilter : LoadFilter {
02095 lzma_stream lzma;
02096 byte fread_buf[MEMORY_CHUNK_SIZE];
02097
02102 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02103 {
02104
02105 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02106 }
02107
02109 ~LZMALoadFilter()
02110 {
02111 lzma_end(&this->lzma);
02112 }
02113
02114 size_t Read(byte *buf, size_t size)
02115 {
02116 this->lzma.next_out = buf;
02117 this->lzma.avail_out = size;
02118
02119 do {
02120
02121 if (this->lzma.avail_in == 0) {
02122 this->lzma.next_in = this->fread_buf;
02123 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02124 }
02125
02126
02127 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02128 if (r == LZMA_STREAM_END) break;
02129 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02130 } while (this->lzma.avail_out != 0);
02131
02132 return size - this->lzma.avail_out;
02133 }
02134 };
02135
02137 struct LZMASaveFilter : SaveFilter {
02138 lzma_stream lzma;
02139
02145 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02146 {
02147 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02148 }
02149
02151 ~LZMASaveFilter()
02152 {
02153 lzma_end(&this->lzma);
02154 }
02155
02162 void WriteLoop(byte *p, size_t len, lzma_action action)
02163 {
02164 byte buf[MEMORY_CHUNK_SIZE];
02165 size_t n;
02166 this->lzma.next_in = p;
02167 this->lzma.avail_in = len;
02168 do {
02169 this->lzma.next_out = buf;
02170 this->lzma.avail_out = sizeof(buf);
02171
02172 lzma_ret r = lzma_code(&this->lzma, action);
02173
02174
02175 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02176 this->chain->Write(buf, n);
02177 }
02178 if (r == LZMA_STREAM_END) break;
02179 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02180 } while (this->lzma.avail_in || !this->lzma.avail_out);
02181 }
02182
02183 void Write(byte *buf, size_t size)
02184 {
02185 this->WriteLoop(buf, size, LZMA_RUN);
02186 }
02187
02188 void Finish()
02189 {
02190 this->WriteLoop(NULL, 0, LZMA_FINISH);
02191 this->chain->Finish();
02192 }
02193 };
02194
02195 #endif
02196
02197
02198
02199
02200
02202 struct SaveLoadFormat {
02203 const char *name;
02204 uint32 tag;
02205
02206 LoadFilter *(*init_load)(LoadFilter *chain);
02207 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02208
02209 byte min_compression;
02210 byte default_compression;
02211 byte max_compression;
02212 };
02213
02215 static const SaveLoadFormat _saveload_formats[] = {
02216 #if defined(WITH_LZO)
02217
02218 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02219 #else
02220 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02221 #endif
02222
02223 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02224 #if defined(WITH_ZLIB)
02225
02226
02227
02228 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02229 #else
02230 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02231 #endif
02232 #if defined(WITH_LZMA)
02233
02234
02235
02236
02237
02238 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02239 #else
02240 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02241 #endif
02242 };
02243
02251 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02252 {
02253 const SaveLoadFormat *def = lastof(_saveload_formats);
02254
02255
02256 while (!def->init_write) def--;
02257
02258 if (!StrEmpty(s)) {
02259
02260 char *complevel = strrchr(s, ':');
02261 if (complevel != NULL) *complevel = '\0';
02262
02263 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02264 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02265 *compression_level = slf->default_compression;
02266 if (complevel != NULL) {
02267
02268
02269
02270 *complevel = ':';
02271 complevel++;
02272
02273
02274 char *end;
02275 long level = strtol(complevel, &end, 10);
02276 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02277 ShowInfoF("Compression level '%s' is not valid.", complevel);
02278 } else {
02279 *compression_level = level;
02280 }
02281 }
02282 return slf;
02283 }
02284 }
02285
02286 ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
02287
02288
02289 if (complevel != NULL) *complevel = ':';
02290 }
02291 *compression_level = def->default_compression;
02292 return def;
02293 }
02294
02295
02296 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02297 extern bool AfterLoadGame();
02298 extern bool LoadOldSaveGame(const char *file);
02299
02303 static inline void ClearSaveLoadState()
02304 {
02305 delete _sl.dumper;
02306 _sl.dumper = NULL;
02307
02308 delete _sl.sf;
02309 _sl.sf = NULL;
02310
02311 delete _sl.reader;
02312 _sl.reader = NULL;
02313
02314 delete _sl.lf;
02315 _sl.lf = NULL;
02316 }
02317
02323 static void SaveFileStart()
02324 {
02325 _sl.ff_state = _fast_forward;
02326 _fast_forward = 0;
02327 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02328
02329 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02330 _sl.saveinprogress = true;
02331 }
02332
02334 static void SaveFileDone()
02335 {
02336 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02337 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02338
02339 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02340 _sl.saveinprogress = false;
02341 }
02342
02344 void SetSaveLoadError(StringID str)
02345 {
02346 _sl.error_str = str;
02347 }
02348
02350 const char *GetSaveLoadErrorString()
02351 {
02352 SetDParam(0, _sl.error_str);
02353 SetDParamStr(1, _sl.extra_msg);
02354
02355 static char err_str[512];
02356 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02357 return err_str;
02358 }
02359
02361 static void SaveFileError()
02362 {
02363 SetDParamStr(0, GetSaveLoadErrorString());
02364 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02365 SaveFileDone();
02366 }
02367
02372 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02373 {
02374 try {
02375 byte compression;
02376 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02377
02378
02379 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02380 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02381
02382 _sl.sf = fmt->init_write(_sl.sf, compression);
02383 _sl.dumper->Flush(_sl.sf);
02384
02385 ClearSaveLoadState();
02386
02387 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02388
02389 return SL_OK;
02390 } catch (...) {
02391 ClearSaveLoadState();
02392
02393 AsyncSaveFinishProc asfp = SaveFileDone;
02394
02395
02396
02397 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02398
02399 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02400 asfp = SaveFileError;
02401 }
02402
02403 if (threaded) {
02404 SetAsyncSaveFinish(asfp);
02405 } else {
02406 asfp();
02407 }
02408 return SL_ERROR;
02409 }
02410 }
02411
02413 static void SaveFileToDiskThread(void *arg)
02414 {
02415 SaveFileToDisk(true);
02416 }
02417
02418 void WaitTillSaved()
02419 {
02420 if (_save_thread == NULL) return;
02421
02422 _save_thread->Join();
02423 delete _save_thread;
02424 _save_thread = NULL;
02425
02426
02427 ProcessAsyncSaveFinish();
02428 }
02429
02438 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02439 {
02440 assert(!_sl.saveinprogress);
02441
02442 _sl.dumper = new MemoryDumper();
02443 _sl.sf = writer;
02444
02445 _sl_version = SAVEGAME_VERSION;
02446
02447 SaveViewportBeforeSaveGame();
02448 SlSaveChunks();
02449
02450 SaveFileStart();
02451 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02452 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02453
02454 SaveOrLoadResult result = SaveFileToDisk(false);
02455 SaveFileDone();
02456
02457 return result;
02458 }
02459
02460 return SL_OK;
02461 }
02462
02469 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02470 {
02471 try {
02472 _sl.action = SLA_SAVE;
02473 return DoSave(writer, threaded);
02474 } catch (...) {
02475 ClearSaveLoadState();
02476 return SL_ERROR;
02477 }
02478 }
02479
02486 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02487 {
02488 _sl.lf = reader;
02489
02490 if (load_check) {
02491
02492 _load_check_data.Clear();
02493
02494 _load_check_data.checkable = true;
02495 }
02496
02497 uint32 hdr[2];
02498 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02499
02500
02501 const SaveLoadFormat *fmt = _saveload_formats;
02502 for (;;) {
02503
02504 if (fmt == endof(_saveload_formats)) {
02505 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02506 _sl.lf->Reset();
02507 _sl_version = 0;
02508 _sl_minor_version = 0;
02509
02510
02511 fmt = _saveload_formats;
02512 for (;;) {
02513 if (fmt == endof(_saveload_formats)) {
02514
02515 NOT_REACHED();
02516 }
02517 if (fmt->tag == TO_BE32X('OTTD')) break;
02518 fmt++;
02519 }
02520 break;
02521 }
02522
02523 if (fmt->tag == hdr[0]) {
02524
02525 _sl_version = TO_BE32(hdr[1]) >> 16;
02526
02527
02528
02529
02530 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02531
02532 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02533
02534
02535 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02536 break;
02537 }
02538
02539 fmt++;
02540 }
02541
02542
02543 if (fmt->init_load == NULL) {
02544 char err_str[64];
02545 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02546 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02547 }
02548
02549 _sl.lf = fmt->init_load(_sl.lf);
02550 _sl.reader = new ReadBuffer(_sl.lf);
02551 _next_offs = 0;
02552
02553 if (!load_check) {
02554 _engine_mngr.ResetToDefaultMapping();
02555
02556
02557
02558
02559 InitializeGame(256, 256, true, true);
02560
02561 GamelogReset();
02562
02563 if (IsSavegameVersionBefore(4)) {
02564
02565
02566
02567
02568
02569
02570
02571
02572
02573
02574
02575
02576
02577
02578
02579
02580
02581
02582
02583
02584
02585 ClearGRFConfigList(&_grfconfig);
02586 }
02587 }
02588
02589 if (load_check) {
02590
02591
02592 SlLoadCheckChunks();
02593 } else {
02594
02595 SlLoadChunks();
02596 SlFixPointers();
02597 }
02598
02599 ClearSaveLoadState();
02600
02601 _savegame_type = SGT_OTTD;
02602
02603 if (load_check) {
02604
02605 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02606 } else {
02607 GamelogStartAction(GLAT_LOAD);
02608
02609
02610
02611 if (!AfterLoadGame()) {
02612 GamelogStopAction();
02613 return SL_REINIT;
02614 }
02615
02616 GamelogStopAction();
02617 }
02618
02619 return SL_OK;
02620 }
02621
02627 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02628 {
02629 try {
02630 _sl.action = SLA_LOAD;
02631 return DoLoad(reader, false);
02632 } catch (...) {
02633 ClearSaveLoadState();
02634 return SL_REINIT;
02635 }
02636 }
02637
02647 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02648 {
02649
02650 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02651
02652 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02653 return SL_OK;
02654 }
02655 WaitTillSaved();
02656
02657
02658 if (mode == SL_OLD_LOAD) {
02659 _engine_mngr.ResetToDefaultMapping();
02660 InitializeGame(256, 256, true, true);
02661
02662
02663
02664
02665
02666 ClearGRFConfigList(&_grfconfig);
02667 GamelogReset();
02668 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02669 _sl_version = 0;
02670 _sl_minor_version = 0;
02671 GamelogStartAction(GLAT_LOAD);
02672 if (!AfterLoadGame()) {
02673 GamelogStopAction();
02674 return SL_REINIT;
02675 }
02676 GamelogStopAction();
02677 return SL_OK;
02678 }
02679
02680 switch (mode) {
02681 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02682 case SL_LOAD: _sl.action = SLA_LOAD; break;
02683 case SL_SAVE: _sl.action = SLA_SAVE; break;
02684 default: NOT_REACHED();
02685 }
02686
02687 try {
02688 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02689
02690
02691 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02692 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02693
02694 if (fh == NULL) {
02695 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02696 }
02697
02698 if (mode == SL_SAVE) {
02699 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02700 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02701
02702 return DoSave(new FileWriter(fh), threaded);
02703 }
02704
02705
02706 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02707 DEBUG(desync, 1, "load: %s", filename);
02708 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02709 } catch (...) {
02710 ClearSaveLoadState();
02711
02712
02713 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02714
02715
02716 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02717 }
02718 }
02719
02721 void DoExitSave()
02722 {
02723 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02724 }
02725
02731 void GenerateDefaultSaveName(char *buf, const char *last)
02732 {
02733
02734
02735
02736 CompanyID cid = _local_company;
02737 if (!Company::IsValidID(cid)) {
02738 const Company *c;
02739 FOR_ALL_COMPANIES(c) {
02740 cid = c->index;
02741 break;
02742 }
02743 }
02744
02745 SetDParam(0, cid);
02746
02747
02748 switch (_settings_client.gui.date_format_in_default_names) {
02749 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02750 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02751 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02752 default: NOT_REACHED();
02753 }
02754 SetDParam(2, _date);
02755
02756
02757 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02758 SanitizeFilename(buf);
02759 }
02760
02761 #if 0
02762
02768 int GetSavegameType(char *file)
02769 {
02770 const SaveLoadFormat *fmt;
02771 uint32 hdr;
02772 FILE *f;
02773 int mode = SL_OLD_LOAD;
02774
02775 f = fopen(file, "rb");
02776 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02777 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02778 mode = SL_LOAD;
02779 } else {
02780
02781 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02782 if (fmt->tag == hdr) {
02783 mode = SL_LOAD;
02784 break;
02785 }
02786 }
02787 }
02788
02789 fclose(f);
02790 return mode;
02791 }
02792 #endif