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