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