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 SlErrorCorrupt("Unsupported gamma");
00674 }
00675 i = (i << 8) | SlReadByte();
00676 }
00677 i = (i << 8) | SlReadByte();
00678 }
00679 i = (i << 8) | SlReadByte();
00680 }
00681 return i;
00682 }
00683
00696 static void SlWriteSimpleGamma(size_t i)
00697 {
00698 if (i >= (1 << 7)) {
00699 if (i >= (1 << 14)) {
00700 if (i >= (1 << 21)) {
00701 assert(i < (1 << 28));
00702 SlWriteByte((byte)(0xE0 | (i >> 24)));
00703 SlWriteByte((byte)(i >> 16));
00704 } else {
00705 SlWriteByte((byte)(0xC0 | (i >> 16)));
00706 }
00707 SlWriteByte((byte)(i >> 8));
00708 } else {
00709 SlWriteByte((byte)(0x80 | (i >> 8)));
00710 }
00711 }
00712 SlWriteByte((byte)i);
00713 }
00714
00716 static inline uint SlGetGammaLength(size_t i)
00717 {
00718 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00719 }
00720
00721 static inline uint SlReadSparseIndex()
00722 {
00723 return SlReadSimpleGamma();
00724 }
00725
00726 static inline void SlWriteSparseIndex(uint index)
00727 {
00728 SlWriteSimpleGamma(index);
00729 }
00730
00731 static inline uint SlReadArrayLength()
00732 {
00733 return SlReadSimpleGamma();
00734 }
00735
00736 static inline void SlWriteArrayLength(size_t length)
00737 {
00738 SlWriteSimpleGamma(length);
00739 }
00740
00741 static inline uint SlGetArrayLength(size_t length)
00742 {
00743 return SlGetGammaLength(length);
00744 }
00745
00752 static inline uint SlCalcConvMemLen(VarType conv)
00753 {
00754 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00755 byte length = GB(conv, 4, 4);
00756
00757 switch (length << 4) {
00758 case SLE_VAR_STRB:
00759 case SLE_VAR_STRBQ:
00760 case SLE_VAR_STR:
00761 case SLE_VAR_STRQ:
00762 return SlReadArrayLength();
00763
00764 default:
00765 assert(length < lengthof(conv_mem_size));
00766 return conv_mem_size[length];
00767 }
00768 }
00769
00776 static inline byte SlCalcConvFileLen(VarType conv)
00777 {
00778 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00779 byte length = GB(conv, 0, 4);
00780 assert(length < lengthof(conv_file_size));
00781 return conv_file_size[length];
00782 }
00783
00785 static inline size_t SlCalcRefLen()
00786 {
00787 return IsSavegameVersionBefore(69) ? 2 : 4;
00788 }
00789
00790 void SlSetArrayIndex(uint index)
00791 {
00792 _sl.need_length = NL_WANTLENGTH;
00793 _sl.array_index = index;
00794 }
00795
00796 static size_t _next_offs;
00797
00802 int SlIterateArray()
00803 {
00804 int index;
00805
00806
00807
00808 if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00809
00810 for (;;) {
00811 uint length = SlReadArrayLength();
00812 if (length == 0) {
00813 _next_offs = 0;
00814 return -1;
00815 }
00816
00817 _sl.obj_len = --length;
00818 _next_offs = _sl.reader->GetSize() + length;
00819
00820 switch (_sl.block_mode) {
00821 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00822 case CH_ARRAY: index = _sl.array_index++; break;
00823 default:
00824 DEBUG(sl, 0, "SlIterateArray error");
00825 return -1;
00826 }
00827
00828 if (length != 0) return index;
00829 }
00830 }
00831
00835 void SlSkipArray()
00836 {
00837 while (SlIterateArray() != -1) {
00838 SlSkipBytes(_next_offs - _sl.reader->GetSize());
00839 }
00840 }
00841
00847 void SlSetLength(size_t length)
00848 {
00849 assert(_sl.action == SLA_SAVE);
00850
00851 switch (_sl.need_length) {
00852 case NL_WANTLENGTH:
00853 _sl.need_length = NL_NONE;
00854 switch (_sl.block_mode) {
00855 case CH_RIFF:
00856
00857
00858
00859 assert(length < (1 << 28));
00860 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00861 break;
00862 case CH_ARRAY:
00863 assert(_sl.last_array_index <= _sl.array_index);
00864 while (++_sl.last_array_index <= _sl.array_index) {
00865 SlWriteArrayLength(1);
00866 }
00867 SlWriteArrayLength(length + 1);
00868 break;
00869 case CH_SPARSE_ARRAY:
00870 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00871 SlWriteSparseIndex(_sl.array_index);
00872 break;
00873 default: NOT_REACHED();
00874 }
00875 break;
00876
00877 case NL_CALCLENGTH:
00878 _sl.obj_len += (int)length;
00879 break;
00880
00881 default: NOT_REACHED();
00882 }
00883 }
00884
00891 static void SlCopyBytes(void *ptr, size_t length)
00892 {
00893 byte *p = (byte *)ptr;
00894
00895 switch (_sl.action) {
00896 case SLA_LOAD_CHECK:
00897 case SLA_LOAD:
00898 for (; length != 0; length--) *p++ = SlReadByte();
00899 break;
00900 case SLA_SAVE:
00901 for (; length != 0; length--) SlWriteByte(*p++);
00902 break;
00903 default: NOT_REACHED();
00904 }
00905 }
00906
00908 size_t SlGetFieldLength()
00909 {
00910 return _sl.obj_len;
00911 }
00912
00920 int64 ReadValue(const void *ptr, VarType conv)
00921 {
00922 switch (GetVarMemType(conv)) {
00923 case SLE_VAR_BL: return (*(const bool *)ptr != 0);
00924 case SLE_VAR_I8: return *(const int8 *)ptr;
00925 case SLE_VAR_U8: return *(const byte *)ptr;
00926 case SLE_VAR_I16: return *(const int16 *)ptr;
00927 case SLE_VAR_U16: return *(const uint16*)ptr;
00928 case SLE_VAR_I32: return *(const int32 *)ptr;
00929 case SLE_VAR_U32: return *(const uint32*)ptr;
00930 case SLE_VAR_I64: return *(const int64 *)ptr;
00931 case SLE_VAR_U64: return *(const uint64*)ptr;
00932 case SLE_VAR_NULL:return 0;
00933 default: NOT_REACHED();
00934 }
00935 }
00936
00944 void WriteValue(void *ptr, VarType conv, int64 val)
00945 {
00946 switch (GetVarMemType(conv)) {
00947 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00948 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00949 case SLE_VAR_U8: *(byte *)ptr = val; break;
00950 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00951 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00952 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00953 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00954 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00955 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00956 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00957 case SLE_VAR_NULL: break;
00958 default: NOT_REACHED();
00959 }
00960 }
00961
00970 static void SlSaveLoadConv(void *ptr, VarType conv)
00971 {
00972 switch (_sl.action) {
00973 case SLA_SAVE: {
00974 int64 x = ReadValue(ptr, conv);
00975
00976
00977 switch (GetVarFileType(conv)) {
00978 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00979 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00980 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00981 case SLE_FILE_STRINGID:
00982 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00983 case SLE_FILE_I32:
00984 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00985 case SLE_FILE_I64:
00986 case SLE_FILE_U64: SlWriteUint64(x);break;
00987 default: NOT_REACHED();
00988 }
00989 break;
00990 }
00991 case SLA_LOAD_CHECK:
00992 case SLA_LOAD: {
00993 int64 x;
00994
00995 switch (GetVarFileType(conv)) {
00996 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00997 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00998 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00999 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
01000 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
01001 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
01002 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
01003 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
01004 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
01005 default: NOT_REACHED();
01006 }
01007
01008
01009 WriteValue(ptr, conv, x);
01010 break;
01011 }
01012 case SLA_PTRS: break;
01013 case SLA_NULL: break;
01014 default: NOT_REACHED();
01015 }
01016 }
01017
01027 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
01028 {
01029 if (ptr == NULL) return 0;
01030 return min(strlen(ptr), length - 1);
01031 }
01032
01042 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
01043 {
01044 size_t len;
01045 const char *str;
01046
01047 switch (GetVarMemType(conv)) {
01048 default: NOT_REACHED();
01049 case SLE_VAR_STR:
01050 case SLE_VAR_STRQ:
01051 str = *(const char * const *)ptr;
01052 len = SIZE_MAX;
01053 break;
01054 case SLE_VAR_STRB:
01055 case SLE_VAR_STRBQ:
01056 str = (const char *)ptr;
01057 len = length;
01058 break;
01059 }
01060
01061 len = SlCalcNetStringLen(str, len);
01062 return len + SlGetArrayLength(len);
01063 }
01064
01071 static void SlString(void *ptr, size_t length, VarType conv)
01072 {
01073 switch (_sl.action) {
01074 case SLA_SAVE: {
01075 size_t len;
01076 switch (GetVarMemType(conv)) {
01077 default: NOT_REACHED();
01078 case SLE_VAR_STRB:
01079 case SLE_VAR_STRBQ:
01080 len = SlCalcNetStringLen((char *)ptr, length);
01081 break;
01082 case SLE_VAR_STR:
01083 case SLE_VAR_STRQ:
01084 ptr = *(char **)ptr;
01085 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01086 break;
01087 }
01088
01089 SlWriteArrayLength(len);
01090 SlCopyBytes(ptr, len);
01091 break;
01092 }
01093 case SLA_LOAD_CHECK:
01094 case SLA_LOAD: {
01095 size_t len = SlReadArrayLength();
01096
01097 switch (GetVarMemType(conv)) {
01098 default: NOT_REACHED();
01099 case SLE_VAR_STRB:
01100 case SLE_VAR_STRBQ:
01101 if (len >= length) {
01102 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01103 SlCopyBytes(ptr, length);
01104 SlSkipBytes(len - length);
01105 len = length - 1;
01106 } else {
01107 SlCopyBytes(ptr, len);
01108 }
01109 break;
01110 case SLE_VAR_STR:
01111 case SLE_VAR_STRQ:
01112 free(*(char **)ptr);
01113 if (len == 0) {
01114 *(char **)ptr = NULL;
01115 return;
01116 } else {
01117 *(char **)ptr = MallocT<char>(len + 1);
01118 ptr = *(char **)ptr;
01119 SlCopyBytes(ptr, len);
01120 }
01121 break;
01122 }
01123
01124 ((char *)ptr)[len] = '\0';
01125 StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
01126 if ((conv & SLF_ALLOW_CONTROL) != 0) {
01127 settings = settings | SVS_ALLOW_CONTROL_CODE;
01128 if (IsSavegameVersionBefore(169)) {
01129 str_fix_scc_encoded((char *)ptr, (char *)ptr + len);
01130 }
01131 }
01132 if ((conv & SLF_ALLOW_NEWLINE) != 0) {
01133 settings = settings | SVS_ALLOW_NEWLINE;
01134 }
01135 str_validate((char *)ptr, (char *)ptr + len, settings);
01136 break;
01137 }
01138 case SLA_PTRS: break;
01139 case SLA_NULL: break;
01140 default: NOT_REACHED();
01141 }
01142 }
01143
01149 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01150 {
01151 return SlCalcConvFileLen(conv) * length;
01152 }
01153
01160 void SlArray(void *array, size_t length, VarType conv)
01161 {
01162 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01163
01164
01165 if (_sl.need_length != NL_NONE) {
01166 SlSetLength(SlCalcArrayLen(length, conv));
01167
01168 if (_sl.need_length == NL_CALCLENGTH) return;
01169 }
01170
01171
01172
01173 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01174
01175 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01176 conv == SLE_INT32 || conv == SLE_UINT32) {
01177 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01178 return;
01179 }
01180
01181 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01182 for (uint i = 0; i < length; i++) {
01183 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01184 }
01185 return;
01186 }
01187 }
01188
01189
01190
01191 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01192 SlCopyBytes(array, length);
01193 } else {
01194 byte *a = (byte*)array;
01195 byte mem_size = SlCalcConvMemLen(conv);
01196
01197 for (; length != 0; length --) {
01198 SlSaveLoadConv(a, conv);
01199 a += mem_size;
01200 }
01201 }
01202 }
01203
01204
01215 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01216 {
01217 assert(_sl.action == SLA_SAVE);
01218
01219 if (obj == NULL) return 0;
01220
01221 switch (rt) {
01222 case REF_VEHICLE_OLD:
01223 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01224 case REF_STATION: return ((const Station*)obj)->index + 1;
01225 case REF_TOWN: return ((const Town*)obj)->index + 1;
01226 case REF_ORDER: return ((const Order*)obj)->index + 1;
01227 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01228 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01229 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01230 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01231 case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
01232 case REF_LINK_GRAPH: return ((const LinkGraph*)obj)->index + 1;
01233 case REF_LINK_GRAPH_JOB: return ((const LinkGraphJob*)obj)->index + 1;
01234 default: NOT_REACHED();
01235 }
01236 }
01237
01248 static void *IntToReference(size_t index, SLRefType rt)
01249 {
01250 assert_compile(sizeof(size_t) <= sizeof(void *));
01251
01252 assert(_sl.action == SLA_PTRS);
01253
01254
01255
01256 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01257 rt = REF_VEHICLE;
01258 }
01259
01260
01261 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01262
01263
01264
01265 if (rt != REF_VEHICLE_OLD) index--;
01266
01267 switch (rt) {
01268 case REF_ORDERLIST:
01269 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01270 SlErrorCorrupt("Referencing invalid OrderList");
01271
01272 case REF_ORDER:
01273 if (Order::IsValidID(index)) return Order::Get(index);
01274
01275 if (IsSavegameVersionBefore(5, 2)) return NULL;
01276 SlErrorCorrupt("Referencing invalid Order");
01277
01278 case REF_VEHICLE_OLD:
01279 case REF_VEHICLE:
01280 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01281 SlErrorCorrupt("Referencing invalid Vehicle");
01282
01283 case REF_STATION:
01284 if (Station::IsValidID(index)) return Station::Get(index);
01285 SlErrorCorrupt("Referencing invalid Station");
01286
01287 case REF_TOWN:
01288 if (Town::IsValidID(index)) return Town::Get(index);
01289 SlErrorCorrupt("Referencing invalid Town");
01290
01291 case REF_ROADSTOPS:
01292 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01293 SlErrorCorrupt("Referencing invalid RoadStop");
01294
01295 case REF_ENGINE_RENEWS:
01296 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01297 SlErrorCorrupt("Referencing invalid EngineRenew");
01298
01299 case REF_CARGO_PACKET:
01300 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01301 SlErrorCorrupt("Referencing invalid CargoPacket");
01302
01303 case REF_STORAGE:
01304 if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index);
01305 SlErrorCorrupt("Referencing invalid PersistentStorage");
01306
01307 case REF_LINK_GRAPH:
01308 if (LinkGraph::IsValidID(index)) return LinkGraph::Get(index);
01309 SlErrorCorrupt("Referencing invalid LinkGraph");
01310
01311 case REF_LINK_GRAPH_JOB:
01312 if (LinkGraphJob::IsValidID(index)) return LinkGraphJob::Get(index);
01313 SlErrorCorrupt("Referencing invalid LinkGraphJob");
01314
01315 default: NOT_REACHED();
01316 }
01317 }
01318
01323 static inline size_t SlCalcListLen(const void *list)
01324 {
01325 const std::list<void *> *l = (const std::list<void *> *) list;
01326
01327 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01328
01329
01330 return l->size() * type_size + type_size;
01331 }
01332
01333
01339 static void SlList(void *list, SLRefType conv)
01340 {
01341
01342 if (_sl.need_length != NL_NONE) {
01343 SlSetLength(SlCalcListLen(list));
01344
01345 if (_sl.need_length == NL_CALCLENGTH) return;
01346 }
01347
01348 typedef std::list<void *> PtrList;
01349 PtrList *l = (PtrList *)list;
01350
01351 switch (_sl.action) {
01352 case SLA_SAVE: {
01353 SlWriteUint32((uint32)l->size());
01354
01355 PtrList::iterator iter;
01356 for (iter = l->begin(); iter != l->end(); ++iter) {
01357 void *ptr = *iter;
01358 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01359 }
01360 break;
01361 }
01362 case SLA_LOAD_CHECK:
01363 case SLA_LOAD: {
01364 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01365
01366
01367 for (size_t i = 0; i < length; i++) {
01368 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01369 l->push_back((void *)data);
01370 }
01371 break;
01372 }
01373 case SLA_PTRS: {
01374 PtrList temp = *l;
01375
01376 l->clear();
01377 PtrList::iterator iter;
01378 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01379 void *ptr = IntToReference((size_t)*iter, conv);
01380 l->push_back(ptr);
01381 }
01382 break;
01383 }
01384 case SLA_NULL:
01385 l->clear();
01386 break;
01387 default: NOT_REACHED();
01388 }
01389 }
01390
01391
01393 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01394 {
01395 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01396 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01397
01398 return true;
01399 }
01400
01406 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01407 {
01408 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01409 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01410 return true;
01411 }
01412
01413 return false;
01414 }
01415
01422 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01423 {
01424 size_t length = 0;
01425
01426
01427 for (; sld->cmd != SL_END; sld++) {
01428 length += SlCalcObjMemberLength(object, sld);
01429 }
01430 return length;
01431 }
01432
01433 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01434 {
01435 assert(_sl.action == SLA_SAVE);
01436
01437 switch (sld->cmd) {
01438 case SL_VAR:
01439 case SL_REF:
01440 case SL_ARR:
01441 case SL_STR:
01442 case SL_LST:
01443
01444 if (!SlIsObjectValidInSavegame(sld)) break;
01445
01446 switch (sld->cmd) {
01447 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01448 case SL_REF: return SlCalcRefLen();
01449 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01450 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01451 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01452 default: NOT_REACHED();
01453 }
01454 break;
01455 case SL_WRITEBYTE: return 1;
01456 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01457 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01458 default: NOT_REACHED();
01459 }
01460 return 0;
01461 }
01462
01463
01464 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01465 {
01466 VarType conv = GB(sld->conv, 0, 8);
01467 switch (sld->cmd) {
01468 case SL_VAR:
01469 case SL_REF:
01470 case SL_ARR:
01471 case SL_STR:
01472 case SL_LST:
01473
01474 if (!SlIsObjectValidInSavegame(sld)) return false;
01475 if (SlSkipVariableOnLoad(sld)) return false;
01476
01477 switch (sld->cmd) {
01478 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01479 case SL_REF:
01480 switch (_sl.action) {
01481 case SLA_SAVE:
01482 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01483 break;
01484 case SLA_LOAD_CHECK:
01485 case SLA_LOAD:
01486 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01487 break;
01488 case SLA_PTRS:
01489 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01490 break;
01491 case SLA_NULL:
01492 *(void **)ptr = NULL;
01493 break;
01494 default: NOT_REACHED();
01495 }
01496 break;
01497 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01498 case SL_STR: SlString(ptr, sld->length, sld->conv); break;
01499 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01500 default: NOT_REACHED();
01501 }
01502 break;
01503
01504
01505
01506
01507
01508
01509 case SL_WRITEBYTE:
01510 switch (_sl.action) {
01511 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01512 case SLA_LOAD_CHECK:
01513 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01514 case SLA_PTRS: break;
01515 case SLA_NULL: break;
01516 default: NOT_REACHED();
01517 }
01518 break;
01519
01520
01521 case SL_VEH_INCLUDE:
01522 SlObject(ptr, GetVehicleDescription(VEH_END));
01523 break;
01524
01525 case SL_ST_INCLUDE:
01526 SlObject(ptr, GetBaseStationDescription());
01527 break;
01528
01529 default: NOT_REACHED();
01530 }
01531 return true;
01532 }
01533
01539 void SlObject(void *object, const SaveLoad *sld)
01540 {
01541
01542 if (_sl.need_length != NL_NONE) {
01543 SlSetLength(SlCalcObjLength(object, sld));
01544 if (_sl.need_length == NL_CALCLENGTH) return;
01545 }
01546
01547 for (; sld->cmd != SL_END; sld++) {
01548 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01549 SlObjectMember(ptr, sld);
01550 }
01551 }
01552
01557 void SlGlobList(const SaveLoadGlobVarList *sldg)
01558 {
01559 SlObject(NULL, (const SaveLoad*)sldg);
01560 }
01561
01567 void SlAutolength(AutolengthProc *proc, void *arg)
01568 {
01569 size_t offs;
01570
01571 assert(_sl.action == SLA_SAVE);
01572
01573
01574 _sl.need_length = NL_CALCLENGTH;
01575 _sl.obj_len = 0;
01576 proc(arg);
01577
01578
01579 _sl.need_length = NL_WANTLENGTH;
01580 SlSetLength(_sl.obj_len);
01581
01582 offs = _sl.dumper->GetSize() + _sl.obj_len;
01583
01584
01585 proc(arg);
01586
01587 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01588 }
01589
01594 static void SlLoadChunk(const ChunkHandler *ch)
01595 {
01596 byte m = SlReadByte();
01597 size_t len;
01598 size_t endoffs;
01599
01600 _sl.block_mode = m;
01601 _sl.obj_len = 0;
01602
01603 switch (m) {
01604 case CH_ARRAY:
01605 _sl.array_index = 0;
01606 ch->load_proc();
01607 break;
01608 case CH_SPARSE_ARRAY:
01609 ch->load_proc();
01610 break;
01611 default:
01612 if ((m & 0xF) == CH_RIFF) {
01613
01614 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01615 len += SlReadUint16();
01616 _sl.obj_len = len;
01617 endoffs = _sl.reader->GetSize() + len;
01618 ch->load_proc();
01619 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01620 } else {
01621 SlErrorCorrupt("Invalid chunk type");
01622 }
01623 break;
01624 }
01625 }
01626
01632 static void SlLoadCheckChunk(const ChunkHandler *ch)
01633 {
01634 byte m = SlReadByte();
01635 size_t len;
01636 size_t endoffs;
01637
01638 _sl.block_mode = m;
01639 _sl.obj_len = 0;
01640
01641 switch (m) {
01642 case CH_ARRAY:
01643 _sl.array_index = 0;
01644 if (ch->load_check_proc) {
01645 ch->load_check_proc();
01646 } else {
01647 SlSkipArray();
01648 }
01649 break;
01650 case CH_SPARSE_ARRAY:
01651 if (ch->load_check_proc) {
01652 ch->load_check_proc();
01653 } else {
01654 SlSkipArray();
01655 }
01656 break;
01657 default:
01658 if ((m & 0xF) == CH_RIFF) {
01659
01660 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01661 len += SlReadUint16();
01662 _sl.obj_len = len;
01663 endoffs = _sl.reader->GetSize() + len;
01664 if (ch->load_check_proc) {
01665 ch->load_check_proc();
01666 } else {
01667 SlSkipBytes(len);
01668 }
01669 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01670 } else {
01671 SlErrorCorrupt("Invalid chunk type");
01672 }
01673 break;
01674 }
01675 }
01676
01681 static ChunkSaveLoadProc *_stub_save_proc;
01682
01688 static inline void SlStubSaveProc2(void *arg)
01689 {
01690 _stub_save_proc();
01691 }
01692
01698 static void SlStubSaveProc()
01699 {
01700 SlAutolength(SlStubSaveProc2, NULL);
01701 }
01702
01708 static void SlSaveChunk(const ChunkHandler *ch)
01709 {
01710 ChunkSaveLoadProc *proc = ch->save_proc;
01711
01712
01713 if (proc == NULL) return;
01714
01715 SlWriteUint32(ch->id);
01716 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01717
01718 if (ch->flags & CH_AUTO_LENGTH) {
01719
01720 _stub_save_proc = proc;
01721 proc = SlStubSaveProc;
01722 }
01723
01724 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01725 switch (ch->flags & CH_TYPE_MASK) {
01726 case CH_RIFF:
01727 _sl.need_length = NL_WANTLENGTH;
01728 proc();
01729 break;
01730 case CH_ARRAY:
01731 _sl.last_array_index = 0;
01732 SlWriteByte(CH_ARRAY);
01733 proc();
01734 SlWriteArrayLength(0);
01735 break;
01736 case CH_SPARSE_ARRAY:
01737 SlWriteByte(CH_SPARSE_ARRAY);
01738 proc();
01739 SlWriteArrayLength(0);
01740 break;
01741 default: NOT_REACHED();
01742 }
01743 }
01744
01746 static void SlSaveChunks()
01747 {
01748 FOR_ALL_CHUNK_HANDLERS(ch) {
01749 SlSaveChunk(ch);
01750 }
01751
01752
01753 SlWriteUint32(0);
01754 }
01755
01762 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01763 {
01764 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01765 return NULL;
01766 }
01767
01769 static void SlLoadChunks()
01770 {
01771 uint32 id;
01772 const ChunkHandler *ch;
01773
01774 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01775 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01776
01777 ch = SlFindChunkHandler(id);
01778 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01779 SlLoadChunk(ch);
01780 }
01781 }
01782
01784 static void SlLoadCheckChunks()
01785 {
01786 uint32 id;
01787 const ChunkHandler *ch;
01788
01789 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01790 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01791
01792 ch = SlFindChunkHandler(id);
01793 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01794 SlLoadCheckChunk(ch);
01795 }
01796 }
01797
01799 static void SlFixPointers()
01800 {
01801 _sl.action = SLA_PTRS;
01802
01803 DEBUG(sl, 1, "Fixing pointers");
01804
01805 FOR_ALL_CHUNK_HANDLERS(ch) {
01806 if (ch->ptrs_proc != NULL) {
01807 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01808 ch->ptrs_proc();
01809 }
01810 }
01811
01812 DEBUG(sl, 1, "All pointers fixed");
01813
01814 assert(_sl.action == SLA_PTRS);
01815 }
01816
01817
01819 struct FileReader : LoadFilter {
01820 FILE *file;
01821 long begin;
01822
01827 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01828 {
01829 }
01830
01832 ~FileReader()
01833 {
01834 if (this->file != NULL) fclose(this->file);
01835 this->file = NULL;
01836
01837
01838 _sl.sf = NULL;
01839 }
01840
01841 size_t Read(byte *buf, size_t size)
01842 {
01843
01844 if (this->file == NULL) return 0;
01845
01846 return fread(buf, 1, size, this->file);
01847 }
01848
01849 void Reset()
01850 {
01851 clearerr(this->file);
01852 if (fseek(this->file, this->begin, SEEK_SET)) {
01853 DEBUG(sl, 1, "Could not reset the file reading");
01854 }
01855 }
01856 };
01857
01859 struct FileWriter : SaveFilter {
01860 FILE *file;
01861
01866 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01867 {
01868 }
01869
01871 ~FileWriter()
01872 {
01873 this->Finish();
01874
01875
01876 _sl.sf = NULL;
01877 }
01878
01879 void Write(byte *buf, size_t size)
01880 {
01881
01882 if (this->file == NULL) return;
01883
01884 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01885 }
01886
01887 void Finish()
01888 {
01889 if (this->file != NULL) fclose(this->file);
01890 this->file = NULL;
01891 }
01892 };
01893
01894
01895
01896
01897
01898 #ifdef WITH_LZO
01899 #include <lzo/lzo1x.h>
01900
01902 static const uint LZO_BUFFER_SIZE = 8192;
01903
01905 struct LZOLoadFilter : LoadFilter {
01910 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01911 {
01912 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01913 }
01914
01915 size_t Read(byte *buf, size_t ssize)
01916 {
01917 assert(ssize >= LZO_BUFFER_SIZE);
01918
01919
01920 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01921 uint32 tmp[2];
01922 uint32 size;
01923 lzo_uint len;
01924
01925
01926 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01927
01928
01929 ((uint32*)out)[0] = size = tmp[1];
01930
01931 if (_sl_version != 0) {
01932 tmp[0] = TO_BE32(tmp[0]);
01933 size = TO_BE32(size);
01934 }
01935
01936 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01937
01938
01939 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01940
01941
01942 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01943
01944
01945 lzo1x_decompress_safe(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01946 return len;
01947 }
01948 };
01949
01951 struct LZOSaveFilter : SaveFilter {
01957 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01958 {
01959 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01960 }
01961
01962 void Write(byte *buf, size_t size)
01963 {
01964 const lzo_bytep in = buf;
01965
01966 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01967 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01968 lzo_uint outlen;
01969
01970 do {
01971
01972 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01973 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01974 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01975 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01976 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01977
01978
01979 size -= len;
01980 in += len;
01981 } while (size > 0);
01982 }
01983 };
01984
01985 #endif
01986
01987
01988
01989
01990
01992 struct NoCompLoadFilter : LoadFilter {
01997 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01998 {
01999 }
02000
02001 size_t Read(byte *buf, size_t size)
02002 {
02003 return this->chain->Read(buf, size);
02004 }
02005 };
02006
02008 struct NoCompSaveFilter : SaveFilter {
02014 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02015 {
02016 }
02017
02018 void Write(byte *buf, size_t size)
02019 {
02020 this->chain->Write(buf, size);
02021 }
02022 };
02023
02024
02025
02026
02027
02028 #if defined(WITH_ZLIB)
02029 #include <zlib.h>
02030
02032 struct ZlibLoadFilter : LoadFilter {
02033 z_stream z;
02034 byte fread_buf[MEMORY_CHUNK_SIZE];
02035
02040 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
02041 {
02042 memset(&this->z, 0, sizeof(this->z));
02043 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02044 }
02045
02047 ~ZlibLoadFilter()
02048 {
02049 inflateEnd(&this->z);
02050 }
02051
02052 size_t Read(byte *buf, size_t size)
02053 {
02054 this->z.next_out = buf;
02055 this->z.avail_out = (uint)size;
02056
02057 do {
02058
02059 if (this->z.avail_in == 0) {
02060 this->z.next_in = this->fread_buf;
02061 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02062 }
02063
02064
02065 int r = inflate(&this->z, 0);
02066 if (r == Z_STREAM_END) break;
02067
02068 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02069 } while (this->z.avail_out != 0);
02070
02071 return size - this->z.avail_out;
02072 }
02073 };
02074
02076 struct ZlibSaveFilter : SaveFilter {
02077 z_stream z;
02078
02084 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02085 {
02086 memset(&this->z, 0, sizeof(this->z));
02087 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02088 }
02089
02091 ~ZlibSaveFilter()
02092 {
02093 deflateEnd(&this->z);
02094 }
02095
02102 void WriteLoop(byte *p, size_t len, int mode)
02103 {
02104 byte buf[MEMORY_CHUNK_SIZE];
02105 uint n;
02106 this->z.next_in = p;
02107 this->z.avail_in = (uInt)len;
02108 do {
02109 this->z.next_out = buf;
02110 this->z.avail_out = sizeof(buf);
02111
02119 int r = deflate(&this->z, mode);
02120
02121
02122 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02123 this->chain->Write(buf, n);
02124 }
02125 if (r == Z_STREAM_END) break;
02126
02127 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02128 } while (this->z.avail_in || !this->z.avail_out);
02129 }
02130
02131 void Write(byte *buf, size_t size)
02132 {
02133 this->WriteLoop(buf, size, 0);
02134 }
02135
02136 void Finish()
02137 {
02138 this->WriteLoop(NULL, 0, Z_FINISH);
02139 this->chain->Finish();
02140 }
02141 };
02142
02143 #endif
02144
02145
02146
02147
02148
02149 #if defined(WITH_LZMA)
02150 #include <lzma.h>
02151
02158 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02159
02161 struct LZMALoadFilter : LoadFilter {
02162 lzma_stream lzma;
02163 byte fread_buf[MEMORY_CHUNK_SIZE];
02164
02169 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02170 {
02171
02172 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02173 }
02174
02176 ~LZMALoadFilter()
02177 {
02178 lzma_end(&this->lzma);
02179 }
02180
02181 size_t Read(byte *buf, size_t size)
02182 {
02183 this->lzma.next_out = buf;
02184 this->lzma.avail_out = size;
02185
02186 do {
02187
02188 if (this->lzma.avail_in == 0) {
02189 this->lzma.next_in = this->fread_buf;
02190 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02191 }
02192
02193
02194 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02195 if (r == LZMA_STREAM_END) break;
02196 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02197 } while (this->lzma.avail_out != 0);
02198
02199 return size - this->lzma.avail_out;
02200 }
02201 };
02202
02204 struct LZMASaveFilter : SaveFilter {
02205 lzma_stream lzma;
02206
02212 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02213 {
02214 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02215 }
02216
02218 ~LZMASaveFilter()
02219 {
02220 lzma_end(&this->lzma);
02221 }
02222
02229 void WriteLoop(byte *p, size_t len, lzma_action action)
02230 {
02231 byte buf[MEMORY_CHUNK_SIZE];
02232 size_t n;
02233 this->lzma.next_in = p;
02234 this->lzma.avail_in = len;
02235 do {
02236 this->lzma.next_out = buf;
02237 this->lzma.avail_out = sizeof(buf);
02238
02239 lzma_ret r = lzma_code(&this->lzma, action);
02240
02241
02242 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02243 this->chain->Write(buf, n);
02244 }
02245 if (r == LZMA_STREAM_END) break;
02246 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02247 } while (this->lzma.avail_in || !this->lzma.avail_out);
02248 }
02249
02250 void Write(byte *buf, size_t size)
02251 {
02252 this->WriteLoop(buf, size, LZMA_RUN);
02253 }
02254
02255 void Finish()
02256 {
02257 this->WriteLoop(NULL, 0, LZMA_FINISH);
02258 this->chain->Finish();
02259 }
02260 };
02261
02262 #endif
02263
02264
02265
02266
02267
02269 struct SaveLoadFormat {
02270 const char *name;
02271 uint32 tag;
02272
02273 LoadFilter *(*init_load)(LoadFilter *chain);
02274 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02275
02276 byte min_compression;
02277 byte default_compression;
02278 byte max_compression;
02279 };
02280
02282 static const SaveLoadFormat _saveload_formats[] = {
02283 #if defined(WITH_LZO)
02284
02285 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02286 #else
02287 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02288 #endif
02289
02290 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02291 #if defined(WITH_ZLIB)
02292
02293
02294
02295 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02296 #else
02297 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02298 #endif
02299 #if defined(WITH_LZMA)
02300
02301
02302
02303
02304
02305 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02306 #else
02307 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02308 #endif
02309 };
02310
02318 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02319 {
02320 const SaveLoadFormat *def = lastof(_saveload_formats);
02321
02322
02323 while (!def->init_write) def--;
02324
02325 if (!StrEmpty(s)) {
02326
02327 char *complevel = strrchr(s, ':');
02328 if (complevel != NULL) *complevel = '\0';
02329
02330 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02331 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02332 *compression_level = slf->default_compression;
02333 if (complevel != NULL) {
02334
02335
02336
02337 *complevel = ':';
02338 complevel++;
02339
02340
02341 char *end;
02342 long level = strtol(complevel, &end, 10);
02343 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02344 SetDParamStr(0, complevel);
02345 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL);
02346 } else {
02347 *compression_level = level;
02348 }
02349 }
02350 return slf;
02351 }
02352 }
02353
02354 SetDParamStr(0, s);
02355 SetDParamStr(1, def->name);
02356 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL);
02357
02358
02359 if (complevel != NULL) *complevel = ':';
02360 }
02361 *compression_level = def->default_compression;
02362 return def;
02363 }
02364
02365
02366 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02367 extern bool AfterLoadGame();
02368 extern bool LoadOldSaveGame(const char *file);
02369
02373 static inline void ClearSaveLoadState()
02374 {
02375 delete _sl.dumper;
02376 _sl.dumper = NULL;
02377
02378 delete _sl.sf;
02379 _sl.sf = NULL;
02380
02381 delete _sl.reader;
02382 _sl.reader = NULL;
02383
02384 delete _sl.lf;
02385 _sl.lf = NULL;
02386 }
02387
02393 static void SaveFileStart()
02394 {
02395 _sl.ff_state = _fast_forward;
02396 _fast_forward = 0;
02397 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02398
02399 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02400 _sl.saveinprogress = true;
02401 }
02402
02404 static void SaveFileDone()
02405 {
02406 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02407 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02408
02409 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02410 _sl.saveinprogress = false;
02411 }
02412
02414 void SetSaveLoadError(StringID str)
02415 {
02416 _sl.error_str = str;
02417 }
02418
02420 const char *GetSaveLoadErrorString()
02421 {
02422 SetDParam(0, _sl.error_str);
02423 SetDParamStr(1, _sl.extra_msg);
02424
02425 static char err_str[512];
02426 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02427 return err_str;
02428 }
02429
02431 static void SaveFileError()
02432 {
02433 SetDParamStr(0, GetSaveLoadErrorString());
02434 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02435 SaveFileDone();
02436 }
02437
02442 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02443 {
02444 try {
02445 byte compression;
02446 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02447
02448
02449 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02450 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02451
02452 _sl.sf = fmt->init_write(_sl.sf, compression);
02453 _sl.dumper->Flush(_sl.sf);
02454
02455 ClearSaveLoadState();
02456
02457 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02458
02459 return SL_OK;
02460 } catch (...) {
02461 ClearSaveLoadState();
02462
02463 AsyncSaveFinishProc asfp = SaveFileDone;
02464
02465
02466
02467 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02468
02469 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02470 asfp = SaveFileError;
02471 }
02472
02473 if (threaded) {
02474 SetAsyncSaveFinish(asfp);
02475 } else {
02476 asfp();
02477 }
02478 return SL_ERROR;
02479 }
02480 }
02481
02483 static void SaveFileToDiskThread(void *arg)
02484 {
02485 SaveFileToDisk(true);
02486 }
02487
02488 void WaitTillSaved()
02489 {
02490 if (_save_thread == NULL) return;
02491
02492 _save_thread->Join();
02493 delete _save_thread;
02494 _save_thread = NULL;
02495
02496
02497 ProcessAsyncSaveFinish();
02498 }
02499
02508 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02509 {
02510 assert(!_sl.saveinprogress);
02511
02512 _sl.dumper = new MemoryDumper();
02513 _sl.sf = writer;
02514
02515 _sl_version = SAVEGAME_VERSION;
02516
02517 SaveViewportBeforeSaveGame();
02518 SlSaveChunks();
02519
02520 SaveFileStart();
02521 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02522 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02523
02524 SaveOrLoadResult result = SaveFileToDisk(false);
02525 SaveFileDone();
02526
02527 return result;
02528 }
02529
02530 return SL_OK;
02531 }
02532
02539 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02540 {
02541 try {
02542 _sl.action = SLA_SAVE;
02543 return DoSave(writer, threaded);
02544 } catch (...) {
02545 ClearSaveLoadState();
02546 return SL_ERROR;
02547 }
02548 }
02549
02556 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02557 {
02558 _sl.lf = reader;
02559
02560 if (load_check) {
02561
02562 _load_check_data.Clear();
02563
02564 _load_check_data.checkable = true;
02565 }
02566
02567 uint32 hdr[2];
02568 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02569
02570
02571 const SaveLoadFormat *fmt = _saveload_formats;
02572 for (;;) {
02573
02574 if (fmt == endof(_saveload_formats)) {
02575 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02576 _sl.lf->Reset();
02577 _sl_version = 0;
02578 _sl_minor_version = 0;
02579
02580
02581 fmt = _saveload_formats;
02582 for (;;) {
02583 if (fmt == endof(_saveload_formats)) {
02584
02585 NOT_REACHED();
02586 }
02587 if (fmt->tag == TO_BE32X('OTTD')) break;
02588 fmt++;
02589 }
02590 break;
02591 }
02592
02593 if (fmt->tag == hdr[0]) {
02594
02595 _sl_version = TO_BE32(hdr[1]) >> 16;
02596
02597
02598
02599 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02600
02601 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02602
02603
02604 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02605 break;
02606 }
02607
02608 fmt++;
02609 }
02610
02611
02612 if (fmt->init_load == NULL) {
02613 char err_str[64];
02614 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02615 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02616 }
02617
02618 _sl.lf = fmt->init_load(_sl.lf);
02619 _sl.reader = new ReadBuffer(_sl.lf);
02620 _next_offs = 0;
02621
02622 if (!load_check) {
02623
02624
02625
02626 InitializeGame(256, 256, true, true);
02627
02628 GamelogReset();
02629
02630 if (IsSavegameVersionBefore(4)) {
02631
02632
02633
02634
02635
02636
02637
02638
02639
02640
02641
02642
02643
02644
02645
02646
02647
02648
02649
02650
02651
02652 ClearGRFConfigList(&_grfconfig);
02653 }
02654 }
02655
02656 if (load_check) {
02657
02658
02659 SlLoadCheckChunks();
02660 } else {
02661
02662 SlLoadChunks();
02663 SlFixPointers();
02664 }
02665
02666 ClearSaveLoadState();
02667
02668 _savegame_type = SGT_OTTD;
02669
02670 if (load_check) {
02671
02672 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02673 } else {
02674 GamelogStartAction(GLAT_LOAD);
02675
02676
02677
02678 if (!AfterLoadGame()) {
02679 GamelogStopAction();
02680 return SL_REINIT;
02681 }
02682
02683 GamelogStopAction();
02684 }
02685
02686 return SL_OK;
02687 }
02688
02694 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02695 {
02696 try {
02697 _sl.action = SLA_LOAD;
02698 return DoLoad(reader, false);
02699 } catch (...) {
02700 ClearSaveLoadState();
02701 return SL_REINIT;
02702 }
02703 }
02704
02714 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02715 {
02716
02717 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02718
02719 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02720 return SL_OK;
02721 }
02722 WaitTillSaved();
02723
02724 try {
02725
02726 if (mode == SL_OLD_LOAD) {
02727 InitializeGame(256, 256, true, true);
02728
02729
02730
02731
02732
02733 ClearGRFConfigList(&_grfconfig);
02734 GamelogReset();
02735 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02736 _sl_version = 0;
02737 _sl_minor_version = 0;
02738 GamelogStartAction(GLAT_LOAD);
02739 if (!AfterLoadGame()) {
02740 GamelogStopAction();
02741 return SL_REINIT;
02742 }
02743 GamelogStopAction();
02744 return SL_OK;
02745 }
02746
02747 switch (mode) {
02748 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02749 case SL_LOAD: _sl.action = SLA_LOAD; break;
02750 case SL_SAVE: _sl.action = SLA_SAVE; break;
02751 default: NOT_REACHED();
02752 }
02753
02754 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02755
02756
02757 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02758 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02759 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
02760
02761 if (fh == NULL) {
02762 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02763 }
02764
02765 if (mode == SL_SAVE) {
02766 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02767 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02768
02769 return DoSave(new FileWriter(fh), threaded);
02770 }
02771
02772
02773 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02774 DEBUG(desync, 1, "load: %s", filename);
02775 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02776 } catch (...) {
02777 ClearSaveLoadState();
02778
02779
02780 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02781
02782
02783 return (mode == SL_LOAD || mode == SL_OLD_LOAD) ? SL_REINIT : SL_ERROR;
02784 }
02785 }
02786
02788 void DoExitSave()
02789 {
02790 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02791 }
02792
02798 void GenerateDefaultSaveName(char *buf, const char *last)
02799 {
02800
02801
02802
02803 CompanyID cid = _local_company;
02804 if (!Company::IsValidID(cid)) {
02805 const Company *c;
02806 FOR_ALL_COMPANIES(c) {
02807 cid = c->index;
02808 break;
02809 }
02810 }
02811
02812 SetDParam(0, cid);
02813
02814
02815 switch (_settings_client.gui.date_format_in_default_names) {
02816 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02817 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02818 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02819 default: NOT_REACHED();
02820 }
02821 SetDParam(2, _date);
02822
02823
02824 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02825 SanitizeFilename(buf);
02826 }
02827
02828 #if 0
02829
02835 int GetSavegameType(char *file)
02836 {
02837 const SaveLoadFormat *fmt;
02838 uint32 hdr;
02839 FILE *f;
02840 int mode = SL_OLD_LOAD;
02841
02842 f = fopen(file, "rb");
02843 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02844 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02845 mode = SL_LOAD;
02846 } else {
02847
02848 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02849 if (fmt->tag == hdr) {
02850 mode = SL_LOAD;
02851 break;
02852 }
02853 }
02854 }
02855
02856 fclose(f);
02857 return mode;
02858 }
02859 #endif