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 "../engine_base.h"
00043 #include "../fios.h"
00044 #include "../error.h"
00045
00046 #include "table/strings.h"
00047
00048 #include "saveload_internal.h"
00049 #include "saveload_filter.h"
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237 extern const uint16 SAVEGAME_VERSION = 168;
00238
00239 SavegameType _savegame_type;
00240
00241 uint32 _ttdp_version;
00242 uint16 _sl_version;
00243 byte _sl_minor_version;
00244 char _savegame_format[8];
00245 bool _do_autosave;
00246
00248 enum SaveLoadAction {
00249 SLA_LOAD,
00250 SLA_SAVE,
00251 SLA_PTRS,
00252 SLA_NULL,
00253 SLA_LOAD_CHECK,
00254 };
00255
00256 enum NeedLength {
00257 NL_NONE = 0,
00258 NL_WANTLENGTH = 1,
00259 NL_CALCLENGTH = 2,
00260 };
00261
00263 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
00264
00266 struct ReadBuffer {
00267 byte buf[MEMORY_CHUNK_SIZE];
00268 byte *bufp;
00269 byte *bufe;
00270 LoadFilter *reader;
00271 size_t read;
00272
00277 ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
00278 {
00279 }
00280
00281 inline byte ReadByte()
00282 {
00283 if (this->bufp == this->bufe) {
00284 size_t len = this->reader->Read(this->buf, lengthof(this->buf));
00285 if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00286
00287 this->read += len;
00288 this->bufp = this->buf;
00289 this->bufe = this->buf + len;
00290 }
00291
00292 return *this->bufp++;
00293 }
00294
00299 size_t GetSize() const
00300 {
00301 return this->read - (this->bufe - this->bufp);
00302 }
00303 };
00304
00305
00307 struct MemoryDumper {
00308 AutoFreeSmallVector<byte *, 16> blocks;
00309 byte *buf;
00310 byte *bufe;
00311
00313 MemoryDumper() : buf(NULL), bufe(NULL)
00314 {
00315 }
00316
00321 inline void WriteByte(byte b)
00322 {
00323
00324 if (this->buf == this->bufe) {
00325 this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
00326 *this->blocks.Append() = this->buf;
00327 this->bufe = this->buf + MEMORY_CHUNK_SIZE;
00328 }
00329
00330 *this->buf++ = b;
00331 }
00332
00337 void Flush(SaveFilter *writer)
00338 {
00339 uint i = 0;
00340 size_t t = this->GetSize();
00341
00342 while (t > 0) {
00343 size_t to_write = min(MEMORY_CHUNK_SIZE, t);
00344
00345 writer->Write(this->blocks[i++], to_write);
00346 t -= to_write;
00347 }
00348
00349 writer->Finish();
00350 }
00351
00356 size_t GetSize() const
00357 {
00358 return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
00359 }
00360 };
00361
00363 struct SaveLoadParams {
00364 SaveLoadAction action;
00365 NeedLength need_length;
00366 byte block_mode;
00367 bool error;
00368
00369 size_t obj_len;
00370 int array_index, last_array_index;
00371
00372 MemoryDumper *dumper;
00373 SaveFilter *sf;
00374
00375 ReadBuffer *reader;
00376 LoadFilter *lf;
00377
00378 StringID error_str;
00379 char *extra_msg;
00380
00381 byte ff_state;
00382 bool saveinprogress;
00383 };
00384
00385 static SaveLoadParams _sl;
00386
00387
00388 extern const ChunkHandler _gamelog_chunk_handlers[];
00389 extern const ChunkHandler _map_chunk_handlers[];
00390 extern const ChunkHandler _misc_chunk_handlers[];
00391 extern const ChunkHandler _name_chunk_handlers[];
00392 extern const ChunkHandler _cheat_chunk_handlers[] ;
00393 extern const ChunkHandler _setting_chunk_handlers[];
00394 extern const ChunkHandler _company_chunk_handlers[];
00395 extern const ChunkHandler _engine_chunk_handlers[];
00396 extern const ChunkHandler _veh_chunk_handlers[];
00397 extern const ChunkHandler _waypoint_chunk_handlers[];
00398 extern const ChunkHandler _depot_chunk_handlers[];
00399 extern const ChunkHandler _order_chunk_handlers[];
00400 extern const ChunkHandler _town_chunk_handlers[];
00401 extern const ChunkHandler _sign_chunk_handlers[];
00402 extern const ChunkHandler _station_chunk_handlers[];
00403 extern const ChunkHandler _industry_chunk_handlers[];
00404 extern const ChunkHandler _economy_chunk_handlers[];
00405 extern const ChunkHandler _subsidy_chunk_handlers[];
00406 extern const ChunkHandler _goal_chunk_handlers[];
00407 extern const ChunkHandler _ai_chunk_handlers[];
00408 extern const ChunkHandler _game_chunk_handlers[];
00409 extern const ChunkHandler _animated_tile_chunk_handlers[];
00410 extern const ChunkHandler _newgrf_chunk_handlers[];
00411 extern const ChunkHandler _group_chunk_handlers[];
00412 extern const ChunkHandler _cargopacket_chunk_handlers[];
00413 extern const ChunkHandler _autoreplace_chunk_handlers[];
00414 extern const ChunkHandler _labelmaps_chunk_handlers[];
00415 extern const ChunkHandler _airport_chunk_handlers[];
00416 extern const ChunkHandler _object_chunk_handlers[];
00417 extern const ChunkHandler _persistent_storage_chunk_handlers[];
00418
00420 static const ChunkHandler * const _chunk_handlers[] = {
00421 _gamelog_chunk_handlers,
00422 _map_chunk_handlers,
00423 _misc_chunk_handlers,
00424 _name_chunk_handlers,
00425 _cheat_chunk_handlers,
00426 _setting_chunk_handlers,
00427 _veh_chunk_handlers,
00428 _waypoint_chunk_handlers,
00429 _depot_chunk_handlers,
00430 _order_chunk_handlers,
00431 _industry_chunk_handlers,
00432 _economy_chunk_handlers,
00433 _subsidy_chunk_handlers,
00434 _goal_chunk_handlers,
00435 _engine_chunk_handlers,
00436 _town_chunk_handlers,
00437 _sign_chunk_handlers,
00438 _station_chunk_handlers,
00439 _company_chunk_handlers,
00440 _ai_chunk_handlers,
00441 _game_chunk_handlers,
00442 _animated_tile_chunk_handlers,
00443 _newgrf_chunk_handlers,
00444 _group_chunk_handlers,
00445 _cargopacket_chunk_handlers,
00446 _autoreplace_chunk_handlers,
00447 _labelmaps_chunk_handlers,
00448 _airport_chunk_handlers,
00449 _object_chunk_handlers,
00450 _persistent_storage_chunk_handlers,
00451 NULL,
00452 };
00453
00458 #define FOR_ALL_CHUNK_HANDLERS(ch) \
00459 for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \
00460 for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1)
00461
00463 static void SlNullPointers()
00464 {
00465 _sl.action = SLA_NULL;
00466
00467
00468
00469
00470 _sl_version = SAVEGAME_VERSION;
00471
00472 DEBUG(sl, 1, "Nulling pointers");
00473
00474 FOR_ALL_CHUNK_HANDLERS(ch) {
00475 if (ch->ptrs_proc != NULL) {
00476 DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00477 ch->ptrs_proc();
00478 }
00479 }
00480
00481 DEBUG(sl, 1, "All pointers nulled");
00482
00483 assert(_sl.action == SLA_NULL);
00484 }
00485
00494 void NORETURN SlError(StringID string, const char *extra_msg)
00495 {
00496
00497 if (_sl.action == SLA_LOAD_CHECK) {
00498 _load_check_data.error = string;
00499 free(_load_check_data.error_data);
00500 _load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00501 } else {
00502 _sl.error_str = string;
00503 free(_sl.extra_msg);
00504 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00505 }
00506
00507
00508
00509
00510
00511 if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00512 throw std::exception();
00513 }
00514
00522 void NORETURN SlErrorCorrupt(const char *msg)
00523 {
00524 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00525 }
00526
00527
00528 typedef void (*AsyncSaveFinishProc)();
00529 static AsyncSaveFinishProc _async_save_finish = NULL;
00530 static ThreadObject *_save_thread;
00531
00536 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00537 {
00538 if (_exit_game) return;
00539 while (_async_save_finish != NULL) CSleep(10);
00540
00541 _async_save_finish = proc;
00542 }
00543
00547 void ProcessAsyncSaveFinish()
00548 {
00549 if (_async_save_finish == NULL) return;
00550
00551 _async_save_finish();
00552
00553 _async_save_finish = NULL;
00554
00555 if (_save_thread != NULL) {
00556 _save_thread->Join();
00557 delete _save_thread;
00558 _save_thread = NULL;
00559 }
00560 }
00561
00566 byte SlReadByte()
00567 {
00568 return _sl.reader->ReadByte();
00569 }
00570
00575 void SlWriteByte(byte b)
00576 {
00577 _sl.dumper->WriteByte(b);
00578 }
00579
00580 static inline int SlReadUint16()
00581 {
00582 int x = SlReadByte() << 8;
00583 return x | SlReadByte();
00584 }
00585
00586 static inline uint32 SlReadUint32()
00587 {
00588 uint32 x = SlReadUint16() << 16;
00589 return x | SlReadUint16();
00590 }
00591
00592 static inline uint64 SlReadUint64()
00593 {
00594 uint32 x = SlReadUint32();
00595 uint32 y = SlReadUint32();
00596 return (uint64)x << 32 | y;
00597 }
00598
00599 static inline void SlWriteUint16(uint16 v)
00600 {
00601 SlWriteByte(GB(v, 8, 8));
00602 SlWriteByte(GB(v, 0, 8));
00603 }
00604
00605 static inline void SlWriteUint32(uint32 v)
00606 {
00607 SlWriteUint16(GB(v, 16, 16));
00608 SlWriteUint16(GB(v, 0, 16));
00609 }
00610
00611 static inline void SlWriteUint64(uint64 x)
00612 {
00613 SlWriteUint32((uint32)(x >> 32));
00614 SlWriteUint32((uint32)x);
00615 }
00616
00622 static inline void SlSkipBytes(size_t length)
00623 {
00624 for (; length != 0; length--) SlReadByte();
00625 }
00626
00636 static uint SlReadSimpleGamma()
00637 {
00638 uint i = SlReadByte();
00639 if (HasBit(i, 7)) {
00640 i &= ~0x80;
00641 if (HasBit(i, 6)) {
00642 i &= ~0x40;
00643 if (HasBit(i, 5)) {
00644 i &= ~0x20;
00645 if (HasBit(i, 4)) {
00646 SlErrorCorrupt("Unsupported gamma");
00647 }
00648 i = (i << 8) | SlReadByte();
00649 }
00650 i = (i << 8) | SlReadByte();
00651 }
00652 i = (i << 8) | SlReadByte();
00653 }
00654 return i;
00655 }
00656
00669 static void SlWriteSimpleGamma(size_t i)
00670 {
00671 if (i >= (1 << 7)) {
00672 if (i >= (1 << 14)) {
00673 if (i >= (1 << 21)) {
00674 assert(i < (1 << 28));
00675 SlWriteByte((byte)(0xE0 | (i >> 24)));
00676 SlWriteByte((byte)(i >> 16));
00677 } else {
00678 SlWriteByte((byte)(0xC0 | (i >> 16)));
00679 }
00680 SlWriteByte((byte)(i >> 8));
00681 } else {
00682 SlWriteByte((byte)(0x80 | (i >> 8)));
00683 }
00684 }
00685 SlWriteByte((byte)i);
00686 }
00687
00689 static inline uint SlGetGammaLength(size_t i)
00690 {
00691 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00692 }
00693
00694 static inline uint SlReadSparseIndex()
00695 {
00696 return SlReadSimpleGamma();
00697 }
00698
00699 static inline void SlWriteSparseIndex(uint index)
00700 {
00701 SlWriteSimpleGamma(index);
00702 }
00703
00704 static inline uint SlReadArrayLength()
00705 {
00706 return SlReadSimpleGamma();
00707 }
00708
00709 static inline void SlWriteArrayLength(size_t length)
00710 {
00711 SlWriteSimpleGamma(length);
00712 }
00713
00714 static inline uint SlGetArrayLength(size_t length)
00715 {
00716 return SlGetGammaLength(length);
00717 }
00718
00725 static inline uint SlCalcConvMemLen(VarType conv)
00726 {
00727 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00728 byte length = GB(conv, 4, 4);
00729
00730 switch (length << 4) {
00731 case SLE_VAR_STRB:
00732 case SLE_VAR_STRBQ:
00733 case SLE_VAR_STR:
00734 case SLE_VAR_STRQ:
00735 return SlReadArrayLength();
00736
00737 default:
00738 assert(length < lengthof(conv_mem_size));
00739 return conv_mem_size[length];
00740 }
00741 }
00742
00749 static inline byte SlCalcConvFileLen(VarType conv)
00750 {
00751 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00752 byte length = GB(conv, 0, 4);
00753 assert(length < lengthof(conv_file_size));
00754 return conv_file_size[length];
00755 }
00756
00758 static inline size_t SlCalcRefLen()
00759 {
00760 return IsSavegameVersionBefore(69) ? 2 : 4;
00761 }
00762
00763 void SlSetArrayIndex(uint index)
00764 {
00765 _sl.need_length = NL_WANTLENGTH;
00766 _sl.array_index = index;
00767 }
00768
00769 static size_t _next_offs;
00770
00775 int SlIterateArray()
00776 {
00777 int index;
00778
00779
00780
00781 if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00782
00783 for (;;) {
00784 uint length = SlReadArrayLength();
00785 if (length == 0) {
00786 _next_offs = 0;
00787 return -1;
00788 }
00789
00790 _sl.obj_len = --length;
00791 _next_offs = _sl.reader->GetSize() + length;
00792
00793 switch (_sl.block_mode) {
00794 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00795 case CH_ARRAY: index = _sl.array_index++; break;
00796 default:
00797 DEBUG(sl, 0, "SlIterateArray error");
00798 return -1;
00799 }
00800
00801 if (length != 0) return index;
00802 }
00803 }
00804
00808 void SlSkipArray()
00809 {
00810 while (SlIterateArray() != -1) {
00811 SlSkipBytes(_next_offs - _sl.reader->GetSize());
00812 }
00813 }
00814
00820 void SlSetLength(size_t length)
00821 {
00822 assert(_sl.action == SLA_SAVE);
00823
00824 switch (_sl.need_length) {
00825 case NL_WANTLENGTH:
00826 _sl.need_length = NL_NONE;
00827 switch (_sl.block_mode) {
00828 case CH_RIFF:
00829
00830
00831
00832 assert(length < (1 << 28));
00833 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00834 break;
00835 case CH_ARRAY:
00836 assert(_sl.last_array_index <= _sl.array_index);
00837 while (++_sl.last_array_index <= _sl.array_index) {
00838 SlWriteArrayLength(1);
00839 }
00840 SlWriteArrayLength(length + 1);
00841 break;
00842 case CH_SPARSE_ARRAY:
00843 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00844 SlWriteSparseIndex(_sl.array_index);
00845 break;
00846 default: NOT_REACHED();
00847 }
00848 break;
00849
00850 case NL_CALCLENGTH:
00851 _sl.obj_len += (int)length;
00852 break;
00853
00854 default: NOT_REACHED();
00855 }
00856 }
00857
00864 static void SlCopyBytes(void *ptr, size_t length)
00865 {
00866 byte *p = (byte *)ptr;
00867
00868 switch (_sl.action) {
00869 case SLA_LOAD_CHECK:
00870 case SLA_LOAD:
00871 for (; length != 0; length--) *p++ = SlReadByte();
00872 break;
00873 case SLA_SAVE:
00874 for (; length != 0; length--) SlWriteByte(*p++);
00875 break;
00876 default: NOT_REACHED();
00877 }
00878 }
00879
00881 size_t SlGetFieldLength()
00882 {
00883 return _sl.obj_len;
00884 }
00885
00893 int64 ReadValue(const void *ptr, VarType conv)
00894 {
00895 switch (GetVarMemType(conv)) {
00896 case SLE_VAR_BL: return (*(const bool *)ptr != 0);
00897 case SLE_VAR_I8: return *(const int8 *)ptr;
00898 case SLE_VAR_U8: return *(const byte *)ptr;
00899 case SLE_VAR_I16: return *(const int16 *)ptr;
00900 case SLE_VAR_U16: return *(const uint16*)ptr;
00901 case SLE_VAR_I32: return *(const int32 *)ptr;
00902 case SLE_VAR_U32: return *(const uint32*)ptr;
00903 case SLE_VAR_I64: return *(const int64 *)ptr;
00904 case SLE_VAR_U64: return *(const uint64*)ptr;
00905 case SLE_VAR_NULL:return 0;
00906 default: NOT_REACHED();
00907 }
00908 }
00909
00917 void WriteValue(void *ptr, VarType conv, int64 val)
00918 {
00919 switch (GetVarMemType(conv)) {
00920 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00921 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00922 case SLE_VAR_U8: *(byte *)ptr = val; break;
00923 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00924 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00925 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00926 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00927 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00928 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00929 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00930 case SLE_VAR_NULL: break;
00931 default: NOT_REACHED();
00932 }
00933 }
00934
00943 static void SlSaveLoadConv(void *ptr, VarType conv)
00944 {
00945 switch (_sl.action) {
00946 case SLA_SAVE: {
00947 int64 x = ReadValue(ptr, conv);
00948
00949
00950 switch (GetVarFileType(conv)) {
00951 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00952 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00953 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00954 case SLE_FILE_STRINGID:
00955 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00956 case SLE_FILE_I32:
00957 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00958 case SLE_FILE_I64:
00959 case SLE_FILE_U64: SlWriteUint64(x);break;
00960 default: NOT_REACHED();
00961 }
00962 break;
00963 }
00964 case SLA_LOAD_CHECK:
00965 case SLA_LOAD: {
00966 int64 x;
00967
00968 switch (GetVarFileType(conv)) {
00969 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00970 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00971 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00972 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00973 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00974 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00975 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00976 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00977 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00978 default: NOT_REACHED();
00979 }
00980
00981
00982 WriteValue(ptr, conv, x);
00983 break;
00984 }
00985 case SLA_PTRS: break;
00986 case SLA_NULL: break;
00987 default: NOT_REACHED();
00988 }
00989 }
00990
01000 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
01001 {
01002 if (ptr == NULL) return 0;
01003 return min(strlen(ptr), length - 1);
01004 }
01005
01015 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
01016 {
01017 size_t len;
01018 const char *str;
01019
01020 switch (GetVarMemType(conv)) {
01021 default: NOT_REACHED();
01022 case SLE_VAR_STR:
01023 case SLE_VAR_STRQ:
01024 str = *(const char * const *)ptr;
01025 len = SIZE_MAX;
01026 break;
01027 case SLE_VAR_STRB:
01028 case SLE_VAR_STRBQ:
01029 str = (const char *)ptr;
01030 len = length;
01031 break;
01032 }
01033
01034 len = SlCalcNetStringLen(str, len);
01035 return len + SlGetArrayLength(len);
01036 }
01037
01044 static void SlString(void *ptr, size_t length, VarType conv)
01045 {
01046 switch (_sl.action) {
01047 case SLA_SAVE: {
01048 size_t len;
01049 switch (GetVarMemType(conv)) {
01050 default: NOT_REACHED();
01051 case SLE_VAR_STRB:
01052 case SLE_VAR_STRBQ:
01053 len = SlCalcNetStringLen((char *)ptr, length);
01054 break;
01055 case SLE_VAR_STR:
01056 case SLE_VAR_STRQ:
01057 ptr = *(char **)ptr;
01058 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01059 break;
01060 }
01061
01062 SlWriteArrayLength(len);
01063 SlCopyBytes(ptr, len);
01064 break;
01065 }
01066 case SLA_LOAD_CHECK:
01067 case SLA_LOAD: {
01068 size_t len = SlReadArrayLength();
01069
01070 switch (GetVarMemType(conv)) {
01071 default: NOT_REACHED();
01072 case SLE_VAR_STRB:
01073 case SLE_VAR_STRBQ:
01074 if (len >= length) {
01075 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01076 SlCopyBytes(ptr, length);
01077 SlSkipBytes(len - length);
01078 len = length - 1;
01079 } else {
01080 SlCopyBytes(ptr, len);
01081 }
01082 break;
01083 case SLE_VAR_STR:
01084 case SLE_VAR_STRQ:
01085 free(*(char **)ptr);
01086 if (len == 0) {
01087 *(char **)ptr = NULL;
01088 } else {
01089 *(char **)ptr = MallocT<char>(len + 1);
01090 ptr = *(char **)ptr;
01091 SlCopyBytes(ptr, len);
01092 }
01093 break;
01094 }
01095
01096 ((char *)ptr)[len] = '\0';
01097 StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
01098 if ((conv & SLF_ALLOW_CONTROL) != 0) {
01099 settings = settings | SVS_ALLOW_CONTROL_CODE;
01100 }
01101 if ((conv & SLF_ALLOW_NEWLINE) != 0) {
01102 settings = settings | SVS_ALLOW_NEWLINE;
01103 }
01104 str_validate((char *)ptr, (char *)ptr + len, settings);
01105 break;
01106 }
01107 case SLA_PTRS: break;
01108 case SLA_NULL: break;
01109 default: NOT_REACHED();
01110 }
01111 }
01112
01118 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01119 {
01120 return SlCalcConvFileLen(conv) * length;
01121 }
01122
01129 void SlArray(void *array, size_t length, VarType conv)
01130 {
01131 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01132
01133
01134 if (_sl.need_length != NL_NONE) {
01135 SlSetLength(SlCalcArrayLen(length, conv));
01136
01137 if (_sl.need_length == NL_CALCLENGTH) return;
01138 }
01139
01140
01141
01142 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01143
01144 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01145 conv == SLE_INT32 || conv == SLE_UINT32) {
01146 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01147 return;
01148 }
01149
01150 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01151 for (uint i = 0; i < length; i++) {
01152 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01153 }
01154 return;
01155 }
01156 }
01157
01158
01159
01160 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01161 SlCopyBytes(array, length);
01162 } else {
01163 byte *a = (byte*)array;
01164 byte mem_size = SlCalcConvMemLen(conv);
01165
01166 for (; length != 0; length --) {
01167 SlSaveLoadConv(a, conv);
01168 a += mem_size;
01169 }
01170 }
01171 }
01172
01173
01184 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01185 {
01186 assert(_sl.action == SLA_SAVE);
01187
01188 if (obj == NULL) return 0;
01189
01190 switch (rt) {
01191 case REF_VEHICLE_OLD:
01192 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01193 case REF_STATION: return ((const Station*)obj)->index + 1;
01194 case REF_TOWN: return ((const Town*)obj)->index + 1;
01195 case REF_ORDER: return ((const Order*)obj)->index + 1;
01196 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01197 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01198 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01199 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01200 case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
01201 default: NOT_REACHED();
01202 }
01203 }
01204
01215 static void *IntToReference(size_t index, SLRefType rt)
01216 {
01217 assert_compile(sizeof(size_t) <= sizeof(void *));
01218
01219 assert(_sl.action == SLA_PTRS);
01220
01221
01222
01223 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01224 rt = REF_VEHICLE;
01225 }
01226
01227
01228 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01229
01230
01231
01232 if (rt != REF_VEHICLE_OLD) index--;
01233
01234 switch (rt) {
01235 case REF_ORDERLIST:
01236 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01237 SlErrorCorrupt("Referencing invalid OrderList");
01238
01239 case REF_ORDER:
01240 if (Order::IsValidID(index)) return Order::Get(index);
01241
01242 if (IsSavegameVersionBefore(5, 2)) return NULL;
01243 SlErrorCorrupt("Referencing invalid Order");
01244
01245 case REF_VEHICLE_OLD:
01246 case REF_VEHICLE:
01247 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01248 SlErrorCorrupt("Referencing invalid Vehicle");
01249
01250 case REF_STATION:
01251 if (Station::IsValidID(index)) return Station::Get(index);
01252 SlErrorCorrupt("Referencing invalid Station");
01253
01254 case REF_TOWN:
01255 if (Town::IsValidID(index)) return Town::Get(index);
01256 SlErrorCorrupt("Referencing invalid Town");
01257
01258 case REF_ROADSTOPS:
01259 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01260 SlErrorCorrupt("Referencing invalid RoadStop");
01261
01262 case REF_ENGINE_RENEWS:
01263 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01264 SlErrorCorrupt("Referencing invalid EngineRenew");
01265
01266 case REF_CARGO_PACKET:
01267 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01268 SlErrorCorrupt("Referencing invalid CargoPacket");
01269
01270 case REF_STORAGE:
01271 if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index);
01272 SlErrorCorrupt("Referencing invalid PersistentStorage");
01273
01274 default: NOT_REACHED();
01275 }
01276 }
01277
01282 static inline size_t SlCalcListLen(const void *list)
01283 {
01284 const std::list<void *> *l = (const std::list<void *> *) list;
01285
01286 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01287
01288
01289 return l->size() * type_size + type_size;
01290 }
01291
01292
01298 static void SlList(void *list, SLRefType conv)
01299 {
01300
01301 if (_sl.need_length != NL_NONE) {
01302 SlSetLength(SlCalcListLen(list));
01303
01304 if (_sl.need_length == NL_CALCLENGTH) return;
01305 }
01306
01307 typedef std::list<void *> PtrList;
01308 PtrList *l = (PtrList *)list;
01309
01310 switch (_sl.action) {
01311 case SLA_SAVE: {
01312 SlWriteUint32((uint32)l->size());
01313
01314 PtrList::iterator iter;
01315 for (iter = l->begin(); iter != l->end(); ++iter) {
01316 void *ptr = *iter;
01317 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01318 }
01319 break;
01320 }
01321 case SLA_LOAD_CHECK:
01322 case SLA_LOAD: {
01323 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01324
01325
01326 for (size_t i = 0; i < length; i++) {
01327 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01328 l->push_back((void *)data);
01329 }
01330 break;
01331 }
01332 case SLA_PTRS: {
01333 PtrList temp = *l;
01334
01335 l->clear();
01336 PtrList::iterator iter;
01337 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01338 void *ptr = IntToReference((size_t)*iter, conv);
01339 l->push_back(ptr);
01340 }
01341 break;
01342 }
01343 case SLA_NULL:
01344 l->clear();
01345 break;
01346 default: NOT_REACHED();
01347 }
01348 }
01349
01350
01352 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01353 {
01354 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01355 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01356
01357 return true;
01358 }
01359
01365 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01366 {
01367 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01368 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01369 return true;
01370 }
01371
01372 return false;
01373 }
01374
01381 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01382 {
01383 size_t length = 0;
01384
01385
01386 for (; sld->cmd != SL_END; sld++) {
01387 length += SlCalcObjMemberLength(object, sld);
01388 }
01389 return length;
01390 }
01391
01392 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01393 {
01394 assert(_sl.action == SLA_SAVE);
01395
01396 switch (sld->cmd) {
01397 case SL_VAR:
01398 case SL_REF:
01399 case SL_ARR:
01400 case SL_STR:
01401 case SL_LST:
01402
01403 if (!SlIsObjectValidInSavegame(sld)) break;
01404
01405 switch (sld->cmd) {
01406 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01407 case SL_REF: return SlCalcRefLen();
01408 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01409 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01410 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01411 default: NOT_REACHED();
01412 }
01413 break;
01414 case SL_WRITEBYTE: return 1;
01415 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01416 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01417 default: NOT_REACHED();
01418 }
01419 return 0;
01420 }
01421
01422
01423 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01424 {
01425 VarType conv = GB(sld->conv, 0, 8);
01426 switch (sld->cmd) {
01427 case SL_VAR:
01428 case SL_REF:
01429 case SL_ARR:
01430 case SL_STR:
01431 case SL_LST:
01432
01433 if (!SlIsObjectValidInSavegame(sld)) return false;
01434 if (SlSkipVariableOnLoad(sld)) return false;
01435
01436 switch (sld->cmd) {
01437 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01438 case SL_REF:
01439 switch (_sl.action) {
01440 case SLA_SAVE:
01441 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01442 break;
01443 case SLA_LOAD_CHECK:
01444 case SLA_LOAD:
01445 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01446 break;
01447 case SLA_PTRS:
01448 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01449 break;
01450 case SLA_NULL:
01451 *(void **)ptr = NULL;
01452 break;
01453 default: NOT_REACHED();
01454 }
01455 break;
01456 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01457 case SL_STR: SlString(ptr, sld->length, sld->conv); break;
01458 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01459 default: NOT_REACHED();
01460 }
01461 break;
01462
01463
01464
01465
01466
01467
01468 case SL_WRITEBYTE:
01469 switch (_sl.action) {
01470 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01471 case SLA_LOAD_CHECK:
01472 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01473 case SLA_PTRS: break;
01474 case SLA_NULL: break;
01475 default: NOT_REACHED();
01476 }
01477 break;
01478
01479
01480 case SL_VEH_INCLUDE:
01481 SlObject(ptr, GetVehicleDescription(VEH_END));
01482 break;
01483
01484 case SL_ST_INCLUDE:
01485 SlObject(ptr, GetBaseStationDescription());
01486 break;
01487
01488 default: NOT_REACHED();
01489 }
01490 return true;
01491 }
01492
01498 void SlObject(void *object, const SaveLoad *sld)
01499 {
01500
01501 if (_sl.need_length != NL_NONE) {
01502 SlSetLength(SlCalcObjLength(object, sld));
01503 if (_sl.need_length == NL_CALCLENGTH) return;
01504 }
01505
01506 for (; sld->cmd != SL_END; sld++) {
01507 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01508 SlObjectMember(ptr, sld);
01509 }
01510 }
01511
01516 void SlGlobList(const SaveLoadGlobVarList *sldg)
01517 {
01518 SlObject(NULL, (const SaveLoad*)sldg);
01519 }
01520
01526 void SlAutolength(AutolengthProc *proc, void *arg)
01527 {
01528 size_t offs;
01529
01530 assert(_sl.action == SLA_SAVE);
01531
01532
01533 _sl.need_length = NL_CALCLENGTH;
01534 _sl.obj_len = 0;
01535 proc(arg);
01536
01537
01538 _sl.need_length = NL_WANTLENGTH;
01539 SlSetLength(_sl.obj_len);
01540
01541 offs = _sl.dumper->GetSize() + _sl.obj_len;
01542
01543
01544 proc(arg);
01545
01546 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01547 }
01548
01553 static void SlLoadChunk(const ChunkHandler *ch)
01554 {
01555 byte m = SlReadByte();
01556 size_t len;
01557 size_t endoffs;
01558
01559 _sl.block_mode = m;
01560 _sl.obj_len = 0;
01561
01562 switch (m) {
01563 case CH_ARRAY:
01564 _sl.array_index = 0;
01565 ch->load_proc();
01566 break;
01567 case CH_SPARSE_ARRAY:
01568 ch->load_proc();
01569 break;
01570 default:
01571 if ((m & 0xF) == CH_RIFF) {
01572
01573 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01574 len += SlReadUint16();
01575 _sl.obj_len = len;
01576 endoffs = _sl.reader->GetSize() + len;
01577 ch->load_proc();
01578 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01579 } else {
01580 SlErrorCorrupt("Invalid chunk type");
01581 }
01582 break;
01583 }
01584 }
01585
01591 static void SlLoadCheckChunk(const ChunkHandler *ch)
01592 {
01593 byte m = SlReadByte();
01594 size_t len;
01595 size_t endoffs;
01596
01597 _sl.block_mode = m;
01598 _sl.obj_len = 0;
01599
01600 switch (m) {
01601 case CH_ARRAY:
01602 _sl.array_index = 0;
01603 if (ch->load_check_proc) {
01604 ch->load_check_proc();
01605 } else {
01606 SlSkipArray();
01607 }
01608 break;
01609 case CH_SPARSE_ARRAY:
01610 if (ch->load_check_proc) {
01611 ch->load_check_proc();
01612 } else {
01613 SlSkipArray();
01614 }
01615 break;
01616 default:
01617 if ((m & 0xF) == CH_RIFF) {
01618
01619 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01620 len += SlReadUint16();
01621 _sl.obj_len = len;
01622 endoffs = _sl.reader->GetSize() + len;
01623 if (ch->load_check_proc) {
01624 ch->load_check_proc();
01625 } else {
01626 SlSkipBytes(len);
01627 }
01628 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01629 } else {
01630 SlErrorCorrupt("Invalid chunk type");
01631 }
01632 break;
01633 }
01634 }
01635
01640 static ChunkSaveLoadProc *_stub_save_proc;
01641
01647 static inline void SlStubSaveProc2(void *arg)
01648 {
01649 _stub_save_proc();
01650 }
01651
01657 static void SlStubSaveProc()
01658 {
01659 SlAutolength(SlStubSaveProc2, NULL);
01660 }
01661
01667 static void SlSaveChunk(const ChunkHandler *ch)
01668 {
01669 ChunkSaveLoadProc *proc = ch->save_proc;
01670
01671
01672 if (proc == NULL) return;
01673
01674 SlWriteUint32(ch->id);
01675 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01676
01677 if (ch->flags & CH_AUTO_LENGTH) {
01678
01679 _stub_save_proc = proc;
01680 proc = SlStubSaveProc;
01681 }
01682
01683 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01684 switch (ch->flags & CH_TYPE_MASK) {
01685 case CH_RIFF:
01686 _sl.need_length = NL_WANTLENGTH;
01687 proc();
01688 break;
01689 case CH_ARRAY:
01690 _sl.last_array_index = 0;
01691 SlWriteByte(CH_ARRAY);
01692 proc();
01693 SlWriteArrayLength(0);
01694 break;
01695 case CH_SPARSE_ARRAY:
01696 SlWriteByte(CH_SPARSE_ARRAY);
01697 proc();
01698 SlWriteArrayLength(0);
01699 break;
01700 default: NOT_REACHED();
01701 }
01702 }
01703
01705 static void SlSaveChunks()
01706 {
01707 FOR_ALL_CHUNK_HANDLERS(ch) {
01708 SlSaveChunk(ch);
01709 }
01710
01711
01712 SlWriteUint32(0);
01713 }
01714
01721 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01722 {
01723 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01724 return NULL;
01725 }
01726
01728 static void SlLoadChunks()
01729 {
01730 uint32 id;
01731 const ChunkHandler *ch;
01732
01733 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01734 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01735
01736 ch = SlFindChunkHandler(id);
01737 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01738 SlLoadChunk(ch);
01739 }
01740 }
01741
01743 static void SlLoadCheckChunks()
01744 {
01745 uint32 id;
01746 const ChunkHandler *ch;
01747
01748 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01749 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01750
01751 ch = SlFindChunkHandler(id);
01752 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01753 SlLoadCheckChunk(ch);
01754 }
01755 }
01756
01758 static void SlFixPointers()
01759 {
01760 _sl.action = SLA_PTRS;
01761
01762 DEBUG(sl, 1, "Fixing pointers");
01763
01764 FOR_ALL_CHUNK_HANDLERS(ch) {
01765 if (ch->ptrs_proc != NULL) {
01766 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01767 ch->ptrs_proc();
01768 }
01769 }
01770
01771 DEBUG(sl, 1, "All pointers fixed");
01772
01773 assert(_sl.action == SLA_PTRS);
01774 }
01775
01776
01778 struct FileReader : LoadFilter {
01779 FILE *file;
01780 long begin;
01781
01786 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01787 {
01788 }
01789
01791 ~FileReader()
01792 {
01793 if (this->file != NULL) fclose(this->file);
01794 this->file = NULL;
01795
01796
01797 _sl.sf = NULL;
01798 }
01799
01800 size_t Read(byte *buf, size_t size)
01801 {
01802
01803 if (this->file == NULL) return 0;
01804
01805 return fread(buf, 1, size, this->file);
01806 }
01807
01808 void Reset()
01809 {
01810 clearerr(this->file);
01811 fseek(this->file, this->begin, SEEK_SET);
01812 }
01813 };
01814
01816 struct FileWriter : SaveFilter {
01817 FILE *file;
01818
01823 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01824 {
01825 }
01826
01828 ~FileWriter()
01829 {
01830 this->Finish();
01831
01832
01833 _sl.sf = NULL;
01834 }
01835
01836 void Write(byte *buf, size_t size)
01837 {
01838
01839 if (this->file == NULL) return;
01840
01841 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01842 }
01843
01844 void Finish()
01845 {
01846 if (this->file != NULL) fclose(this->file);
01847 this->file = NULL;
01848 }
01849 };
01850
01851
01852
01853
01854
01855 #ifdef WITH_LZO
01856 #include <lzo/lzo1x.h>
01857
01859 static const uint LZO_BUFFER_SIZE = 8192;
01860
01862 struct LZOLoadFilter : LoadFilter {
01867 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01868 {
01869 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01870 }
01871
01872 size_t Read(byte *buf, size_t ssize)
01873 {
01874 assert(ssize >= LZO_BUFFER_SIZE);
01875
01876
01877 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01878 uint32 tmp[2];
01879 uint32 size;
01880 lzo_uint len;
01881
01882
01883 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01884
01885
01886 ((uint32*)out)[0] = size = tmp[1];
01887
01888 if (_sl_version != 0) {
01889 tmp[0] = TO_BE32(tmp[0]);
01890 size = TO_BE32(size);
01891 }
01892
01893 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01894
01895
01896 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01897
01898
01899 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01900
01901
01902 lzo1x_decompress(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01903 return len;
01904 }
01905 };
01906
01908 struct LZOSaveFilter : SaveFilter {
01914 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01915 {
01916 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01917 }
01918
01919 void Write(byte *buf, size_t size)
01920 {
01921 const lzo_bytep in = buf;
01922
01923 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01924 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01925 lzo_uint outlen;
01926
01927 do {
01928
01929 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01930 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01931 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01932 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01933 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01934
01935
01936 size -= len;
01937 in += len;
01938 } while (size > 0);
01939 }
01940 };
01941
01942 #endif
01943
01944
01945
01946
01947
01949 struct NoCompLoadFilter : LoadFilter {
01954 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01955 {
01956 }
01957
01958 size_t Read(byte *buf, size_t size)
01959 {
01960 return this->chain->Read(buf, size);
01961 }
01962 };
01963
01965 struct NoCompSaveFilter : SaveFilter {
01971 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01972 {
01973 }
01974
01975 void Write(byte *buf, size_t size)
01976 {
01977 this->chain->Write(buf, size);
01978 }
01979 };
01980
01981
01982
01983
01984
01985 #if defined(WITH_ZLIB)
01986 #include <zlib.h>
01987
01989 struct ZlibLoadFilter : LoadFilter {
01990 z_stream z;
01991 byte fread_buf[MEMORY_CHUNK_SIZE];
01992
01997 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01998 {
01999 memset(&this->z, 0, sizeof(this->z));
02000 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02001 }
02002
02004 ~ZlibLoadFilter()
02005 {
02006 inflateEnd(&this->z);
02007 }
02008
02009 size_t Read(byte *buf, size_t size)
02010 {
02011 this->z.next_out = buf;
02012 this->z.avail_out = (uint)size;
02013
02014 do {
02015
02016 if (this->z.avail_in == 0) {
02017 this->z.next_in = this->fread_buf;
02018 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02019 }
02020
02021
02022 int r = inflate(&this->z, 0);
02023 if (r == Z_STREAM_END) break;
02024
02025 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02026 } while (this->z.avail_out != 0);
02027
02028 return size - this->z.avail_out;
02029 }
02030 };
02031
02033 struct ZlibSaveFilter : SaveFilter {
02034 z_stream z;
02035
02041 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02042 {
02043 memset(&this->z, 0, sizeof(this->z));
02044 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02045 }
02046
02048 ~ZlibSaveFilter()
02049 {
02050 deflateEnd(&this->z);
02051 }
02052
02059 void WriteLoop(byte *p, size_t len, int mode)
02060 {
02061 byte buf[MEMORY_CHUNK_SIZE];
02062 uint n;
02063 this->z.next_in = p;
02064 this->z.avail_in = (uInt)len;
02065 do {
02066 this->z.next_out = buf;
02067 this->z.avail_out = sizeof(buf);
02068
02076 int r = deflate(&this->z, mode);
02077
02078
02079 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02080 this->chain->Write(buf, n);
02081 }
02082 if (r == Z_STREAM_END) break;
02083
02084 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02085 } while (this->z.avail_in || !this->z.avail_out);
02086 }
02087
02088 void Write(byte *buf, size_t size)
02089 {
02090 this->WriteLoop(buf, size, 0);
02091 }
02092
02093 void Finish()
02094 {
02095 this->WriteLoop(NULL, 0, Z_FINISH);
02096 this->chain->Finish();
02097 }
02098 };
02099
02100 #endif
02101
02102
02103
02104
02105
02106 #if defined(WITH_LZMA)
02107 #include <lzma.h>
02108
02115 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02116
02118 struct LZMALoadFilter : LoadFilter {
02119 lzma_stream lzma;
02120 byte fread_buf[MEMORY_CHUNK_SIZE];
02121
02126 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02127 {
02128
02129 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02130 }
02131
02133 ~LZMALoadFilter()
02134 {
02135 lzma_end(&this->lzma);
02136 }
02137
02138 size_t Read(byte *buf, size_t size)
02139 {
02140 this->lzma.next_out = buf;
02141 this->lzma.avail_out = size;
02142
02143 do {
02144
02145 if (this->lzma.avail_in == 0) {
02146 this->lzma.next_in = this->fread_buf;
02147 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02148 }
02149
02150
02151 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02152 if (r == LZMA_STREAM_END) break;
02153 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02154 } while (this->lzma.avail_out != 0);
02155
02156 return size - this->lzma.avail_out;
02157 }
02158 };
02159
02161 struct LZMASaveFilter : SaveFilter {
02162 lzma_stream lzma;
02163
02169 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02170 {
02171 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02172 }
02173
02175 ~LZMASaveFilter()
02176 {
02177 lzma_end(&this->lzma);
02178 }
02179
02186 void WriteLoop(byte *p, size_t len, lzma_action action)
02187 {
02188 byte buf[MEMORY_CHUNK_SIZE];
02189 size_t n;
02190 this->lzma.next_in = p;
02191 this->lzma.avail_in = len;
02192 do {
02193 this->lzma.next_out = buf;
02194 this->lzma.avail_out = sizeof(buf);
02195
02196 lzma_ret r = lzma_code(&this->lzma, action);
02197
02198
02199 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02200 this->chain->Write(buf, n);
02201 }
02202 if (r == LZMA_STREAM_END) break;
02203 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02204 } while (this->lzma.avail_in || !this->lzma.avail_out);
02205 }
02206
02207 void Write(byte *buf, size_t size)
02208 {
02209 this->WriteLoop(buf, size, LZMA_RUN);
02210 }
02211
02212 void Finish()
02213 {
02214 this->WriteLoop(NULL, 0, LZMA_FINISH);
02215 this->chain->Finish();
02216 }
02217 };
02218
02219 #endif
02220
02221
02222
02223
02224
02226 struct SaveLoadFormat {
02227 const char *name;
02228 uint32 tag;
02229
02230 LoadFilter *(*init_load)(LoadFilter *chain);
02231 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02232
02233 byte min_compression;
02234 byte default_compression;
02235 byte max_compression;
02236 };
02237
02239 static const SaveLoadFormat _saveload_formats[] = {
02240 #if defined(WITH_LZO)
02241
02242 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02243 #else
02244 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02245 #endif
02246
02247 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02248 #if defined(WITH_ZLIB)
02249
02250
02251
02252 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02253 #else
02254 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02255 #endif
02256 #if defined(WITH_LZMA)
02257
02258
02259
02260
02261
02262 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02263 #else
02264 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02265 #endif
02266 };
02267
02275 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02276 {
02277 const SaveLoadFormat *def = lastof(_saveload_formats);
02278
02279
02280 while (!def->init_write) def--;
02281
02282 if (!StrEmpty(s)) {
02283
02284 char *complevel = strrchr(s, ':');
02285 if (complevel != NULL) *complevel = '\0';
02286
02287 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02288 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02289 *compression_level = slf->default_compression;
02290 if (complevel != NULL) {
02291
02292
02293
02294 *complevel = ':';
02295 complevel++;
02296
02297
02298 char *end;
02299 long level = strtol(complevel, &end, 10);
02300 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02301 SetDParamStr(0, complevel);
02302 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL);
02303 } else {
02304 *compression_level = level;
02305 }
02306 }
02307 return slf;
02308 }
02309 }
02310
02311 SetDParamStr(0, s);
02312 SetDParamStr(1, def->name);
02313 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL);
02314
02315
02316 if (complevel != NULL) *complevel = ':';
02317 }
02318 *compression_level = def->default_compression;
02319 return def;
02320 }
02321
02322
02323 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02324 extern bool AfterLoadGame();
02325 extern bool LoadOldSaveGame(const char *file);
02326
02330 static inline void ClearSaveLoadState()
02331 {
02332 delete _sl.dumper;
02333 _sl.dumper = NULL;
02334
02335 delete _sl.sf;
02336 _sl.sf = NULL;
02337
02338 delete _sl.reader;
02339 _sl.reader = NULL;
02340
02341 delete _sl.lf;
02342 _sl.lf = NULL;
02343 }
02344
02350 static void SaveFileStart()
02351 {
02352 _sl.ff_state = _fast_forward;
02353 _fast_forward = 0;
02354 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02355
02356 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02357 _sl.saveinprogress = true;
02358 }
02359
02361 static void SaveFileDone()
02362 {
02363 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02364 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02365
02366 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02367 _sl.saveinprogress = false;
02368 }
02369
02371 void SetSaveLoadError(StringID str)
02372 {
02373 _sl.error_str = str;
02374 }
02375
02377 const char *GetSaveLoadErrorString()
02378 {
02379 SetDParam(0, _sl.error_str);
02380 SetDParamStr(1, _sl.extra_msg);
02381
02382 static char err_str[512];
02383 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02384 return err_str;
02385 }
02386
02388 static void SaveFileError()
02389 {
02390 SetDParamStr(0, GetSaveLoadErrorString());
02391 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02392 SaveFileDone();
02393 }
02394
02399 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02400 {
02401 try {
02402 byte compression;
02403 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02404
02405
02406 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02407 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02408
02409 _sl.sf = fmt->init_write(_sl.sf, compression);
02410 _sl.dumper->Flush(_sl.sf);
02411
02412 ClearSaveLoadState();
02413
02414 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02415
02416 return SL_OK;
02417 } catch (...) {
02418 ClearSaveLoadState();
02419
02420 AsyncSaveFinishProc asfp = SaveFileDone;
02421
02422
02423
02424 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02425
02426 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02427 asfp = SaveFileError;
02428 }
02429
02430 if (threaded) {
02431 SetAsyncSaveFinish(asfp);
02432 } else {
02433 asfp();
02434 }
02435 return SL_ERROR;
02436 }
02437 }
02438
02440 static void SaveFileToDiskThread(void *arg)
02441 {
02442 SaveFileToDisk(true);
02443 }
02444
02445 void WaitTillSaved()
02446 {
02447 if (_save_thread == NULL) return;
02448
02449 _save_thread->Join();
02450 delete _save_thread;
02451 _save_thread = NULL;
02452
02453
02454 ProcessAsyncSaveFinish();
02455 }
02456
02465 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02466 {
02467 assert(!_sl.saveinprogress);
02468
02469 _sl.dumper = new MemoryDumper();
02470 _sl.sf = writer;
02471
02472 _sl_version = SAVEGAME_VERSION;
02473
02474 SaveViewportBeforeSaveGame();
02475 SlSaveChunks();
02476
02477 SaveFileStart();
02478 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02479 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02480
02481 SaveOrLoadResult result = SaveFileToDisk(false);
02482 SaveFileDone();
02483
02484 return result;
02485 }
02486
02487 return SL_OK;
02488 }
02489
02496 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02497 {
02498 try {
02499 _sl.action = SLA_SAVE;
02500 return DoSave(writer, threaded);
02501 } catch (...) {
02502 ClearSaveLoadState();
02503 return SL_ERROR;
02504 }
02505 }
02506
02513 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02514 {
02515 _sl.lf = reader;
02516
02517 if (load_check) {
02518
02519 _load_check_data.Clear();
02520
02521 _load_check_data.checkable = true;
02522 }
02523
02524 uint32 hdr[2];
02525 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02526
02527
02528 const SaveLoadFormat *fmt = _saveload_formats;
02529 for (;;) {
02530
02531 if (fmt == endof(_saveload_formats)) {
02532 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02533 _sl.lf->Reset();
02534 _sl_version = 0;
02535 _sl_minor_version = 0;
02536
02537
02538 fmt = _saveload_formats;
02539 for (;;) {
02540 if (fmt == endof(_saveload_formats)) {
02541
02542 NOT_REACHED();
02543 }
02544 if (fmt->tag == TO_BE32X('OTTD')) break;
02545 fmt++;
02546 }
02547 break;
02548 }
02549
02550 if (fmt->tag == hdr[0]) {
02551
02552 _sl_version = TO_BE32(hdr[1]) >> 16;
02553
02554
02555
02556 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02557
02558 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02559
02560
02561 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02562 break;
02563 }
02564
02565 fmt++;
02566 }
02567
02568
02569 if (fmt->init_load == NULL) {
02570 char err_str[64];
02571 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02572 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02573 }
02574
02575 _sl.lf = fmt->init_load(_sl.lf);
02576 _sl.reader = new ReadBuffer(_sl.lf);
02577 _next_offs = 0;
02578
02579 if (!load_check) {
02580
02581
02582
02583 InitializeGame(256, 256, true, true);
02584
02585 GamelogReset();
02586
02587 if (IsSavegameVersionBefore(4)) {
02588
02589
02590
02591
02592
02593
02594
02595
02596
02597
02598
02599
02600
02601
02602
02603
02604
02605
02606
02607
02608
02609 ClearGRFConfigList(&_grfconfig);
02610 }
02611 }
02612
02613 if (load_check) {
02614
02615
02616 SlLoadCheckChunks();
02617 } else {
02618
02619 SlLoadChunks();
02620 SlFixPointers();
02621 }
02622
02623 ClearSaveLoadState();
02624
02625 _savegame_type = SGT_OTTD;
02626
02627 if (load_check) {
02628
02629 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02630 } else {
02631 GamelogStartAction(GLAT_LOAD);
02632
02633
02634
02635 if (!AfterLoadGame()) {
02636 GamelogStopAction();
02637 return SL_REINIT;
02638 }
02639
02640 GamelogStopAction();
02641 }
02642
02643 return SL_OK;
02644 }
02645
02651 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02652 {
02653 try {
02654 _sl.action = SLA_LOAD;
02655 return DoLoad(reader, false);
02656 } catch (...) {
02657 ClearSaveLoadState();
02658 return SL_REINIT;
02659 }
02660 }
02661
02671 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02672 {
02673
02674 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02675
02676 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02677 return SL_OK;
02678 }
02679 WaitTillSaved();
02680
02681
02682 if (mode == SL_OLD_LOAD) {
02683 InitializeGame(256, 256, true, true);
02684
02685
02686
02687
02688
02689 ClearGRFConfigList(&_grfconfig);
02690 GamelogReset();
02691 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02692 _sl_version = 0;
02693 _sl_minor_version = 0;
02694 GamelogStartAction(GLAT_LOAD);
02695 if (!AfterLoadGame()) {
02696 GamelogStopAction();
02697 return SL_REINIT;
02698 }
02699 GamelogStopAction();
02700 return SL_OK;
02701 }
02702
02703 switch (mode) {
02704 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02705 case SL_LOAD: _sl.action = SLA_LOAD; break;
02706 case SL_SAVE: _sl.action = SLA_SAVE; break;
02707 default: NOT_REACHED();
02708 }
02709
02710 try {
02711 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02712
02713
02714 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02715 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02716 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
02717
02718 if (fh == NULL) {
02719 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02720 }
02721
02722 if (mode == SL_SAVE) {
02723 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02724 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02725
02726 return DoSave(new FileWriter(fh), threaded);
02727 }
02728
02729
02730 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02731 DEBUG(desync, 1, "load: %s", filename);
02732 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02733 } catch (...) {
02734 ClearSaveLoadState();
02735
02736
02737 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02738
02739
02740 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02741 }
02742 }
02743
02745 void DoExitSave()
02746 {
02747 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02748 }
02749
02755 void GenerateDefaultSaveName(char *buf, const char *last)
02756 {
02757
02758
02759
02760 CompanyID cid = _local_company;
02761 if (!Company::IsValidID(cid)) {
02762 const Company *c;
02763 FOR_ALL_COMPANIES(c) {
02764 cid = c->index;
02765 break;
02766 }
02767 }
02768
02769 SetDParam(0, cid);
02770
02771
02772 switch (_settings_client.gui.date_format_in_default_names) {
02773 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02774 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02775 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02776 default: NOT_REACHED();
02777 }
02778 SetDParam(2, _date);
02779
02780
02781 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02782 SanitizeFilename(buf);
02783 }
02784
02785 #if 0
02786
02792 int GetSavegameType(char *file)
02793 {
02794 const SaveLoadFormat *fmt;
02795 uint32 hdr;
02796 FILE *f;
02797 int mode = SL_OLD_LOAD;
02798
02799 f = fopen(file, "rb");
02800 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02801 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02802 mode = SL_LOAD;
02803 } else {
02804
02805 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02806 if (fmt->tag == hdr) {
02807 mode = SL_LOAD;
02808 break;
02809 }
02810 }
02811 }
02812
02813 fclose(f);
02814 return mode;
02815 }
02816 #endif