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 extern const uint16 SAVEGAME_VERSION = 177;
00246 assert_compile(SAVEGAME_VERSION_H2H == SAVEGAME_VERSION);
00247
00248 SavegameType _savegame_type;
00249
00250 uint32 _ttdp_version;
00251 uint16 _sl_version;
00252 byte _sl_minor_version;
00253 char _savegame_format[8];
00254 bool _do_autosave;
00255
00257 enum SaveLoadAction {
00258 SLA_LOAD,
00259 SLA_SAVE,
00260 SLA_PTRS,
00261 SLA_NULL,
00262 SLA_LOAD_CHECK,
00263 };
00264
00265 enum NeedLength {
00266 NL_NONE = 0,
00267 NL_WANTLENGTH = 1,
00268 NL_CALCLENGTH = 2,
00269 };
00270
00272 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
00273
00275 struct ReadBuffer {
00276 byte buf[MEMORY_CHUNK_SIZE];
00277 byte *bufp;
00278 byte *bufe;
00279 LoadFilter *reader;
00280 size_t read;
00281
00286 ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
00287 {
00288 }
00289
00290 inline byte ReadByte()
00291 {
00292 if (this->bufp == this->bufe) {
00293 size_t len = this->reader->Read(this->buf, lengthof(this->buf));
00294 if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00295
00296 this->read += len;
00297 this->bufp = this->buf;
00298 this->bufe = this->buf + len;
00299 }
00300
00301 return *this->bufp++;
00302 }
00303
00308 size_t GetSize() const
00309 {
00310 return this->read - (this->bufe - this->bufp);
00311 }
00312 };
00313
00314
00316 struct MemoryDumper {
00317 AutoFreeSmallVector<byte *, 16> blocks;
00318 byte *buf;
00319 byte *bufe;
00320
00322 MemoryDumper() : buf(NULL), bufe(NULL)
00323 {
00324 }
00325
00330 inline void WriteByte(byte b)
00331 {
00332
00333 if (this->buf == this->bufe) {
00334 this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
00335 *this->blocks.Append() = this->buf;
00336 this->bufe = this->buf + MEMORY_CHUNK_SIZE;
00337 }
00338
00339 *this->buf++ = b;
00340 }
00341
00346 void Flush(SaveFilter *writer)
00347 {
00348 uint i = 0;
00349 size_t t = this->GetSize();
00350
00351 while (t > 0) {
00352 size_t to_write = min(MEMORY_CHUNK_SIZE, t);
00353
00354 writer->Write(this->blocks[i++], to_write);
00355 t -= to_write;
00356 }
00357
00358 writer->Finish();
00359 }
00360
00365 size_t GetSize() const
00366 {
00367 return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
00368 }
00369 };
00370
00372 struct SaveLoadParams {
00373 SaveLoadAction action;
00374 NeedLength need_length;
00375 byte block_mode;
00376 bool error;
00377
00378 size_t obj_len;
00379 int array_index, last_array_index;
00380
00381 MemoryDumper *dumper;
00382 SaveFilter *sf;
00383
00384 ReadBuffer *reader;
00385 LoadFilter *lf;
00386
00387 StringID error_str;
00388 char *extra_msg;
00389
00390 byte ff_state;
00391 bool saveinprogress;
00392 };
00393
00394 static SaveLoadParams _sl;
00395
00396
00397 extern const ChunkHandler _gamelog_chunk_handlers[];
00398 extern const ChunkHandler _map_chunk_handlers[];
00399 extern const ChunkHandler _misc_chunk_handlers[];
00400 extern const ChunkHandler _name_chunk_handlers[];
00401 extern const ChunkHandler _cheat_chunk_handlers[] ;
00402 extern const ChunkHandler _setting_chunk_handlers[];
00403 extern const ChunkHandler _company_chunk_handlers[];
00404 extern const ChunkHandler _engine_chunk_handlers[];
00405 extern const ChunkHandler _veh_chunk_handlers[];
00406 extern const ChunkHandler _waypoint_chunk_handlers[];
00407 extern const ChunkHandler _depot_chunk_handlers[];
00408 extern const ChunkHandler _order_chunk_handlers[];
00409 extern const ChunkHandler _town_chunk_handlers[];
00410 extern const ChunkHandler _sign_chunk_handlers[];
00411 extern const ChunkHandler _station_chunk_handlers[];
00412 extern const ChunkHandler _industry_chunk_handlers[];
00413 extern const ChunkHandler _economy_chunk_handlers[];
00414 extern const ChunkHandler _subsidy_chunk_handlers[];
00415 extern const ChunkHandler _cargomonitor_chunk_handlers[];
00416 extern const ChunkHandler _goal_chunk_handlers[];
00417 extern const ChunkHandler _ai_chunk_handlers[];
00418 extern const ChunkHandler _game_chunk_handlers[];
00419 extern const ChunkHandler _animated_tile_chunk_handlers[];
00420 extern const ChunkHandler _newgrf_chunk_handlers[];
00421 extern const ChunkHandler _group_chunk_handlers[];
00422 extern const ChunkHandler _cargopacket_chunk_handlers[];
00423 extern const ChunkHandler _autoreplace_chunk_handlers[];
00424 extern const ChunkHandler _labelmaps_chunk_handlers[];
00425 extern const ChunkHandler _airport_chunk_handlers[];
00426 extern const ChunkHandler _object_chunk_handlers[];
00427 extern const ChunkHandler _persistent_storage_chunk_handlers[];
00428
00430 static const ChunkHandler * const _chunk_handlers[] = {
00431 _gamelog_chunk_handlers,
00432 _map_chunk_handlers,
00433 _misc_chunk_handlers,
00434 _name_chunk_handlers,
00435 _cheat_chunk_handlers,
00436 _setting_chunk_handlers,
00437 _veh_chunk_handlers,
00438 _waypoint_chunk_handlers,
00439 _depot_chunk_handlers,
00440 _order_chunk_handlers,
00441 _industry_chunk_handlers,
00442 _economy_chunk_handlers,
00443 _subsidy_chunk_handlers,
00444 _cargomonitor_chunk_handlers,
00445 _goal_chunk_handlers,
00446 _engine_chunk_handlers,
00447 _town_chunk_handlers,
00448 _sign_chunk_handlers,
00449 _station_chunk_handlers,
00450 _company_chunk_handlers,
00451 _ai_chunk_handlers,
00452 _game_chunk_handlers,
00453 _animated_tile_chunk_handlers,
00454 _newgrf_chunk_handlers,
00455 _group_chunk_handlers,
00456 _cargopacket_chunk_handlers,
00457 _autoreplace_chunk_handlers,
00458 _labelmaps_chunk_handlers,
00459 _airport_chunk_handlers,
00460 _object_chunk_handlers,
00461 _persistent_storage_chunk_handlers,
00462 NULL,
00463 };
00464
00469 #define FOR_ALL_CHUNK_HANDLERS(ch) \
00470 for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \
00471 for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1)
00472
00474 static void SlNullPointers()
00475 {
00476 _sl.action = SLA_NULL;
00477
00478
00479
00480
00481 _sl_version = SAVEGAME_VERSION;
00482
00483 DEBUG(sl, 1, "Nulling pointers");
00484
00485 FOR_ALL_CHUNK_HANDLERS(ch) {
00486 if (ch->ptrs_proc != NULL) {
00487 DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00488 ch->ptrs_proc();
00489 }
00490 }
00491
00492 DEBUG(sl, 1, "All pointers nulled");
00493
00494 assert(_sl.action == SLA_NULL);
00495 }
00496
00505 void NORETURN SlError(StringID string, const char *extra_msg)
00506 {
00507
00508 if (_sl.action == SLA_LOAD_CHECK) {
00509 _load_check_data.error = string;
00510 free(_load_check_data.error_data);
00511 _load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00512 } else {
00513 _sl.error_str = string;
00514 free(_sl.extra_msg);
00515 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00516 }
00517
00518
00519
00520
00521
00522 if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00523 throw std::exception();
00524 }
00525
00533 void NORETURN SlErrorCorrupt(const char *msg)
00534 {
00535 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00536 }
00537
00538
00539 typedef void (*AsyncSaveFinishProc)();
00540 static AsyncSaveFinishProc _async_save_finish = NULL;
00541 static ThreadObject *_save_thread;
00542
00547 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00548 {
00549 if (_exit_game) return;
00550 while (_async_save_finish != NULL) CSleep(10);
00551
00552 _async_save_finish = proc;
00553 }
00554
00558 void ProcessAsyncSaveFinish()
00559 {
00560 if (_async_save_finish == NULL) return;
00561
00562 _async_save_finish();
00563
00564 _async_save_finish = NULL;
00565
00566 if (_save_thread != NULL) {
00567 _save_thread->Join();
00568 delete _save_thread;
00569 _save_thread = NULL;
00570 }
00571 }
00572
00577 byte SlReadByte()
00578 {
00579 return _sl.reader->ReadByte();
00580 }
00581
00586 void SlWriteByte(byte b)
00587 {
00588 _sl.dumper->WriteByte(b);
00589 }
00590
00591 static inline int SlReadUint16()
00592 {
00593 int x = SlReadByte() << 8;
00594 return x | SlReadByte();
00595 }
00596
00597 static inline uint32 SlReadUint32()
00598 {
00599 uint32 x = SlReadUint16() << 16;
00600 return x | SlReadUint16();
00601 }
00602
00603 static inline uint64 SlReadUint64()
00604 {
00605 uint32 x = SlReadUint32();
00606 uint32 y = SlReadUint32();
00607 return (uint64)x << 32 | y;
00608 }
00609
00610 static inline void SlWriteUint16(uint16 v)
00611 {
00612 SlWriteByte(GB(v, 8, 8));
00613 SlWriteByte(GB(v, 0, 8));
00614 }
00615
00616 static inline void SlWriteUint32(uint32 v)
00617 {
00618 SlWriteUint16(GB(v, 16, 16));
00619 SlWriteUint16(GB(v, 0, 16));
00620 }
00621
00622 static inline void SlWriteUint64(uint64 x)
00623 {
00624 SlWriteUint32((uint32)(x >> 32));
00625 SlWriteUint32((uint32)x);
00626 }
00627
00633 static inline void SlSkipBytes(size_t length)
00634 {
00635 for (; length != 0; length--) SlReadByte();
00636 }
00637
00647 static uint SlReadSimpleGamma()
00648 {
00649 uint i = SlReadByte();
00650 if (HasBit(i, 7)) {
00651 i &= ~0x80;
00652 if (HasBit(i, 6)) {
00653 i &= ~0x40;
00654 if (HasBit(i, 5)) {
00655 i &= ~0x20;
00656 if (HasBit(i, 4)) {
00657 SlErrorCorrupt("Unsupported gamma");
00658 }
00659 i = (i << 8) | SlReadByte();
00660 }
00661 i = (i << 8) | SlReadByte();
00662 }
00663 i = (i << 8) | SlReadByte();
00664 }
00665 return i;
00666 }
00667
00680 static void SlWriteSimpleGamma(size_t i)
00681 {
00682 if (i >= (1 << 7)) {
00683 if (i >= (1 << 14)) {
00684 if (i >= (1 << 21)) {
00685 assert(i < (1 << 28));
00686 SlWriteByte((byte)(0xE0 | (i >> 24)));
00687 SlWriteByte((byte)(i >> 16));
00688 } else {
00689 SlWriteByte((byte)(0xC0 | (i >> 16)));
00690 }
00691 SlWriteByte((byte)(i >> 8));
00692 } else {
00693 SlWriteByte((byte)(0x80 | (i >> 8)));
00694 }
00695 }
00696 SlWriteByte((byte)i);
00697 }
00698
00700 static inline uint SlGetGammaLength(size_t i)
00701 {
00702 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00703 }
00704
00705 static inline uint SlReadSparseIndex()
00706 {
00707 return SlReadSimpleGamma();
00708 }
00709
00710 static inline void SlWriteSparseIndex(uint index)
00711 {
00712 SlWriteSimpleGamma(index);
00713 }
00714
00715 static inline uint SlReadArrayLength()
00716 {
00717 return SlReadSimpleGamma();
00718 }
00719
00720 static inline void SlWriteArrayLength(size_t length)
00721 {
00722 SlWriteSimpleGamma(length);
00723 }
00724
00725 static inline uint SlGetArrayLength(size_t length)
00726 {
00727 return SlGetGammaLength(length);
00728 }
00729
00736 static inline uint SlCalcConvMemLen(VarType conv)
00737 {
00738 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00739 byte length = GB(conv, 4, 4);
00740
00741 switch (length << 4) {
00742 case SLE_VAR_STRB:
00743 case SLE_VAR_STRBQ:
00744 case SLE_VAR_STR:
00745 case SLE_VAR_STRQ:
00746 return SlReadArrayLength();
00747
00748 default:
00749 assert(length < lengthof(conv_mem_size));
00750 return conv_mem_size[length];
00751 }
00752 }
00753
00760 static inline byte SlCalcConvFileLen(VarType conv)
00761 {
00762 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00763 byte length = GB(conv, 0, 4);
00764 assert(length < lengthof(conv_file_size));
00765 return conv_file_size[length];
00766 }
00767
00769 static inline size_t SlCalcRefLen()
00770 {
00771 return IsSavegameVersionBefore(69) ? 2 : 4;
00772 }
00773
00774 void SlSetArrayIndex(uint index)
00775 {
00776 _sl.need_length = NL_WANTLENGTH;
00777 _sl.array_index = index;
00778 }
00779
00780 static size_t _next_offs;
00781
00786 int SlIterateArray()
00787 {
00788 int index;
00789
00790
00791
00792 if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00793
00794 for (;;) {
00795 uint length = SlReadArrayLength();
00796 if (length == 0) {
00797 _next_offs = 0;
00798 return -1;
00799 }
00800
00801 _sl.obj_len = --length;
00802 _next_offs = _sl.reader->GetSize() + length;
00803
00804 switch (_sl.block_mode) {
00805 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00806 case CH_ARRAY: index = _sl.array_index++; break;
00807 default:
00808 DEBUG(sl, 0, "SlIterateArray error");
00809 return -1;
00810 }
00811
00812 if (length != 0) return index;
00813 }
00814 }
00815
00819 void SlSkipArray()
00820 {
00821 while (SlIterateArray() != -1) {
00822 SlSkipBytes(_next_offs - _sl.reader->GetSize());
00823 }
00824 }
00825
00831 void SlSetLength(size_t length)
00832 {
00833 assert(_sl.action == SLA_SAVE);
00834
00835 switch (_sl.need_length) {
00836 case NL_WANTLENGTH:
00837 _sl.need_length = NL_NONE;
00838 switch (_sl.block_mode) {
00839 case CH_RIFF:
00840
00841
00842
00843 assert(length < (1 << 28));
00844 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00845 break;
00846 case CH_ARRAY:
00847 assert(_sl.last_array_index <= _sl.array_index);
00848 while (++_sl.last_array_index <= _sl.array_index) {
00849 SlWriteArrayLength(1);
00850 }
00851 SlWriteArrayLength(length + 1);
00852 break;
00853 case CH_SPARSE_ARRAY:
00854 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00855 SlWriteSparseIndex(_sl.array_index);
00856 break;
00857 default: NOT_REACHED();
00858 }
00859 break;
00860
00861 case NL_CALCLENGTH:
00862 _sl.obj_len += (int)length;
00863 break;
00864
00865 default: NOT_REACHED();
00866 }
00867 }
00868
00875 static void SlCopyBytes(void *ptr, size_t length)
00876 {
00877 byte *p = (byte *)ptr;
00878
00879 switch (_sl.action) {
00880 case SLA_LOAD_CHECK:
00881 case SLA_LOAD:
00882 for (; length != 0; length--) *p++ = SlReadByte();
00883 break;
00884 case SLA_SAVE:
00885 for (; length != 0; length--) SlWriteByte(*p++);
00886 break;
00887 default: NOT_REACHED();
00888 }
00889 }
00890
00892 size_t SlGetFieldLength()
00893 {
00894 return _sl.obj_len;
00895 }
00896
00904 int64 ReadValue(const void *ptr, VarType conv)
00905 {
00906 switch (GetVarMemType(conv)) {
00907 case SLE_VAR_BL: return (*(const bool *)ptr != 0);
00908 case SLE_VAR_I8: return *(const int8 *)ptr;
00909 case SLE_VAR_U8: return *(const byte *)ptr;
00910 case SLE_VAR_I16: return *(const int16 *)ptr;
00911 case SLE_VAR_U16: return *(const uint16*)ptr;
00912 case SLE_VAR_I32: return *(const int32 *)ptr;
00913 case SLE_VAR_U32: return *(const uint32*)ptr;
00914 case SLE_VAR_I64: return *(const int64 *)ptr;
00915 case SLE_VAR_U64: return *(const uint64*)ptr;
00916 case SLE_VAR_NULL:return 0;
00917 default: NOT_REACHED();
00918 }
00919 }
00920
00928 void WriteValue(void *ptr, VarType conv, int64 val)
00929 {
00930 switch (GetVarMemType(conv)) {
00931 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00932 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00933 case SLE_VAR_U8: *(byte *)ptr = val; break;
00934 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00935 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00936 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00937 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00938 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00939 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00940 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00941 case SLE_VAR_NULL: break;
00942 default: NOT_REACHED();
00943 }
00944 }
00945
00954 static void SlSaveLoadConv(void *ptr, VarType conv)
00955 {
00956 switch (_sl.action) {
00957 case SLA_SAVE: {
00958 int64 x = ReadValue(ptr, conv);
00959
00960
00961 switch (GetVarFileType(conv)) {
00962 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00963 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00964 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00965 case SLE_FILE_STRINGID:
00966 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00967 case SLE_FILE_I32:
00968 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00969 case SLE_FILE_I64:
00970 case SLE_FILE_U64: SlWriteUint64(x);break;
00971 default: NOT_REACHED();
00972 }
00973 break;
00974 }
00975 case SLA_LOAD_CHECK:
00976 case SLA_LOAD: {
00977 int64 x;
00978
00979 switch (GetVarFileType(conv)) {
00980 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00981 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00982 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00983 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00984 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00985 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00986 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00987 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00988 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00989 default: NOT_REACHED();
00990 }
00991
00992
00993 WriteValue(ptr, conv, x);
00994 break;
00995 }
00996 case SLA_PTRS: break;
00997 case SLA_NULL: break;
00998 default: NOT_REACHED();
00999 }
01000 }
01001
01011 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
01012 {
01013 if (ptr == NULL) return 0;
01014 return min(strlen(ptr), length - 1);
01015 }
01016
01026 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
01027 {
01028 size_t len;
01029 const char *str;
01030
01031 switch (GetVarMemType(conv)) {
01032 default: NOT_REACHED();
01033 case SLE_VAR_STR:
01034 case SLE_VAR_STRQ:
01035 str = *(const char * const *)ptr;
01036 len = SIZE_MAX;
01037 break;
01038 case SLE_VAR_STRB:
01039 case SLE_VAR_STRBQ:
01040 str = (const char *)ptr;
01041 len = length;
01042 break;
01043 }
01044
01045 len = SlCalcNetStringLen(str, len);
01046 return len + SlGetArrayLength(len);
01047 }
01048
01055 static void SlString(void *ptr, size_t length, VarType conv)
01056 {
01057 switch (_sl.action) {
01058 case SLA_SAVE: {
01059 size_t len;
01060 switch (GetVarMemType(conv)) {
01061 default: NOT_REACHED();
01062 case SLE_VAR_STRB:
01063 case SLE_VAR_STRBQ:
01064 len = SlCalcNetStringLen((char *)ptr, length);
01065 break;
01066 case SLE_VAR_STR:
01067 case SLE_VAR_STRQ:
01068 ptr = *(char **)ptr;
01069 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01070 break;
01071 }
01072
01073 SlWriteArrayLength(len);
01074 SlCopyBytes(ptr, len);
01075 break;
01076 }
01077 case SLA_LOAD_CHECK:
01078 case SLA_LOAD: {
01079 size_t len = SlReadArrayLength();
01080
01081 switch (GetVarMemType(conv)) {
01082 default: NOT_REACHED();
01083 case SLE_VAR_STRB:
01084 case SLE_VAR_STRBQ:
01085 if (len >= length) {
01086 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01087 SlCopyBytes(ptr, length);
01088 SlSkipBytes(len - length);
01089 len = length - 1;
01090 } else {
01091 SlCopyBytes(ptr, len);
01092 }
01093 break;
01094 case SLE_VAR_STR:
01095 case SLE_VAR_STRQ:
01096 free(*(char **)ptr);
01097 if (len == 0) {
01098 *(char **)ptr = NULL;
01099 return;
01100 } else {
01101 *(char **)ptr = MallocT<char>(len + 1);
01102 ptr = *(char **)ptr;
01103 SlCopyBytes(ptr, len);
01104 }
01105 break;
01106 }
01107
01108 ((char *)ptr)[len] = '\0';
01109 StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
01110 if ((conv & SLF_ALLOW_CONTROL) != 0) {
01111 settings = settings | SVS_ALLOW_CONTROL_CODE;
01112 if (IsSavegameVersionBefore(169)) {
01113 str_fix_scc_encoded((char *)ptr, (char *)ptr + len);
01114 }
01115 }
01116 if ((conv & SLF_ALLOW_NEWLINE) != 0) {
01117 settings = settings | SVS_ALLOW_NEWLINE;
01118 }
01119 str_validate((char *)ptr, (char *)ptr + len, settings);
01120 break;
01121 }
01122 case SLA_PTRS: break;
01123 case SLA_NULL: break;
01124 default: NOT_REACHED();
01125 }
01126 }
01127
01133 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01134 {
01135 return SlCalcConvFileLen(conv) * length;
01136 }
01137
01144 void SlArray(void *array, size_t length, VarType conv)
01145 {
01146 if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01147
01148
01149 if (_sl.need_length != NL_NONE) {
01150 SlSetLength(SlCalcArrayLen(length, conv));
01151
01152 if (_sl.need_length == NL_CALCLENGTH) return;
01153 }
01154
01155
01156
01157 if (_sl.action != SLA_SAVE && _sl_version == 0) {
01158
01159 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01160 conv == SLE_INT32 || conv == SLE_UINT32) {
01161 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01162 return;
01163 }
01164
01165 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01166 for (uint i = 0; i < length; i++) {
01167 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01168 }
01169 return;
01170 }
01171 }
01172
01173
01174
01175 if (conv == SLE_INT8 || conv == SLE_UINT8) {
01176 SlCopyBytes(array, length);
01177 } else {
01178 byte *a = (byte*)array;
01179 byte mem_size = SlCalcConvMemLen(conv);
01180
01181 for (; length != 0; length --) {
01182 SlSaveLoadConv(a, conv);
01183 a += mem_size;
01184 }
01185 }
01186 }
01187
01188
01199 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01200 {
01201 assert(_sl.action == SLA_SAVE);
01202
01203 if (obj == NULL) return 0;
01204
01205 switch (rt) {
01206 case REF_VEHICLE_OLD:
01207 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01208 case REF_STATION: return ((const Station*)obj)->index + 1;
01209 case REF_TOWN: return ((const Town*)obj)->index + 1;
01210 case REF_ORDER: return ((const Order*)obj)->index + 1;
01211 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01212 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01213 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01214 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01215 case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
01216 default: NOT_REACHED();
01217 }
01218 }
01219
01230 static void *IntToReference(size_t index, SLRefType rt)
01231 {
01232 assert_compile(sizeof(size_t) <= sizeof(void *));
01233
01234 assert(_sl.action == SLA_PTRS);
01235
01236
01237
01238 if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01239 rt = REF_VEHICLE;
01240 }
01241
01242
01243 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01244
01245
01246
01247 if (rt != REF_VEHICLE_OLD) index--;
01248
01249 switch (rt) {
01250 case REF_ORDERLIST:
01251 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01252 SlErrorCorrupt("Referencing invalid OrderList");
01253
01254 case REF_ORDER:
01255 if (Order::IsValidID(index)) return Order::Get(index);
01256
01257 if (IsSavegameVersionBefore(5, 2)) return NULL;
01258 SlErrorCorrupt("Referencing invalid Order");
01259
01260 case REF_VEHICLE_OLD:
01261 case REF_VEHICLE:
01262 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01263 SlErrorCorrupt("Referencing invalid Vehicle");
01264
01265 case REF_STATION:
01266 if (Station::IsValidID(index)) return Station::Get(index);
01267 SlErrorCorrupt("Referencing invalid Station");
01268
01269 case REF_TOWN:
01270 if (Town::IsValidID(index)) return Town::Get(index);
01271 SlErrorCorrupt("Referencing invalid Town");
01272
01273 case REF_ROADSTOPS:
01274 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01275 SlErrorCorrupt("Referencing invalid RoadStop");
01276
01277 case REF_ENGINE_RENEWS:
01278 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01279 SlErrorCorrupt("Referencing invalid EngineRenew");
01280
01281 case REF_CARGO_PACKET:
01282 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01283 SlErrorCorrupt("Referencing invalid CargoPacket");
01284
01285 case REF_STORAGE:
01286 if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index);
01287 SlErrorCorrupt("Referencing invalid PersistentStorage");
01288
01289 default: NOT_REACHED();
01290 }
01291 }
01292
01297 static inline size_t SlCalcListLen(const void *list)
01298 {
01299 const std::list<void *> *l = (const std::list<void *> *) list;
01300
01301 int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01302
01303
01304 return l->size() * type_size + type_size;
01305 }
01306
01307
01313 static void SlList(void *list, SLRefType conv)
01314 {
01315
01316 if (_sl.need_length != NL_NONE) {
01317 SlSetLength(SlCalcListLen(list));
01318
01319 if (_sl.need_length == NL_CALCLENGTH) return;
01320 }
01321
01322 typedef std::list<void *> PtrList;
01323 PtrList *l = (PtrList *)list;
01324
01325 switch (_sl.action) {
01326 case SLA_SAVE: {
01327 SlWriteUint32((uint32)l->size());
01328
01329 PtrList::iterator iter;
01330 for (iter = l->begin(); iter != l->end(); ++iter) {
01331 void *ptr = *iter;
01332 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01333 }
01334 break;
01335 }
01336 case SLA_LOAD_CHECK:
01337 case SLA_LOAD: {
01338 size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01339
01340
01341 for (size_t i = 0; i < length; i++) {
01342 size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01343 l->push_back((void *)data);
01344 }
01345 break;
01346 }
01347 case SLA_PTRS: {
01348 PtrList temp = *l;
01349
01350 l->clear();
01351 PtrList::iterator iter;
01352 for (iter = temp.begin(); iter != temp.end(); ++iter) {
01353 void *ptr = IntToReference((size_t)*iter, conv);
01354 l->push_back(ptr);
01355 }
01356 break;
01357 }
01358 case SLA_NULL:
01359 l->clear();
01360 break;
01361 default: NOT_REACHED();
01362 }
01363 }
01364
01365
01367 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01368 {
01369 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01370 if (sld->conv & SLF_NOT_IN_SAVE) return false;
01371
01372 return true;
01373 }
01374
01380 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01381 {
01382 if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01383 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01384 return true;
01385 }
01386
01387 return false;
01388 }
01389
01396 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01397 {
01398 size_t length = 0;
01399
01400
01401 for (; sld->cmd != SL_END; sld++) {
01402 length += SlCalcObjMemberLength(object, sld);
01403 }
01404 return length;
01405 }
01406
01407 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01408 {
01409 assert(_sl.action == SLA_SAVE);
01410
01411 switch (sld->cmd) {
01412 case SL_VAR:
01413 case SL_REF:
01414 case SL_ARR:
01415 case SL_STR:
01416 case SL_LST:
01417
01418 if (!SlIsObjectValidInSavegame(sld)) break;
01419
01420 switch (sld->cmd) {
01421 case SL_VAR: return SlCalcConvFileLen(sld->conv);
01422 case SL_REF: return SlCalcRefLen();
01423 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01424 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01425 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01426 default: NOT_REACHED();
01427 }
01428 break;
01429 case SL_WRITEBYTE: return 1;
01430 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01431 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01432 default: NOT_REACHED();
01433 }
01434 return 0;
01435 }
01436
01437
01438 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01439 {
01440 VarType conv = GB(sld->conv, 0, 8);
01441 switch (sld->cmd) {
01442 case SL_VAR:
01443 case SL_REF:
01444 case SL_ARR:
01445 case SL_STR:
01446 case SL_LST:
01447
01448 if (!SlIsObjectValidInSavegame(sld)) return false;
01449 if (SlSkipVariableOnLoad(sld)) return false;
01450
01451 switch (sld->cmd) {
01452 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01453 case SL_REF:
01454 switch (_sl.action) {
01455 case SLA_SAVE:
01456 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01457 break;
01458 case SLA_LOAD_CHECK:
01459 case SLA_LOAD:
01460 *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01461 break;
01462 case SLA_PTRS:
01463 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01464 break;
01465 case SLA_NULL:
01466 *(void **)ptr = NULL;
01467 break;
01468 default: NOT_REACHED();
01469 }
01470 break;
01471 case SL_ARR: SlArray(ptr, sld->length, conv); break;
01472 case SL_STR: SlString(ptr, sld->length, sld->conv); break;
01473 case SL_LST: SlList(ptr, (SLRefType)conv); break;
01474 default: NOT_REACHED();
01475 }
01476 break;
01477
01478
01479
01480
01481
01482
01483 case SL_WRITEBYTE:
01484 switch (_sl.action) {
01485 case SLA_SAVE: SlWriteByte(sld->version_to); break;
01486 case SLA_LOAD_CHECK:
01487 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01488 case SLA_PTRS: break;
01489 case SLA_NULL: break;
01490 default: NOT_REACHED();
01491 }
01492 break;
01493
01494
01495 case SL_VEH_INCLUDE:
01496 SlObject(ptr, GetVehicleDescription(VEH_END));
01497 break;
01498
01499 case SL_ST_INCLUDE:
01500 SlObject(ptr, GetBaseStationDescription());
01501 break;
01502
01503 default: NOT_REACHED();
01504 }
01505 return true;
01506 }
01507
01513 void SlObject(void *object, const SaveLoad *sld)
01514 {
01515
01516 if (_sl.need_length != NL_NONE) {
01517 SlSetLength(SlCalcObjLength(object, sld));
01518 if (_sl.need_length == NL_CALCLENGTH) return;
01519 }
01520
01521 for (; sld->cmd != SL_END; sld++) {
01522 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01523 SlObjectMember(ptr, sld);
01524 }
01525 }
01526
01531 void SlGlobList(const SaveLoadGlobVarList *sldg)
01532 {
01533 SlObject(NULL, (const SaveLoad*)sldg);
01534 }
01535
01541 void SlAutolength(AutolengthProc *proc, void *arg)
01542 {
01543 size_t offs;
01544
01545 assert(_sl.action == SLA_SAVE);
01546
01547
01548 _sl.need_length = NL_CALCLENGTH;
01549 _sl.obj_len = 0;
01550 proc(arg);
01551
01552
01553 _sl.need_length = NL_WANTLENGTH;
01554 SlSetLength(_sl.obj_len);
01555
01556 offs = _sl.dumper->GetSize() + _sl.obj_len;
01557
01558
01559 proc(arg);
01560
01561 if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01562 }
01563
01568 static void SlLoadChunk(const ChunkHandler *ch)
01569 {
01570 byte m = SlReadByte();
01571 size_t len;
01572 size_t endoffs;
01573
01574 _sl.block_mode = m;
01575 _sl.obj_len = 0;
01576
01577 switch (m) {
01578 case CH_ARRAY:
01579 _sl.array_index = 0;
01580 ch->load_proc();
01581 break;
01582 case CH_SPARSE_ARRAY:
01583 ch->load_proc();
01584 break;
01585 default:
01586 if ((m & 0xF) == CH_RIFF) {
01587
01588 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01589 len += SlReadUint16();
01590 _sl.obj_len = len;
01591 endoffs = _sl.reader->GetSize() + len;
01592 ch->load_proc();
01593 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01594 } else {
01595 SlErrorCorrupt("Invalid chunk type");
01596 }
01597 break;
01598 }
01599 }
01600
01606 static void SlLoadCheckChunk(const ChunkHandler *ch)
01607 {
01608 byte m = SlReadByte();
01609 size_t len;
01610 size_t endoffs;
01611
01612 _sl.block_mode = m;
01613 _sl.obj_len = 0;
01614
01615 switch (m) {
01616 case CH_ARRAY:
01617 _sl.array_index = 0;
01618 if (ch->load_check_proc) {
01619 ch->load_check_proc();
01620 } else {
01621 SlSkipArray();
01622 }
01623 break;
01624 case CH_SPARSE_ARRAY:
01625 if (ch->load_check_proc) {
01626 ch->load_check_proc();
01627 } else {
01628 SlSkipArray();
01629 }
01630 break;
01631 default:
01632 if ((m & 0xF) == CH_RIFF) {
01633
01634 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01635 len += SlReadUint16();
01636 _sl.obj_len = len;
01637 endoffs = _sl.reader->GetSize() + len;
01638 if (ch->load_check_proc) {
01639 ch->load_check_proc();
01640 } else {
01641 SlSkipBytes(len);
01642 }
01643 if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01644 } else {
01645 SlErrorCorrupt("Invalid chunk type");
01646 }
01647 break;
01648 }
01649 }
01650
01655 static ChunkSaveLoadProc *_stub_save_proc;
01656
01662 static inline void SlStubSaveProc2(void *arg)
01663 {
01664 _stub_save_proc();
01665 }
01666
01672 static void SlStubSaveProc()
01673 {
01674 SlAutolength(SlStubSaveProc2, NULL);
01675 }
01676
01682 static void SlSaveChunk(const ChunkHandler *ch)
01683 {
01684 ChunkSaveLoadProc *proc = ch->save_proc;
01685
01686
01687 if (proc == NULL) return;
01688
01689 SlWriteUint32(ch->id);
01690 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01691
01692 if (ch->flags & CH_AUTO_LENGTH) {
01693
01694 _stub_save_proc = proc;
01695 proc = SlStubSaveProc;
01696 }
01697
01698 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01699 switch (ch->flags & CH_TYPE_MASK) {
01700 case CH_RIFF:
01701 _sl.need_length = NL_WANTLENGTH;
01702 proc();
01703 break;
01704 case CH_ARRAY:
01705 _sl.last_array_index = 0;
01706 SlWriteByte(CH_ARRAY);
01707 proc();
01708 SlWriteArrayLength(0);
01709 break;
01710 case CH_SPARSE_ARRAY:
01711 SlWriteByte(CH_SPARSE_ARRAY);
01712 proc();
01713 SlWriteArrayLength(0);
01714 break;
01715 default: NOT_REACHED();
01716 }
01717 }
01718
01720 static void SlSaveChunks()
01721 {
01722 FOR_ALL_CHUNK_HANDLERS(ch) {
01723 SlSaveChunk(ch);
01724 }
01725
01726
01727 SlWriteUint32(0);
01728 }
01729
01736 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01737 {
01738 FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01739 return NULL;
01740 }
01741
01743 static void SlLoadChunks()
01744 {
01745 uint32 id;
01746 const ChunkHandler *ch;
01747
01748 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01749 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01750
01751 ch = SlFindChunkHandler(id);
01752 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01753 SlLoadChunk(ch);
01754 }
01755 }
01756
01758 static void SlLoadCheckChunks()
01759 {
01760 uint32 id;
01761 const ChunkHandler *ch;
01762
01763 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01764 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01765
01766 ch = SlFindChunkHandler(id);
01767 if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01768 SlLoadCheckChunk(ch);
01769 }
01770 }
01771
01773 static void SlFixPointers()
01774 {
01775 _sl.action = SLA_PTRS;
01776
01777 DEBUG(sl, 1, "Fixing pointers");
01778
01779 FOR_ALL_CHUNK_HANDLERS(ch) {
01780 if (ch->ptrs_proc != NULL) {
01781 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01782 ch->ptrs_proc();
01783 }
01784 }
01785
01786 DEBUG(sl, 1, "All pointers fixed");
01787
01788 assert(_sl.action == SLA_PTRS);
01789 }
01790
01791
01793 struct FileReader : LoadFilter {
01794 FILE *file;
01795 long begin;
01796
01801 FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01802 {
01803 }
01804
01806 ~FileReader()
01807 {
01808 if (this->file != NULL) fclose(this->file);
01809 this->file = NULL;
01810
01811
01812 _sl.sf = NULL;
01813 }
01814
01815 size_t Read(byte *buf, size_t size)
01816 {
01817
01818 if (this->file == NULL) return 0;
01819
01820 return fread(buf, 1, size, this->file);
01821 }
01822
01823 void Reset()
01824 {
01825 clearerr(this->file);
01826 fseek(this->file, this->begin, SEEK_SET);
01827 }
01828 };
01829
01831 struct FileWriter : SaveFilter {
01832 FILE *file;
01833
01838 FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01839 {
01840 }
01841
01843 ~FileWriter()
01844 {
01845 this->Finish();
01846
01847
01848 _sl.sf = NULL;
01849 }
01850
01851 void Write(byte *buf, size_t size)
01852 {
01853
01854 if (this->file == NULL) return;
01855
01856 if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01857 }
01858
01859 void Finish()
01860 {
01861 if (this->file != NULL) fclose(this->file);
01862 this->file = NULL;
01863 }
01864 };
01865
01866
01867
01868
01869
01870 #ifdef WITH_LZO
01871 #include <lzo/lzo1x.h>
01872
01874 static const uint LZO_BUFFER_SIZE = 8192;
01875
01877 struct LZOLoadFilter : LoadFilter {
01882 LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01883 {
01884 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01885 }
01886
01887 size_t Read(byte *buf, size_t ssize)
01888 {
01889 assert(ssize >= LZO_BUFFER_SIZE);
01890
01891
01892 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01893 uint32 tmp[2];
01894 uint32 size;
01895 lzo_uint len;
01896
01897
01898 if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01899
01900
01901 ((uint32*)out)[0] = size = tmp[1];
01902
01903 if (_sl_version != 0) {
01904 tmp[0] = TO_BE32(tmp[0]);
01905 size = TO_BE32(size);
01906 }
01907
01908 if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01909
01910
01911 if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01912
01913
01914 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01915
01916
01917 lzo1x_decompress(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01918 return len;
01919 }
01920 };
01921
01923 struct LZOSaveFilter : SaveFilter {
01929 LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01930 {
01931 if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01932 }
01933
01934 void Write(byte *buf, size_t size)
01935 {
01936 const lzo_bytep in = buf;
01937
01938 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01939 byte wrkmem[LZO1X_1_MEM_COMPRESS];
01940 lzo_uint outlen;
01941
01942 do {
01943
01944 lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01945 lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01946 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01947 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01948 this->chain->Write(out, outlen + sizeof(uint32) * 2);
01949
01950
01951 size -= len;
01952 in += len;
01953 } while (size > 0);
01954 }
01955 };
01956
01957 #endif
01958
01959
01960
01961
01962
01964 struct NoCompLoadFilter : LoadFilter {
01969 NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01970 {
01971 }
01972
01973 size_t Read(byte *buf, size_t size)
01974 {
01975 return this->chain->Read(buf, size);
01976 }
01977 };
01978
01980 struct NoCompSaveFilter : SaveFilter {
01986 NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01987 {
01988 }
01989
01990 void Write(byte *buf, size_t size)
01991 {
01992 this->chain->Write(buf, size);
01993 }
01994 };
01995
01996
01997
01998
01999
02000 #if defined(WITH_ZLIB)
02001 #include <zlib.h>
02002
02004 struct ZlibLoadFilter : LoadFilter {
02005 z_stream z;
02006 byte fread_buf[MEMORY_CHUNK_SIZE];
02007
02012 ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
02013 {
02014 memset(&this->z, 0, sizeof(this->z));
02015 if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02016 }
02017
02019 ~ZlibLoadFilter()
02020 {
02021 inflateEnd(&this->z);
02022 }
02023
02024 size_t Read(byte *buf, size_t size)
02025 {
02026 this->z.next_out = buf;
02027 this->z.avail_out = (uint)size;
02028
02029 do {
02030
02031 if (this->z.avail_in == 0) {
02032 this->z.next_in = this->fread_buf;
02033 this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02034 }
02035
02036
02037 int r = inflate(&this->z, 0);
02038 if (r == Z_STREAM_END) break;
02039
02040 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
02041 } while (this->z.avail_out != 0);
02042
02043 return size - this->z.avail_out;
02044 }
02045 };
02046
02048 struct ZlibSaveFilter : SaveFilter {
02049 z_stream z;
02050
02056 ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02057 {
02058 memset(&this->z, 0, sizeof(this->z));
02059 if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02060 }
02061
02063 ~ZlibSaveFilter()
02064 {
02065 deflateEnd(&this->z);
02066 }
02067
02074 void WriteLoop(byte *p, size_t len, int mode)
02075 {
02076 byte buf[MEMORY_CHUNK_SIZE];
02077 uint n;
02078 this->z.next_in = p;
02079 this->z.avail_in = (uInt)len;
02080 do {
02081 this->z.next_out = buf;
02082 this->z.avail_out = sizeof(buf);
02083
02091 int r = deflate(&this->z, mode);
02092
02093
02094 if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02095 this->chain->Write(buf, n);
02096 }
02097 if (r == Z_STREAM_END) break;
02098
02099 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02100 } while (this->z.avail_in || !this->z.avail_out);
02101 }
02102
02103 void Write(byte *buf, size_t size)
02104 {
02105 this->WriteLoop(buf, size, 0);
02106 }
02107
02108 void Finish()
02109 {
02110 this->WriteLoop(NULL, 0, Z_FINISH);
02111 this->chain->Finish();
02112 }
02113 };
02114
02115 #endif
02116
02117
02118
02119
02120
02121 #if defined(WITH_LZMA)
02122 #include <lzma.h>
02123
02130 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02131
02133 struct LZMALoadFilter : LoadFilter {
02134 lzma_stream lzma;
02135 byte fread_buf[MEMORY_CHUNK_SIZE];
02136
02141 LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02142 {
02143
02144 if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02145 }
02146
02148 ~LZMALoadFilter()
02149 {
02150 lzma_end(&this->lzma);
02151 }
02152
02153 size_t Read(byte *buf, size_t size)
02154 {
02155 this->lzma.next_out = buf;
02156 this->lzma.avail_out = size;
02157
02158 do {
02159
02160 if (this->lzma.avail_in == 0) {
02161 this->lzma.next_in = this->fread_buf;
02162 this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02163 }
02164
02165
02166 lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02167 if (r == LZMA_STREAM_END) break;
02168 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02169 } while (this->lzma.avail_out != 0);
02170
02171 return size - this->lzma.avail_out;
02172 }
02173 };
02174
02176 struct LZMASaveFilter : SaveFilter {
02177 lzma_stream lzma;
02178
02184 LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02185 {
02186 if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02187 }
02188
02190 ~LZMASaveFilter()
02191 {
02192 lzma_end(&this->lzma);
02193 }
02194
02201 void WriteLoop(byte *p, size_t len, lzma_action action)
02202 {
02203 byte buf[MEMORY_CHUNK_SIZE];
02204 size_t n;
02205 this->lzma.next_in = p;
02206 this->lzma.avail_in = len;
02207 do {
02208 this->lzma.next_out = buf;
02209 this->lzma.avail_out = sizeof(buf);
02210
02211 lzma_ret r = lzma_code(&this->lzma, action);
02212
02213
02214 if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02215 this->chain->Write(buf, n);
02216 }
02217 if (r == LZMA_STREAM_END) break;
02218 if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02219 } while (this->lzma.avail_in || !this->lzma.avail_out);
02220 }
02221
02222 void Write(byte *buf, size_t size)
02223 {
02224 this->WriteLoop(buf, size, LZMA_RUN);
02225 }
02226
02227 void Finish()
02228 {
02229 this->WriteLoop(NULL, 0, LZMA_FINISH);
02230 this->chain->Finish();
02231 }
02232 };
02233
02234 #endif
02235
02236
02237
02238
02239
02241 struct SaveLoadFormat {
02242 const char *name;
02243 uint32 tag;
02244
02245 LoadFilter *(*init_load)(LoadFilter *chain);
02246 SaveFilter *(*init_write)(SaveFilter *chain, byte compression);
02247
02248 byte min_compression;
02249 byte default_compression;
02250 byte max_compression;
02251 };
02252
02254 static const SaveLoadFormat _saveload_formats[] = {
02255 #if defined(WITH_LZO)
02256
02257 {"lzo", TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>, CreateSaveFilter<LZOSaveFilter>, 0, 0, 0},
02258 #else
02259 {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0},
02260 #endif
02261
02262 {"none", TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02263 #if defined(WITH_ZLIB)
02264
02265
02266
02267 {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>, CreateSaveFilter<ZlibSaveFilter>, 0, 6, 9},
02268 #else
02269 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0},
02270 #endif
02271 #if defined(WITH_LZMA)
02272
02273
02274
02275
02276
02277 {"lzma", TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>, CreateSaveFilter<LZMASaveFilter>, 0, 2, 9},
02278 #else
02279 {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0},
02280 #endif
02281 };
02282
02290 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02291 {
02292 const SaveLoadFormat *def = lastof(_saveload_formats);
02293
02294
02295 while (!def->init_write) def--;
02296
02297 if (!StrEmpty(s)) {
02298
02299 char *complevel = strrchr(s, ':');
02300 if (complevel != NULL) *complevel = '\0';
02301
02302 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02303 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02304 *compression_level = slf->default_compression;
02305 if (complevel != NULL) {
02306
02307
02308
02309 *complevel = ':';
02310 complevel++;
02311
02312
02313 char *end;
02314 long level = strtol(complevel, &end, 10);
02315 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02316 SetDParamStr(0, complevel);
02317 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL);
02318 } else {
02319 *compression_level = level;
02320 }
02321 }
02322 return slf;
02323 }
02324 }
02325
02326 SetDParamStr(0, s);
02327 SetDParamStr(1, def->name);
02328 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL);
02329
02330
02331 if (complevel != NULL) *complevel = ':';
02332 }
02333 *compression_level = def->default_compression;
02334 return def;
02335 }
02336
02337
02338 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02339 extern bool AfterLoadGame();
02340 extern bool LoadOldSaveGame(const char *file);
02341
02345 static inline void ClearSaveLoadState()
02346 {
02347 delete _sl.dumper;
02348 _sl.dumper = NULL;
02349
02350 delete _sl.sf;
02351 _sl.sf = NULL;
02352
02353 delete _sl.reader;
02354 _sl.reader = NULL;
02355
02356 delete _sl.lf;
02357 _sl.lf = NULL;
02358 }
02359
02365 static void SaveFileStart()
02366 {
02367 _sl.ff_state = _fast_forward;
02368 _fast_forward = 0;
02369 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02370
02371 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02372 _sl.saveinprogress = true;
02373 }
02374
02376 static void SaveFileDone()
02377 {
02378 if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02379 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02380
02381 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02382 _sl.saveinprogress = false;
02383 }
02384
02386 void SetSaveLoadError(StringID str)
02387 {
02388 _sl.error_str = str;
02389 }
02390
02392 const char *GetSaveLoadErrorString()
02393 {
02394 SetDParam(0, _sl.error_str);
02395 SetDParamStr(1, _sl.extra_msg);
02396
02397 static char err_str[512];
02398 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02399 return err_str;
02400 }
02401
02403 static void SaveFileError()
02404 {
02405 SetDParamStr(0, GetSaveLoadErrorString());
02406 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02407 SaveFileDone();
02408 }
02409
02414 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02415 {
02416 try {
02417 byte compression;
02418 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02419
02420
02421 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02422 _sl.sf->Write((byte*)hdr, sizeof(hdr));
02423
02424 _sl.sf = fmt->init_write(_sl.sf, compression);
02425 _sl.dumper->Flush(_sl.sf);
02426
02427 ClearSaveLoadState();
02428
02429 if (threaded) SetAsyncSaveFinish(SaveFileDone);
02430
02431 return SL_OK;
02432 } catch (...) {
02433 ClearSaveLoadState();
02434
02435 AsyncSaveFinishProc asfp = SaveFileDone;
02436
02437
02438
02439 if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
02440
02441 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02442 asfp = SaveFileError;
02443 }
02444
02445 if (threaded) {
02446 SetAsyncSaveFinish(asfp);
02447 } else {
02448 asfp();
02449 }
02450 return SL_ERROR;
02451 }
02452 }
02453
02455 static void SaveFileToDiskThread(void *arg)
02456 {
02457 SaveFileToDisk(true);
02458 }
02459
02460 void WaitTillSaved()
02461 {
02462 if (_save_thread == NULL) return;
02463
02464 _save_thread->Join();
02465 delete _save_thread;
02466 _save_thread = NULL;
02467
02468
02469 ProcessAsyncSaveFinish();
02470 }
02471
02480 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02481 {
02482 assert(!_sl.saveinprogress);
02483
02484 _sl.dumper = new MemoryDumper();
02485 _sl.sf = writer;
02486
02487 _sl_version = SAVEGAME_VERSION;
02488
02489 SaveViewportBeforeSaveGame();
02490 SlSaveChunks();
02491
02492 SaveFileStart();
02493 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02494 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02495
02496 SaveOrLoadResult result = SaveFileToDisk(false);
02497 SaveFileDone();
02498
02499 return result;
02500 }
02501
02502 return SL_OK;
02503 }
02504
02511 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02512 {
02513 try {
02514 _sl.action = SLA_SAVE;
02515 return DoSave(writer, threaded);
02516 } catch (...) {
02517 ClearSaveLoadState();
02518 return SL_ERROR;
02519 }
02520 }
02521
02528 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02529 {
02530 _sl.lf = reader;
02531
02532 if (load_check) {
02533
02534 _load_check_data.Clear();
02535
02536 _load_check_data.checkable = true;
02537 }
02538
02539 uint32 hdr[2];
02540 if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02541
02542
02543 const SaveLoadFormat *fmt = _saveload_formats;
02544 for (;;) {
02545
02546 if (fmt == endof(_saveload_formats)) {
02547 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02548 _sl.lf->Reset();
02549 _sl_version = 0;
02550 _sl_minor_version = 0;
02551
02552
02553 fmt = _saveload_formats;
02554 for (;;) {
02555 if (fmt == endof(_saveload_formats)) {
02556
02557 NOT_REACHED();
02558 }
02559 if (fmt->tag == TO_BE32X('OTTD')) break;
02560 fmt++;
02561 }
02562 break;
02563 }
02564
02565 if (fmt->tag == hdr[0]) {
02566
02567 _sl_version = TO_BE32(hdr[1]) >> 16;
02568
02569
02570
02571 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02572
02573 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02574
02575
02576 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02577 break;
02578 }
02579
02580 fmt++;
02581 }
02582
02583
02584 if (fmt->init_load == NULL) {
02585 char err_str[64];
02586 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02587 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02588 }
02589
02590 _sl.lf = fmt->init_load(_sl.lf);
02591 _sl.reader = new ReadBuffer(_sl.lf);
02592 _next_offs = 0;
02593
02594 if (!load_check) {
02595
02596
02597
02598 InitializeGame(256, 256, true, true);
02599
02600 if (_sl_version < SAVEGAME_VERSION_H2H)
02601 _settings_game.game_creation.head_to_head_areas = 1;
02602
02603 GamelogReset();
02604
02605 if (IsSavegameVersionBefore(4)) {
02606
02607
02608
02609
02610
02611
02612
02613
02614
02615
02616
02617
02618
02619
02620
02621
02622
02623
02624
02625
02626
02627 ClearGRFConfigList(&_grfconfig);
02628 }
02629 }
02630
02631 if (load_check) {
02632
02633
02634 SlLoadCheckChunks();
02635 } else {
02636
02637 SlLoadChunks();
02638 SlFixPointers();
02639 }
02640
02641 ClearSaveLoadState();
02642
02643 _savegame_type = SGT_OTTD;
02644
02645 if (load_check) {
02646
02647 _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02648 } else {
02649 GamelogStartAction(GLAT_LOAD);
02650
02651
02652
02653 if (!AfterLoadGame()) {
02654 GamelogStopAction();
02655 return SL_REINIT;
02656 }
02657
02658 GamelogStopAction();
02659 }
02660
02661 return SL_OK;
02662 }
02663
02669 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02670 {
02671 try {
02672 _sl.action = SLA_LOAD;
02673 return DoLoad(reader, false);
02674 } catch (...) {
02675 ClearSaveLoadState();
02676 return SL_REINIT;
02677 }
02678 }
02679
02689 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02690 {
02691
02692 if (_sl.saveinprogress && mode == SL_SAVE && threaded) {
02693
02694 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02695 return SL_OK;
02696 }
02697 WaitTillSaved();
02698
02699
02700 if (mode == SL_OLD_LOAD) {
02701 InitializeGame(256, 256, true, true);
02702
02703
02704
02705
02706
02707 ClearGRFConfigList(&_grfconfig);
02708 GamelogReset();
02709 if (!LoadOldSaveGame(filename)) return SL_REINIT;
02710 _sl_version = 0;
02711 _sl_minor_version = 0;
02712 GamelogStartAction(GLAT_LOAD);
02713 if (!AfterLoadGame()) {
02714 GamelogStopAction();
02715 return SL_REINIT;
02716 }
02717 GamelogStopAction();
02718 return SL_OK;
02719 }
02720
02721 switch (mode) {
02722 case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02723 case SL_LOAD: _sl.action = SLA_LOAD; break;
02724 case SL_SAVE: _sl.action = SLA_SAVE; break;
02725 default: NOT_REACHED();
02726 }
02727
02728 try {
02729 FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02730
02731
02732 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02733 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02734 if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
02735
02736 if (fh == NULL) {
02737 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02738 }
02739
02740 if (mode == SL_SAVE) {
02741 DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02742 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02743
02744 return DoSave(new FileWriter(fh), threaded);
02745 }
02746
02747
02748 assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02749 DEBUG(desync, 1, "load: %s", filename);
02750 return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02751 } catch (...) {
02752 ClearSaveLoadState();
02753
02754
02755 if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02756
02757
02758 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02759 }
02760 }
02761
02763 void DoExitSave()
02764 {
02765 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02766 }
02767
02773 void GenerateDefaultSaveName(char *buf, const char *last)
02774 {
02775
02776
02777
02778 CompanyID cid = _local_company;
02779 if (!Company::IsValidID(cid)) {
02780 const Company *c;
02781 FOR_ALL_COMPANIES(c) {
02782 cid = c->index;
02783 break;
02784 }
02785 }
02786
02787 SetDParam(0, cid);
02788
02789
02790 switch (_settings_client.gui.date_format_in_default_names) {
02791 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02792 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02793 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02794 default: NOT_REACHED();
02795 }
02796 SetDParam(2, _date);
02797
02798
02799 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02800 SanitizeFilename(buf);
02801 }
02802
02803 #if 0
02804
02810 int GetSavegameType(char *file)
02811 {
02812 const SaveLoadFormat *fmt;
02813 uint32 hdr;
02814 FILE *f;
02815 int mode = SL_OLD_LOAD;
02816
02817 f = fopen(file, "rb");
02818 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02819 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02820 mode = SL_LOAD;
02821 } else {
02822
02823 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02824 if (fmt->tag == hdr) {
02825 mode = SL_LOAD;
02826 break;
02827 }
02828 }
02829 }
02830
02831 fclose(f);
02832 return mode;
02833 }
02834 #endif