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