00001
00002
00003
00004
00005
00006
00007
00008
00009
00024 #include "../stdafx.h"
00025 #include "../debug.h"
00026 #include "../station_base.h"
00027 #include "../thread/thread.h"
00028 #include "../town.h"
00029 #include "../network/network.h"
00030 #include "../window_func.h"
00031 #include "../strings_func.h"
00032 #include "../core/endian_func.hpp"
00033 #include "../vehicle_base.h"
00034 #include "../company_func.h"
00035 #include "../date_func.h"
00036 #include "../autoreplace_base.h"
00037 #include "../roadstop_base.h"
00038 #include "../statusbar_gui.h"
00039 #include "../fileio_func.h"
00040 #include "../gamelog.h"
00041 #include "../string_func.h"
00042 #include "../fios.h"
00043 #include "../error.h"
00044
00045 #include "table/strings.h"
00046
00047 #include "saveload_internal.h"
00048 #include "saveload_filter.h"
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243 extern const uint16 SAVEGAME_VERSION = SL_EXT_RATING;
00244
00245 SavegameType _savegame_type;
00246
00247 uint32 _ttdp_version;
00248 uint16 _sl_version;
00249 byte _sl_minor_version;
00250 char _savegame_format[8];
00251 bool _do_autosave;
00252
00254 enum SaveLoadAction {
00255 SLA_LOAD,
00256 SLA_SAVE,
00257 SLA_PTRS,
00258 SLA_NULL,
00259 SLA_LOAD_CHECK,
00260 };
00261
00262 enum NeedLength {
00263 NL_NONE = 0,
00264 NL_WANTLENGTH = 1,
00265 NL_CALCLENGTH = 2,
00266 };
00267
00269 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
00270
00272 struct ReadBuffer {
00273 byte buf[MEMORY_CHUNK_SIZE];
00274 byte *bufp;
00275 byte *bufe;
00276 LoadFilter *reader;
00277 size_t read;
00278
00283 ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
00284 {
00285 }
00286
00287 inline byte ReadByte()
00288 {
00289 if (this->bufp == this->bufe) {
00290 size_t len = this->reader->Read(this->buf, lengthof(this->buf));
00291 if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00292
00293 this->read += len;
00294 this->bufp = this->buf;
00295 this->bufe = this->buf + len;
00296 }
00297
00298 return *this->bufp++;
00299 }
00300
00305 size_t GetSize() const
00306 {
00307 return this->read - (this->bufe - this->bufp);
00308 }
00309 };
00310
00311
00313 struct MemoryDumper {
00314 AutoFreeSmallVector<byte *, 16> blocks;
00315 byte *buf;
00316 byte *bufe;
00317
00319 MemoryDumper() : buf(NULL), bufe(NULL)
00320 {
00321 }
00322
00327 inline void WriteByte(byte b)
00328 {
00329
00330 if (this->buf == this->bufe) {
00331 this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
00332 *this->blocks.Append() = this->buf;
00333 this->bufe = this->buf + MEMORY_CHUNK_SIZE;
00334 }
00335
00336 *this->buf++ = b;
00337 }
00338
00343 void Flush(SaveFilter *writer)
00344 {
00345 uint i = 0;
00346 size_t t = this->GetSize();
00347
00348 while (t > 0) {
00349 size_t to_write = min(MEMORY_CHUNK_SIZE, t);
00350
00351 writer->Write(this->blocks[i++], to_write);
00352 t -= to_write;
00353 }
00354
00355 writer->Finish();
00356 }
00357
00362 size_t GetSize() const
00363 {
00364 return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
00365 }
00366 };
00367
00369 struct SaveLoadParams {
00370 SaveLoadAction action;
00371 NeedLength need_length;
00372 byte block_mode;
00373 bool error;
00374
00375 size_t obj_len;
00376 int array_index, last_array_index;
00377
00378 MemoryDumper *dumper;
00379 SaveFilter *sf;
00380
00381 ReadBuffer *reader;
00382 LoadFilter *lf;
00383
00384 StringID error_str;
00385 char *extra_msg;
00386
00387 byte ff_state;
00388 bool saveinprogress;
00389 };
00390
00391 static SaveLoadParams _sl;
00392
00393
00394 extern const ChunkHandler _gamelog_chunk_handlers[];
00395 extern const ChunkHandler _map_chunk_handlers[];
00396 extern const ChunkHandler _misc_chunk_handlers[];
00397 extern const ChunkHandler _name_chunk_handlers[];
00398 extern const ChunkHandler _cheat_chunk_handlers[] ;
00399 extern const ChunkHandler _setting_chunk_handlers[];
00400 extern const ChunkHandler _company_chunk_handlers[];
00401 extern const ChunkHandler _engine_chunk_handlers[];
00402 extern const ChunkHandler _veh_chunk_handlers[];
00403 extern const ChunkHandler _waypoint_chunk_handlers[];
00404 extern const ChunkHandler _depot_chunk_handlers[];
00405 extern const ChunkHandler _order_chunk_handlers[];
00406 extern const ChunkHandler _town_chunk_handlers[];
00407 extern const ChunkHandler _sign_chunk_handlers[];
00408 extern const ChunkHandler _station_chunk_handlers[];
00409 extern const ChunkHandler _industry_chunk_handlers[];
00410 extern const ChunkHandler _economy_chunk_handlers[];
00411 extern const ChunkHandler _subsidy_chunk_handlers[];
00412 extern const ChunkHandler _goal_chunk_handlers[];
00413 extern const ChunkHandler _ai_chunk_handlers[];
00414 extern const ChunkHandler _game_chunk_handlers[];
00415 extern const ChunkHandler _animated_tile_chunk_handlers[];
00416 extern const ChunkHandler _newgrf_chunk_handlers[];
00417 extern const ChunkHandler _group_chunk_handlers[];
00418 extern const ChunkHandler _cargopacket_chunk_handlers[];
00419 extern const ChunkHandler _autoreplace_chunk_handlers[];
00420 extern const ChunkHandler _labelmaps_chunk_handlers[];
00421 extern const ChunkHandler _linkgraph_chunk_handlers[];
00422 extern const ChunkHandler _airport_chunk_handlers[];
00423 extern const ChunkHandler _object_chunk_handlers[];
00424 extern const ChunkHandler _persistent_storage_chunk_handlers[];
00425
00427 static const ChunkHandler * const _chunk_handlers[] = {
00428 _gamelog_chunk_handlers,
00429 _map_chunk_handlers,
00430 _misc_chunk_handlers,
00431 _name_chunk_handlers,
00432 _cheat_chunk_handlers,
00433 _setting_chunk_handlers,
00434 _veh_chunk_handlers,
00435 _waypoint_chunk_handlers,
00436 _depot_chunk_handlers,
00437 _order_chunk_handlers,
00438 _industry_chunk_handlers,
00439 _economy_chunk_handlers,
00440 _subsidy_chunk_handlers,
00441 _goal_chunk_handlers,
00442 _engine_chunk_handlers,
00443 _town_chunk_handlers,
00444 _sign_chunk_handlers,
00445 _station_chunk_handlers,
00446 _company_chunk_handlers,
00447 _ai_chunk_handlers,
00448 _game_chunk_handlers,
00449 _animated_tile_chunk_handlers,
00450 _newgrf_chunk_handlers,
00451 _group_chunk_handlers,
00452 _cargopacket_chunk_handlers,
00453 _autoreplace_chunk_handlers,
00454 _labelmaps_chunk_handlers,
00455 _linkgraph_chunk_handlers,
00456 _airport_chunk_handlers,
00457 _object_chunk_handlers,
00458 _persistent_storage_chunk_handlers,
00459 NULL,
00460 };
00461
00466 #define FOR_ALL_CHUNK_HANDLERS(ch) \
00467 for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \
00468 for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1)
00469
00471 static void SlNullPointers()
00472 {
00473 _sl.action = SLA_NULL;
00474
00475
00476
00477
00478 _sl_version = SAVEGAME_VERSION;
00479
00480 DEBUG(sl, 1, "Nulling pointers");
00481
00482 FOR_ALL_CHUNK_HANDLERS(ch) {
00483 if (ch->ptrs_proc != NULL) {
00484 DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00485 ch->ptrs_proc();
00486 }
00487 }
00488
00489 DEBUG(sl, 1, "All pointers nulled");
00490
00491 assert(_sl.action == SLA_NULL);
00492 }
00493
00502 void NORETURN SlError(StringID string, const char *extra_msg)
00503 {
00504
00505 if (_sl.action == SLA_LOAD_CHECK) {
00506 _load_check_data.error = string;
00507 free(_load_check_data.error_data);
00508 _load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00509 } else {
00510 _sl.error_str = string;
00511 free(_sl.extra_msg);
00512 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00513 }
00514
00515
00516
00517
00518
00519 if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00520 throw std::exception();
00521 }
00522
00530 void NORETURN SlErrorCorrupt(const char *msg)
00531 {
00532 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00533 }
00534
00535
00536 typedef void (*AsyncSaveFinishProc)();
00537 static AsyncSaveFinishProc _async_save_finish = NULL;
00538 static ThreadObject *_save_thread;
00539
00544 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00545 {
00546 if (_exit_game) return;
00547 while (_async_save_finish != NULL) CSleep(10);
00548
00549 _async_save_finish = proc;
00550 }
00551
00555 void ProcessAsyncSaveFinish()
00556 {
00557 if (_async_save_finish == NULL) return;
00558
00559 _async_save_finish();
00560
00561 _async_save_finish = NULL;
00562
00563 if (_save_thread != NULL) {
00564 _save_thread->Join();
00565 delete _save_thread;
00566 _save_thread = NULL;
00567 }
00568 }
00569
00574 byte SlReadByte()
00575 {
00576 return _sl.reader->ReadByte();
00577 }
00578
00583 void SlWriteByte(byte b)
00584 {
00585 _sl.dumper->WriteByte(b);
00586 }
00587
00588 static inline int SlReadUint16()
00589 {
00590 int x = SlReadByte() << 8;
00591 return x | SlReadByte();
00592 }
00593
00594 static inline uint32 SlReadUint32()
00595 {
00596 uint32 x = SlReadUint16() << 16;
00597 return x | SlReadUint16();
00598 }
00599
00600 static inline uint64 SlReadUint64()
00601 {
00602 uint32 x = SlReadUint32();
00603 uint32 y = SlReadUint32();
00604 return (uint64)x << 32 | y;
00605 }
00606
00607 static inline void SlWriteUint16(uint16 v)
00608 {
00609 SlWriteByte(GB(v, 8, 8));
00610 SlWriteByte(GB(v, 0, 8));
00611 }
00612
00613 static inline void SlWriteUint32(uint32 v)
00614 {
00615 SlWriteUint16(GB(v, 16, 16));
00616 SlWriteUint16(GB(v, 0, 16));
00617 }
00618
00619 static inline void SlWriteUint64(uint64 x)
00620 {
00621 SlWriteUint32((uint32)(x >> 32));
00622 SlWriteUint32((uint32)x);
00623 }
00624
00630 static inline void SlSkipBytes(size_t length)
00631 {
00632 for (; length != 0; length--) SlReadByte();
00633 }
00634
00644 static uint SlReadSimpleGamma()
00645 {
00646 uint i = SlReadByte();
00647 if (HasBit(i, 7)) {
00648 i &= ~0x80;
00649 if (HasBit(i, 6)) {
00650 i &= ~0x40;
00651 if (HasBit(i, 5)) {
00652 i &= ~0x20;
00653 if (HasBit(i, 4)) {
00654 SlErrorCorrupt("Unsupported gamma");
00655 }
00656 i = (i << 8) | SlReadByte();
00657 }
00658 i = (i << 8) | SlReadByte();
00659 }
00660 i = (i << 8) | SlReadByte();
00661 }
00662 return i;
00663 }
00664
00677 static void SlWriteSimpleGamma(size_t i)
00678 {
00679 if (i >= (1 << 7)) {
00680 if (i >= (1 << 14)) {
00681 if (i >= (1 << 21)) {
00682 assert(i < (1 << 28));
00683 SlWriteByte((byte)(0xE0 | (i >> 24)));
00684 SlWriteByte((byte)(i >> 16));
00685 } else {
00686 SlWriteByte((byte)(0xC0 | (i >> 16)));
00687 }
00688 SlWriteByte((byte)(i >> 8));
00689 } else {
00690 SlWriteByte((byte)(0x80 | (i >> 8)));
00691 }
00692 }
00693 SlWriteByte((byte)i);
00694 }
00695
00697 static inline uint SlGetGammaLength(size_t i)
00698 {
00699 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00700 }
00701
00702 static inline uint SlReadSparseIndex()
00703 {
00704 return SlReadSimpleGamma();
00705 }
00706
00707 static inline void SlWriteSparseIndex(uint index)
00708 {
00709 SlWriteSimpleGamma(index);
00710 }
00711
00712 static inline uint SlReadArrayLength()
00713 {
00714 return SlReadSimpleGamma();
00715 }
00716
00717 static inline void SlWriteArrayLength(size_t length)
00718 {
00719 SlWriteSimpleGamma(length);
00720 }
00721
00722 static inline uint SlGetArrayLength(size_t length)
00723 {
00724 return SlGetGammaLength(length);
00725 }
00726
00733 static inline uint SlCalcConvMemLen(VarType conv)
00734 {
00735 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00736 byte length = GB(conv, 4, 4);
00737
00738 switch (length << 4) {
00739 case SLE_VAR_STRB:
00740 case SLE_VAR_STRBQ:
00741 case SLE_VAR_STR:
00742 case SLE_VAR_STRQ:
00743 return SlReadArrayLength();
00744
00745 default:
00746 assert(length < lengthof(conv_mem_size));
00747 return conv_mem_size[length];
00748 }
00749 }
00750
00757 static inline byte SlCalcConvFileLen(VarType conv)
00758 {
00759 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00760 byte length = GB(conv, 0, 4);
00761 assert(length < lengthof(conv_file_size));
00762 return conv_file_size[length];
00763 }
00764
00766 static inline size_t SlCalcRefLen()
00767 {
00768 return IsSavegameVersionBefore(69) ? 2 : 4;
00769 }
00770
00771 void SlSetArrayIndex(uint index)
00772 {
00773 _sl.need_length = NL_WANTLENGTH;
00774 _sl.array_index = index;
00775 }
00776
00777 static size_t _next_offs;
00778
00783 int SlIterateArray()
00784 {
00785 int index;
00786
00787
00788
00789 if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00790
00791 for (;;) {
00792 uint length = SlReadArrayLength();
00793 if (length == 0) {
00794 _next_offs = 0;
00795 return -1;
00796 }
00797
00798 _sl.obj_len = --length;
00799 _next_offs = _sl.reader->GetSize() + length;
00800
00801 switch (_sl.block_mode) {
00802 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00803 case CH_ARRAY: index = _sl.array_index++; break;
00804 default:
00805 DEBUG(sl, 0, "SlIterateArray error");
00806 return -1;
00807 }
00808
00809 if (length != 0) return index;
00810 }
00811 }
00812
00816 void SlSkipArray()
00817 {
00818 while (SlIterateArray() != -1) {
00819 SlSkipBytes(_next_offs - _sl.reader->GetSize());
00820 }
00821 }
00822
00828 void SlSetLength(size_t length)
00829 {
00830 assert(_sl.action == SLA_SAVE);
00831
00832 switch (_sl.need_length) {
00833 case NL_WANTLENGTH:
00834 _sl.need_length = NL_NONE;
00835 switch (_sl.block_mode) {
00836 case CH_RIFF:
00837
00838
00839
00840 assert(length < (1 << 28));
00841 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00842 break;
00843 case CH_ARRAY:
00844 assert(_sl.last_array_index <= _sl.array_index);
00845 while (++_sl.last_array_index <= _sl.array_index) {
00846 SlWriteArrayLength(1);
00847 }
00848 SlWriteArrayLength(length + 1);
00849 break;
00850 case CH_SPARSE_ARRAY:
00851 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00852 SlWriteSparseIndex(_sl.array_index);
00853 break;
00854 default: NOT_REACHED();
00855 }
00856 break;
00857
00858 case NL_CALCLENGTH:
00859 _sl.obj_len += (int)length;
00860 break;
00861
00862 default: NOT_REACHED();
00863 }
00864 }
00865
00872 static void SlCopyBytes(void *ptr, size_t length)
00873 {
00874 byte *p = (byte *)ptr;
00875
00876 switch (_sl.action) {
00877 case SLA_LOAD_CHECK:
00878 case SLA_LOAD:
00879 for (; length != 0; length--) *p++ = SlReadByte();
00880 break;
00881 case SLA_SAVE:
00882 for (; length != 0; length--) SlWriteByte(*p++);
00883 break;
00884 default: NOT_REACHED();
00885 }
00886 }
00887
00889 size_t SlGetFieldLength()
00890 {
00891 return _sl.obj_len;
00892 }
00893
00901 int64 ReadValue(const void *ptr, VarType conv)
00902 {
00903 switch (GetVarMemType(conv)) {
00904 case SLE_VAR_BL: return (*(const bool *)ptr != 0);
00905 case SLE_VAR_I8: return *(const int8 *)ptr;
00906 case SLE_VAR_U8: return *(const byte *)ptr;
00907 case SLE_VAR_I16: return *(const int16 *)ptr;
00908 case SLE_VAR_U16: return *(const uint16*)ptr;
00909 case SLE_VAR_I32: return *(const int32 *)ptr;
00910 case SLE_VAR_U32: return *(const uint32*)ptr;
00911 case SLE_VAR_I64: return *(const int64 *)ptr;
00912 case SLE_VAR_U64: return *(const uint64*)ptr;
00913 case SLE_VAR_NULL:return 0;
00914 default: NOT_REACHED();
00915 }
00916 }
00917
00925 void WriteValue(void *ptr, VarType conv, int64 val)
00926 {
00927 switch (GetVarMemType(conv)) {
00928 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00929 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00930 case SLE_VAR_U8: *(byte *)ptr = val; break;
00931 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00932 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00933 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00934 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00935 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00936 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00937 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00938 case SLE_VAR_NULL: break;
00939 default: NOT_REACHED();
00940 }
00941 }
00942
00951 static void SlSaveLoadConv(void *ptr, VarType conv)
00952 {
00953 switch (_sl.action) {
00954 case SLA_SAVE: {
00955 int64 x = ReadValue(ptr, conv);
00956
00957
00958 switch (GetVarFileType(conv)) {
00959 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00960 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00961 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00962 case SLE_FILE_STRINGID:
00963 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00964 case SLE_FILE_I32:
00965 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00966 case SLE_FILE_I64:
00967 case SLE_FILE_U64: SlWriteUint64(x);break;
00968 default: NOT_REACHED();
00969 }
00970 break;
00971 }
00972 case SLA_LOAD_CHECK:
00973 case SLA_LOAD: {
00974 int64 x;
00975
00976 switch (GetVarFileType(conv)) {
00977 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00978 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00979 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00980 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00981 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00982 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00983 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00984 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00985 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00986 default: NOT_REACHED();
00987 }
00988
00989
00990 WriteValue(ptr, conv, x);
00991 break;
00992 }
00993 case SLA_PTRS: break;
00994 case SLA_NULL: break;
00995 default: NOT_REACHED();
00996 }
00997 }
00998
01008 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
01009 {
01010 if (ptr == NULL) return 0;
01011 return min(strlen(ptr), length - 1);
01012 }
01013
01023 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
01024 {
01025 size_t len;
01026 const char *str;
01027
01028 switch (GetVarMemType(conv)) {
01029 default: NOT_REACHED();
01030 case SLE_VAR_STR:
01031 case SLE_VAR_STRQ:
01032 str = *(const char * const *)ptr;
01033 len = SIZE_MAX;
01034 break;
01035 case SLE_VAR_STRB:
01036 case SLE_VAR_STRBQ:
01037 str = (const char *)ptr;
01038 len = length;
01039 break;
01040 }
01041
01042 len = SlCalcNetStringLen(str, len);
01043 return len + SlGetArrayLength(len);
01044 }
01045
01052 static void SlString(void *ptr, size_t length, VarType conv)
01053 {
01054 switch (_sl.action) {
01055 case SLA_SAVE: {
01056 size_t len;
01057 switch (GetVarMemType(conv)) {
01058 default: NOT_REACHED();
01059 case SLE_VAR_STRB:
01060 case SLE_VAR_STRBQ:
01061 len = SlCalcNetStringLen((char *)ptr, length);
01062 break;
01063 case SLE_VAR_STR:
01064 case SLE_VAR_STRQ:
01065 ptr = *(char **)ptr;
01066 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01067 break;
01068 }
01069
01070 SlWriteArrayLength(len);
01071 SlCopyBytes(ptr, len);
01072 break;
01073 }
01074 case SLA_LOAD_CHECK:
01075 case SLA_LOAD: {
01076 size_t len = SlReadArrayLength();
01077
01078 switch (GetVarMemType(conv)) {
01079 default: NOT_REACHED();
01080 case SLE_VAR_STRB:
01081 case SLE_VAR_STRBQ:
01082 if (len >= length) {
01083 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01084 SlCopyBytes(ptr, length);
01085 SlSkipBytes(len - length);
01086 len = length - 1;
01087 } else {
01088 SlCopyBytes(ptr, len);
01089 }
01090 break;
01091 case SLE_VAR_STR:
01092 case SLE_VAR_STRQ:
01093 free(*(char **)ptr);
01094 if (len == 0) {
01095 *(char **)ptr = NULL;
01096 return;
01097 } else {
01098 *(char **)ptr = MallocT<char>(len + 1);
01099 ptr = *(char **)ptr;
01100 SlCopyBytes(ptr, len);
01101 }
01102 break;
01103 }
01104
01105 ((char *)ptr)[len] = '\0';
01106 StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
01107 if ((conv & SLF_ALLOW_CONTROL) != 0) {
01108 settings = settings | SVS_ALLOW_CONTROL_CODE;
01109 if (IsSavegameVersionBefore(169)) {
01110 str_fix_scc_encoded((char *)ptr, (char *)ptr + len);
01111 }
01112 }
01113 if ((conv & SLF_ALLOW_NEWLINE) != 0) {
01114 settings = settings | SVS_ALLOW_NEWLINE;
01115 }
01116 str_validate((char *)ptr, (char *)ptr + len, settings);
01117 break;
01118 }
01119 case SLA_PTRS: break;
01120 case SLA_NULL: break;
01121 default: NOT_REACHED();
01122 }
01123 }
01124
01130 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01131 {
01132 return SlCalcConvFileLen(conv) * length;
01133 }
01134
01141 void SlArray(void *array, size_t length, VarType conv)
01142 {
01143 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01144
01145
01146 if (_sl.need_length != NL_NONE) {
01147 SlSetLength(SlCalcArrayLen(length, conv));
01148
01149 if (_sl.need_length == NL_CALCLENGTH) return;
01150 }
01151
01152
01153
01154 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01155
01156 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01157 conv == SLE_INT32 || conv == SLE_UINT32) {
01158 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01159 return;
01160 }
01161
01162 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01163 for (uint i = 0; i < length; i++) {
01164 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01165 }
01166 return;
01167 }
01168 }
01169
01170
01171
01172 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01173 SlCopyBytes(array, length);
01174 } else {
01175 byte *a = (byte*)array;
01176 byte mem_size = SlCalcConvMemLen(conv);
01177
01178 for (; length != 0; length --) {
01179 SlSaveLoadConv(a, conv);
01180 a += mem_size;
01181 }
01182 }
01183 }
01184
01185
01196 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01197 {
01198 assert(_sl.action == SLA_SAVE);
01199
01200 if (obj == NULL) return 0;
01201
01202 switch (rt) {
01203 case REF_VEHICLE_OLD:
01204 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01205 case REF_STATION: return ((const Station*)obj)->index + 1;
01206 case REF_TOWN: return ((const Town*)obj)->index + 1;
01207 case REF_ORDER: return ((const Order*)obj)->index + 1;
01208 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01209 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01210 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01211 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01212 case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
01213 default: NOT_REACHED();
01214 }
01215 }
01216
01227 static void *IntToReference(size_t index, SLRefType rt)
01228 {
01229 assert_compile(sizeof(size_t) <= sizeof(void *));
01230
01231 assert(_sl.action == SLA_PTRS);
01232
01233
01234
01235 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01236 rt = REF_VEHICLE;
01237 }
01238
01239
01240 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01241
01242
01243
01244 if (rt != REF_VEHICLE_OLD) index--;
01245
01246 switch (rt) {
01247 case REF_ORDERLIST:
01248 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01249 SlErrorCorrupt("Referencing invalid OrderList");
01250
01251 case REF_ORDER:
01252 if (Order::IsValidID(index)) return Order::Get(index);
01253
01254 if (IsSavegameVersionBefore(5, 2)) return NULL;
01255 SlErrorCorrupt("Referencing invalid Order");
01256
01257 case REF_VEHICLE_OLD:
01258 case REF_VEHICLE:
01259 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01260 SlErrorCorrupt("Referencing invalid Vehicle");
01261
01262 case REF_STATION:
01263 if (Station::IsValidID(index)) return Station::Get(index);
01264 SlErrorCorrupt("Referencing invalid Station");
01265
01266 case REF_TOWN:
01267 if (Town::IsValidID(index)) return Town::Get(index);
01268 SlErrorCorrupt("Referencing invalid Town");
01269
01270 case REF_ROADSTOPS:
01271 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01272 SlErrorCorrupt("Referencing invalid RoadStop");
01273
01274 case REF_ENGINE_RENEWS:
01275 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01276 SlErrorCorrupt("Referencing invalid EngineRenew");
01277
01278 case REF_CARGO_PACKET:
01279 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01280 SlErrorCorrupt("Referencing invalid CargoPacket");
01281
01282 case REF_STORAGE:
01283 if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index);
01284 SlErrorCorrupt("Referencing invalid PersistentStorage");
01285
01286 default: NOT_REACHED();
01287 }
01288 }
01289
01294 static inline size_t SlCalcListLen(const void *list)
01295 {
01296 const std::list<void *> *l = (const std::list<void *> *) list;
01297
01298 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01299
01300
01301 return l->size() * type_size + type_size;
01302 }
01303
01304
01310 static void SlList(void *list, SLRefType conv)
01311 {
01312
01313 if (_sl.need_length != NL_NONE) {
01314 SlSetLength(SlCalcListLen(list));
01315
01316 if (_sl.need_length == NL_CALCLENGTH) return;
01317 }
01318
01319 typedef std::list<void *> PtrList;
01320 PtrList *l = (PtrList *)list;
01321
01322 switch (_sl.action) {
01323 case SLA_SAVE: {
01324 SlWriteUint32((uint32)l->size());
01325
01326 PtrList::iterator iter;
01327 for (iter = l->begin(); iter != l->end(); ++iter) {
01328 void *ptr = *iter;
01329 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01330 }
01331 break;
01332 }
01333 case SLA_LOAD_CHECK:
01334 case SLA_LOAD: {
01335 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01336
01337
01338 for (size_t i = 0; i < length; i++) {
01339 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01340 l->push_back((void *)data);
01341 }
01342 break;
01343 }
01344 case SLA_PTRS: {
01345 PtrList temp = *l;
01346
01347 l->clear();
01348 PtrList::iterator iter;
01349 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01350 void *ptr = IntToReference((size_t)*iter, conv);
01351 l->push_back(ptr);
01352 }
01353 break;
01354 }
01355 case SLA_NULL:
01356 l->clear();
01357 break;
01358 default: NOT_REACHED();
01359 }
01360 }
01361
01362
01364 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01365 {
01366 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01367 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01368
01369 return true;
01370 }
01371
01377 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01378 {
01379 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01380 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01381 return true;
01382 }
01383
01384 return false;
01385 }
01386
01393 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01394 {
01395 size_t length = 0;
01396
01397
01398 for (; sld->cmd != SL_END; sld++) {
01399 length += SlCalcObjMemberLength(object, sld);
01400 }
01401 return length;
01402 }
01403
01404 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01405 {
01406 assert(_sl.action == SLA_SAVE);
01407
01408 switch (sld->cmd) {
01409 case SL_VAR:
01410 case SL_REF:
01411 case SL_ARR:
01412 case SL_STR:
01413 case SL_LST:
01414
01415 if (!SlIsObjectValidInSavegame(sld)) break;
01416
01417 switch (sld->cmd) {
01418 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01419 case SL_REF: return SlCalcRefLen();
01420 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01421 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01422 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01423 default: NOT_REACHED();
01424 }
01425 break;
01426 case SL_WRITEBYTE: return 1;
01427 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01428 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01429 default: NOT_REACHED();
01430 }
01431 return 0;
01432 }
01433
01434
01435 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01436 {
01437 VarType conv = GB(sld->conv, 0, 8);
01438 switch (sld->cmd) {
01439 case SL_VAR:
01440 case SL_REF:
01441 case SL_ARR:
01442 case SL_STR:
01443 case SL_LST:
01444
01445 if (!SlIsObjectValidInSavegame(sld)) return false;
01446 if (SlSkipVariableOnLoad(sld)) return false;
01447
01448 switch (sld->cmd) {
01449 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01450 case SL_REF:
01451 switch (_sl.action) {
01452 case SLA_SAVE:
01453 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01454 break;
01455 case SLA_LOAD_CHECK:
01456 case SLA_LOAD:
01457 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01458 break;
01459 case SLA_PTRS:
01460 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01461 break;
01462 case SLA_NULL:
01463 *(void **)ptr = NULL;
01464 break;
01465 default: NOT_REACHED();
01466 }
01467 break;
01468 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01469 case SL_STR: SlString(ptr, sld->length, sld->conv); break;
01470 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01471 default: NOT_REACHED();
01472 }
01473 break;
01474
01475
01476
01477
01478
01479
01480 case SL_WRITEBYTE:
01481 switch (_sl.action) {
01482 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01483 case SLA_LOAD_CHECK:
01484 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01485 case SLA_PTRS: break;
01486 case SLA_NULL: break;
01487 default: NOT_REACHED();
01488 }
01489 break;
01490
01491
01492 case SL_VEH_INCLUDE:
01493 SlObject(ptr, GetVehicleDescription(VEH_END));
01494 break;
01495
01496 case SL_ST_INCLUDE:
01497 SlObject(ptr, GetBaseStationDescription());
01498 break;
01499
01500 default: NOT_REACHED();
01501 }
01502 return true;
01503 }
01504
01510 void SlObject(void *object, const SaveLoad *sld)
01511 {
01512
01513 if (_sl.need_length != NL_NONE) {
01514 SlSetLength(SlCalcObjLength(object, sld));
01515 if (_sl.need_length == NL_CALCLENGTH) return;
01516 }
01517
01518 for (; sld->cmd != SL_END; sld++) {
01519 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01520 SlObjectMember(ptr, sld);
01521 }
01522 }
01523
01528 void SlGlobList(const SaveLoadGlobVarList *sldg)
01529 {
01530 SlObject(NULL, (const SaveLoad*)sldg);
01531 }
01532
01538 void SlAutolength(AutolengthProc *proc, void *arg)
01539 {
01540 size_t offs;
01541
01542 assert(_sl.action == SLA_SAVE);
01543
01544
01545 _sl.need_length = NL_CALCLENGTH;
01546 _sl.obj_len = 0;
01547 proc(arg);
01548
01549
01550 _sl.need_length = NL_WANTLENGTH;
01551 SlSetLength(_sl.obj_len);
01552
01553 offs = _sl.dumper->GetSize() + _sl.obj_len;
01554
01555
01556 proc(arg);
01557
01558 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01559 }
01560
01565 static void SlLoadChunk(const ChunkHandler *ch)
01566 {
01567 byte m = SlReadByte();
01568 size_t len;
01569 size_t endoffs;
01570
01571 _sl.block_mode = m;
01572 _sl.obj_len = 0;
01573
01574 switch (m) {
01575 case CH_ARRAY:
01576 _sl.array_index = 0;
01577 ch->load_proc();
01578 break;
01579 case CH_SPARSE_ARRAY:
01580 ch->load_proc();
01581 break;
01582 default:
01583 if ((m & 0xF) == CH_RIFF) {
01584
01585 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01586 len += SlReadUint16();
01587 _sl.obj_len = len;
01588 endoffs = _sl.reader->GetSize() + len;
01589 ch->load_proc();
01590 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01591 } else {
01592 SlErrorCorrupt("Invalid chunk type");
01593 }
01594 break;
01595 }
01596 }
01597
01603 static void SlLoadCheckChunk(const ChunkHandler *ch)
01604 {
01605 byte m = SlReadByte();
01606 size_t len;
01607 size_t endoffs;
01608
01609 _sl.block_mode = m;
01610 _sl.obj_len = 0;
01611
01612 switch (m) {
01613 case CH_ARRAY:
01614 _sl.array_index = 0;
01615 if (ch->load_check_proc) {
01616 ch->load_check_proc();
01617 } else {
01618 SlSkipArray();
01619 }
01620 break;
01621 case CH_SPARSE_ARRAY:
01622 if (ch->load_check_proc) {
01623 ch->load_check_proc();
01624 } else {
01625 SlSkipArray();
01626 }
01627 break;
01628 default:
01629 if ((m & 0xF) == CH_RIFF) {
01630
01631 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01632 len += SlReadUint16();
01633 _sl.obj_len = len;
01634 endoffs = _sl.reader->GetSize() + len;
01635 if (ch->load_check_proc) {
01636 ch->load_check_proc();
01637 } else {
01638 SlSkipBytes(len);
01639 }
01640 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01641 } else {
01642 SlErrorCorrupt("Invalid chunk type");
01643 }
01644 break;
01645 }
01646 }
01647
01652 static ChunkSaveLoadProc *_stub_save_proc;
01653
01659 static inline void SlStubSaveProc2(void *arg)
01660 {
01661 _stub_save_proc();
01662 }
01663
01669 static void SlStubSaveProc()
01670 {
01671 SlAutolength(SlStubSaveProc2, NULL);
01672 }
01673
01679 static void SlSaveChunk(const ChunkHandler *ch)
01680 {
01681 ChunkSaveLoadProc *proc = ch->save_proc;
01682
01683
01684 if (proc == NULL) return;
01685
01686 SlWriteUint32(ch->id);
01687 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01688
01689 if (ch->flags & CH_AUTO_LENGTH) {
01690
01691 _stub_save_proc = proc;
01692 proc = SlStubSaveProc;
01693 }
01694
01695 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01696 switch (ch->flags & CH_TYPE_MASK) {
01697 case CH_RIFF:
01698 _sl.need_length = NL_WANTLENGTH;
01699 proc();
01700 break;
01701 case CH_ARRAY:
01702 _sl.last_array_index = 0;
01703 SlWriteByte(CH_ARRAY);
01704 proc();
01705 SlWriteArrayLength(0);
01706 break;
01707 case CH_SPARSE_ARRAY:
01708 SlWriteByte(CH_SPARSE_ARRAY);
01709 proc();
01710 SlWriteArrayLength(0);
01711 break;
01712 default: NOT_REACHED();
01713 }
01714 }
01715
01717 static void SlSaveChunks()
01718 {
01719 FOR_ALL_CHUNK_HANDLERS(ch) {
01720 SlSaveChunk(ch);
01721 }
01722
01723
01724 SlWriteUint32(0);
01725 }
01726
01733 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01734 {
01735 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01736 return NULL;
01737 }
01738
01740 static void SlLoadChunks()
01741 {
01742 uint32 id;
01743 const ChunkHandler *ch;
01744
01745 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01746 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01747
01748 ch = SlFindChunkHandler(id);
01749 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01750 SlLoadChunk(ch);
01751 }
01752 }
01753
01755 static void SlLoadCheckChunks()
01756 {
01757 uint32 id;
01758 const ChunkHandler *ch;
01759
01760 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01761 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01762
01763 ch = SlFindChunkHandler(id);
01764 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01765 SlLoadCheckChunk(ch);
01766 }
01767 }
01768
01770 static void SlFixPointers()
01771 {
01772 _sl.action = SLA_PTRS;
01773
01774 DEBUG(sl, 1, "Fixing pointers");
01775
01776 FOR_ALL_CHUNK_HANDLERS(ch) {
01777 if (ch->ptrs_proc != NULL) {
01778 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01779 ch->ptrs_proc();
01780 }
01781 }
01782
01783 DEBUG(sl, 1, "All pointers fixed");
01784
01785 assert(_sl.action == SLA_PTRS);
01786 }
01787
01788
01790 struct FileReader : LoadFilter {
01791 FILE *file;
01792 long begin;
01793
01798 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01799 {
01800 }
01801
01803 ~FileReader()
01804 {
01805 if (this->file != NULL) fclose(this->file);
01806 this->file = NULL;
01807
01808
01809 _sl.sf = NULL;
01810 }
01811
01812 size_t Read(byte *buf, size_t size)
01813 {
01814
01815 if (this->file == NULL) return 0;
01816
01817 return fread(buf, 1, size, this->file);
01818 }
01819
01820 void Reset()
01821 {
01822 clearerr(this->file);
01823 fseek(this->file, this->begin, SEEK_SET);
01824 }
01825 };
01826
01828 struct FileWriter : SaveFilter {
01829 FILE *file;
01830
01835 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01836 {
01837 }
01838
01840 ~FileWriter()
01841 {
01842 this->Finish();
01843
01844
01845 _sl.sf = NULL;
01846 }
01847
01848 void Write(byte *buf, size_t size)
01849 {
01850
01851 if (this->file == NULL) return;
01852
01853 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01854 }
01855
01856 void Finish()
01857 {
01858 if (this->file != NULL) fclose(this->file);
01859 this->file = NULL;
01860 }
01861 };
01862
01863
01864
01865
01866
01867 #ifdef WITH_LZO
01868 #include <lzo/lzo1x.h>
01869
01871 static const uint LZO_BUFFER_SIZE = 8192;
01872
01874 struct LZOLoadFilter : LoadFilter {
01879 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01880 {
01881 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01882 }
01883
01884 size_t Read(byte *buf, size_t ssize)
01885 {
01886 assert(ssize >= LZO_BUFFER_SIZE);
01887
01888
01889 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01890 uint32 tmp[2];
01891 uint32 size;
01892 lzo_uint len;
01893
01894
01895 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01896
01897
01898 ((uint32*)out)[0] = size = tmp[1];
01899
01900 if (_sl_version != 0) {
01901 tmp[0] = TO_BE32(tmp[0]);
01902 size = TO_BE32(size);
01903 }
01904
01905 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01906
01907
01908 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01909
01910
01911 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01912
01913
01914 lzo1x_decompress(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01915 return len;
01916 }
01917 };
01918
01920 struct LZOSaveFilter : SaveFilter {
01926 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01927 {
01928 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01929 }
01930
01931 void Write(byte *buf, size_t size)
01932 {
01933 const lzo_bytep in = buf;
01934
01935 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01936 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01937 lzo_uint outlen;
01938
01939 do {
01940
01941 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01942 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01943 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01944 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01945 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01946
01947
01948 size -= len;
01949 in += len;
01950 } while (size > 0);
01951 }
01952 };
01953
01954 #endif
01955
01956
01957
01958
01959
01961 struct NoCompLoadFilter : LoadFilter {
01966 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01967 {
01968 }
01969
01970 size_t Read(byte *buf, size_t size)
01971 {
01972 return this->chain->Read(buf, size);
01973 }
01974 };
01975
01977 struct NoCompSaveFilter : SaveFilter {
01983 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01984 {
01985 }
01986
01987 void Write(byte *buf, size_t size)
01988 {
01989 this->chain->Write(buf, size);
01990 }
01991 };
01992
01993
01994
01995
01996
01997 #if defined(WITH_ZLIB)
01998 #include <zlib.h>
01999
02001 struct ZlibLoadFilter : LoadFilter {
02002 z_stream z;
02003 byte fread_buf[MEMORY_CHUNK_SIZE];
02004
02009 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
02010 {
02011 memset(&this->z, 0, sizeof(this->z));
02012 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02013 }
02014
02016 ~ZlibLoadFilter()
02017 {
02018 inflateEnd(&this->z);
02019 }
02020
02021 size_t Read(byte *buf, size_t size)
02022 {
02023 this->z.next_out = buf;
02024 this->z.avail_out = (uint)size;
02025
02026 do {
02027
02028 if (this->z.avail_in == 0) {
02029 this->z.next_in = this->fread_buf;
02030 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02031 }
02032
02033
02034 int r = inflate(&this->z, 0);
02035 if (r == Z_STREAM_END) break;
02036
02037 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02038 } while (this->z.avail_out != 0);
02039
02040 return size - this->z.avail_out;
02041 }
02042 };
02043
02045 struct ZlibSaveFilter : SaveFilter {
02046 z_stream z;
02047
02053 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02054 {
02055 memset(&this->z, 0, sizeof(this->z));
02056 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02057 }
02058
02060 ~ZlibSaveFilter()
02061 {
02062 deflateEnd(&this->z);
02063 }
02064
02071 void WriteLoop(byte *p, size_t len, int mode)
02072 {
02073 byte buf[MEMORY_CHUNK_SIZE];
02074 uint n;
02075 this->z.next_in = p;
02076 this->z.avail_in = (uInt)len;
02077 do {
02078 this->z.next_out = buf;
02079 this->z.avail_out = sizeof(buf);
02080
02088 int r = deflate(&this->z, mode);
02089
02090
02091 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02092 this->chain->Write(buf, n);
02093 }
02094 if (r == Z_STREAM_END) break;
02095
02096 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02097 } while (this->z.avail_in || !this->z.avail_out);
02098 }
02099
02100 void Write(byte *buf, size_t size)
02101 {
02102 this->WriteLoop(buf, size, 0);
02103 }
02104
02105 void Finish()
02106 {
02107 this->WriteLoop(NULL, 0, Z_FINISH);
02108 this->chain->Finish();
02109 }
02110 };
02111
02112 #endif
02113
02114
02115
02116
02117
02118 #if defined(WITH_LZMA)
02119 #include <lzma.h>
02120
02127 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02128
02130 struct LZMALoadFilter : LoadFilter {
02131 lzma_stream lzma;
02132 byte fread_buf[MEMORY_CHUNK_SIZE];
02133
02138 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02139 {
02140
02141 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02142 }
02143
02145 ~LZMALoadFilter()
02146 {
02147 lzma_end(&this->lzma);
02148 }
02149
02150 size_t Read(byte *buf, size_t size)
02151 {
02152 this->lzma.next_out = buf;
02153 this->lzma.avail_out = size;
02154
02155 do {
02156
02157 if (this->lzma.avail_in == 0) {
02158 this->lzma.next_in = this->fread_buf;
02159 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02160 }
02161
02162
02163 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02164 if (r == LZMA_STREAM_END) break;
02165 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02166 } while (this->lzma.avail_out != 0);
02167
02168 return size - this->lzma.avail_out;
02169 }
02170 };
02171
02173 struct LZMASaveFilter : SaveFilter {
02174 lzma_stream lzma;
02175
02181 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02182 {
02183 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02184 }
02185
02187 ~LZMASaveFilter()
02188 {
02189 lzma_end(&this->lzma);
02190 }
02191
02198 void WriteLoop(byte *p, size_t len, lzma_action action)
02199 {
02200 byte buf[MEMORY_CHUNK_SIZE];
02201 size_t n;
02202 this->lzma.next_in = p;
02203 this->lzma.avail_in = len;
02204 do {
02205 this->lzma.next_out = buf;
02206 this->lzma.avail_out = sizeof(buf);
02207
02208 lzma_ret r = lzma_code(&this->lzma, action);
02209
02210
02211 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02212 this->chain->Write(buf, n);
02213 }
02214 if (r == LZMA_STREAM_END) break;
02215 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02216 } while (this->lzma.avail_in || !this->lzma.avail_out);
02217 }
02218
02219 void Write(byte *buf, size_t size)
02220 {
02221 this->WriteLoop(buf, size, LZMA_RUN);
02222 }
02223
02224 void Finish()
02225 {
02226 this->WriteLoop(NULL, 0, LZMA_FINISH);
02227 this->chain->Finish();
02228 }
02229 };
02230
02231 #endif
02232
02233
02234
02235
02236
02238 struct SaveLoadFormat {
02239 const char *name;
02240 uint32 tag;
02241
02242 LoadFilter *(*init_load)(LoadFilter *chain);
02243 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02244
02245 byte min_compression;
02246 byte default_compression;
02247 byte max_compression;
02248 };
02249
02251 static const SaveLoadFormat _saveload_formats[] = {
02252 #if defined(WITH_LZO)
02253
02254 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02255 #else
02256 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02257 #endif
02258
02259 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02260 #if defined(WITH_ZLIB)
02261
02262
02263
02264 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02265 #else
02266 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02267 #endif
02268 #if defined(WITH_LZMA)
02269
02270
02271
02272
02273
02274 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02275 #else
02276 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02277 #endif
02278 };
02279
02287 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02288 {
02289 const SaveLoadFormat *def = lastof(_saveload_formats);
02290
02291
02292 while (!def->init_write) def--;
02293
02294 if (!StrEmpty(s)) {
02295
02296 char *complevel = strrchr(s, ':');
02297 if (complevel != NULL) *complevel = '\0';
02298
02299 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02300 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02301 *compression_level = slf->default_compression;
02302 if (complevel != NULL) {
02303
02304
02305
02306 *complevel = ':';
02307 complevel++;
02308
02309
02310 char *end;
02311 long level = strtol(complevel, &end, 10);
02312 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02313 SetDParamStr(0, complevel);
02314 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL);
02315 } else {
02316 *compression_level = level;
02317 }
02318 }
02319 return slf;
02320 }
02321 }
02322
02323 SetDParamStr(0, s);
02324 SetDParamStr(1, def->name);
02325 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL);
02326
02327
02328 if (complevel != NULL) *complevel = ':';
02329 }
02330 *compression_level = def->default_compression;
02331 return def;
02332 }
02333
02334
02335 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02336 extern bool AfterLoadGame();
02337 extern bool LoadOldSaveGame(const char *file);
02338
02342 static inline void ClearSaveLoadState()
02343 {
02344 delete _sl.dumper;
02345 _sl.dumper = NULL;
02346
02347 delete _sl.sf;
02348 _sl.sf = NULL;
02349
02350 delete _sl.reader;
02351 _sl.reader = NULL;
02352
02353 delete _sl.lf;
02354 _sl.lf = NULL;
02355 }
02356
02362 static void SaveFileStart()
02363 {
02364 _sl.ff_state = _fast_forward;
02365 _fast_forward = 0;
02366 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02367
02368 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02369 _sl.saveinprogress = true;
02370 }
02371
02373 static void SaveFileDone()
02374 {
02375 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02376 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02377
02378 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02379 _sl.saveinprogress = false;
02380 }
02381
02383 void SetSaveLoadError(StringID str)
02384 {
02385 _sl.error_str = str;
02386 }
02387
02389 const char *GetSaveLoadErrorString()
02390 {
02391 SetDParam(0, _sl.error_str);
02392 SetDParamStr(1, _sl.extra_msg);
02393
02394 static char err_str[512];
02395 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02396 return err_str;
02397 }
02398
02400 static void SaveFileError()
02401 {
02402 SetDParamStr(0, GetSaveLoadErrorString());
02403 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02404 SaveFileDone();
02405 }
02406
02411 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02412 {
02413 try {
02414 byte compression;
02415 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02416
02417
02418 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02419 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02420
02421 _sl.sf = fmt->init_write(_sl.sf, compression);
02422 _sl.dumper->Flush(_sl.sf);
02423
02424 ClearSaveLoadState();
02425
02426 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02427
02428 return SL_OK;
02429 } catch (...) {
02430 ClearSaveLoadState();
02431
02432 AsyncSaveFinishProc asfp = SaveFileDone;
02433
02434
02435
02436 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02437
02438 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02439 asfp = SaveFileError;
02440 }
02441
02442 if (threaded) {
02443 SetAsyncSaveFinish(asfp);
02444 } else {
02445 asfp();
02446 }
02447 return SL_ERROR;
02448 }
02449 }
02450
02452 static void SaveFileToDiskThread(void *arg)
02453 {
02454 SaveFileToDisk(true);
02455 }
02456
02457 void WaitTillSaved()
02458 {
02459 if (_save_thread == NULL) return;
02460
02461 _save_thread->Join();
02462 delete _save_thread;
02463 _save_thread = NULL;
02464
02465
02466 ProcessAsyncSaveFinish();
02467 }
02468
02477 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02478 {
02479 assert(!_sl.saveinprogress);
02480
02481 _sl.dumper = new MemoryDumper();
02482 _sl.sf = writer;
02483
02484 _sl_version = SAVEGAME_VERSION;
02485
02486 SaveViewportBeforeSaveGame();
02487 SlSaveChunks();
02488
02489 SaveFileStart();
02490 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02491 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02492
02493 SaveOrLoadResult result = SaveFileToDisk(false);
02494 SaveFileDone();
02495
02496 return result;
02497 }
02498
02499 return SL_OK;
02500 }
02501
02508 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02509 {
02510 try {
02511 _sl.action = SLA_SAVE;
02512 return DoSave(writer, threaded);
02513 } catch (...) {
02514 ClearSaveLoadState();
02515 return SL_ERROR;
02516 }
02517 }
02518
02525 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02526 {
02527 _sl.lf = reader;
02528
02529 if (load_check) {
02530
02531 _load_check_data.Clear();
02532
02533 _load_check_data.checkable = true;
02534 }
02535
02536 uint32 hdr[2];
02537 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02538
02539
02540 const SaveLoadFormat *fmt = _saveload_formats;
02541 for (;;) {
02542
02543 if (fmt == endof(_saveload_formats)) {
02544 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02545 _sl.lf->Reset();
02546 _sl_version = 0;
02547 _sl_minor_version = 0;
02548
02549
02550 fmt = _saveload_formats;
02551 for (;;) {
02552 if (fmt == endof(_saveload_formats)) {
02553
02554 NOT_REACHED();
02555 }
02556 if (fmt->tag == TO_BE32X('OTTD')) break;
02557 fmt++;
02558 }
02559 break;
02560 }
02561
02562 if (fmt->tag == hdr[0]) {
02563
02564 _sl_version = TO_BE32(hdr[1]) >> 16;
02565
02566
02567
02568 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02569
02570 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02571
02572
02573 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02574 break;
02575 }
02576
02577 fmt++;
02578 }
02579
02580
02581 if (fmt->init_load == NULL) {
02582 char err_str[64];
02583 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02584 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02585 }
02586
02587 _sl.lf = fmt->init_load(_sl.lf);
02588 _sl.reader = new ReadBuffer(_sl.lf);
02589 _next_offs = 0;
02590
02591 if (!load_check) {
02592
02593
02594
02595 InitializeGame(256, 256, true, true);
02596
02597 GamelogReset();
02598
02599 if (IsSavegameVersionBefore(4)) {
02600
02601
02602
02603
02604
02605
02606
02607
02608
02609
02610
02611
02612
02613
02614
02615
02616
02617
02618
02619
02620
02621 ClearGRFConfigList(&_grfconfig);
02622 }
02623 }
02624
02625 if (load_check) {
02626
02627
02628 SlLoadCheckChunks();
02629 } else {
02630
02631 SlLoadChunks();
02632 SlFixPointers();
02633 }
02634
02635 ClearSaveLoadState();
02636
02637 _savegame_type = SGT_OTTD;
02638
02639 if (load_check) {
02640
02641 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02642 } else {
02643 GamelogStartAction(GLAT_LOAD);
02644
02645
02646
02647 if (!AfterLoadGame()) {
02648 GamelogStopAction();
02649 return SL_REINIT;
02650 }
02651
02652 GamelogStopAction();
02653 }
02654
02655 return SL_OK;
02656 }
02657
02663 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02664 {
02665 try {
02666 _sl.action = SLA_LOAD;
02667 return DoLoad(reader, false);
02668 } catch (...) {
02669 ClearSaveLoadState();
02670 return SL_REINIT;
02671 }
02672 }
02673
02683 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02684 {
02685
02686 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02687
02688 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02689 return SL_OK;
02690 }
02691 WaitTillSaved();
02692
02693
02694 if (mode == SL_OLD_LOAD) {
02695 InitializeGame(256, 256, true, true);
02696
02697
02698
02699
02700
02701 ClearGRFConfigList(&_grfconfig);
02702 GamelogReset();
02703 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02704 _sl_version = 0;
02705 _sl_minor_version = 0;
02706 GamelogStartAction(GLAT_LOAD);
02707 if (!AfterLoadGame()) {
02708 GamelogStopAction();
02709 return SL_REINIT;
02710 }
02711 GamelogStopAction();
02712 return SL_OK;
02713 }
02714
02715 switch (mode) {
02716 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02717 case SL_LOAD: _sl.action = SLA_LOAD; break;
02718 case SL_SAVE: _sl.action = SLA_SAVE; break;
02719 default: NOT_REACHED();
02720 }
02721
02722 try {
02723 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02724
02725
02726 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02727 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02728 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
02729
02730 if (fh == NULL) {
02731 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02732 }
02733
02734 if (mode == SL_SAVE) {
02735 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02736 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02737
02738 return DoSave(new FileWriter(fh), threaded);
02739 }
02740
02741
02742 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02743 DEBUG(desync, 1, "load: %s", filename);
02744 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02745 } catch (...) {
02746 ClearSaveLoadState();
02747
02748
02749 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02750
02751
02752 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02753 }
02754 }
02755
02757 void DoExitSave()
02758 {
02759 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02760 }
02761
02767 void GenerateDefaultSaveName(char *buf, const char *last)
02768 {
02769
02770
02771
02772 CompanyID cid = _local_company;
02773 if (!Company::IsValidID(cid)) {
02774 const Company *c;
02775 FOR_ALL_COMPANIES(c) {
02776 cid = c->index;
02777 break;
02778 }
02779 }
02780
02781 SetDParam(0, cid);
02782
02783
02784 switch (_settings_client.gui.date_format_in_default_names) {
02785 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02786 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02787 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02788 default: NOT_REACHED();
02789 }
02790 SetDParam(2, _date);
02791
02792
02793 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02794 SanitizeFilename(buf);
02795 }
02796
02797 #if 0
02798
02804 int GetSavegameType(char *file)
02805 {
02806 const SaveLoadFormat *fmt;
02807 uint32 hdr;
02808 FILE *f;
02809 int mode = SL_OLD_LOAD;
02810
02811 f = fopen(file, "rb");
02812 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02813 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02814 mode = SL_LOAD;
02815 } else {
02816
02817 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02818 if (fmt->tag == hdr) {
02819 mode = SL_LOAD;
02820 break;
02821 }
02822 }
02823 }
02824
02825 fclose(f);
02826 return mode;
02827 }
02828 #endif