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
00252
00253
00254
00255
00256
00257
00258 extern const uint16 SAVEGAME_VERSION = 188;
00259
00260 SavegameType _savegame_type;
00261
00262 uint32 _ttdp_version;
00263 uint16 _sl_version;
00264 byte _sl_minor_version;
00265 char _savegame_format[8];
00266 bool _do_autosave;
00267
00269 enum SaveLoadAction {
00270 SLA_LOAD,
00271 SLA_SAVE,
00272 SLA_PTRS,
00273 SLA_NULL,
00274 SLA_LOAD_CHECK,
00275 };
00276
00277 enum NeedLength {
00278 NL_NONE = 0,
00279 NL_WANTLENGTH = 1,
00280 NL_CALCLENGTH = 2,
00281 };
00282
00284 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
00285
00287 struct ReadBuffer {
00288 byte buf[MEMORY_CHUNK_SIZE];
00289 byte *bufp;
00290 byte *bufe;
00291 LoadFilter *reader;
00292 size_t read;
00293
00298 ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
00299 {
00300 }
00301
00302 inline byte ReadByte()
00303 {
00304 if (this->bufp == this->bufe) {
00305 size_t len = this->reader->Read(this->buf, lengthof(this->buf));
00306 if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00307
00308 this->read += len;
00309 this->bufp = this->buf;
00310 this->bufe = this->buf + len;
00311 }
00312
00313 return *this->bufp++;
00314 }
00315
00320 size_t GetSize() const
00321 {
00322 return this->read - (this->bufe - this->bufp);
00323 }
00324 };
00325
00326
00328 struct MemoryDumper {
00329 AutoFreeSmallVector<byte *, 16> blocks;
00330 byte *buf;
00331 byte *bufe;
00332
00334 MemoryDumper() : buf(NULL), bufe(NULL)
00335 {
00336 }
00337
00342 inline void WriteByte(byte b)
00343 {
00344
00345 if (this->buf == this->bufe) {
00346 this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
00347 *this->blocks.Append() = this->buf;
00348 this->bufe = this->buf + MEMORY_CHUNK_SIZE;
00349 }
00350
00351 *this->buf++ = b;
00352 }
00353
00358 void Flush(SaveFilter *writer)
00359 {
00360 uint i = 0;
00361 size_t t = this->GetSize();
00362
00363 while (t > 0) {
00364 size_t to_write = min(MEMORY_CHUNK_SIZE, t);
00365
00366 writer->Write(this->blocks[i++], to_write);
00367 t -= to_write;
00368 }
00369
00370 writer->Finish();
00371 }
00372
00377 size_t GetSize() const
00378 {
00379 return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
00380 }
00381 };
00382
00384 struct SaveLoadParams {
00385 SaveLoadAction action;
00386 NeedLength need_length;
00387 byte block_mode;
00388 bool error;
00389
00390 size_t obj_len;
00391 int array_index, last_array_index;
00392
00393 MemoryDumper *dumper;
00394 SaveFilter *sf;
00395
00396 ReadBuffer *reader;
00397 LoadFilter *lf;
00398
00399 StringID error_str;
00400 char *extra_msg;
00401
00402 byte ff_state;
00403 bool saveinprogress;
00404 };
00405
00406 static SaveLoadParams _sl;
00407
00408
00409 extern const ChunkHandler _gamelog_chunk_handlers[];
00410 extern const ChunkHandler _map_chunk_handlers[];
00411 extern const ChunkHandler _misc_chunk_handlers[];
00412 extern const ChunkHandler _name_chunk_handlers[];
00413 extern const ChunkHandler _cheat_chunk_handlers[] ;
00414 extern const ChunkHandler _setting_chunk_handlers[];
00415 extern const ChunkHandler _company_chunk_handlers[];
00416 extern const ChunkHandler _engine_chunk_handlers[];
00417 extern const ChunkHandler _veh_chunk_handlers[];
00418 extern const ChunkHandler _waypoint_chunk_handlers[];
00419 extern const ChunkHandler _depot_chunk_handlers[];
00420 extern const ChunkHandler _order_chunk_handlers[];
00421 extern const ChunkHandler _town_chunk_handlers[];
00422 extern const ChunkHandler _sign_chunk_handlers[];
00423 extern const ChunkHandler _station_chunk_handlers[];
00424 extern const ChunkHandler _industry_chunk_handlers[];
00425 extern const ChunkHandler _economy_chunk_handlers[];
00426 extern const ChunkHandler _subsidy_chunk_handlers[];
00427 extern const ChunkHandler _cargomonitor_chunk_handlers[];
00428 extern const ChunkHandler _goal_chunk_handlers[];
00429 extern const ChunkHandler _story_page_chunk_handlers[];
00430 extern const ChunkHandler _ai_chunk_handlers[];
00431 extern const ChunkHandler _game_chunk_handlers[];
00432 extern const ChunkHandler _animated_tile_chunk_handlers[];
00433 extern const ChunkHandler _newgrf_chunk_handlers[];
00434 extern const ChunkHandler _group_chunk_handlers[];
00435 extern const ChunkHandler _cargopacket_chunk_handlers[];
00436 extern const ChunkHandler _autoreplace_chunk_handlers[];
00437 extern const ChunkHandler _labelmaps_chunk_handlers[];
00438 extern const ChunkHandler _linkgraph_chunk_handlers[];
00439 extern const ChunkHandler _airport_chunk_handlers[];
00440 extern const ChunkHandler _object_chunk_handlers[];
00441 extern const ChunkHandler _persistent_storage_chunk_handlers[];
00442
00444 static const ChunkHandler * const _chunk_handlers[] = {
00445 _gamelog_chunk_handlers,
00446 _map_chunk_handlers,
00447 _misc_chunk_handlers,
00448 _name_chunk_handlers,
00449 _cheat_chunk_handlers,
00450 _setting_chunk_handlers,
00451 _veh_chunk_handlers,
00452 _waypoint_chunk_handlers,
00453 _depot_chunk_handlers,
00454 _order_chunk_handlers,
00455 _industry_chunk_handlers,
00456 _economy_chunk_handlers,
00457 _subsidy_chunk_handlers,
00458 _cargomonitor_chunk_handlers,
00459 _goal_chunk_handlers,
00460 _story_page_chunk_handlers,
00461 _engine_chunk_handlers,
00462 _town_chunk_handlers,
00463 _sign_chunk_handlers,
00464 _station_chunk_handlers,
00465 _company_chunk_handlers,
00466 _ai_chunk_handlers,
00467 _game_chunk_handlers,
00468 _animated_tile_chunk_handlers,
00469 _newgrf_chunk_handlers,
00470 _group_chunk_handlers,
00471 _cargopacket_chunk_handlers,
00472 _autoreplace_chunk_handlers,
00473 _labelmaps_chunk_handlers,
00474 _linkgraph_chunk_handlers,
00475 _airport_chunk_handlers,
00476 _object_chunk_handlers,
00477 _persistent_storage_chunk_handlers,
00478 NULL,
00479 };
00480
00485 #define FOR_ALL_CHUNK_HANDLERS(ch) \
00486 for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \
00487 for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1)
00488
00490 static void SlNullPointers()
00491 {
00492 _sl.action = SLA_NULL;
00493
00494
00495
00496
00497 _sl_version = SAVEGAME_VERSION;
00498
00499 DEBUG(sl, 1, "Nulling pointers");
00500
00501 FOR_ALL_CHUNK_HANDLERS(ch) {
00502 if (ch->ptrs_proc != NULL) {
00503 DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00504 ch->ptrs_proc();
00505 }
00506 }
00507
00508 DEBUG(sl, 1, "All pointers nulled");
00509
00510 assert(_sl.action == SLA_NULL);
00511 }
00512
00521 void NORETURN SlError(StringID string, const char *extra_msg)
00522 {
00523
00524 if (_sl.action == SLA_LOAD_CHECK) {
00525 _load_check_data.error = string;
00526 free(_load_check_data.error_data);
00527 _load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00528 } else {
00529 _sl.error_str = string;
00530 free(_sl.extra_msg);
00531 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00532 }
00533
00534
00535
00536
00537
00538 if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00539 throw std::exception();
00540 }
00541
00549 void NORETURN SlErrorCorrupt(const char *msg)
00550 {
00551 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00552 }
00553
00554
00555 typedef void (*AsyncSaveFinishProc)();
00556 static AsyncSaveFinishProc _async_save_finish = NULL;
00557 static ThreadObject *_save_thread;
00558
00563 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00564 {
00565 if (_exit_game) return;
00566 while (_async_save_finish != NULL) CSleep(10);
00567
00568 _async_save_finish = proc;
00569 }
00570
00574 void ProcessAsyncSaveFinish()
00575 {
00576 if (_async_save_finish == NULL) return;
00577
00578 _async_save_finish();
00579
00580 _async_save_finish = NULL;
00581
00582 if (_save_thread != NULL) {
00583 _save_thread->Join();
00584 delete _save_thread;
00585 _save_thread = NULL;
00586 }
00587 }
00588
00593 byte SlReadByte()
00594 {
00595 return _sl.reader->ReadByte();
00596 }
00597
00602 void SlWriteByte(byte b)
00603 {
00604 _sl.dumper->WriteByte(b);
00605 }
00606
00607 static inline int SlReadUint16()
00608 {
00609 int x = SlReadByte() << 8;
00610 return x | SlReadByte();
00611 }
00612
00613 static inline uint32 SlReadUint32()
00614 {
00615 uint32 x = SlReadUint16() << 16;
00616 return x | SlReadUint16();
00617 }
00618
00619 static inline uint64 SlReadUint64()
00620 {
00621 uint32 x = SlReadUint32();
00622 uint32 y = SlReadUint32();
00623 return (uint64)x << 32 | y;
00624 }
00625
00626 static inline void SlWriteUint16(uint16 v)
00627 {
00628 SlWriteByte(GB(v, 8, 8));
00629 SlWriteByte(GB(v, 0, 8));
00630 }
00631
00632 static inline void SlWriteUint32(uint32 v)
00633 {
00634 SlWriteUint16(GB(v, 16, 16));
00635 SlWriteUint16(GB(v, 0, 16));
00636 }
00637
00638 static inline void SlWriteUint64(uint64 x)
00639 {
00640 SlWriteUint32((uint32)(x >> 32));
00641 SlWriteUint32((uint32)x);
00642 }
00643
00649 static inline void SlSkipBytes(size_t length)
00650 {
00651 for (; length != 0; length--) SlReadByte();
00652 }
00653
00663 static uint SlReadSimpleGamma()
00664 {
00665 uint i = SlReadByte();
00666 if (HasBit(i, 7)) {
00667 i &= ~0x80;
00668 if (HasBit(i, 6)) {
00669 i &= ~0x40;
00670 if (HasBit(i, 5)) {
00671 i &= ~0x20;
00672 if (HasBit(i, 4)) {
00673 i &= ~0x10;
00674 if (HasBit(i, 3)) {
00675 SlErrorCorrupt("Unsupported gamma");
00676 }
00677 i = SlReadByte();
00678 }
00679 i = (i << 8) | SlReadByte();
00680 }
00681 i = (i << 8) | SlReadByte();
00682 }
00683 i = (i << 8) | SlReadByte();
00684 }
00685 return i;
00686 }
00687
00705 static void SlWriteSimpleGamma(size_t i)
00706 {
00707 if (i >= (1 << 7)) {
00708 if (i >= (1 << 14)) {
00709 if (i >= (1 << 21)) {
00710 if (i >= (1 << 28)) {
00711 assert(i <= UINT32_MAX);
00712 SlWriteByte((byte)(0xF0));
00713 SlWriteByte((byte)(i >> 24));
00714 } else {
00715 SlWriteByte((byte)(0xE0 | (i >> 24)));
00716 }
00717 SlWriteByte((byte)(i >> 16));
00718 } else {
00719 SlWriteByte((byte)(0xC0 | (i >> 16)));
00720 }
00721 SlWriteByte((byte)(i >> 8));
00722 } else {
00723 SlWriteByte((byte)(0x80 | (i >> 8)));
00724 }
00725 }
00726 SlWriteByte((byte)i);
00727 }
00728
00730 static inline uint SlGetGammaLength(size_t i)
00731 {
00732 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21)) + (i >= (1 << 28));
00733 }
00734
00735 static inline uint SlReadSparseIndex()
00736 {
00737 return SlReadSimpleGamma();
00738 }
00739
00740 static inline void SlWriteSparseIndex(uint index)
00741 {
00742 SlWriteSimpleGamma(index);
00743 }
00744
00745 static inline uint SlReadArrayLength()
00746 {
00747 return SlReadSimpleGamma();
00748 }
00749
00750 static inline void SlWriteArrayLength(size_t length)
00751 {
00752 SlWriteSimpleGamma(length);
00753 }
00754
00755 static inline uint SlGetArrayLength(size_t length)
00756 {
00757 return SlGetGammaLength(length);
00758 }
00759
00766 static inline uint SlCalcConvMemLen(VarType conv)
00767 {
00768 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00769 byte length = GB(conv, 4, 4);
00770
00771 switch (length << 4) {
00772 case SLE_VAR_STRB:
00773 case SLE_VAR_STRBQ:
00774 case SLE_VAR_STR:
00775 case SLE_VAR_STRQ:
00776 return SlReadArrayLength();
00777
00778 default:
00779 assert(length < lengthof(conv_mem_size));
00780 return conv_mem_size[length];
00781 }
00782 }
00783
00790 static inline byte SlCalcConvFileLen(VarType conv)
00791 {
00792 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00793 byte length = GB(conv, 0, 4);
00794 assert(length < lengthof(conv_file_size));
00795 return conv_file_size[length];
00796 }
00797
00799 static inline size_t SlCalcRefLen()
00800 {
00801 return IsSavegameVersionBefore(69) ? 2 : 4;
00802 }
00803
00804 void SlSetArrayIndex(uint index)
00805 {
00806 _sl.need_length = NL_WANTLENGTH;
00807 _sl.array_index = index;
00808 }
00809
00810 static size_t _next_offs;
00811
00816 int SlIterateArray()
00817 {
00818 int index;
00819
00820
00821
00822 if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00823
00824 for (;;) {
00825 uint length = SlReadArrayLength();
00826 if (length == 0) {
00827 _next_offs = 0;
00828 return -1;
00829 }
00830
00831 _sl.obj_len = --length;
00832 _next_offs = _sl.reader->GetSize() + length;
00833
00834 switch (_sl.block_mode) {
00835 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00836 case CH_ARRAY: index = _sl.array_index++; break;
00837 default:
00838 DEBUG(sl, 0, "SlIterateArray error");
00839 return -1;
00840 }
00841
00842 if (length != 0) return index;
00843 }
00844 }
00845
00849 void SlSkipArray()
00850 {
00851 while (SlIterateArray() != -1) {
00852 SlSkipBytes(_next_offs - _sl.reader->GetSize());
00853 }
00854 }
00855
00861 void SlSetLength(size_t length)
00862 {
00863 assert(_sl.action == SLA_SAVE);
00864
00865 switch (_sl.need_length) {
00866 case NL_WANTLENGTH:
00867 _sl.need_length = NL_NONE;
00868 switch (_sl.block_mode) {
00869 case CH_RIFF:
00870
00871
00872
00873 assert(length < (1 << 28));
00874 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00875 break;
00876 case CH_ARRAY:
00877 assert(_sl.last_array_index <= _sl.array_index);
00878 while (++_sl.last_array_index <= _sl.array_index) {
00879 SlWriteArrayLength(1);
00880 }
00881 SlWriteArrayLength(length + 1);
00882 break;
00883 case CH_SPARSE_ARRAY:
00884 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00885 SlWriteSparseIndex(_sl.array_index);
00886 break;
00887 default: NOT_REACHED();
00888 }
00889 break;
00890
00891 case NL_CALCLENGTH:
00892 _sl.obj_len += (int)length;
00893 break;
00894
00895 default: NOT_REACHED();
00896 }
00897 }
00898
00905 static void SlCopyBytes(void *ptr, size_t length)
00906 {
00907 byte *p = (byte *)ptr;
00908
00909 switch (_sl.action) {
00910 case SLA_LOAD_CHECK:
00911 case SLA_LOAD:
00912 for (; length != 0; length--) *p++ = SlReadByte();
00913 break;
00914 case SLA_SAVE:
00915 for (; length != 0; length--) SlWriteByte(*p++);
00916 break;
00917 default: NOT_REACHED();
00918 }
00919 }
00920
00922 size_t SlGetFieldLength()
00923 {
00924 return _sl.obj_len;
00925 }
00926
00934 int64 ReadValue(const void *ptr, VarType conv)
00935 {
00936 switch (GetVarMemType(conv)) {
00937 case SLE_VAR_BL: return (*(const bool *)ptr != 0);
00938 case SLE_VAR_I8: return *(const int8 *)ptr;
00939 case SLE_VAR_U8: return *(const byte *)ptr;
00940 case SLE_VAR_I16: return *(const int16 *)ptr;
00941 case SLE_VAR_U16: return *(const uint16*)ptr;
00942 case SLE_VAR_I32: return *(const int32 *)ptr;
00943 case SLE_VAR_U32: return *(const uint32*)ptr;
00944 case SLE_VAR_I64: return *(const int64 *)ptr;
00945 case SLE_VAR_U64: return *(const uint64*)ptr;
00946 case SLE_VAR_NULL:return 0;
00947 default: NOT_REACHED();
00948 }
00949 }
00950
00958 void WriteValue(void *ptr, VarType conv, int64 val)
00959 {
00960 switch (GetVarMemType(conv)) {
00961 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00962 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00963 case SLE_VAR_U8: *(byte *)ptr = val; break;
00964 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00965 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00966 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00967 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00968 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00969 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00970 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00971 case SLE_VAR_NULL: break;
00972 default: NOT_REACHED();
00973 }
00974 }
00975
00984 static void SlSaveLoadConv(void *ptr, VarType conv)
00985 {
00986 switch (_sl.action) {
00987 case SLA_SAVE: {
00988 int64 x = ReadValue(ptr, conv);
00989
00990
00991 switch (GetVarFileType(conv)) {
00992 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00993 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00994 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00995 case SLE_FILE_STRINGID:
00996 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00997 case SLE_FILE_I32:
00998 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00999 case SLE_FILE_I64:
01000 case SLE_FILE_U64: SlWriteUint64(x);break;
01001 default: NOT_REACHED();
01002 }
01003 break;
01004 }
01005 case SLA_LOAD_CHECK:
01006 case SLA_LOAD: {
01007 int64 x;
01008
01009 switch (GetVarFileType(conv)) {
01010 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
01011 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
01012 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
01013 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
01014 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
01015 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
01016 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
01017 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
01018 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
01019 default: NOT_REACHED();
01020 }
01021
01022
01023 WriteValue(ptr, conv, x);
01024 break;
01025 }
01026 case SLA_PTRS: break;
01027 case SLA_NULL: break;
01028 default: NOT_REACHED();
01029 }
01030 }
01031
01041 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
01042 {
01043 if (ptr == NULL) return 0;
01044 return min(strlen(ptr), length - 1);
01045 }
01046
01056 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
01057 {
01058 size_t len;
01059 const char *str;
01060
01061 switch (GetVarMemType(conv)) {
01062 default: NOT_REACHED();
01063 case SLE_VAR_STR:
01064 case SLE_VAR_STRQ:
01065 str = *(const char * const *)ptr;
01066 len = SIZE_MAX;
01067 break;
01068 case SLE_VAR_STRB:
01069 case SLE_VAR_STRBQ:
01070 str = (const char *)ptr;
01071 len = length;
01072 break;
01073 }
01074
01075 len = SlCalcNetStringLen(str, len);
01076 return len + SlGetArrayLength(len);
01077 }
01078
01085 static void SlString(void *ptr, size_t length, VarType conv)
01086 {
01087 switch (_sl.action) {
01088 case SLA_SAVE: {
01089 size_t len;
01090 switch (GetVarMemType(conv)) {
01091 default: NOT_REACHED();
01092 case SLE_VAR_STRB:
01093 case SLE_VAR_STRBQ:
01094 len = SlCalcNetStringLen((char *)ptr, length);
01095 break;
01096 case SLE_VAR_STR:
01097 case SLE_VAR_STRQ:
01098 ptr = *(char **)ptr;
01099 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01100 break;
01101 }
01102
01103 SlWriteArrayLength(len);
01104 SlCopyBytes(ptr, len);
01105 break;
01106 }
01107 case SLA_LOAD_CHECK:
01108 case SLA_LOAD: {
01109 size_t len = SlReadArrayLength();
01110
01111 switch (GetVarMemType(conv)) {
01112 default: NOT_REACHED();
01113 case SLE_VAR_STRB:
01114 case SLE_VAR_STRBQ:
01115 if (len >= length) {
01116 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01117 SlCopyBytes(ptr, length);
01118 SlSkipBytes(len - length);
01119 len = length - 1;
01120 } else {
01121 SlCopyBytes(ptr, len);
01122 }
01123 break;
01124 case SLE_VAR_STR:
01125 case SLE_VAR_STRQ:
01126 free(*(char **)ptr);
01127 if (len == 0) {
01128 *(char **)ptr = NULL;
01129 return;
01130 } else {
01131 *(char **)ptr = MallocT<char>(len + 1);
01132 ptr = *(char **)ptr;
01133 SlCopyBytes(ptr, len);
01134 }
01135 break;
01136 }
01137
01138 ((char *)ptr)[len] = '\0';
01139 StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
01140 if ((conv & SLF_ALLOW_CONTROL) != 0) {
01141 settings = settings | SVS_ALLOW_CONTROL_CODE;
01142 if (IsSavegameVersionBefore(169)) {
01143 str_fix_scc_encoded((char *)ptr, (char *)ptr + len);
01144 }
01145 }
01146 if ((conv & SLF_ALLOW_NEWLINE) != 0) {
01147 settings = settings | SVS_ALLOW_NEWLINE;
01148 }
01149 str_validate((char *)ptr, (char *)ptr + len, settings);
01150 break;
01151 }
01152 case SLA_PTRS: break;
01153 case SLA_NULL: break;
01154 default: NOT_REACHED();
01155 }
01156 }
01157
01163 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01164 {
01165 return SlCalcConvFileLen(conv) * length;
01166 }
01167
01174 void SlArray(void *array, size_t length, VarType conv)
01175 {
01176 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01177
01178
01179 if (_sl.need_length != NL_NONE) {
01180 SlSetLength(SlCalcArrayLen(length, conv));
01181
01182 if (_sl.need_length == NL_CALCLENGTH) return;
01183 }
01184
01185
01186
01187 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01188
01189 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01190 conv == SLE_INT32 || conv == SLE_UINT32) {
01191 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01192 return;
01193 }
01194
01195 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01196 for (uint i = 0; i < length; i++) {
01197 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01198 }
01199 return;
01200 }
01201 }
01202
01203
01204
01205 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01206 SlCopyBytes(array, length);
01207 } else {
01208 byte *a = (byte*)array;
01209 byte mem_size = SlCalcConvMemLen(conv);
01210
01211 for (; length != 0; length --) {
01212 SlSaveLoadConv(a, conv);
01213 a += mem_size;
01214 }
01215 }
01216 }
01217
01218
01229 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01230 {
01231 assert(_sl.action == SLA_SAVE);
01232
01233 if (obj == NULL) return 0;
01234
01235 switch (rt) {
01236 case REF_VEHICLE_OLD:
01237 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01238 case REF_STATION: return ((const Station*)obj)->index + 1;
01239 case REF_TOWN: return ((const Town*)obj)->index + 1;
01240 case REF_ORDER: return ((const Order*)obj)->index + 1;
01241 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01242 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01243 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01244 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01245 case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
01246 case REF_LINK_GRAPH: return ((const LinkGraph*)obj)->index + 1;
01247 case REF_LINK_GRAPH_JOB: return ((const LinkGraphJob*)obj)->index + 1;
01248 default: NOT_REACHED();
01249 }
01250 }
01251
01262 static void *IntToReference(size_t index, SLRefType rt)
01263 {
01264 assert_compile(sizeof(size_t) <= sizeof(void *));
01265
01266 assert(_sl.action == SLA_PTRS);
01267
01268
01269
01270 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01271 rt = REF_VEHICLE;
01272 }
01273
01274
01275 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01276
01277
01278
01279 if (rt != REF_VEHICLE_OLD) index--;
01280
01281 switch (rt) {
01282 case REF_ORDERLIST:
01283 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01284 SlErrorCorrupt("Referencing invalid OrderList");
01285
01286 case REF_ORDER:
01287 if (Order::IsValidID(index)) return Order::Get(index);
01288
01289 if (IsSavegameVersionBefore(5, 2)) return NULL;
01290 SlErrorCorrupt("Referencing invalid Order");
01291
01292 case REF_VEHICLE_OLD:
01293 case REF_VEHICLE:
01294 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01295 SlErrorCorrupt("Referencing invalid Vehicle");
01296
01297 case REF_STATION:
01298 if (Station::IsValidID(index)) return Station::Get(index);
01299 SlErrorCorrupt("Referencing invalid Station");
01300
01301 case REF_TOWN:
01302 if (Town::IsValidID(index)) return Town::Get(index);
01303 SlErrorCorrupt("Referencing invalid Town");
01304
01305 case REF_ROADSTOPS:
01306 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01307 SlErrorCorrupt("Referencing invalid RoadStop");
01308
01309 case REF_ENGINE_RENEWS:
01310 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01311 SlErrorCorrupt("Referencing invalid EngineRenew");
01312
01313 case REF_CARGO_PACKET:
01314 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01315 SlErrorCorrupt("Referencing invalid CargoPacket");
01316
01317 case REF_STORAGE:
01318 if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index);
01319 SlErrorCorrupt("Referencing invalid PersistentStorage");
01320
01321 case REF_LINK_GRAPH:
01322 if (LinkGraph::IsValidID(index)) return LinkGraph::Get(index);
01323 SlErrorCorrupt("Referencing invalid LinkGraph");
01324
01325 case REF_LINK_GRAPH_JOB:
01326 if (LinkGraphJob::IsValidID(index)) return LinkGraphJob::Get(index);
01327 SlErrorCorrupt("Referencing invalid LinkGraphJob");
01328
01329 default: NOT_REACHED();
01330 }
01331 }
01332
01337 static inline size_t SlCalcListLen(const void *list)
01338 {
01339 const std::list<void *> *l = (const std::list<void *> *) list;
01340
01341 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01342
01343
01344 return l->size() * type_size + type_size;
01345 }
01346
01347
01353 static void SlList(void *list, SLRefType conv)
01354 {
01355
01356 if (_sl.need_length != NL_NONE) {
01357 SlSetLength(SlCalcListLen(list));
01358
01359 if (_sl.need_length == NL_CALCLENGTH) return;
01360 }
01361
01362 typedef std::list<void *> PtrList;
01363 PtrList *l = (PtrList *)list;
01364
01365 switch (_sl.action) {
01366 case SLA_SAVE: {
01367 SlWriteUint32((uint32)l->size());
01368
01369 PtrList::iterator iter;
01370 for (iter = l->begin(); iter != l->end(); ++iter) {
01371 void *ptr = *iter;
01372 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01373 }
01374 break;
01375 }
01376 case SLA_LOAD_CHECK:
01377 case SLA_LOAD: {
01378 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01379
01380
01381 for (size_t i = 0; i < length; i++) {
01382 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01383 l->push_back((void *)data);
01384 }
01385 break;
01386 }
01387 case SLA_PTRS: {
01388 PtrList temp = *l;
01389
01390 l->clear();
01391 PtrList::iterator iter;
01392 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01393 void *ptr = IntToReference((size_t)*iter, conv);
01394 l->push_back(ptr);
01395 }
01396 break;
01397 }
01398 case SLA_NULL:
01399 l->clear();
01400 break;
01401 default: NOT_REACHED();
01402 }
01403 }
01404
01405
01407 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01408 {
01409 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01410 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01411
01412 return true;
01413 }
01414
01420 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01421 {
01422 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01423 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01424 return true;
01425 }
01426
01427 return false;
01428 }
01429
01436 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01437 {
01438 size_t length = 0;
01439
01440
01441 for (; sld->cmd != SL_END; sld++) {
01442 length += SlCalcObjMemberLength(object, sld);
01443 }
01444 return length;
01445 }
01446
01447 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01448 {
01449 assert(_sl.action == SLA_SAVE);
01450
01451 switch (sld->cmd) {
01452 case SL_VAR:
01453 case SL_REF:
01454 case SL_ARR:
01455 case SL_STR:
01456 case SL_LST:
01457
01458 if (!SlIsObjectValidInSavegame(sld)) break;
01459
01460 switch (sld->cmd) {
01461 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01462 case SL_REF: return SlCalcRefLen();
01463 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01464 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01465 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01466 default: NOT_REACHED();
01467 }
01468 break;
01469 case SL_WRITEBYTE: return 1;
01470 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01471 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01472 default: NOT_REACHED();
01473 }
01474 return 0;
01475 }
01476
01477
01478 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01479 {
01480 VarType conv = GB(sld->conv, 0, 8);
01481 switch (sld->cmd) {
01482 case SL_VAR:
01483 case SL_REF:
01484 case SL_ARR:
01485 case SL_STR:
01486 case SL_LST:
01487
01488 if (!SlIsObjectValidInSavegame(sld)) return false;
01489 if (SlSkipVariableOnLoad(sld)) return false;
01490
01491 switch (sld->cmd) {
01492 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01493 case SL_REF:
01494 switch (_sl.action) {
01495 case SLA_SAVE:
01496 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01497 break;
01498 case SLA_LOAD_CHECK:
01499 case SLA_LOAD:
01500 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01501 break;
01502 case SLA_PTRS:
01503 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01504 break;
01505 case SLA_NULL:
01506 *(void **)ptr = NULL;
01507 break;
01508 default: NOT_REACHED();
01509 }
01510 break;
01511 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01512 case SL_STR: SlString(ptr, sld->length, sld->conv); break;
01513 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01514 default: NOT_REACHED();
01515 }
01516 break;
01517
01518
01519
01520
01521
01522
01523 case SL_WRITEBYTE:
01524 switch (_sl.action) {
01525 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01526 case SLA_LOAD_CHECK:
01527 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01528 case SLA_PTRS: break;
01529 case SLA_NULL: break;
01530 default: NOT_REACHED();
01531 }
01532 break;
01533
01534
01535 case SL_VEH_INCLUDE:
01536 SlObject(ptr, GetVehicleDescription(VEH_END));
01537 break;
01538
01539 case SL_ST_INCLUDE:
01540 SlObject(ptr, GetBaseStationDescription());
01541 break;
01542
01543 default: NOT_REACHED();
01544 }
01545 return true;
01546 }
01547
01553 void SlObject(void *object, const SaveLoad *sld)
01554 {
01555
01556 if (_sl.need_length != NL_NONE) {
01557 SlSetLength(SlCalcObjLength(object, sld));
01558 if (_sl.need_length == NL_CALCLENGTH) return;
01559 }
01560
01561 for (; sld->cmd != SL_END; sld++) {
01562 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01563 SlObjectMember(ptr, sld);
01564 }
01565 }
01566
01571 void SlGlobList(const SaveLoadGlobVarList *sldg)
01572 {
01573 SlObject(NULL, (const SaveLoad*)sldg);
01574 }
01575
01581 void SlAutolength(AutolengthProc *proc, void *arg)
01582 {
01583 size_t offs;
01584
01585 assert(_sl.action == SLA_SAVE);
01586
01587
01588 _sl.need_length = NL_CALCLENGTH;
01589 _sl.obj_len = 0;
01590 proc(arg);
01591
01592
01593 _sl.need_length = NL_WANTLENGTH;
01594 SlSetLength(_sl.obj_len);
01595
01596 offs = _sl.dumper->GetSize() + _sl.obj_len;
01597
01598
01599 proc(arg);
01600
01601 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01602 }
01603
01608 static void SlLoadChunk(const ChunkHandler *ch)
01609 {
01610 byte m = SlReadByte();
01611 size_t len;
01612 size_t endoffs;
01613
01614 _sl.block_mode = m;
01615 _sl.obj_len = 0;
01616
01617 switch (m) {
01618 case CH_ARRAY:
01619 _sl.array_index = 0;
01620 ch->load_proc();
01621 break;
01622 case CH_SPARSE_ARRAY:
01623 ch->load_proc();
01624 break;
01625 default:
01626 if ((m & 0xF) == CH_RIFF) {
01627
01628 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01629 len += SlReadUint16();
01630 _sl.obj_len = len;
01631 endoffs = _sl.reader->GetSize() + len;
01632 ch->load_proc();
01633 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01634 } else {
01635 SlErrorCorrupt("Invalid chunk type");
01636 }
01637 break;
01638 }
01639 }
01640
01646 static void SlLoadCheckChunk(const ChunkHandler *ch)
01647 {
01648 byte m = SlReadByte();
01649 size_t len;
01650 size_t endoffs;
01651
01652 _sl.block_mode = m;
01653 _sl.obj_len = 0;
01654
01655 switch (m) {
01656 case CH_ARRAY:
01657 _sl.array_index = 0;
01658 if (ch->load_check_proc) {
01659 ch->load_check_proc();
01660 } else {
01661 SlSkipArray();
01662 }
01663 break;
01664 case CH_SPARSE_ARRAY:
01665 if (ch->load_check_proc) {
01666 ch->load_check_proc();
01667 } else {
01668 SlSkipArray();
01669 }
01670 break;
01671 default:
01672 if ((m & 0xF) == CH_RIFF) {
01673
01674 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01675 len += SlReadUint16();
01676 _sl.obj_len = len;
01677 endoffs = _sl.reader->GetSize() + len;
01678 if (ch->load_check_proc) {
01679 ch->load_check_proc();
01680 } else {
01681 SlSkipBytes(len);
01682 }
01683 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01684 } else {
01685 SlErrorCorrupt("Invalid chunk type");
01686 }
01687 break;
01688 }
01689 }
01690
01695 static ChunkSaveLoadProc *_stub_save_proc;
01696
01702 static inline void SlStubSaveProc2(void *arg)
01703 {
01704 _stub_save_proc();
01705 }
01706
01712 static void SlStubSaveProc()
01713 {
01714 SlAutolength(SlStubSaveProc2, NULL);
01715 }
01716
01722 static void SlSaveChunk(const ChunkHandler *ch)
01723 {
01724 ChunkSaveLoadProc *proc = ch->save_proc;
01725
01726
01727 if (proc == NULL) return;
01728
01729 SlWriteUint32(ch->id);
01730 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01731
01732 if (ch->flags & CH_AUTO_LENGTH) {
01733
01734 _stub_save_proc = proc;
01735 proc = SlStubSaveProc;
01736 }
01737
01738 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01739 switch (ch->flags & CH_TYPE_MASK) {
01740 case CH_RIFF:
01741 _sl.need_length = NL_WANTLENGTH;
01742 proc();
01743 break;
01744 case CH_ARRAY:
01745 _sl.last_array_index = 0;
01746 SlWriteByte(CH_ARRAY);
01747 proc();
01748 SlWriteArrayLength(0);
01749 break;
01750 case CH_SPARSE_ARRAY:
01751 SlWriteByte(CH_SPARSE_ARRAY);
01752 proc();
01753 SlWriteArrayLength(0);
01754 break;
01755 default: NOT_REACHED();
01756 }
01757 }
01758
01760 static void SlSaveChunks()
01761 {
01762 FOR_ALL_CHUNK_HANDLERS(ch) {
01763 SlSaveChunk(ch);
01764 }
01765
01766
01767 SlWriteUint32(0);
01768 }
01769
01776 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01777 {
01778 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01779 return NULL;
01780 }
01781
01783 static void SlLoadChunks()
01784 {
01785 uint32 id;
01786 const ChunkHandler *ch;
01787
01788 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01789 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01790
01791 ch = SlFindChunkHandler(id);
01792 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01793 SlLoadChunk(ch);
01794 }
01795 }
01796
01798 static void SlLoadCheckChunks()
01799 {
01800 uint32 id;
01801 const ChunkHandler *ch;
01802
01803 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01804 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01805
01806 ch = SlFindChunkHandler(id);
01807 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01808 SlLoadCheckChunk(ch);
01809 }
01810 }
01811
01813 static void SlFixPointers()
01814 {
01815 _sl.action = SLA_PTRS;
01816
01817 DEBUG(sl, 1, "Fixing pointers");
01818
01819 FOR_ALL_CHUNK_HANDLERS(ch) {
01820 if (ch->ptrs_proc != NULL) {
01821 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01822 ch->ptrs_proc();
01823 }
01824 }
01825
01826 DEBUG(sl, 1, "All pointers fixed");
01827
01828 assert(_sl.action == SLA_PTRS);
01829 }
01830
01831
01833 struct FileReader : LoadFilter {
01834 FILE *file;
01835 long begin;
01836
01841 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01842 {
01843 }
01844
01846 ~FileReader()
01847 {
01848 if (this->file != NULL) fclose(this->file);
01849 this->file = NULL;
01850
01851
01852 _sl.sf = NULL;
01853 }
01854
01855 size_t Read(byte *buf, size_t size)
01856 {
01857
01858 if (this->file == NULL) return 0;
01859
01860 return fread(buf, 1, size, this->file);
01861 }
01862
01863 void Reset()
01864 {
01865 clearerr(this->file);
01866 if (fseek(this->file, this->begin, SEEK_SET)) {
01867 DEBUG(sl, 1, "Could not reset the file reading");
01868 }
01869 }
01870 };
01871
01873 struct FileWriter : SaveFilter {
01874 FILE *file;
01875
01880 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01881 {
01882 }
01883
01885 ~FileWriter()
01886 {
01887 this->Finish();
01888
01889
01890 _sl.sf = NULL;
01891 }
01892
01893 void Write(byte *buf, size_t size)
01894 {
01895
01896 if (this->file == NULL) return;
01897
01898 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01899 }
01900
01901 void Finish()
01902 {
01903 if (this->file != NULL) fclose(this->file);
01904 this->file = NULL;
01905 }
01906 };
01907
01908
01909
01910
01911
01912 #ifdef WITH_LZO
01913 #include <lzo/lzo1x.h>
01914
01916 static const uint LZO_BUFFER_SIZE = 8192;
01917
01919 struct LZOLoadFilter : LoadFilter {
01924 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01925 {
01926 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01927 }
01928
01929 size_t Read(byte *buf, size_t ssize)
01930 {
01931 assert(ssize >= LZO_BUFFER_SIZE);
01932
01933
01934 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01935 uint32 tmp[2];
01936 uint32 size;
01937 lzo_uint len;
01938
01939
01940 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01941
01942
01943 ((uint32*)out)[0] = size = tmp[1];
01944
01945 if (_sl_version != 0) {
01946 tmp[0] = TO_BE32(tmp[0]);
01947 size = TO_BE32(size);
01948 }
01949
01950 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01951
01952
01953 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01954
01955
01956 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01957
01958
01959 lzo1x_decompress_safe(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01960 return len;
01961 }
01962 };
01963
01965 struct LZOSaveFilter : SaveFilter {
01971 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01972 {
01973 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01974 }
01975
01976 void Write(byte *buf, size_t size)
01977 {
01978 const lzo_bytep in = buf;
01979
01980 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01981 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01982 lzo_uint outlen;
01983
01984 do {
01985
01986 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01987 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01988 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01989 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01990 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01991
01992
01993 size -= len;
01994 in += len;
01995 } while (size > 0);
01996 }
01997 };
01998
01999 #endif
02000
02001
02002
02003
02004
02006 struct NoCompLoadFilter : LoadFilter {
02011 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
02012 {
02013 }
02014
02015 size_t Read(byte *buf, size_t size)
02016 {
02017 return this->chain->Read(buf, size);
02018 }
02019 };
02020
02022 struct NoCompSaveFilter : SaveFilter {
02028 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02029 {
02030 }
02031
02032 void Write(byte *buf, size_t size)
02033 {
02034 this->chain->Write(buf, size);
02035 }
02036 };
02037
02038
02039
02040
02041
02042 #if defined(WITH_ZLIB)
02043 #include <zlib.h>
02044
02046 struct ZlibLoadFilter : LoadFilter {
02047 z_stream z;
02048 byte fread_buf[MEMORY_CHUNK_SIZE];
02049
02054 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
02055 {
02056 memset(&this->z, 0, sizeof(this->z));
02057 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02058 }
02059
02061 ~ZlibLoadFilter()
02062 {
02063 inflateEnd(&this->z);
02064 }
02065
02066 size_t Read(byte *buf, size_t size)
02067 {
02068 this->z.next_out = buf;
02069 this->z.avail_out = (uint)size;
02070
02071 do {
02072
02073 if (this->z.avail_in == 0) {
02074 this->z.next_in = this->fread_buf;
02075 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02076 }
02077
02078
02079 int r = inflate(&this->z, 0);
02080 if (r == Z_STREAM_END) break;
02081
02082 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02083 } while (this->z.avail_out != 0);
02084
02085 return size - this->z.avail_out;
02086 }
02087 };
02088
02090 struct ZlibSaveFilter : SaveFilter {
02091 z_stream z;
02092
02098 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02099 {
02100 memset(&this->z, 0, sizeof(this->z));
02101 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02102 }
02103
02105 ~ZlibSaveFilter()
02106 {
02107 deflateEnd(&this->z);
02108 }
02109
02116 void WriteLoop(byte *p, size_t len, int mode)
02117 {
02118 byte buf[MEMORY_CHUNK_SIZE];
02119 uint n;
02120 this->z.next_in = p;
02121 this->z.avail_in = (uInt)len;
02122 do {
02123 this->z.next_out = buf;
02124 this->z.avail_out = sizeof(buf);
02125
02133 int r = deflate(&this->z, mode);
02134
02135
02136 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02137 this->chain->Write(buf, n);
02138 }
02139 if (r == Z_STREAM_END) break;
02140
02141 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02142 } while (this->z.avail_in || !this->z.avail_out);
02143 }
02144
02145 void Write(byte *buf, size_t size)
02146 {
02147 this->WriteLoop(buf, size, 0);
02148 }
02149
02150 void Finish()
02151 {
02152 this->WriteLoop(NULL, 0, Z_FINISH);
02153 this->chain->Finish();
02154 }
02155 };
02156
02157 #endif
02158
02159
02160
02161
02162
02163 #if defined(WITH_LZMA)
02164 #include <lzma.h>
02165
02172 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02173
02175 struct LZMALoadFilter : LoadFilter {
02176 lzma_stream lzma;
02177 byte fread_buf[MEMORY_CHUNK_SIZE];
02178
02183 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02184 {
02185
02186 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02187 }
02188
02190 ~LZMALoadFilter()
02191 {
02192 lzma_end(&this->lzma);
02193 }
02194
02195 size_t Read(byte *buf, size_t size)
02196 {
02197 this->lzma.next_out = buf;
02198 this->lzma.avail_out = size;
02199
02200 do {
02201
02202 if (this->lzma.avail_in == 0) {
02203 this->lzma.next_in = this->fread_buf;
02204 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02205 }
02206
02207
02208 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02209 if (r == LZMA_STREAM_END) break;
02210 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02211 } while (this->lzma.avail_out != 0);
02212
02213 return size - this->lzma.avail_out;
02214 }
02215 };
02216
02218 struct LZMASaveFilter : SaveFilter {
02219 lzma_stream lzma;
02220
02226 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02227 {
02228 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02229 }
02230
02232 ~LZMASaveFilter()
02233 {
02234 lzma_end(&this->lzma);
02235 }
02236
02243 void WriteLoop(byte *p, size_t len, lzma_action action)
02244 {
02245 byte buf[MEMORY_CHUNK_SIZE];
02246 size_t n;
02247 this->lzma.next_in = p;
02248 this->lzma.avail_in = len;
02249 do {
02250 this->lzma.next_out = buf;
02251 this->lzma.avail_out = sizeof(buf);
02252
02253 lzma_ret r = lzma_code(&this->lzma, action);
02254
02255
02256 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02257 this->chain->Write(buf, n);
02258 }
02259 if (r == LZMA_STREAM_END) break;
02260 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02261 } while (this->lzma.avail_in || !this->lzma.avail_out);
02262 }
02263
02264 void Write(byte *buf, size_t size)
02265 {
02266 this->WriteLoop(buf, size, LZMA_RUN);
02267 }
02268
02269 void Finish()
02270 {
02271 this->WriteLoop(NULL, 0, LZMA_FINISH);
02272 this->chain->Finish();
02273 }
02274 };
02275
02276 #endif
02277
02278
02279
02280
02281
02283 struct SaveLoadFormat {
02284 const char *name;
02285 uint32 tag;
02286
02287 LoadFilter *(*init_load)(LoadFilter *chain);
02288 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02289
02290 byte min_compression;
02291 byte default_compression;
02292 byte max_compression;
02293 };
02294
02296 static const SaveLoadFormat _saveload_formats[] = {
02297 #if defined(WITH_LZO)
02298
02299 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02300 #else
02301 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02302 #endif
02303
02304 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02305 #if defined(WITH_ZLIB)
02306
02307
02308
02309 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02310 #else
02311 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02312 #endif
02313 #if defined(WITH_LZMA)
02314
02315
02316
02317
02318
02319 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02320 #else
02321 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02322 #endif
02323 };
02324
02332 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02333 {
02334 const SaveLoadFormat *def = lastof(_saveload_formats);
02335
02336
02337 while (!def->init_write) def--;
02338
02339 if (!StrEmpty(s)) {
02340
02341 char *complevel = strrchr(s, ':');
02342 if (complevel != NULL) *complevel = '\0';
02343
02344 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02345 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02346 *compression_level = slf->default_compression;
02347 if (complevel != NULL) {
02348
02349
02350
02351 *complevel = ':';
02352 complevel++;
02353
02354
02355 char *end;
02356 long level = strtol(complevel, &end, 10);
02357 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02358 SetDParamStr(0, complevel);
02359 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL);
02360 } else {
02361 *compression_level = level;
02362 }
02363 }
02364 return slf;
02365 }
02366 }
02367
02368 SetDParamStr(0, s);
02369 SetDParamStr(1, def->name);
02370 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL);
02371
02372
02373 if (complevel != NULL) *complevel = ':';
02374 }
02375 *compression_level = def->default_compression;
02376 return def;
02377 }
02378
02379
02380 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02381 extern bool AfterLoadGame();
02382 extern bool LoadOldSaveGame(const char *file);
02383
02387 static inline void ClearSaveLoadState()
02388 {
02389 delete _sl.dumper;
02390 _sl.dumper = NULL;
02391
02392 delete _sl.sf;
02393 _sl.sf = NULL;
02394
02395 delete _sl.reader;
02396 _sl.reader = NULL;
02397
02398 delete _sl.lf;
02399 _sl.lf = NULL;
02400 }
02401
02407 static void SaveFileStart()
02408 {
02409 _sl.ff_state = _fast_forward;
02410 _fast_forward = 0;
02411 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02412
02413 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02414 _sl.saveinprogress = true;
02415 }
02416
02418 static void SaveFileDone()
02419 {
02420 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02421 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02422
02423 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02424 _sl.saveinprogress = false;
02425 }
02426
02428 void SetSaveLoadError(StringID str)
02429 {
02430 _sl.error_str = str;
02431 }
02432
02434 const char *GetSaveLoadErrorString()
02435 {
02436 SetDParam(0, _sl.error_str);
02437 SetDParamStr(1, _sl.extra_msg);
02438
02439 static char err_str[512];
02440 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02441 return err_str;
02442 }
02443
02445 static void SaveFileError()
02446 {
02447 SetDParamStr(0, GetSaveLoadErrorString());
02448 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02449 SaveFileDone();
02450 }
02451
02456 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02457 {
02458 try {
02459 byte compression;
02460 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02461
02462
02463 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02464 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02465
02466 _sl.sf = fmt->init_write(_sl.sf, compression);
02467 _sl.dumper->Flush(_sl.sf);
02468
02469 ClearSaveLoadState();
02470
02471 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02472
02473 return SL_OK;
02474 } catch (...) {
02475 ClearSaveLoadState();
02476
02477 AsyncSaveFinishProc asfp = SaveFileDone;
02478
02479
02480
02481 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02482
02483 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02484 asfp = SaveFileError;
02485 }
02486
02487 if (threaded) {
02488 SetAsyncSaveFinish(asfp);
02489 } else {
02490 asfp();
02491 }
02492 return SL_ERROR;
02493 }
02494 }
02495
02497 static void SaveFileToDiskThread(void *arg)
02498 {
02499 SaveFileToDisk(true);
02500 }
02501
02502 void WaitTillSaved()
02503 {
02504 if (_save_thread == NULL) return;
02505
02506 _save_thread->Join();
02507 delete _save_thread;
02508 _save_thread = NULL;
02509
02510
02511 ProcessAsyncSaveFinish();
02512 }
02513
02522 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02523 {
02524 assert(!_sl.saveinprogress);
02525
02526 _sl.dumper = new MemoryDumper();
02527 _sl.sf = writer;
02528
02529 _sl_version = SAVEGAME_VERSION;
02530
02531 SaveViewportBeforeSaveGame();
02532 SlSaveChunks();
02533
02534 SaveFileStart();
02535 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02536 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02537
02538 SaveOrLoadResult result = SaveFileToDisk(false);
02539 SaveFileDone();
02540
02541 return result;
02542 }
02543
02544 return SL_OK;
02545 }
02546
02553 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02554 {
02555 try {
02556 _sl.action = SLA_SAVE;
02557 return DoSave(writer, threaded);
02558 } catch (...) {
02559 ClearSaveLoadState();
02560 return SL_ERROR;
02561 }
02562 }
02563
02570 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02571 {
02572 _sl.lf = reader;
02573
02574 if (load_check) {
02575
02576 _load_check_data.Clear();
02577
02578 _load_check_data.checkable = true;
02579 }
02580
02581 uint32 hdr[2];
02582 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02583
02584
02585 const SaveLoadFormat *fmt = _saveload_formats;
02586 for (;;) {
02587
02588 if (fmt == endof(_saveload_formats)) {
02589 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02590 _sl.lf->Reset();
02591 _sl_version = 0;
02592 _sl_minor_version = 0;
02593
02594
02595 fmt = _saveload_formats;
02596 for (;;) {
02597 if (fmt == endof(_saveload_formats)) {
02598
02599 NOT_REACHED();
02600 }
02601 if (fmt->tag == TO_BE32X('OTTD')) break;
02602 fmt++;
02603 }
02604 break;
02605 }
02606
02607 if (fmt->tag == hdr[0]) {
02608
02609 _sl_version = TO_BE32(hdr[1]) >> 16;
02610
02611
02612
02613 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02614
02615 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02616
02617
02618 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02619 break;
02620 }
02621
02622 fmt++;
02623 }
02624
02625
02626 if (fmt->init_load == NULL) {
02627 char err_str[64];
02628 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02629 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02630 }
02631
02632 _sl.lf = fmt->init_load(_sl.lf);
02633 _sl.reader = new ReadBuffer(_sl.lf);
02634 _next_offs = 0;
02635
02636 if (!load_check) {
02637
02638
02639
02640 InitializeGame(256, 256, true, true);
02641
02642 GamelogReset();
02643
02644 if (IsSavegameVersionBefore(4)) {
02645
02646
02647
02648
02649
02650
02651
02652
02653
02654
02655
02656
02657
02658
02659
02660
02661
02662
02663
02664
02665
02666 ClearGRFConfigList(&_grfconfig);
02667 }
02668 }
02669
02670 if (load_check) {
02671
02672
02673 SlLoadCheckChunks();
02674 } else {
02675
02676 SlLoadChunks();
02677 SlFixPointers();
02678 }
02679
02680 ClearSaveLoadState();
02681
02682 _savegame_type = SGT_OTTD;
02683
02684 if (load_check) {
02685
02686 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02687 } else {
02688 GamelogStartAction(GLAT_LOAD);
02689
02690
02691
02692 if (!AfterLoadGame()) {
02693 GamelogStopAction();
02694 return SL_REINIT;
02695 }
02696
02697 GamelogStopAction();
02698 }
02699
02700 return SL_OK;
02701 }
02702
02708 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02709 {
02710 try {
02711 _sl.action = SLA_LOAD;
02712 return DoLoad(reader, false);
02713 } catch (...) {
02714 ClearSaveLoadState();
02715 return SL_REINIT;
02716 }
02717 }
02718
02728 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02729 {
02730
02731 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02732
02733 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02734 return SL_OK;
02735 }
02736 WaitTillSaved();
02737
02738 try {
02739
02740 if (mode == SL_OLD_LOAD) {
02741 InitializeGame(256, 256, true, true);
02742
02743
02744
02745
02746
02747 ClearGRFConfigList(&_grfconfig);
02748 GamelogReset();
02749 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02750 _sl_version = 0;
02751 _sl_minor_version = 0;
02752 GamelogStartAction(GLAT_LOAD);
02753 if (!AfterLoadGame()) {
02754 GamelogStopAction();
02755 return SL_REINIT;
02756 }
02757 GamelogStopAction();
02758 return SL_OK;
02759 }
02760
02761 switch (mode) {
02762 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02763 case SL_LOAD: _sl.action = SLA_LOAD; break;
02764 case SL_SAVE: _sl.action = SLA_SAVE; break;
02765 default: NOT_REACHED();
02766 }
02767
02768 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02769
02770
02771 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02772 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02773 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
02774
02775 if (fh == NULL) {
02776 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02777 }
02778
02779 if (mode == SL_SAVE) {
02780 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02781 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02782
02783 return DoSave(new FileWriter(fh), threaded);
02784 }
02785
02786
02787 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02788 DEBUG(desync, 1, "load: %s", filename);
02789 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02790 } catch (...) {
02791 ClearSaveLoadState();
02792
02793
02794 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02795
02796
02797 return (mode == SL_LOAD || mode == SL_OLD_LOAD) ? SL_REINIT : SL_ERROR;
02798 }
02799 }
02800
02802 void DoExitSave()
02803 {
02804 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02805 }
02806
02812 void GenerateDefaultSaveName(char *buf, const char *last)
02813 {
02814
02815
02816
02817 CompanyID cid = _local_company;
02818 if (!Company::IsValidID(cid)) {
02819 const Company *c;
02820 FOR_ALL_COMPANIES(c) {
02821 cid = c->index;
02822 break;
02823 }
02824 }
02825
02826 SetDParam(0, cid);
02827
02828
02829 switch (_settings_client.gui.date_format_in_default_names) {
02830 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02831 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02832 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02833 default: NOT_REACHED();
02834 }
02835 SetDParam(2, _date);
02836
02837
02838 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02839 SanitizeFilename(buf);
02840 }
02841
02842 #if 0
02843
02849 int GetSavegameType(char *file)
02850 {
02851 const SaveLoadFormat *fmt;
02852 uint32 hdr;
02853 FILE *f;
02854 int mode = SL_OLD_LOAD;
02855
02856 f = fopen(file, "rb");
02857 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02858 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02859 mode = SL_LOAD;
02860 } else {
02861
02862 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02863 if (fmt->tag == hdr) {
02864 mode = SL_LOAD;
02865 break;
02866 }
02867 }
02868 }
02869
02870 fclose(f);
02871 return mode;
02872 }
02873 #endif