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