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