00001
00002
00003
00004
00005
00006
00007
00008
00009
00023 #include "../stdafx.h"
00024 #include "../openttd.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 "../variables.h"
00031 #include "../window_func.h"
00032 #include "../strings_func.h"
00033 #include "../gfx_func.h"
00034 #include "../core/endian_func.hpp"
00035 #include "../vehicle_base.h"
00036 #include "../company_func.h"
00037 #include "../date_func.h"
00038 #include "../autoreplace_base.h"
00039 #include "../roadstop_base.h"
00040 #include "../statusbar_gui.h"
00041 #include "../fileio_func.h"
00042 #include "../gamelog.h"
00043 #include "../string_func.h"
00044 #include "../engine_base.h"
00045
00046 #include "table/strings.h"
00047
00048 #include "saveload_internal.h"
00049
00050 extern const uint16 SAVEGAME_VERSION = 132;
00051
00052 SavegameType _savegame_type;
00053
00054 uint32 _ttdp_version;
00055 uint16 _sl_version;
00056 byte _sl_minor_version;
00057 char _savegame_format[8];
00058
00059 typedef void WriterProc(size_t len);
00060 typedef size_t ReaderProc();
00061
00063 enum SaveLoadAction {
00064 SLA_LOAD,
00065 SLA_SAVE,
00066 SLA_PTRS,
00067 };
00068
00069 enum NeedLength {
00070 NL_NONE = 0,
00071 NL_WANTLENGTH = 1,
00072 NL_CALCLENGTH = 2,
00073 };
00074
00076 struct SaveLoadParams {
00077 SaveLoadAction action;
00078 NeedLength need_length;
00079 byte block_mode;
00080 bool error;
00081
00082 size_t obj_len;
00083 int array_index, last_array_index;
00084
00085 size_t offs_base;
00086
00087 WriterProc *write_bytes;
00088 ReaderProc *read_bytes;
00089
00090 const ChunkHandler * const *chs;
00091
00092
00093
00094 byte *bufp, *bufe;
00095
00096
00097 byte *buf;
00098 byte *buf_ori;
00099 uint bufsize;
00100 FILE *fh;
00101
00102 void (*excpt_uninit)();
00103 StringID error_str;
00104 char *extra_msg;
00105 };
00106
00107 static SaveLoadParams _sl;
00108
00112 static void NORETURN SlError(StringID string, const char *extra_msg = NULL)
00113 {
00114 _sl.error_str = string;
00115 free(_sl.extra_msg);
00116 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00117 throw std::exception();
00118 }
00119
00120 typedef void (*AsyncSaveFinishProc)();
00121 static AsyncSaveFinishProc _async_save_finish = NULL;
00122 static ThreadObject *_save_thread;
00123
00127 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00128 {
00129 if (_exit_game) return;
00130 while (_async_save_finish != NULL) CSleep(10);
00131
00132 _async_save_finish = proc;
00133 }
00134
00138 void ProcessAsyncSaveFinish()
00139 {
00140 if (_async_save_finish == NULL) return;
00141
00142 _async_save_finish();
00143
00144 _async_save_finish = NULL;
00145
00146 if (_save_thread != NULL) {
00147 _save_thread->Join();
00148 delete _save_thread;
00149 _save_thread = NULL;
00150 }
00151 }
00152
00156 static void SlReadFill()
00157 {
00158 size_t len = _sl.read_bytes();
00159 if (len == 0) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected end of chunk");
00160
00161 _sl.bufp = _sl.buf;
00162 _sl.bufe = _sl.buf + len;
00163 _sl.offs_base += len;
00164 }
00165
00166 static inline size_t SlGetOffs() {return _sl.offs_base - (_sl.bufe - _sl.bufp);}
00167 static inline uint SlReadArrayLength();
00168
00173 static inline uint SlCalcConvMemLen(VarType conv)
00174 {
00175 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00176 byte length = GB(conv, 4, 4);
00177
00178 switch (length << 4) {
00179 case SLE_VAR_STRB:
00180 case SLE_VAR_STRBQ:
00181 case SLE_VAR_STR:
00182 case SLE_VAR_STRQ:
00183 return SlReadArrayLength();
00184
00185 default:
00186 assert(length < lengthof(conv_mem_size));
00187 return conv_mem_size[length];
00188 }
00189 }
00190
00195 static inline byte SlCalcConvFileLen(VarType conv)
00196 {
00197 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00198 byte length = GB(conv, 0, 4);
00199 assert(length < lengthof(conv_file_size));
00200 return conv_file_size[length];
00201 }
00202
00204 static inline size_t SlCalcRefLen() {return CheckSavegameVersion(69) ? 2 : 4;}
00205
00210 static void SlWriteFill()
00211 {
00212
00213 if (_sl.bufp != NULL) {
00214 uint len = _sl.bufp - _sl.buf;
00215 _sl.offs_base += len;
00216 if (len) _sl.write_bytes(len);
00217 }
00218
00219
00220
00221 _sl.bufp = _sl.buf;
00222 _sl.bufe = _sl.buf + _sl.bufsize;
00223 }
00224
00229 static inline byte SlReadByteInternal()
00230 {
00231 if (_sl.bufp == _sl.bufe) SlReadFill();
00232 return *_sl.bufp++;
00233 }
00234
00236 byte SlReadByte() {return SlReadByteInternal();}
00237
00242 static inline void SlWriteByteInternal(byte b)
00243 {
00244 if (_sl.bufp == _sl.bufe) SlWriteFill();
00245 *_sl.bufp++ = b;
00246 }
00247
00249 void SlWriteByte(byte b) {SlWriteByteInternal(b);}
00250
00251 static inline int SlReadUint16()
00252 {
00253 int x = SlReadByte() << 8;
00254 return x | SlReadByte();
00255 }
00256
00257 static inline uint32 SlReadUint32()
00258 {
00259 uint32 x = SlReadUint16() << 16;
00260 return x | SlReadUint16();
00261 }
00262
00263 static inline uint64 SlReadUint64()
00264 {
00265 uint32 x = SlReadUint32();
00266 uint32 y = SlReadUint32();
00267 return (uint64)x << 32 | y;
00268 }
00269
00270 static inline void SlWriteUint16(uint16 v)
00271 {
00272 SlWriteByte(GB(v, 8, 8));
00273 SlWriteByte(GB(v, 0, 8));
00274 }
00275
00276 static inline void SlWriteUint32(uint32 v)
00277 {
00278 SlWriteUint16(GB(v, 16, 16));
00279 SlWriteUint16(GB(v, 0, 16));
00280 }
00281
00282 static inline void SlWriteUint64(uint64 x)
00283 {
00284 SlWriteUint32((uint32)(x >> 32));
00285 SlWriteUint32((uint32)x);
00286 }
00287
00297 static uint SlReadSimpleGamma()
00298 {
00299 uint i = SlReadByte();
00300 if (HasBit(i, 7)) {
00301 i &= ~0x80;
00302 if (HasBit(i, 6)) {
00303 i &= ~0x40;
00304 if (HasBit(i, 5)) {
00305 i &= ~0x20;
00306 if (HasBit(i, 4))
00307 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unsupported gamma");
00308 i = (i << 8) | SlReadByte();
00309 }
00310 i = (i << 8) | SlReadByte();
00311 }
00312 i = (i << 8) | SlReadByte();
00313 }
00314 return i;
00315 }
00316
00329 static void SlWriteSimpleGamma(size_t i)
00330 {
00331 if (i >= (1 << 7)) {
00332 if (i >= (1 << 14)) {
00333 if (i >= (1 << 21)) {
00334 assert(i < (1 << 28));
00335 SlWriteByte((byte)(0xE0 | (i >> 24)));
00336 SlWriteByte((byte)(i >> 16));
00337 } else {
00338 SlWriteByte((byte)(0xC0 | (i >> 16)));
00339 }
00340 SlWriteByte((byte)(i >> 8));
00341 } else {
00342 SlWriteByte((byte)(0x80 | (i >> 8)));
00343 }
00344 }
00345 SlWriteByte((byte)i);
00346 }
00347
00349 static inline uint SlGetGammaLength(size_t i)
00350 {
00351 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00352 }
00353
00354 static inline uint SlReadSparseIndex() {return SlReadSimpleGamma();}
00355 static inline void SlWriteSparseIndex(uint index) {SlWriteSimpleGamma(index);}
00356
00357 static inline uint SlReadArrayLength() {return SlReadSimpleGamma();}
00358 static inline void SlWriteArrayLength(size_t length) {SlWriteSimpleGamma(length);}
00359 static inline uint SlGetArrayLength(size_t length) {return SlGetGammaLength(length);}
00360
00361 void SlSetArrayIndex(uint index)
00362 {
00363 _sl.need_length = NL_WANTLENGTH;
00364 _sl.array_index = index;
00365 }
00366
00367 static size_t _next_offs;
00368
00373 int SlIterateArray()
00374 {
00375 int index;
00376
00377
00378
00379 if (_next_offs != 0 && SlGetOffs() != _next_offs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
00380
00381 while (true) {
00382 uint length = SlReadArrayLength();
00383 if (length == 0) {
00384 _next_offs = 0;
00385 return -1;
00386 }
00387
00388 _sl.obj_len = --length;
00389 _next_offs = SlGetOffs() + length;
00390
00391 switch (_sl.block_mode) {
00392 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00393 case CH_ARRAY: index = _sl.array_index++; break;
00394 default:
00395 DEBUG(sl, 0, "SlIterateArray error");
00396 return -1;
00397 }
00398
00399 if (length != 0) return index;
00400 }
00401 }
00402
00408 void SlSetLength(size_t length)
00409 {
00410 assert(_sl.action == SLA_SAVE);
00411
00412 switch (_sl.need_length) {
00413 case NL_WANTLENGTH:
00414 _sl.need_length = NL_NONE;
00415 switch (_sl.block_mode) {
00416 case CH_RIFF:
00417
00418
00419
00420 assert(length < (1 << 28));
00421 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00422 break;
00423 case CH_ARRAY:
00424 assert(_sl.last_array_index <= _sl.array_index);
00425 while (++_sl.last_array_index <= _sl.array_index)
00426 SlWriteArrayLength(1);
00427 SlWriteArrayLength(length + 1);
00428 break;
00429 case CH_SPARSE_ARRAY:
00430 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00431 SlWriteSparseIndex(_sl.array_index);
00432 break;
00433 default: NOT_REACHED();
00434 }
00435 break;
00436
00437 case NL_CALCLENGTH:
00438 _sl.obj_len += (int)length;
00439 break;
00440
00441 default: NOT_REACHED();
00442 }
00443 }
00444
00451 static void SlCopyBytes(void *ptr, size_t length)
00452 {
00453 byte *p = (byte *)ptr;
00454
00455 switch (_sl.action) {
00456 case SLA_LOAD:
00457 for (; length != 0; length--) { *p++ = SlReadByteInternal(); }
00458 break;
00459 case SLA_SAVE:
00460 for (; length != 0; length--) { SlWriteByteInternal(*p++); }
00461 break;
00462 default: NOT_REACHED();
00463 }
00464 }
00465
00470 static inline void SlSkipBytes(size_t length)
00471 {
00472 for (; length != 0; length--) SlReadByte();
00473 }
00474
00475
00476 size_t SlGetFieldLength() {return _sl.obj_len;}
00477
00483 int64 ReadValue(const void *ptr, VarType conv)
00484 {
00485 switch (GetVarMemType(conv)) {
00486 case SLE_VAR_BL: return (*(bool *)ptr != 0);
00487 case SLE_VAR_I8: return *(int8 *)ptr;
00488 case SLE_VAR_U8: return *(byte *)ptr;
00489 case SLE_VAR_I16: return *(int16 *)ptr;
00490 case SLE_VAR_U16: return *(uint16*)ptr;
00491 case SLE_VAR_I32: return *(int32 *)ptr;
00492 case SLE_VAR_U32: return *(uint32*)ptr;
00493 case SLE_VAR_I64: return *(int64 *)ptr;
00494 case SLE_VAR_U64: return *(uint64*)ptr;
00495 case SLE_VAR_NULL:return 0;
00496 default: NOT_REACHED();
00497 }
00498 }
00499
00505 void WriteValue(void *ptr, VarType conv, int64 val)
00506 {
00507 switch (GetVarMemType(conv)) {
00508 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00509 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00510 case SLE_VAR_U8: *(byte *)ptr = val; break;
00511 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00512 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00513 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00514 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00515 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00516 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00517 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00518 case SLE_VAR_NULL: break;
00519 default: NOT_REACHED();
00520 }
00521 }
00522
00531 static void SlSaveLoadConv(void *ptr, VarType conv)
00532 {
00533 switch (_sl.action) {
00534 case SLA_SAVE: {
00535 int64 x = ReadValue(ptr, conv);
00536
00537
00538 switch (GetVarFileType(conv)) {
00539 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00540 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00541 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00542 case SLE_FILE_STRINGID:
00543 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00544 case SLE_FILE_I32:
00545 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00546 case SLE_FILE_I64:
00547 case SLE_FILE_U64: SlWriteUint64(x);break;
00548 default: NOT_REACHED();
00549 }
00550 break;
00551 }
00552 case SLA_LOAD: {
00553 int64 x;
00554
00555 switch (GetVarFileType(conv)) {
00556 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00557 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00558 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00559 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00560 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00561 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00562 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00563 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00564 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00565 default: NOT_REACHED();
00566 }
00567
00568
00569 WriteValue(ptr, conv, x);
00570 break;
00571 }
00572 case SLA_PTRS: break;
00573 default: NOT_REACHED();
00574 }
00575 }
00576
00584 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
00585 {
00586 if (ptr == NULL) return 0;
00587 return min(strlen(ptr), length - 1);
00588 }
00589
00597 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
00598 {
00599 size_t len;
00600 const char *str;
00601
00602 switch (GetVarMemType(conv)) {
00603 default: NOT_REACHED();
00604 case SLE_VAR_STR:
00605 case SLE_VAR_STRQ:
00606 str = *(const char**)ptr;
00607 len = SIZE_MAX;
00608 break;
00609 case SLE_VAR_STRB:
00610 case SLE_VAR_STRBQ:
00611 str = (const char*)ptr;
00612 len = length;
00613 break;
00614 }
00615
00616 len = SlCalcNetStringLen(str, len);
00617 return len + SlGetArrayLength(len);
00618 }
00619
00625 static void SlString(void *ptr, size_t length, VarType conv)
00626 {
00627 switch (_sl.action) {
00628 case SLA_SAVE: {
00629 size_t len;
00630 switch (GetVarMemType(conv)) {
00631 default: NOT_REACHED();
00632 case SLE_VAR_STRB:
00633 case SLE_VAR_STRBQ:
00634 len = SlCalcNetStringLen((char *)ptr, length);
00635 break;
00636 case SLE_VAR_STR:
00637 case SLE_VAR_STRQ:
00638 ptr = *(char **)ptr;
00639 len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
00640 break;
00641 }
00642
00643 SlWriteArrayLength(len);
00644 SlCopyBytes(ptr, len);
00645 break;
00646 }
00647 case SLA_LOAD: {
00648 size_t len = SlReadArrayLength();
00649
00650 switch (GetVarMemType(conv)) {
00651 default: NOT_REACHED();
00652 case SLE_VAR_STRB:
00653 case SLE_VAR_STRBQ:
00654 if (len >= length) {
00655 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
00656 SlCopyBytes(ptr, length);
00657 SlSkipBytes(len - length);
00658 len = length - 1;
00659 } else {
00660 SlCopyBytes(ptr, len);
00661 }
00662 break;
00663 case SLE_VAR_STR:
00664 case SLE_VAR_STRQ:
00665 free(*(char **)ptr);
00666 if (len == 0) {
00667 *(char **)ptr = NULL;
00668 } else {
00669 *(char **)ptr = MallocT<char>(len + 1);
00670 ptr = *(char **)ptr;
00671 SlCopyBytes(ptr, len);
00672 }
00673 break;
00674 }
00675
00676 ((char *)ptr)[len] = '\0';
00677 str_validate((char *)ptr, (char *)ptr + len);
00678 break;
00679 }
00680 case SLA_PTRS: break;
00681 default: NOT_REACHED();
00682 }
00683 }
00684
00690 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
00691 {
00692 return SlCalcConvFileLen(conv) * length;
00693 }
00694
00701 void SlArray(void *array, size_t length, VarType conv)
00702 {
00703 if (_sl.action == SLA_PTRS) return;
00704
00705
00706 if (_sl.need_length != NL_NONE) {
00707 SlSetLength(SlCalcArrayLen(length, conv));
00708
00709 if (_sl.need_length == NL_CALCLENGTH) return;
00710 }
00711
00712
00713
00714 if (_sl.action != SLA_SAVE && _sl_version == 0) {
00715
00716 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
00717 conv == SLE_INT32 || conv == SLE_UINT32) {
00718 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
00719 return;
00720 }
00721
00722 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
00723 for (uint i = 0; i < length; i++) {
00724 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
00725 }
00726 return;
00727 }
00728 }
00729
00730
00731
00732 if (conv == SLE_INT8 || conv == SLE_UINT8) {
00733 SlCopyBytes(array, length);
00734 } else {
00735 byte *a = (byte*)array;
00736 byte mem_size = SlCalcConvMemLen(conv);
00737
00738 for (; length != 0; length --) {
00739 SlSaveLoadConv(a, conv);
00740 a += mem_size;
00741 }
00742 }
00743 }
00744
00745
00746 static size_t ReferenceToInt(const void *obj, SLRefType rt);
00747 static void *IntToReference(size_t index, SLRefType rt);
00748
00749
00754 static inline size_t SlCalcListLen(const void *list)
00755 {
00756 std::list<void *> *l = (std::list<void *> *) list;
00757
00758 int type_size = CheckSavegameVersion(69) ? 2 : 4;
00759
00760
00761 return l->size() * type_size + type_size;
00762 }
00763
00764
00770 static void SlList(void *list, SLRefType conv)
00771 {
00772
00773 if (_sl.need_length != NL_NONE) {
00774 SlSetLength(SlCalcListLen(list));
00775
00776 if (_sl.need_length == NL_CALCLENGTH) return;
00777 }
00778
00779 typedef std::list<void *> PtrList;
00780 PtrList *l = (PtrList *)list;
00781
00782 switch (_sl.action) {
00783 case SLA_SAVE: {
00784 SlWriteUint32((uint32)l->size());
00785
00786 PtrList::iterator iter;
00787 for (iter = l->begin(); iter != l->end(); ++iter) {
00788 void *ptr = *iter;
00789 SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
00790 }
00791 break;
00792 }
00793 case SLA_LOAD: {
00794 size_t length = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
00795
00796
00797 for (size_t i = 0; i < length; i++) {
00798 size_t data = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
00799 l->push_back((void *)data);
00800 }
00801 break;
00802 }
00803 case SLA_PTRS: {
00804 PtrList temp = *l;
00805
00806 l->clear();
00807 PtrList::iterator iter;
00808 for (iter = temp.begin(); iter != temp.end(); ++iter) {
00809 void *ptr = IntToReference((size_t)*iter, conv);
00810 l->push_back(ptr);
00811 }
00812 break;
00813 }
00814 default: NOT_REACHED();
00815 }
00816 }
00817
00818
00820 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
00821 {
00822 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
00823 if (sld->conv & SLF_SAVE_NO) return false;
00824
00825 return true;
00826 }
00827
00831 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
00832 {
00833 if ((sld->conv & SLF_NETWORK_NO) && _sl.action != SLA_SAVE && _networking && !_network_server) {
00834 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
00835 return true;
00836 }
00837
00838 return false;
00839 }
00840
00847 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
00848 {
00849 size_t length = 0;
00850
00851
00852 for (; sld->cmd != SL_END; sld++) {
00853 length += SlCalcObjMemberLength(object, sld);
00854 }
00855 return length;
00856 }
00857
00858 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
00859 {
00860 assert(_sl.action == SLA_SAVE);
00861
00862 switch (sld->cmd) {
00863 case SL_VAR:
00864 case SL_REF:
00865 case SL_ARR:
00866 case SL_STR:
00867 case SL_LST:
00868
00869 if (!SlIsObjectValidInSavegame(sld)) break;
00870
00871 switch (sld->cmd) {
00872 case SL_VAR: return SlCalcConvFileLen(sld->conv);
00873 case SL_REF: return SlCalcRefLen();
00874 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
00875 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
00876 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
00877 default: NOT_REACHED();
00878 }
00879 break;
00880 case SL_WRITEBYTE: return 1;
00881 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
00882 case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
00883 default: NOT_REACHED();
00884 }
00885 return 0;
00886 }
00887
00888
00889 bool SlObjectMember(void *ptr, const SaveLoad *sld)
00890 {
00891 VarType conv = GB(sld->conv, 0, 8);
00892 switch (sld->cmd) {
00893 case SL_VAR:
00894 case SL_REF:
00895 case SL_ARR:
00896 case SL_STR:
00897 case SL_LST:
00898
00899 if (!SlIsObjectValidInSavegame(sld)) return false;
00900 if (SlSkipVariableOnLoad(sld)) return false;
00901
00902 switch (sld->cmd) {
00903 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
00904 case SL_REF:
00905 switch (_sl.action) {
00906 case SLA_SAVE:
00907 SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
00908 break;
00909 case SLA_LOAD:
00910 *(size_t *)ptr = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
00911 break;
00912 case SLA_PTRS:
00913 *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
00914 break;
00915 default: NOT_REACHED();
00916 }
00917 break;
00918 case SL_ARR: SlArray(ptr, sld->length, conv); break;
00919 case SL_STR: SlString(ptr, sld->length, conv); break;
00920 case SL_LST: SlList(ptr, (SLRefType)conv); break;
00921 default: NOT_REACHED();
00922 }
00923 break;
00924
00925
00926
00927
00928
00929
00930 case SL_WRITEBYTE:
00931 switch (_sl.action) {
00932 case SLA_SAVE: SlWriteByte(sld->version_to); break;
00933 case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
00934 case SLA_PTRS: break;
00935 default: NOT_REACHED();
00936 }
00937 break;
00938
00939
00940 case SL_VEH_INCLUDE:
00941 SlObject(ptr, GetVehicleDescription(VEH_END));
00942 break;
00943
00944 case SL_ST_INCLUDE:
00945 SlObject(ptr, GetBaseStationDescription());
00946 break;
00947
00948 default: NOT_REACHED();
00949 }
00950 return true;
00951 }
00952
00958 void SlObject(void *object, const SaveLoad *sld)
00959 {
00960
00961 if (_sl.need_length != NL_NONE) {
00962 SlSetLength(SlCalcObjLength(object, sld));
00963 if (_sl.need_length == NL_CALCLENGTH) return;
00964 }
00965
00966 for (; sld->cmd != SL_END; sld++) {
00967 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
00968 SlObjectMember(ptr, sld);
00969 }
00970 }
00971
00976 void SlGlobList(const SaveLoadGlobVarList *sldg)
00977 {
00978 SlObject(NULL, (const SaveLoad*)sldg);
00979 }
00980
00986 void SlAutolength(AutolengthProc *proc, void *arg)
00987 {
00988 size_t offs;
00989
00990 assert(_sl.action == SLA_SAVE);
00991
00992
00993 _sl.need_length = NL_CALCLENGTH;
00994 _sl.obj_len = 0;
00995 proc(arg);
00996
00997
00998 _sl.need_length = NL_WANTLENGTH;
00999 SlSetLength(_sl.obj_len);
01000
01001 offs = SlGetOffs() + _sl.obj_len;
01002
01003
01004 proc(arg);
01005
01006 if (offs != SlGetOffs()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
01007 }
01008
01013 static void SlLoadChunk(const ChunkHandler *ch)
01014 {
01015 byte m = SlReadByte();
01016 size_t len;
01017 size_t endoffs;
01018
01019 _sl.block_mode = m;
01020 _sl.obj_len = 0;
01021
01022 switch (m) {
01023 case CH_ARRAY:
01024 _sl.array_index = 0;
01025 ch->load_proc();
01026 break;
01027 case CH_SPARSE_ARRAY:
01028 ch->load_proc();
01029 break;
01030 default:
01031 if ((m & 0xF) == CH_RIFF) {
01032
01033 len = (SlReadByte() << 16) | ((m >> 4) << 24);
01034 len += SlReadUint16();
01035 _sl.obj_len = len;
01036 endoffs = SlGetOffs() + len;
01037 ch->load_proc();
01038 if (SlGetOffs() != endoffs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
01039 } else {
01040 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk type");
01041 }
01042 break;
01043 }
01044 }
01045
01046
01047 static ChunkSaveLoadProc *_tmp_proc_1;
01048 static inline void SlStubSaveProc2(void *arg) {_tmp_proc_1();}
01049 static void SlStubSaveProc() {SlAutolength(SlStubSaveProc2, NULL);}
01050
01055 static void SlSaveChunk(const ChunkHandler *ch)
01056 {
01057 ChunkSaveLoadProc *proc = ch->save_proc;
01058
01059
01060 if (proc == NULL) return;
01061
01062 SlWriteUint32(ch->id);
01063 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01064
01065 if (ch->flags & CH_AUTO_LENGTH) {
01066
01067 _tmp_proc_1 = proc;
01068 proc = SlStubSaveProc;
01069 }
01070
01071 _sl.block_mode = ch->flags & CH_TYPE_MASK;
01072 switch (ch->flags & CH_TYPE_MASK) {
01073 case CH_RIFF:
01074 _sl.need_length = NL_WANTLENGTH;
01075 proc();
01076 break;
01077 case CH_ARRAY:
01078 _sl.last_array_index = 0;
01079 SlWriteByte(CH_ARRAY);
01080 proc();
01081 SlWriteArrayLength(0);
01082 break;
01083 case CH_SPARSE_ARRAY:
01084 SlWriteByte(CH_SPARSE_ARRAY);
01085 proc();
01086 SlWriteArrayLength(0);
01087 break;
01088 default: NOT_REACHED();
01089 }
01090 }
01091
01093 static void SlSaveChunks()
01094 {
01095 const ChunkHandler *ch;
01096 const ChunkHandler * const *chsc;
01097 uint p;
01098
01099 for (p = 0; p != CH_NUM_PRI_LEVELS; p++) {
01100 for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
01101 while (true) {
01102 if (((ch->flags >> CH_PRI_SHL) & (CH_NUM_PRI_LEVELS - 1)) == p)
01103 SlSaveChunk(ch);
01104 if (ch->flags & CH_LAST)
01105 break;
01106 ch++;
01107 }
01108 }
01109 }
01110
01111
01112 SlWriteUint32(0);
01113 }
01114
01120 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01121 {
01122 const ChunkHandler *ch;
01123 const ChunkHandler *const *chsc;
01124 for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
01125 for (;;) {
01126 if (ch->id == id) return ch;
01127 if (ch->flags & CH_LAST) break;
01128 ch++;
01129 }
01130 }
01131 return NULL;
01132 }
01133
01135 static void SlLoadChunks()
01136 {
01137 uint32 id;
01138 const ChunkHandler *ch;
01139
01140 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01141 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01142
01143 ch = SlFindChunkHandler(id);
01144 if (ch == NULL) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unknown chunk type");
01145 SlLoadChunk(ch);
01146 }
01147 }
01148
01149 static const char *_sl_ptrs_error;
01150
01152 static void SlFixPointers()
01153 {
01154 const ChunkHandler *ch;
01155 const ChunkHandler * const *chsc;
01156
01157 _sl.action = SLA_PTRS;
01158 _sl_ptrs_error = NULL;
01159
01160 DEBUG(sl, 1, "Fixing pointers");
01161
01162 for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
01163 while (true) {
01164 if (ch->ptrs_proc != NULL) {
01165 DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01166 ch->ptrs_proc();
01167 }
01168 if (ch->flags & CH_LAST)
01169 break;
01170 ch++;
01171 }
01172 }
01173
01174
01175 if (_sl_ptrs_error != NULL) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, _sl_ptrs_error);
01176
01177 DEBUG(sl, 1, "All pointers fixed");
01178
01179 assert(_sl.action == SLA_PTRS);
01180 }
01181
01182
01183
01184
01185 #define LZO_SIZE 8192
01186
01187 #include "../3rdparty/minilzo/minilzo.h"
01188
01189 static size_t ReadLZO()
01190 {
01191 byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
01192 uint32 tmp[2];
01193 uint32 size;
01194 lzo_uint len;
01195
01196
01197 if (fread(tmp, sizeof(tmp), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01198
01199
01200 ((uint32*)out)[0] = size = tmp[1];
01201
01202 if (_sl_version != 0) {
01203 tmp[0] = TO_BE32(tmp[0]);
01204 size = TO_BE32(size);
01205 }
01206
01207 if (size >= sizeof(out)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Inconsistent size");
01208
01209
01210 if (fread(out + sizeof(uint32), size, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01211
01212
01213 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Bad checksum");
01214
01215
01216 lzo1x_decompress(out + sizeof(uint32) * 1, size, _sl.buf, &len, NULL);
01217 return len;
01218 }
01219
01220
01221
01222 static void WriteLZO(size_t size)
01223 {
01224 byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
01225 byte wrkmem[sizeof(byte*) * 4096];
01226 lzo_uint outlen;
01227
01228 lzo1x_1_compress(_sl.buf, (lzo_uint)size, out + sizeof(uint32) * 2, &outlen, wrkmem);
01229 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01230 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01231 if (fwrite(out, outlen + sizeof(uint32) * 2, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01232 }
01233
01234 static bool InitLZO()
01235 {
01236 _sl.bufsize = LZO_SIZE;
01237 _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
01238 return true;
01239 }
01240
01241 static void UninitLZO()
01242 {
01243 free(_sl.buf_ori);
01244 }
01245
01246
01247
01248
01249 static size_t ReadNoComp()
01250 {
01251 return fread(_sl.buf, 1, LZO_SIZE, _sl.fh);
01252 }
01253
01254 static void WriteNoComp(size_t size)
01255 {
01256 if (fwrite(_sl.buf, 1, size, _sl.fh) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01257 }
01258
01259 static bool InitNoComp()
01260 {
01261 _sl.bufsize = LZO_SIZE;
01262 _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
01263 return true;
01264 }
01265
01266 static void UninitNoComp()
01267 {
01268 free(_sl.buf_ori);
01269 }
01270
01271
01272
01273
01274
01275 #include "../gui.h"
01276
01277 struct ThreadedSave {
01278 uint count;
01279 byte ff_state;
01280 bool saveinprogress;
01281 CursorID cursor;
01282 };
01283
01285 static const int MEMORY_CHUNK_SIZE = 128 * 1024;
01287 static AutoFreeSmallVector<byte *, 16> _memory_savegame;
01288
01289 static ThreadedSave _ts;
01290
01291 static void WriteMem(size_t size)
01292 {
01293 _ts.count += (uint)size;
01294
01295 _sl.buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
01296 *_memory_savegame.Append() = _sl.buf;
01297 }
01298
01299 static void UnInitMem()
01300 {
01301 _memory_savegame.Clear();
01302 }
01303
01304 static bool InitMem()
01305 {
01306 _ts.count = 0;
01307 _sl.bufsize = MEMORY_CHUNK_SIZE;
01308
01309 UnInitMem();
01310 WriteMem(0);
01311 return true;
01312 }
01313
01314
01315
01316
01317
01318 #if defined(WITH_ZLIB)
01319 #include <zlib.h>
01320
01321 static z_stream _z;
01322
01323 static bool InitReadZlib()
01324 {
01325 memset(&_z, 0, sizeof(_z));
01326 if (inflateInit(&_z) != Z_OK) return false;
01327
01328 _sl.bufsize = 4096;
01329 _sl.buf = _sl.buf_ori = MallocT<byte>(4096 + 4096);
01330 return true;
01331 }
01332
01333 static size_t ReadZlib()
01334 {
01335 int r;
01336
01337 _z.next_out = _sl.buf;
01338 _z.avail_out = 4096;
01339
01340 do {
01341
01342 if (_z.avail_in == 0) {
01343 _z.avail_in = (uint)fread(_z.next_in = _sl.buf + 4096, 1, 4096, _sl.fh);
01344 }
01345
01346
01347 r = inflate(&_z, 0);
01348 if (r == Z_STREAM_END)
01349 break;
01350
01351 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
01352 } while (_z.avail_out);
01353
01354 return 4096 - _z.avail_out;
01355 }
01356
01357 static void UninitReadZlib()
01358 {
01359 inflateEnd(&_z);
01360 free(_sl.buf_ori);
01361 }
01362
01363 static bool InitWriteZlib()
01364 {
01365 memset(&_z, 0, sizeof(_z));
01366 if (deflateInit(&_z, 6) != Z_OK) return false;
01367
01368 _sl.bufsize = 4096;
01369 _sl.buf = _sl.buf_ori = MallocT<byte>(4096);
01370 return true;
01371 }
01372
01373 static void WriteZlibLoop(z_streamp z, byte *p, size_t len, int mode)
01374 {
01375 byte buf[1024];
01376 int r;
01377 uint n;
01378 z->next_in = p;
01379 z->avail_in = (uInt)len;
01380 do {
01381 z->next_out = buf;
01382 z->avail_out = sizeof(buf);
01383
01391 r = deflate(z, mode);
01392
01393
01394 if ((n = sizeof(buf) - z->avail_out) != 0) {
01395 if (fwrite(buf, n, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01396 }
01397 if (r == Z_STREAM_END)
01398 break;
01399 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
01400 } while (z->avail_in || !z->avail_out);
01401 }
01402
01403 static void WriteZlib(size_t len)
01404 {
01405 WriteZlibLoop(&_z, _sl.buf, len, 0);
01406 }
01407
01408 static void UninitWriteZlib()
01409 {
01410
01411 if (_sl.fh) WriteZlibLoop(&_z, NULL, 0, Z_FINISH);
01412 deflateEnd(&_z);
01413 free(_sl.buf_ori);
01414 }
01415
01416 #endif
01417
01418
01419
01420
01421
01422
01423 extern const ChunkHandler _gamelog_chunk_handlers[];
01424 extern const ChunkHandler _map_chunk_handlers[];
01425 extern const ChunkHandler _misc_chunk_handlers[];
01426 extern const ChunkHandler _name_chunk_handlers[];
01427 extern const ChunkHandler _cheat_chunk_handlers[] ;
01428 extern const ChunkHandler _setting_chunk_handlers[];
01429 extern const ChunkHandler _company_chunk_handlers[];
01430 extern const ChunkHandler _engine_chunk_handlers[];
01431 extern const ChunkHandler _veh_chunk_handlers[];
01432 extern const ChunkHandler _waypoint_chunk_handlers[];
01433 extern const ChunkHandler _depot_chunk_handlers[];
01434 extern const ChunkHandler _order_chunk_handlers[];
01435 extern const ChunkHandler _town_chunk_handlers[];
01436 extern const ChunkHandler _sign_chunk_handlers[];
01437 extern const ChunkHandler _station_chunk_handlers[];
01438 extern const ChunkHandler _industry_chunk_handlers[];
01439 extern const ChunkHandler _economy_chunk_handlers[];
01440 extern const ChunkHandler _subsidy_chunk_handlers[];
01441 extern const ChunkHandler _ai_chunk_handlers[];
01442 extern const ChunkHandler _animated_tile_chunk_handlers[];
01443 extern const ChunkHandler _newgrf_chunk_handlers[];
01444 extern const ChunkHandler _group_chunk_handlers[];
01445 extern const ChunkHandler _cargopacket_chunk_handlers[];
01446 extern const ChunkHandler _autoreplace_chunk_handlers[];
01447 extern const ChunkHandler _labelmaps_chunk_handlers[];
01448
01449 static const ChunkHandler * const _chunk_handlers[] = {
01450 _gamelog_chunk_handlers,
01451 _map_chunk_handlers,
01452 _misc_chunk_handlers,
01453 _name_chunk_handlers,
01454 _cheat_chunk_handlers,
01455 _setting_chunk_handlers,
01456 _veh_chunk_handlers,
01457 _waypoint_chunk_handlers,
01458 _depot_chunk_handlers,
01459 _order_chunk_handlers,
01460 _industry_chunk_handlers,
01461 _economy_chunk_handlers,
01462 _subsidy_chunk_handlers,
01463 _engine_chunk_handlers,
01464 _town_chunk_handlers,
01465 _sign_chunk_handlers,
01466 _station_chunk_handlers,
01467 _company_chunk_handlers,
01468 _ai_chunk_handlers,
01469 _animated_tile_chunk_handlers,
01470 _newgrf_chunk_handlers,
01471 _group_chunk_handlers,
01472 _cargopacket_chunk_handlers,
01473 _autoreplace_chunk_handlers,
01474 _labelmaps_chunk_handlers,
01475 NULL,
01476 };
01477
01488 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01489 {
01490 assert(_sl.action == SLA_SAVE);
01491
01492 if (obj == NULL) return 0;
01493
01494 switch (rt) {
01495 case REF_VEHICLE_OLD:
01496 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01497 case REF_STATION: return ((const Station*)obj)->index + 1;
01498 case REF_TOWN: return ((const Town*)obj)->index + 1;
01499 case REF_ORDER: return ((const Order*)obj)->index + 1;
01500 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01501 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01502 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01503 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01504 default: NOT_REACHED();
01505 }
01506 }
01507
01518 static void *IntToReference(size_t index, SLRefType rt)
01519 {
01520 assert_compile(sizeof(size_t) <= sizeof(void *));
01521
01522 assert(_sl.action == SLA_PTRS);
01523
01524
01525
01526 if (rt == REF_VEHICLE_OLD && !CheckSavegameVersionOldStyle(4, 4)) {
01527 rt = REF_VEHICLE;
01528 }
01529
01530
01531 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01532
01533
01534
01535 if (rt != REF_VEHICLE_OLD) index--;
01536
01537 switch (rt) {
01538 case REF_ORDERLIST:
01539 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01540 _sl_ptrs_error = "Referencing invalid OrderList";
01541 break;
01542
01543 case REF_ORDER:
01544 if (Order::IsValidID(index)) return Order::Get(index);
01545
01546 if (CheckSavegameVersionOldStyle(5, 2)) return NULL;
01547 _sl_ptrs_error = "Referencing invalid Order";
01548 break;
01549
01550 case REF_VEHICLE_OLD:
01551 case REF_VEHICLE:
01552 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01553 _sl_ptrs_error = "Referencing invalid Vehicle";
01554 break;
01555
01556 case REF_STATION:
01557 if (Station::IsValidID(index)) return Station::Get(index);
01558 _sl_ptrs_error = "Referencing invalid Station";
01559 break;
01560
01561 case REF_TOWN:
01562 if (Town::IsValidID(index)) return Town::Get(index);
01563 _sl_ptrs_error = "Referencing invalid Town";
01564 break;
01565
01566 case REF_ROADSTOPS:
01567 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01568 _sl_ptrs_error = "Referencing invalid RoadStop";
01569 break;
01570
01571 case REF_ENGINE_RENEWS:
01572 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01573 _sl_ptrs_error = "Referencing invalid EngineRenew";
01574 break;
01575
01576 case REF_CARGO_PACKET:
01577 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01578 _sl_ptrs_error = "Referencing invalid CargoPacket";
01579 break;
01580
01581 default: NOT_REACHED();
01582 }
01583
01584
01585 DEBUG(sl, 1, "%s (index = " PRINTF_SIZE ")", _sl_ptrs_error, index);
01586
01587
01588 return NULL;
01589 }
01590
01592 struct SaveLoadFormat {
01593 const char *name;
01594 uint32 tag;
01595
01596 bool (*init_read)();
01597 ReaderProc *reader;
01598 void (*uninit_read)();
01599
01600 bool (*init_write)();
01601 WriterProc *writer;
01602 void (*uninit_write)();
01603 };
01604
01605 static const SaveLoadFormat _saveload_formats[] = {
01606 {"memory", 0, NULL, NULL, NULL, InitMem, WriteMem, UnInitMem},
01607 {"lzo", TO_BE32X('OTTD'), InitLZO, ReadLZO, UninitLZO, InitLZO, WriteLZO, UninitLZO},
01608 {"none", TO_BE32X('OTTN'), InitNoComp, ReadNoComp, UninitNoComp, InitNoComp, WriteNoComp, UninitNoComp},
01609 #if defined(WITH_ZLIB)
01610 {"zlib", TO_BE32X('OTTZ'), InitReadZlib, ReadZlib, UninitReadZlib, InitWriteZlib, WriteZlib, UninitWriteZlib},
01611 #else
01612 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, NULL, NULL, NULL, NULL},
01613 #endif
01614 };
01615
01622 static const SaveLoadFormat *GetSavegameFormat(const char *s)
01623 {
01624 const SaveLoadFormat *def = endof(_saveload_formats) - 1;
01625
01626
01627 while (!def->init_write) def--;
01628
01629 if (s != NULL && s[0] != '\0') {
01630 const SaveLoadFormat *slf;
01631 for (slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
01632 if (slf->init_write != NULL && strcmp(s, slf->name) == 0)
01633 return slf;
01634 }
01635
01636 ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
01637 }
01638 return def;
01639 }
01640
01641
01642 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
01643 extern bool AfterLoadGame();
01644 extern bool LoadOldSaveGame(const char *file);
01645
01647 static inline SaveOrLoadResult AbortSaveLoad()
01648 {
01649 if (_sl.fh != NULL) fclose(_sl.fh);
01650
01651 _sl.fh = NULL;
01652 return SL_ERROR;
01653 }
01654
01658 static void SaveFileStart()
01659 {
01660 _ts.ff_state = _fast_forward;
01661 _fast_forward = 0;
01662 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
01663
01664 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
01665 _ts.saveinprogress = true;
01666 }
01667
01670 static void SaveFileDone()
01671 {
01672 if (_game_mode != GM_MENU) _fast_forward = _ts.ff_state;
01673 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
01674
01675 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
01676 _ts.saveinprogress = false;
01677 }
01678
01680 void SetSaveLoadError(StringID str)
01681 {
01682 _sl.error_str = str;
01683 }
01684
01686 const char *GetSaveLoadErrorString()
01687 {
01688 SetDParam(0, _sl.error_str);
01689 SetDParamStr(1, _sl.extra_msg);
01690
01691 static char err_str[512];
01692 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
01693 return err_str;
01694 }
01695
01697 static void SaveFileError()
01698 {
01699 SetDParamStr(0, GetSaveLoadErrorString());
01700 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, 0, 0);
01701 SaveFileDone();
01702 }
01703
01707 static SaveOrLoadResult SaveFileToDisk(bool threaded)
01708 {
01709 const SaveLoadFormat *fmt;
01710 uint32 hdr[2];
01711
01712 _sl.excpt_uninit = NULL;
01713 try {
01714 fmt = GetSavegameFormat(_savegame_format);
01715
01716
01717 hdr[0] = fmt->tag;
01718 hdr[1] = TO_BE32(SAVEGAME_VERSION << 16);
01719 if (fwrite(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01720
01721 if (!fmt->init_write()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01722
01723 {
01724 uint i;
01725
01726 if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
01727 for (i = 0; i != _memory_savegame.Length() - 1; i++) {
01728 _sl.buf = _memory_savegame[i];
01729 fmt->writer(MEMORY_CHUNK_SIZE);
01730 }
01731
01732
01733
01734 _sl.buf = _memory_savegame[i];
01735 fmt->writer(_ts.count % MEMORY_CHUNK_SIZE);
01736 }
01737
01738 fmt->uninit_write();
01739 if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
01740 GetSavegameFormat("memory")->uninit_write();
01741 fclose(_sl.fh);
01742
01743 if (threaded) SetAsyncSaveFinish(SaveFileDone);
01744
01745 return SL_OK;
01746 }
01747 catch (...) {
01748 AbortSaveLoad();
01749 if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
01750
01751
01752 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
01753
01754 if (threaded) {
01755 SetAsyncSaveFinish(SaveFileError);
01756 } else {
01757 SaveFileError();
01758 }
01759 return SL_ERROR;
01760 }
01761 }
01762
01763 static void SaveFileToDiskThread(void *arg)
01764 {
01765 SaveFileToDisk(true);
01766 }
01767
01768 void WaitTillSaved()
01769 {
01770 if (_save_thread == NULL) return;
01771
01772 _save_thread->Join();
01773 delete _save_thread;
01774 _save_thread = NULL;
01775 }
01776
01786 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
01787 {
01788 uint32 hdr[2];
01789 const SaveLoadFormat *fmt;
01790
01791
01792 if (_ts.saveinprogress && mode == SL_SAVE) {
01793
01794 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, 0, 0);
01795 return SL_OK;
01796 }
01797 WaitTillSaved();
01798
01799 _next_offs = 0;
01800
01801
01802 if (mode == SL_OLD_LOAD) {
01803 _engine_mngr.ResetToDefaultMapping();
01804 InitializeGame(256, 256, true, true);
01805 GamelogReset();
01806 if (!LoadOldSaveGame(filename)) return SL_REINIT;
01807 _sl_version = 0;
01808 _sl_minor_version = 0;
01809 GamelogStartAction(GLAT_LOAD);
01810 if (!AfterLoadGame()) {
01811 GamelogStopAction();
01812 return SL_REINIT;
01813 }
01814 GamelogStopAction();
01815 return SL_OK;
01816 }
01817
01818 _sl.excpt_uninit = NULL;
01819 try {
01820 _sl.fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
01821
01822
01823 if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", SAVE_DIR);
01824 if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", BASE_DIR);
01825
01826 if (_sl.fh == NULL) {
01827 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01828 }
01829
01830 _sl.bufe = _sl.bufp = NULL;
01831 _sl.offs_base = 0;
01832 _sl.action = (mode != 0) ? SLA_SAVE : SLA_LOAD;
01833 _sl.chs = _chunk_handlers;
01834
01835
01836
01837 if (mode == SL_SAVE) {
01838 DEBUG(desync, 1, "save: %s\n", filename);
01839 fmt = GetSavegameFormat("memory");
01840
01841 _sl.write_bytes = fmt->writer;
01842 _sl.excpt_uninit = fmt->uninit_write;
01843 if (!fmt->init_write()) {
01844 DEBUG(sl, 0, "Initializing writer '%s' failed.", fmt->name);
01845 return AbortSaveLoad();
01846 }
01847
01848 _sl_version = SAVEGAME_VERSION;
01849
01850 SaveViewportBeforeSaveGame();
01851 SlSaveChunks();
01852 SlWriteFill();
01853
01854 SaveFileStart();
01855 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
01856 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
01857 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
01858
01859 SaveOrLoadResult result = SaveFileToDisk(false);
01860 SaveFileDone();
01861
01862 return result;
01863 }
01864 } else {
01865 assert(mode == SL_LOAD);
01866 DEBUG(desync, 1, "load: %s\n", filename);
01867
01868
01869 long pos = ftell(_sl.fh);
01870 if (fread(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01871
01872
01873 for (fmt = _saveload_formats; ; fmt++) {
01874
01875 if (fmt == endof(_saveload_formats)) {
01876 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
01877 clearerr(_sl.fh);
01878 fseek(_sl.fh, pos, SEEK_SET);
01879 _sl_version = 0;
01880 _sl_minor_version = 0;
01881 fmt = _saveload_formats + 1;
01882 break;
01883 }
01884
01885 if (fmt->tag == hdr[0]) {
01886
01887 _sl_version = TO_BE32(hdr[1]) >> 16;
01888
01889
01890
01891
01892 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
01893
01894 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
01895
01896
01897 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
01898 break;
01899 }
01900 }
01901
01902 _sl.read_bytes = fmt->reader;
01903 _sl.excpt_uninit = fmt->uninit_read;
01904
01905
01906 if (fmt->init_read == NULL) {
01907 char err_str[64];
01908 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
01909 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
01910 }
01911
01912 if (!fmt->init_read()) {
01913 char err_str[64];
01914 snprintf(err_str, lengthof(err_str), "Initializing loader '%s' failed", fmt->name);
01915 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
01916 }
01917
01918 _engine_mngr.ResetToDefaultMapping();
01919
01920
01921
01922
01923 InitializeGame(256, 256, true, true);
01924
01925 GamelogReset();
01926
01927 SlLoadChunks();
01928 SlFixPointers();
01929 fmt->uninit_read();
01930 fclose(_sl.fh);
01931
01932 GamelogStartAction(GLAT_LOAD);
01933
01934 _savegame_type = SGT_OTTD;
01935
01936
01937
01938 if (!AfterLoadGame()) {
01939 GamelogStopAction();
01940 return SL_REINIT;
01941 }
01942
01943 GamelogStopAction();
01944 }
01945
01946 return SL_OK;
01947 }
01948 catch (...) {
01949 AbortSaveLoad();
01950
01951
01952 if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
01953
01954
01955 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
01956
01957
01958 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
01959 }
01960 }
01961
01963 void DoExitSave()
01964 {
01965 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
01966 }
01967
01973 void GenerateDefaultSaveName(char *buf, const char *last)
01974 {
01975
01976
01977
01978 CompanyID cid = _local_company;
01979 if (!Company::IsValidID(cid)) {
01980 const Company *c;
01981 FOR_ALL_COMPANIES(c) {
01982 cid = c->index;
01983 break;
01984 }
01985 }
01986
01987 SetDParam(0, cid);
01988
01989
01990 switch (_settings_client.gui.date_format_in_default_names) {
01991 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
01992 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
01993 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
01994 default: NOT_REACHED();
01995 }
01996 SetDParam(2, _date);
01997
01998
01999 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02000 SanitizeFilename(buf);
02001 }
02002
02003 #if 0
02004
02010 int GetSavegameType(char *file)
02011 {
02012 const SaveLoadFormat *fmt;
02013 uint32 hdr;
02014 FILE *f;
02015 int mode = SL_OLD_LOAD;
02016
02017 f = fopen(file, "rb");
02018 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02019 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02020 mode = SL_LOAD;
02021 } else {
02022
02023 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02024 if (fmt->tag == hdr) {
02025 mode = SL_LOAD;
02026 break;
02027 }
02028 }
02029 }
02030
02031 fclose(f);
02032 return mode;
02033 }
02034 #endif