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 "../linkgraph/linkgraph.h"
00039 #include "../linkgraph/linkgraphjob.h"
00040 #include "../statusbar_gui.h"
00041 #include "../fileio_func.h"
00042 #include "../gamelog.h"
00043 #include "../string_func.h"
00044 #include "../fios.h"
00045 #include "../error.h"
00046
00047 #include "table/strings.h"
00048
00049 #include "saveload_internal.h"
00050 #include "saveload_filter.h"
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 extern const uint16 SAVEGAME_VERSION = SL_EXT_RATING;
00252
00253 SavegameType _savegame_type;
00254
00255 uint32 _ttdp_version;
00256 uint16 _sl_version;
00257 byte _sl_minor_version;
00258 char _savegame_format[8];
00259 bool _do_autosave;
00260
00262 enum SaveLoadAction {
00263 SLA_LOAD,
00264 SLA_SAVE,
00265 SLA_PTRS,
00266 SLA_NULL,
00267 SLA_LOAD_CHECK,
00268 };
00269
00270 enum NeedLength {
00271 NL_NONE = 0,
00272 NL_WANTLENGTH = 1,
00273 NL_CALCLENGTH = 2,
00274 };
00275
00277 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
00278
00280 struct ReadBuffer {
00281 byte buf[MEMORY_CHUNK_SIZE];
00282 byte *bufp;
00283 byte *bufe;
00284 LoadFilter *reader;
00285 size_t read;
00286
00291 ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
00292 {
00293 }
00294
00295 inline byte ReadByte()
00296 {
00297 if (this->bufp == this->bufe) {
00298 size_t len = this->reader->Read(this->buf, lengthof(this->buf));
00299 if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00300
00301 this->read += len;
00302 this->bufp = this->buf;
00303 this->bufe = this->buf + len;
00304 }
00305
00306 return *this->bufp++;
00307 }
00308
00313 size_t GetSize() const
00314 {
00315 return this->read - (this->bufe - this->bufp);
00316 }
00317 };
00318
00319
00321 struct MemoryDumper {
00322 AutoFreeSmallVector<byte *, 16> blocks;
00323 byte *buf;
00324 byte *bufe;
00325
00327 MemoryDumper() : buf(NULL), bufe(NULL)
00328 {
00329 }
00330
00335 inline void WriteByte(byte b)
00336 {
00337
00338 if (this->buf == this->bufe) {
00339 this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
00340 *this->blocks.Append() = this->buf;
00341 this->bufe = this->buf + MEMORY_CHUNK_SIZE;
00342 }
00343
00344 *this->buf++ = b;
00345 }
00346
00351 void Flush(SaveFilter *writer)
00352 {
00353 uint i = 0;
00354 size_t t = this->GetSize();
00355
00356 while (t > 0) {
00357 size_t to_write = min(MEMORY_CHUNK_SIZE, t);
00358
00359 writer->Write(this->blocks[i++], to_write);
00360 t -= to_write;
00361 }
00362
00363 writer->Finish();
00364 }
00365
00370 size_t GetSize() const
00371 {
00372 return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
00373 }
00374 };
00375
00377 struct SaveLoadParams {
00378 SaveLoadAction action;
00379 NeedLength need_length;
00380 byte block_mode;
00381 bool error;
00382
00383 size_t obj_len;
00384 int array_index, last_array_index;
00385
00386 MemoryDumper *dumper;
00387 SaveFilter *sf;
00388
00389 ReadBuffer *reader;
00390 LoadFilter *lf;
00391
00392 StringID error_str;
00393 char *extra_msg;
00394
00395 byte ff_state;
00396 bool saveinprogress;
00397 };
00398
00399 static SaveLoadParams _sl;
00400
00401
00402 extern const ChunkHandler _gamelog_chunk_handlers[];
00403 extern const ChunkHandler _map_chunk_handlers[];
00404 extern const ChunkHandler _misc_chunk_handlers[];
00405 extern const ChunkHandler _name_chunk_handlers[];
00406 extern const ChunkHandler _cheat_chunk_handlers[] ;
00407 extern const ChunkHandler _setting_chunk_handlers[];
00408 extern const ChunkHandler _company_chunk_handlers[];
00409 extern const ChunkHandler _engine_chunk_handlers[];
00410 extern const ChunkHandler _veh_chunk_handlers[];
00411 extern const ChunkHandler _waypoint_chunk_handlers[];
00412 extern const ChunkHandler _depot_chunk_handlers[];
00413 extern const ChunkHandler _order_chunk_handlers[];
00414 extern const ChunkHandler _town_chunk_handlers[];
00415 extern const ChunkHandler _sign_chunk_handlers[];
00416 extern const ChunkHandler _station_chunk_handlers[];
00417 extern const ChunkHandler _industry_chunk_handlers[];
00418 extern const ChunkHandler _economy_chunk_handlers[];
00419 extern const ChunkHandler _subsidy_chunk_handlers[];
00420 extern const ChunkHandler _cargomonitor_chunk_handlers[];
00421 extern const ChunkHandler _goal_chunk_handlers[];
00422 extern const ChunkHandler _ai_chunk_handlers[];
00423 extern const ChunkHandler _game_chunk_handlers[];
00424 extern const ChunkHandler _animated_tile_chunk_handlers[];
00425 extern const ChunkHandler _newgrf_chunk_handlers[];
00426 extern const ChunkHandler _group_chunk_handlers[];
00427 extern const ChunkHandler _cargopacket_chunk_handlers[];
00428 extern const ChunkHandler _autoreplace_chunk_handlers[];
00429 extern const ChunkHandler _labelmaps_chunk_handlers[];
00430 extern const ChunkHandler _linkgraph_chunk_handlers[];
00431 extern const ChunkHandler _airport_chunk_handlers[];
00432 extern const ChunkHandler _object_chunk_handlers[];
00433 extern const ChunkHandler _persistent_storage_chunk_handlers[];
00434
00436 static const ChunkHandler * const _chunk_handlers[] = {
00437 _gamelog_chunk_handlers,
00438 _map_chunk_handlers,
00439 _misc_chunk_handlers,
00440 _name_chunk_handlers,
00441 _cheat_chunk_handlers,
00442 _setting_chunk_handlers,
00443 _veh_chunk_handlers,
00444 _waypoint_chunk_handlers,
00445 _depot_chunk_handlers,
00446 _order_chunk_handlers,
00447 _industry_chunk_handlers,
00448 _economy_chunk_handlers,
00449 _subsidy_chunk_handlers,
00450 _cargomonitor_chunk_handlers,
00451 _goal_chunk_handlers,
00452 _engine_chunk_handlers,
00453 _town_chunk_handlers,
00454 _sign_chunk_handlers,
00455 _station_chunk_handlers,
00456 _company_chunk_handlers,
00457 _ai_chunk_handlers,
00458 _game_chunk_handlers,
00459 _animated_tile_chunk_handlers,
00460 _newgrf_chunk_handlers,
00461 _group_chunk_handlers,
00462 _cargopacket_chunk_handlers,
00463 _autoreplace_chunk_handlers,
00464 _labelmaps_chunk_handlers,
00465 _linkgraph_chunk_handlers,
00466 _airport_chunk_handlers,
00467 _object_chunk_handlers,
00468 _persistent_storage_chunk_handlers,
00469 NULL,
00470 };
00471
00476 #define FOR_ALL_CHUNK_HANDLERS(ch) \
00477 for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \
00478 for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1)
00479
00481 static void SlNullPointers()
00482 {
00483 _sl.action = SLA_NULL;
00484
00485
00486
00487
00488 _sl_version = SAVEGAME_VERSION;
00489
00490 DEBUG(sl, 1, "Nulling pointers");
00491
00492 FOR_ALL_CHUNK_HANDLERS(ch) {
00493 if (ch->ptrs_proc != NULL) {
00494 DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00495 ch->ptrs_proc();
00496 }
00497 }
00498
00499 DEBUG(sl, 1, "All pointers nulled");
00500
00501 assert(_sl.action == SLA_NULL);
00502 }
00503
00512 void NORETURN SlError(StringID string, const char *extra_msg)
00513 {
00514
00515 if (_sl.action == SLA_LOAD_CHECK) {
00516 _load_check_data.error = string;
00517 free(_load_check_data.error_data);
00518 _load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00519 } else {
00520 _sl.error_str = string;
00521 free(_sl.extra_msg);
00522 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00523 }
00524
00525
00526
00527
00528
00529 if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00530 throw std::exception();
00531 }
00532
00540 void NORETURN SlErrorCorrupt(const char *msg)
00541 {
00542 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00543 }
00544
00545
00546 typedef void (*AsyncSaveFinishProc)();
00547 static AsyncSaveFinishProc _async_save_finish = NULL;
00548 static ThreadObject *_save_thread;
00549
00554 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00555 {
00556 if (_exit_game) return;
00557 while (_async_save_finish != NULL) CSleep(10);
00558
00559 _async_save_finish = proc;
00560 }
00561
00565 void ProcessAsyncSaveFinish()
00566 {
00567 if (_async_save_finish == NULL) return;
00568
00569 _async_save_finish();
00570
00571 _async_save_finish = NULL;
00572
00573 if (_save_thread != NULL) {
00574 _save_thread->Join();
00575 delete _save_thread;
00576 _save_thread = NULL;
00577 }
00578 }
00579
00584 byte SlReadByte()
00585 {
00586 return _sl.reader->ReadByte();
00587 }
00588
00593 void SlWriteByte(byte b)
00594 {
00595 _sl.dumper->WriteByte(b);
00596 }
00597
00598 static inline int SlReadUint16()
00599 {
00600 int x = SlReadByte() << 8;
00601 return x | SlReadByte();
00602 }
00603
00604 static inline uint32 SlReadUint32()
00605 {
00606 uint32 x = SlReadUint16() << 16;
00607 return x | SlReadUint16();
00608 }
00609
00610 static inline uint64 SlReadUint64()
00611 {
00612 uint32 x = SlReadUint32();
00613 uint32 y = SlReadUint32();
00614 return (uint64)x << 32 | y;
00615 }
00616
00617 static inline void SlWriteUint16(uint16 v)
00618 {
00619 SlWriteByte(GB(v, 8, 8));
00620 SlWriteByte(GB(v, 0, 8));
00621 }
00622
00623 static inline void SlWriteUint32(uint32 v)
00624 {
00625 SlWriteUint16(GB(v, 16, 16));
00626 SlWriteUint16(GB(v, 0, 16));
00627 }
00628
00629 static inline void SlWriteUint64(uint64 x)
00630 {
00631 SlWriteUint32((uint32)(x >> 32));
00632 SlWriteUint32((uint32)x);
00633 }
00634
00640 static inline void SlSkipBytes(size_t length)
00641 {
00642 for (; length != 0; length--) SlReadByte();
00643 }
00644
00654 static uint SlReadSimpleGamma()
00655 {
00656 uint i = SlReadByte();
00657 if (HasBit(i, 7)) {
00658 i &= ~0x80;
00659 if (HasBit(i, 6)) {
00660 i &= ~0x40;
00661 if (HasBit(i, 5)) {
00662 i &= ~0x20;
00663 if (HasBit(i, 4)) {
00664 SlErrorCorrupt("Unsupported gamma");
00665 }
00666 i = (i << 8) | SlReadByte();
00667 }
00668 i = (i << 8) | SlReadByte();
00669 }
00670 i = (i << 8) | SlReadByte();
00671 }
00672 return i;
00673 }
00674
00687 static void SlWriteSimpleGamma(size_t i)
00688 {
00689 if (i >= (1 << 7)) {
00690 if (i >= (1 << 14)) {
00691 if (i >= (1 << 21)) {
00692 assert(i < (1 << 28));
00693 SlWriteByte((byte)(0xE0 | (i >> 24)));
00694 SlWriteByte((byte)(i >> 16));
00695 } else {
00696 SlWriteByte((byte)(0xC0 | (i >> 16)));
00697 }
00698 SlWriteByte((byte)(i >> 8));
00699 } else {
00700 SlWriteByte((byte)(0x80 | (i >> 8)));
00701 }
00702 }
00703 SlWriteByte((byte)i);
00704 }
00705
00707 static inline uint SlGetGammaLength(size_t i)
00708 {
00709 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00710 }
00711
00712 static inline uint SlReadSparseIndex()
00713 {
00714 return SlReadSimpleGamma();
00715 }
00716
00717 static inline void SlWriteSparseIndex(uint index)
00718 {
00719 SlWriteSimpleGamma(index);
00720 }
00721
00722 static inline uint SlReadArrayLength()
00723 {
00724 return SlReadSimpleGamma();
00725 }
00726
00727 static inline void SlWriteArrayLength(size_t length)
00728 {
00729 SlWriteSimpleGamma(length);
00730 }
00731
00732 static inline uint SlGetArrayLength(size_t length)
00733 {
00734 return SlGetGammaLength(length);
00735 }
00736
00743 static inline uint SlCalcConvMemLen(VarType conv)
00744 {
00745 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00746 byte length = GB(conv, 4, 4);
00747
00748 switch (length << 4) {
00749 case SLE_VAR_STRB:
00750 case SLE_VAR_STRBQ:
00751 case SLE_VAR_STR:
00752 case SLE_VAR_STRQ:
00753 return SlReadArrayLength();
00754
00755 default:
00756 assert(length < lengthof(conv_mem_size));
00757 return conv_mem_size[length];
00758 }
00759 }
00760
00767 static inline byte SlCalcConvFileLen(VarType conv)
00768 {
00769 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00770 byte length = GB(conv, 0, 4);
00771 assert(length < lengthof(conv_file_size));
00772 return conv_file_size[length];
00773 }
00774
00776 static inline size_t SlCalcRefLen()
00777 {
00778 return IsSavegameVersionBefore(69) ? 2 : 4;
00779 }
00780
00781 void SlSetArrayIndex(uint index)
00782 {
00783 _sl.need_length = NL_WANTLENGTH;
00784 _sl.array_index = index;
00785 }
00786
00787 static size_t _next_offs;
00788
00793 int SlIterateArray()
00794 {
00795 int index;
00796
00797
00798
00799 if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00800
00801 for (;;) {
00802 uint length = SlReadArrayLength();
00803 if (length == 0) {
00804 _next_offs = 0;
00805 return -1;
00806 }
00807
00808 _sl.obj_len = --length;
00809 _next_offs = _sl.reader->GetSize() + length;
00810
00811 switch (_sl.block_mode) {
00812 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00813 case CH_ARRAY: index = _sl.array_index++; break;
00814 default:
00815 DEBUG(sl, 0, "SlIterateArray error");
00816 return -1;
00817 }
00818
00819 if (length != 0) return index;
00820 }
00821 }
00822
00826 void SlSkipArray()
00827 {
00828 while (SlIterateArray() != -1) {
00829 SlSkipBytes(_next_offs - _sl.reader->GetSize());
00830 }
00831 }
00832
00838 void SlSetLength(size_t length)
00839 {
00840 assert(_sl.action == SLA_SAVE);
00841
00842 switch (_sl.need_length) {
00843 case NL_WANTLENGTH:
00844 _sl.need_length = NL_NONE;
00845 switch (_sl.block_mode) {
00846 case CH_RIFF:
00847
00848
00849
00850 assert(length < (1 << 28));
00851 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00852 break;
00853 case CH_ARRAY:
00854 assert(_sl.last_array_index <= _sl.array_index);
00855 while (++_sl.last_array_index <= _sl.array_index) {
00856 SlWriteArrayLength(1);
00857 }
00858 SlWriteArrayLength(length + 1);
00859 break;
00860 case CH_SPARSE_ARRAY:
00861 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00862 SlWriteSparseIndex(_sl.array_index);
00863 break;
00864 default: NOT_REACHED();
00865 }
00866 break;
00867
00868 case NL_CALCLENGTH:
00869 _sl.obj_len += (int)length;
00870 break;
00871
00872 default: NOT_REACHED();
00873 }
00874 }
00875
00882 static void SlCopyBytes(void *ptr, size_t length)
00883 {
00884 byte *p = (byte *)ptr;
00885
00886 switch (_sl.action) {
00887 case SLA_LOAD_CHECK:
00888 case SLA_LOAD:
00889 for (; length != 0; length--) *p++ = SlReadByte();
00890 break;
00891 case SLA_SAVE:
00892 for (; length != 0; length--) SlWriteByte(*p++);
00893 break;
00894 default: NOT_REACHED();
00895 }
00896 }
00897
00899 size_t SlGetFieldLength()
00900 {
00901 return _sl.obj_len;
00902 }
00903
00911 int64 ReadValue(const void *ptr, VarType conv)
00912 {
00913 switch (GetVarMemType(conv)) {
00914 case SLE_VAR_BL: return (*(const bool *)ptr != 0);
00915 case SLE_VAR_I8: return *(const int8 *)ptr;
00916 case SLE_VAR_U8: return *(const byte *)ptr;
00917 case SLE_VAR_I16: return *(const int16 *)ptr;
00918 case SLE_VAR_U16: return *(const uint16*)ptr;
00919 case SLE_VAR_I32: return *(const int32 *)ptr;
00920 case SLE_VAR_U32: return *(const uint32*)ptr;
00921 case SLE_VAR_I64: return *(const int64 *)ptr;
00922 case SLE_VAR_U64: return *(const uint64*)ptr;
00923 case SLE_VAR_NULL:return 0;
00924 default: NOT_REACHED();
00925 }
00926 }
00927
00935 void WriteValue(void *ptr, VarType conv, int64 val)
00936 {
00937 switch (GetVarMemType(conv)) {
00938 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00939 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00940 case SLE_VAR_U8: *(byte *)ptr = val; break;
00941 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00942 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00943 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00944 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00945 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00946 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00947 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00948 case SLE_VAR_NULL: break;
00949 default: NOT_REACHED();
00950 }
00951 }
00952
00961 static void SlSaveLoadConv(void *ptr, VarType conv)
00962 {
00963 switch (_sl.action) {
00964 case SLA_SAVE: {
00965 int64 x = ReadValue(ptr, conv);
00966
00967
00968 switch (GetVarFileType(conv)) {
00969 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00970 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00971 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00972 case SLE_FILE_STRINGID:
00973 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00974 case SLE_FILE_I32:
00975 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00976 case SLE_FILE_I64:
00977 case SLE_FILE_U64: SlWriteUint64(x);break;
00978 default: NOT_REACHED();
00979 }
00980 break;
00981 }
00982 case SLA_LOAD_CHECK:
00983 case SLA_LOAD: {
00984 int64 x;
00985
00986 switch (GetVarFileType(conv)) {
00987 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00988 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00989 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00990 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00991 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00992 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00993 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00994 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00995 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00996 default: NOT_REACHED();
00997 }
00998
00999
01000 WriteValue(ptr, conv, x);
01001 break;
01002 }
01003 case SLA_PTRS: break;
01004 case SLA_NULL: break;
01005 default: NOT_REACHED();
01006 }
01007 }
01008
01018 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
01019 {
01020 if (ptr == NULL) return 0;
01021 return min(strlen(ptr), length - 1);
01022 }
01023
01033 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
01034 {
01035 size_t len;
01036 const char *str;
01037
01038 switch (GetVarMemType(conv)) {
01039 default: NOT_REACHED();
01040 case SLE_VAR_STR:
01041 case SLE_VAR_STRQ:
01042 str = *(const char * const *)ptr;
01043 len = SIZE_MAX;
01044 break;
01045 case SLE_VAR_STRB:
01046 case SLE_VAR_STRBQ:
01047 str = (const char *)ptr;
01048 len = length;
01049 break;
01050 }
01051
01052 len = SlCalcNetStringLen(str, len);
01053 return len + SlGetArrayLength(len);
01054 }
01055
01062 static void SlString(void *ptr, size_t length, VarType conv)
01063 {
01064 switch (_sl.action) {
01065 case SLA_SAVE: {
01066 size_t len;
01067 switch (GetVarMemType(conv)) {
01068 default: NOT_REACHED();
01069 case SLE_VAR_STRB:
01070 case SLE_VAR_STRBQ:
01071 len = SlCalcNetStringLen((char *)ptr, length);
01072 break;
01073 case SLE_VAR_STR:
01074 case SLE_VAR_STRQ:
01075 ptr = *(char **)ptr;
01076 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01077 break;
01078 }
01079
01080 SlWriteArrayLength(len);
01081 SlCopyBytes(ptr, len);
01082 break;
01083 }
01084 case SLA_LOAD_CHECK:
01085 case SLA_LOAD: {
01086 size_t len = SlReadArrayLength();
01087
01088 switch (GetVarMemType(conv)) {
01089 default: NOT_REACHED();
01090 case SLE_VAR_STRB:
01091 case SLE_VAR_STRBQ:
01092 if (len >= length) {
01093 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01094 SlCopyBytes(ptr, length);
01095 SlSkipBytes(len - length);
01096 len = length - 1;
01097 } else {
01098 SlCopyBytes(ptr, len);
01099 }
01100 break;
01101 case SLE_VAR_STR:
01102 case SLE_VAR_STRQ:
01103 free(*(char **)ptr);
01104 if (len == 0) {
01105 *(char **)ptr = NULL;
01106 return;
01107 } else {
01108 *(char **)ptr = MallocT<char>(len + 1);
01109 ptr = *(char **)ptr;
01110 SlCopyBytes(ptr, len);
01111 }
01112 break;
01113 }
01114
01115 ((char *)ptr)[len] = '\0';
01116 StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
01117 if ((conv & SLF_ALLOW_CONTROL) != 0) {
01118 settings = settings | SVS_ALLOW_CONTROL_CODE;
01119 if (IsSavegameVersionBefore(169)) {
01120 str_fix_scc_encoded((char *)ptr, (char *)ptr + len);
01121 }
01122 }
01123 if ((conv & SLF_ALLOW_NEWLINE) != 0) {
01124 settings = settings | SVS_ALLOW_NEWLINE;
01125 }
01126 str_validate((char *)ptr, (char *)ptr + len, settings);
01127 break;
01128 }
01129 case SLA_PTRS: break;
01130 case SLA_NULL: break;
01131 default: NOT_REACHED();
01132 }
01133 }
01134
01140 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01141 {
01142 return SlCalcConvFileLen(conv) * length;
01143 }
01144
01151 void SlArray(void *array, size_t length, VarType conv)
01152 {
01153 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01154
01155
01156 if (_sl.need_length != NL_NONE) {
01157 SlSetLength(SlCalcArrayLen(length, conv));
01158
01159 if (_sl.need_length == NL_CALCLENGTH) return;
01160 }
01161
01162
01163
01164 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01165
01166 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01167 conv == SLE_INT32 || conv == SLE_UINT32) {
01168 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01169 return;
01170 }
01171
01172 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01173 for (uint i = 0; i < length; i++) {
01174 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01175 }
01176 return;
01177 }
01178 }
01179
01180
01181
01182 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01183 SlCopyBytes(array, length);
01184 } else {
01185 byte *a = (byte*)array;
01186 byte mem_size = SlCalcConvMemLen(conv);
01187
01188 for (; length != 0; length --) {
01189 SlSaveLoadConv(a, conv);
01190 a += mem_size;
01191 }
01192 }
01193 }
01194
01195
01206 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01207 {
01208 assert(_sl.action == SLA_SAVE);
01209
01210 if (obj == NULL) return 0;
01211
01212 switch (rt) {
01213 case REF_VEHICLE_OLD:
01214 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01215 case REF_STATION: return ((const Station*)obj)->index + 1;
01216 case REF_TOWN: return ((const Town*)obj)->index + 1;
01217 case REF_ORDER: return ((const Order*)obj)->index + 1;
01218 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01219 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01220 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01221 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01222 case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
01223 case REF_LINK_GRAPH: return ((const LinkGraph*)obj)->index + 1;
01224 case REF_LINK_GRAPH_JOB: return ((const LinkGraphJob*)obj)->index + 1;
01225 default: NOT_REACHED();
01226 }
01227 }
01228
01239 static void *IntToReference(size_t index, SLRefType rt)
01240 {
01241 assert_compile(sizeof(size_t) <= sizeof(void *));
01242
01243 assert(_sl.action == SLA_PTRS);
01244
01245
01246
01247 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01248 rt = REF_VEHICLE;
01249 }
01250
01251
01252 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01253
01254
01255
01256 if (rt != REF_VEHICLE_OLD) index--;
01257
01258 switch (rt) {
01259 case REF_ORDERLIST:
01260 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01261 SlErrorCorrupt("Referencing invalid OrderList");
01262
01263 case REF_ORDER:
01264 if (Order::IsValidID(index)) return Order::Get(index);
01265
01266 if (IsSavegameVersionBefore(5, 2)) return NULL;
01267 SlErrorCorrupt("Referencing invalid Order");
01268
01269 case REF_VEHICLE_OLD:
01270 case REF_VEHICLE:
01271 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01272 SlErrorCorrupt("Referencing invalid Vehicle");
01273
01274 case REF_STATION:
01275 if (Station::IsValidID(index)) return Station::Get(index);
01276 SlErrorCorrupt("Referencing invalid Station");
01277
01278 case REF_TOWN:
01279 if (Town::IsValidID(index)) return Town::Get(index);
01280 SlErrorCorrupt("Referencing invalid Town");
01281
01282 case REF_ROADSTOPS:
01283 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01284 SlErrorCorrupt("Referencing invalid RoadStop");
01285
01286 case REF_ENGINE_RENEWS:
01287 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01288 SlErrorCorrupt("Referencing invalid EngineRenew");
01289
01290 case REF_CARGO_PACKET:
01291 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01292 SlErrorCorrupt("Referencing invalid CargoPacket");
01293
01294 case REF_STORAGE:
01295 if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index);
01296 SlErrorCorrupt("Referencing invalid PersistentStorage");
01297
01298 case REF_LINK_GRAPH:
01299 if (LinkGraph::IsValidID(index)) return LinkGraph::Get(index);
01300 SlErrorCorrupt("Referencing invalid LinkGraph");
01301
01302 case REF_LINK_GRAPH_JOB:
01303 if (LinkGraphJob::IsValidID(index)) return LinkGraphJob::Get(index);
01304 SlErrorCorrupt("Referencing invalid LinkGraphJob");
01305
01306 default: NOT_REACHED();
01307 }
01308 }
01309
01314 static inline size_t SlCalcListLen(const void *list)
01315 {
01316 const std::list<void *> *l = (const std::list<void *> *) list;
01317
01318 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01319
01320
01321 return l->size() * type_size + type_size;
01322 }
01323
01324
01330 static void SlList(void *list, SLRefType conv)
01331 {
01332
01333 if (_sl.need_length != NL_NONE) {
01334 SlSetLength(SlCalcListLen(list));
01335
01336 if (_sl.need_length == NL_CALCLENGTH) return;
01337 }
01338
01339 typedef std::list<void *> PtrList;
01340 PtrList *l = (PtrList *)list;
01341
01342 switch (_sl.action) {
01343 case SLA_SAVE: {
01344 SlWriteUint32((uint32)l->size());
01345
01346 PtrList::iterator iter;
01347 for (iter = l->begin(); iter != l->end(); ++iter) {
01348 void *ptr = *iter;
01349 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01350 }
01351 break;
01352 }
01353 case SLA_LOAD_CHECK:
01354 case SLA_LOAD: {
01355 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01356
01357
01358 for (size_t i = 0; i < length; i++) {
01359 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01360 l->push_back((void *)data);
01361 }
01362 break;
01363 }
01364 case SLA_PTRS: {
01365 PtrList temp = *l;
01366
01367 l->clear();
01368 PtrList::iterator iter;
01369 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01370 void *ptr = IntToReference((size_t)*iter, conv);
01371 l->push_back(ptr);
01372 }
01373 break;
01374 }
01375 case SLA_NULL:
01376 l->clear();
01377 break;
01378 default: NOT_REACHED();
01379 }
01380 }
01381
01382
01384 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01385 {
01386 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01387 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01388
01389 return true;
01390 }
01391
01397 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01398 {
01399 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01400 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01401 return true;
01402 }
01403
01404 return false;
01405 }
01406
01413 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01414 {
01415 size_t length = 0;
01416
01417
01418 for (; sld->cmd != SL_END; sld++) {
01419 length += SlCalcObjMemberLength(object, sld);
01420 }
01421 return length;
01422 }
01423
01424 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01425 {
01426 assert(_sl.action == SLA_SAVE);
01427
01428 switch (sld->cmd) {
01429 case SL_VAR:
01430 case SL_REF:
01431 case SL_ARR:
01432 case SL_STR:
01433 case SL_LST:
01434
01435 if (!SlIsObjectValidInSavegame(sld)) break;
01436
01437 switch (sld->cmd) {
01438 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01439 case SL_REF: return SlCalcRefLen();
01440 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01441 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01442 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01443 default: NOT_REACHED();
01444 }
01445 break;
01446 case SL_WRITEBYTE: return 1;
01447 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01448 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01449 default: NOT_REACHED();
01450 }
01451 return 0;
01452 }
01453
01454
01455 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01456 {
01457 VarType conv = GB(sld->conv, 0, 8);
01458 switch (sld->cmd) {
01459 case SL_VAR:
01460 case SL_REF:
01461 case SL_ARR:
01462 case SL_STR:
01463 case SL_LST:
01464
01465 if (!SlIsObjectValidInSavegame(sld)) return false;
01466 if (SlSkipVariableOnLoad(sld)) return false;
01467
01468 switch (sld->cmd) {
01469 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01470 case SL_REF:
01471 switch (_sl.action) {
01472 case SLA_SAVE:
01473 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01474 break;
01475 case SLA_LOAD_CHECK:
01476 case SLA_LOAD:
01477 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01478 break;
01479 case SLA_PTRS:
01480 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01481 break;
01482 case SLA_NULL:
01483 *(void **)ptr = NULL;
01484 break;
01485 default: NOT_REACHED();
01486 }
01487 break;
01488 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01489 case SL_STR: SlString(ptr, sld->length, sld->conv); break;
01490 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01491 default: NOT_REACHED();
01492 }
01493 break;
01494
01495
01496
01497
01498
01499
01500 case SL_WRITEBYTE:
01501 switch (_sl.action) {
01502 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01503 case SLA_LOAD_CHECK:
01504 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01505 case SLA_PTRS: break;
01506 case SLA_NULL: break;
01507 default: NOT_REACHED();
01508 }
01509 break;
01510
01511
01512 case SL_VEH_INCLUDE:
01513 SlObject(ptr, GetVehicleDescription(VEH_END));
01514 break;
01515
01516 case SL_ST_INCLUDE:
01517 SlObject(ptr, GetBaseStationDescription());
01518 break;
01519
01520 default: NOT_REACHED();
01521 }
01522 return true;
01523 }
01524
01530 void SlObject(void *object, const SaveLoad *sld)
01531 {
01532
01533 if (_sl.need_length != NL_NONE) {
01534 SlSetLength(SlCalcObjLength(object, sld));
01535 if (_sl.need_length == NL_CALCLENGTH) return;
01536 }
01537
01538 for (; sld->cmd != SL_END; sld++) {
01539 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01540 SlObjectMember(ptr, sld);
01541 }
01542 }
01543
01548 void SlGlobList(const SaveLoadGlobVarList *sldg)
01549 {
01550 SlObject(NULL, (const SaveLoad*)sldg);
01551 }
01552
01558 void SlAutolength(AutolengthProc *proc, void *arg)
01559 {
01560 size_t offs;
01561
01562 assert(_sl.action == SLA_SAVE);
01563
01564
01565 _sl.need_length = NL_CALCLENGTH;
01566 _sl.obj_len = 0;
01567 proc(arg);
01568
01569
01570 _sl.need_length = NL_WANTLENGTH;
01571 SlSetLength(_sl.obj_len);
01572
01573 offs = _sl.dumper->GetSize() + _sl.obj_len;
01574
01575
01576 proc(arg);
01577
01578 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01579 }
01580
01585 static void SlLoadChunk(const ChunkHandler *ch)
01586 {
01587 byte m = SlReadByte();
01588 size_t len;
01589 size_t endoffs;
01590
01591 _sl.block_mode = m;
01592 _sl.obj_len = 0;
01593
01594 switch (m) {
01595 case CH_ARRAY:
01596 _sl.array_index = 0;
01597 ch->load_proc();
01598 break;
01599 case CH_SPARSE_ARRAY:
01600 ch->load_proc();
01601 break;
01602 default:
01603 if ((m & 0xF) == CH_RIFF) {
01604
01605 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01606 len += SlReadUint16();
01607 _sl.obj_len = len;
01608 endoffs = _sl.reader->GetSize() + len;
01609 ch->load_proc();
01610 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01611 } else {
01612 SlErrorCorrupt("Invalid chunk type");
01613 }
01614 break;
01615 }
01616 }
01617
01623 static void SlLoadCheckChunk(const ChunkHandler *ch)
01624 {
01625 byte m = SlReadByte();
01626 size_t len;
01627 size_t endoffs;
01628
01629 _sl.block_mode = m;
01630 _sl.obj_len = 0;
01631
01632 switch (m) {
01633 case CH_ARRAY:
01634 _sl.array_index = 0;
01635 if (ch->load_check_proc) {
01636 ch->load_check_proc();
01637 } else {
01638 SlSkipArray();
01639 }
01640 break;
01641 case CH_SPARSE_ARRAY:
01642 if (ch->load_check_proc) {
01643 ch->load_check_proc();
01644 } else {
01645 SlSkipArray();
01646 }
01647 break;
01648 default:
01649 if ((m & 0xF) == CH_RIFF) {
01650
01651 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01652 len += SlReadUint16();
01653 _sl.obj_len = len;
01654 endoffs = _sl.reader->GetSize() + len;
01655 if (ch->load_check_proc) {
01656 ch->load_check_proc();
01657 } else {
01658 SlSkipBytes(len);
01659 }
01660 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01661 } else {
01662 SlErrorCorrupt("Invalid chunk type");
01663 }
01664 break;
01665 }
01666 }
01667
01672 static ChunkSaveLoadProc *_stub_save_proc;
01673
01679 static inline void SlStubSaveProc2(void *arg)
01680 {
01681 _stub_save_proc();
01682 }
01683
01689 static void SlStubSaveProc()
01690 {
01691 SlAutolength(SlStubSaveProc2, NULL);
01692 }
01693
01699 static void SlSaveChunk(const ChunkHandler *ch)
01700 {
01701 ChunkSaveLoadProc *proc = ch->save_proc;
01702
01703
01704 if (proc == NULL) return;
01705
01706 SlWriteUint32(ch->id);
01707 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01708
01709 if (ch->flags & CH_AUTO_LENGTH) {
01710
01711 _stub_save_proc = proc;
01712 proc = SlStubSaveProc;
01713 }
01714
01715 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01716 switch (ch->flags & CH_TYPE_MASK) {
01717 case CH_RIFF:
01718 _sl.need_length = NL_WANTLENGTH;
01719 proc();
01720 break;
01721 case CH_ARRAY:
01722 _sl.last_array_index = 0;
01723 SlWriteByte(CH_ARRAY);
01724 proc();
01725 SlWriteArrayLength(0);
01726 break;
01727 case CH_SPARSE_ARRAY:
01728 SlWriteByte(CH_SPARSE_ARRAY);
01729 proc();
01730 SlWriteArrayLength(0);
01731 break;
01732 default: NOT_REACHED();
01733 }
01734 }
01735
01737 static void SlSaveChunks()
01738 {
01739 FOR_ALL_CHUNK_HANDLERS(ch) {
01740 SlSaveChunk(ch);
01741 }
01742
01743
01744 SlWriteUint32(0);
01745 }
01746
01753 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01754 {
01755 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01756 return NULL;
01757 }
01758
01760 static void SlLoadChunks()
01761 {
01762 uint32 id;
01763 const ChunkHandler *ch;
01764
01765 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01766 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01767
01768 ch = SlFindChunkHandler(id);
01769 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01770 SlLoadChunk(ch);
01771 }
01772 }
01773
01775 static void SlLoadCheckChunks()
01776 {
01777 uint32 id;
01778 const ChunkHandler *ch;
01779
01780 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01781 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01782
01783 ch = SlFindChunkHandler(id);
01784 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01785 SlLoadCheckChunk(ch);
01786 }
01787 }
01788
01790 static void SlFixPointers()
01791 {
01792 _sl.action = SLA_PTRS;
01793
01794 DEBUG(sl, 1, "Fixing pointers");
01795
01796 FOR_ALL_CHUNK_HANDLERS(ch) {
01797 if (ch->ptrs_proc != NULL) {
01798 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01799 ch->ptrs_proc();
01800 }
01801 }
01802
01803 DEBUG(sl, 1, "All pointers fixed");
01804
01805 assert(_sl.action == SLA_PTRS);
01806 }
01807
01808
01810 struct FileReader : LoadFilter {
01811 FILE *file;
01812 long begin;
01813
01818 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01819 {
01820 }
01821
01823 ~FileReader()
01824 {
01825 if (this->file != NULL) fclose(this->file);
01826 this->file = NULL;
01827
01828
01829 _sl.sf = NULL;
01830 }
01831
01832 size_t Read(byte *buf, size_t size)
01833 {
01834
01835 if (this->file == NULL) return 0;
01836
01837 return fread(buf, 1, size, this->file);
01838 }
01839
01840 void Reset()
01841 {
01842 clearerr(this->file);
01843 fseek(this->file, this->begin, SEEK_SET);
01844 }
01845 };
01846
01848 struct FileWriter : SaveFilter {
01849 FILE *file;
01850
01855 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01856 {
01857 }
01858
01860 ~FileWriter()
01861 {
01862 this->Finish();
01863
01864
01865 _sl.sf = NULL;
01866 }
01867
01868 void Write(byte *buf, size_t size)
01869 {
01870
01871 if (this->file == NULL) return;
01872
01873 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01874 }
01875
01876 void Finish()
01877 {
01878 if (this->file != NULL) fclose(this->file);
01879 this->file = NULL;
01880 }
01881 };
01882
01883
01884
01885
01886
01887 #ifdef WITH_LZO
01888 #include <lzo/lzo1x.h>
01889
01891 static const uint LZO_BUFFER_SIZE = 8192;
01892
01894 struct LZOLoadFilter : LoadFilter {
01899 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01900 {
01901 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01902 }
01903
01904 size_t Read(byte *buf, size_t ssize)
01905 {
01906 assert(ssize >= LZO_BUFFER_SIZE);
01907
01908
01909 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01910 uint32 tmp[2];
01911 uint32 size;
01912 lzo_uint len;
01913
01914
01915 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01916
01917
01918 ((uint32*)out)[0] = size = tmp[1];
01919
01920 if (_sl_version != 0) {
01921 tmp[0] = TO_BE32(tmp[0]);
01922 size = TO_BE32(size);
01923 }
01924
01925 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01926
01927
01928 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01929
01930
01931 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01932
01933
01934 lzo1x_decompress_safe(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01935 return len;
01936 }
01937 };
01938
01940 struct LZOSaveFilter : SaveFilter {
01946 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01947 {
01948 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01949 }
01950
01951 void Write(byte *buf, size_t size)
01952 {
01953 const lzo_bytep in = buf;
01954
01955 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01956 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01957 lzo_uint outlen;
01958
01959 do {
01960
01961 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01962 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01963 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01964 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01965 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01966
01967
01968 size -= len;
01969 in += len;
01970 } while (size > 0);
01971 }
01972 };
01973
01974 #endif
01975
01976
01977
01978
01979
01981 struct NoCompLoadFilter : LoadFilter {
01986 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01987 {
01988 }
01989
01990 size_t Read(byte *buf, size_t size)
01991 {
01992 return this->chain->Read(buf, size);
01993 }
01994 };
01995
01997 struct NoCompSaveFilter : SaveFilter {
02003 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02004 {
02005 }
02006
02007 void Write(byte *buf, size_t size)
02008 {
02009 this->chain->Write(buf, size);
02010 }
02011 };
02012
02013
02014
02015
02016
02017 #if defined(WITH_ZLIB)
02018 #include <zlib.h>
02019
02021 struct ZlibLoadFilter : LoadFilter {
02022 z_stream z;
02023 byte fread_buf[MEMORY_CHUNK_SIZE];
02024
02029 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
02030 {
02031 memset(&this->z, 0, sizeof(this->z));
02032 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02033 }
02034
02036 ~ZlibLoadFilter()
02037 {
02038 inflateEnd(&this->z);
02039 }
02040
02041 size_t Read(byte *buf, size_t size)
02042 {
02043 this->z.next_out = buf;
02044 this->z.avail_out = (uint)size;
02045
02046 do {
02047
02048 if (this->z.avail_in == 0) {
02049 this->z.next_in = this->fread_buf;
02050 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02051 }
02052
02053
02054 int r = inflate(&this->z, 0);
02055 if (r == Z_STREAM_END) break;
02056
02057 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02058 } while (this->z.avail_out != 0);
02059
02060 return size - this->z.avail_out;
02061 }
02062 };
02063
02065 struct ZlibSaveFilter : SaveFilter {
02066 z_stream z;
02067
02073 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02074 {
02075 memset(&this->z, 0, sizeof(this->z));
02076 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02077 }
02078
02080 ~ZlibSaveFilter()
02081 {
02082 deflateEnd(&this->z);
02083 }
02084
02091 void WriteLoop(byte *p, size_t len, int mode)
02092 {
02093 byte buf[MEMORY_CHUNK_SIZE];
02094 uint n;
02095 this->z.next_in = p;
02096 this->z.avail_in = (uInt)len;
02097 do {
02098 this->z.next_out = buf;
02099 this->z.avail_out = sizeof(buf);
02100
02108 int r = deflate(&this->z, mode);
02109
02110
02111 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02112 this->chain->Write(buf, n);
02113 }
02114 if (r == Z_STREAM_END) break;
02115
02116 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02117 } while (this->z.avail_in || !this->z.avail_out);
02118 }
02119
02120 void Write(byte *buf, size_t size)
02121 {
02122 this->WriteLoop(buf, size, 0);
02123 }
02124
02125 void Finish()
02126 {
02127 this->WriteLoop(NULL, 0, Z_FINISH);
02128 this->chain->Finish();
02129 }
02130 };
02131
02132 #endif
02133
02134
02135
02136
02137
02138 #if defined(WITH_LZMA)
02139 #include <lzma.h>
02140
02147 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02148
02150 struct LZMALoadFilter : LoadFilter {
02151 lzma_stream lzma;
02152 byte fread_buf[MEMORY_CHUNK_SIZE];
02153
02158 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02159 {
02160
02161 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02162 }
02163
02165 ~LZMALoadFilter()
02166 {
02167 lzma_end(&this->lzma);
02168 }
02169
02170 size_t Read(byte *buf, size_t size)
02171 {
02172 this->lzma.next_out = buf;
02173 this->lzma.avail_out = size;
02174
02175 do {
02176
02177 if (this->lzma.avail_in == 0) {
02178 this->lzma.next_in = this->fread_buf;
02179 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02180 }
02181
02182
02183 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02184 if (r == LZMA_STREAM_END) break;
02185 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02186 } while (this->lzma.avail_out != 0);
02187
02188 return size - this->lzma.avail_out;
02189 }
02190 };
02191
02193 struct LZMASaveFilter : SaveFilter {
02194 lzma_stream lzma;
02195
02201 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02202 {
02203 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02204 }
02205
02207 ~LZMASaveFilter()
02208 {
02209 lzma_end(&this->lzma);
02210 }
02211
02218 void WriteLoop(byte *p, size_t len, lzma_action action)
02219 {
02220 byte buf[MEMORY_CHUNK_SIZE];
02221 size_t n;
02222 this->lzma.next_in = p;
02223 this->lzma.avail_in = len;
02224 do {
02225 this->lzma.next_out = buf;
02226 this->lzma.avail_out = sizeof(buf);
02227
02228 lzma_ret r = lzma_code(&this->lzma, action);
02229
02230
02231 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02232 this->chain->Write(buf, n);
02233 }
02234 if (r == LZMA_STREAM_END) break;
02235 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02236 } while (this->lzma.avail_in || !this->lzma.avail_out);
02237 }
02238
02239 void Write(byte *buf, size_t size)
02240 {
02241 this->WriteLoop(buf, size, LZMA_RUN);
02242 }
02243
02244 void Finish()
02245 {
02246 this->WriteLoop(NULL, 0, LZMA_FINISH);
02247 this->chain->Finish();
02248 }
02249 };
02250
02251 #endif
02252
02253
02254
02255
02256
02258 struct SaveLoadFormat {
02259 const char *name;
02260 uint32 tag;
02261
02262 LoadFilter *(*init_load)(LoadFilter *chain);
02263 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02264
02265 byte min_compression;
02266 byte default_compression;
02267 byte max_compression;
02268 };
02269
02271 static const SaveLoadFormat _saveload_formats[] = {
02272 #if defined(WITH_LZO)
02273
02274 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02275 #else
02276 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02277 #endif
02278
02279 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02280 #if defined(WITH_ZLIB)
02281
02282
02283
02284 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02285 #else
02286 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02287 #endif
02288 #if defined(WITH_LZMA)
02289
02290
02291
02292
02293
02294 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02295 #else
02296 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02297 #endif
02298 };
02299
02307 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02308 {
02309 const SaveLoadFormat *def = lastof(_saveload_formats);
02310
02311
02312 while (!def->init_write) def--;
02313
02314 if (!StrEmpty(s)) {
02315
02316 char *complevel = strrchr(s, ':');
02317 if (complevel != NULL) *complevel = '\0';
02318
02319 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02320 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02321 *compression_level = slf->default_compression;
02322 if (complevel != NULL) {
02323
02324
02325
02326 *complevel = ':';
02327 complevel++;
02328
02329
02330 char *end;
02331 long level = strtol(complevel, &end, 10);
02332 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02333 SetDParamStr(0, complevel);
02334 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL);
02335 } else {
02336 *compression_level = level;
02337 }
02338 }
02339 return slf;
02340 }
02341 }
02342
02343 SetDParamStr(0, s);
02344 SetDParamStr(1, def->name);
02345 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL);
02346
02347
02348 if (complevel != NULL) *complevel = ':';
02349 }
02350 *compression_level = def->default_compression;
02351 return def;
02352 }
02353
02354
02355 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02356 extern bool AfterLoadGame();
02357 extern bool LoadOldSaveGame(const char *file);
02358
02362 static inline void ClearSaveLoadState()
02363 {
02364 delete _sl.dumper;
02365 _sl.dumper = NULL;
02366
02367 delete _sl.sf;
02368 _sl.sf = NULL;
02369
02370 delete _sl.reader;
02371 _sl.reader = NULL;
02372
02373 delete _sl.lf;
02374 _sl.lf = NULL;
02375 }
02376
02382 static void SaveFileStart()
02383 {
02384 _sl.ff_state = _fast_forward;
02385 _fast_forward = 0;
02386 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02387
02388 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02389 _sl.saveinprogress = true;
02390 }
02391
02393 static void SaveFileDone()
02394 {
02395 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02396 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02397
02398 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02399 _sl.saveinprogress = false;
02400 }
02401
02403 void SetSaveLoadError(StringID str)
02404 {
02405 _sl.error_str = str;
02406 }
02407
02409 const char *GetSaveLoadErrorString()
02410 {
02411 SetDParam(0, _sl.error_str);
02412 SetDParamStr(1, _sl.extra_msg);
02413
02414 static char err_str[512];
02415 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02416 return err_str;
02417 }
02418
02420 static void SaveFileError()
02421 {
02422 SetDParamStr(0, GetSaveLoadErrorString());
02423 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02424 SaveFileDone();
02425 }
02426
02431 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02432 {
02433 try {
02434 byte compression;
02435 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02436
02437
02438 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02439 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02440
02441 _sl.sf = fmt->init_write(_sl.sf, compression);
02442 _sl.dumper->Flush(_sl.sf);
02443
02444 ClearSaveLoadState();
02445
02446 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02447
02448 return SL_OK;
02449 } catch (...) {
02450 ClearSaveLoadState();
02451
02452 AsyncSaveFinishProc asfp = SaveFileDone;
02453
02454
02455
02456 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02457
02458 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02459 asfp = SaveFileError;
02460 }
02461
02462 if (threaded) {
02463 SetAsyncSaveFinish(asfp);
02464 } else {
02465 asfp();
02466 }
02467 return SL_ERROR;
02468 }
02469 }
02470
02472 static void SaveFileToDiskThread(void *arg)
02473 {
02474 SaveFileToDisk(true);
02475 }
02476
02477 void WaitTillSaved()
02478 {
02479 if (_save_thread == NULL) return;
02480
02481 _save_thread->Join();
02482 delete _save_thread;
02483 _save_thread = NULL;
02484
02485
02486 ProcessAsyncSaveFinish();
02487 }
02488
02497 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02498 {
02499 assert(!_sl.saveinprogress);
02500
02501 _sl.dumper = new MemoryDumper();
02502 _sl.sf = writer;
02503
02504 _sl_version = SAVEGAME_VERSION;
02505
02506 SaveViewportBeforeSaveGame();
02507 SlSaveChunks();
02508
02509 SaveFileStart();
02510 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02511 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02512
02513 SaveOrLoadResult result = SaveFileToDisk(false);
02514 SaveFileDone();
02515
02516 return result;
02517 }
02518
02519 return SL_OK;
02520 }
02521
02528 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02529 {
02530 try {
02531 _sl.action = SLA_SAVE;
02532 return DoSave(writer, threaded);
02533 } catch (...) {
02534 ClearSaveLoadState();
02535 return SL_ERROR;
02536 }
02537 }
02538
02545 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02546 {
02547 _sl.lf = reader;
02548
02549 if (load_check) {
02550
02551 _load_check_data.Clear();
02552
02553 _load_check_data.checkable = true;
02554 }
02555
02556 uint32 hdr[2];
02557 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02558
02559
02560 const SaveLoadFormat *fmt = _saveload_formats;
02561 for (;;) {
02562
02563 if (fmt == endof(_saveload_formats)) {
02564 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02565 _sl.lf->Reset();
02566 _sl_version = 0;
02567 _sl_minor_version = 0;
02568
02569
02570 fmt = _saveload_formats;
02571 for (;;) {
02572 if (fmt == endof(_saveload_formats)) {
02573
02574 NOT_REACHED();
02575 }
02576 if (fmt->tag == TO_BE32X('OTTD')) break;
02577 fmt++;
02578 }
02579 break;
02580 }
02581
02582 if (fmt->tag == hdr[0]) {
02583
02584 _sl_version = TO_BE32(hdr[1]) >> 16;
02585
02586
02587
02588 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02589
02590 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02591
02592
02593 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02594 break;
02595 }
02596
02597 fmt++;
02598 }
02599
02600
02601 if (fmt->init_load == NULL) {
02602 char err_str[64];
02603 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02604 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02605 }
02606
02607 _sl.lf = fmt->init_load(_sl.lf);
02608 _sl.reader = new ReadBuffer(_sl.lf);
02609 _next_offs = 0;
02610
02611 if (!load_check) {
02612
02613
02614
02615 InitializeGame(256, 256, true, true);
02616
02617 GamelogReset();
02618
02619 if (IsSavegameVersionBefore(4)) {
02620
02621
02622
02623
02624
02625
02626
02627
02628
02629
02630
02631
02632
02633
02634
02635
02636
02637
02638
02639
02640
02641 ClearGRFConfigList(&_grfconfig);
02642 }
02643 }
02644
02645 if (load_check) {
02646
02647
02648 SlLoadCheckChunks();
02649 } else {
02650
02651 SlLoadChunks();
02652 SlFixPointers();
02653 }
02654
02655 ClearSaveLoadState();
02656
02657 _savegame_type = SGT_OTTD;
02658
02659 if (load_check) {
02660
02661 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02662 } else {
02663 GamelogStartAction(GLAT_LOAD);
02664
02665
02666
02667 if (!AfterLoadGame()) {
02668 GamelogStopAction();
02669 return SL_REINIT;
02670 }
02671
02672 GamelogStopAction();
02673 }
02674
02675 return SL_OK;
02676 }
02677
02683 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02684 {
02685 try {
02686 _sl.action = SLA_LOAD;
02687 return DoLoad(reader, false);
02688 } catch (...) {
02689 ClearSaveLoadState();
02690 return SL_REINIT;
02691 }
02692 }
02693
02703 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02704 {
02705
02706 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02707
02708 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02709 return SL_OK;
02710 }
02711 WaitTillSaved();
02712
02713
02714 if (mode == SL_OLD_LOAD) {
02715 InitializeGame(256, 256, true, true);
02716
02717
02718
02719
02720
02721 ClearGRFConfigList(&_grfconfig);
02722 GamelogReset();
02723 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02724 _sl_version = 0;
02725 _sl_minor_version = 0;
02726 GamelogStartAction(GLAT_LOAD);
02727 if (!AfterLoadGame()) {
02728 GamelogStopAction();
02729 return SL_REINIT;
02730 }
02731 GamelogStopAction();
02732 return SL_OK;
02733 }
02734
02735 switch (mode) {
02736 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02737 case SL_LOAD: _sl.action = SLA_LOAD; break;
02738 case SL_SAVE: _sl.action = SLA_SAVE; break;
02739 default: NOT_REACHED();
02740 }
02741
02742 try {
02743 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02744
02745
02746 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02747 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02748 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
02749
02750 if (fh == NULL) {
02751 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02752 }
02753
02754 if (mode == SL_SAVE) {
02755 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02756 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02757
02758 return DoSave(new FileWriter(fh), threaded);
02759 }
02760
02761
02762 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02763 DEBUG(desync, 1, "load: %s", filename);
02764 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02765 } catch (...) {
02766 ClearSaveLoadState();
02767
02768
02769 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02770
02771
02772 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02773 }
02774 }
02775
02777 void DoExitSave()
02778 {
02779 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02780 }
02781
02787 void GenerateDefaultSaveName(char *buf, const char *last)
02788 {
02789
02790
02791
02792 CompanyID cid = _local_company;
02793 if (!Company::IsValidID(cid)) {
02794 const Company *c;
02795 FOR_ALL_COMPANIES(c) {
02796 cid = c->index;
02797 break;
02798 }
02799 }
02800
02801 SetDParam(0, cid);
02802
02803
02804 switch (_settings_client.gui.date_format_in_default_names) {
02805 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02806 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02807 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02808 default: NOT_REACHED();
02809 }
02810 SetDParam(2, _date);
02811
02812
02813 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02814 SanitizeFilename(buf);
02815 }
02816
02817 #if 0
02818
02824 int GetSavegameType(char *file)
02825 {
02826 const SaveLoadFormat *fmt;
02827 uint32 hdr;
02828 FILE *f;
02829 int mode = SL_OLD_LOAD;
02830
02831 f = fopen(file, "rb");
02832 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02833 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02834 mode = SL_LOAD;
02835 } else {
02836
02837 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02838 if (fmt->tag == hdr) {
02839 mode = SL_LOAD;
02840 break;
02841 }
02842 }
02843 }
02844
02845 fclose(f);
02846 return mode;
02847 }
02848 #endif