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 #include "../cargodest_base.h"
00046
00047 #include "table/strings.h"
00048
00049 #include "saveload_internal.h"
00050 #include "saveload_filter.h"
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231 extern const uint16 SAVEGAME_VERSION = 161;
00232
00233 SavegameType _savegame_type;
00234
00235 uint32 _ttdp_version;
00236 uint16 _sl_version;
00237 byte _sl_minor_version;
00238 char _savegame_format[8];
00239 bool _do_autosave;
00240
00242 enum SaveLoadAction {
00243 SLA_LOAD,
00244 SLA_SAVE,
00245 SLA_PTRS,
00246 SLA_NULL,
00247 SLA_LOAD_CHECK,
00248 };
00249
00250 enum NeedLength {
00251 NL_NONE = 0,
00252 NL_WANTLENGTH = 1,
00253 NL_CALCLENGTH = 2,
00254 };
00255
00257 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
00258
00260 struct ReadBuffer {
00261 byte buf[MEMORY_CHUNK_SIZE];
00262 byte *bufp;
00263 byte *bufe;
00264 LoadFilter *reader;
00265 size_t read;
00266
00271 ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
00272 {
00273 }
00274
00275 FORCEINLINE byte ReadByte()
00276 {
00277 if (this->bufp == this->bufe) {
00278 size_t len = this->reader->Read(this->buf, lengthof(this->buf));
00279 if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00280
00281 this->read += len;
00282 this->bufp = this->buf;
00283 this->bufe = this->buf + len;
00284 }
00285
00286 return *this->bufp++;
00287 }
00288
00293 size_t GetSize() const
00294 {
00295 return this->read - (this->bufe - this->bufp);
00296 }
00297 };
00298
00299
00301 struct MemoryDumper {
00302 AutoFreeSmallVector<byte *, 16> blocks;
00303 byte *buf;
00304 byte *bufe;
00305
00307 MemoryDumper() : buf(NULL), bufe(NULL)
00308 {
00309 }
00310
00315 FORCEINLINE void WriteByte(byte b)
00316 {
00317
00318 if (this->buf == this->bufe) {
00319 this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
00320 *this->blocks.Append() = this->buf;
00321 this->bufe = this->buf + MEMORY_CHUNK_SIZE;
00322 }
00323
00324 *this->buf++ = b;
00325 }
00326
00331 void Flush(SaveFilter *writer)
00332 {
00333 uint i = 0;
00334 size_t t = this->GetSize();
00335
00336 while (t > 0) {
00337 size_t to_write = min(MEMORY_CHUNK_SIZE, t);
00338
00339 writer->Write(this->blocks[i++], to_write);
00340 t -= to_write;
00341 }
00342
00343 writer->Finish();
00344 }
00345
00350 size_t GetSize() const
00351 {
00352 return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
00353 }
00354 };
00355
00357 struct SaveLoadParams {
00358 SaveLoadAction action;
00359 NeedLength need_length;
00360 byte block_mode;
00361 bool error;
00362
00363 size_t obj_len;
00364 int array_index, last_array_index;
00365
00366 MemoryDumper *dumper;
00367 SaveFilter *sf;
00368
00369 ReadBuffer *reader;
00370 LoadFilter *lf;
00371
00372 StringID error_str;
00373 char *extra_msg;
00374
00375 byte ff_state;
00376 bool saveinprogress;
00377 };
00378
00379 static SaveLoadParams _sl;
00380
00381
00382 extern const ChunkHandler _gamelog_chunk_handlers[];
00383 extern const ChunkHandler _map_chunk_handlers[];
00384 extern const ChunkHandler _misc_chunk_handlers[];
00385 extern const ChunkHandler _name_chunk_handlers[];
00386 extern const ChunkHandler _cheat_chunk_handlers[] ;
00387 extern const ChunkHandler _setting_chunk_handlers[];
00388 extern const ChunkHandler _company_chunk_handlers[];
00389 extern const ChunkHandler _engine_chunk_handlers[];
00390 extern const ChunkHandler _veh_chunk_handlers[];
00391 extern const ChunkHandler _waypoint_chunk_handlers[];
00392 extern const ChunkHandler _depot_chunk_handlers[];
00393 extern const ChunkHandler _order_chunk_handlers[];
00394 extern const ChunkHandler _town_chunk_handlers[];
00395 extern const ChunkHandler _sign_chunk_handlers[];
00396 extern const ChunkHandler _station_chunk_handlers[];
00397 extern const ChunkHandler _industry_chunk_handlers[];
00398 extern const ChunkHandler _economy_chunk_handlers[];
00399 extern const ChunkHandler _subsidy_chunk_handlers[];
00400 extern const ChunkHandler _ai_chunk_handlers[];
00401 extern const ChunkHandler _animated_tile_chunk_handlers[];
00402 extern const ChunkHandler _newgrf_chunk_handlers[];
00403 extern const ChunkHandler _group_chunk_handlers[];
00404 extern const ChunkHandler _cargopacket_chunk_handlers[];
00405 extern const ChunkHandler _autoreplace_chunk_handlers[];
00406 extern const ChunkHandler _labelmaps_chunk_handlers[];
00407 extern const ChunkHandler _airport_chunk_handlers[];
00408 extern const ChunkHandler _object_chunk_handlers[];
00409 extern const ChunkHandler _routelink_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 _routelink_chunk_handlers,
00441 NULL,
00442 };
00443
00448 #define FOR_ALL_CHUNK_HANDLERS(ch) \
00449 for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \
00450 for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1)
00451
00453 static void SlNullPointers()
00454 {
00455 _sl.action = SLA_NULL;
00456
00457
00458
00459
00460 _sl_version = SAVEGAME_VERSION;
00461
00462 DEBUG(sl, 1, "Nulling pointers");
00463
00464 FOR_ALL_CHUNK_HANDLERS(ch) {
00465 if (ch->ptrs_proc != NULL) {
00466 DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00467 ch->ptrs_proc();
00468 }
00469 }
00470
00471 DEBUG(sl, 1, "All pointers nulled");
00472
00473 assert(_sl.action == SLA_NULL);
00474 }
00475
00484 void NORETURN SlError(StringID string, const char *extra_msg)
00485 {
00486
00487 if (_sl.action == SLA_LOAD_CHECK) {
00488 _load_check_data.error = string;
00489 free(_load_check_data.error_data);
00490 _load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00491 } else {
00492 _sl.error_str = string;
00493 free(_sl.extra_msg);
00494 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00495 }
00496
00497
00498
00499
00500
00501 if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00502 throw std::exception();
00503 }
00504
00512 void NORETURN SlErrorCorrupt(const char *msg)
00513 {
00514 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00515 }
00516
00517
00518 typedef void (*AsyncSaveFinishProc)();
00519 static AsyncSaveFinishProc _async_save_finish = NULL;
00520 static ThreadObject *_save_thread;
00521
00526 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00527 {
00528 if (_exit_game) return;
00529 while (_async_save_finish != NULL) CSleep(10);
00530
00531 _async_save_finish = proc;
00532 }
00533
00537 void ProcessAsyncSaveFinish()
00538 {
00539 if (_async_save_finish == NULL) return;
00540
00541 _async_save_finish();
00542
00543 _async_save_finish = NULL;
00544
00545 if (_save_thread != NULL) {
00546 _save_thread->Join();
00547 delete _save_thread;
00548 _save_thread = NULL;
00549 }
00550 }
00551
00556 byte SlReadByte()
00557 {
00558 return _sl.reader->ReadByte();
00559 }
00560
00565 void SlWriteByte(byte b)
00566 {
00567 _sl.dumper->WriteByte(b);
00568 }
00569
00570 static inline int SlReadUint16()
00571 {
00572 int x = SlReadByte() << 8;
00573 return x | SlReadByte();
00574 }
00575
00576 static inline uint32 SlReadUint32()
00577 {
00578 uint32 x = SlReadUint16() << 16;
00579 return x | SlReadUint16();
00580 }
00581
00582 static inline uint64 SlReadUint64()
00583 {
00584 uint32 x = SlReadUint32();
00585 uint32 y = SlReadUint32();
00586 return (uint64)x << 32 | y;
00587 }
00588
00589 static inline void SlWriteUint16(uint16 v)
00590 {
00591 SlWriteByte(GB(v, 8, 8));
00592 SlWriteByte(GB(v, 0, 8));
00593 }
00594
00595 static inline void SlWriteUint32(uint32 v)
00596 {
00597 SlWriteUint16(GB(v, 16, 16));
00598 SlWriteUint16(GB(v, 0, 16));
00599 }
00600
00601 static inline void SlWriteUint64(uint64 x)
00602 {
00603 SlWriteUint32((uint32)(x >> 32));
00604 SlWriteUint32((uint32)x);
00605 }
00606
00612 static inline void SlSkipBytes(size_t length)
00613 {
00614 for (; length != 0; length--) SlReadByte();
00615 }
00616
00626 static uint SlReadSimpleGamma()
00627 {
00628 uint i = SlReadByte();
00629 if (HasBit(i, 7)) {
00630 i &= ~0x80;
00631 if (HasBit(i, 6)) {
00632 i &= ~0x40;
00633 if (HasBit(i, 5)) {
00634 i &= ~0x20;
00635 if (HasBit(i, 4)) {
00636 SlErrorCorrupt("Unsupported gamma");
00637 }
00638 i = (i << 8) | SlReadByte();
00639 }
00640 i = (i << 8) | SlReadByte();
00641 }
00642 i = (i << 8) | SlReadByte();
00643 }
00644 return i;
00645 }
00646
00659 static void SlWriteSimpleGamma(size_t i)
00660 {
00661 if (i >= (1 << 7)) {
00662 if (i >= (1 << 14)) {
00663 if (i >= (1 << 21)) {
00664 assert(i < (1 << 28));
00665 SlWriteByte((byte)(0xE0 | (i >> 24)));
00666 SlWriteByte((byte)(i >> 16));
00667 } else {
00668 SlWriteByte((byte)(0xC0 | (i >> 16)));
00669 }
00670 SlWriteByte((byte)(i >> 8));
00671 } else {
00672 SlWriteByte((byte)(0x80 | (i >> 8)));
00673 }
00674 }
00675 SlWriteByte((byte)i);
00676 }
00677
00679 static inline uint SlGetGammaLength(size_t i)
00680 {
00681 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00682 }
00683
00684 static inline uint SlReadSparseIndex()
00685 {
00686 return SlReadSimpleGamma();
00687 }
00688
00689 static inline void SlWriteSparseIndex(uint index)
00690 {
00691 SlWriteSimpleGamma(index);
00692 }
00693
00694 static inline uint SlReadArrayLength()
00695 {
00696 return SlReadSimpleGamma();
00697 }
00698
00699 static inline void SlWriteArrayLength(size_t length)
00700 {
00701 SlWriteSimpleGamma(length);
00702 }
00703
00704 static inline uint SlGetArrayLength(size_t length)
00705 {
00706 return SlGetGammaLength(length);
00707 }
00708
00715 static inline uint SlCalcConvMemLen(VarType conv)
00716 {
00717 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00718 byte length = GB(conv, 4, 4);
00719
00720 switch (length << 4) {
00721 case SLE_VAR_STRB:
00722 case SLE_VAR_STRBQ:
00723 case SLE_VAR_STR:
00724 case SLE_VAR_STRQ:
00725 return SlReadArrayLength();
00726
00727 default:
00728 assert(length < lengthof(conv_mem_size));
00729 return conv_mem_size[length];
00730 }
00731 }
00732
00739 static inline byte SlCalcConvFileLen(VarType conv)
00740 {
00741 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00742 byte length = GB(conv, 0, 4);
00743 assert(length < lengthof(conv_file_size));
00744 return conv_file_size[length];
00745 }
00746
00748 static inline size_t SlCalcRefLen()
00749 {
00750 return IsSavegameVersionBefore(69) ? 2 : 4;
00751 }
00752
00753 void SlSetArrayIndex(uint index)
00754 {
00755 _sl.need_length = NL_WANTLENGTH;
00756 _sl.array_index = index;
00757 }
00758
00759 static size_t _next_offs;
00760
00765 int SlIterateArray()
00766 {
00767 int index;
00768
00769
00770
00771 if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00772
00773 for (;;) {
00774 uint length = SlReadArrayLength();
00775 if (length == 0) {
00776 _next_offs = 0;
00777 return -1;
00778 }
00779
00780 _sl.obj_len = --length;
00781 _next_offs = _sl.reader->GetSize() + length;
00782
00783 switch (_sl.block_mode) {
00784 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00785 case CH_ARRAY: index = _sl.array_index++; break;
00786 default:
00787 DEBUG(sl, 0, "SlIterateArray error");
00788 return -1;
00789 }
00790
00791 if (length != 0) return index;
00792 }
00793 }
00794
00798 void SlSkipArray()
00799 {
00800 while (SlIterateArray() != -1) {
00801 SlSkipBytes(_next_offs - _sl.reader->GetSize());
00802 }
00803 }
00804
00810 void SlSetLength(size_t length)
00811 {
00812 assert(_sl.action == SLA_SAVE);
00813
00814 switch (_sl.need_length) {
00815 case NL_WANTLENGTH:
00816 _sl.need_length = NL_NONE;
00817 switch (_sl.block_mode) {
00818 case CH_RIFF:
00819
00820
00821
00822 assert(length < (1 << 28));
00823 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00824 break;
00825 case CH_ARRAY:
00826 assert(_sl.last_array_index <= _sl.array_index);
00827 while (++_sl.last_array_index <= _sl.array_index) {
00828 SlWriteArrayLength(1);
00829 }
00830 SlWriteArrayLength(length + 1);
00831 break;
00832 case CH_SPARSE_ARRAY:
00833 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00834 SlWriteSparseIndex(_sl.array_index);
00835 break;
00836 default: NOT_REACHED();
00837 }
00838 break;
00839
00840 case NL_CALCLENGTH:
00841 _sl.obj_len += (int)length;
00842 break;
00843
00844 default: NOT_REACHED();
00845 }
00846 }
00847
00854 static void SlCopyBytes(void *ptr, size_t length)
00855 {
00856 byte *p = (byte *)ptr;
00857
00858 switch (_sl.action) {
00859 case SLA_LOAD_CHECK:
00860 case SLA_LOAD:
00861 for (; length != 0; length--) *p++ = SlReadByte();
00862 break;
00863 case SLA_SAVE:
00864 for (; length != 0; length--) SlWriteByte(*p++);
00865 break;
00866 default: NOT_REACHED();
00867 }
00868 }
00869
00871 size_t SlGetFieldLength()
00872 {
00873 return _sl.obj_len;
00874 }
00875
00883 int64 ReadValue(const void *ptr, VarType conv)
00884 {
00885 switch (GetVarMemType(conv)) {
00886 case SLE_VAR_BL: return (*(bool *)ptr != 0);
00887 case SLE_VAR_I8: return *(int8 *)ptr;
00888 case SLE_VAR_U8: return *(byte *)ptr;
00889 case SLE_VAR_I16: return *(int16 *)ptr;
00890 case SLE_VAR_U16: return *(uint16*)ptr;
00891 case SLE_VAR_I32: return *(int32 *)ptr;
00892 case SLE_VAR_U32: return *(uint32*)ptr;
00893 case SLE_VAR_I64: return *(int64 *)ptr;
00894 case SLE_VAR_U64: return *(uint64*)ptr;
00895 case SLE_VAR_NULL:return 0;
00896 default: NOT_REACHED();
00897 }
00898 }
00899
00907 void WriteValue(void *ptr, VarType conv, int64 val)
00908 {
00909 switch (GetVarMemType(conv)) {
00910 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00911 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00912 case SLE_VAR_U8: *(byte *)ptr = val; break;
00913 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00914 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00915 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00916 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00917 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00918 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00919 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00920 case SLE_VAR_NULL: break;
00921 default: NOT_REACHED();
00922 }
00923 }
00924
00933 static void SlSaveLoadConv(void *ptr, VarType conv)
00934 {
00935 switch (_sl.action) {
00936 case SLA_SAVE: {
00937 int64 x = ReadValue(ptr, conv);
00938
00939
00940 switch (GetVarFileType(conv)) {
00941 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00942 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00943 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00944 case SLE_FILE_STRINGID:
00945 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00946 case SLE_FILE_I32:
00947 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00948 case SLE_FILE_I64:
00949 case SLE_FILE_U64: SlWriteUint64(x);break;
00950 default: NOT_REACHED();
00951 }
00952 break;
00953 }
00954 case SLA_LOAD_CHECK:
00955 case SLA_LOAD: {
00956 int64 x;
00957
00958 switch (GetVarFileType(conv)) {
00959 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00960 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00961 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00962 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00963 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00964 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00965 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00966 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00967 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00968 default: NOT_REACHED();
00969 }
00970
00971
00972 WriteValue(ptr, conv, x);
00973 break;
00974 }
00975 case SLA_PTRS: break;
00976 case SLA_NULL: break;
00977 default: NOT_REACHED();
00978 }
00979 }
00980
00990 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
00991 {
00992 if (ptr == NULL) return 0;
00993 return min(strlen(ptr), length - 1);
00994 }
00995
01005 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
01006 {
01007 size_t len;
01008 const char *str;
01009
01010 switch (GetVarMemType(conv)) {
01011 default: NOT_REACHED();
01012 case SLE_VAR_STR:
01013 case SLE_VAR_STRQ:
01014 str = *(const char**)ptr;
01015 len = SIZE_MAX;
01016 break;
01017 case SLE_VAR_STRB:
01018 case SLE_VAR_STRBQ:
01019 str = (const char*)ptr;
01020 len = length;
01021 break;
01022 }
01023
01024 len = SlCalcNetStringLen(str, len);
01025 return len + SlGetArrayLength(len);
01026 }
01027
01034 static void SlString(void *ptr, size_t length, VarType conv)
01035 {
01036 switch (_sl.action) {
01037 case SLA_SAVE: {
01038 size_t len;
01039 switch (GetVarMemType(conv)) {
01040 default: NOT_REACHED();
01041 case SLE_VAR_STRB:
01042 case SLE_VAR_STRBQ:
01043 len = SlCalcNetStringLen((char *)ptr, length);
01044 break;
01045 case SLE_VAR_STR:
01046 case SLE_VAR_STRQ:
01047 ptr = *(char **)ptr;
01048 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01049 break;
01050 }
01051
01052 SlWriteArrayLength(len);
01053 SlCopyBytes(ptr, len);
01054 break;
01055 }
01056 case SLA_LOAD_CHECK:
01057 case SLA_LOAD: {
01058 size_t len = SlReadArrayLength();
01059
01060 switch (GetVarMemType(conv)) {
01061 default: NOT_REACHED();
01062 case SLE_VAR_STRB:
01063 case SLE_VAR_STRBQ:
01064 if (len >= length) {
01065 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01066 SlCopyBytes(ptr, length);
01067 SlSkipBytes(len - length);
01068 len = length - 1;
01069 } else {
01070 SlCopyBytes(ptr, len);
01071 }
01072 break;
01073 case SLE_VAR_STR:
01074 case SLE_VAR_STRQ:
01075 free(*(char **)ptr);
01076 if (len == 0) {
01077 *(char **)ptr = NULL;
01078 } else {
01079 *(char **)ptr = MallocT<char>(len + 1);
01080 ptr = *(char **)ptr;
01081 SlCopyBytes(ptr, len);
01082 }
01083 break;
01084 }
01085
01086 ((char *)ptr)[len] = '\0';
01087 str_validate((char *)ptr, (char *)ptr + len);
01088 break;
01089 }
01090 case SLA_PTRS: break;
01091 case SLA_NULL: break;
01092 default: NOT_REACHED();
01093 }
01094 }
01095
01101 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01102 {
01103 return SlCalcConvFileLen(conv) * length;
01104 }
01105
01112 void SlArray(void *array, size_t length, VarType conv)
01113 {
01114 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01115
01116
01117 if (_sl.need_length != NL_NONE) {
01118 SlSetLength(SlCalcArrayLen(length, conv));
01119
01120 if (_sl.need_length == NL_CALCLENGTH) return;
01121 }
01122
01123
01124
01125 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01126
01127 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01128 conv == SLE_INT32 || conv == SLE_UINT32) {
01129 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01130 return;
01131 }
01132
01133 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01134 for (uint i = 0; i < length; i++) {
01135 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01136 }
01137 return;
01138 }
01139 }
01140
01141
01142
01143 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01144 SlCopyBytes(array, length);
01145 } else {
01146 byte *a = (byte*)array;
01147 byte mem_size = SlCalcConvMemLen(conv);
01148
01149 for (; length != 0; length --) {
01150 SlSaveLoadConv(a, conv);
01151 a += mem_size;
01152 }
01153 }
01154 }
01155
01156
01167 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01168 {
01169 assert(_sl.action == SLA_SAVE);
01170
01171 if (obj == NULL) return 0;
01172
01173 switch (rt) {
01174 case REF_VEHICLE_OLD:
01175 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01176 case REF_STATION: return ((const Station*)obj)->index + 1;
01177 case REF_TOWN: return ((const Town*)obj)->index + 1;
01178 case REF_ORDER: return ((const Order*)obj)->index + 1;
01179 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01180 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01181 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01182 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01183 case REF_ROUTE_LINK: return ((const RouteLink*)obj)->index + 1;
01184 default: NOT_REACHED();
01185 }
01186 }
01187
01198 static void *IntToReference(size_t index, SLRefType rt)
01199 {
01200 assert_compile(sizeof(size_t) <= sizeof(void *));
01201
01202 assert(_sl.action == SLA_PTRS);
01203
01204
01205
01206 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01207 rt = REF_VEHICLE;
01208 }
01209
01210
01211 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01212
01213
01214
01215 if (rt != REF_VEHICLE_OLD) index--;
01216
01217 switch (rt) {
01218 case REF_ORDERLIST:
01219 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01220 SlErrorCorrupt("Referencing invalid OrderList");
01221
01222 case REF_ORDER:
01223 if (Order::IsValidID(index)) return Order::Get(index);
01224
01225 if (IsSavegameVersionBefore(5, 2)) return NULL;
01226 SlErrorCorrupt("Referencing invalid Order");
01227
01228 case REF_VEHICLE_OLD:
01229 case REF_VEHICLE:
01230 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01231 SlErrorCorrupt("Referencing invalid Vehicle");
01232
01233 case REF_STATION:
01234 if (Station::IsValidID(index)) return Station::Get(index);
01235 SlErrorCorrupt("Referencing invalid Station");
01236
01237 case REF_TOWN:
01238 if (Town::IsValidID(index)) return Town::Get(index);
01239 SlErrorCorrupt("Referencing invalid Town");
01240
01241 case REF_ROADSTOPS:
01242 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01243 SlErrorCorrupt("Referencing invalid RoadStop");
01244
01245 case REF_ENGINE_RENEWS:
01246 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01247 SlErrorCorrupt("Referencing invalid EngineRenew");
01248
01249 case REF_CARGO_PACKET:
01250 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01251 SlErrorCorrupt("Referencing invalid CargoPacket");
01252
01253 case REF_ROUTE_LINK:
01254 if (RouteLink::IsValidID(index)) return RouteLink::Get(index);
01255 SlErrorCorrupt("Referencing invalid RouteLink");
01256
01257 default: NOT_REACHED();
01258 }
01259 }
01260
01265 static inline size_t SlCalcListLen(const void *list)
01266 {
01267 std::list<void *> *l = (std::list<void *> *) list;
01268
01269 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01270
01271
01272 return l->size() * type_size + type_size;
01273 }
01274
01275
01281 static void SlList(void *list, SLRefType conv)
01282 {
01283
01284 if (_sl.need_length != NL_NONE) {
01285 SlSetLength(SlCalcListLen(list));
01286
01287 if (_sl.need_length == NL_CALCLENGTH) return;
01288 }
01289
01290 typedef std::list<void *> PtrList;
01291 PtrList *l = (PtrList *)list;
01292
01293 switch (_sl.action) {
01294 case SLA_SAVE: {
01295 SlWriteUint32((uint32)l->size());
01296
01297 PtrList::iterator iter;
01298 for (iter = l->begin(); iter != l->end(); ++iter) {
01299 void *ptr = *iter;
01300 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01301 }
01302 break;
01303 }
01304 case SLA_LOAD_CHECK:
01305 case SLA_LOAD: {
01306 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01307
01308
01309 for (size_t i = 0; i < length; i++) {
01310 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01311 l->push_back((void *)data);
01312 }
01313 break;
01314 }
01315 case SLA_PTRS: {
01316 PtrList temp = *l;
01317
01318 l->clear();
01319 PtrList::iterator iter;
01320 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01321 void *ptr = IntToReference((size_t)*iter, conv);
01322 l->push_back(ptr);
01323 }
01324 break;
01325 }
01326 case SLA_NULL:
01327 l->clear();
01328 break;
01329 default: NOT_REACHED();
01330 }
01331 }
01332
01333
01335 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01336 {
01337 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01338 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01339
01340 return true;
01341 }
01342
01348 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01349 {
01350 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01351 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01352 return true;
01353 }
01354
01355 return false;
01356 }
01357
01364 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01365 {
01366 size_t length = 0;
01367
01368
01369 for (; sld->cmd != SL_END; sld++) {
01370 length += SlCalcObjMemberLength(object, sld);
01371 }
01372 return length;
01373 }
01374
01375 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01376 {
01377 assert(_sl.action == SLA_SAVE);
01378
01379 switch (sld->cmd) {
01380 case SL_VAR:
01381 case SL_REF:
01382 case SL_ARR:
01383 case SL_STR:
01384 case SL_LST:
01385
01386 if (!SlIsObjectValidInSavegame(sld)) break;
01387
01388 switch (sld->cmd) {
01389 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01390 case SL_REF: return SlCalcRefLen();
01391 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01392 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01393 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01394 default: NOT_REACHED();
01395 }
01396 break;
01397 case SL_WRITEBYTE: return 1;
01398 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01399 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01400 default: NOT_REACHED();
01401 }
01402 return 0;
01403 }
01404
01405
01406 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01407 {
01408 VarType conv = GB(sld->conv, 0, 8);
01409 switch (sld->cmd) {
01410 case SL_VAR:
01411 case SL_REF:
01412 case SL_ARR:
01413 case SL_STR:
01414 case SL_LST:
01415
01416 if (!SlIsObjectValidInSavegame(sld)) return false;
01417 if (SlSkipVariableOnLoad(sld)) return false;
01418
01419 switch (sld->cmd) {
01420 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01421 case SL_REF:
01422 switch (_sl.action) {
01423 case SLA_SAVE:
01424 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01425 break;
01426 case SLA_LOAD_CHECK:
01427 case SLA_LOAD:
01428 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01429 break;
01430 case SLA_PTRS:
01431 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01432 break;
01433 case SLA_NULL:
01434 *(void **)ptr = NULL;
01435 break;
01436 default: NOT_REACHED();
01437 }
01438 break;
01439 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01440 case SL_STR: SlString(ptr, sld->length, conv); break;
01441 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01442 default: NOT_REACHED();
01443 }
01444 break;
01445
01446
01447
01448
01449
01450
01451 case SL_WRITEBYTE:
01452 switch (_sl.action) {
01453 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01454 case SLA_LOAD_CHECK:
01455 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01456 case SLA_PTRS: break;
01457 case SLA_NULL: break;
01458 default: NOT_REACHED();
01459 }
01460 break;
01461
01462
01463 case SL_VEH_INCLUDE:
01464 SlObject(ptr, GetVehicleDescription(VEH_END));
01465 break;
01466
01467 case SL_ST_INCLUDE:
01468 SlObject(ptr, GetBaseStationDescription());
01469 break;
01470
01471 default: NOT_REACHED();
01472 }
01473 return true;
01474 }
01475
01481 void SlObject(void *object, const SaveLoad *sld)
01482 {
01483
01484 if (_sl.need_length != NL_NONE) {
01485 SlSetLength(SlCalcObjLength(object, sld));
01486 if (_sl.need_length == NL_CALCLENGTH) return;
01487 }
01488
01489 for (; sld->cmd != SL_END; sld++) {
01490 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01491 SlObjectMember(ptr, sld);
01492 }
01493 }
01494
01499 void SlGlobList(const SaveLoadGlobVarList *sldg)
01500 {
01501 SlObject(NULL, (const SaveLoad*)sldg);
01502 }
01503
01509 void SlAutolength(AutolengthProc *proc, void *arg)
01510 {
01511 size_t offs;
01512
01513 assert(_sl.action == SLA_SAVE);
01514
01515
01516 _sl.need_length = NL_CALCLENGTH;
01517 _sl.obj_len = 0;
01518 proc(arg);
01519
01520
01521 _sl.need_length = NL_WANTLENGTH;
01522 SlSetLength(_sl.obj_len);
01523
01524 offs = _sl.dumper->GetSize() + _sl.obj_len;
01525
01526
01527 proc(arg);
01528
01529 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01530 }
01531
01536 static void SlLoadChunk(const ChunkHandler *ch)
01537 {
01538 byte m = SlReadByte();
01539 size_t len;
01540 size_t endoffs;
01541
01542 _sl.block_mode = m;
01543 _sl.obj_len = 0;
01544
01545 switch (m) {
01546 case CH_ARRAY:
01547 _sl.array_index = 0;
01548 ch->load_proc();
01549 break;
01550 case CH_SPARSE_ARRAY:
01551 ch->load_proc();
01552 break;
01553 default:
01554 if ((m & 0xF) == CH_RIFF) {
01555
01556 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01557 len += SlReadUint16();
01558 _sl.obj_len = len;
01559 endoffs = _sl.reader->GetSize() + len;
01560 ch->load_proc();
01561 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01562 } else {
01563 SlErrorCorrupt("Invalid chunk type");
01564 }
01565 break;
01566 }
01567 }
01568
01574 static void SlLoadCheckChunk(const ChunkHandler *ch)
01575 {
01576 byte m = SlReadByte();
01577 size_t len;
01578 size_t endoffs;
01579
01580 _sl.block_mode = m;
01581 _sl.obj_len = 0;
01582
01583 switch (m) {
01584 case CH_ARRAY:
01585 _sl.array_index = 0;
01586 if (ch->load_check_proc) {
01587 ch->load_check_proc();
01588 } else {
01589 SlSkipArray();
01590 }
01591 break;
01592 case CH_SPARSE_ARRAY:
01593 if (ch->load_check_proc) {
01594 ch->load_check_proc();
01595 } else {
01596 SlSkipArray();
01597 }
01598 break;
01599 default:
01600 if ((m & 0xF) == CH_RIFF) {
01601
01602 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01603 len += SlReadUint16();
01604 _sl.obj_len = len;
01605 endoffs = _sl.reader->GetSize() + len;
01606 if (ch->load_check_proc) {
01607 ch->load_check_proc();
01608 } else {
01609 SlSkipBytes(len);
01610 }
01611 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01612 } else {
01613 SlErrorCorrupt("Invalid chunk type");
01614 }
01615 break;
01616 }
01617 }
01618
01623 static ChunkSaveLoadProc *_stub_save_proc;
01624
01630 static inline void SlStubSaveProc2(void *arg)
01631 {
01632 _stub_save_proc();
01633 }
01634
01640 static void SlStubSaveProc()
01641 {
01642 SlAutolength(SlStubSaveProc2, NULL);
01643 }
01644
01650 static void SlSaveChunk(const ChunkHandler *ch)
01651 {
01652 ChunkSaveLoadProc *proc = ch->save_proc;
01653
01654
01655 if (proc == NULL) return;
01656
01657 SlWriteUint32(ch->id);
01658 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01659
01660 if (ch->flags & CH_AUTO_LENGTH) {
01661
01662 _stub_save_proc = proc;
01663 proc = SlStubSaveProc;
01664 }
01665
01666 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01667 switch (ch->flags & CH_TYPE_MASK) {
01668 case CH_RIFF:
01669 _sl.need_length = NL_WANTLENGTH;
01670 proc();
01671 break;
01672 case CH_ARRAY:
01673 _sl.last_array_index = 0;
01674 SlWriteByte(CH_ARRAY);
01675 proc();
01676 SlWriteArrayLength(0);
01677 break;
01678 case CH_SPARSE_ARRAY:
01679 SlWriteByte(CH_SPARSE_ARRAY);
01680 proc();
01681 SlWriteArrayLength(0);
01682 break;
01683 default: NOT_REACHED();
01684 }
01685 }
01686
01688 static void SlSaveChunks()
01689 {
01690 FOR_ALL_CHUNK_HANDLERS(ch) {
01691 SlSaveChunk(ch);
01692 }
01693
01694
01695 SlWriteUint32(0);
01696 }
01697
01704 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01705 {
01706 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01707 return NULL;
01708 }
01709
01711 static void SlLoadChunks()
01712 {
01713 uint32 id;
01714 const ChunkHandler *ch;
01715
01716 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01717 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01718
01719 ch = SlFindChunkHandler(id);
01720 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01721 SlLoadChunk(ch);
01722 }
01723 }
01724
01726 static void SlLoadCheckChunks()
01727 {
01728 uint32 id;
01729 const ChunkHandler *ch;
01730
01731 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01732 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01733
01734 ch = SlFindChunkHandler(id);
01735 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01736 SlLoadCheckChunk(ch);
01737 }
01738 }
01739
01741 static void SlFixPointers()
01742 {
01743 _sl.action = SLA_PTRS;
01744
01745 DEBUG(sl, 1, "Fixing pointers");
01746
01747 FOR_ALL_CHUNK_HANDLERS(ch) {
01748 if (ch->ptrs_proc != NULL) {
01749 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01750 ch->ptrs_proc();
01751 }
01752 }
01753
01754 DEBUG(sl, 1, "All pointers fixed");
01755
01756 assert(_sl.action == SLA_PTRS);
01757 }
01758
01759
01761 struct FileReader : LoadFilter {
01762 FILE *file;
01763 long begin;
01764
01769 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01770 {
01771 }
01772
01774 ~FileReader()
01775 {
01776 if (this->file != NULL) fclose(this->file);
01777 this->file = NULL;
01778
01779
01780 _sl.sf = NULL;
01781 }
01782
01783 size_t Read(byte *buf, size_t size)
01784 {
01785
01786 if (this->file == NULL) return 0;
01787
01788 return fread(buf, 1, size, this->file);
01789 }
01790
01791 void Reset()
01792 {
01793 clearerr(this->file);
01794 fseek(this->file, this->begin, SEEK_SET);
01795 }
01796 };
01797
01799 struct FileWriter : SaveFilter {
01800 FILE *file;
01801
01806 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01807 {
01808 }
01809
01811 ~FileWriter()
01812 {
01813 this->Finish();
01814
01815
01816 _sl.sf = NULL;
01817 }
01818
01819 void Write(byte *buf, size_t size)
01820 {
01821
01822 if (this->file == NULL) return;
01823
01824 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01825 }
01826
01827 void Finish()
01828 {
01829 if (this->file != NULL) fclose(this->file);
01830 this->file = NULL;
01831 }
01832 };
01833
01834
01835
01836
01837
01838 #ifdef WITH_LZO
01839 #include <lzo/lzo1x.h>
01840
01842 static const uint LZO_BUFFER_SIZE = 8192;
01843
01845 struct LZOLoadFilter : LoadFilter {
01850 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01851 {
01852 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01853 }
01854
01855 size_t Read(byte *buf, size_t ssize)
01856 {
01857 assert(ssize >= LZO_BUFFER_SIZE);
01858
01859
01860 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01861 uint32 tmp[2];
01862 uint32 size;
01863 lzo_uint len;
01864
01865
01866 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01867
01868
01869 ((uint32*)out)[0] = size = tmp[1];
01870
01871 if (_sl_version != 0) {
01872 tmp[0] = TO_BE32(tmp[0]);
01873 size = TO_BE32(size);
01874 }
01875
01876 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01877
01878
01879 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01880
01881
01882 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01883
01884
01885 lzo1x_decompress(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01886 return len;
01887 }
01888 };
01889
01891 struct LZOSaveFilter : SaveFilter {
01897 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01898 {
01899 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01900 }
01901
01902 void Write(byte *buf, size_t size)
01903 {
01904 const lzo_bytep in = buf;
01905
01906 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01907 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01908 lzo_uint outlen;
01909
01910 do {
01911
01912 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01913 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01914 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01915 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01916 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01917
01918
01919 size -= len;
01920 in += len;
01921 } while (size > 0);
01922 }
01923 };
01924
01925 #endif
01926
01927
01928
01929
01930
01932 struct NoCompLoadFilter : LoadFilter {
01937 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01938 {
01939 }
01940
01941 size_t Read(byte *buf, size_t size)
01942 {
01943 return this->chain->Read(buf, size);
01944 }
01945 };
01946
01948 struct NoCompSaveFilter : SaveFilter {
01954 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01955 {
01956 }
01957
01958 void Write(byte *buf, size_t size)
01959 {
01960 this->chain->Write(buf, size);
01961 }
01962 };
01963
01964
01965
01966
01967
01968 #if defined(WITH_ZLIB)
01969 #include <zlib.h>
01970
01972 struct ZlibLoadFilter : LoadFilter {
01973 z_stream z;
01974 byte fread_buf[MEMORY_CHUNK_SIZE];
01975
01980 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01981 {
01982 memset(&this->z, 0, sizeof(this->z));
01983 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01984 }
01985
01987 ~ZlibLoadFilter()
01988 {
01989 inflateEnd(&this->z);
01990 }
01991
01992 size_t Read(byte *buf, size_t size)
01993 {
01994 this->z.next_out = buf;
01995 this->z.avail_out = (uint)size;
01996
01997 do {
01998
01999 if (this->z.avail_in == 0) {
02000 this->z.next_in = this->fread_buf;
02001 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02002 }
02003
02004
02005 int r = inflate(&this->z, 0);
02006 if (r == Z_STREAM_END) break;
02007
02008 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02009 } while (this->z.avail_out != 0);
02010
02011 return size - this->z.avail_out;
02012 }
02013 };
02014
02016 struct ZlibSaveFilter : SaveFilter {
02017 z_stream z;
02018
02024 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02025 {
02026 memset(&this->z, 0, sizeof(this->z));
02027 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02028 }
02029
02031 ~ZlibSaveFilter()
02032 {
02033 deflateEnd(&this->z);
02034 }
02035
02042 void WriteLoop(byte *p, size_t len, int mode)
02043 {
02044 byte buf[MEMORY_CHUNK_SIZE];
02045 uint n;
02046 this->z.next_in = p;
02047 this->z.avail_in = (uInt)len;
02048 do {
02049 this->z.next_out = buf;
02050 this->z.avail_out = sizeof(buf);
02051
02059 int r = deflate(&this->z, mode);
02060
02061
02062 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02063 this->chain->Write(buf, n);
02064 }
02065 if (r == Z_STREAM_END) break;
02066
02067 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02068 } while (this->z.avail_in || !this->z.avail_out);
02069 }
02070
02071 void Write(byte *buf, size_t size)
02072 {
02073 this->WriteLoop(buf, size, 0);
02074 }
02075
02076 void Finish()
02077 {
02078 this->WriteLoop(NULL, 0, Z_FINISH);
02079 this->chain->Finish();
02080 }
02081 };
02082
02083 #endif
02084
02085
02086
02087
02088
02089 #if defined(WITH_LZMA)
02090 #include <lzma.h>
02091
02098 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02099
02101 struct LZMALoadFilter : LoadFilter {
02102 lzma_stream lzma;
02103 byte fread_buf[MEMORY_CHUNK_SIZE];
02104
02109 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02110 {
02111
02112 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02113 }
02114
02116 ~LZMALoadFilter()
02117 {
02118 lzma_end(&this->lzma);
02119 }
02120
02121 size_t Read(byte *buf, size_t size)
02122 {
02123 this->lzma.next_out = buf;
02124 this->lzma.avail_out = size;
02125
02126 do {
02127
02128 if (this->lzma.avail_in == 0) {
02129 this->lzma.next_in = this->fread_buf;
02130 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02131 }
02132
02133
02134 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02135 if (r == LZMA_STREAM_END) break;
02136 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02137 } while (this->lzma.avail_out != 0);
02138
02139 return size - this->lzma.avail_out;
02140 }
02141 };
02142
02144 struct LZMASaveFilter : SaveFilter {
02145 lzma_stream lzma;
02146
02152 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02153 {
02154 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02155 }
02156
02158 ~LZMASaveFilter()
02159 {
02160 lzma_end(&this->lzma);
02161 }
02162
02169 void WriteLoop(byte *p, size_t len, lzma_action action)
02170 {
02171 byte buf[MEMORY_CHUNK_SIZE];
02172 size_t n;
02173 this->lzma.next_in = p;
02174 this->lzma.avail_in = len;
02175 do {
02176 this->lzma.next_out = buf;
02177 this->lzma.avail_out = sizeof(buf);
02178
02179 lzma_ret r = lzma_code(&this->lzma, action);
02180
02181
02182 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02183 this->chain->Write(buf, n);
02184 }
02185 if (r == LZMA_STREAM_END) break;
02186 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02187 } while (this->lzma.avail_in || !this->lzma.avail_out);
02188 }
02189
02190 void Write(byte *buf, size_t size)
02191 {
02192 this->WriteLoop(buf, size, LZMA_RUN);
02193 }
02194
02195 void Finish()
02196 {
02197 this->WriteLoop(NULL, 0, LZMA_FINISH);
02198 this->chain->Finish();
02199 }
02200 };
02201
02202 #endif
02203
02204
02205
02206
02207
02209 struct SaveLoadFormat {
02210 const char *name;
02211 uint32 tag;
02212
02213 LoadFilter *(*init_load)(LoadFilter *chain);
02214 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02215
02216 byte min_compression;
02217 byte default_compression;
02218 byte max_compression;
02219 };
02220
02222 static const SaveLoadFormat _saveload_formats[] = {
02223 #if defined(WITH_LZO)
02224
02225 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02226 #else
02227 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02228 #endif
02229
02230 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02231 #if defined(WITH_ZLIB)
02232
02233
02234
02235 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02236 #else
02237 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02238 #endif
02239 #if defined(WITH_LZMA)
02240
02241
02242
02243
02244
02245 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02246 #else
02247 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02248 #endif
02249 };
02250
02258 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02259 {
02260 const SaveLoadFormat *def = lastof(_saveload_formats);
02261
02262
02263 while (!def->init_write) def--;
02264
02265 if (!StrEmpty(s)) {
02266
02267 char *complevel = strrchr(s, ':');
02268 if (complevel != NULL) *complevel = '\0';
02269
02270 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02271 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02272 *compression_level = slf->default_compression;
02273 if (complevel != NULL) {
02274
02275
02276
02277 *complevel = ':';
02278 complevel++;
02279
02280
02281 char *end;
02282 long level = strtol(complevel, &end, 10);
02283 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02284 ShowInfoF("Compression level '%s' is not valid.", complevel);
02285 } else {
02286 *compression_level = level;
02287 }
02288 }
02289 return slf;
02290 }
02291 }
02292
02293 ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
02294
02295
02296 if (complevel != NULL) *complevel = ':';
02297 }
02298 *compression_level = def->default_compression;
02299 return def;
02300 }
02301
02302
02303 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02304 extern bool AfterLoadGame();
02305 extern bool LoadOldSaveGame(const char *file);
02306
02310 static inline void ClearSaveLoadState()
02311 {
02312 delete _sl.dumper;
02313 _sl.dumper = NULL;
02314
02315 delete _sl.sf;
02316 _sl.sf = NULL;
02317
02318 delete _sl.reader;
02319 _sl.reader = NULL;
02320
02321 delete _sl.lf;
02322 _sl.lf = NULL;
02323 }
02324
02330 static void SaveFileStart()
02331 {
02332 _sl.ff_state = _fast_forward;
02333 _fast_forward = 0;
02334 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02335
02336 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02337 _sl.saveinprogress = true;
02338 }
02339
02341 static void SaveFileDone()
02342 {
02343 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02344 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02345
02346 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02347 _sl.saveinprogress = false;
02348 }
02349
02351 void SetSaveLoadError(StringID str)
02352 {
02353 _sl.error_str = str;
02354 }
02355
02357 const char *GetSaveLoadErrorString()
02358 {
02359 SetDParam(0, _sl.error_str);
02360 SetDParamStr(1, _sl.extra_msg);
02361
02362 static char err_str[512];
02363 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02364 return err_str;
02365 }
02366
02368 static void SaveFileError()
02369 {
02370 SetDParamStr(0, GetSaveLoadErrorString());
02371 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02372 SaveFileDone();
02373 }
02374
02379 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02380 {
02381 try {
02382 byte compression;
02383 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02384
02385
02386 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02387 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02388
02389 _sl.sf = fmt->init_write(_sl.sf, compression);
02390 _sl.dumper->Flush(_sl.sf);
02391
02392 ClearSaveLoadState();
02393
02394 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02395
02396 return SL_OK;
02397 } catch (...) {
02398 ClearSaveLoadState();
02399
02400 AsyncSaveFinishProc asfp = SaveFileDone;
02401
02402
02403
02404 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02405
02406 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02407 asfp = SaveFileError;
02408 }
02409
02410 if (threaded) {
02411 SetAsyncSaveFinish(asfp);
02412 } else {
02413 asfp();
02414 }
02415 return SL_ERROR;
02416 }
02417 }
02418
02420 static void SaveFileToDiskThread(void *arg)
02421 {
02422 SaveFileToDisk(true);
02423 }
02424
02425 void WaitTillSaved()
02426 {
02427 if (_save_thread == NULL) return;
02428
02429 _save_thread->Join();
02430 delete _save_thread;
02431 _save_thread = NULL;
02432
02433
02434 ProcessAsyncSaveFinish();
02435 }
02436
02445 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02446 {
02447 assert(!_sl.saveinprogress);
02448
02449 _sl.dumper = new MemoryDumper();
02450 _sl.sf = writer;
02451
02452 _sl_version = SAVEGAME_VERSION;
02453
02454 SaveViewportBeforeSaveGame();
02455 SlSaveChunks();
02456
02457 SaveFileStart();
02458 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02459 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02460
02461 SaveOrLoadResult result = SaveFileToDisk(false);
02462 SaveFileDone();
02463
02464 return result;
02465 }
02466
02467 return SL_OK;
02468 }
02469
02476 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02477 {
02478 try {
02479 _sl.action = SLA_SAVE;
02480 return DoSave(writer, threaded);
02481 } catch (...) {
02482 ClearSaveLoadState();
02483 return SL_ERROR;
02484 }
02485 }
02486
02493 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02494 {
02495 _sl.lf = reader;
02496
02497 if (load_check) {
02498
02499 _load_check_data.Clear();
02500
02501 _load_check_data.checkable = true;
02502 }
02503
02504 uint32 hdr[2];
02505 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02506
02507
02508 const SaveLoadFormat *fmt = _saveload_formats;
02509 for (;;) {
02510
02511 if (fmt == endof(_saveload_formats)) {
02512 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02513 _sl.lf->Reset();
02514 _sl_version = 0;
02515 _sl_minor_version = 0;
02516
02517
02518 fmt = _saveload_formats;
02519 for (;;) {
02520 if (fmt == endof(_saveload_formats)) {
02521
02522 NOT_REACHED();
02523 }
02524 if (fmt->tag == TO_BE32X('OTTD')) break;
02525 fmt++;
02526 }
02527 break;
02528 }
02529
02530 if (fmt->tag == hdr[0]) {
02531
02532 _sl_version = TO_BE32(hdr[1]) >> 16;
02533
02534
02535
02536
02537 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02538
02539 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02540
02541
02542 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02543 break;
02544 }
02545
02546 fmt++;
02547 }
02548
02549
02550 if (fmt->init_load == NULL) {
02551 char err_str[64];
02552 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02553 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02554 }
02555
02556 _sl.lf = fmt->init_load(_sl.lf);
02557 _sl.reader = new ReadBuffer(_sl.lf);
02558 _next_offs = 0;
02559
02560 if (!load_check) {
02561 _engine_mngr.ResetToDefaultMapping();
02562
02563
02564
02565
02566 InitializeGame(256, 256, true, true);
02567
02568 GamelogReset();
02569
02570 if (IsSavegameVersionBefore(4)) {
02571
02572
02573
02574
02575
02576
02577
02578
02579
02580
02581
02582
02583
02584
02585
02586
02587
02588
02589
02590
02591
02592 ClearGRFConfigList(&_grfconfig);
02593 }
02594 }
02595
02596 if (load_check) {
02597
02598
02599 SlLoadCheckChunks();
02600 } else {
02601
02602 SlLoadChunks();
02603 SlFixPointers();
02604 }
02605
02606 ClearSaveLoadState();
02607
02608 _savegame_type = SGT_OTTD;
02609
02610 if (load_check) {
02611
02612 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02613 } else {
02614 GamelogStartAction(GLAT_LOAD);
02615
02616
02617
02618 if (!AfterLoadGame()) {
02619 GamelogStopAction();
02620 return SL_REINIT;
02621 }
02622
02623 GamelogStopAction();
02624 }
02625
02626 return SL_OK;
02627 }
02628
02634 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02635 {
02636 try {
02637 _sl.action = SLA_LOAD;
02638 return DoLoad(reader, false);
02639 } catch (...) {
02640 ClearSaveLoadState();
02641 return SL_REINIT;
02642 }
02643 }
02644
02654 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02655 {
02656
02657 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02658
02659 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02660 return SL_OK;
02661 }
02662 WaitTillSaved();
02663
02664
02665 if (mode == SL_OLD_LOAD) {
02666 _engine_mngr.ResetToDefaultMapping();
02667 InitializeGame(256, 256, true, true);
02668
02669
02670
02671
02672
02673 ClearGRFConfigList(&_grfconfig);
02674 GamelogReset();
02675 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02676 _sl_version = 0;
02677 _sl_minor_version = 0;
02678 GamelogStartAction(GLAT_LOAD);
02679 if (!AfterLoadGame()) {
02680 GamelogStopAction();
02681 return SL_REINIT;
02682 }
02683 GamelogStopAction();
02684 return SL_OK;
02685 }
02686
02687 switch (mode) {
02688 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02689 case SL_LOAD: _sl.action = SLA_LOAD; break;
02690 case SL_SAVE: _sl.action = SLA_SAVE; break;
02691 default: NOT_REACHED();
02692 }
02693
02694 try {
02695 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02696
02697
02698 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02699 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02700
02701 if (fh == NULL) {
02702 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02703 }
02704
02705 if (mode == SL_SAVE) {
02706 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02707 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02708
02709 return DoSave(new FileWriter(fh), threaded);
02710 }
02711
02712
02713 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02714 DEBUG(desync, 1, "load: %s", filename);
02715 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02716 } catch (...) {
02717 ClearSaveLoadState();
02718
02719
02720 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02721
02722
02723 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02724 }
02725 }
02726
02728 void DoExitSave()
02729 {
02730 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02731 }
02732
02738 void GenerateDefaultSaveName(char *buf, const char *last)
02739 {
02740
02741
02742
02743 CompanyID cid = _local_company;
02744 if (!Company::IsValidID(cid)) {
02745 const Company *c;
02746 FOR_ALL_COMPANIES(c) {
02747 cid = c->index;
02748 break;
02749 }
02750 }
02751
02752 SetDParam(0, cid);
02753
02754
02755 switch (_settings_client.gui.date_format_in_default_names) {
02756 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02757 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02758 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02759 default: NOT_REACHED();
02760 }
02761 SetDParam(2, _date);
02762
02763
02764 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02765 SanitizeFilename(buf);
02766 }
02767
02768 #if 0
02769
02775 int GetSavegameType(char *file)
02776 {
02777 const SaveLoadFormat *fmt;
02778 uint32 hdr;
02779 FILE *f;
02780 int mode = SL_OLD_LOAD;
02781
02782 f = fopen(file, "rb");
02783 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02784 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02785 mode = SL_LOAD;
02786 } else {
02787
02788 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02789 if (fmt->tag == hdr) {
02790 mode = SL_LOAD;
02791 break;
02792 }
02793 }
02794 }
02795
02796 fclose(f);
02797 return mode;
02798 }
02799 #endif