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