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