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 = INFRA_MAINT_FIX_SV;
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 _airport_chunk_handlers[];
00406 extern const ChunkHandler _object_chunk_handlers[];
00407 extern const ChunkHandler _linkgraph_chunk_handlers[];
00408 extern const ChunkHandler _signal_chunk_handlers[];
00409 extern const ChunkHandler _speed_signal_chunk_handlers[];
00410
00412 static const ChunkHandler * const _chunk_handlers[] = {
00413 _gamelog_chunk_handlers,
00414 _map_chunk_handlers,
00415 _misc_chunk_handlers,
00416 _name_chunk_handlers,
00417 _cheat_chunk_handlers,
00418 _setting_chunk_handlers,
00419 _veh_chunk_handlers,
00420 _waypoint_chunk_handlers,
00421 _depot_chunk_handlers,
00422 _order_chunk_handlers,
00423 _industry_chunk_handlers,
00424 _economy_chunk_handlers,
00425 _subsidy_chunk_handlers,
00426 _engine_chunk_handlers,
00427 _town_chunk_handlers,
00428 _sign_chunk_handlers,
00429 _station_chunk_handlers,
00430 _company_chunk_handlers,
00431 _ai_chunk_handlers,
00432 _animated_tile_chunk_handlers,
00433 _newgrf_chunk_handlers,
00434 _group_chunk_handlers,
00435 _cargopacket_chunk_handlers,
00436 _autoreplace_chunk_handlers,
00437 _labelmaps_chunk_handlers,
00438 _airport_chunk_handlers,
00439 _object_chunk_handlers,
00440 _linkgraph_chunk_handlers,
00441 _signal_chunk_handlers,
00442 _speed_signal_chunk_handlers,
00443 NULL,
00444 };
00445
00450 #define FOR_ALL_CHUNK_HANDLERS(ch) \
00451 for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \
00452 for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1)
00453
00455 static void SlNullPointers()
00456 {
00457 _sl.action = SLA_NULL;
00458
00459
00460
00461
00462 _sl_version = SAVEGAME_VERSION;
00463
00464 DEBUG(sl, 1, "Nulling pointers");
00465
00466 FOR_ALL_CHUNK_HANDLERS(ch) {
00467 if (ch->ptrs_proc != NULL) {
00468 DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00469 ch->ptrs_proc();
00470 }
00471 }
00472
00473 DEBUG(sl, 1, "All pointers nulled");
00474
00475 assert(_sl.action == SLA_NULL);
00476 }
00477
00486 void NORETURN SlError(StringID string, const char *extra_msg)
00487 {
00488
00489 if (_sl.action == SLA_LOAD_CHECK) {
00490 _load_check_data.error = string;
00491 free(_load_check_data.error_data);
00492 _load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00493 } else {
00494 _sl.error_str = string;
00495 free(_sl.extra_msg);
00496 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00497 }
00498
00499
00500
00501
00502
00503 if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00504 throw std::exception();
00505 }
00506
00514 void NORETURN SlErrorCorrupt(const char *msg)
00515 {
00516 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00517 }
00518
00519
00520 typedef void (*AsyncSaveFinishProc)();
00521 static AsyncSaveFinishProc _async_save_finish = NULL;
00522 static ThreadObject *_save_thread;
00523
00528 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00529 {
00530 if (_exit_game) return;
00531 while (_async_save_finish != NULL) CSleep(10);
00532
00533 _async_save_finish = proc;
00534 }
00535
00539 void ProcessAsyncSaveFinish()
00540 {
00541 if (_async_save_finish == NULL) return;
00542
00543 _async_save_finish();
00544
00545 _async_save_finish = NULL;
00546
00547 if (_save_thread != NULL) {
00548 _save_thread->Join();
00549 delete _save_thread;
00550 _save_thread = NULL;
00551 }
00552 }
00553
00558 byte SlReadByte()
00559 {
00560 return _sl.reader->ReadByte();
00561 }
00562
00567 void SlWriteByte(byte b)
00568 {
00569 _sl.dumper->WriteByte(b);
00570 }
00571
00572 static inline int SlReadUint16()
00573 {
00574 int x = SlReadByte() << 8;
00575 return x | SlReadByte();
00576 }
00577
00578 static inline uint32 SlReadUint32()
00579 {
00580 uint32 x = SlReadUint16() << 16;
00581 return x | SlReadUint16();
00582 }
00583
00584 static inline uint64 SlReadUint64()
00585 {
00586 uint32 x = SlReadUint32();
00587 uint32 y = SlReadUint32();
00588 return (uint64)x << 32 | y;
00589 }
00590
00591 static inline void SlWriteUint16(uint16 v)
00592 {
00593 SlWriteByte(GB(v, 8, 8));
00594 SlWriteByte(GB(v, 0, 8));
00595 }
00596
00597 static inline void SlWriteUint32(uint32 v)
00598 {
00599 SlWriteUint16(GB(v, 16, 16));
00600 SlWriteUint16(GB(v, 0, 16));
00601 }
00602
00603 static inline void SlWriteUint64(uint64 x)
00604 {
00605 SlWriteUint32((uint32)(x >> 32));
00606 SlWriteUint32((uint32)x);
00607 }
00608
00614 static inline void SlSkipBytes(size_t length)
00615 {
00616 for (; length != 0; length--) SlReadByte();
00617 }
00618
00628 static uint SlReadSimpleGamma()
00629 {
00630 uint i = SlReadByte();
00631 if (HasBit(i, 7)) {
00632 i &= ~0x80;
00633 if (HasBit(i, 6)) {
00634 i &= ~0x40;
00635 if (HasBit(i, 5)) {
00636 i &= ~0x20;
00637 if (HasBit(i, 4)) {
00638 SlErrorCorrupt("Unsupported gamma");
00639 }
00640 i = (i << 8) | SlReadByte();
00641 }
00642 i = (i << 8) | SlReadByte();
00643 }
00644 i = (i << 8) | SlReadByte();
00645 }
00646 return i;
00647 }
00648
00661 static void SlWriteSimpleGamma(size_t i)
00662 {
00663 if (i >= (1 << 7)) {
00664 if (i >= (1 << 14)) {
00665 if (i >= (1 << 21)) {
00666 assert(i < (1 << 28));
00667 SlWriteByte((byte)(0xE0 | (i >> 24)));
00668 SlWriteByte((byte)(i >> 16));
00669 } else {
00670 SlWriteByte((byte)(0xC0 | (i >> 16)));
00671 }
00672 SlWriteByte((byte)(i >> 8));
00673 } else {
00674 SlWriteByte((byte)(0x80 | (i >> 8)));
00675 }
00676 }
00677 SlWriteByte((byte)i);
00678 }
00679
00681 static inline uint SlGetGammaLength(size_t i)
00682 {
00683 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00684 }
00685
00686 static inline uint SlReadSparseIndex()
00687 {
00688 return SlReadSimpleGamma();
00689 }
00690
00691 static inline void SlWriteSparseIndex(uint index)
00692 {
00693 SlWriteSimpleGamma(index);
00694 }
00695
00696 static inline uint SlReadArrayLength()
00697 {
00698 return SlReadSimpleGamma();
00699 }
00700
00701 static inline void SlWriteArrayLength(size_t length)
00702 {
00703 SlWriteSimpleGamma(length);
00704 }
00705
00706 static inline uint SlGetArrayLength(size_t length)
00707 {
00708 return SlGetGammaLength(length);
00709 }
00710
00717 static inline uint SlCalcConvMemLen(VarType conv)
00718 {
00719 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00720 byte length = GB(conv, 4, 4);
00721
00722 switch (length << 4) {
00723 case SLE_VAR_STRB:
00724 case SLE_VAR_STRBQ:
00725 case SLE_VAR_STR:
00726 case SLE_VAR_STRQ:
00727 return SlReadArrayLength();
00728
00729 default:
00730 assert(length < lengthof(conv_mem_size));
00731 return conv_mem_size[length];
00732 }
00733 }
00734
00741 static inline byte SlCalcConvFileLen(VarType conv)
00742 {
00743 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00744 byte length = GB(conv, 0, 4);
00745 assert(length < lengthof(conv_file_size));
00746 return conv_file_size[length];
00747 }
00748
00750 static inline size_t SlCalcRefLen()
00751 {
00752 return IsSavegameVersionBefore(69) ? 2 : 4;
00753 }
00754
00755 void SlSetArrayIndex(uint index)
00756 {
00757 _sl.need_length = NL_WANTLENGTH;
00758 _sl.array_index = index;
00759 }
00760
00761 static size_t _next_offs;
00762
00767 int SlIterateArray()
00768 {
00769 int index;
00770
00771
00772
00773 if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00774
00775 for (;;) {
00776 uint length = SlReadArrayLength();
00777 if (length == 0) {
00778 _next_offs = 0;
00779 return -1;
00780 }
00781
00782 _sl.obj_len = --length;
00783 _next_offs = _sl.reader->GetSize() + length;
00784
00785 switch (_sl.block_mode) {
00786 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00787 case CH_ARRAY: index = _sl.array_index++; break;
00788 default:
00789 DEBUG(sl, 0, "SlIterateArray error");
00790 return -1;
00791 }
00792
00793 if (length != 0) return index;
00794 }
00795 }
00796
00800 void SlSkipArray()
00801 {
00802 while (SlIterateArray() != -1) {
00803 SlSkipBytes(_next_offs - _sl.reader->GetSize());
00804 }
00805 }
00806
00812 void SlSetLength(size_t length)
00813 {
00814 assert(_sl.action == SLA_SAVE);
00815
00816 switch (_sl.need_length) {
00817 case NL_WANTLENGTH:
00818 _sl.need_length = NL_NONE;
00819 switch (_sl.block_mode) {
00820 case CH_RIFF:
00821
00822
00823
00824 assert(length < (1 << 28));
00825 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00826 break;
00827 case CH_ARRAY:
00828 assert(_sl.last_array_index <= _sl.array_index);
00829 while (++_sl.last_array_index <= _sl.array_index) {
00830 SlWriteArrayLength(1);
00831 }
00832 SlWriteArrayLength(length + 1);
00833 break;
00834 case CH_SPARSE_ARRAY:
00835 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00836 SlWriteSparseIndex(_sl.array_index);
00837 break;
00838 default: NOT_REACHED();
00839 }
00840 break;
00841
00842 case NL_CALCLENGTH:
00843 _sl.obj_len += (int)length;
00844 break;
00845
00846 default: NOT_REACHED();
00847 }
00848 }
00849
00856 static void SlCopyBytes(void *ptr, size_t length)
00857 {
00858 byte *p = (byte *)ptr;
00859
00860 switch (_sl.action) {
00861 case SLA_LOAD_CHECK:
00862 case SLA_LOAD:
00863 for (; length != 0; length--) *p++ = SlReadByte();
00864 break;
00865 case SLA_SAVE:
00866 for (; length != 0; length--) SlWriteByte(*p++);
00867 break;
00868 default: NOT_REACHED();
00869 }
00870 }
00871
00873 size_t SlGetFieldLength()
00874 {
00875 return _sl.obj_len;
00876 }
00877
00885 int64 ReadValue(const void *ptr, VarType conv)
00886 {
00887 switch (GetVarMemType(conv)) {
00888 case SLE_VAR_BL: return (*(bool *)ptr != 0);
00889 case SLE_VAR_I8: return *(int8 *)ptr;
00890 case SLE_VAR_U8: return *(byte *)ptr;
00891 case SLE_VAR_I16: return *(int16 *)ptr;
00892 case SLE_VAR_U16: return *(uint16*)ptr;
00893 case SLE_VAR_I32: return *(int32 *)ptr;
00894 case SLE_VAR_U32: return *(uint32*)ptr;
00895 case SLE_VAR_I64: return *(int64 *)ptr;
00896 case SLE_VAR_U64: return *(uint64*)ptr;
00897 case SLE_VAR_NULL:return 0;
00898 default: NOT_REACHED();
00899 }
00900 }
00901
00909 void WriteValue(void *ptr, VarType conv, int64 val)
00910 {
00911 switch (GetVarMemType(conv)) {
00912 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00913 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00914 case SLE_VAR_U8: *(byte *)ptr = val; break;
00915 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00916 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00917 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00918 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00919 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00920 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00921 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00922 case SLE_VAR_NULL: break;
00923 default: NOT_REACHED();
00924 }
00925 }
00926
00935 static void SlSaveLoadConv(void *ptr, VarType conv)
00936 {
00937 switch (_sl.action) {
00938 case SLA_SAVE: {
00939 int64 x = ReadValue(ptr, conv);
00940
00941
00942 switch (GetVarFileType(conv)) {
00943 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00944 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00945 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00946 case SLE_FILE_STRINGID:
00947 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00948 case SLE_FILE_I32:
00949 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00950 case SLE_FILE_I64:
00951 case SLE_FILE_U64: SlWriteUint64(x);break;
00952 default: NOT_REACHED();
00953 }
00954 break;
00955 }
00956 case SLA_LOAD_CHECK:
00957 case SLA_LOAD: {
00958 int64 x;
00959
00960 switch (GetVarFileType(conv)) {
00961 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00962 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00963 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00964 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00965 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00966 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00967 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00968 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00969 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00970 default: NOT_REACHED();
00971 }
00972
00973
00974 WriteValue(ptr, conv, x);
00975 break;
00976 }
00977 case SLA_PTRS: break;
00978 case SLA_NULL: break;
00979 default: NOT_REACHED();
00980 }
00981 }
00982
00992 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
00993 {
00994 if (ptr == NULL) return 0;
00995 return min(strlen(ptr), length - 1);
00996 }
00997
01007 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
01008 {
01009 size_t len;
01010 const char *str;
01011
01012 switch (GetVarMemType(conv)) {
01013 default: NOT_REACHED();
01014 case SLE_VAR_STR:
01015 case SLE_VAR_STRQ:
01016 str = *(const char**)ptr;
01017 len = SIZE_MAX;
01018 break;
01019 case SLE_VAR_STRB:
01020 case SLE_VAR_STRBQ:
01021 str = (const char*)ptr;
01022 len = length;
01023 break;
01024 }
01025
01026 len = SlCalcNetStringLen(str, len);
01027 return len + SlGetArrayLength(len);
01028 }
01029
01036 static void SlString(void *ptr, size_t length, VarType conv)
01037 {
01038 switch (_sl.action) {
01039 case SLA_SAVE: {
01040 size_t len;
01041 switch (GetVarMemType(conv)) {
01042 default: NOT_REACHED();
01043 case SLE_VAR_STRB:
01044 case SLE_VAR_STRBQ:
01045 len = SlCalcNetStringLen((char *)ptr, length);
01046 break;
01047 case SLE_VAR_STR:
01048 case SLE_VAR_STRQ:
01049 ptr = *(char **)ptr;
01050 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01051 break;
01052 }
01053
01054 SlWriteArrayLength(len);
01055 SlCopyBytes(ptr, len);
01056 break;
01057 }
01058 case SLA_LOAD_CHECK:
01059 case SLA_LOAD: {
01060 size_t len = SlReadArrayLength();
01061
01062 switch (GetVarMemType(conv)) {
01063 default: NOT_REACHED();
01064 case SLE_VAR_STRB:
01065 case SLE_VAR_STRBQ:
01066 if (len >= length) {
01067 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01068 SlCopyBytes(ptr, length);
01069 SlSkipBytes(len - length);
01070 len = length - 1;
01071 } else {
01072 SlCopyBytes(ptr, len);
01073 }
01074 break;
01075 case SLE_VAR_STR:
01076 case SLE_VAR_STRQ:
01077 free(*(char **)ptr);
01078 if (len == 0) {
01079 *(char **)ptr = NULL;
01080 } else {
01081 *(char **)ptr = MallocT<char>(len + 1);
01082 ptr = *(char **)ptr;
01083 SlCopyBytes(ptr, len);
01084 }
01085 break;
01086 }
01087
01088 ((char *)ptr)[len] = '\0';
01089 str_validate((char *)ptr, (char *)ptr + len);
01090 break;
01091 }
01092 case SLA_PTRS: break;
01093 case SLA_NULL: break;
01094 default: NOT_REACHED();
01095 }
01096 }
01097
01103 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01104 {
01105 return SlCalcConvFileLen(conv) * length;
01106 }
01107
01114 void SlArray(void *array, size_t length, VarType conv)
01115 {
01116 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01117
01118
01119 if (_sl.need_length != NL_NONE) {
01120 SlSetLength(SlCalcArrayLen(length, conv));
01121
01122 if (_sl.need_length == NL_CALCLENGTH) return;
01123 }
01124
01125
01126
01127 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01128
01129 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01130 conv == SLE_INT32 || conv == SLE_UINT32) {
01131 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01132 return;
01133 }
01134
01135 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01136 for (uint i = 0; i < length; i++) {
01137 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01138 }
01139 return;
01140 }
01141 }
01142
01143
01144
01145 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01146 SlCopyBytes(array, length);
01147 } else {
01148 byte *a = (byte*)array;
01149 byte mem_size = SlCalcConvMemLen(conv);
01150
01151 for (; length != 0; length --) {
01152 SlSaveLoadConv(a, conv);
01153 a += mem_size;
01154 }
01155 }
01156 }
01157
01158
01169 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01170 {
01171 assert(_sl.action == SLA_SAVE);
01172
01173 if (obj == NULL) return 0;
01174
01175 switch (rt) {
01176 case REF_VEHICLE_OLD:
01177 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01178 case REF_STATION: return ((const Station*)obj)->index + 1;
01179 case REF_TOWN: return ((const Town*)obj)->index + 1;
01180 case REF_ORDER: return ((const Order*)obj)->index + 1;
01181 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01182 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01183 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01184 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01185 default: NOT_REACHED();
01186 }
01187 }
01188
01199 static void *IntToReference(size_t index, SLRefType rt)
01200 {
01201 assert_compile(sizeof(size_t) <= sizeof(void *));
01202
01203 assert(_sl.action == SLA_PTRS);
01204
01205
01206
01207 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01208 rt = REF_VEHICLE;
01209 }
01210
01211
01212 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01213
01214
01215
01216 if (rt != REF_VEHICLE_OLD) index--;
01217
01218 switch (rt) {
01219 case REF_ORDERLIST:
01220 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01221 SlErrorCorrupt("Referencing invalid OrderList");
01222
01223 case REF_ORDER:
01224 if (Order::IsValidID(index)) return Order::Get(index);
01225
01226 if (IsSavegameVersionBefore(5, 2)) return NULL;
01227 SlErrorCorrupt("Referencing invalid Order");
01228
01229 case REF_VEHICLE_OLD:
01230 case REF_VEHICLE:
01231 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01232 SlErrorCorrupt("Referencing invalid Vehicle");
01233
01234 case REF_STATION:
01235 if (Station::IsValidID(index)) return Station::Get(index);
01236 SlErrorCorrupt("Referencing invalid Station");
01237
01238 case REF_TOWN:
01239 if (Town::IsValidID(index)) return Town::Get(index);
01240 SlErrorCorrupt("Referencing invalid Town");
01241
01242 case REF_ROADSTOPS:
01243 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01244 SlErrorCorrupt("Referencing invalid RoadStop");
01245
01246 case REF_ENGINE_RENEWS:
01247 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01248 SlErrorCorrupt("Referencing invalid EngineRenew");
01249
01250 case REF_CARGO_PACKET:
01251 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01252 SlErrorCorrupt("Referencing invalid CargoPacket");
01253
01254 default: NOT_REACHED();
01255 }
01256 }
01257
01262 static inline size_t SlCalcListLen(const void *list)
01263 {
01264 std::list<void *> *l = (std::list<void *> *) list;
01265
01266 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01267
01268
01269 return l->size() * type_size + type_size;
01270 }
01271
01272
01278 static void SlList(void *list, SLRefType conv)
01279 {
01280
01281 if (_sl.need_length != NL_NONE) {
01282 SlSetLength(SlCalcListLen(list));
01283
01284 if (_sl.need_length == NL_CALCLENGTH) return;
01285 }
01286
01287 typedef std::list<void *> PtrList;
01288 PtrList *l = (PtrList *)list;
01289
01290 switch (_sl.action) {
01291 case SLA_SAVE: {
01292 SlWriteUint32((uint32)l->size());
01293
01294 PtrList::iterator iter;
01295 for (iter = l->begin(); iter != l->end(); ++iter) {
01296 void *ptr = *iter;
01297 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01298 }
01299 break;
01300 }
01301 case SLA_LOAD_CHECK:
01302 case SLA_LOAD: {
01303 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01304
01305
01306 for (size_t i = 0; i < length; i++) {
01307 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01308 l->push_back((void *)data);
01309 }
01310 break;
01311 }
01312 case SLA_PTRS: {
01313 PtrList temp = *l;
01314
01315 l->clear();
01316 PtrList::iterator iter;
01317 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01318 void *ptr = IntToReference((size_t)*iter, conv);
01319 l->push_back(ptr);
01320 }
01321 break;
01322 }
01323 case SLA_NULL:
01324 l->clear();
01325 break;
01326 default: NOT_REACHED();
01327 }
01328 }
01329
01330
01332 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01333 {
01334 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01335 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01336
01337 return true;
01338 }
01339
01345 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01346 {
01347 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01348 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01349 return true;
01350 }
01351
01352 return false;
01353 }
01354
01361 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01362 {
01363 size_t length = 0;
01364
01365
01366 for (; sld->cmd != SL_END; sld++) {
01367 length += SlCalcObjMemberLength(object, sld);
01368 }
01369 return length;
01370 }
01371
01372 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01373 {
01374 assert(_sl.action == SLA_SAVE);
01375
01376 switch (sld->cmd) {
01377 case SL_VAR:
01378 case SL_REF:
01379 case SL_ARR:
01380 case SL_STR:
01381 case SL_LST:
01382
01383 if (!SlIsObjectValidInSavegame(sld)) break;
01384
01385 switch (sld->cmd) {
01386 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01387 case SL_REF: return SlCalcRefLen();
01388 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01389 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01390 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01391 default: NOT_REACHED();
01392 }
01393 break;
01394 case SL_WRITEBYTE: return 1;
01395 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01396 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01397 default: NOT_REACHED();
01398 }
01399 return 0;
01400 }
01401
01402
01403 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01404 {
01405 VarType conv = GB(sld->conv, 0, 8);
01406 switch (sld->cmd) {
01407 case SL_VAR:
01408 case SL_REF:
01409 case SL_ARR:
01410 case SL_STR:
01411 case SL_LST:
01412
01413 if (!SlIsObjectValidInSavegame(sld)) return false;
01414 if (SlSkipVariableOnLoad(sld)) return false;
01415
01416 switch (sld->cmd) {
01417 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01418 case SL_REF:
01419 switch (_sl.action) {
01420 case SLA_SAVE:
01421 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01422 break;
01423 case SLA_LOAD_CHECK:
01424 case SLA_LOAD:
01425 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01426 break;
01427 case SLA_PTRS:
01428 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01429 break;
01430 case SLA_NULL:
01431 *(void **)ptr = NULL;
01432 break;
01433 default: NOT_REACHED();
01434 }
01435 break;
01436 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01437 case SL_STR: SlString(ptr, sld->length, conv); break;
01438 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01439 default: NOT_REACHED();
01440 }
01441 break;
01442
01443
01444
01445
01446
01447
01448 case SL_WRITEBYTE:
01449 switch (_sl.action) {
01450 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01451 case SLA_LOAD_CHECK:
01452 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01453 case SLA_PTRS: break;
01454 case SLA_NULL: break;
01455 default: NOT_REACHED();
01456 }
01457 break;
01458
01459
01460 case SL_VEH_INCLUDE:
01461 SlObject(ptr, GetVehicleDescription(VEH_END));
01462 break;
01463
01464 case SL_ST_INCLUDE:
01465 SlObject(ptr, GetBaseStationDescription());
01466 break;
01467
01468 default: NOT_REACHED();
01469 }
01470 return true;
01471 }
01472
01478 void SlObject(void *object, const SaveLoad *sld)
01479 {
01480
01481 if (_sl.need_length != NL_NONE) {
01482 SlSetLength(SlCalcObjLength(object, sld));
01483 if (_sl.need_length == NL_CALCLENGTH) return;
01484 }
01485
01486 for (; sld->cmd != SL_END; sld++) {
01487 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01488 SlObjectMember(ptr, sld);
01489 }
01490 }
01491
01496 void SlGlobList(const SaveLoadGlobVarList *sldg)
01497 {
01498 SlObject(NULL, (const SaveLoad*)sldg);
01499 }
01500
01506 void SlAutolength(AutolengthProc *proc, void *arg)
01507 {
01508 size_t offs;
01509
01510 assert(_sl.action == SLA_SAVE);
01511
01512
01513 _sl.need_length = NL_CALCLENGTH;
01514 _sl.obj_len = 0;
01515 proc(arg);
01516
01517
01518 _sl.need_length = NL_WANTLENGTH;
01519 SlSetLength(_sl.obj_len);
01520
01521 offs = _sl.dumper->GetSize() + _sl.obj_len;
01522
01523
01524 proc(arg);
01525
01526 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01527 }
01528
01533 static void SlLoadChunk(const ChunkHandler *ch)
01534 {
01535 byte m = SlReadByte();
01536 size_t len;
01537 size_t endoffs;
01538
01539 _sl.block_mode = m;
01540 _sl.obj_len = 0;
01541
01542 switch (m) {
01543 case CH_ARRAY:
01544 _sl.array_index = 0;
01545 ch->load_proc();
01546 break;
01547 case CH_SPARSE_ARRAY:
01548 ch->load_proc();
01549 break;
01550 default:
01551 if ((m & 0xF) == CH_RIFF) {
01552
01553 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01554 len += SlReadUint16();
01555 _sl.obj_len = len;
01556 endoffs = _sl.reader->GetSize() + len;
01557 ch->load_proc();
01558 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01559 } else {
01560 SlErrorCorrupt("Invalid chunk type");
01561 }
01562 break;
01563 }
01564 }
01565
01571 static void SlLoadCheckChunk(const ChunkHandler *ch)
01572 {
01573 byte m = SlReadByte();
01574 size_t len;
01575 size_t endoffs;
01576
01577 _sl.block_mode = m;
01578 _sl.obj_len = 0;
01579
01580 switch (m) {
01581 case CH_ARRAY:
01582 _sl.array_index = 0;
01583 if (ch->load_check_proc) {
01584 ch->load_check_proc();
01585 } else {
01586 SlSkipArray();
01587 }
01588 break;
01589 case CH_SPARSE_ARRAY:
01590 if (ch->load_check_proc) {
01591 ch->load_check_proc();
01592 } else {
01593 SlSkipArray();
01594 }
01595 break;
01596 default:
01597 if ((m & 0xF) == CH_RIFF) {
01598
01599 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01600 len += SlReadUint16();
01601 _sl.obj_len = len;
01602 endoffs = _sl.reader->GetSize() + len;
01603 if (ch->load_check_proc) {
01604 ch->load_check_proc();
01605 } else {
01606 SlSkipBytes(len);
01607 }
01608 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01609 } else {
01610 SlErrorCorrupt("Invalid chunk type");
01611 }
01612 break;
01613 }
01614 }
01615
01620 static ChunkSaveLoadProc *_stub_save_proc;
01621
01627 static inline void SlStubSaveProc2(void *arg)
01628 {
01629 _stub_save_proc();
01630 }
01631
01637 static void SlStubSaveProc()
01638 {
01639 SlAutolength(SlStubSaveProc2, NULL);
01640 }
01641
01647 static void SlSaveChunk(const ChunkHandler *ch)
01648 {
01649 ChunkSaveLoadProc *proc = ch->save_proc;
01650
01651
01652 if (proc == NULL) return;
01653
01654 SlWriteUint32(ch->id);
01655 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01656
01657 if (ch->flags & CH_AUTO_LENGTH) {
01658
01659 _stub_save_proc = proc;
01660 proc = SlStubSaveProc;
01661 }
01662
01663 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01664 switch (ch->flags & CH_TYPE_MASK) {
01665 case CH_RIFF:
01666 _sl.need_length = NL_WANTLENGTH;
01667 proc();
01668 break;
01669 case CH_ARRAY:
01670 _sl.last_array_index = 0;
01671 SlWriteByte(CH_ARRAY);
01672 proc();
01673 SlWriteArrayLength(0);
01674 break;
01675 case CH_SPARSE_ARRAY:
01676 SlWriteByte(CH_SPARSE_ARRAY);
01677 proc();
01678 SlWriteArrayLength(0);
01679 break;
01680 default: NOT_REACHED();
01681 }
01682 }
01683
01685 static void SlSaveChunks()
01686 {
01687 FOR_ALL_CHUNK_HANDLERS(ch) {
01688 SlSaveChunk(ch);
01689 }
01690
01691
01692 SlWriteUint32(0);
01693 }
01694
01701 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01702 {
01703 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01704 return NULL;
01705 }
01706
01708 static void SlLoadChunks()
01709 {
01710 uint32 id;
01711 const ChunkHandler *ch;
01712
01713 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01714 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01715
01716 ch = SlFindChunkHandler(id);
01717 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01718 SlLoadChunk(ch);
01719 }
01720 }
01721
01723 static void SlLoadCheckChunks()
01724 {
01725 uint32 id;
01726 const ChunkHandler *ch;
01727
01728 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01729 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01730
01731 ch = SlFindChunkHandler(id);
01732 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01733 SlLoadCheckChunk(ch);
01734 }
01735 }
01736
01738 static void SlFixPointers()
01739 {
01740 _sl.action = SLA_PTRS;
01741
01742 DEBUG(sl, 1, "Fixing pointers");
01743
01744 FOR_ALL_CHUNK_HANDLERS(ch) {
01745 if (ch->ptrs_proc != NULL) {
01746 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01747 ch->ptrs_proc();
01748 }
01749 }
01750
01751 DEBUG(sl, 1, "All pointers fixed");
01752
01753 assert(_sl.action == SLA_PTRS);
01754 }
01755
01756
01758 struct FileReader : LoadFilter {
01759 FILE *file;
01760 long begin;
01761
01766 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01767 {
01768 }
01769
01771 ~FileReader()
01772 {
01773 if (this->file != NULL) fclose(this->file);
01774 this->file = NULL;
01775
01776
01777 _sl.sf = NULL;
01778 }
01779
01780 size_t Read(byte *buf, size_t size)
01781 {
01782
01783 if (this->file == NULL) return 0;
01784
01785 return fread(buf, 1, size, this->file);
01786 }
01787
01788 void Reset()
01789 {
01790 clearerr(this->file);
01791 fseek(this->file, this->begin, SEEK_SET);
01792 }
01793 };
01794
01796 struct FileWriter : SaveFilter {
01797 FILE *file;
01798
01803 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01804 {
01805 }
01806
01808 ~FileWriter()
01809 {
01810 this->Finish();
01811
01812
01813 _sl.sf = NULL;
01814 }
01815
01816 void Write(byte *buf, size_t size)
01817 {
01818
01819 if (this->file == NULL) return;
01820
01821 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01822 }
01823
01824 void Finish()
01825 {
01826 if (this->file != NULL) fclose(this->file);
01827 this->file = NULL;
01828 }
01829 };
01830
01831
01832
01833
01834
01835 #ifdef WITH_LZO
01836 #include <lzo/lzo1x.h>
01837
01839 static const uint LZO_BUFFER_SIZE = 8192;
01840
01842 struct LZOLoadFilter : LoadFilter {
01847 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01848 {
01849 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01850 }
01851
01852 size_t Read(byte *buf, size_t ssize)
01853 {
01854 assert(ssize >= LZO_BUFFER_SIZE);
01855
01856
01857 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01858 uint32 tmp[2];
01859 uint32 size;
01860 lzo_uint len;
01861
01862
01863 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01864
01865
01866 ((uint32*)out)[0] = size = tmp[1];
01867
01868 if (_sl_version != 0) {
01869 tmp[0] = TO_BE32(tmp[0]);
01870 size = TO_BE32(size);
01871 }
01872
01873 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01874
01875
01876 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01877
01878
01879 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01880
01881
01882 lzo1x_decompress(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01883 return len;
01884 }
01885 };
01886
01888 struct LZOSaveFilter : SaveFilter {
01894 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01895 {
01896 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01897 }
01898
01899 void Write(byte *buf, size_t size)
01900 {
01901 const lzo_bytep in = buf;
01902
01903 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01904 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01905 lzo_uint outlen;
01906
01907 do {
01908
01909 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01910 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01911 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01912 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01913 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01914
01915
01916 size -= len;
01917 in += len;
01918 } while (size > 0);
01919 }
01920 };
01921
01922 #endif
01923
01924
01925
01926
01927
01929 struct NoCompLoadFilter : LoadFilter {
01934 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01935 {
01936 }
01937
01938 size_t Read(byte *buf, size_t size)
01939 {
01940 return this->chain->Read(buf, size);
01941 }
01942 };
01943
01945 struct NoCompSaveFilter : SaveFilter {
01951 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01952 {
01953 }
01954
01955 void Write(byte *buf, size_t size)
01956 {
01957 this->chain->Write(buf, size);
01958 }
01959 };
01960
01961
01962
01963
01964
01965 #if defined(WITH_ZLIB)
01966 #include <zlib.h>
01967
01969 struct ZlibLoadFilter : LoadFilter {
01970 z_stream z;
01971 byte fread_buf[MEMORY_CHUNK_SIZE];
01972
01977 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01978 {
01979 memset(&this->z, 0, sizeof(this->z));
01980 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01981 }
01982
01984 ~ZlibLoadFilter()
01985 {
01986 inflateEnd(&this->z);
01987 }
01988
01989 size_t Read(byte *buf, size_t size)
01990 {
01991 this->z.next_out = buf;
01992 this->z.avail_out = (uint)size;
01993
01994 do {
01995
01996 if (this->z.avail_in == 0) {
01997 this->z.next_in = this->fread_buf;
01998 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
01999 }
02000
02001
02002 int r = inflate(&this->z, 0);
02003 if (r == Z_STREAM_END) break;
02004
02005 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02006 } while (this->z.avail_out != 0);
02007
02008 return size - this->z.avail_out;
02009 }
02010 };
02011
02013 struct ZlibSaveFilter : SaveFilter {
02014 z_stream z;
02015
02021 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02022 {
02023 memset(&this->z, 0, sizeof(this->z));
02024 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02025 }
02026
02028 ~ZlibSaveFilter()
02029 {
02030 deflateEnd(&this->z);
02031 }
02032
02039 void WriteLoop(byte *p, size_t len, int mode)
02040 {
02041 byte buf[MEMORY_CHUNK_SIZE];
02042 uint n;
02043 this->z.next_in = p;
02044 this->z.avail_in = (uInt)len;
02045 do {
02046 this->z.next_out = buf;
02047 this->z.avail_out = sizeof(buf);
02048
02056 int r = deflate(&this->z, mode);
02057
02058
02059 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02060 this->chain->Write(buf, n);
02061 }
02062 if (r == Z_STREAM_END) break;
02063
02064 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02065 } while (this->z.avail_in || !this->z.avail_out);
02066 }
02067
02068 void Write(byte *buf, size_t size)
02069 {
02070 this->WriteLoop(buf, size, 0);
02071 }
02072
02073 void Finish()
02074 {
02075 this->WriteLoop(NULL, 0, Z_FINISH);
02076 this->chain->Finish();
02077 }
02078 };
02079
02080 #endif
02081
02082
02083
02084
02085
02086 #if defined(WITH_LZMA)
02087 #include <lzma.h>
02088
02095 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02096
02098 struct LZMALoadFilter : LoadFilter {
02099 lzma_stream lzma;
02100 byte fread_buf[MEMORY_CHUNK_SIZE];
02101
02106 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02107 {
02108
02109 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02110 }
02111
02113 ~LZMALoadFilter()
02114 {
02115 lzma_end(&this->lzma);
02116 }
02117
02118 size_t Read(byte *buf, size_t size)
02119 {
02120 this->lzma.next_out = buf;
02121 this->lzma.avail_out = size;
02122
02123 do {
02124
02125 if (this->lzma.avail_in == 0) {
02126 this->lzma.next_in = this->fread_buf;
02127 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02128 }
02129
02130
02131 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02132 if (r == LZMA_STREAM_END) break;
02133 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02134 } while (this->lzma.avail_out != 0);
02135
02136 return size - this->lzma.avail_out;
02137 }
02138 };
02139
02141 struct LZMASaveFilter : SaveFilter {
02142 lzma_stream lzma;
02143
02149 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02150 {
02151 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02152 }
02153
02155 ~LZMASaveFilter()
02156 {
02157 lzma_end(&this->lzma);
02158 }
02159
02166 void WriteLoop(byte *p, size_t len, lzma_action action)
02167 {
02168 byte buf[MEMORY_CHUNK_SIZE];
02169 size_t n;
02170 this->lzma.next_in = p;
02171 this->lzma.avail_in = len;
02172 do {
02173 this->lzma.next_out = buf;
02174 this->lzma.avail_out = sizeof(buf);
02175
02176 lzma_ret r = lzma_code(&this->lzma, action);
02177
02178
02179 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02180 this->chain->Write(buf, n);
02181 }
02182 if (r == LZMA_STREAM_END) break;
02183 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02184 } while (this->lzma.avail_in || !this->lzma.avail_out);
02185 }
02186
02187 void Write(byte *buf, size_t size)
02188 {
02189 this->WriteLoop(buf, size, LZMA_RUN);
02190 }
02191
02192 void Finish()
02193 {
02194 this->WriteLoop(NULL, 0, LZMA_FINISH);
02195 this->chain->Finish();
02196 }
02197 };
02198
02199 #endif
02200
02201
02202
02203
02204
02206 struct SaveLoadFormat {
02207 const char *name;
02208 uint32 tag;
02209
02210 LoadFilter *(*init_load)(LoadFilter *chain);
02211 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02212
02213 byte min_compression;
02214 byte default_compression;
02215 byte max_compression;
02216 };
02217
02219 static const SaveLoadFormat _saveload_formats[] = {
02220 #if defined(WITH_LZO)
02221
02222 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02223 #else
02224 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02225 #endif
02226
02227 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02228 #if defined(WITH_ZLIB)
02229
02230
02231
02232 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02233 #else
02234 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02235 #endif
02236 #if defined(WITH_LZMA)
02237
02238
02239
02240
02241
02242 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02243 #else
02244 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02245 #endif
02246 };
02247
02255 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02256 {
02257 const SaveLoadFormat *def = lastof(_saveload_formats);
02258
02259
02260 while (!def->init_write) def--;
02261
02262 if (!StrEmpty(s)) {
02263
02264 char *complevel = strrchr(s, ':');
02265 if (complevel != NULL) *complevel = '\0';
02266
02267 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02268 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02269 *compression_level = slf->default_compression;
02270 if (complevel != NULL) {
02271
02272
02273
02274 *complevel = ':';
02275 complevel++;
02276
02277
02278 char *end;
02279 long level = strtol(complevel, &end, 10);
02280 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02281 ShowInfoF("Compression level '%s' is not valid.", complevel);
02282 } else {
02283 *compression_level = level;
02284 }
02285 }
02286 return slf;
02287 }
02288 }
02289
02290 ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
02291
02292
02293 if (complevel != NULL) *complevel = ':';
02294 }
02295 *compression_level = def->default_compression;
02296 return def;
02297 }
02298
02299
02300 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02301 extern bool AfterLoadGame();
02302 extern bool LoadOldSaveGame(const char *file);
02303
02307 static inline void ClearSaveLoadState()
02308 {
02309 delete _sl.dumper;
02310 _sl.dumper = NULL;
02311
02312 delete _sl.sf;
02313 _sl.sf = NULL;
02314
02315 delete _sl.reader;
02316 _sl.reader = NULL;
02317
02318 delete _sl.lf;
02319 _sl.lf = NULL;
02320 }
02321
02327 static void SaveFileStart()
02328 {
02329 _sl.ff_state = _fast_forward;
02330 _fast_forward = 0;
02331 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02332
02333 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02334 _sl.saveinprogress = true;
02335 }
02336
02338 static void SaveFileDone()
02339 {
02340 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02341 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02342
02343 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02344 _sl.saveinprogress = false;
02345 }
02346
02348 void SetSaveLoadError(StringID str)
02349 {
02350 _sl.error_str = str;
02351 }
02352
02354 const char *GetSaveLoadErrorString()
02355 {
02356 SetDParam(0, _sl.error_str);
02357 SetDParamStr(1, _sl.extra_msg);
02358
02359 static char err_str[512];
02360 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02361 return err_str;
02362 }
02363
02365 static void SaveFileError()
02366 {
02367 SetDParamStr(0, GetSaveLoadErrorString());
02368 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02369 SaveFileDone();
02370 }
02371
02376 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02377 {
02378 try {
02379 byte compression;
02380 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02381
02382
02383 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02384 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02385
02386 _sl.sf = fmt->init_write(_sl.sf, compression);
02387 _sl.dumper->Flush(_sl.sf);
02388
02389 ClearSaveLoadState();
02390
02391 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02392
02393 return SL_OK;
02394 } catch (...) {
02395 ClearSaveLoadState();
02396
02397 AsyncSaveFinishProc asfp = SaveFileDone;
02398
02399
02400
02401 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02402
02403 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02404 asfp = SaveFileError;
02405 }
02406
02407 if (threaded) {
02408 SetAsyncSaveFinish(asfp);
02409 } else {
02410 asfp();
02411 }
02412 return SL_ERROR;
02413 }
02414 }
02415
02417 static void SaveFileToDiskThread(void *arg)
02418 {
02419 SaveFileToDisk(true);
02420 }
02421
02422 void WaitTillSaved()
02423 {
02424 if (_save_thread == NULL) return;
02425
02426 _save_thread->Join();
02427 delete _save_thread;
02428 _save_thread = NULL;
02429
02430
02431 ProcessAsyncSaveFinish();
02432 }
02433
02442 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02443 {
02444 assert(!_sl.saveinprogress);
02445
02446 _sl.dumper = new MemoryDumper();
02447 _sl.sf = writer;
02448
02449 _sl_version = SAVEGAME_VERSION;
02450
02451 SaveViewportBeforeSaveGame();
02452 SlSaveChunks();
02453
02454 SaveFileStart();
02455 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02456 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02457
02458 SaveOrLoadResult result = SaveFileToDisk(false);
02459 SaveFileDone();
02460
02461 return result;
02462 }
02463
02464 return SL_OK;
02465 }
02466
02473 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02474 {
02475 try {
02476 _sl.action = SLA_SAVE;
02477 return DoSave(writer, threaded);
02478 } catch (...) {
02479 ClearSaveLoadState();
02480 return SL_ERROR;
02481 }
02482 }
02483
02490 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02491 {
02492 _sl.lf = reader;
02493
02494 if (load_check) {
02495
02496 _load_check_data.Clear();
02497
02498 _load_check_data.checkable = true;
02499 }
02500
02501 uint32 hdr[2];
02502 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02503
02504
02505 const SaveLoadFormat *fmt = _saveload_formats;
02506 for (;;) {
02507
02508 if (fmt == endof(_saveload_formats)) {
02509 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02510 _sl.lf->Reset();
02511 _sl_version = 0;
02512 _sl_minor_version = 0;
02513
02514
02515 fmt = _saveload_formats;
02516 for (;;) {
02517 if (fmt == endof(_saveload_formats)) {
02518
02519 NOT_REACHED();
02520 }
02521 if (fmt->tag == TO_BE32X('OTTD')) break;
02522 fmt++;
02523 }
02524 break;
02525 }
02526
02527 if (fmt->tag == hdr[0]) {
02528
02529 _sl_version = TO_BE32(hdr[1]) >> 16;
02530
02531
02532
02533
02534 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02535
02536 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02537
02538
02539 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02540 break;
02541 }
02542
02543 fmt++;
02544 }
02545
02546
02547 if (fmt->init_load == NULL) {
02548 char err_str[64];
02549 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02550 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02551 }
02552
02553 _sl.lf = fmt->init_load(_sl.lf);
02554 _sl.reader = new ReadBuffer(_sl.lf);
02555 _next_offs = 0;
02556
02557 if (!load_check) {
02558 _engine_mngr.ResetToDefaultMapping();
02559
02560
02561
02562
02563 InitializeGame(256, 256, true, true);
02564
02565 GamelogReset();
02566
02567 if (IsSavegameVersionBefore(4)) {
02568
02569
02570
02571
02572
02573
02574
02575
02576
02577
02578
02579
02580
02581
02582
02583
02584
02585
02586
02587
02588
02589 ClearGRFConfigList(&_grfconfig);
02590 }
02591 }
02592
02593 if (load_check) {
02594
02595
02596 SlLoadCheckChunks();
02597 } else {
02598
02599 SlLoadChunks();
02600 SlFixPointers();
02601 }
02602
02603 ClearSaveLoadState();
02604
02605 _savegame_type = SGT_OTTD;
02606
02607 if (load_check) {
02608
02609 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02610 } else {
02611 GamelogStartAction(GLAT_LOAD);
02612
02613
02614
02615 if (!AfterLoadGame()) {
02616 GamelogStopAction();
02617 return SL_REINIT;
02618 }
02619
02620 GamelogStopAction();
02621 }
02622
02623 return SL_OK;
02624 }
02625
02631 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02632 {
02633 try {
02634 _sl.action = SLA_LOAD;
02635 return DoLoad(reader, false);
02636 } catch (...) {
02637 ClearSaveLoadState();
02638 return SL_REINIT;
02639 }
02640 }
02641
02651 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02652 {
02653
02654 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02655
02656 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02657 return SL_OK;
02658 }
02659 WaitTillSaved();
02660
02661
02662 if (mode == SL_OLD_LOAD) {
02663 _engine_mngr.ResetToDefaultMapping();
02664 InitializeGame(256, 256, true, true);
02665
02666
02667
02668
02669
02670 ClearGRFConfigList(&_grfconfig);
02671 GamelogReset();
02672 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02673 _sl_version = 0;
02674 _sl_minor_version = 0;
02675 GamelogStartAction(GLAT_LOAD);
02676 if (!AfterLoadGame()) {
02677 GamelogStopAction();
02678 return SL_REINIT;
02679 }
02680 GamelogStopAction();
02681 return SL_OK;
02682 }
02683
02684 switch (mode) {
02685 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02686 case SL_LOAD: _sl.action = SLA_LOAD; break;
02687 case SL_SAVE: _sl.action = SLA_SAVE; break;
02688 default: NOT_REACHED();
02689 }
02690
02691 try {
02692 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02693
02694
02695 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02696 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02697
02698 if (fh == NULL) {
02699 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02700 }
02701
02702 if (mode == SL_SAVE) {
02703 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02704 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02705
02706 return DoSave(new FileWriter(fh), threaded);
02707 }
02708
02709
02710 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02711 DEBUG(desync, 1, "load: %s", filename);
02712 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02713 } catch (...) {
02714 ClearSaveLoadState();
02715
02716
02717 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02718
02719
02720 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02721 }
02722 }
02723
02725 void DoExitSave()
02726 {
02727 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02728 }
02729
02735 void GenerateDefaultSaveName(char *buf, const char *last)
02736 {
02737
02738
02739
02740 CompanyID cid = _local_company;
02741 if (!Company::IsValidID(cid)) {
02742 const Company *c;
02743 FOR_ALL_COMPANIES(c) {
02744 cid = c->index;
02745 break;
02746 }
02747 }
02748
02749 SetDParam(0, cid);
02750
02751
02752 switch (_settings_client.gui.date_format_in_default_names) {
02753 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02754 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02755 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02756 default: NOT_REACHED();
02757 }
02758 SetDParam(2, _date);
02759
02760
02761 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02762 SanitizeFilename(buf);
02763 }
02764
02765 #if 0
02766
02772 int GetSavegameType(char *file)
02773 {
02774 const SaveLoadFormat *fmt;
02775 uint32 hdr;
02776 FILE *f;
02777 int mode = SL_OLD_LOAD;
02778
02779 f = fopen(file, "rb");
02780 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02781 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02782 mode = SL_LOAD;
02783 } else {
02784
02785 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02786 if (fmt->tag == hdr) {
02787 mode = SL_LOAD;
02788 break;
02789 }
02790 }
02791 }
02792
02793 fclose(f);
02794 return mode;
02795 }
02796 #endif