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