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 extern const uint16 SAVEGAME_VERSION = SL_EXT_RATING;
00238
00239 SavegameType _savegame_type;
00240
00241 uint32 _ttdp_version;
00242 uint16 _sl_version;
00243 byte _sl_minor_version;
00244 char _savegame_format[8];
00245 bool _do_autosave;
00246
00248 enum SaveLoadAction {
00249 SLA_LOAD,
00250 SLA_SAVE,
00251 SLA_PTRS,
00252 SLA_NULL,
00253 SLA_LOAD_CHECK,
00254 };
00255
00256 enum NeedLength {
00257 NL_NONE = 0,
00258 NL_WANTLENGTH = 1,
00259 NL_CALCLENGTH = 2,
00260 };
00261
00263 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
00264
00266 struct ReadBuffer {
00267 byte buf[MEMORY_CHUNK_SIZE];
00268 byte *bufp;
00269 byte *bufe;
00270 LoadFilter *reader;
00271 size_t read;
00272
00277 ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
00278 {
00279 }
00280
00281 inline byte ReadByte()
00282 {
00283 if (this->bufp == this->bufe) {
00284 size_t len = this->reader->Read(this->buf, lengthof(this->buf));
00285 if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00286
00287 this->read += len;
00288 this->bufp = this->buf;
00289 this->bufe = this->buf + len;
00290 }
00291
00292 return *this->bufp++;
00293 }
00294
00299 size_t GetSize() const
00300 {
00301 return this->read - (this->bufe - this->bufp);
00302 }
00303 };
00304
00305
00307 struct MemoryDumper {
00308 AutoFreeSmallVector<byte *, 16> blocks;
00309 byte *buf;
00310 byte *bufe;
00311
00313 MemoryDumper() : buf(NULL), bufe(NULL)
00314 {
00315 }
00316
00321 inline void WriteByte(byte b)
00322 {
00323
00324 if (this->buf == this->bufe) {
00325 this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
00326 *this->blocks.Append() = this->buf;
00327 this->bufe = this->buf + MEMORY_CHUNK_SIZE;
00328 }
00329
00330 *this->buf++ = b;
00331 }
00332
00337 void Flush(SaveFilter *writer)
00338 {
00339 uint i = 0;
00340 size_t t = this->GetSize();
00341
00342 while (t > 0) {
00343 size_t to_write = min(MEMORY_CHUNK_SIZE, t);
00344
00345 writer->Write(this->blocks[i++], to_write);
00346 t -= to_write;
00347 }
00348
00349 writer->Finish();
00350 }
00351
00356 size_t GetSize() const
00357 {
00358 return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
00359 }
00360 };
00361
00363 struct SaveLoadParams {
00364 SaveLoadAction action;
00365 NeedLength need_length;
00366 byte block_mode;
00367 bool error;
00368
00369 size_t obj_len;
00370 int array_index, last_array_index;
00371
00372 MemoryDumper *dumper;
00373 SaveFilter *sf;
00374
00375 ReadBuffer *reader;
00376 LoadFilter *lf;
00377
00378 StringID error_str;
00379 char *extra_msg;
00380
00381 byte ff_state;
00382 bool saveinprogress;
00383 };
00384
00385 static SaveLoadParams _sl;
00386
00387
00388 extern const ChunkHandler _gamelog_chunk_handlers[];
00389 extern const ChunkHandler _map_chunk_handlers[];
00390 extern const ChunkHandler _misc_chunk_handlers[];
00391 extern const ChunkHandler _name_chunk_handlers[];
00392 extern const ChunkHandler _cheat_chunk_handlers[] ;
00393 extern const ChunkHandler _setting_chunk_handlers[];
00394 extern const ChunkHandler _company_chunk_handlers[];
00395 extern const ChunkHandler _engine_chunk_handlers[];
00396 extern const ChunkHandler _veh_chunk_handlers[];
00397 extern const ChunkHandler _waypoint_chunk_handlers[];
00398 extern const ChunkHandler _depot_chunk_handlers[];
00399 extern const ChunkHandler _order_chunk_handlers[];
00400 extern const ChunkHandler _town_chunk_handlers[];
00401 extern const ChunkHandler _sign_chunk_handlers[];
00402 extern const ChunkHandler _station_chunk_handlers[];
00403 extern const ChunkHandler _industry_chunk_handlers[];
00404 extern const ChunkHandler _economy_chunk_handlers[];
00405 extern const ChunkHandler _subsidy_chunk_handlers[];
00406 extern const ChunkHandler _goal_chunk_handlers[];
00407 extern const ChunkHandler _ai_chunk_handlers[];
00408 extern const ChunkHandler _game_chunk_handlers[];
00409 extern const ChunkHandler _animated_tile_chunk_handlers[];
00410 extern const ChunkHandler _newgrf_chunk_handlers[];
00411 extern const ChunkHandler _group_chunk_handlers[];
00412 extern const ChunkHandler _cargopacket_chunk_handlers[];
00413 extern const ChunkHandler _autoreplace_chunk_handlers[];
00414 extern const ChunkHandler _labelmaps_chunk_handlers[];
00415 extern const ChunkHandler _linkgraph_chunk_handlers[];
00416 extern const ChunkHandler _airport_chunk_handlers[];
00417 extern const ChunkHandler _object_chunk_handlers[];
00418 extern const ChunkHandler _persistent_storage_chunk_handlers[];
00419
00421 static const ChunkHandler * const _chunk_handlers[] = {
00422 _gamelog_chunk_handlers,
00423 _map_chunk_handlers,
00424 _misc_chunk_handlers,
00425 _name_chunk_handlers,
00426 _cheat_chunk_handlers,
00427 _setting_chunk_handlers,
00428 _veh_chunk_handlers,
00429 _waypoint_chunk_handlers,
00430 _depot_chunk_handlers,
00431 _order_chunk_handlers,
00432 _industry_chunk_handlers,
00433 _economy_chunk_handlers,
00434 _subsidy_chunk_handlers,
00435 _goal_chunk_handlers,
00436 _engine_chunk_handlers,
00437 _town_chunk_handlers,
00438 _sign_chunk_handlers,
00439 _station_chunk_handlers,
00440 _company_chunk_handlers,
00441 _ai_chunk_handlers,
00442 _game_chunk_handlers,
00443 _animated_tile_chunk_handlers,
00444 _newgrf_chunk_handlers,
00445 _group_chunk_handlers,
00446 _cargopacket_chunk_handlers,
00447 _autoreplace_chunk_handlers,
00448 _labelmaps_chunk_handlers,
00449 _linkgraph_chunk_handlers,
00450 _airport_chunk_handlers,
00451 _object_chunk_handlers,
00452 _persistent_storage_chunk_handlers,
00453 NULL,
00454 };
00455
00460 #define FOR_ALL_CHUNK_HANDLERS(ch) \
00461 for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \
00462 for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1)
00463
00465 static void SlNullPointers()
00466 {
00467 _sl.action = SLA_NULL;
00468
00469
00470
00471
00472 _sl_version = SAVEGAME_VERSION;
00473
00474 DEBUG(sl, 1, "Nulling pointers");
00475
00476 FOR_ALL_CHUNK_HANDLERS(ch) {
00477 if (ch->ptrs_proc != NULL) {
00478 DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00479 ch->ptrs_proc();
00480 }
00481 }
00482
00483 DEBUG(sl, 1, "All pointers nulled");
00484
00485 assert(_sl.action == SLA_NULL);
00486 }
00487
00496 void NORETURN SlError(StringID string, const char *extra_msg)
00497 {
00498
00499 if (_sl.action == SLA_LOAD_CHECK) {
00500 _load_check_data.error = string;
00501 free(_load_check_data.error_data);
00502 _load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00503 } else {
00504 _sl.error_str = string;
00505 free(_sl.extra_msg);
00506 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00507 }
00508
00509
00510
00511
00512
00513 if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00514 throw std::exception();
00515 }
00516
00524 void NORETURN SlErrorCorrupt(const char *msg)
00525 {
00526 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00527 }
00528
00529
00530 typedef void (*AsyncSaveFinishProc)();
00531 static AsyncSaveFinishProc _async_save_finish = NULL;
00532 static ThreadObject *_save_thread;
00533
00538 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00539 {
00540 if (_exit_game) return;
00541 while (_async_save_finish != NULL) CSleep(10);
00542
00543 _async_save_finish = proc;
00544 }
00545
00549 void ProcessAsyncSaveFinish()
00550 {
00551 if (_async_save_finish == NULL) return;
00552
00553 _async_save_finish();
00554
00555 _async_save_finish = NULL;
00556
00557 if (_save_thread != NULL) {
00558 _save_thread->Join();
00559 delete _save_thread;
00560 _save_thread = NULL;
00561 }
00562 }
00563
00568 byte SlReadByte()
00569 {
00570 return _sl.reader->ReadByte();
00571 }
00572
00577 void SlWriteByte(byte b)
00578 {
00579 _sl.dumper->WriteByte(b);
00580 }
00581
00582 static inline int SlReadUint16()
00583 {
00584 int x = SlReadByte() << 8;
00585 return x | SlReadByte();
00586 }
00587
00588 static inline uint32 SlReadUint32()
00589 {
00590 uint32 x = SlReadUint16() << 16;
00591 return x | SlReadUint16();
00592 }
00593
00594 static inline uint64 SlReadUint64()
00595 {
00596 uint32 x = SlReadUint32();
00597 uint32 y = SlReadUint32();
00598 return (uint64)x << 32 | y;
00599 }
00600
00601 static inline void SlWriteUint16(uint16 v)
00602 {
00603 SlWriteByte(GB(v, 8, 8));
00604 SlWriteByte(GB(v, 0, 8));
00605 }
00606
00607 static inline void SlWriteUint32(uint32 v)
00608 {
00609 SlWriteUint16(GB(v, 16, 16));
00610 SlWriteUint16(GB(v, 0, 16));
00611 }
00612
00613 static inline void SlWriteUint64(uint64 x)
00614 {
00615 SlWriteUint32((uint32)(x >> 32));
00616 SlWriteUint32((uint32)x);
00617 }
00618
00624 static inline void SlSkipBytes(size_t length)
00625 {
00626 for (; length != 0; length--) SlReadByte();
00627 }
00628
00638 static uint SlReadSimpleGamma()
00639 {
00640 uint i = SlReadByte();
00641 if (HasBit(i, 7)) {
00642 i &= ~0x80;
00643 if (HasBit(i, 6)) {
00644 i &= ~0x40;
00645 if (HasBit(i, 5)) {
00646 i &= ~0x20;
00647 if (HasBit(i, 4)) {
00648 SlErrorCorrupt("Unsupported gamma");
00649 }
00650 i = (i << 8) | SlReadByte();
00651 }
00652 i = (i << 8) | SlReadByte();
00653 }
00654 i = (i << 8) | SlReadByte();
00655 }
00656 return i;
00657 }
00658
00671 static void SlWriteSimpleGamma(size_t i)
00672 {
00673 if (i >= (1 << 7)) {
00674 if (i >= (1 << 14)) {
00675 if (i >= (1 << 21)) {
00676 assert(i < (1 << 28));
00677 SlWriteByte((byte)(0xE0 | (i >> 24)));
00678 SlWriteByte((byte)(i >> 16));
00679 } else {
00680 SlWriteByte((byte)(0xC0 | (i >> 16)));
00681 }
00682 SlWriteByte((byte)(i >> 8));
00683 } else {
00684 SlWriteByte((byte)(0x80 | (i >> 8)));
00685 }
00686 }
00687 SlWriteByte((byte)i);
00688 }
00689
00691 static inline uint SlGetGammaLength(size_t i)
00692 {
00693 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00694 }
00695
00696 static inline uint SlReadSparseIndex()
00697 {
00698 return SlReadSimpleGamma();
00699 }
00700
00701 static inline void SlWriteSparseIndex(uint index)
00702 {
00703 SlWriteSimpleGamma(index);
00704 }
00705
00706 static inline uint SlReadArrayLength()
00707 {
00708 return SlReadSimpleGamma();
00709 }
00710
00711 static inline void SlWriteArrayLength(size_t length)
00712 {
00713 SlWriteSimpleGamma(length);
00714 }
00715
00716 static inline uint SlGetArrayLength(size_t length)
00717 {
00718 return SlGetGammaLength(length);
00719 }
00720
00727 static inline uint SlCalcConvMemLen(VarType conv)
00728 {
00729 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00730 byte length = GB(conv, 4, 4);
00731
00732 switch (length << 4) {
00733 case SLE_VAR_STRB:
00734 case SLE_VAR_STRBQ:
00735 case SLE_VAR_STR:
00736 case SLE_VAR_STRQ:
00737 return SlReadArrayLength();
00738
00739 default:
00740 assert(length < lengthof(conv_mem_size));
00741 return conv_mem_size[length];
00742 }
00743 }
00744
00751 static inline byte SlCalcConvFileLen(VarType conv)
00752 {
00753 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00754 byte length = GB(conv, 0, 4);
00755 assert(length < lengthof(conv_file_size));
00756 return conv_file_size[length];
00757 }
00758
00760 static inline size_t SlCalcRefLen()
00761 {
00762 return IsSavegameVersionBefore(69) ? 2 : 4;
00763 }
00764
00765 void SlSetArrayIndex(uint index)
00766 {
00767 _sl.need_length = NL_WANTLENGTH;
00768 _sl.array_index = index;
00769 }
00770
00771 static size_t _next_offs;
00772
00777 int SlIterateArray()
00778 {
00779 int index;
00780
00781
00782
00783 if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00784
00785 for (;;) {
00786 uint length = SlReadArrayLength();
00787 if (length == 0) {
00788 _next_offs = 0;
00789 return -1;
00790 }
00791
00792 _sl.obj_len = --length;
00793 _next_offs = _sl.reader->GetSize() + length;
00794
00795 switch (_sl.block_mode) {
00796 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00797 case CH_ARRAY: index = _sl.array_index++; break;
00798 default:
00799 DEBUG(sl, 0, "SlIterateArray error");
00800 return -1;
00801 }
00802
00803 if (length != 0) return index;
00804 }
00805 }
00806
00810 void SlSkipArray()
00811 {
00812 while (SlIterateArray() != -1) {
00813 SlSkipBytes(_next_offs - _sl.reader->GetSize());
00814 }
00815 }
00816
00822 void SlSetLength(size_t length)
00823 {
00824 assert(_sl.action == SLA_SAVE);
00825
00826 switch (_sl.need_length) {
00827 case NL_WANTLENGTH:
00828 _sl.need_length = NL_NONE;
00829 switch (_sl.block_mode) {
00830 case CH_RIFF:
00831
00832
00833
00834 assert(length < (1 << 28));
00835 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00836 break;
00837 case CH_ARRAY:
00838 assert(_sl.last_array_index <= _sl.array_index);
00839 while (++_sl.last_array_index <= _sl.array_index) {
00840 SlWriteArrayLength(1);
00841 }
00842 SlWriteArrayLength(length + 1);
00843 break;
00844 case CH_SPARSE_ARRAY:
00845 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00846 SlWriteSparseIndex(_sl.array_index);
00847 break;
00848 default: NOT_REACHED();
00849 }
00850 break;
00851
00852 case NL_CALCLENGTH:
00853 _sl.obj_len += (int)length;
00854 break;
00855
00856 default: NOT_REACHED();
00857 }
00858 }
00859
00866 static void SlCopyBytes(void *ptr, size_t length)
00867 {
00868 byte *p = (byte *)ptr;
00869
00870 switch (_sl.action) {
00871 case SLA_LOAD_CHECK:
00872 case SLA_LOAD:
00873 for (; length != 0; length--) *p++ = SlReadByte();
00874 break;
00875 case SLA_SAVE:
00876 for (; length != 0; length--) SlWriteByte(*p++);
00877 break;
00878 default: NOT_REACHED();
00879 }
00880 }
00881
00883 size_t SlGetFieldLength()
00884 {
00885 return _sl.obj_len;
00886 }
00887
00895 int64 ReadValue(const void *ptr, VarType conv)
00896 {
00897 switch (GetVarMemType(conv)) {
00898 case SLE_VAR_BL: return (*(const bool *)ptr != 0);
00899 case SLE_VAR_I8: return *(const int8 *)ptr;
00900 case SLE_VAR_U8: return *(const byte *)ptr;
00901 case SLE_VAR_I16: return *(const int16 *)ptr;
00902 case SLE_VAR_U16: return *(const uint16*)ptr;
00903 case SLE_VAR_I32: return *(const int32 *)ptr;
00904 case SLE_VAR_U32: return *(const uint32*)ptr;
00905 case SLE_VAR_I64: return *(const int64 *)ptr;
00906 case SLE_VAR_U64: return *(const uint64*)ptr;
00907 case SLE_VAR_NULL:return 0;
00908 default: NOT_REACHED();
00909 }
00910 }
00911
00919 void WriteValue(void *ptr, VarType conv, int64 val)
00920 {
00921 switch (GetVarMemType(conv)) {
00922 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00923 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00924 case SLE_VAR_U8: *(byte *)ptr = val; break;
00925 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00926 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00927 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00928 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00929 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00930 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00931 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00932 case SLE_VAR_NULL: break;
00933 default: NOT_REACHED();
00934 }
00935 }
00936
00945 static void SlSaveLoadConv(void *ptr, VarType conv)
00946 {
00947 switch (_sl.action) {
00948 case SLA_SAVE: {
00949 int64 x = ReadValue(ptr, conv);
00950
00951
00952 switch (GetVarFileType(conv)) {
00953 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00954 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00955 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00956 case SLE_FILE_STRINGID:
00957 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00958 case SLE_FILE_I32:
00959 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00960 case SLE_FILE_I64:
00961 case SLE_FILE_U64: SlWriteUint64(x);break;
00962 default: NOT_REACHED();
00963 }
00964 break;
00965 }
00966 case SLA_LOAD_CHECK:
00967 case SLA_LOAD: {
00968 int64 x;
00969
00970 switch (GetVarFileType(conv)) {
00971 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00972 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00973 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00974 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00975 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00976 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00977 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00978 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00979 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00980 default: NOT_REACHED();
00981 }
00982
00983
00984 WriteValue(ptr, conv, x);
00985 break;
00986 }
00987 case SLA_PTRS: break;
00988 case SLA_NULL: break;
00989 default: NOT_REACHED();
00990 }
00991 }
00992
01002 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
01003 {
01004 if (ptr == NULL) return 0;
01005 return min(strlen(ptr), length - 1);
01006 }
01007
01017 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
01018 {
01019 size_t len;
01020 const char *str;
01021
01022 switch (GetVarMemType(conv)) {
01023 default: NOT_REACHED();
01024 case SLE_VAR_STR:
01025 case SLE_VAR_STRQ:
01026 str = *(const char * const *)ptr;
01027 len = SIZE_MAX;
01028 break;
01029 case SLE_VAR_STRB:
01030 case SLE_VAR_STRBQ:
01031 str = (const char *)ptr;
01032 len = length;
01033 break;
01034 }
01035
01036 len = SlCalcNetStringLen(str, len);
01037 return len + SlGetArrayLength(len);
01038 }
01039
01046 static void SlString(void *ptr, size_t length, VarType conv)
01047 {
01048 switch (_sl.action) {
01049 case SLA_SAVE: {
01050 size_t len;
01051 switch (GetVarMemType(conv)) {
01052 default: NOT_REACHED();
01053 case SLE_VAR_STRB:
01054 case SLE_VAR_STRBQ:
01055 len = SlCalcNetStringLen((char *)ptr, length);
01056 break;
01057 case SLE_VAR_STR:
01058 case SLE_VAR_STRQ:
01059 ptr = *(char **)ptr;
01060 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01061 break;
01062 }
01063
01064 SlWriteArrayLength(len);
01065 SlCopyBytes(ptr, len);
01066 break;
01067 }
01068 case SLA_LOAD_CHECK:
01069 case SLA_LOAD: {
01070 size_t len = SlReadArrayLength();
01071
01072 switch (GetVarMemType(conv)) {
01073 default: NOT_REACHED();
01074 case SLE_VAR_STRB:
01075 case SLE_VAR_STRBQ:
01076 if (len >= length) {
01077 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01078 SlCopyBytes(ptr, length);
01079 SlSkipBytes(len - length);
01080 len = length - 1;
01081 } else {
01082 SlCopyBytes(ptr, len);
01083 }
01084 break;
01085 case SLE_VAR_STR:
01086 case SLE_VAR_STRQ:
01087 free(*(char **)ptr);
01088 if (len == 0) {
01089 *(char **)ptr = NULL;
01090 } else {
01091 *(char **)ptr = MallocT<char>(len + 1);
01092 ptr = *(char **)ptr;
01093 SlCopyBytes(ptr, len);
01094 }
01095 break;
01096 }
01097
01098 ((char *)ptr)[len] = '\0';
01099 StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
01100 if ((conv & SLF_ALLOW_CONTROL) != 0) {
01101 settings = settings | SVS_ALLOW_CONTROL_CODE;
01102 if (IsSavegameVersionBefore(169)) {
01103 str_fix_scc_encoded((char *)ptr, (char *)ptr + len);
01104 }
01105 }
01106 if ((conv & SLF_ALLOW_NEWLINE) != 0) {
01107 settings = settings | SVS_ALLOW_NEWLINE;
01108 }
01109 str_validate((char *)ptr, (char *)ptr + len, settings);
01110 break;
01111 }
01112 case SLA_PTRS: break;
01113 case SLA_NULL: break;
01114 default: NOT_REACHED();
01115 }
01116 }
01117
01123 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01124 {
01125 return SlCalcConvFileLen(conv) * length;
01126 }
01127
01134 void SlArray(void *array, size_t length, VarType conv)
01135 {
01136 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01137
01138
01139 if (_sl.need_length != NL_NONE) {
01140 SlSetLength(SlCalcArrayLen(length, conv));
01141
01142 if (_sl.need_length == NL_CALCLENGTH) return;
01143 }
01144
01145
01146
01147 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01148
01149 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01150 conv == SLE_INT32 || conv == SLE_UINT32) {
01151 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01152 return;
01153 }
01154
01155 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01156 for (uint i = 0; i < length; i++) {
01157 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01158 }
01159 return;
01160 }
01161 }
01162
01163
01164
01165 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01166 SlCopyBytes(array, length);
01167 } else {
01168 byte *a = (byte*)array;
01169 byte mem_size = SlCalcConvMemLen(conv);
01170
01171 for (; length != 0; length --) {
01172 SlSaveLoadConv(a, conv);
01173 a += mem_size;
01174 }
01175 }
01176 }
01177
01178
01189 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01190 {
01191 assert(_sl.action == SLA_SAVE);
01192
01193 if (obj == NULL) return 0;
01194
01195 switch (rt) {
01196 case REF_VEHICLE_OLD:
01197 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01198 case REF_STATION: return ((const Station*)obj)->index + 1;
01199 case REF_TOWN: return ((const Town*)obj)->index + 1;
01200 case REF_ORDER: return ((const Order*)obj)->index + 1;
01201 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01202 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01203 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01204 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01205 case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
01206 default: NOT_REACHED();
01207 }
01208 }
01209
01220 static void *IntToReference(size_t index, SLRefType rt)
01221 {
01222 assert_compile(sizeof(size_t) <= sizeof(void *));
01223
01224 assert(_sl.action == SLA_PTRS);
01225
01226
01227
01228 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01229 rt = REF_VEHICLE;
01230 }
01231
01232
01233 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01234
01235
01236
01237 if (rt != REF_VEHICLE_OLD) index--;
01238
01239 switch (rt) {
01240 case REF_ORDERLIST:
01241 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01242 SlErrorCorrupt("Referencing invalid OrderList");
01243
01244 case REF_ORDER:
01245 if (Order::IsValidID(index)) return Order::Get(index);
01246
01247 if (IsSavegameVersionBefore(5, 2)) return NULL;
01248 SlErrorCorrupt("Referencing invalid Order");
01249
01250 case REF_VEHICLE_OLD:
01251 case REF_VEHICLE:
01252 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01253 SlErrorCorrupt("Referencing invalid Vehicle");
01254
01255 case REF_STATION:
01256 if (Station::IsValidID(index)) return Station::Get(index);
01257 SlErrorCorrupt("Referencing invalid Station");
01258
01259 case REF_TOWN:
01260 if (Town::IsValidID(index)) return Town::Get(index);
01261 SlErrorCorrupt("Referencing invalid Town");
01262
01263 case REF_ROADSTOPS:
01264 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01265 SlErrorCorrupt("Referencing invalid RoadStop");
01266
01267 case REF_ENGINE_RENEWS:
01268 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01269 SlErrorCorrupt("Referencing invalid EngineRenew");
01270
01271 case REF_CARGO_PACKET:
01272 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01273 SlErrorCorrupt("Referencing invalid CargoPacket");
01274
01275 case REF_STORAGE:
01276 if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index);
01277 SlErrorCorrupt("Referencing invalid PersistentStorage");
01278
01279 default: NOT_REACHED();
01280 }
01281 }
01282
01287 static inline size_t SlCalcListLen(const void *list)
01288 {
01289 const std::list<void *> *l = (const std::list<void *> *) list;
01290
01291 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01292
01293
01294 return l->size() * type_size + type_size;
01295 }
01296
01297
01303 static void SlList(void *list, SLRefType conv)
01304 {
01305
01306 if (_sl.need_length != NL_NONE) {
01307 SlSetLength(SlCalcListLen(list));
01308
01309 if (_sl.need_length == NL_CALCLENGTH) return;
01310 }
01311
01312 typedef std::list<void *> PtrList;
01313 PtrList *l = (PtrList *)list;
01314
01315 switch (_sl.action) {
01316 case SLA_SAVE: {
01317 SlWriteUint32((uint32)l->size());
01318
01319 PtrList::iterator iter;
01320 for (iter = l->begin(); iter != l->end(); ++iter) {
01321 void *ptr = *iter;
01322 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01323 }
01324 break;
01325 }
01326 case SLA_LOAD_CHECK:
01327 case SLA_LOAD: {
01328 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01329
01330
01331 for (size_t i = 0; i < length; i++) {
01332 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01333 l->push_back((void *)data);
01334 }
01335 break;
01336 }
01337 case SLA_PTRS: {
01338 PtrList temp = *l;
01339
01340 l->clear();
01341 PtrList::iterator iter;
01342 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01343 void *ptr = IntToReference((size_t)*iter, conv);
01344 l->push_back(ptr);
01345 }
01346 break;
01347 }
01348 case SLA_NULL:
01349 l->clear();
01350 break;
01351 default: NOT_REACHED();
01352 }
01353 }
01354
01355
01357 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01358 {
01359 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01360 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01361
01362 return true;
01363 }
01364
01370 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01371 {
01372 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01373 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01374 return true;
01375 }
01376
01377 return false;
01378 }
01379
01386 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01387 {
01388 size_t length = 0;
01389
01390
01391 for (; sld->cmd != SL_END; sld++) {
01392 length += SlCalcObjMemberLength(object, sld);
01393 }
01394 return length;
01395 }
01396
01397 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01398 {
01399 assert(_sl.action == SLA_SAVE);
01400
01401 switch (sld->cmd) {
01402 case SL_VAR:
01403 case SL_REF:
01404 case SL_ARR:
01405 case SL_STR:
01406 case SL_LST:
01407
01408 if (!SlIsObjectValidInSavegame(sld)) break;
01409
01410 switch (sld->cmd) {
01411 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01412 case SL_REF: return SlCalcRefLen();
01413 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01414 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01415 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01416 default: NOT_REACHED();
01417 }
01418 break;
01419 case SL_WRITEBYTE: return 1;
01420 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01421 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01422 default: NOT_REACHED();
01423 }
01424 return 0;
01425 }
01426
01427
01428 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01429 {
01430 VarType conv = GB(sld->conv, 0, 8);
01431 switch (sld->cmd) {
01432 case SL_VAR:
01433 case SL_REF:
01434 case SL_ARR:
01435 case SL_STR:
01436 case SL_LST:
01437
01438 if (!SlIsObjectValidInSavegame(sld)) return false;
01439 if (SlSkipVariableOnLoad(sld)) return false;
01440
01441 switch (sld->cmd) {
01442 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01443 case SL_REF:
01444 switch (_sl.action) {
01445 case SLA_SAVE:
01446 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01447 break;
01448 case SLA_LOAD_CHECK:
01449 case SLA_LOAD:
01450 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01451 break;
01452 case SLA_PTRS:
01453 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01454 break;
01455 case SLA_NULL:
01456 *(void **)ptr = NULL;
01457 break;
01458 default: NOT_REACHED();
01459 }
01460 break;
01461 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01462 case SL_STR: SlString(ptr, sld->length, sld->conv); break;
01463 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01464 default: NOT_REACHED();
01465 }
01466 break;
01467
01468
01469
01470
01471
01472
01473 case SL_WRITEBYTE:
01474 switch (_sl.action) {
01475 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01476 case SLA_LOAD_CHECK:
01477 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01478 case SLA_PTRS: break;
01479 case SLA_NULL: break;
01480 default: NOT_REACHED();
01481 }
01482 break;
01483
01484
01485 case SL_VEH_INCLUDE:
01486 SlObject(ptr, GetVehicleDescription(VEH_END));
01487 break;
01488
01489 case SL_ST_INCLUDE:
01490 SlObject(ptr, GetBaseStationDescription());
01491 break;
01492
01493 default: NOT_REACHED();
01494 }
01495 return true;
01496 }
01497
01503 void SlObject(void *object, const SaveLoad *sld)
01504 {
01505
01506 if (_sl.need_length != NL_NONE) {
01507 SlSetLength(SlCalcObjLength(object, sld));
01508 if (_sl.need_length == NL_CALCLENGTH) return;
01509 }
01510
01511 for (; sld->cmd != SL_END; sld++) {
01512 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01513 SlObjectMember(ptr, sld);
01514 }
01515 }
01516
01521 void SlGlobList(const SaveLoadGlobVarList *sldg)
01522 {
01523 SlObject(NULL, (const SaveLoad*)sldg);
01524 }
01525
01531 void SlAutolength(AutolengthProc *proc, void *arg)
01532 {
01533 size_t offs;
01534
01535 assert(_sl.action == SLA_SAVE);
01536
01537
01538 _sl.need_length = NL_CALCLENGTH;
01539 _sl.obj_len = 0;
01540 proc(arg);
01541
01542
01543 _sl.need_length = NL_WANTLENGTH;
01544 SlSetLength(_sl.obj_len);
01545
01546 offs = _sl.dumper->GetSize() + _sl.obj_len;
01547
01548
01549 proc(arg);
01550
01551 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01552 }
01553
01558 static void SlLoadChunk(const ChunkHandler *ch)
01559 {
01560 byte m = SlReadByte();
01561 size_t len;
01562 size_t endoffs;
01563
01564 _sl.block_mode = m;
01565 _sl.obj_len = 0;
01566
01567 switch (m) {
01568 case CH_ARRAY:
01569 _sl.array_index = 0;
01570 ch->load_proc();
01571 break;
01572 case CH_SPARSE_ARRAY:
01573 ch->load_proc();
01574 break;
01575 default:
01576 if ((m & 0xF) == CH_RIFF) {
01577
01578 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01579 len += SlReadUint16();
01580 _sl.obj_len = len;
01581 endoffs = _sl.reader->GetSize() + len;
01582 ch->load_proc();
01583 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01584 } else {
01585 SlErrorCorrupt("Invalid chunk type");
01586 }
01587 break;
01588 }
01589 }
01590
01596 static void SlLoadCheckChunk(const ChunkHandler *ch)
01597 {
01598 byte m = SlReadByte();
01599 size_t len;
01600 size_t endoffs;
01601
01602 _sl.block_mode = m;
01603 _sl.obj_len = 0;
01604
01605 switch (m) {
01606 case CH_ARRAY:
01607 _sl.array_index = 0;
01608 if (ch->load_check_proc) {
01609 ch->load_check_proc();
01610 } else {
01611 SlSkipArray();
01612 }
01613 break;
01614 case CH_SPARSE_ARRAY:
01615 if (ch->load_check_proc) {
01616 ch->load_check_proc();
01617 } else {
01618 SlSkipArray();
01619 }
01620 break;
01621 default:
01622 if ((m & 0xF) == CH_RIFF) {
01623
01624 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01625 len += SlReadUint16();
01626 _sl.obj_len = len;
01627 endoffs = _sl.reader->GetSize() + len;
01628 if (ch->load_check_proc) {
01629 ch->load_check_proc();
01630 } else {
01631 SlSkipBytes(len);
01632 }
01633 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01634 } else {
01635 SlErrorCorrupt("Invalid chunk type");
01636 }
01637 break;
01638 }
01639 }
01640
01645 static ChunkSaveLoadProc *_stub_save_proc;
01646
01652 static inline void SlStubSaveProc2(void *arg)
01653 {
01654 _stub_save_proc();
01655 }
01656
01662 static void SlStubSaveProc()
01663 {
01664 SlAutolength(SlStubSaveProc2, NULL);
01665 }
01666
01672 static void SlSaveChunk(const ChunkHandler *ch)
01673 {
01674 ChunkSaveLoadProc *proc = ch->save_proc;
01675
01676
01677 if (proc == NULL) return;
01678
01679 SlWriteUint32(ch->id);
01680 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01681
01682 if (ch->flags & CH_AUTO_LENGTH) {
01683
01684 _stub_save_proc = proc;
01685 proc = SlStubSaveProc;
01686 }
01687
01688 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01689 switch (ch->flags & CH_TYPE_MASK) {
01690 case CH_RIFF:
01691 _sl.need_length = NL_WANTLENGTH;
01692 proc();
01693 break;
01694 case CH_ARRAY:
01695 _sl.last_array_index = 0;
01696 SlWriteByte(CH_ARRAY);
01697 proc();
01698 SlWriteArrayLength(0);
01699 break;
01700 case CH_SPARSE_ARRAY:
01701 SlWriteByte(CH_SPARSE_ARRAY);
01702 proc();
01703 SlWriteArrayLength(0);
01704 break;
01705 default: NOT_REACHED();
01706 }
01707 }
01708
01710 static void SlSaveChunks()
01711 {
01712 FOR_ALL_CHUNK_HANDLERS(ch) {
01713 SlSaveChunk(ch);
01714 }
01715
01716
01717 SlWriteUint32(0);
01718 }
01719
01726 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01727 {
01728 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01729 return NULL;
01730 }
01731
01733 static void SlLoadChunks()
01734 {
01735 uint32 id;
01736 const ChunkHandler *ch;
01737
01738 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01739 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01740
01741 ch = SlFindChunkHandler(id);
01742 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01743 SlLoadChunk(ch);
01744 }
01745 }
01746
01748 static void SlLoadCheckChunks()
01749 {
01750 uint32 id;
01751 const ChunkHandler *ch;
01752
01753 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01754 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01755
01756 ch = SlFindChunkHandler(id);
01757 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01758 SlLoadCheckChunk(ch);
01759 }
01760 }
01761
01763 static void SlFixPointers()
01764 {
01765 _sl.action = SLA_PTRS;
01766
01767 DEBUG(sl, 1, "Fixing pointers");
01768
01769 FOR_ALL_CHUNK_HANDLERS(ch) {
01770 if (ch->ptrs_proc != NULL) {
01771 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01772 ch->ptrs_proc();
01773 }
01774 }
01775
01776 DEBUG(sl, 1, "All pointers fixed");
01777
01778 assert(_sl.action == SLA_PTRS);
01779 }
01780
01781
01783 struct FileReader : LoadFilter {
01784 FILE *file;
01785 long begin;
01786
01791 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01792 {
01793 }
01794
01796 ~FileReader()
01797 {
01798 if (this->file != NULL) fclose(this->file);
01799 this->file = NULL;
01800
01801
01802 _sl.sf = NULL;
01803 }
01804
01805 size_t Read(byte *buf, size_t size)
01806 {
01807
01808 if (this->file == NULL) return 0;
01809
01810 return fread(buf, 1, size, this->file);
01811 }
01812
01813 void Reset()
01814 {
01815 clearerr(this->file);
01816 fseek(this->file, this->begin, SEEK_SET);
01817 }
01818 };
01819
01821 struct FileWriter : SaveFilter {
01822 FILE *file;
01823
01828 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01829 {
01830 }
01831
01833 ~FileWriter()
01834 {
01835 this->Finish();
01836
01837
01838 _sl.sf = NULL;
01839 }
01840
01841 void Write(byte *buf, size_t size)
01842 {
01843
01844 if (this->file == NULL) return;
01845
01846 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01847 }
01848
01849 void Finish()
01850 {
01851 if (this->file != NULL) fclose(this->file);
01852 this->file = NULL;
01853 }
01854 };
01855
01856
01857
01858
01859
01860 #ifdef WITH_LZO
01861 #include <lzo/lzo1x.h>
01862
01864 static const uint LZO_BUFFER_SIZE = 8192;
01865
01867 struct LZOLoadFilter : LoadFilter {
01872 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01873 {
01874 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01875 }
01876
01877 size_t Read(byte *buf, size_t ssize)
01878 {
01879 assert(ssize >= LZO_BUFFER_SIZE);
01880
01881
01882 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01883 uint32 tmp[2];
01884 uint32 size;
01885 lzo_uint len;
01886
01887
01888 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01889
01890
01891 ((uint32*)out)[0] = size = tmp[1];
01892
01893 if (_sl_version != 0) {
01894 tmp[0] = TO_BE32(tmp[0]);
01895 size = TO_BE32(size);
01896 }
01897
01898 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01899
01900
01901 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01902
01903
01904 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01905
01906
01907 lzo1x_decompress(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01908 return len;
01909 }
01910 };
01911
01913 struct LZOSaveFilter : SaveFilter {
01919 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01920 {
01921 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01922 }
01923
01924 void Write(byte *buf, size_t size)
01925 {
01926 const lzo_bytep in = buf;
01927
01928 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01929 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01930 lzo_uint outlen;
01931
01932 do {
01933
01934 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01935 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01936 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01937 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01938 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01939
01940
01941 size -= len;
01942 in += len;
01943 } while (size > 0);
01944 }
01945 };
01946
01947 #endif
01948
01949
01950
01951
01952
01954 struct NoCompLoadFilter : LoadFilter {
01959 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01960 {
01961 }
01962
01963 size_t Read(byte *buf, size_t size)
01964 {
01965 return this->chain->Read(buf, size);
01966 }
01967 };
01968
01970 struct NoCompSaveFilter : SaveFilter {
01976 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01977 {
01978 }
01979
01980 void Write(byte *buf, size_t size)
01981 {
01982 this->chain->Write(buf, size);
01983 }
01984 };
01985
01986
01987
01988
01989
01990 #if defined(WITH_ZLIB)
01991 #include <zlib.h>
01992
01994 struct ZlibLoadFilter : LoadFilter {
01995 z_stream z;
01996 byte fread_buf[MEMORY_CHUNK_SIZE];
01997
02002 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
02003 {
02004 memset(&this->z, 0, sizeof(this->z));
02005 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02006 }
02007
02009 ~ZlibLoadFilter()
02010 {
02011 inflateEnd(&this->z);
02012 }
02013
02014 size_t Read(byte *buf, size_t size)
02015 {
02016 this->z.next_out = buf;
02017 this->z.avail_out = (uint)size;
02018
02019 do {
02020
02021 if (this->z.avail_in == 0) {
02022 this->z.next_in = this->fread_buf;
02023 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02024 }
02025
02026
02027 int r = inflate(&this->z, 0);
02028 if (r == Z_STREAM_END) break;
02029
02030 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02031 } while (this->z.avail_out != 0);
02032
02033 return size - this->z.avail_out;
02034 }
02035 };
02036
02038 struct ZlibSaveFilter : SaveFilter {
02039 z_stream z;
02040
02046 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02047 {
02048 memset(&this->z, 0, sizeof(this->z));
02049 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02050 }
02051
02053 ~ZlibSaveFilter()
02054 {
02055 deflateEnd(&this->z);
02056 }
02057
02064 void WriteLoop(byte *p, size_t len, int mode)
02065 {
02066 byte buf[MEMORY_CHUNK_SIZE];
02067 uint n;
02068 this->z.next_in = p;
02069 this->z.avail_in = (uInt)len;
02070 do {
02071 this->z.next_out = buf;
02072 this->z.avail_out = sizeof(buf);
02073
02081 int r = deflate(&this->z, mode);
02082
02083
02084 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02085 this->chain->Write(buf, n);
02086 }
02087 if (r == Z_STREAM_END) break;
02088
02089 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02090 } while (this->z.avail_in || !this->z.avail_out);
02091 }
02092
02093 void Write(byte *buf, size_t size)
02094 {
02095 this->WriteLoop(buf, size, 0);
02096 }
02097
02098 void Finish()
02099 {
02100 this->WriteLoop(NULL, 0, Z_FINISH);
02101 this->chain->Finish();
02102 }
02103 };
02104
02105 #endif
02106
02107
02108
02109
02110
02111 #if defined(WITH_LZMA)
02112 #include <lzma.h>
02113
02120 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02121
02123 struct LZMALoadFilter : LoadFilter {
02124 lzma_stream lzma;
02125 byte fread_buf[MEMORY_CHUNK_SIZE];
02126
02131 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02132 {
02133
02134 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02135 }
02136
02138 ~LZMALoadFilter()
02139 {
02140 lzma_end(&this->lzma);
02141 }
02142
02143 size_t Read(byte *buf, size_t size)
02144 {
02145 this->lzma.next_out = buf;
02146 this->lzma.avail_out = size;
02147
02148 do {
02149
02150 if (this->lzma.avail_in == 0) {
02151 this->lzma.next_in = this->fread_buf;
02152 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02153 }
02154
02155
02156 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02157 if (r == LZMA_STREAM_END) break;
02158 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02159 } while (this->lzma.avail_out != 0);
02160
02161 return size - this->lzma.avail_out;
02162 }
02163 };
02164
02166 struct LZMASaveFilter : SaveFilter {
02167 lzma_stream lzma;
02168
02174 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02175 {
02176 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02177 }
02178
02180 ~LZMASaveFilter()
02181 {
02182 lzma_end(&this->lzma);
02183 }
02184
02191 void WriteLoop(byte *p, size_t len, lzma_action action)
02192 {
02193 byte buf[MEMORY_CHUNK_SIZE];
02194 size_t n;
02195 this->lzma.next_in = p;
02196 this->lzma.avail_in = len;
02197 do {
02198 this->lzma.next_out = buf;
02199 this->lzma.avail_out = sizeof(buf);
02200
02201 lzma_ret r = lzma_code(&this->lzma, action);
02202
02203
02204 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02205 this->chain->Write(buf, n);
02206 }
02207 if (r == LZMA_STREAM_END) break;
02208 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02209 } while (this->lzma.avail_in || !this->lzma.avail_out);
02210 }
02211
02212 void Write(byte *buf, size_t size)
02213 {
02214 this->WriteLoop(buf, size, LZMA_RUN);
02215 }
02216
02217 void Finish()
02218 {
02219 this->WriteLoop(NULL, 0, LZMA_FINISH);
02220 this->chain->Finish();
02221 }
02222 };
02223
02224 #endif
02225
02226
02227
02228
02229
02231 struct SaveLoadFormat {
02232 const char *name;
02233 uint32 tag;
02234
02235 LoadFilter *(*init_load)(LoadFilter *chain);
02236 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02237
02238 byte min_compression;
02239 byte default_compression;
02240 byte max_compression;
02241 };
02242
02244 static const SaveLoadFormat _saveload_formats[] = {
02245 #if defined(WITH_LZO)
02246
02247 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02248 #else
02249 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02250 #endif
02251
02252 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02253 #if defined(WITH_ZLIB)
02254
02255
02256
02257 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02258 #else
02259 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02260 #endif
02261 #if defined(WITH_LZMA)
02262
02263
02264
02265
02266
02267 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02268 #else
02269 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02270 #endif
02271 };
02272
02280 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02281 {
02282 const SaveLoadFormat *def = lastof(_saveload_formats);
02283
02284
02285 while (!def->init_write) def--;
02286
02287 if (!StrEmpty(s)) {
02288
02289 char *complevel = strrchr(s, ':');
02290 if (complevel != NULL) *complevel = '\0';
02291
02292 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02293 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02294 *compression_level = slf->default_compression;
02295 if (complevel != NULL) {
02296
02297
02298
02299 *complevel = ':';
02300 complevel++;
02301
02302
02303 char *end;
02304 long level = strtol(complevel, &end, 10);
02305 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02306 SetDParamStr(0, complevel);
02307 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL);
02308 } else {
02309 *compression_level = level;
02310 }
02311 }
02312 return slf;
02313 }
02314 }
02315
02316 SetDParamStr(0, s);
02317 SetDParamStr(1, def->name);
02318 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL);
02319
02320
02321 if (complevel != NULL) *complevel = ':';
02322 }
02323 *compression_level = def->default_compression;
02324 return def;
02325 }
02326
02327
02328 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02329 extern bool AfterLoadGame();
02330 extern bool LoadOldSaveGame(const char *file);
02331
02335 static inline void ClearSaveLoadState()
02336 {
02337 delete _sl.dumper;
02338 _sl.dumper = NULL;
02339
02340 delete _sl.sf;
02341 _sl.sf = NULL;
02342
02343 delete _sl.reader;
02344 _sl.reader = NULL;
02345
02346 delete _sl.lf;
02347 _sl.lf = NULL;
02348 }
02349
02355 static void SaveFileStart()
02356 {
02357 _sl.ff_state = _fast_forward;
02358 _fast_forward = 0;
02359 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02360
02361 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02362 _sl.saveinprogress = true;
02363 }
02364
02366 static void SaveFileDone()
02367 {
02368 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02369 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02370
02371 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02372 _sl.saveinprogress = false;
02373 }
02374
02376 void SetSaveLoadError(StringID str)
02377 {
02378 _sl.error_str = str;
02379 }
02380
02382 const char *GetSaveLoadErrorString()
02383 {
02384 SetDParam(0, _sl.error_str);
02385 SetDParamStr(1, _sl.extra_msg);
02386
02387 static char err_str[512];
02388 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02389 return err_str;
02390 }
02391
02393 static void SaveFileError()
02394 {
02395 SetDParamStr(0, GetSaveLoadErrorString());
02396 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02397 SaveFileDone();
02398 }
02399
02404 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02405 {
02406 try {
02407 byte compression;
02408 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02409
02410
02411 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02412 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02413
02414 _sl.sf = fmt->init_write(_sl.sf, compression);
02415 _sl.dumper->Flush(_sl.sf);
02416
02417 ClearSaveLoadState();
02418
02419 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02420
02421 return SL_OK;
02422 } catch (...) {
02423 ClearSaveLoadState();
02424
02425 AsyncSaveFinishProc asfp = SaveFileDone;
02426
02427
02428
02429 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02430
02431 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02432 asfp = SaveFileError;
02433 }
02434
02435 if (threaded) {
02436 SetAsyncSaveFinish(asfp);
02437 } else {
02438 asfp();
02439 }
02440 return SL_ERROR;
02441 }
02442 }
02443
02445 static void SaveFileToDiskThread(void *arg)
02446 {
02447 SaveFileToDisk(true);
02448 }
02449
02450 void WaitTillSaved()
02451 {
02452 if (_save_thread == NULL) return;
02453
02454 _save_thread->Join();
02455 delete _save_thread;
02456 _save_thread = NULL;
02457
02458
02459 ProcessAsyncSaveFinish();
02460 }
02461
02470 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02471 {
02472 assert(!_sl.saveinprogress);
02473
02474 _sl.dumper = new MemoryDumper();
02475 _sl.sf = writer;
02476
02477 _sl_version = SAVEGAME_VERSION;
02478
02479 SaveViewportBeforeSaveGame();
02480 SlSaveChunks();
02481
02482 SaveFileStart();
02483 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02484 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02485
02486 SaveOrLoadResult result = SaveFileToDisk(false);
02487 SaveFileDone();
02488
02489 return result;
02490 }
02491
02492 return SL_OK;
02493 }
02494
02501 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02502 {
02503 try {
02504 _sl.action = SLA_SAVE;
02505 return DoSave(writer, threaded);
02506 } catch (...) {
02507 ClearSaveLoadState();
02508 return SL_ERROR;
02509 }
02510 }
02511
02518 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02519 {
02520 _sl.lf = reader;
02521
02522 if (load_check) {
02523
02524 _load_check_data.Clear();
02525
02526 _load_check_data.checkable = true;
02527 }
02528
02529 uint32 hdr[2];
02530 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02531
02532
02533 const SaveLoadFormat *fmt = _saveload_formats;
02534 for (;;) {
02535
02536 if (fmt == endof(_saveload_formats)) {
02537 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02538 _sl.lf->Reset();
02539 _sl_version = 0;
02540 _sl_minor_version = 0;
02541
02542
02543 fmt = _saveload_formats;
02544 for (;;) {
02545 if (fmt == endof(_saveload_formats)) {
02546
02547 NOT_REACHED();
02548 }
02549 if (fmt->tag == TO_BE32X('OTTD')) break;
02550 fmt++;
02551 }
02552 break;
02553 }
02554
02555 if (fmt->tag == hdr[0]) {
02556
02557 _sl_version = TO_BE32(hdr[1]) >> 16;
02558
02559
02560
02561 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02562
02563 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02564
02565
02566 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02567 break;
02568 }
02569
02570 fmt++;
02571 }
02572
02573
02574 if (fmt->init_load == NULL) {
02575 char err_str[64];
02576 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02577 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02578 }
02579
02580 _sl.lf = fmt->init_load(_sl.lf);
02581 _sl.reader = new ReadBuffer(_sl.lf);
02582 _next_offs = 0;
02583
02584 if (!load_check) {
02585
02586
02587
02588 InitializeGame(256, 256, true, true);
02589
02590 GamelogReset();
02591
02592 if (IsSavegameVersionBefore(4)) {
02593
02594
02595
02596
02597
02598
02599
02600
02601
02602
02603
02604
02605
02606
02607
02608
02609
02610
02611
02612
02613
02614 ClearGRFConfigList(&_grfconfig);
02615 }
02616 }
02617
02618 if (load_check) {
02619
02620
02621 SlLoadCheckChunks();
02622 } else {
02623
02624 SlLoadChunks();
02625 SlFixPointers();
02626 }
02627
02628 ClearSaveLoadState();
02629
02630 _savegame_type = SGT_OTTD;
02631
02632 if (load_check) {
02633
02634 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02635 } else {
02636 GamelogStartAction(GLAT_LOAD);
02637
02638
02639
02640 if (!AfterLoadGame()) {
02641 GamelogStopAction();
02642 return SL_REINIT;
02643 }
02644
02645 GamelogStopAction();
02646 }
02647
02648 return SL_OK;
02649 }
02650
02656 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02657 {
02658 try {
02659 _sl.action = SLA_LOAD;
02660 return DoLoad(reader, false);
02661 } catch (...) {
02662 ClearSaveLoadState();
02663 return SL_REINIT;
02664 }
02665 }
02666
02676 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02677 {
02678
02679 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02680
02681 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02682 return SL_OK;
02683 }
02684 WaitTillSaved();
02685
02686
02687 if (mode == SL_OLD_LOAD) {
02688 InitializeGame(256, 256, true, true);
02689
02690
02691
02692
02693
02694 ClearGRFConfigList(&_grfconfig);
02695 GamelogReset();
02696 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02697 _sl_version = 0;
02698 _sl_minor_version = 0;
02699 GamelogStartAction(GLAT_LOAD);
02700 if (!AfterLoadGame()) {
02701 GamelogStopAction();
02702 return SL_REINIT;
02703 }
02704 GamelogStopAction();
02705 return SL_OK;
02706 }
02707
02708 switch (mode) {
02709 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02710 case SL_LOAD: _sl.action = SLA_LOAD; break;
02711 case SL_SAVE: _sl.action = SLA_SAVE; break;
02712 default: NOT_REACHED();
02713 }
02714
02715 try {
02716 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02717
02718
02719 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02720 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02721 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
02722
02723 if (fh == NULL) {
02724 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02725 }
02726
02727 if (mode == SL_SAVE) {
02728 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02729 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02730
02731 return DoSave(new FileWriter(fh), threaded);
02732 }
02733
02734
02735 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02736 DEBUG(desync, 1, "load: %s", filename);
02737 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02738 } catch (...) {
02739 ClearSaveLoadState();
02740
02741
02742 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02743
02744
02745 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02746 }
02747 }
02748
02750 void DoExitSave()
02751 {
02752 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02753 }
02754
02760 void GenerateDefaultSaveName(char *buf, const char *last)
02761 {
02762
02763
02764
02765 CompanyID cid = _local_company;
02766 if (!Company::IsValidID(cid)) {
02767 const Company *c;
02768 FOR_ALL_COMPANIES(c) {
02769 cid = c->index;
02770 break;
02771 }
02772 }
02773
02774 SetDParam(0, cid);
02775
02776
02777 switch (_settings_client.gui.date_format_in_default_names) {
02778 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02779 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02780 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02781 default: NOT_REACHED();
02782 }
02783 SetDParam(2, _date);
02784
02785
02786 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02787 SanitizeFilename(buf);
02788 }
02789
02790 #if 0
02791
02797 int GetSavegameType(char *file)
02798 {
02799 const SaveLoadFormat *fmt;
02800 uint32 hdr;
02801 FILE *f;
02802 int mode = SL_OLD_LOAD;
02803
02804 f = fopen(file, "rb");
02805 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02806 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02807 mode = SL_LOAD;
02808 } else {
02809
02810 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02811 if (fmt->tag == hdr) {
02812 mode = SL_LOAD;
02813 break;
02814 }
02815 }
02816 }
02817
02818 fclose(f);
02819 return mode;
02820 }
02821 #endif