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