00001
00002
00003
00004
00005
00006
00007
00008
00009
00024 #include "../stdafx.h"
00025 #include "../debug.h"
00026 #include "../station_base.h"
00027 #include "../thread/thread.h"
00028 #include "../town.h"
00029 #include "../network/network.h"
00030 #include "../window_func.h"
00031 #include "../strings_func.h"
00032 #include "../core/endian_func.hpp"
00033 #include "../vehicle_base.h"
00034 #include "../company_func.h"
00035 #include "../date_func.h"
00036 #include "../autoreplace_base.h"
00037 #include "../roadstop_base.h"
00038 #include "../statusbar_gui.h"
00039 #include "../fileio_func.h"
00040 #include "../gamelog.h"
00041 #include "../string_func.h"
00042 #include "../fios.h"
00043 #include "../error.h"
00044
00045 #include "table/strings.h"
00046
00047 #include "saveload_internal.h"
00048 #include "saveload_filter.h"
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247 extern const uint16 SAVEGAME_VERSION = SL_EXT_RATING;
00248
00249 SavegameType _savegame_type;
00250
00251 uint32 _ttdp_version;
00252 uint16 _sl_version;
00253 byte _sl_minor_version;
00254 char _savegame_format[8];
00255 bool _do_autosave;
00256
00258 enum SaveLoadAction {
00259 SLA_LOAD,
00260 SLA_SAVE,
00261 SLA_PTRS,
00262 SLA_NULL,
00263 SLA_LOAD_CHECK,
00264 };
00265
00266 enum NeedLength {
00267 NL_NONE = 0,
00268 NL_WANTLENGTH = 1,
00269 NL_CALCLENGTH = 2,
00270 };
00271
00273 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
00274
00276 struct ReadBuffer {
00277 byte buf[MEMORY_CHUNK_SIZE];
00278 byte *bufp;
00279 byte *bufe;
00280 LoadFilter *reader;
00281 size_t read;
00282
00287 ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
00288 {
00289 }
00290
00291 inline byte ReadByte()
00292 {
00293 if (this->bufp == this->bufe) {
00294 size_t len = this->reader->Read(this->buf, lengthof(this->buf));
00295 if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00296
00297 this->read += len;
00298 this->bufp = this->buf;
00299 this->bufe = this->buf + len;
00300 }
00301
00302 return *this->bufp++;
00303 }
00304
00309 size_t GetSize() const
00310 {
00311 return this->read - (this->bufe - this->bufp);
00312 }
00313 };
00314
00315
00317 struct MemoryDumper {
00318 AutoFreeSmallVector<byte *, 16> blocks;
00319 byte *buf;
00320 byte *bufe;
00321
00323 MemoryDumper() : buf(NULL), bufe(NULL)
00324 {
00325 }
00326
00331 inline void WriteByte(byte b)
00332 {
00333
00334 if (this->buf == this->bufe) {
00335 this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
00336 *this->blocks.Append() = this->buf;
00337 this->bufe = this->buf + MEMORY_CHUNK_SIZE;
00338 }
00339
00340 *this->buf++ = b;
00341 }
00342
00347 void Flush(SaveFilter *writer)
00348 {
00349 uint i = 0;
00350 size_t t = this->GetSize();
00351
00352 while (t > 0) {
00353 size_t to_write = min(MEMORY_CHUNK_SIZE, t);
00354
00355 writer->Write(this->blocks[i++], to_write);
00356 t -= to_write;
00357 }
00358
00359 writer->Finish();
00360 }
00361
00366 size_t GetSize() const
00367 {
00368 return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
00369 }
00370 };
00371
00373 struct SaveLoadParams {
00374 SaveLoadAction action;
00375 NeedLength need_length;
00376 byte block_mode;
00377 bool error;
00378
00379 size_t obj_len;
00380 int array_index, last_array_index;
00381
00382 MemoryDumper *dumper;
00383 SaveFilter *sf;
00384
00385 ReadBuffer *reader;
00386 LoadFilter *lf;
00387
00388 StringID error_str;
00389 char *extra_msg;
00390
00391 byte ff_state;
00392 bool saveinprogress;
00393 };
00394
00395 static SaveLoadParams _sl;
00396
00397
00398 extern const ChunkHandler _gamelog_chunk_handlers[];
00399 extern const ChunkHandler _map_chunk_handlers[];
00400 extern const ChunkHandler _misc_chunk_handlers[];
00401 extern const ChunkHandler _name_chunk_handlers[];
00402 extern const ChunkHandler _cheat_chunk_handlers[] ;
00403 extern const ChunkHandler _setting_chunk_handlers[];
00404 extern const ChunkHandler _company_chunk_handlers[];
00405 extern const ChunkHandler _engine_chunk_handlers[];
00406 extern const ChunkHandler _veh_chunk_handlers[];
00407 extern const ChunkHandler _waypoint_chunk_handlers[];
00408 extern const ChunkHandler _depot_chunk_handlers[];
00409 extern const ChunkHandler _order_chunk_handlers[];
00410 extern const ChunkHandler _town_chunk_handlers[];
00411 extern const ChunkHandler _sign_chunk_handlers[];
00412 extern const ChunkHandler _station_chunk_handlers[];
00413 extern const ChunkHandler _industry_chunk_handlers[];
00414 extern const ChunkHandler _economy_chunk_handlers[];
00415 extern const ChunkHandler _subsidy_chunk_handlers[];
00416 extern const ChunkHandler _cargomonitor_chunk_handlers[];
00417 extern const ChunkHandler _goal_chunk_handlers[];
00418 extern const ChunkHandler _ai_chunk_handlers[];
00419 extern const ChunkHandler _game_chunk_handlers[];
00420 extern const ChunkHandler _animated_tile_chunk_handlers[];
00421 extern const ChunkHandler _newgrf_chunk_handlers[];
00422 extern const ChunkHandler _group_chunk_handlers[];
00423 extern const ChunkHandler _cargopacket_chunk_handlers[];
00424 extern const ChunkHandler _autoreplace_chunk_handlers[];
00425 extern const ChunkHandler _labelmaps_chunk_handlers[];
00426 extern const ChunkHandler _linkgraph_chunk_handlers[];
00427 extern const ChunkHandler _airport_chunk_handlers[];
00428 extern const ChunkHandler _object_chunk_handlers[];
00429 extern const ChunkHandler _persistent_storage_chunk_handlers[];
00430
00432 static const ChunkHandler * const _chunk_handlers[] = {
00433 _gamelog_chunk_handlers,
00434 _map_chunk_handlers,
00435 _misc_chunk_handlers,
00436 _name_chunk_handlers,
00437 _cheat_chunk_handlers,
00438 _setting_chunk_handlers,
00439 _veh_chunk_handlers,
00440 _waypoint_chunk_handlers,
00441 _depot_chunk_handlers,
00442 _order_chunk_handlers,
00443 _industry_chunk_handlers,
00444 _economy_chunk_handlers,
00445 _subsidy_chunk_handlers,
00446 _cargomonitor_chunk_handlers,
00447 _goal_chunk_handlers,
00448 _engine_chunk_handlers,
00449 _town_chunk_handlers,
00450 _sign_chunk_handlers,
00451 _station_chunk_handlers,
00452 _company_chunk_handlers,
00453 _ai_chunk_handlers,
00454 _game_chunk_handlers,
00455 _animated_tile_chunk_handlers,
00456 _newgrf_chunk_handlers,
00457 _group_chunk_handlers,
00458 _cargopacket_chunk_handlers,
00459 _autoreplace_chunk_handlers,
00460 _labelmaps_chunk_handlers,
00461 _linkgraph_chunk_handlers,
00462 _airport_chunk_handlers,
00463 _object_chunk_handlers,
00464 _persistent_storage_chunk_handlers,
00465 NULL,
00466 };
00467
00472 #define FOR_ALL_CHUNK_HANDLERS(ch) \
00473 for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \
00474 for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1)
00475
00477 static void SlNullPointers()
00478 {
00479 _sl.action = SLA_NULL;
00480
00481
00482
00483
00484 _sl_version = SAVEGAME_VERSION;
00485
00486 DEBUG(sl, 1, "Nulling pointers");
00487
00488 FOR_ALL_CHUNK_HANDLERS(ch) {
00489 if (ch->ptrs_proc != NULL) {
00490 DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00491 ch->ptrs_proc();
00492 }
00493 }
00494
00495 DEBUG(sl, 1, "All pointers nulled");
00496
00497 assert(_sl.action == SLA_NULL);
00498 }
00499
00508 void NORETURN SlError(StringID string, const char *extra_msg)
00509 {
00510
00511 if (_sl.action == SLA_LOAD_CHECK) {
00512 _load_check_data.error = string;
00513 free(_load_check_data.error_data);
00514 _load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00515 } else {
00516 _sl.error_str = string;
00517 free(_sl.extra_msg);
00518 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00519 }
00520
00521
00522
00523
00524
00525 if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00526 throw std::exception();
00527 }
00528
00536 void NORETURN SlErrorCorrupt(const char *msg)
00537 {
00538 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00539 }
00540
00541
00542 typedef void (*AsyncSaveFinishProc)();
00543 static AsyncSaveFinishProc _async_save_finish = NULL;
00544 static ThreadObject *_save_thread;
00545
00550 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00551 {
00552 if (_exit_game) return;
00553 while (_async_save_finish != NULL) CSleep(10);
00554
00555 _async_save_finish = proc;
00556 }
00557
00561 void ProcessAsyncSaveFinish()
00562 {
00563 if (_async_save_finish == NULL) return;
00564
00565 _async_save_finish();
00566
00567 _async_save_finish = NULL;
00568
00569 if (_save_thread != NULL) {
00570 _save_thread->Join();
00571 delete _save_thread;
00572 _save_thread = NULL;
00573 }
00574 }
00575
00580 byte SlReadByte()
00581 {
00582 return _sl.reader->ReadByte();
00583 }
00584
00589 void SlWriteByte(byte b)
00590 {
00591 _sl.dumper->WriteByte(b);
00592 }
00593
00594 static inline int SlReadUint16()
00595 {
00596 int x = SlReadByte() << 8;
00597 return x | SlReadByte();
00598 }
00599
00600 static inline uint32 SlReadUint32()
00601 {
00602 uint32 x = SlReadUint16() << 16;
00603 return x | SlReadUint16();
00604 }
00605
00606 static inline uint64 SlReadUint64()
00607 {
00608 uint32 x = SlReadUint32();
00609 uint32 y = SlReadUint32();
00610 return (uint64)x << 32 | y;
00611 }
00612
00613 static inline void SlWriteUint16(uint16 v)
00614 {
00615 SlWriteByte(GB(v, 8, 8));
00616 SlWriteByte(GB(v, 0, 8));
00617 }
00618
00619 static inline void SlWriteUint32(uint32 v)
00620 {
00621 SlWriteUint16(GB(v, 16, 16));
00622 SlWriteUint16(GB(v, 0, 16));
00623 }
00624
00625 static inline void SlWriteUint64(uint64 x)
00626 {
00627 SlWriteUint32((uint32)(x >> 32));
00628 SlWriteUint32((uint32)x);
00629 }
00630
00636 static inline void SlSkipBytes(size_t length)
00637 {
00638 for (; length != 0; length--) SlReadByte();
00639 }
00640
00650 static uint SlReadSimpleGamma()
00651 {
00652 uint i = SlReadByte();
00653 if (HasBit(i, 7)) {
00654 i &= ~0x80;
00655 if (HasBit(i, 6)) {
00656 i &= ~0x40;
00657 if (HasBit(i, 5)) {
00658 i &= ~0x20;
00659 if (HasBit(i, 4)) {
00660 SlErrorCorrupt("Unsupported gamma");
00661 }
00662 i = (i << 8) | SlReadByte();
00663 }
00664 i = (i << 8) | SlReadByte();
00665 }
00666 i = (i << 8) | SlReadByte();
00667 }
00668 return i;
00669 }
00670
00683 static void SlWriteSimpleGamma(size_t i)
00684 {
00685 if (i >= (1 << 7)) {
00686 if (i >= (1 << 14)) {
00687 if (i >= (1 << 21)) {
00688 assert(i < (1 << 28));
00689 SlWriteByte((byte)(0xE0 | (i >> 24)));
00690 SlWriteByte((byte)(i >> 16));
00691 } else {
00692 SlWriteByte((byte)(0xC0 | (i >> 16)));
00693 }
00694 SlWriteByte((byte)(i >> 8));
00695 } else {
00696 SlWriteByte((byte)(0x80 | (i >> 8)));
00697 }
00698 }
00699 SlWriteByte((byte)i);
00700 }
00701
00703 static inline uint SlGetGammaLength(size_t i)
00704 {
00705 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00706 }
00707
00708 static inline uint SlReadSparseIndex()
00709 {
00710 return SlReadSimpleGamma();
00711 }
00712
00713 static inline void SlWriteSparseIndex(uint index)
00714 {
00715 SlWriteSimpleGamma(index);
00716 }
00717
00718 static inline uint SlReadArrayLength()
00719 {
00720 return SlReadSimpleGamma();
00721 }
00722
00723 static inline void SlWriteArrayLength(size_t length)
00724 {
00725 SlWriteSimpleGamma(length);
00726 }
00727
00728 static inline uint SlGetArrayLength(size_t length)
00729 {
00730 return SlGetGammaLength(length);
00731 }
00732
00739 static inline uint SlCalcConvMemLen(VarType conv)
00740 {
00741 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00742 byte length = GB(conv, 4, 4);
00743
00744 switch (length << 4) {
00745 case SLE_VAR_STRB:
00746 case SLE_VAR_STRBQ:
00747 case SLE_VAR_STR:
00748 case SLE_VAR_STRQ:
00749 return SlReadArrayLength();
00750
00751 default:
00752 assert(length < lengthof(conv_mem_size));
00753 return conv_mem_size[length];
00754 }
00755 }
00756
00763 static inline byte SlCalcConvFileLen(VarType conv)
00764 {
00765 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00766 byte length = GB(conv, 0, 4);
00767 assert(length < lengthof(conv_file_size));
00768 return conv_file_size[length];
00769 }
00770
00772 static inline size_t SlCalcRefLen()
00773 {
00774 return IsSavegameVersionBefore(69) ? 2 : 4;
00775 }
00776
00777 void SlSetArrayIndex(uint index)
00778 {
00779 _sl.need_length = NL_WANTLENGTH;
00780 _sl.array_index = index;
00781 }
00782
00783 static size_t _next_offs;
00784
00789 int SlIterateArray()
00790 {
00791 int index;
00792
00793
00794
00795 if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00796
00797 for (;;) {
00798 uint length = SlReadArrayLength();
00799 if (length == 0) {
00800 _next_offs = 0;
00801 return -1;
00802 }
00803
00804 _sl.obj_len = --length;
00805 _next_offs = _sl.reader->GetSize() + length;
00806
00807 switch (_sl.block_mode) {
00808 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00809 case CH_ARRAY: index = _sl.array_index++; break;
00810 default:
00811 DEBUG(sl, 0, "SlIterateArray error");
00812 return -1;
00813 }
00814
00815 if (length != 0) return index;
00816 }
00817 }
00818
00822 void SlSkipArray()
00823 {
00824 while (SlIterateArray() != -1) {
00825 SlSkipBytes(_next_offs - _sl.reader->GetSize());
00826 }
00827 }
00828
00834 void SlSetLength(size_t length)
00835 {
00836 assert(_sl.action == SLA_SAVE);
00837
00838 switch (_sl.need_length) {
00839 case NL_WANTLENGTH:
00840 _sl.need_length = NL_NONE;
00841 switch (_sl.block_mode) {
00842 case CH_RIFF:
00843
00844
00845
00846 assert(length < (1 << 28));
00847 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00848 break;
00849 case CH_ARRAY:
00850 assert(_sl.last_array_index <= _sl.array_index);
00851 while (++_sl.last_array_index <= _sl.array_index) {
00852 SlWriteArrayLength(1);
00853 }
00854 SlWriteArrayLength(length + 1);
00855 break;
00856 case CH_SPARSE_ARRAY:
00857 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00858 SlWriteSparseIndex(_sl.array_index);
00859 break;
00860 default: NOT_REACHED();
00861 }
00862 break;
00863
00864 case NL_CALCLENGTH:
00865 _sl.obj_len += (int)length;
00866 break;
00867
00868 default: NOT_REACHED();
00869 }
00870 }
00871
00878 static void SlCopyBytes(void *ptr, size_t length)
00879 {
00880 byte *p = (byte *)ptr;
00881
00882 switch (_sl.action) {
00883 case SLA_LOAD_CHECK:
00884 case SLA_LOAD:
00885 for (; length != 0; length--) *p++ = SlReadByte();
00886 break;
00887 case SLA_SAVE:
00888 for (; length != 0; length--) SlWriteByte(*p++);
00889 break;
00890 default: NOT_REACHED();
00891 }
00892 }
00893
00895 size_t SlGetFieldLength()
00896 {
00897 return _sl.obj_len;
00898 }
00899
00907 int64 ReadValue(const void *ptr, VarType conv)
00908 {
00909 switch (GetVarMemType(conv)) {
00910 case SLE_VAR_BL: return (*(const bool *)ptr != 0);
00911 case SLE_VAR_I8: return *(const int8 *)ptr;
00912 case SLE_VAR_U8: return *(const byte *)ptr;
00913 case SLE_VAR_I16: return *(const int16 *)ptr;
00914 case SLE_VAR_U16: return *(const uint16*)ptr;
00915 case SLE_VAR_I32: return *(const int32 *)ptr;
00916 case SLE_VAR_U32: return *(const uint32*)ptr;
00917 case SLE_VAR_I64: return *(const int64 *)ptr;
00918 case SLE_VAR_U64: return *(const uint64*)ptr;
00919 case SLE_VAR_NULL:return 0;
00920 default: NOT_REACHED();
00921 }
00922 }
00923
00931 void WriteValue(void *ptr, VarType conv, int64 val)
00932 {
00933 switch (GetVarMemType(conv)) {
00934 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00935 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00936 case SLE_VAR_U8: *(byte *)ptr = val; break;
00937 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00938 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00939 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00940 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00941 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00942 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00943 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00944 case SLE_VAR_NULL: break;
00945 default: NOT_REACHED();
00946 }
00947 }
00948
00957 static void SlSaveLoadConv(void *ptr, VarType conv)
00958 {
00959 switch (_sl.action) {
00960 case SLA_SAVE: {
00961 int64 x = ReadValue(ptr, conv);
00962
00963
00964 switch (GetVarFileType(conv)) {
00965 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00966 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00967 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00968 case SLE_FILE_STRINGID:
00969 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00970 case SLE_FILE_I32:
00971 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00972 case SLE_FILE_I64:
00973 case SLE_FILE_U64: SlWriteUint64(x);break;
00974 default: NOT_REACHED();
00975 }
00976 break;
00977 }
00978 case SLA_LOAD_CHECK:
00979 case SLA_LOAD: {
00980 int64 x;
00981
00982 switch (GetVarFileType(conv)) {
00983 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00984 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00985 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00986 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00987 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00988 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00989 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00990 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00991 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00992 default: NOT_REACHED();
00993 }
00994
00995
00996 WriteValue(ptr, conv, x);
00997 break;
00998 }
00999 case SLA_PTRS: break;
01000 case SLA_NULL: break;
01001 default: NOT_REACHED();
01002 }
01003 }
01004
01014 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
01015 {
01016 if (ptr == NULL) return 0;
01017 return min(strlen(ptr), length - 1);
01018 }
01019
01029 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
01030 {
01031 size_t len;
01032 const char *str;
01033
01034 switch (GetVarMemType(conv)) {
01035 default: NOT_REACHED();
01036 case SLE_VAR_STR:
01037 case SLE_VAR_STRQ:
01038 str = *(const char * const *)ptr;
01039 len = SIZE_MAX;
01040 break;
01041 case SLE_VAR_STRB:
01042 case SLE_VAR_STRBQ:
01043 str = (const char *)ptr;
01044 len = length;
01045 break;
01046 }
01047
01048 len = SlCalcNetStringLen(str, len);
01049 return len + SlGetArrayLength(len);
01050 }
01051
01058 static void SlString(void *ptr, size_t length, VarType conv)
01059 {
01060 switch (_sl.action) {
01061 case SLA_SAVE: {
01062 size_t len;
01063 switch (GetVarMemType(conv)) {
01064 default: NOT_REACHED();
01065 case SLE_VAR_STRB:
01066 case SLE_VAR_STRBQ:
01067 len = SlCalcNetStringLen((char *)ptr, length);
01068 break;
01069 case SLE_VAR_STR:
01070 case SLE_VAR_STRQ:
01071 ptr = *(char **)ptr;
01072 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01073 break;
01074 }
01075
01076 SlWriteArrayLength(len);
01077 SlCopyBytes(ptr, len);
01078 break;
01079 }
01080 case SLA_LOAD_CHECK:
01081 case SLA_LOAD: {
01082 size_t len = SlReadArrayLength();
01083
01084 switch (GetVarMemType(conv)) {
01085 default: NOT_REACHED();
01086 case SLE_VAR_STRB:
01087 case SLE_VAR_STRBQ:
01088 if (len >= length) {
01089 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01090 SlCopyBytes(ptr, length);
01091 SlSkipBytes(len - length);
01092 len = length - 1;
01093 } else {
01094 SlCopyBytes(ptr, len);
01095 }
01096 break;
01097 case SLE_VAR_STR:
01098 case SLE_VAR_STRQ:
01099 free(*(char **)ptr);
01100 if (len == 0) {
01101 *(char **)ptr = NULL;
01102 return;
01103 } else {
01104 *(char **)ptr = MallocT<char>(len + 1);
01105 ptr = *(char **)ptr;
01106 SlCopyBytes(ptr, len);
01107 }
01108 break;
01109 }
01110
01111 ((char *)ptr)[len] = '\0';
01112 StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
01113 if ((conv & SLF_ALLOW_CONTROL) != 0) {
01114 settings = settings | SVS_ALLOW_CONTROL_CODE;
01115 if (IsSavegameVersionBefore(169)) {
01116 str_fix_scc_encoded((char *)ptr, (char *)ptr + len);
01117 }
01118 }
01119 if ((conv & SLF_ALLOW_NEWLINE) != 0) {
01120 settings = settings | SVS_ALLOW_NEWLINE;
01121 }
01122 str_validate((char *)ptr, (char *)ptr + len, settings);
01123 break;
01124 }
01125 case SLA_PTRS: break;
01126 case SLA_NULL: break;
01127 default: NOT_REACHED();
01128 }
01129 }
01130
01136 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01137 {
01138 return SlCalcConvFileLen(conv) * length;
01139 }
01140
01147 void SlArray(void *array, size_t length, VarType conv)
01148 {
01149 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01150
01151
01152 if (_sl.need_length != NL_NONE) {
01153 SlSetLength(SlCalcArrayLen(length, conv));
01154
01155 if (_sl.need_length == NL_CALCLENGTH) return;
01156 }
01157
01158
01159
01160 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01161
01162 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01163 conv == SLE_INT32 || conv == SLE_UINT32) {
01164 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01165 return;
01166 }
01167
01168 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01169 for (uint i = 0; i < length; i++) {
01170 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01171 }
01172 return;
01173 }
01174 }
01175
01176
01177
01178 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01179 SlCopyBytes(array, length);
01180 } else {
01181 byte *a = (byte*)array;
01182 byte mem_size = SlCalcConvMemLen(conv);
01183
01184 for (; length != 0; length --) {
01185 SlSaveLoadConv(a, conv);
01186 a += mem_size;
01187 }
01188 }
01189 }
01190
01191
01202 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01203 {
01204 assert(_sl.action == SLA_SAVE);
01205
01206 if (obj == NULL) return 0;
01207
01208 switch (rt) {
01209 case REF_VEHICLE_OLD:
01210 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01211 case REF_STATION: return ((const Station*)obj)->index + 1;
01212 case REF_TOWN: return ((const Town*)obj)->index + 1;
01213 case REF_ORDER: return ((const Order*)obj)->index + 1;
01214 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01215 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01216 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01217 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01218 case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
01219 default: NOT_REACHED();
01220 }
01221 }
01222
01233 static void *IntToReference(size_t index, SLRefType rt)
01234 {
01235 assert_compile(sizeof(size_t) <= sizeof(void *));
01236
01237 assert(_sl.action == SLA_PTRS);
01238
01239
01240
01241 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01242 rt = REF_VEHICLE;
01243 }
01244
01245
01246 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01247
01248
01249
01250 if (rt != REF_VEHICLE_OLD) index--;
01251
01252 switch (rt) {
01253 case REF_ORDERLIST:
01254 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01255 SlErrorCorrupt("Referencing invalid OrderList");
01256
01257 case REF_ORDER:
01258 if (Order::IsValidID(index)) return Order::Get(index);
01259
01260 if (IsSavegameVersionBefore(5, 2)) return NULL;
01261 SlErrorCorrupt("Referencing invalid Order");
01262
01263 case REF_VEHICLE_OLD:
01264 case REF_VEHICLE:
01265 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01266 SlErrorCorrupt("Referencing invalid Vehicle");
01267
01268 case REF_STATION:
01269 if (Station::IsValidID(index)) return Station::Get(index);
01270 SlErrorCorrupt("Referencing invalid Station");
01271
01272 case REF_TOWN:
01273 if (Town::IsValidID(index)) return Town::Get(index);
01274 SlErrorCorrupt("Referencing invalid Town");
01275
01276 case REF_ROADSTOPS:
01277 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01278 SlErrorCorrupt("Referencing invalid RoadStop");
01279
01280 case REF_ENGINE_RENEWS:
01281 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01282 SlErrorCorrupt("Referencing invalid EngineRenew");
01283
01284 case REF_CARGO_PACKET:
01285 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01286 SlErrorCorrupt("Referencing invalid CargoPacket");
01287
01288 case REF_STORAGE:
01289 if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index);
01290 SlErrorCorrupt("Referencing invalid PersistentStorage");
01291
01292 default: NOT_REACHED();
01293 }
01294 }
01295
01300 static inline size_t SlCalcListLen(const void *list)
01301 {
01302 const std::list<void *> *l = (const std::list<void *> *) list;
01303
01304 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01305
01306
01307 return l->size() * type_size + type_size;
01308 }
01309
01310
01316 static void SlList(void *list, SLRefType conv)
01317 {
01318
01319 if (_sl.need_length != NL_NONE) {
01320 SlSetLength(SlCalcListLen(list));
01321
01322 if (_sl.need_length == NL_CALCLENGTH) return;
01323 }
01324
01325 typedef std::list<void *> PtrList;
01326 PtrList *l = (PtrList *)list;
01327
01328 switch (_sl.action) {
01329 case SLA_SAVE: {
01330 SlWriteUint32((uint32)l->size());
01331
01332 PtrList::iterator iter;
01333 for (iter = l->begin(); iter != l->end(); ++iter) {
01334 void *ptr = *iter;
01335 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01336 }
01337 break;
01338 }
01339 case SLA_LOAD_CHECK:
01340 case SLA_LOAD: {
01341 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01342
01343
01344 for (size_t i = 0; i < length; i++) {
01345 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01346 l->push_back((void *)data);
01347 }
01348 break;
01349 }
01350 case SLA_PTRS: {
01351 PtrList temp = *l;
01352
01353 l->clear();
01354 PtrList::iterator iter;
01355 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01356 void *ptr = IntToReference((size_t)*iter, conv);
01357 l->push_back(ptr);
01358 }
01359 break;
01360 }
01361 case SLA_NULL:
01362 l->clear();
01363 break;
01364 default: NOT_REACHED();
01365 }
01366 }
01367
01368
01370 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01371 {
01372 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01373 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01374
01375 return true;
01376 }
01377
01383 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01384 {
01385 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01386 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01387 return true;
01388 }
01389
01390 return false;
01391 }
01392
01399 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01400 {
01401 size_t length = 0;
01402
01403
01404 for (; sld->cmd != SL_END; sld++) {
01405 length += SlCalcObjMemberLength(object, sld);
01406 }
01407 return length;
01408 }
01409
01410 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01411 {
01412 assert(_sl.action == SLA_SAVE);
01413
01414 switch (sld->cmd) {
01415 case SL_VAR:
01416 case SL_REF:
01417 case SL_ARR:
01418 case SL_STR:
01419 case SL_LST:
01420
01421 if (!SlIsObjectValidInSavegame(sld)) break;
01422
01423 switch (sld->cmd) {
01424 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01425 case SL_REF: return SlCalcRefLen();
01426 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01427 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01428 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01429 default: NOT_REACHED();
01430 }
01431 break;
01432 case SL_WRITEBYTE: return 1;
01433 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01434 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01435 default: NOT_REACHED();
01436 }
01437 return 0;
01438 }
01439
01440
01441 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01442 {
01443 VarType conv = GB(sld->conv, 0, 8);
01444 switch (sld->cmd) {
01445 case SL_VAR:
01446 case SL_REF:
01447 case SL_ARR:
01448 case SL_STR:
01449 case SL_LST:
01450
01451 if (!SlIsObjectValidInSavegame(sld)) return false;
01452 if (SlSkipVariableOnLoad(sld)) return false;
01453
01454 switch (sld->cmd) {
01455 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01456 case SL_REF:
01457 switch (_sl.action) {
01458 case SLA_SAVE:
01459 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01460 break;
01461 case SLA_LOAD_CHECK:
01462 case SLA_LOAD:
01463 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01464 break;
01465 case SLA_PTRS:
01466 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01467 break;
01468 case SLA_NULL:
01469 *(void **)ptr = NULL;
01470 break;
01471 default: NOT_REACHED();
01472 }
01473 break;
01474 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01475 case SL_STR: SlString(ptr, sld->length, sld->conv); break;
01476 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01477 default: NOT_REACHED();
01478 }
01479 break;
01480
01481
01482
01483
01484
01485
01486 case SL_WRITEBYTE:
01487 switch (_sl.action) {
01488 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01489 case SLA_LOAD_CHECK:
01490 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01491 case SLA_PTRS: break;
01492 case SLA_NULL: break;
01493 default: NOT_REACHED();
01494 }
01495 break;
01496
01497
01498 case SL_VEH_INCLUDE:
01499 SlObject(ptr, GetVehicleDescription(VEH_END));
01500 break;
01501
01502 case SL_ST_INCLUDE:
01503 SlObject(ptr, GetBaseStationDescription());
01504 break;
01505
01506 default: NOT_REACHED();
01507 }
01508 return true;
01509 }
01510
01516 void SlObject(void *object, const SaveLoad *sld)
01517 {
01518
01519 if (_sl.need_length != NL_NONE) {
01520 SlSetLength(SlCalcObjLength(object, sld));
01521 if (_sl.need_length == NL_CALCLENGTH) return;
01522 }
01523
01524 for (; sld->cmd != SL_END; sld++) {
01525 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01526 SlObjectMember(ptr, sld);
01527 }
01528 }
01529
01534 void SlGlobList(const SaveLoadGlobVarList *sldg)
01535 {
01536 SlObject(NULL, (const SaveLoad*)sldg);
01537 }
01538
01544 void SlAutolength(AutolengthProc *proc, void *arg)
01545 {
01546 size_t offs;
01547
01548 assert(_sl.action == SLA_SAVE);
01549
01550
01551 _sl.need_length = NL_CALCLENGTH;
01552 _sl.obj_len = 0;
01553 proc(arg);
01554
01555
01556 _sl.need_length = NL_WANTLENGTH;
01557 SlSetLength(_sl.obj_len);
01558
01559 offs = _sl.dumper->GetSize() + _sl.obj_len;
01560
01561
01562 proc(arg);
01563
01564 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01565 }
01566
01571 static void SlLoadChunk(const ChunkHandler *ch)
01572 {
01573 byte m = SlReadByte();
01574 size_t len;
01575 size_t endoffs;
01576
01577 _sl.block_mode = m;
01578 _sl.obj_len = 0;
01579
01580 switch (m) {
01581 case CH_ARRAY:
01582 _sl.array_index = 0;
01583 ch->load_proc();
01584 break;
01585 case CH_SPARSE_ARRAY:
01586 ch->load_proc();
01587 break;
01588 default:
01589 if ((m & 0xF) == CH_RIFF) {
01590
01591 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01592 len += SlReadUint16();
01593 _sl.obj_len = len;
01594 endoffs = _sl.reader->GetSize() + len;
01595 ch->load_proc();
01596 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01597 } else {
01598 SlErrorCorrupt("Invalid chunk type");
01599 }
01600 break;
01601 }
01602 }
01603
01609 static void SlLoadCheckChunk(const ChunkHandler *ch)
01610 {
01611 byte m = SlReadByte();
01612 size_t len;
01613 size_t endoffs;
01614
01615 _sl.block_mode = m;
01616 _sl.obj_len = 0;
01617
01618 switch (m) {
01619 case CH_ARRAY:
01620 _sl.array_index = 0;
01621 if (ch->load_check_proc) {
01622 ch->load_check_proc();
01623 } else {
01624 SlSkipArray();
01625 }
01626 break;
01627 case CH_SPARSE_ARRAY:
01628 if (ch->load_check_proc) {
01629 ch->load_check_proc();
01630 } else {
01631 SlSkipArray();
01632 }
01633 break;
01634 default:
01635 if ((m & 0xF) == CH_RIFF) {
01636
01637 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01638 len += SlReadUint16();
01639 _sl.obj_len = len;
01640 endoffs = _sl.reader->GetSize() + len;
01641 if (ch->load_check_proc) {
01642 ch->load_check_proc();
01643 } else {
01644 SlSkipBytes(len);
01645 }
01646 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01647 } else {
01648 SlErrorCorrupt("Invalid chunk type");
01649 }
01650 break;
01651 }
01652 }
01653
01658 static ChunkSaveLoadProc *_stub_save_proc;
01659
01665 static inline void SlStubSaveProc2(void *arg)
01666 {
01667 _stub_save_proc();
01668 }
01669
01675 static void SlStubSaveProc()
01676 {
01677 SlAutolength(SlStubSaveProc2, NULL);
01678 }
01679
01685 static void SlSaveChunk(const ChunkHandler *ch)
01686 {
01687 ChunkSaveLoadProc *proc = ch->save_proc;
01688
01689
01690 if (proc == NULL) return;
01691
01692 SlWriteUint32(ch->id);
01693 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01694
01695 if (ch->flags & CH_AUTO_LENGTH) {
01696
01697 _stub_save_proc = proc;
01698 proc = SlStubSaveProc;
01699 }
01700
01701 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01702 switch (ch->flags & CH_TYPE_MASK) {
01703 case CH_RIFF:
01704 _sl.need_length = NL_WANTLENGTH;
01705 proc();
01706 break;
01707 case CH_ARRAY:
01708 _sl.last_array_index = 0;
01709 SlWriteByte(CH_ARRAY);
01710 proc();
01711 SlWriteArrayLength(0);
01712 break;
01713 case CH_SPARSE_ARRAY:
01714 SlWriteByte(CH_SPARSE_ARRAY);
01715 proc();
01716 SlWriteArrayLength(0);
01717 break;
01718 default: NOT_REACHED();
01719 }
01720 }
01721
01723 static void SlSaveChunks()
01724 {
01725 FOR_ALL_CHUNK_HANDLERS(ch) {
01726 SlSaveChunk(ch);
01727 }
01728
01729
01730 SlWriteUint32(0);
01731 }
01732
01739 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01740 {
01741 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01742 return NULL;
01743 }
01744
01746 static void SlLoadChunks()
01747 {
01748 uint32 id;
01749 const ChunkHandler *ch;
01750
01751 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01752 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01753
01754 ch = SlFindChunkHandler(id);
01755 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01756 SlLoadChunk(ch);
01757 }
01758 }
01759
01761 static void SlLoadCheckChunks()
01762 {
01763 uint32 id;
01764 const ChunkHandler *ch;
01765
01766 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01767 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01768
01769 ch = SlFindChunkHandler(id);
01770 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01771 SlLoadCheckChunk(ch);
01772 }
01773 }
01774
01776 static void SlFixPointers()
01777 {
01778 _sl.action = SLA_PTRS;
01779
01780 DEBUG(sl, 1, "Fixing pointers");
01781
01782 FOR_ALL_CHUNK_HANDLERS(ch) {
01783 if (ch->ptrs_proc != NULL) {
01784 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01785 ch->ptrs_proc();
01786 }
01787 }
01788
01789 DEBUG(sl, 1, "All pointers fixed");
01790
01791 assert(_sl.action == SLA_PTRS);
01792 }
01793
01794
01796 struct FileReader : LoadFilter {
01797 FILE *file;
01798 long begin;
01799
01804 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01805 {
01806 }
01807
01809 ~FileReader()
01810 {
01811 if (this->file != NULL) fclose(this->file);
01812 this->file = NULL;
01813
01814
01815 _sl.sf = NULL;
01816 }
01817
01818 size_t Read(byte *buf, size_t size)
01819 {
01820
01821 if (this->file == NULL) return 0;
01822
01823 return fread(buf, 1, size, this->file);
01824 }
01825
01826 void Reset()
01827 {
01828 clearerr(this->file);
01829 fseek(this->file, this->begin, SEEK_SET);
01830 }
01831 };
01832
01834 struct FileWriter : SaveFilter {
01835 FILE *file;
01836
01841 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01842 {
01843 }
01844
01846 ~FileWriter()
01847 {
01848 this->Finish();
01849
01850
01851 _sl.sf = NULL;
01852 }
01853
01854 void Write(byte *buf, size_t size)
01855 {
01856
01857 if (this->file == NULL) return;
01858
01859 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01860 }
01861
01862 void Finish()
01863 {
01864 if (this->file != NULL) fclose(this->file);
01865 this->file = NULL;
01866 }
01867 };
01868
01869
01870
01871
01872
01873 #ifdef WITH_LZO
01874 #include <lzo/lzo1x.h>
01875
01877 static const uint LZO_BUFFER_SIZE = 8192;
01878
01880 struct LZOLoadFilter : LoadFilter {
01885 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01886 {
01887 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01888 }
01889
01890 size_t Read(byte *buf, size_t ssize)
01891 {
01892 assert(ssize >= LZO_BUFFER_SIZE);
01893
01894
01895 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01896 uint32 tmp[2];
01897 uint32 size;
01898 lzo_uint len;
01899
01900
01901 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01902
01903
01904 ((uint32*)out)[0] = size = tmp[1];
01905
01906 if (_sl_version != 0) {
01907 tmp[0] = TO_BE32(tmp[0]);
01908 size = TO_BE32(size);
01909 }
01910
01911 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01912
01913
01914 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01915
01916
01917 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01918
01919
01920 lzo1x_decompress_safe(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01921 return len;
01922 }
01923 };
01924
01926 struct LZOSaveFilter : SaveFilter {
01932 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01933 {
01934 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01935 }
01936
01937 void Write(byte *buf, size_t size)
01938 {
01939 const lzo_bytep in = buf;
01940
01941 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01942 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01943 lzo_uint outlen;
01944
01945 do {
01946
01947 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01948 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01949 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01950 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01951 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01952
01953
01954 size -= len;
01955 in += len;
01956 } while (size > 0);
01957 }
01958 };
01959
01960 #endif
01961
01962
01963
01964
01965
01967 struct NoCompLoadFilter : LoadFilter {
01972 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01973 {
01974 }
01975
01976 size_t Read(byte *buf, size_t size)
01977 {
01978 return this->chain->Read(buf, size);
01979 }
01980 };
01981
01983 struct NoCompSaveFilter : SaveFilter {
01989 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01990 {
01991 }
01992
01993 void Write(byte *buf, size_t size)
01994 {
01995 this->chain->Write(buf, size);
01996 }
01997 };
01998
01999
02000
02001
02002
02003 #if defined(WITH_ZLIB)
02004 #include <zlib.h>
02005
02007 struct ZlibLoadFilter : LoadFilter {
02008 z_stream z;
02009 byte fread_buf[MEMORY_CHUNK_SIZE];
02010
02015 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
02016 {
02017 memset(&this->z, 0, sizeof(this->z));
02018 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02019 }
02020
02022 ~ZlibLoadFilter()
02023 {
02024 inflateEnd(&this->z);
02025 }
02026
02027 size_t Read(byte *buf, size_t size)
02028 {
02029 this->z.next_out = buf;
02030 this->z.avail_out = (uint)size;
02031
02032 do {
02033
02034 if (this->z.avail_in == 0) {
02035 this->z.next_in = this->fread_buf;
02036 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02037 }
02038
02039
02040 int r = inflate(&this->z, 0);
02041 if (r == Z_STREAM_END) break;
02042
02043 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02044 } while (this->z.avail_out != 0);
02045
02046 return size - this->z.avail_out;
02047 }
02048 };
02049
02051 struct ZlibSaveFilter : SaveFilter {
02052 z_stream z;
02053
02059 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02060 {
02061 memset(&this->z, 0, sizeof(this->z));
02062 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02063 }
02064
02066 ~ZlibSaveFilter()
02067 {
02068 deflateEnd(&this->z);
02069 }
02070
02077 void WriteLoop(byte *p, size_t len, int mode)
02078 {
02079 byte buf[MEMORY_CHUNK_SIZE];
02080 uint n;
02081 this->z.next_in = p;
02082 this->z.avail_in = (uInt)len;
02083 do {
02084 this->z.next_out = buf;
02085 this->z.avail_out = sizeof(buf);
02086
02094 int r = deflate(&this->z, mode);
02095
02096
02097 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02098 this->chain->Write(buf, n);
02099 }
02100 if (r == Z_STREAM_END) break;
02101
02102 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02103 } while (this->z.avail_in || !this->z.avail_out);
02104 }
02105
02106 void Write(byte *buf, size_t size)
02107 {
02108 this->WriteLoop(buf, size, 0);
02109 }
02110
02111 void Finish()
02112 {
02113 this->WriteLoop(NULL, 0, Z_FINISH);
02114 this->chain->Finish();
02115 }
02116 };
02117
02118 #endif
02119
02120
02121
02122
02123
02124 #if defined(WITH_LZMA)
02125 #include <lzma.h>
02126
02133 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02134
02136 struct LZMALoadFilter : LoadFilter {
02137 lzma_stream lzma;
02138 byte fread_buf[MEMORY_CHUNK_SIZE];
02139
02144 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02145 {
02146
02147 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02148 }
02149
02151 ~LZMALoadFilter()
02152 {
02153 lzma_end(&this->lzma);
02154 }
02155
02156 size_t Read(byte *buf, size_t size)
02157 {
02158 this->lzma.next_out = buf;
02159 this->lzma.avail_out = size;
02160
02161 do {
02162
02163 if (this->lzma.avail_in == 0) {
02164 this->lzma.next_in = this->fread_buf;
02165 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02166 }
02167
02168
02169 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02170 if (r == LZMA_STREAM_END) break;
02171 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02172 } while (this->lzma.avail_out != 0);
02173
02174 return size - this->lzma.avail_out;
02175 }
02176 };
02177
02179 struct LZMASaveFilter : SaveFilter {
02180 lzma_stream lzma;
02181
02187 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02188 {
02189 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02190 }
02191
02193 ~LZMASaveFilter()
02194 {
02195 lzma_end(&this->lzma);
02196 }
02197
02204 void WriteLoop(byte *p, size_t len, lzma_action action)
02205 {
02206 byte buf[MEMORY_CHUNK_SIZE];
02207 size_t n;
02208 this->lzma.next_in = p;
02209 this->lzma.avail_in = len;
02210 do {
02211 this->lzma.next_out = buf;
02212 this->lzma.avail_out = sizeof(buf);
02213
02214 lzma_ret r = lzma_code(&this->lzma, action);
02215
02216
02217 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02218 this->chain->Write(buf, n);
02219 }
02220 if (r == LZMA_STREAM_END) break;
02221 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02222 } while (this->lzma.avail_in || !this->lzma.avail_out);
02223 }
02224
02225 void Write(byte *buf, size_t size)
02226 {
02227 this->WriteLoop(buf, size, LZMA_RUN);
02228 }
02229
02230 void Finish()
02231 {
02232 this->WriteLoop(NULL, 0, LZMA_FINISH);
02233 this->chain->Finish();
02234 }
02235 };
02236
02237 #endif
02238
02239
02240
02241
02242
02244 struct SaveLoadFormat {
02245 const char *name;
02246 uint32 tag;
02247
02248 LoadFilter *(*init_load)(LoadFilter *chain);
02249 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02250
02251 byte min_compression;
02252 byte default_compression;
02253 byte max_compression;
02254 };
02255
02257 static const SaveLoadFormat _saveload_formats[] = {
02258 #if defined(WITH_LZO)
02259
02260 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02261 #else
02262 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02263 #endif
02264
02265 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02266 #if defined(WITH_ZLIB)
02267
02268
02269
02270 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02271 #else
02272 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02273 #endif
02274 #if defined(WITH_LZMA)
02275
02276
02277
02278
02279
02280 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02281 #else
02282 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02283 #endif
02284 };
02285
02293 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02294 {
02295 const SaveLoadFormat *def = lastof(_saveload_formats);
02296
02297
02298 while (!def->init_write) def--;
02299
02300 if (!StrEmpty(s)) {
02301
02302 char *complevel = strrchr(s, ':');
02303 if (complevel != NULL) *complevel = '\0';
02304
02305 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02306 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02307 *compression_level = slf->default_compression;
02308 if (complevel != NULL) {
02309
02310
02311
02312 *complevel = ':';
02313 complevel++;
02314
02315
02316 char *end;
02317 long level = strtol(complevel, &end, 10);
02318 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02319 SetDParamStr(0, complevel);
02320 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL);
02321 } else {
02322 *compression_level = level;
02323 }
02324 }
02325 return slf;
02326 }
02327 }
02328
02329 SetDParamStr(0, s);
02330 SetDParamStr(1, def->name);
02331 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL);
02332
02333
02334 if (complevel != NULL) *complevel = ':';
02335 }
02336 *compression_level = def->default_compression;
02337 return def;
02338 }
02339
02340
02341 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02342 extern bool AfterLoadGame();
02343 extern bool LoadOldSaveGame(const char *file);
02344
02348 static inline void ClearSaveLoadState()
02349 {
02350 delete _sl.dumper;
02351 _sl.dumper = NULL;
02352
02353 delete _sl.sf;
02354 _sl.sf = NULL;
02355
02356 delete _sl.reader;
02357 _sl.reader = NULL;
02358
02359 delete _sl.lf;
02360 _sl.lf = NULL;
02361 }
02362
02368 static void SaveFileStart()
02369 {
02370 _sl.ff_state = _fast_forward;
02371 _fast_forward = 0;
02372 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02373
02374 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02375 _sl.saveinprogress = true;
02376 }
02377
02379 static void SaveFileDone()
02380 {
02381 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02382 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02383
02384 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02385 _sl.saveinprogress = false;
02386 }
02387
02389 void SetSaveLoadError(StringID str)
02390 {
02391 _sl.error_str = str;
02392 }
02393
02395 const char *GetSaveLoadErrorString()
02396 {
02397 SetDParam(0, _sl.error_str);
02398 SetDParamStr(1, _sl.extra_msg);
02399
02400 static char err_str[512];
02401 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02402 return err_str;
02403 }
02404
02406 static void SaveFileError()
02407 {
02408 SetDParamStr(0, GetSaveLoadErrorString());
02409 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02410 SaveFileDone();
02411 }
02412
02417 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02418 {
02419 try {
02420 byte compression;
02421 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02422
02423
02424 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02425 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02426
02427 _sl.sf = fmt->init_write(_sl.sf, compression);
02428 _sl.dumper->Flush(_sl.sf);
02429
02430 ClearSaveLoadState();
02431
02432 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02433
02434 return SL_OK;
02435 } catch (...) {
02436 ClearSaveLoadState();
02437
02438 AsyncSaveFinishProc asfp = SaveFileDone;
02439
02440
02441
02442 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02443
02444 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02445 asfp = SaveFileError;
02446 }
02447
02448 if (threaded) {
02449 SetAsyncSaveFinish(asfp);
02450 } else {
02451 asfp();
02452 }
02453 return SL_ERROR;
02454 }
02455 }
02456
02458 static void SaveFileToDiskThread(void *arg)
02459 {
02460 SaveFileToDisk(true);
02461 }
02462
02463 void WaitTillSaved()
02464 {
02465 if (_save_thread == NULL) return;
02466
02467 _save_thread->Join();
02468 delete _save_thread;
02469 _save_thread = NULL;
02470
02471
02472 ProcessAsyncSaveFinish();
02473 }
02474
02483 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02484 {
02485 assert(!_sl.saveinprogress);
02486
02487 _sl.dumper = new MemoryDumper();
02488 _sl.sf = writer;
02489
02490 _sl_version = SAVEGAME_VERSION;
02491
02492 SaveViewportBeforeSaveGame();
02493 SlSaveChunks();
02494
02495 SaveFileStart();
02496 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02497 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02498
02499 SaveOrLoadResult result = SaveFileToDisk(false);
02500 SaveFileDone();
02501
02502 return result;
02503 }
02504
02505 return SL_OK;
02506 }
02507
02514 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02515 {
02516 try {
02517 _sl.action = SLA_SAVE;
02518 return DoSave(writer, threaded);
02519 } catch (...) {
02520 ClearSaveLoadState();
02521 return SL_ERROR;
02522 }
02523 }
02524
02531 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02532 {
02533 _sl.lf = reader;
02534
02535 if (load_check) {
02536
02537 _load_check_data.Clear();
02538
02539 _load_check_data.checkable = true;
02540 }
02541
02542 uint32 hdr[2];
02543 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02544
02545
02546 const SaveLoadFormat *fmt = _saveload_formats;
02547 for (;;) {
02548
02549 if (fmt == endof(_saveload_formats)) {
02550 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02551 _sl.lf->Reset();
02552 _sl_version = 0;
02553 _sl_minor_version = 0;
02554
02555
02556 fmt = _saveload_formats;
02557 for (;;) {
02558 if (fmt == endof(_saveload_formats)) {
02559
02560 NOT_REACHED();
02561 }
02562 if (fmt->tag == TO_BE32X('OTTD')) break;
02563 fmt++;
02564 }
02565 break;
02566 }
02567
02568 if (fmt->tag == hdr[0]) {
02569
02570 _sl_version = TO_BE32(hdr[1]) >> 16;
02571
02572
02573
02574 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02575
02576 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02577
02578
02579 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02580 break;
02581 }
02582
02583 fmt++;
02584 }
02585
02586
02587 if (fmt->init_load == NULL) {
02588 char err_str[64];
02589 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02590 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02591 }
02592
02593 _sl.lf = fmt->init_load(_sl.lf);
02594 _sl.reader = new ReadBuffer(_sl.lf);
02595 _next_offs = 0;
02596
02597 if (!load_check) {
02598
02599
02600
02601 InitializeGame(256, 256, true, true);
02602
02603 GamelogReset();
02604
02605 if (IsSavegameVersionBefore(4)) {
02606
02607
02608
02609
02610
02611
02612
02613
02614
02615
02616
02617
02618
02619
02620
02621
02622
02623
02624
02625
02626
02627 ClearGRFConfigList(&_grfconfig);
02628 }
02629 }
02630
02631 if (load_check) {
02632
02633
02634 SlLoadCheckChunks();
02635 } else {
02636
02637 SlLoadChunks();
02638 SlFixPointers();
02639 }
02640
02641 ClearSaveLoadState();
02642
02643 _savegame_type = SGT_OTTD;
02644
02645 if (load_check) {
02646
02647 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02648 } else {
02649 GamelogStartAction(GLAT_LOAD);
02650
02651
02652
02653 if (!AfterLoadGame()) {
02654 GamelogStopAction();
02655 return SL_REINIT;
02656 }
02657
02658 GamelogStopAction();
02659 }
02660
02661 return SL_OK;
02662 }
02663
02669 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02670 {
02671 try {
02672 _sl.action = SLA_LOAD;
02673 return DoLoad(reader, false);
02674 } catch (...) {
02675 ClearSaveLoadState();
02676 return SL_REINIT;
02677 }
02678 }
02679
02689 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02690 {
02691
02692 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02693
02694 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02695 return SL_OK;
02696 }
02697 WaitTillSaved();
02698
02699
02700 if (mode == SL_OLD_LOAD) {
02701 InitializeGame(256, 256, true, true);
02702
02703
02704
02705
02706
02707 ClearGRFConfigList(&_grfconfig);
02708 GamelogReset();
02709 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02710 _sl_version = 0;
02711 _sl_minor_version = 0;
02712 GamelogStartAction(GLAT_LOAD);
02713 if (!AfterLoadGame()) {
02714 GamelogStopAction();
02715 return SL_REINIT;
02716 }
02717 GamelogStopAction();
02718 return SL_OK;
02719 }
02720
02721 switch (mode) {
02722 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02723 case SL_LOAD: _sl.action = SLA_LOAD; break;
02724 case SL_SAVE: _sl.action = SLA_SAVE; break;
02725 default: NOT_REACHED();
02726 }
02727
02728 try {
02729 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02730
02731
02732 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02733 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02734 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
02735
02736 if (fh == NULL) {
02737 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02738 }
02739
02740 if (mode == SL_SAVE) {
02741 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02742 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02743
02744 return DoSave(new FileWriter(fh), threaded);
02745 }
02746
02747
02748 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02749 DEBUG(desync, 1, "load: %s", filename);
02750 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02751 } catch (...) {
02752 ClearSaveLoadState();
02753
02754
02755 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02756
02757
02758 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02759 }
02760 }
02761
02763 void DoExitSave()
02764 {
02765 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02766 }
02767
02773 void GenerateDefaultSaveName(char *buf, const char *last)
02774 {
02775
02776
02777
02778 CompanyID cid = _local_company;
02779 if (!Company::IsValidID(cid)) {
02780 const Company *c;
02781 FOR_ALL_COMPANIES(c) {
02782 cid = c->index;
02783 break;
02784 }
02785 }
02786
02787 SetDParam(0, cid);
02788
02789
02790 switch (_settings_client.gui.date_format_in_default_names) {
02791 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02792 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02793 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02794 default: NOT_REACHED();
02795 }
02796 SetDParam(2, _date);
02797
02798
02799 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02800 SanitizeFilename(buf);
02801 }
02802
02803 #if 0
02804
02810 int GetSavegameType(char *file)
02811 {
02812 const SaveLoadFormat *fmt;
02813 uint32 hdr;
02814 FILE *f;
02815 int mode = SL_OLD_LOAD;
02816
02817 f = fopen(file, "rb");
02818 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02819 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02820 mode = SL_LOAD;
02821 } else {
02822
02823 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02824 if (fmt->tag == hdr) {
02825 mode = SL_LOAD;
02826 break;
02827 }
02828 }
02829 }
02830
02831 fclose(f);
02832 return mode;
02833 }
02834 #endif