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 "../fios.h"
00043 #include "../error.h"
00044
00045 #include "table/strings.h"
00046
00047 #include "saveload_internal.h"
00048 #include "saveload_filter.h"
00049
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
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 extern const uint16 SAVEGAME_VERSION = 180;
00249
00250 SavegameType _savegame_type;
00251
00252 uint32 _ttdp_version;
00253 uint16 _sl_version;
00254 byte _sl_minor_version;
00255 char _savegame_format[8];
00256 bool _do_autosave;
00257
00259 enum SaveLoadAction {
00260 SLA_LOAD,
00261 SLA_SAVE,
00262 SLA_PTRS,
00263 SLA_NULL,
00264 SLA_LOAD_CHECK,
00265 };
00266
00267 enum NeedLength {
00268 NL_NONE = 0,
00269 NL_WANTLENGTH = 1,
00270 NL_CALCLENGTH = 2,
00271 };
00272
00274 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
00275
00277 struct ReadBuffer {
00278 byte buf[MEMORY_CHUNK_SIZE];
00279 byte *bufp;
00280 byte *bufe;
00281 LoadFilter *reader;
00282 size_t read;
00283
00288 ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
00289 {
00290 }
00291
00292 inline byte ReadByte()
00293 {
00294 if (this->bufp == this->bufe) {
00295 size_t len = this->reader->Read(this->buf, lengthof(this->buf));
00296 if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00297
00298 this->read += len;
00299 this->bufp = this->buf;
00300 this->bufe = this->buf + len;
00301 }
00302
00303 return *this->bufp++;
00304 }
00305
00310 size_t GetSize() const
00311 {
00312 return this->read - (this->bufe - this->bufp);
00313 }
00314 };
00315
00316
00318 struct MemoryDumper {
00319 AutoFreeSmallVector<byte *, 16> blocks;
00320 byte *buf;
00321 byte *bufe;
00322
00324 MemoryDumper() : buf(NULL), bufe(NULL)
00325 {
00326 }
00327
00332 inline void WriteByte(byte b)
00333 {
00334
00335 if (this->buf == this->bufe) {
00336 this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
00337 *this->blocks.Append() = this->buf;
00338 this->bufe = this->buf + MEMORY_CHUNK_SIZE;
00339 }
00340
00341 *this->buf++ = b;
00342 }
00343
00348 void Flush(SaveFilter *writer)
00349 {
00350 uint i = 0;
00351 size_t t = this->GetSize();
00352
00353 while (t > 0) {
00354 size_t to_write = min(MEMORY_CHUNK_SIZE, t);
00355
00356 writer->Write(this->blocks[i++], to_write);
00357 t -= to_write;
00358 }
00359
00360 writer->Finish();
00361 }
00362
00367 size_t GetSize() const
00368 {
00369 return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
00370 }
00371 };
00372
00374 struct SaveLoadParams {
00375 SaveLoadAction action;
00376 NeedLength need_length;
00377 byte block_mode;
00378 bool error;
00379
00380 size_t obj_len;
00381 int array_index, last_array_index;
00382
00383 MemoryDumper *dumper;
00384 SaveFilter *sf;
00385
00386 ReadBuffer *reader;
00387 LoadFilter *lf;
00388
00389 StringID error_str;
00390 char *extra_msg;
00391
00392 byte ff_state;
00393 bool saveinprogress;
00394 };
00395
00396 static SaveLoadParams _sl;
00397
00398
00399 extern const ChunkHandler _gamelog_chunk_handlers[];
00400 extern const ChunkHandler _map_chunk_handlers[];
00401 extern const ChunkHandler _misc_chunk_handlers[];
00402 extern const ChunkHandler _name_chunk_handlers[];
00403 extern const ChunkHandler _cheat_chunk_handlers[] ;
00404 extern const ChunkHandler _setting_chunk_handlers[];
00405 extern const ChunkHandler _company_chunk_handlers[];
00406 extern const ChunkHandler _engine_chunk_handlers[];
00407 extern const ChunkHandler _veh_chunk_handlers[];
00408 extern const ChunkHandler _waypoint_chunk_handlers[];
00409 extern const ChunkHandler _depot_chunk_handlers[];
00410 extern const ChunkHandler _order_chunk_handlers[];
00411 extern const ChunkHandler _town_chunk_handlers[];
00412 extern const ChunkHandler _sign_chunk_handlers[];
00413 extern const ChunkHandler _station_chunk_handlers[];
00414 extern const ChunkHandler _industry_chunk_handlers[];
00415 extern const ChunkHandler _economy_chunk_handlers[];
00416 extern const ChunkHandler _subsidy_chunk_handlers[];
00417 extern const ChunkHandler _cargomonitor_chunk_handlers[];
00418 extern const ChunkHandler _goal_chunk_handlers[];
00419 extern const ChunkHandler _ai_chunk_handlers[];
00420 extern const ChunkHandler _game_chunk_handlers[];
00421 extern const ChunkHandler _animated_tile_chunk_handlers[];
00422 extern const ChunkHandler _newgrf_chunk_handlers[];
00423 extern const ChunkHandler _group_chunk_handlers[];
00424 extern const ChunkHandler _cargopacket_chunk_handlers[];
00425 extern const ChunkHandler _autoreplace_chunk_handlers[];
00426 extern const ChunkHandler _labelmaps_chunk_handlers[];
00427 extern const ChunkHandler _airport_chunk_handlers[];
00428 extern const ChunkHandler _object_chunk_handlers[];
00429 extern const ChunkHandler _persistent_storage_chunk_handlers[];
00430
00432 static const ChunkHandler * const _chunk_handlers[] = {
00433 _gamelog_chunk_handlers,
00434 _map_chunk_handlers,
00435 _misc_chunk_handlers,
00436 _name_chunk_handlers,
00437 _cheat_chunk_handlers,
00438 _setting_chunk_handlers,
00439 _veh_chunk_handlers,
00440 _waypoint_chunk_handlers,
00441 _depot_chunk_handlers,
00442 _order_chunk_handlers,
00443 _industry_chunk_handlers,
00444 _economy_chunk_handlers,
00445 _subsidy_chunk_handlers,
00446 _cargomonitor_chunk_handlers,
00447 _goal_chunk_handlers,
00448 _engine_chunk_handlers,
00449 _town_chunk_handlers,
00450 _sign_chunk_handlers,
00451 _station_chunk_handlers,
00452 _company_chunk_handlers,
00453 _ai_chunk_handlers,
00454 _game_chunk_handlers,
00455 _animated_tile_chunk_handlers,
00456 _newgrf_chunk_handlers,
00457 _group_chunk_handlers,
00458 _cargopacket_chunk_handlers,
00459 _autoreplace_chunk_handlers,
00460 _labelmaps_chunk_handlers,
00461 _airport_chunk_handlers,
00462 _object_chunk_handlers,
00463 _persistent_storage_chunk_handlers,
00464 NULL,
00465 };
00466
00471 #define FOR_ALL_CHUNK_HANDLERS(ch) \
00472 for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \
00473 for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1)
00474
00476 static void SlNullPointers()
00477 {
00478 _sl.action = SLA_NULL;
00479
00480
00481
00482
00483 _sl_version = SAVEGAME_VERSION;
00484
00485 DEBUG(sl, 1, "Nulling pointers");
00486
00487 FOR_ALL_CHUNK_HANDLERS(ch) {
00488 if (ch->ptrs_proc != NULL) {
00489 DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00490 ch->ptrs_proc();
00491 }
00492 }
00493
00494 DEBUG(sl, 1, "All pointers nulled");
00495
00496 assert(_sl.action == SLA_NULL);
00497 }
00498
00507 void NORETURN SlError(StringID string, const char *extra_msg)
00508 {
00509
00510 if (_sl.action == SLA_LOAD_CHECK) {
00511 _load_check_data.error = string;
00512 free(_load_check_data.error_data);
00513 _load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00514 } else {
00515 _sl.error_str = string;
00516 free(_sl.extra_msg);
00517 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00518 }
00519
00520
00521
00522
00523
00524 if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00525 throw std::exception();
00526 }
00527
00535 void NORETURN SlErrorCorrupt(const char *msg)
00536 {
00537 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00538 }
00539
00540
00541 typedef void (*AsyncSaveFinishProc)();
00542 static AsyncSaveFinishProc _async_save_finish = NULL;
00543 static ThreadObject *_save_thread;
00544
00549 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00550 {
00551 if (_exit_game) return;
00552 while (_async_save_finish != NULL) CSleep(10);
00553
00554 _async_save_finish = proc;
00555 }
00556
00560 void ProcessAsyncSaveFinish()
00561 {
00562 if (_async_save_finish == NULL) return;
00563
00564 _async_save_finish();
00565
00566 _async_save_finish = NULL;
00567
00568 if (_save_thread != NULL) {
00569 _save_thread->Join();
00570 delete _save_thread;
00571 _save_thread = NULL;
00572 }
00573 }
00574
00579 byte SlReadByte()
00580 {
00581 return _sl.reader->ReadByte();
00582 }
00583
00588 void SlWriteByte(byte b)
00589 {
00590 _sl.dumper->WriteByte(b);
00591 }
00592
00593 static inline int SlReadUint16()
00594 {
00595 int x = SlReadByte() << 8;
00596 return x | SlReadByte();
00597 }
00598
00599 static inline uint32 SlReadUint32()
00600 {
00601 uint32 x = SlReadUint16() << 16;
00602 return x | SlReadUint16();
00603 }
00604
00605 static inline uint64 SlReadUint64()
00606 {
00607 uint32 x = SlReadUint32();
00608 uint32 y = SlReadUint32();
00609 return (uint64)x << 32 | y;
00610 }
00611
00612 static inline void SlWriteUint16(uint16 v)
00613 {
00614 SlWriteByte(GB(v, 8, 8));
00615 SlWriteByte(GB(v, 0, 8));
00616 }
00617
00618 static inline void SlWriteUint32(uint32 v)
00619 {
00620 SlWriteUint16(GB(v, 16, 16));
00621 SlWriteUint16(GB(v, 0, 16));
00622 }
00623
00624 static inline void SlWriteUint64(uint64 x)
00625 {
00626 SlWriteUint32((uint32)(x >> 32));
00627 SlWriteUint32((uint32)x);
00628 }
00629
00635 static inline void SlSkipBytes(size_t length)
00636 {
00637 for (; length != 0; length--) SlReadByte();
00638 }
00639
00649 static uint SlReadSimpleGamma()
00650 {
00651 uint i = SlReadByte();
00652 if (HasBit(i, 7)) {
00653 i &= ~0x80;
00654 if (HasBit(i, 6)) {
00655 i &= ~0x40;
00656 if (HasBit(i, 5)) {
00657 i &= ~0x20;
00658 if (HasBit(i, 4)) {
00659 SlErrorCorrupt("Unsupported gamma");
00660 }
00661 i = (i << 8) | SlReadByte();
00662 }
00663 i = (i << 8) | SlReadByte();
00664 }
00665 i = (i << 8) | SlReadByte();
00666 }
00667 return i;
00668 }
00669
00682 static void SlWriteSimpleGamma(size_t i)
00683 {
00684 if (i >= (1 << 7)) {
00685 if (i >= (1 << 14)) {
00686 if (i >= (1 << 21)) {
00687 assert(i < (1 << 28));
00688 SlWriteByte((byte)(0xE0 | (i >> 24)));
00689 SlWriteByte((byte)(i >> 16));
00690 } else {
00691 SlWriteByte((byte)(0xC0 | (i >> 16)));
00692 }
00693 SlWriteByte((byte)(i >> 8));
00694 } else {
00695 SlWriteByte((byte)(0x80 | (i >> 8)));
00696 }
00697 }
00698 SlWriteByte((byte)i);
00699 }
00700
00702 static inline uint SlGetGammaLength(size_t i)
00703 {
00704 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00705 }
00706
00707 static inline uint SlReadSparseIndex()
00708 {
00709 return SlReadSimpleGamma();
00710 }
00711
00712 static inline void SlWriteSparseIndex(uint index)
00713 {
00714 SlWriteSimpleGamma(index);
00715 }
00716
00717 static inline uint SlReadArrayLength()
00718 {
00719 return SlReadSimpleGamma();
00720 }
00721
00722 static inline void SlWriteArrayLength(size_t length)
00723 {
00724 SlWriteSimpleGamma(length);
00725 }
00726
00727 static inline uint SlGetArrayLength(size_t length)
00728 {
00729 return SlGetGammaLength(length);
00730 }
00731
00738 static inline uint SlCalcConvMemLen(VarType conv)
00739 {
00740 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00741 byte length = GB(conv, 4, 4);
00742
00743 switch (length << 4) {
00744 case SLE_VAR_STRB:
00745 case SLE_VAR_STRBQ:
00746 case SLE_VAR_STR:
00747 case SLE_VAR_STRQ:
00748 return SlReadArrayLength();
00749
00750 default:
00751 assert(length < lengthof(conv_mem_size));
00752 return conv_mem_size[length];
00753 }
00754 }
00755
00762 static inline byte SlCalcConvFileLen(VarType conv)
00763 {
00764 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00765 byte length = GB(conv, 0, 4);
00766 assert(length < lengthof(conv_file_size));
00767 return conv_file_size[length];
00768 }
00769
00771 static inline size_t SlCalcRefLen()
00772 {
00773 return IsSavegameVersionBefore(69) ? 2 : 4;
00774 }
00775
00776 void SlSetArrayIndex(uint index)
00777 {
00778 _sl.need_length = NL_WANTLENGTH;
00779 _sl.array_index = index;
00780 }
00781
00782 static size_t _next_offs;
00783
00788 int SlIterateArray()
00789 {
00790 int index;
00791
00792
00793
00794 if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00795
00796 for (;;) {
00797 uint length = SlReadArrayLength();
00798 if (length == 0) {
00799 _next_offs = 0;
00800 return -1;
00801 }
00802
00803 _sl.obj_len = --length;
00804 _next_offs = _sl.reader->GetSize() + length;
00805
00806 switch (_sl.block_mode) {
00807 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00808 case CH_ARRAY: index = _sl.array_index++; break;
00809 default:
00810 DEBUG(sl, 0, "SlIterateArray error");
00811 return -1;
00812 }
00813
00814 if (length != 0) return index;
00815 }
00816 }
00817
00821 void SlSkipArray()
00822 {
00823 while (SlIterateArray() != -1) {
00824 SlSkipBytes(_next_offs - _sl.reader->GetSize());
00825 }
00826 }
00827
00833 void SlSetLength(size_t length)
00834 {
00835 assert(_sl.action == SLA_SAVE);
00836
00837 switch (_sl.need_length) {
00838 case NL_WANTLENGTH:
00839 _sl.need_length = NL_NONE;
00840 switch (_sl.block_mode) {
00841 case CH_RIFF:
00842
00843
00844
00845 assert(length < (1 << 28));
00846 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00847 break;
00848 case CH_ARRAY:
00849 assert(_sl.last_array_index <= _sl.array_index);
00850 while (++_sl.last_array_index <= _sl.array_index) {
00851 SlWriteArrayLength(1);
00852 }
00853 SlWriteArrayLength(length + 1);
00854 break;
00855 case CH_SPARSE_ARRAY:
00856 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00857 SlWriteSparseIndex(_sl.array_index);
00858 break;
00859 default: NOT_REACHED();
00860 }
00861 break;
00862
00863 case NL_CALCLENGTH:
00864 _sl.obj_len += (int)length;
00865 break;
00866
00867 default: NOT_REACHED();
00868 }
00869 }
00870
00877 static void SlCopyBytes(void *ptr, size_t length)
00878 {
00879 byte *p = (byte *)ptr;
00880
00881 switch (_sl.action) {
00882 case SLA_LOAD_CHECK:
00883 case SLA_LOAD:
00884 for (; length != 0; length--) *p++ = SlReadByte();
00885 break;
00886 case SLA_SAVE:
00887 for (; length != 0; length--) SlWriteByte(*p++);
00888 break;
00889 default: NOT_REACHED();
00890 }
00891 }
00892
00894 size_t SlGetFieldLength()
00895 {
00896 return _sl.obj_len;
00897 }
00898
00906 int64 ReadValue(const void *ptr, VarType conv)
00907 {
00908 switch (GetVarMemType(conv)) {
00909 case SLE_VAR_BL: return (*(const bool *)ptr != 0);
00910 case SLE_VAR_I8: return *(const int8 *)ptr;
00911 case SLE_VAR_U8: return *(const byte *)ptr;
00912 case SLE_VAR_I16: return *(const int16 *)ptr;
00913 case SLE_VAR_U16: return *(const uint16*)ptr;
00914 case SLE_VAR_I32: return *(const int32 *)ptr;
00915 case SLE_VAR_U32: return *(const uint32*)ptr;
00916 case SLE_VAR_I64: return *(const int64 *)ptr;
00917 case SLE_VAR_U64: return *(const uint64*)ptr;
00918 case SLE_VAR_NULL:return 0;
00919 default: NOT_REACHED();
00920 }
00921 }
00922
00930 void WriteValue(void *ptr, VarType conv, int64 val)
00931 {
00932 switch (GetVarMemType(conv)) {
00933 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00934 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00935 case SLE_VAR_U8: *(byte *)ptr = val; break;
00936 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00937 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00938 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00939 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00940 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00941 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00942 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00943 case SLE_VAR_NULL: break;
00944 default: NOT_REACHED();
00945 }
00946 }
00947
00956 static void SlSaveLoadConv(void *ptr, VarType conv)
00957 {
00958 switch (_sl.action) {
00959 case SLA_SAVE: {
00960 int64 x = ReadValue(ptr, conv);
00961
00962
00963 switch (GetVarFileType(conv)) {
00964 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00965 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00966 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00967 case SLE_FILE_STRINGID:
00968 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00969 case SLE_FILE_I32:
00970 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00971 case SLE_FILE_I64:
00972 case SLE_FILE_U64: SlWriteUint64(x);break;
00973 default: NOT_REACHED();
00974 }
00975 break;
00976 }
00977 case SLA_LOAD_CHECK:
00978 case SLA_LOAD: {
00979 int64 x;
00980
00981 switch (GetVarFileType(conv)) {
00982 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00983 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00984 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00985 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00986 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00987 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00988 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00989 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00990 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00991 default: NOT_REACHED();
00992 }
00993
00994
00995 WriteValue(ptr, conv, x);
00996 break;
00997 }
00998 case SLA_PTRS: break;
00999 case SLA_NULL: break;
01000 default: NOT_REACHED();
01001 }
01002 }
01003
01013 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
01014 {
01015 if (ptr == NULL) return 0;
01016 return min(strlen(ptr), length - 1);
01017 }
01018
01028 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
01029 {
01030 size_t len;
01031 const char *str;
01032
01033 switch (GetVarMemType(conv)) {
01034 default: NOT_REACHED();
01035 case SLE_VAR_STR:
01036 case SLE_VAR_STRQ:
01037 str = *(const char * const *)ptr;
01038 len = SIZE_MAX;
01039 break;
01040 case SLE_VAR_STRB:
01041 case SLE_VAR_STRBQ:
01042 str = (const char *)ptr;
01043 len = length;
01044 break;
01045 }
01046
01047 len = SlCalcNetStringLen(str, len);
01048 return len + SlGetArrayLength(len);
01049 }
01050
01057 static void SlString(void *ptr, size_t length, VarType conv)
01058 {
01059 switch (_sl.action) {
01060 case SLA_SAVE: {
01061 size_t len;
01062 switch (GetVarMemType(conv)) {
01063 default: NOT_REACHED();
01064 case SLE_VAR_STRB:
01065 case SLE_VAR_STRBQ:
01066 len = SlCalcNetStringLen((char *)ptr, length);
01067 break;
01068 case SLE_VAR_STR:
01069 case SLE_VAR_STRQ:
01070 ptr = *(char **)ptr;
01071 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01072 break;
01073 }
01074
01075 SlWriteArrayLength(len);
01076 SlCopyBytes(ptr, len);
01077 break;
01078 }
01079 case SLA_LOAD_CHECK:
01080 case SLA_LOAD: {
01081 size_t len = SlReadArrayLength();
01082
01083 switch (GetVarMemType(conv)) {
01084 default: NOT_REACHED();
01085 case SLE_VAR_STRB:
01086 case SLE_VAR_STRBQ:
01087 if (len >= length) {
01088 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01089 SlCopyBytes(ptr, length);
01090 SlSkipBytes(len - length);
01091 len = length - 1;
01092 } else {
01093 SlCopyBytes(ptr, len);
01094 }
01095 break;
01096 case SLE_VAR_STR:
01097 case SLE_VAR_STRQ:
01098 free(*(char **)ptr);
01099 if (len == 0) {
01100 *(char **)ptr = NULL;
01101 return;
01102 } else {
01103 *(char **)ptr = MallocT<char>(len + 1);
01104 ptr = *(char **)ptr;
01105 SlCopyBytes(ptr, len);
01106 }
01107 break;
01108 }
01109
01110 ((char *)ptr)[len] = '\0';
01111 StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
01112 if ((conv & SLF_ALLOW_CONTROL) != 0) {
01113 settings = settings | SVS_ALLOW_CONTROL_CODE;
01114 if (IsSavegameVersionBefore(169)) {
01115 str_fix_scc_encoded((char *)ptr, (char *)ptr + len);
01116 }
01117 }
01118 if ((conv & SLF_ALLOW_NEWLINE) != 0) {
01119 settings = settings | SVS_ALLOW_NEWLINE;
01120 }
01121 str_validate((char *)ptr, (char *)ptr + len, settings);
01122 break;
01123 }
01124 case SLA_PTRS: break;
01125 case SLA_NULL: break;
01126 default: NOT_REACHED();
01127 }
01128 }
01129
01135 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01136 {
01137 return SlCalcConvFileLen(conv) * length;
01138 }
01139
01146 void SlArray(void *array, size_t length, VarType conv)
01147 {
01148 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01149
01150
01151 if (_sl.need_length != NL_NONE) {
01152 SlSetLength(SlCalcArrayLen(length, conv));
01153
01154 if (_sl.need_length == NL_CALCLENGTH) return;
01155 }
01156
01157
01158
01159 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01160
01161 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01162 conv == SLE_INT32 || conv == SLE_UINT32) {
01163 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01164 return;
01165 }
01166
01167 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01168 for (uint i = 0; i < length; i++) {
01169 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01170 }
01171 return;
01172 }
01173 }
01174
01175
01176
01177 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01178 SlCopyBytes(array, length);
01179 } else {
01180 byte *a = (byte*)array;
01181 byte mem_size = SlCalcConvMemLen(conv);
01182
01183 for (; length != 0; length --) {
01184 SlSaveLoadConv(a, conv);
01185 a += mem_size;
01186 }
01187 }
01188 }
01189
01190
01201 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01202 {
01203 assert(_sl.action == SLA_SAVE);
01204
01205 if (obj == NULL) return 0;
01206
01207 switch (rt) {
01208 case REF_VEHICLE_OLD:
01209 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01210 case REF_STATION: return ((const Station*)obj)->index + 1;
01211 case REF_TOWN: return ((const Town*)obj)->index + 1;
01212 case REF_ORDER: return ((const Order*)obj)->index + 1;
01213 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01214 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01215 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01216 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01217 case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
01218 default: NOT_REACHED();
01219 }
01220 }
01221
01232 static void *IntToReference(size_t index, SLRefType rt)
01233 {
01234 assert_compile(sizeof(size_t) <= sizeof(void *));
01235
01236 assert(_sl.action == SLA_PTRS);
01237
01238
01239
01240 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01241 rt = REF_VEHICLE;
01242 }
01243
01244
01245 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01246
01247
01248
01249 if (rt != REF_VEHICLE_OLD) index--;
01250
01251 switch (rt) {
01252 case REF_ORDERLIST:
01253 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01254 SlErrorCorrupt("Referencing invalid OrderList");
01255
01256 case REF_ORDER:
01257 if (Order::IsValidID(index)) return Order::Get(index);
01258
01259 if (IsSavegameVersionBefore(5, 2)) return NULL;
01260 SlErrorCorrupt("Referencing invalid Order");
01261
01262 case REF_VEHICLE_OLD:
01263 case REF_VEHICLE:
01264 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01265 SlErrorCorrupt("Referencing invalid Vehicle");
01266
01267 case REF_STATION:
01268 if (Station::IsValidID(index)) return Station::Get(index);
01269 SlErrorCorrupt("Referencing invalid Station");
01270
01271 case REF_TOWN:
01272 if (Town::IsValidID(index)) return Town::Get(index);
01273 SlErrorCorrupt("Referencing invalid Town");
01274
01275 case REF_ROADSTOPS:
01276 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01277 SlErrorCorrupt("Referencing invalid RoadStop");
01278
01279 case REF_ENGINE_RENEWS:
01280 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01281 SlErrorCorrupt("Referencing invalid EngineRenew");
01282
01283 case REF_CARGO_PACKET:
01284 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01285 SlErrorCorrupt("Referencing invalid CargoPacket");
01286
01287 case REF_STORAGE:
01288 if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index);
01289 SlErrorCorrupt("Referencing invalid PersistentStorage");
01290
01291 default: NOT_REACHED();
01292 }
01293 }
01294
01299 static inline size_t SlCalcListLen(const void *list)
01300 {
01301 const std::list<void *> *l = (const std::list<void *> *) list;
01302
01303 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01304
01305
01306 return l->size() * type_size + type_size;
01307 }
01308
01309
01315 static void SlList(void *list, SLRefType conv)
01316 {
01317
01318 if (_sl.need_length != NL_NONE) {
01319 SlSetLength(SlCalcListLen(list));
01320
01321 if (_sl.need_length == NL_CALCLENGTH) return;
01322 }
01323
01324 typedef std::list<void *> PtrList;
01325 PtrList *l = (PtrList *)list;
01326
01327 switch (_sl.action) {
01328 case SLA_SAVE: {
01329 SlWriteUint32((uint32)l->size());
01330
01331 PtrList::iterator iter;
01332 for (iter = l->begin(); iter != l->end(); ++iter) {
01333 void *ptr = *iter;
01334 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01335 }
01336 break;
01337 }
01338 case SLA_LOAD_CHECK:
01339 case SLA_LOAD: {
01340 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01341
01342
01343 for (size_t i = 0; i < length; i++) {
01344 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01345 l->push_back((void *)data);
01346 }
01347 break;
01348 }
01349 case SLA_PTRS: {
01350 PtrList temp = *l;
01351
01352 l->clear();
01353 PtrList::iterator iter;
01354 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01355 void *ptr = IntToReference((size_t)*iter, conv);
01356 l->push_back(ptr);
01357 }
01358 break;
01359 }
01360 case SLA_NULL:
01361 l->clear();
01362 break;
01363 default: NOT_REACHED();
01364 }
01365 }
01366
01367
01369 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01370 {
01371 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01372 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01373
01374 return true;
01375 }
01376
01382 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01383 {
01384 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01385 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01386 return true;
01387 }
01388
01389 return false;
01390 }
01391
01398 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01399 {
01400 size_t length = 0;
01401
01402
01403 for (; sld->cmd != SL_END; sld++) {
01404 length += SlCalcObjMemberLength(object, sld);
01405 }
01406 return length;
01407 }
01408
01409 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01410 {
01411 assert(_sl.action == SLA_SAVE);
01412
01413 switch (sld->cmd) {
01414 case SL_VAR:
01415 case SL_REF:
01416 case SL_ARR:
01417 case SL_STR:
01418 case SL_LST:
01419
01420 if (!SlIsObjectValidInSavegame(sld)) break;
01421
01422 switch (sld->cmd) {
01423 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01424 case SL_REF: return SlCalcRefLen();
01425 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01426 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01427 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01428 default: NOT_REACHED();
01429 }
01430 break;
01431 case SL_WRITEBYTE: return 1;
01432 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01433 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01434 default: NOT_REACHED();
01435 }
01436 return 0;
01437 }
01438
01439
01440 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01441 {
01442 VarType conv = GB(sld->conv, 0, 8);
01443 switch (sld->cmd) {
01444 case SL_VAR:
01445 case SL_REF:
01446 case SL_ARR:
01447 case SL_STR:
01448 case SL_LST:
01449
01450 if (!SlIsObjectValidInSavegame(sld)) return false;
01451 if (SlSkipVariableOnLoad(sld)) return false;
01452
01453 switch (sld->cmd) {
01454 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01455 case SL_REF:
01456 switch (_sl.action) {
01457 case SLA_SAVE:
01458 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01459 break;
01460 case SLA_LOAD_CHECK:
01461 case SLA_LOAD:
01462 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01463 break;
01464 case SLA_PTRS:
01465 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01466 break;
01467 case SLA_NULL:
01468 *(void **)ptr = NULL;
01469 break;
01470 default: NOT_REACHED();
01471 }
01472 break;
01473 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01474 case SL_STR: SlString(ptr, sld->length, sld->conv); break;
01475 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01476 default: NOT_REACHED();
01477 }
01478 break;
01479
01480
01481
01482
01483
01484
01485 case SL_WRITEBYTE:
01486 switch (_sl.action) {
01487 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01488 case SLA_LOAD_CHECK:
01489 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01490 case SLA_PTRS: break;
01491 case SLA_NULL: break;
01492 default: NOT_REACHED();
01493 }
01494 break;
01495
01496
01497 case SL_VEH_INCLUDE:
01498 SlObject(ptr, GetVehicleDescription(VEH_END));
01499 break;
01500
01501 case SL_ST_INCLUDE:
01502 SlObject(ptr, GetBaseStationDescription());
01503 break;
01504
01505 default: NOT_REACHED();
01506 }
01507 return true;
01508 }
01509
01515 void SlObject(void *object, const SaveLoad *sld)
01516 {
01517
01518 if (_sl.need_length != NL_NONE) {
01519 SlSetLength(SlCalcObjLength(object, sld));
01520 if (_sl.need_length == NL_CALCLENGTH) return;
01521 }
01522
01523 for (; sld->cmd != SL_END; sld++) {
01524 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01525 SlObjectMember(ptr, sld);
01526 }
01527 }
01528
01533 void SlGlobList(const SaveLoadGlobVarList *sldg)
01534 {
01535 SlObject(NULL, (const SaveLoad*)sldg);
01536 }
01537
01543 void SlAutolength(AutolengthProc *proc, void *arg)
01544 {
01545 size_t offs;
01546
01547 assert(_sl.action == SLA_SAVE);
01548
01549
01550 _sl.need_length = NL_CALCLENGTH;
01551 _sl.obj_len = 0;
01552 proc(arg);
01553
01554
01555 _sl.need_length = NL_WANTLENGTH;
01556 SlSetLength(_sl.obj_len);
01557
01558 offs = _sl.dumper->GetSize() + _sl.obj_len;
01559
01560
01561 proc(arg);
01562
01563 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01564 }
01565
01570 static void SlLoadChunk(const ChunkHandler *ch)
01571 {
01572 byte m = SlReadByte();
01573 size_t len;
01574 size_t endoffs;
01575
01576 _sl.block_mode = m;
01577 _sl.obj_len = 0;
01578
01579 switch (m) {
01580 case CH_ARRAY:
01581 _sl.array_index = 0;
01582 ch->load_proc();
01583 break;
01584 case CH_SPARSE_ARRAY:
01585 ch->load_proc();
01586 break;
01587 default:
01588 if ((m & 0xF) == CH_RIFF) {
01589
01590 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01591 len += SlReadUint16();
01592 _sl.obj_len = len;
01593 endoffs = _sl.reader->GetSize() + len;
01594 ch->load_proc();
01595 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01596 } else {
01597 SlErrorCorrupt("Invalid chunk type");
01598 }
01599 break;
01600 }
01601 }
01602
01608 static void SlLoadCheckChunk(const ChunkHandler *ch)
01609 {
01610 byte m = SlReadByte();
01611 size_t len;
01612 size_t endoffs;
01613
01614 _sl.block_mode = m;
01615 _sl.obj_len = 0;
01616
01617 switch (m) {
01618 case CH_ARRAY:
01619 _sl.array_index = 0;
01620 if (ch->load_check_proc) {
01621 ch->load_check_proc();
01622 } else {
01623 SlSkipArray();
01624 }
01625 break;
01626 case CH_SPARSE_ARRAY:
01627 if (ch->load_check_proc) {
01628 ch->load_check_proc();
01629 } else {
01630 SlSkipArray();
01631 }
01632 break;
01633 default:
01634 if ((m & 0xF) == CH_RIFF) {
01635
01636 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01637 len += SlReadUint16();
01638 _sl.obj_len = len;
01639 endoffs = _sl.reader->GetSize() + len;
01640 if (ch->load_check_proc) {
01641 ch->load_check_proc();
01642 } else {
01643 SlSkipBytes(len);
01644 }
01645 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01646 } else {
01647 SlErrorCorrupt("Invalid chunk type");
01648 }
01649 break;
01650 }
01651 }
01652
01657 static ChunkSaveLoadProc *_stub_save_proc;
01658
01664 static inline void SlStubSaveProc2(void *arg)
01665 {
01666 _stub_save_proc();
01667 }
01668
01674 static void SlStubSaveProc()
01675 {
01676 SlAutolength(SlStubSaveProc2, NULL);
01677 }
01678
01684 static void SlSaveChunk(const ChunkHandler *ch)
01685 {
01686 ChunkSaveLoadProc *proc = ch->save_proc;
01687
01688
01689 if (proc == NULL) return;
01690
01691 SlWriteUint32(ch->id);
01692 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01693
01694 if (ch->flags & CH_AUTO_LENGTH) {
01695
01696 _stub_save_proc = proc;
01697 proc = SlStubSaveProc;
01698 }
01699
01700 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01701 switch (ch->flags & CH_TYPE_MASK) {
01702 case CH_RIFF:
01703 _sl.need_length = NL_WANTLENGTH;
01704 proc();
01705 break;
01706 case CH_ARRAY:
01707 _sl.last_array_index = 0;
01708 SlWriteByte(CH_ARRAY);
01709 proc();
01710 SlWriteArrayLength(0);
01711 break;
01712 case CH_SPARSE_ARRAY:
01713 SlWriteByte(CH_SPARSE_ARRAY);
01714 proc();
01715 SlWriteArrayLength(0);
01716 break;
01717 default: NOT_REACHED();
01718 }
01719 }
01720
01722 static void SlSaveChunks()
01723 {
01724 FOR_ALL_CHUNK_HANDLERS(ch) {
01725 SlSaveChunk(ch);
01726 }
01727
01728
01729 SlWriteUint32(0);
01730 }
01731
01738 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01739 {
01740 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01741 return NULL;
01742 }
01743
01745 static void SlLoadChunks()
01746 {
01747 uint32 id;
01748 const ChunkHandler *ch;
01749
01750 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01751 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01752
01753 ch = SlFindChunkHandler(id);
01754 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01755 SlLoadChunk(ch);
01756 }
01757 }
01758
01760 static void SlLoadCheckChunks()
01761 {
01762 uint32 id;
01763 const ChunkHandler *ch;
01764
01765 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01766 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01767
01768 ch = SlFindChunkHandler(id);
01769 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01770 SlLoadCheckChunk(ch);
01771 }
01772 }
01773
01775 static void SlFixPointers()
01776 {
01777 _sl.action = SLA_PTRS;
01778
01779 DEBUG(sl, 1, "Fixing pointers");
01780
01781 FOR_ALL_CHUNK_HANDLERS(ch) {
01782 if (ch->ptrs_proc != NULL) {
01783 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01784 ch->ptrs_proc();
01785 }
01786 }
01787
01788 DEBUG(sl, 1, "All pointers fixed");
01789
01790 assert(_sl.action == SLA_PTRS);
01791 }
01792
01793
01795 struct FileReader : LoadFilter {
01796 FILE *file;
01797 long begin;
01798
01803 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01804 {
01805 }
01806
01808 ~FileReader()
01809 {
01810 if (this->file != NULL) fclose(this->file);
01811 this->file = NULL;
01812
01813
01814 _sl.sf = NULL;
01815 }
01816
01817 size_t Read(byte *buf, size_t size)
01818 {
01819
01820 if (this->file == NULL) return 0;
01821
01822 return fread(buf, 1, size, this->file);
01823 }
01824
01825 void Reset()
01826 {
01827 clearerr(this->file);
01828 fseek(this->file, this->begin, SEEK_SET);
01829 }
01830 };
01831
01833 struct FileWriter : SaveFilter {
01834 FILE *file;
01835
01840 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01841 {
01842 }
01843
01845 ~FileWriter()
01846 {
01847 this->Finish();
01848
01849
01850 _sl.sf = NULL;
01851 }
01852
01853 void Write(byte *buf, size_t size)
01854 {
01855
01856 if (this->file == NULL) return;
01857
01858 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01859 }
01860
01861 void Finish()
01862 {
01863 if (this->file != NULL) fclose(this->file);
01864 this->file = NULL;
01865 }
01866 };
01867
01868
01869
01870
01871
01872 #ifdef WITH_LZO
01873 #include <lzo/lzo1x.h>
01874
01876 static const uint LZO_BUFFER_SIZE = 8192;
01877
01879 struct LZOLoadFilter : LoadFilter {
01884 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01885 {
01886 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01887 }
01888
01889 size_t Read(byte *buf, size_t ssize)
01890 {
01891 assert(ssize >= LZO_BUFFER_SIZE);
01892
01893
01894 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01895 uint32 tmp[2];
01896 uint32 size;
01897 lzo_uint len;
01898
01899
01900 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01901
01902
01903 ((uint32*)out)[0] = size = tmp[1];
01904
01905 if (_sl_version != 0) {
01906 tmp[0] = TO_BE32(tmp[0]);
01907 size = TO_BE32(size);
01908 }
01909
01910 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01911
01912
01913 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01914
01915
01916 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01917
01918
01919 lzo1x_decompress_safe(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01920 return len;
01921 }
01922 };
01923
01925 struct LZOSaveFilter : SaveFilter {
01931 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01932 {
01933 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01934 }
01935
01936 void Write(byte *buf, size_t size)
01937 {
01938 const lzo_bytep in = buf;
01939
01940 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01941 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01942 lzo_uint outlen;
01943
01944 do {
01945
01946 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01947 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01948 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01949 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01950 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01951
01952
01953 size -= len;
01954 in += len;
01955 } while (size > 0);
01956 }
01957 };
01958
01959 #endif
01960
01961
01962
01963
01964
01966 struct NoCompLoadFilter : LoadFilter {
01971 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01972 {
01973 }
01974
01975 size_t Read(byte *buf, size_t size)
01976 {
01977 return this->chain->Read(buf, size);
01978 }
01979 };
01980
01982 struct NoCompSaveFilter : SaveFilter {
01988 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01989 {
01990 }
01991
01992 void Write(byte *buf, size_t size)
01993 {
01994 this->chain->Write(buf, size);
01995 }
01996 };
01997
01998
01999
02000
02001
02002 #if defined(WITH_ZLIB)
02003 #include <zlib.h>
02004
02006 struct ZlibLoadFilter : LoadFilter {
02007 z_stream z;
02008 byte fread_buf[MEMORY_CHUNK_SIZE];
02009
02014 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
02015 {
02016 memset(&this->z, 0, sizeof(this->z));
02017 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02018 }
02019
02021 ~ZlibLoadFilter()
02022 {
02023 inflateEnd(&this->z);
02024 }
02025
02026 size_t Read(byte *buf, size_t size)
02027 {
02028 this->z.next_out = buf;
02029 this->z.avail_out = (uint)size;
02030
02031 do {
02032
02033 if (this->z.avail_in == 0) {
02034 this->z.next_in = this->fread_buf;
02035 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02036 }
02037
02038
02039 int r = inflate(&this->z, 0);
02040 if (r == Z_STREAM_END) break;
02041
02042 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02043 } while (this->z.avail_out != 0);
02044
02045 return size - this->z.avail_out;
02046 }
02047 };
02048
02050 struct ZlibSaveFilter : SaveFilter {
02051 z_stream z;
02052
02058 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02059 {
02060 memset(&this->z, 0, sizeof(this->z));
02061 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02062 }
02063
02065 ~ZlibSaveFilter()
02066 {
02067 deflateEnd(&this->z);
02068 }
02069
02076 void WriteLoop(byte *p, size_t len, int mode)
02077 {
02078 byte buf[MEMORY_CHUNK_SIZE];
02079 uint n;
02080 this->z.next_in = p;
02081 this->z.avail_in = (uInt)len;
02082 do {
02083 this->z.next_out = buf;
02084 this->z.avail_out = sizeof(buf);
02085
02093 int r = deflate(&this->z, mode);
02094
02095
02096 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02097 this->chain->Write(buf, n);
02098 }
02099 if (r == Z_STREAM_END) break;
02100
02101 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02102 } while (this->z.avail_in || !this->z.avail_out);
02103 }
02104
02105 void Write(byte *buf, size_t size)
02106 {
02107 this->WriteLoop(buf, size, 0);
02108 }
02109
02110 void Finish()
02111 {
02112 this->WriteLoop(NULL, 0, Z_FINISH);
02113 this->chain->Finish();
02114 }
02115 };
02116
02117 #endif
02118
02119
02120
02121
02122
02123 #if defined(WITH_LZMA)
02124 #include <lzma.h>
02125
02132 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02133
02135 struct LZMALoadFilter : LoadFilter {
02136 lzma_stream lzma;
02137 byte fread_buf[MEMORY_CHUNK_SIZE];
02138
02143 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02144 {
02145
02146 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02147 }
02148
02150 ~LZMALoadFilter()
02151 {
02152 lzma_end(&this->lzma);
02153 }
02154
02155 size_t Read(byte *buf, size_t size)
02156 {
02157 this->lzma.next_out = buf;
02158 this->lzma.avail_out = size;
02159
02160 do {
02161
02162 if (this->lzma.avail_in == 0) {
02163 this->lzma.next_in = this->fread_buf;
02164 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02165 }
02166
02167
02168 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02169 if (r == LZMA_STREAM_END) break;
02170 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02171 } while (this->lzma.avail_out != 0);
02172
02173 return size - this->lzma.avail_out;
02174 }
02175 };
02176
02178 struct LZMASaveFilter : SaveFilter {
02179 lzma_stream lzma;
02180
02186 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02187 {
02188 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02189 }
02190
02192 ~LZMASaveFilter()
02193 {
02194 lzma_end(&this->lzma);
02195 }
02196
02203 void WriteLoop(byte *p, size_t len, lzma_action action)
02204 {
02205 byte buf[MEMORY_CHUNK_SIZE];
02206 size_t n;
02207 this->lzma.next_in = p;
02208 this->lzma.avail_in = len;
02209 do {
02210 this->lzma.next_out = buf;
02211 this->lzma.avail_out = sizeof(buf);
02212
02213 lzma_ret r = lzma_code(&this->lzma, action);
02214
02215
02216 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02217 this->chain->Write(buf, n);
02218 }
02219 if (r == LZMA_STREAM_END) break;
02220 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02221 } while (this->lzma.avail_in || !this->lzma.avail_out);
02222 }
02223
02224 void Write(byte *buf, size_t size)
02225 {
02226 this->WriteLoop(buf, size, LZMA_RUN);
02227 }
02228
02229 void Finish()
02230 {
02231 this->WriteLoop(NULL, 0, LZMA_FINISH);
02232 this->chain->Finish();
02233 }
02234 };
02235
02236 #endif
02237
02238
02239
02240
02241
02243 struct SaveLoadFormat {
02244 const char *name;
02245 uint32 tag;
02246
02247 LoadFilter *(*init_load)(LoadFilter *chain);
02248 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02249
02250 byte min_compression;
02251 byte default_compression;
02252 byte max_compression;
02253 };
02254
02256 static const SaveLoadFormat _saveload_formats[] = {
02257 #if defined(WITH_LZO)
02258
02259 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02260 #else
02261 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02262 #endif
02263
02264 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02265 #if defined(WITH_ZLIB)
02266
02267
02268
02269 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02270 #else
02271 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02272 #endif
02273 #if defined(WITH_LZMA)
02274
02275
02276
02277
02278
02279 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02280 #else
02281 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02282 #endif
02283 };
02284
02292 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02293 {
02294 const SaveLoadFormat *def = lastof(_saveload_formats);
02295
02296
02297 while (!def->init_write) def--;
02298
02299 if (!StrEmpty(s)) {
02300
02301 char *complevel = strrchr(s, ':');
02302 if (complevel != NULL) *complevel = '\0';
02303
02304 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02305 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02306 *compression_level = slf->default_compression;
02307 if (complevel != NULL) {
02308
02309
02310
02311 *complevel = ':';
02312 complevel++;
02313
02314
02315 char *end;
02316 long level = strtol(complevel, &end, 10);
02317 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02318 SetDParamStr(0, complevel);
02319 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL);
02320 } else {
02321 *compression_level = level;
02322 }
02323 }
02324 return slf;
02325 }
02326 }
02327
02328 SetDParamStr(0, s);
02329 SetDParamStr(1, def->name);
02330 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL);
02331
02332
02333 if (complevel != NULL) *complevel = ':';
02334 }
02335 *compression_level = def->default_compression;
02336 return def;
02337 }
02338
02339
02340 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02341 extern bool AfterLoadGame();
02342 extern bool LoadOldSaveGame(const char *file);
02343
02347 static inline void ClearSaveLoadState()
02348 {
02349 delete _sl.dumper;
02350 _sl.dumper = NULL;
02351
02352 delete _sl.sf;
02353 _sl.sf = NULL;
02354
02355 delete _sl.reader;
02356 _sl.reader = NULL;
02357
02358 delete _sl.lf;
02359 _sl.lf = NULL;
02360 }
02361
02367 static void SaveFileStart()
02368 {
02369 _sl.ff_state = _fast_forward;
02370 _fast_forward = 0;
02371 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02372
02373 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02374 _sl.saveinprogress = true;
02375 }
02376
02378 static void SaveFileDone()
02379 {
02380 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02381 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02382
02383 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02384 _sl.saveinprogress = false;
02385 }
02386
02388 void SetSaveLoadError(StringID str)
02389 {
02390 _sl.error_str = str;
02391 }
02392
02394 const char *GetSaveLoadErrorString()
02395 {
02396 SetDParam(0, _sl.error_str);
02397 SetDParamStr(1, _sl.extra_msg);
02398
02399 static char err_str[512];
02400 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02401 return err_str;
02402 }
02403
02405 static void SaveFileError()
02406 {
02407 SetDParamStr(0, GetSaveLoadErrorString());
02408 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02409 SaveFileDone();
02410 }
02411
02416 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02417 {
02418 try {
02419 byte compression;
02420 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02421
02422
02423 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02424 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02425
02426 _sl.sf = fmt->init_write(_sl.sf, compression);
02427 _sl.dumper->Flush(_sl.sf);
02428
02429 ClearSaveLoadState();
02430
02431 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02432
02433 return SL_OK;
02434 } catch (...) {
02435 ClearSaveLoadState();
02436
02437 AsyncSaveFinishProc asfp = SaveFileDone;
02438
02439
02440
02441 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02442
02443 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02444 asfp = SaveFileError;
02445 }
02446
02447 if (threaded) {
02448 SetAsyncSaveFinish(asfp);
02449 } else {
02450 asfp();
02451 }
02452 return SL_ERROR;
02453 }
02454 }
02455
02457 static void SaveFileToDiskThread(void *arg)
02458 {
02459 SaveFileToDisk(true);
02460 }
02461
02462 void WaitTillSaved()
02463 {
02464 if (_save_thread == NULL) return;
02465
02466 _save_thread->Join();
02467 delete _save_thread;
02468 _save_thread = NULL;
02469
02470
02471 ProcessAsyncSaveFinish();
02472 }
02473
02482 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02483 {
02484 assert(!_sl.saveinprogress);
02485
02486 _sl.dumper = new MemoryDumper();
02487 _sl.sf = writer;
02488
02489 _sl_version = SAVEGAME_VERSION;
02490
02491 SaveViewportBeforeSaveGame();
02492 SlSaveChunks();
02493
02494 SaveFileStart();
02495 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02496 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02497
02498 SaveOrLoadResult result = SaveFileToDisk(false);
02499 SaveFileDone();
02500
02501 return result;
02502 }
02503
02504 return SL_OK;
02505 }
02506
02513 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02514 {
02515 try {
02516 _sl.action = SLA_SAVE;
02517 return DoSave(writer, threaded);
02518 } catch (...) {
02519 ClearSaveLoadState();
02520 return SL_ERROR;
02521 }
02522 }
02523
02530 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02531 {
02532 _sl.lf = reader;
02533
02534 if (load_check) {
02535
02536 _load_check_data.Clear();
02537
02538 _load_check_data.checkable = true;
02539 }
02540
02541 uint32 hdr[2];
02542 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02543
02544
02545 const SaveLoadFormat *fmt = _saveload_formats;
02546 for (;;) {
02547
02548 if (fmt == endof(_saveload_formats)) {
02549 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02550 _sl.lf->Reset();
02551 _sl_version = 0;
02552 _sl_minor_version = 0;
02553
02554
02555 fmt = _saveload_formats;
02556 for (;;) {
02557 if (fmt == endof(_saveload_formats)) {
02558
02559 NOT_REACHED();
02560 }
02561 if (fmt->tag == TO_BE32X('OTTD')) break;
02562 fmt++;
02563 }
02564 break;
02565 }
02566
02567 if (fmt->tag == hdr[0]) {
02568
02569 _sl_version = TO_BE32(hdr[1]) >> 16;
02570
02571
02572
02573 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02574
02575 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02576
02577
02578 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02579 break;
02580 }
02581
02582 fmt++;
02583 }
02584
02585
02586 if (fmt->init_load == NULL) {
02587 char err_str[64];
02588 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02589 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02590 }
02591
02592 _sl.lf = fmt->init_load(_sl.lf);
02593 _sl.reader = new ReadBuffer(_sl.lf);
02594 _next_offs = 0;
02595
02596 if (!load_check) {
02597
02598
02599
02600 InitializeGame(256, 256, true, true);
02601
02602 GamelogReset();
02603
02604 if (IsSavegameVersionBefore(4)) {
02605
02606
02607
02608
02609
02610
02611
02612
02613
02614
02615
02616
02617
02618
02619
02620
02621
02622
02623
02624
02625
02626 ClearGRFConfigList(&_grfconfig);
02627 }
02628 }
02629
02630 if (load_check) {
02631
02632
02633 SlLoadCheckChunks();
02634 } else {
02635
02636 SlLoadChunks();
02637 SlFixPointers();
02638 }
02639
02640 ClearSaveLoadState();
02641
02642 _savegame_type = SGT_OTTD;
02643
02644 if (load_check) {
02645
02646 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02647 } else {
02648 GamelogStartAction(GLAT_LOAD);
02649
02650
02651
02652 if (!AfterLoadGame()) {
02653 GamelogStopAction();
02654 return SL_REINIT;
02655 }
02656
02657 GamelogStopAction();
02658 }
02659
02660 return SL_OK;
02661 }
02662
02668 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02669 {
02670 try {
02671 _sl.action = SLA_LOAD;
02672 return DoLoad(reader, false);
02673 } catch (...) {
02674 ClearSaveLoadState();
02675 return SL_REINIT;
02676 }
02677 }
02678
02688 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02689 {
02690
02691 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02692
02693 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02694 return SL_OK;
02695 }
02696 WaitTillSaved();
02697
02698
02699 if (mode == SL_OLD_LOAD) {
02700 InitializeGame(256, 256, true, true);
02701
02702
02703
02704
02705
02706 ClearGRFConfigList(&_grfconfig);
02707 GamelogReset();
02708 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02709 _sl_version = 0;
02710 _sl_minor_version = 0;
02711 GamelogStartAction(GLAT_LOAD);
02712 if (!AfterLoadGame()) {
02713 GamelogStopAction();
02714 return SL_REINIT;
02715 }
02716 GamelogStopAction();
02717 return SL_OK;
02718 }
02719
02720 switch (mode) {
02721 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02722 case SL_LOAD: _sl.action = SLA_LOAD; break;
02723 case SL_SAVE: _sl.action = SLA_SAVE; break;
02724 default: NOT_REACHED();
02725 }
02726
02727 try {
02728 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02729
02730
02731 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02732 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02733 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
02734
02735 if (fh == NULL) {
02736 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02737 }
02738
02739 if (mode == SL_SAVE) {
02740 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02741 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02742
02743 return DoSave(new FileWriter(fh), threaded);
02744 }
02745
02746
02747 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02748 DEBUG(desync, 1, "load: %s", filename);
02749 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02750 } catch (...) {
02751 ClearSaveLoadState();
02752
02753
02754 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02755
02756
02757 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02758 }
02759 }
02760
02762 void DoExitSave()
02763 {
02764 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02765 }
02766
02772 void GenerateDefaultSaveName(char *buf, const char *last)
02773 {
02774
02775
02776
02777 CompanyID cid = _local_company;
02778 if (!Company::IsValidID(cid)) {
02779 const Company *c;
02780 FOR_ALL_COMPANIES(c) {
02781 cid = c->index;
02782 break;
02783 }
02784 }
02785
02786 SetDParam(0, cid);
02787
02788
02789 switch (_settings_client.gui.date_format_in_default_names) {
02790 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02791 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02792 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02793 default: NOT_REACHED();
02794 }
02795 SetDParam(2, _date);
02796
02797
02798 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02799 SanitizeFilename(buf);
02800 }
02801
02802 #if 0
02803
02809 int GetSavegameType(char *file)
02810 {
02811 const SaveLoadFormat *fmt;
02812 uint32 hdr;
02813 FILE *f;
02814 int mode = SL_OLD_LOAD;
02815
02816 f = fopen(file, "rb");
02817 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02818 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02819 mode = SL_LOAD;
02820 } else {
02821
02822 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02823 if (fmt->tag == hdr) {
02824 mode = SL_LOAD;
02825 break;
02826 }
02827 }
02828 }
02829
02830 fclose(f);
02831 return mode;
02832 }
02833 #endif