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 extern const uint16 SAVEGAME_VERSION = SL_EXT_RATING;
00240
00241 SavegameType _savegame_type;
00242
00243 uint32 _ttdp_version;
00244 uint16 _sl_version;
00245 byte _sl_minor_version;
00246 char _savegame_format[8];
00247 bool _do_autosave;
00248
00250 enum SaveLoadAction {
00251 SLA_LOAD,
00252 SLA_SAVE,
00253 SLA_PTRS,
00254 SLA_NULL,
00255 SLA_LOAD_CHECK,
00256 };
00257
00258 enum NeedLength {
00259 NL_NONE = 0,
00260 NL_WANTLENGTH = 1,
00261 NL_CALCLENGTH = 2,
00262 };
00263
00265 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
00266
00268 struct ReadBuffer {
00269 byte buf[MEMORY_CHUNK_SIZE];
00270 byte *bufp;
00271 byte *bufe;
00272 LoadFilter *reader;
00273 size_t read;
00274
00279 ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
00280 {
00281 }
00282
00283 inline byte ReadByte()
00284 {
00285 if (this->bufp == this->bufe) {
00286 size_t len = this->reader->Read(this->buf, lengthof(this->buf));
00287 if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00288
00289 this->read += len;
00290 this->bufp = this->buf;
00291 this->bufe = this->buf + len;
00292 }
00293
00294 return *this->bufp++;
00295 }
00296
00301 size_t GetSize() const
00302 {
00303 return this->read - (this->bufe - this->bufp);
00304 }
00305 };
00306
00307
00309 struct MemoryDumper {
00310 AutoFreeSmallVector<byte *, 16> blocks;
00311 byte *buf;
00312 byte *bufe;
00313
00315 MemoryDumper() : buf(NULL), bufe(NULL)
00316 {
00317 }
00318
00323 inline void WriteByte(byte b)
00324 {
00325
00326 if (this->buf == this->bufe) {
00327 this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
00328 *this->blocks.Append() = this->buf;
00329 this->bufe = this->buf + MEMORY_CHUNK_SIZE;
00330 }
00331
00332 *this->buf++ = b;
00333 }
00334
00339 void Flush(SaveFilter *writer)
00340 {
00341 uint i = 0;
00342 size_t t = this->GetSize();
00343
00344 while (t > 0) {
00345 size_t to_write = min(MEMORY_CHUNK_SIZE, t);
00346
00347 writer->Write(this->blocks[i++], to_write);
00348 t -= to_write;
00349 }
00350
00351 writer->Finish();
00352 }
00353
00358 size_t GetSize() const
00359 {
00360 return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
00361 }
00362 };
00363
00365 struct SaveLoadParams {
00366 SaveLoadAction action;
00367 NeedLength need_length;
00368 byte block_mode;
00369 bool error;
00370
00371 size_t obj_len;
00372 int array_index, last_array_index;
00373
00374 MemoryDumper *dumper;
00375 SaveFilter *sf;
00376
00377 ReadBuffer *reader;
00378 LoadFilter *lf;
00379
00380 StringID error_str;
00381 char *extra_msg;
00382
00383 byte ff_state;
00384 bool saveinprogress;
00385 };
00386
00387 static SaveLoadParams _sl;
00388
00389
00390 extern const ChunkHandler _gamelog_chunk_handlers[];
00391 extern const ChunkHandler _map_chunk_handlers[];
00392 extern const ChunkHandler _misc_chunk_handlers[];
00393 extern const ChunkHandler _name_chunk_handlers[];
00394 extern const ChunkHandler _cheat_chunk_handlers[] ;
00395 extern const ChunkHandler _setting_chunk_handlers[];
00396 extern const ChunkHandler _company_chunk_handlers[];
00397 extern const ChunkHandler _engine_chunk_handlers[];
00398 extern const ChunkHandler _veh_chunk_handlers[];
00399 extern const ChunkHandler _waypoint_chunk_handlers[];
00400 extern const ChunkHandler _depot_chunk_handlers[];
00401 extern const ChunkHandler _order_chunk_handlers[];
00402 extern const ChunkHandler _town_chunk_handlers[];
00403 extern const ChunkHandler _sign_chunk_handlers[];
00404 extern const ChunkHandler _station_chunk_handlers[];
00405 extern const ChunkHandler _industry_chunk_handlers[];
00406 extern const ChunkHandler _economy_chunk_handlers[];
00407 extern const ChunkHandler _subsidy_chunk_handlers[];
00408 extern const ChunkHandler _goal_chunk_handlers[];
00409 extern const ChunkHandler _ai_chunk_handlers[];
00410 extern const ChunkHandler _game_chunk_handlers[];
00411 extern const ChunkHandler _animated_tile_chunk_handlers[];
00412 extern const ChunkHandler _newgrf_chunk_handlers[];
00413 extern const ChunkHandler _group_chunk_handlers[];
00414 extern const ChunkHandler _cargopacket_chunk_handlers[];
00415 extern const ChunkHandler _autoreplace_chunk_handlers[];
00416 extern const ChunkHandler _labelmaps_chunk_handlers[];
00417 extern const ChunkHandler _linkgraph_chunk_handlers[];
00418 extern const ChunkHandler _airport_chunk_handlers[];
00419 extern const ChunkHandler _object_chunk_handlers[];
00420 extern const ChunkHandler _persistent_storage_chunk_handlers[];
00421
00423 static const ChunkHandler * const _chunk_handlers[] = {
00424 _gamelog_chunk_handlers,
00425 _map_chunk_handlers,
00426 _misc_chunk_handlers,
00427 _name_chunk_handlers,
00428 _cheat_chunk_handlers,
00429 _setting_chunk_handlers,
00430 _veh_chunk_handlers,
00431 _waypoint_chunk_handlers,
00432 _depot_chunk_handlers,
00433 _order_chunk_handlers,
00434 _industry_chunk_handlers,
00435 _economy_chunk_handlers,
00436 _subsidy_chunk_handlers,
00437 _goal_chunk_handlers,
00438 _engine_chunk_handlers,
00439 _town_chunk_handlers,
00440 _sign_chunk_handlers,
00441 _station_chunk_handlers,
00442 _company_chunk_handlers,
00443 _ai_chunk_handlers,
00444 _game_chunk_handlers,
00445 _animated_tile_chunk_handlers,
00446 _newgrf_chunk_handlers,
00447 _group_chunk_handlers,
00448 _cargopacket_chunk_handlers,
00449 _autoreplace_chunk_handlers,
00450 _labelmaps_chunk_handlers,
00451 _linkgraph_chunk_handlers,
00452 _airport_chunk_handlers,
00453 _object_chunk_handlers,
00454 _persistent_storage_chunk_handlers,
00455 NULL,
00456 };
00457
00462 #define FOR_ALL_CHUNK_HANDLERS(ch) \
00463 for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \
00464 for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1)
00465
00467 static void SlNullPointers()
00468 {
00469 _sl.action = SLA_NULL;
00470
00471
00472
00473
00474 _sl_version = SAVEGAME_VERSION;
00475
00476 DEBUG(sl, 1, "Nulling pointers");
00477
00478 FOR_ALL_CHUNK_HANDLERS(ch) {
00479 if (ch->ptrs_proc != NULL) {
00480 DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00481 ch->ptrs_proc();
00482 }
00483 }
00484
00485 DEBUG(sl, 1, "All pointers nulled");
00486
00487 assert(_sl.action == SLA_NULL);
00488 }
00489
00498 void NORETURN SlError(StringID string, const char *extra_msg)
00499 {
00500
00501 if (_sl.action == SLA_LOAD_CHECK) {
00502 _load_check_data.error = string;
00503 free(_load_check_data.error_data);
00504 _load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00505 } else {
00506 _sl.error_str = string;
00507 free(_sl.extra_msg);
00508 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00509 }
00510
00511
00512
00513
00514
00515 if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00516 throw std::exception();
00517 }
00518
00526 void NORETURN SlErrorCorrupt(const char *msg)
00527 {
00528 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00529 }
00530
00531
00532 typedef void (*AsyncSaveFinishProc)();
00533 static AsyncSaveFinishProc _async_save_finish = NULL;
00534 static ThreadObject *_save_thread;
00535
00540 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00541 {
00542 if (_exit_game) return;
00543 while (_async_save_finish != NULL) CSleep(10);
00544
00545 _async_save_finish = proc;
00546 }
00547
00551 void ProcessAsyncSaveFinish()
00552 {
00553 if (_async_save_finish == NULL) return;
00554
00555 _async_save_finish();
00556
00557 _async_save_finish = NULL;
00558
00559 if (_save_thread != NULL) {
00560 _save_thread->Join();
00561 delete _save_thread;
00562 _save_thread = NULL;
00563 }
00564 }
00565
00570 byte SlReadByte()
00571 {
00572 return _sl.reader->ReadByte();
00573 }
00574
00579 void SlWriteByte(byte b)
00580 {
00581 _sl.dumper->WriteByte(b);
00582 }
00583
00584 static inline int SlReadUint16()
00585 {
00586 int x = SlReadByte() << 8;
00587 return x | SlReadByte();
00588 }
00589
00590 static inline uint32 SlReadUint32()
00591 {
00592 uint32 x = SlReadUint16() << 16;
00593 return x | SlReadUint16();
00594 }
00595
00596 static inline uint64 SlReadUint64()
00597 {
00598 uint32 x = SlReadUint32();
00599 uint32 y = SlReadUint32();
00600 return (uint64)x << 32 | y;
00601 }
00602
00603 static inline void SlWriteUint16(uint16 v)
00604 {
00605 SlWriteByte(GB(v, 8, 8));
00606 SlWriteByte(GB(v, 0, 8));
00607 }
00608
00609 static inline void SlWriteUint32(uint32 v)
00610 {
00611 SlWriteUint16(GB(v, 16, 16));
00612 SlWriteUint16(GB(v, 0, 16));
00613 }
00614
00615 static inline void SlWriteUint64(uint64 x)
00616 {
00617 SlWriteUint32((uint32)(x >> 32));
00618 SlWriteUint32((uint32)x);
00619 }
00620
00626 static inline void SlSkipBytes(size_t length)
00627 {
00628 for (; length != 0; length--) SlReadByte();
00629 }
00630
00640 static uint SlReadSimpleGamma()
00641 {
00642 uint i = SlReadByte();
00643 if (HasBit(i, 7)) {
00644 i &= ~0x80;
00645 if (HasBit(i, 6)) {
00646 i &= ~0x40;
00647 if (HasBit(i, 5)) {
00648 i &= ~0x20;
00649 if (HasBit(i, 4)) {
00650 SlErrorCorrupt("Unsupported gamma");
00651 }
00652 i = (i << 8) | SlReadByte();
00653 }
00654 i = (i << 8) | SlReadByte();
00655 }
00656 i = (i << 8) | SlReadByte();
00657 }
00658 return i;
00659 }
00660
00673 static void SlWriteSimpleGamma(size_t i)
00674 {
00675 if (i >= (1 << 7)) {
00676 if (i >= (1 << 14)) {
00677 if (i >= (1 << 21)) {
00678 assert(i < (1 << 28));
00679 SlWriteByte((byte)(0xE0 | (i >> 24)));
00680 SlWriteByte((byte)(i >> 16));
00681 } else {
00682 SlWriteByte((byte)(0xC0 | (i >> 16)));
00683 }
00684 SlWriteByte((byte)(i >> 8));
00685 } else {
00686 SlWriteByte((byte)(0x80 | (i >> 8)));
00687 }
00688 }
00689 SlWriteByte((byte)i);
00690 }
00691
00693 static inline uint SlGetGammaLength(size_t i)
00694 {
00695 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00696 }
00697
00698 static inline uint SlReadSparseIndex()
00699 {
00700 return SlReadSimpleGamma();
00701 }
00702
00703 static inline void SlWriteSparseIndex(uint index)
00704 {
00705 SlWriteSimpleGamma(index);
00706 }
00707
00708 static inline uint SlReadArrayLength()
00709 {
00710 return SlReadSimpleGamma();
00711 }
00712
00713 static inline void SlWriteArrayLength(size_t length)
00714 {
00715 SlWriteSimpleGamma(length);
00716 }
00717
00718 static inline uint SlGetArrayLength(size_t length)
00719 {
00720 return SlGetGammaLength(length);
00721 }
00722
00729 static inline uint SlCalcConvMemLen(VarType conv)
00730 {
00731 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00732 byte length = GB(conv, 4, 4);
00733
00734 switch (length << 4) {
00735 case SLE_VAR_STRB:
00736 case SLE_VAR_STRBQ:
00737 case SLE_VAR_STR:
00738 case SLE_VAR_STRQ:
00739 return SlReadArrayLength();
00740
00741 default:
00742 assert(length < lengthof(conv_mem_size));
00743 return conv_mem_size[length];
00744 }
00745 }
00746
00753 static inline byte SlCalcConvFileLen(VarType conv)
00754 {
00755 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00756 byte length = GB(conv, 0, 4);
00757 assert(length < lengthof(conv_file_size));
00758 return conv_file_size[length];
00759 }
00760
00762 static inline size_t SlCalcRefLen()
00763 {
00764 return IsSavegameVersionBefore(69) ? 2 : 4;
00765 }
00766
00767 void SlSetArrayIndex(uint index)
00768 {
00769 _sl.need_length = NL_WANTLENGTH;
00770 _sl.array_index = index;
00771 }
00772
00773 static size_t _next_offs;
00774
00779 int SlIterateArray()
00780 {
00781 int index;
00782
00783
00784
00785 if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00786
00787 for (;;) {
00788 uint length = SlReadArrayLength();
00789 if (length == 0) {
00790 _next_offs = 0;
00791 return -1;
00792 }
00793
00794 _sl.obj_len = --length;
00795 _next_offs = _sl.reader->GetSize() + length;
00796
00797 switch (_sl.block_mode) {
00798 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00799 case CH_ARRAY: index = _sl.array_index++; break;
00800 default:
00801 DEBUG(sl, 0, "SlIterateArray error");
00802 return -1;
00803 }
00804
00805 if (length != 0) return index;
00806 }
00807 }
00808
00812 void SlSkipArray()
00813 {
00814 while (SlIterateArray() != -1) {
00815 SlSkipBytes(_next_offs - _sl.reader->GetSize());
00816 }
00817 }
00818
00824 void SlSetLength(size_t length)
00825 {
00826 assert(_sl.action == SLA_SAVE);
00827
00828 switch (_sl.need_length) {
00829 case NL_WANTLENGTH:
00830 _sl.need_length = NL_NONE;
00831 switch (_sl.block_mode) {
00832 case CH_RIFF:
00833
00834
00835
00836 assert(length < (1 << 28));
00837 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00838 break;
00839 case CH_ARRAY:
00840 assert(_sl.last_array_index <= _sl.array_index);
00841 while (++_sl.last_array_index <= _sl.array_index) {
00842 SlWriteArrayLength(1);
00843 }
00844 SlWriteArrayLength(length + 1);
00845 break;
00846 case CH_SPARSE_ARRAY:
00847 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00848 SlWriteSparseIndex(_sl.array_index);
00849 break;
00850 default: NOT_REACHED();
00851 }
00852 break;
00853
00854 case NL_CALCLENGTH:
00855 _sl.obj_len += (int)length;
00856 break;
00857
00858 default: NOT_REACHED();
00859 }
00860 }
00861
00868 static void SlCopyBytes(void *ptr, size_t length)
00869 {
00870 byte *p = (byte *)ptr;
00871
00872 switch (_sl.action) {
00873 case SLA_LOAD_CHECK:
00874 case SLA_LOAD:
00875 for (; length != 0; length--) *p++ = SlReadByte();
00876 break;
00877 case SLA_SAVE:
00878 for (; length != 0; length--) SlWriteByte(*p++);
00879 break;
00880 default: NOT_REACHED();
00881 }
00882 }
00883
00885 size_t SlGetFieldLength()
00886 {
00887 return _sl.obj_len;
00888 }
00889
00897 int64 ReadValue(const void *ptr, VarType conv)
00898 {
00899 switch (GetVarMemType(conv)) {
00900 case SLE_VAR_BL: return (*(const bool *)ptr != 0);
00901 case SLE_VAR_I8: return *(const int8 *)ptr;
00902 case SLE_VAR_U8: return *(const byte *)ptr;
00903 case SLE_VAR_I16: return *(const int16 *)ptr;
00904 case SLE_VAR_U16: return *(const uint16*)ptr;
00905 case SLE_VAR_I32: return *(const int32 *)ptr;
00906 case SLE_VAR_U32: return *(const uint32*)ptr;
00907 case SLE_VAR_I64: return *(const int64 *)ptr;
00908 case SLE_VAR_U64: return *(const uint64*)ptr;
00909 case SLE_VAR_NULL:return 0;
00910 default: NOT_REACHED();
00911 }
00912 }
00913
00921 void WriteValue(void *ptr, VarType conv, int64 val)
00922 {
00923 switch (GetVarMemType(conv)) {
00924 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00925 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00926 case SLE_VAR_U8: *(byte *)ptr = val; break;
00927 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00928 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00929 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00930 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00931 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00932 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00933 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00934 case SLE_VAR_NULL: break;
00935 default: NOT_REACHED();
00936 }
00937 }
00938
00947 static void SlSaveLoadConv(void *ptr, VarType conv)
00948 {
00949 switch (_sl.action) {
00950 case SLA_SAVE: {
00951 int64 x = ReadValue(ptr, conv);
00952
00953
00954 switch (GetVarFileType(conv)) {
00955 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00956 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00957 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00958 case SLE_FILE_STRINGID:
00959 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00960 case SLE_FILE_I32:
00961 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00962 case SLE_FILE_I64:
00963 case SLE_FILE_U64: SlWriteUint64(x);break;
00964 default: NOT_REACHED();
00965 }
00966 break;
00967 }
00968 case SLA_LOAD_CHECK:
00969 case SLA_LOAD: {
00970 int64 x;
00971
00972 switch (GetVarFileType(conv)) {
00973 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00974 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00975 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00976 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00977 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00978 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00979 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00980 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00981 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00982 default: NOT_REACHED();
00983 }
00984
00985
00986 WriteValue(ptr, conv, x);
00987 break;
00988 }
00989 case SLA_PTRS: break;
00990 case SLA_NULL: break;
00991 default: NOT_REACHED();
00992 }
00993 }
00994
01004 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
01005 {
01006 if (ptr == NULL) return 0;
01007 return min(strlen(ptr), length - 1);
01008 }
01009
01019 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
01020 {
01021 size_t len;
01022 const char *str;
01023
01024 switch (GetVarMemType(conv)) {
01025 default: NOT_REACHED();
01026 case SLE_VAR_STR:
01027 case SLE_VAR_STRQ:
01028 str = *(const char * const *)ptr;
01029 len = SIZE_MAX;
01030 break;
01031 case SLE_VAR_STRB:
01032 case SLE_VAR_STRBQ:
01033 str = (const char *)ptr;
01034 len = length;
01035 break;
01036 }
01037
01038 len = SlCalcNetStringLen(str, len);
01039 return len + SlGetArrayLength(len);
01040 }
01041
01048 static void SlString(void *ptr, size_t length, VarType conv)
01049 {
01050 switch (_sl.action) {
01051 case SLA_SAVE: {
01052 size_t len;
01053 switch (GetVarMemType(conv)) {
01054 default: NOT_REACHED();
01055 case SLE_VAR_STRB:
01056 case SLE_VAR_STRBQ:
01057 len = SlCalcNetStringLen((char *)ptr, length);
01058 break;
01059 case SLE_VAR_STR:
01060 case SLE_VAR_STRQ:
01061 ptr = *(char **)ptr;
01062 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01063 break;
01064 }
01065
01066 SlWriteArrayLength(len);
01067 SlCopyBytes(ptr, len);
01068 break;
01069 }
01070 case SLA_LOAD_CHECK:
01071 case SLA_LOAD: {
01072 size_t len = SlReadArrayLength();
01073
01074 switch (GetVarMemType(conv)) {
01075 default: NOT_REACHED();
01076 case SLE_VAR_STRB:
01077 case SLE_VAR_STRBQ:
01078 if (len >= length) {
01079 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01080 SlCopyBytes(ptr, length);
01081 SlSkipBytes(len - length);
01082 len = length - 1;
01083 } else {
01084 SlCopyBytes(ptr, len);
01085 }
01086 break;
01087 case SLE_VAR_STR:
01088 case SLE_VAR_STRQ:
01089 free(*(char **)ptr);
01090 if (len == 0) {
01091 *(char **)ptr = NULL;
01092 return;
01093 } else {
01094 *(char **)ptr = MallocT<char>(len + 1);
01095 ptr = *(char **)ptr;
01096 SlCopyBytes(ptr, len);
01097 }
01098 break;
01099 }
01100
01101 ((char *)ptr)[len] = '\0';
01102 StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
01103 if ((conv & SLF_ALLOW_CONTROL) != 0) {
01104 settings = settings | SVS_ALLOW_CONTROL_CODE;
01105 if (IsSavegameVersionBefore(169)) {
01106 str_fix_scc_encoded((char *)ptr, (char *)ptr + len);
01107 }
01108 }
01109 if ((conv & SLF_ALLOW_NEWLINE) != 0) {
01110 settings = settings | SVS_ALLOW_NEWLINE;
01111 }
01112 str_validate((char *)ptr, (char *)ptr + len, settings);
01113 break;
01114 }
01115 case SLA_PTRS: break;
01116 case SLA_NULL: break;
01117 default: NOT_REACHED();
01118 }
01119 }
01120
01126 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01127 {
01128 return SlCalcConvFileLen(conv) * length;
01129 }
01130
01137 void SlArray(void *array, size_t length, VarType conv)
01138 {
01139 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01140
01141
01142 if (_sl.need_length != NL_NONE) {
01143 SlSetLength(SlCalcArrayLen(length, conv));
01144
01145 if (_sl.need_length == NL_CALCLENGTH) return;
01146 }
01147
01148
01149
01150 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01151
01152 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01153 conv == SLE_INT32 || conv == SLE_UINT32) {
01154 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01155 return;
01156 }
01157
01158 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01159 for (uint i = 0; i < length; i++) {
01160 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01161 }
01162 return;
01163 }
01164 }
01165
01166
01167
01168 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01169 SlCopyBytes(array, length);
01170 } else {
01171 byte *a = (byte*)array;
01172 byte mem_size = SlCalcConvMemLen(conv);
01173
01174 for (; length != 0; length --) {
01175 SlSaveLoadConv(a, conv);
01176 a += mem_size;
01177 }
01178 }
01179 }
01180
01181
01192 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01193 {
01194 assert(_sl.action == SLA_SAVE);
01195
01196 if (obj == NULL) return 0;
01197
01198 switch (rt) {
01199 case REF_VEHICLE_OLD:
01200 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01201 case REF_STATION: return ((const Station*)obj)->index + 1;
01202 case REF_TOWN: return ((const Town*)obj)->index + 1;
01203 case REF_ORDER: return ((const Order*)obj)->index + 1;
01204 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01205 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01206 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01207 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01208 case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
01209 default: NOT_REACHED();
01210 }
01211 }
01212
01223 static void *IntToReference(size_t index, SLRefType rt)
01224 {
01225 assert_compile(sizeof(size_t) <= sizeof(void *));
01226
01227 assert(_sl.action == SLA_PTRS);
01228
01229
01230
01231 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01232 rt = REF_VEHICLE;
01233 }
01234
01235
01236 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01237
01238
01239
01240 if (rt != REF_VEHICLE_OLD) index--;
01241
01242 switch (rt) {
01243 case REF_ORDERLIST:
01244 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01245 SlErrorCorrupt("Referencing invalid OrderList");
01246
01247 case REF_ORDER:
01248 if (Order::IsValidID(index)) return Order::Get(index);
01249
01250 if (IsSavegameVersionBefore(5, 2)) return NULL;
01251 SlErrorCorrupt("Referencing invalid Order");
01252
01253 case REF_VEHICLE_OLD:
01254 case REF_VEHICLE:
01255 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01256 SlErrorCorrupt("Referencing invalid Vehicle");
01257
01258 case REF_STATION:
01259 if (Station::IsValidID(index)) return Station::Get(index);
01260 SlErrorCorrupt("Referencing invalid Station");
01261
01262 case REF_TOWN:
01263 if (Town::IsValidID(index)) return Town::Get(index);
01264 SlErrorCorrupt("Referencing invalid Town");
01265
01266 case REF_ROADSTOPS:
01267 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01268 SlErrorCorrupt("Referencing invalid RoadStop");
01269
01270 case REF_ENGINE_RENEWS:
01271 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01272 SlErrorCorrupt("Referencing invalid EngineRenew");
01273
01274 case REF_CARGO_PACKET:
01275 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01276 SlErrorCorrupt("Referencing invalid CargoPacket");
01277
01278 case REF_STORAGE:
01279 if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index);
01280 SlErrorCorrupt("Referencing invalid PersistentStorage");
01281
01282 default: NOT_REACHED();
01283 }
01284 }
01285
01290 static inline size_t SlCalcListLen(const void *list)
01291 {
01292 const std::list<void *> *l = (const std::list<void *> *) list;
01293
01294 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01295
01296
01297 return l->size() * type_size + type_size;
01298 }
01299
01300
01306 static void SlList(void *list, SLRefType conv)
01307 {
01308
01309 if (_sl.need_length != NL_NONE) {
01310 SlSetLength(SlCalcListLen(list));
01311
01312 if (_sl.need_length == NL_CALCLENGTH) return;
01313 }
01314
01315 typedef std::list<void *> PtrList;
01316 PtrList *l = (PtrList *)list;
01317
01318 switch (_sl.action) {
01319 case SLA_SAVE: {
01320 SlWriteUint32((uint32)l->size());
01321
01322 PtrList::iterator iter;
01323 for (iter = l->begin(); iter != l->end(); ++iter) {
01324 void *ptr = *iter;
01325 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01326 }
01327 break;
01328 }
01329 case SLA_LOAD_CHECK:
01330 case SLA_LOAD: {
01331 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01332
01333
01334 for (size_t i = 0; i < length; i++) {
01335 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01336 l->push_back((void *)data);
01337 }
01338 break;
01339 }
01340 case SLA_PTRS: {
01341 PtrList temp = *l;
01342
01343 l->clear();
01344 PtrList::iterator iter;
01345 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01346 void *ptr = IntToReference((size_t)*iter, conv);
01347 l->push_back(ptr);
01348 }
01349 break;
01350 }
01351 case SLA_NULL:
01352 l->clear();
01353 break;
01354 default: NOT_REACHED();
01355 }
01356 }
01357
01358
01360 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01361 {
01362 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01363 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01364
01365 return true;
01366 }
01367
01373 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01374 {
01375 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01376 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01377 return true;
01378 }
01379
01380 return false;
01381 }
01382
01389 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01390 {
01391 size_t length = 0;
01392
01393
01394 for (; sld->cmd != SL_END; sld++) {
01395 length += SlCalcObjMemberLength(object, sld);
01396 }
01397 return length;
01398 }
01399
01400 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01401 {
01402 assert(_sl.action == SLA_SAVE);
01403
01404 switch (sld->cmd) {
01405 case SL_VAR:
01406 case SL_REF:
01407 case SL_ARR:
01408 case SL_STR:
01409 case SL_LST:
01410
01411 if (!SlIsObjectValidInSavegame(sld)) break;
01412
01413 switch (sld->cmd) {
01414 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01415 case SL_REF: return SlCalcRefLen();
01416 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01417 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01418 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01419 default: NOT_REACHED();
01420 }
01421 break;
01422 case SL_WRITEBYTE: return 1;
01423 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01424 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01425 default: NOT_REACHED();
01426 }
01427 return 0;
01428 }
01429
01430
01431 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01432 {
01433 VarType conv = GB(sld->conv, 0, 8);
01434 switch (sld->cmd) {
01435 case SL_VAR:
01436 case SL_REF:
01437 case SL_ARR:
01438 case SL_STR:
01439 case SL_LST:
01440
01441 if (!SlIsObjectValidInSavegame(sld)) return false;
01442 if (SlSkipVariableOnLoad(sld)) return false;
01443
01444 switch (sld->cmd) {
01445 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01446 case SL_REF:
01447 switch (_sl.action) {
01448 case SLA_SAVE:
01449 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01450 break;
01451 case SLA_LOAD_CHECK:
01452 case SLA_LOAD:
01453 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01454 break;
01455 case SLA_PTRS:
01456 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01457 break;
01458 case SLA_NULL:
01459 *(void **)ptr = NULL;
01460 break;
01461 default: NOT_REACHED();
01462 }
01463 break;
01464 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01465 case SL_STR: SlString(ptr, sld->length, sld->conv); break;
01466 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01467 default: NOT_REACHED();
01468 }
01469 break;
01470
01471
01472
01473
01474
01475
01476 case SL_WRITEBYTE:
01477 switch (_sl.action) {
01478 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01479 case SLA_LOAD_CHECK:
01480 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01481 case SLA_PTRS: break;
01482 case SLA_NULL: break;
01483 default: NOT_REACHED();
01484 }
01485 break;
01486
01487
01488 case SL_VEH_INCLUDE:
01489 SlObject(ptr, GetVehicleDescription(VEH_END));
01490 break;
01491
01492 case SL_ST_INCLUDE:
01493 SlObject(ptr, GetBaseStationDescription());
01494 break;
01495
01496 default: NOT_REACHED();
01497 }
01498 return true;
01499 }
01500
01506 void SlObject(void *object, const SaveLoad *sld)
01507 {
01508
01509 if (_sl.need_length != NL_NONE) {
01510 SlSetLength(SlCalcObjLength(object, sld));
01511 if (_sl.need_length == NL_CALCLENGTH) return;
01512 }
01513
01514 for (; sld->cmd != SL_END; sld++) {
01515 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01516 SlObjectMember(ptr, sld);
01517 }
01518 }
01519
01524 void SlGlobList(const SaveLoadGlobVarList *sldg)
01525 {
01526 SlObject(NULL, (const SaveLoad*)sldg);
01527 }
01528
01534 void SlAutolength(AutolengthProc *proc, void *arg)
01535 {
01536 size_t offs;
01537
01538 assert(_sl.action == SLA_SAVE);
01539
01540
01541 _sl.need_length = NL_CALCLENGTH;
01542 _sl.obj_len = 0;
01543 proc(arg);
01544
01545
01546 _sl.need_length = NL_WANTLENGTH;
01547 SlSetLength(_sl.obj_len);
01548
01549 offs = _sl.dumper->GetSize() + _sl.obj_len;
01550
01551
01552 proc(arg);
01553
01554 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01555 }
01556
01561 static void SlLoadChunk(const ChunkHandler *ch)
01562 {
01563 byte m = SlReadByte();
01564 size_t len;
01565 size_t endoffs;
01566
01567 _sl.block_mode = m;
01568 _sl.obj_len = 0;
01569
01570 switch (m) {
01571 case CH_ARRAY:
01572 _sl.array_index = 0;
01573 ch->load_proc();
01574 break;
01575 case CH_SPARSE_ARRAY:
01576 ch->load_proc();
01577 break;
01578 default:
01579 if ((m & 0xF) == CH_RIFF) {
01580
01581 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01582 len += SlReadUint16();
01583 _sl.obj_len = len;
01584 endoffs = _sl.reader->GetSize() + len;
01585 ch->load_proc();
01586 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01587 } else {
01588 SlErrorCorrupt("Invalid chunk type");
01589 }
01590 break;
01591 }
01592 }
01593
01599 static void SlLoadCheckChunk(const ChunkHandler *ch)
01600 {
01601 byte m = SlReadByte();
01602 size_t len;
01603 size_t endoffs;
01604
01605 _sl.block_mode = m;
01606 _sl.obj_len = 0;
01607
01608 switch (m) {
01609 case CH_ARRAY:
01610 _sl.array_index = 0;
01611 if (ch->load_check_proc) {
01612 ch->load_check_proc();
01613 } else {
01614 SlSkipArray();
01615 }
01616 break;
01617 case CH_SPARSE_ARRAY:
01618 if (ch->load_check_proc) {
01619 ch->load_check_proc();
01620 } else {
01621 SlSkipArray();
01622 }
01623 break;
01624 default:
01625 if ((m & 0xF) == CH_RIFF) {
01626
01627 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01628 len += SlReadUint16();
01629 _sl.obj_len = len;
01630 endoffs = _sl.reader->GetSize() + len;
01631 if (ch->load_check_proc) {
01632 ch->load_check_proc();
01633 } else {
01634 SlSkipBytes(len);
01635 }
01636 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01637 } else {
01638 SlErrorCorrupt("Invalid chunk type");
01639 }
01640 break;
01641 }
01642 }
01643
01648 static ChunkSaveLoadProc *_stub_save_proc;
01649
01655 static inline void SlStubSaveProc2(void *arg)
01656 {
01657 _stub_save_proc();
01658 }
01659
01665 static void SlStubSaveProc()
01666 {
01667 SlAutolength(SlStubSaveProc2, NULL);
01668 }
01669
01675 static void SlSaveChunk(const ChunkHandler *ch)
01676 {
01677 ChunkSaveLoadProc *proc = ch->save_proc;
01678
01679
01680 if (proc == NULL) return;
01681
01682 SlWriteUint32(ch->id);
01683 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01684
01685 if (ch->flags & CH_AUTO_LENGTH) {
01686
01687 _stub_save_proc = proc;
01688 proc = SlStubSaveProc;
01689 }
01690
01691 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01692 switch (ch->flags & CH_TYPE_MASK) {
01693 case CH_RIFF:
01694 _sl.need_length = NL_WANTLENGTH;
01695 proc();
01696 break;
01697 case CH_ARRAY:
01698 _sl.last_array_index = 0;
01699 SlWriteByte(CH_ARRAY);
01700 proc();
01701 SlWriteArrayLength(0);
01702 break;
01703 case CH_SPARSE_ARRAY:
01704 SlWriteByte(CH_SPARSE_ARRAY);
01705 proc();
01706 SlWriteArrayLength(0);
01707 break;
01708 default: NOT_REACHED();
01709 }
01710 }
01711
01713 static void SlSaveChunks()
01714 {
01715 FOR_ALL_CHUNK_HANDLERS(ch) {
01716 SlSaveChunk(ch);
01717 }
01718
01719
01720 SlWriteUint32(0);
01721 }
01722
01729 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01730 {
01731 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01732 return NULL;
01733 }
01734
01736 static void SlLoadChunks()
01737 {
01738 uint32 id;
01739 const ChunkHandler *ch;
01740
01741 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01742 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01743
01744 ch = SlFindChunkHandler(id);
01745 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01746 SlLoadChunk(ch);
01747 }
01748 }
01749
01751 static void SlLoadCheckChunks()
01752 {
01753 uint32 id;
01754 const ChunkHandler *ch;
01755
01756 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01757 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01758
01759 ch = SlFindChunkHandler(id);
01760 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01761 SlLoadCheckChunk(ch);
01762 }
01763 }
01764
01766 static void SlFixPointers()
01767 {
01768 _sl.action = SLA_PTRS;
01769
01770 DEBUG(sl, 1, "Fixing pointers");
01771
01772 FOR_ALL_CHUNK_HANDLERS(ch) {
01773 if (ch->ptrs_proc != NULL) {
01774 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01775 ch->ptrs_proc();
01776 }
01777 }
01778
01779 DEBUG(sl, 1, "All pointers fixed");
01780
01781 assert(_sl.action == SLA_PTRS);
01782 }
01783
01784
01786 struct FileReader : LoadFilter {
01787 FILE *file;
01788 long begin;
01789
01794 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01795 {
01796 }
01797
01799 ~FileReader()
01800 {
01801 if (this->file != NULL) fclose(this->file);
01802 this->file = NULL;
01803
01804
01805 _sl.sf = NULL;
01806 }
01807
01808 size_t Read(byte *buf, size_t size)
01809 {
01810
01811 if (this->file == NULL) return 0;
01812
01813 return fread(buf, 1, size, this->file);
01814 }
01815
01816 void Reset()
01817 {
01818 clearerr(this->file);
01819 fseek(this->file, this->begin, SEEK_SET);
01820 }
01821 };
01822
01824 struct FileWriter : SaveFilter {
01825 FILE *file;
01826
01831 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01832 {
01833 }
01834
01836 ~FileWriter()
01837 {
01838 this->Finish();
01839
01840
01841 _sl.sf = NULL;
01842 }
01843
01844 void Write(byte *buf, size_t size)
01845 {
01846
01847 if (this->file == NULL) return;
01848
01849 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01850 }
01851
01852 void Finish()
01853 {
01854 if (this->file != NULL) fclose(this->file);
01855 this->file = NULL;
01856 }
01857 };
01858
01859
01860
01861
01862
01863 #ifdef WITH_LZO
01864 #include <lzo/lzo1x.h>
01865
01867 static const uint LZO_BUFFER_SIZE = 8192;
01868
01870 struct LZOLoadFilter : LoadFilter {
01875 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01876 {
01877 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01878 }
01879
01880 size_t Read(byte *buf, size_t ssize)
01881 {
01882 assert(ssize >= LZO_BUFFER_SIZE);
01883
01884
01885 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01886 uint32 tmp[2];
01887 uint32 size;
01888 lzo_uint len;
01889
01890
01891 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01892
01893
01894 ((uint32*)out)[0] = size = tmp[1];
01895
01896 if (_sl_version != 0) {
01897 tmp[0] = TO_BE32(tmp[0]);
01898 size = TO_BE32(size);
01899 }
01900
01901 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01902
01903
01904 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01905
01906
01907 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01908
01909
01910 lzo1x_decompress(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01911 return len;
01912 }
01913 };
01914
01916 struct LZOSaveFilter : SaveFilter {
01922 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01923 {
01924 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01925 }
01926
01927 void Write(byte *buf, size_t size)
01928 {
01929 const lzo_bytep in = buf;
01930
01931 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01932 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01933 lzo_uint outlen;
01934
01935 do {
01936
01937 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01938 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01939 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01940 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01941 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01942
01943
01944 size -= len;
01945 in += len;
01946 } while (size > 0);
01947 }
01948 };
01949
01950 #endif
01951
01952
01953
01954
01955
01957 struct NoCompLoadFilter : LoadFilter {
01962 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01963 {
01964 }
01965
01966 size_t Read(byte *buf, size_t size)
01967 {
01968 return this->chain->Read(buf, size);
01969 }
01970 };
01971
01973 struct NoCompSaveFilter : SaveFilter {
01979 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01980 {
01981 }
01982
01983 void Write(byte *buf, size_t size)
01984 {
01985 this->chain->Write(buf, size);
01986 }
01987 };
01988
01989
01990
01991
01992
01993 #if defined(WITH_ZLIB)
01994 #include <zlib.h>
01995
01997 struct ZlibLoadFilter : LoadFilter {
01998 z_stream z;
01999 byte fread_buf[MEMORY_CHUNK_SIZE];
02000
02005 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
02006 {
02007 memset(&this->z, 0, sizeof(this->z));
02008 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02009 }
02010
02012 ~ZlibLoadFilter()
02013 {
02014 inflateEnd(&this->z);
02015 }
02016
02017 size_t Read(byte *buf, size_t size)
02018 {
02019 this->z.next_out = buf;
02020 this->z.avail_out = (uint)size;
02021
02022 do {
02023
02024 if (this->z.avail_in == 0) {
02025 this->z.next_in = this->fread_buf;
02026 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02027 }
02028
02029
02030 int r = inflate(&this->z, 0);
02031 if (r == Z_STREAM_END) break;
02032
02033 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02034 } while (this->z.avail_out != 0);
02035
02036 return size - this->z.avail_out;
02037 }
02038 };
02039
02041 struct ZlibSaveFilter : SaveFilter {
02042 z_stream z;
02043
02049 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02050 {
02051 memset(&this->z, 0, sizeof(this->z));
02052 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02053 }
02054
02056 ~ZlibSaveFilter()
02057 {
02058 deflateEnd(&this->z);
02059 }
02060
02067 void WriteLoop(byte *p, size_t len, int mode)
02068 {
02069 byte buf[MEMORY_CHUNK_SIZE];
02070 uint n;
02071 this->z.next_in = p;
02072 this->z.avail_in = (uInt)len;
02073 do {
02074 this->z.next_out = buf;
02075 this->z.avail_out = sizeof(buf);
02076
02084 int r = deflate(&this->z, mode);
02085
02086
02087 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02088 this->chain->Write(buf, n);
02089 }
02090 if (r == Z_STREAM_END) break;
02091
02092 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02093 } while (this->z.avail_in || !this->z.avail_out);
02094 }
02095
02096 void Write(byte *buf, size_t size)
02097 {
02098 this->WriteLoop(buf, size, 0);
02099 }
02100
02101 void Finish()
02102 {
02103 this->WriteLoop(NULL, 0, Z_FINISH);
02104 this->chain->Finish();
02105 }
02106 };
02107
02108 #endif
02109
02110
02111
02112
02113
02114 #if defined(WITH_LZMA)
02115 #include <lzma.h>
02116
02123 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02124
02126 struct LZMALoadFilter : LoadFilter {
02127 lzma_stream lzma;
02128 byte fread_buf[MEMORY_CHUNK_SIZE];
02129
02134 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02135 {
02136
02137 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02138 }
02139
02141 ~LZMALoadFilter()
02142 {
02143 lzma_end(&this->lzma);
02144 }
02145
02146 size_t Read(byte *buf, size_t size)
02147 {
02148 this->lzma.next_out = buf;
02149 this->lzma.avail_out = size;
02150
02151 do {
02152
02153 if (this->lzma.avail_in == 0) {
02154 this->lzma.next_in = this->fread_buf;
02155 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02156 }
02157
02158
02159 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02160 if (r == LZMA_STREAM_END) break;
02161 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02162 } while (this->lzma.avail_out != 0);
02163
02164 return size - this->lzma.avail_out;
02165 }
02166 };
02167
02169 struct LZMASaveFilter : SaveFilter {
02170 lzma_stream lzma;
02171
02177 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02178 {
02179 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02180 }
02181
02183 ~LZMASaveFilter()
02184 {
02185 lzma_end(&this->lzma);
02186 }
02187
02194 void WriteLoop(byte *p, size_t len, lzma_action action)
02195 {
02196 byte buf[MEMORY_CHUNK_SIZE];
02197 size_t n;
02198 this->lzma.next_in = p;
02199 this->lzma.avail_in = len;
02200 do {
02201 this->lzma.next_out = buf;
02202 this->lzma.avail_out = sizeof(buf);
02203
02204 lzma_ret r = lzma_code(&this->lzma, action);
02205
02206
02207 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02208 this->chain->Write(buf, n);
02209 }
02210 if (r == LZMA_STREAM_END) break;
02211 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02212 } while (this->lzma.avail_in || !this->lzma.avail_out);
02213 }
02214
02215 void Write(byte *buf, size_t size)
02216 {
02217 this->WriteLoop(buf, size, LZMA_RUN);
02218 }
02219
02220 void Finish()
02221 {
02222 this->WriteLoop(NULL, 0, LZMA_FINISH);
02223 this->chain->Finish();
02224 }
02225 };
02226
02227 #endif
02228
02229
02230
02231
02232
02234 struct SaveLoadFormat {
02235 const char *name;
02236 uint32 tag;
02237
02238 LoadFilter *(*init_load)(LoadFilter *chain);
02239 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02240
02241 byte min_compression;
02242 byte default_compression;
02243 byte max_compression;
02244 };
02245
02247 static const SaveLoadFormat _saveload_formats[] = {
02248 #if defined(WITH_LZO)
02249
02250 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02251 #else
02252 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02253 #endif
02254
02255 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02256 #if defined(WITH_ZLIB)
02257
02258
02259
02260 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02261 #else
02262 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02263 #endif
02264 #if defined(WITH_LZMA)
02265
02266
02267
02268
02269
02270 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02271 #else
02272 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02273 #endif
02274 };
02275
02283 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02284 {
02285 const SaveLoadFormat *def = lastof(_saveload_formats);
02286
02287
02288 while (!def->init_write) def--;
02289
02290 if (!StrEmpty(s)) {
02291
02292 char *complevel = strrchr(s, ':');
02293 if (complevel != NULL) *complevel = '\0';
02294
02295 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02296 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02297 *compression_level = slf->default_compression;
02298 if (complevel != NULL) {
02299
02300
02301
02302 *complevel = ':';
02303 complevel++;
02304
02305
02306 char *end;
02307 long level = strtol(complevel, &end, 10);
02308 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02309 SetDParamStr(0, complevel);
02310 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL);
02311 } else {
02312 *compression_level = level;
02313 }
02314 }
02315 return slf;
02316 }
02317 }
02318
02319 SetDParamStr(0, s);
02320 SetDParamStr(1, def->name);
02321 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL);
02322
02323
02324 if (complevel != NULL) *complevel = ':';
02325 }
02326 *compression_level = def->default_compression;
02327 return def;
02328 }
02329
02330
02331 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02332 extern bool AfterLoadGame();
02333 extern bool LoadOldSaveGame(const char *file);
02334
02338 static inline void ClearSaveLoadState()
02339 {
02340 delete _sl.dumper;
02341 _sl.dumper = NULL;
02342
02343 delete _sl.sf;
02344 _sl.sf = NULL;
02345
02346 delete _sl.reader;
02347 _sl.reader = NULL;
02348
02349 delete _sl.lf;
02350 _sl.lf = NULL;
02351 }
02352
02358 static void SaveFileStart()
02359 {
02360 _sl.ff_state = _fast_forward;
02361 _fast_forward = 0;
02362 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02363
02364 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02365 _sl.saveinprogress = true;
02366 }
02367
02369 static void SaveFileDone()
02370 {
02371 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02372 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02373
02374 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02375 _sl.saveinprogress = false;
02376 }
02377
02379 void SetSaveLoadError(StringID str)
02380 {
02381 _sl.error_str = str;
02382 }
02383
02385 const char *GetSaveLoadErrorString()
02386 {
02387 SetDParam(0, _sl.error_str);
02388 SetDParamStr(1, _sl.extra_msg);
02389
02390 static char err_str[512];
02391 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02392 return err_str;
02393 }
02394
02396 static void SaveFileError()
02397 {
02398 SetDParamStr(0, GetSaveLoadErrorString());
02399 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02400 SaveFileDone();
02401 }
02402
02407 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02408 {
02409 try {
02410 byte compression;
02411 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02412
02413
02414 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02415 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02416
02417 _sl.sf = fmt->init_write(_sl.sf, compression);
02418 _sl.dumper->Flush(_sl.sf);
02419
02420 ClearSaveLoadState();
02421
02422 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02423
02424 return SL_OK;
02425 } catch (...) {
02426 ClearSaveLoadState();
02427
02428 AsyncSaveFinishProc asfp = SaveFileDone;
02429
02430
02431
02432 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02433
02434 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02435 asfp = SaveFileError;
02436 }
02437
02438 if (threaded) {
02439 SetAsyncSaveFinish(asfp);
02440 } else {
02441 asfp();
02442 }
02443 return SL_ERROR;
02444 }
02445 }
02446
02448 static void SaveFileToDiskThread(void *arg)
02449 {
02450 SaveFileToDisk(true);
02451 }
02452
02453 void WaitTillSaved()
02454 {
02455 if (_save_thread == NULL) return;
02456
02457 _save_thread->Join();
02458 delete _save_thread;
02459 _save_thread = NULL;
02460
02461
02462 ProcessAsyncSaveFinish();
02463 }
02464
02473 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02474 {
02475 assert(!_sl.saveinprogress);
02476
02477 _sl.dumper = new MemoryDumper();
02478 _sl.sf = writer;
02479
02480 _sl_version = SAVEGAME_VERSION;
02481
02482 SaveViewportBeforeSaveGame();
02483 SlSaveChunks();
02484
02485 SaveFileStart();
02486 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02487 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02488
02489 SaveOrLoadResult result = SaveFileToDisk(false);
02490 SaveFileDone();
02491
02492 return result;
02493 }
02494
02495 return SL_OK;
02496 }
02497
02504 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02505 {
02506 try {
02507 _sl.action = SLA_SAVE;
02508 return DoSave(writer, threaded);
02509 } catch (...) {
02510 ClearSaveLoadState();
02511 return SL_ERROR;
02512 }
02513 }
02514
02521 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02522 {
02523 _sl.lf = reader;
02524
02525 if (load_check) {
02526
02527 _load_check_data.Clear();
02528
02529 _load_check_data.checkable = true;
02530 }
02531
02532 uint32 hdr[2];
02533 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02534
02535
02536 const SaveLoadFormat *fmt = _saveload_formats;
02537 for (;;) {
02538
02539 if (fmt == endof(_saveload_formats)) {
02540 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02541 _sl.lf->Reset();
02542 _sl_version = 0;
02543 _sl_minor_version = 0;
02544
02545
02546 fmt = _saveload_formats;
02547 for (;;) {
02548 if (fmt == endof(_saveload_formats)) {
02549
02550 NOT_REACHED();
02551 }
02552 if (fmt->tag == TO_BE32X('OTTD')) break;
02553 fmt++;
02554 }
02555 break;
02556 }
02557
02558 if (fmt->tag == hdr[0]) {
02559
02560 _sl_version = TO_BE32(hdr[1]) >> 16;
02561
02562
02563
02564 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02565
02566 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02567
02568
02569 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02570 break;
02571 }
02572
02573 fmt++;
02574 }
02575
02576
02577 if (fmt->init_load == NULL) {
02578 char err_str[64];
02579 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02580 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02581 }
02582
02583 _sl.lf = fmt->init_load(_sl.lf);
02584 _sl.reader = new ReadBuffer(_sl.lf);
02585 _next_offs = 0;
02586
02587 if (!load_check) {
02588
02589
02590
02591 InitializeGame(256, 256, true, true);
02592
02593 GamelogReset();
02594
02595 if (IsSavegameVersionBefore(4)) {
02596
02597
02598
02599
02600
02601
02602
02603
02604
02605
02606
02607
02608
02609
02610
02611
02612
02613
02614
02615
02616
02617 ClearGRFConfigList(&_grfconfig);
02618 }
02619 }
02620
02621 if (load_check) {
02622
02623
02624 SlLoadCheckChunks();
02625 } else {
02626
02627 SlLoadChunks();
02628 SlFixPointers();
02629 }
02630
02631 ClearSaveLoadState();
02632
02633 _savegame_type = SGT_OTTD;
02634
02635 if (load_check) {
02636
02637 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02638 } else {
02639 GamelogStartAction(GLAT_LOAD);
02640
02641
02642
02643 if (!AfterLoadGame()) {
02644 GamelogStopAction();
02645 return SL_REINIT;
02646 }
02647
02648 GamelogStopAction();
02649 }
02650
02651 return SL_OK;
02652 }
02653
02659 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02660 {
02661 try {
02662 _sl.action = SLA_LOAD;
02663 return DoLoad(reader, false);
02664 } catch (...) {
02665 ClearSaveLoadState();
02666 return SL_REINIT;
02667 }
02668 }
02669
02679 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02680 {
02681
02682 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02683
02684 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02685 return SL_OK;
02686 }
02687 WaitTillSaved();
02688
02689
02690 if (mode == SL_OLD_LOAD) {
02691 InitializeGame(256, 256, true, true);
02692
02693
02694
02695
02696
02697 ClearGRFConfigList(&_grfconfig);
02698 GamelogReset();
02699 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02700 _sl_version = 0;
02701 _sl_minor_version = 0;
02702 GamelogStartAction(GLAT_LOAD);
02703 if (!AfterLoadGame()) {
02704 GamelogStopAction();
02705 return SL_REINIT;
02706 }
02707 GamelogStopAction();
02708 return SL_OK;
02709 }
02710
02711 switch (mode) {
02712 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02713 case SL_LOAD: _sl.action = SLA_LOAD; break;
02714 case SL_SAVE: _sl.action = SLA_SAVE; break;
02715 default: NOT_REACHED();
02716 }
02717
02718 try {
02719 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02720
02721
02722 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02723 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02724 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
02725
02726 if (fh == NULL) {
02727 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02728 }
02729
02730 if (mode == SL_SAVE) {
02731 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02732 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02733
02734 return DoSave(new FileWriter(fh), threaded);
02735 }
02736
02737
02738 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02739 DEBUG(desync, 1, "load: %s", filename);
02740 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02741 } catch (...) {
02742 ClearSaveLoadState();
02743
02744
02745 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02746
02747
02748 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02749 }
02750 }
02751
02753 void DoExitSave()
02754 {
02755 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02756 }
02757
02763 void GenerateDefaultSaveName(char *buf, const char *last)
02764 {
02765
02766
02767
02768 CompanyID cid = _local_company;
02769 if (!Company::IsValidID(cid)) {
02770 const Company *c;
02771 FOR_ALL_COMPANIES(c) {
02772 cid = c->index;
02773 break;
02774 }
02775 }
02776
02777 SetDParam(0, cid);
02778
02779
02780 switch (_settings_client.gui.date_format_in_default_names) {
02781 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02782 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02783 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02784 default: NOT_REACHED();
02785 }
02786 SetDParam(2, _date);
02787
02788
02789 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02790 SanitizeFilename(buf);
02791 }
02792
02793 #if 0
02794
02800 int GetSavegameType(char *file)
02801 {
02802 const SaveLoadFormat *fmt;
02803 uint32 hdr;
02804 FILE *f;
02805 int mode = SL_OLD_LOAD;
02806
02807 f = fopen(file, "rb");
02808 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02809 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02810 mode = SL_LOAD;
02811 } else {
02812
02813 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02814 if (fmt->tag == hdr) {
02815 mode = SL_LOAD;
02816 break;
02817 }
02818 }
02819 }
02820
02821 fclose(f);
02822 return mode;
02823 }
02824 #endif