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