00001
00002
00016 #include "../stdafx.h"
00017 #include "../openttd.h"
00018 #include "../debug.h"
00019 #include "../station_base.h"
00020 #include "../thread.h"
00021 #include "../town.h"
00022 #include "../network/network.h"
00023 #include "../variables.h"
00024 #include "../window_func.h"
00025 #include "../strings_func.h"
00026 #include "../gfx_func.h"
00027 #include "../core/alloc_func.hpp"
00028 #include "../core/endian_func.hpp"
00029 #include "../vehicle_base.h"
00030 #include "../company_func.h"
00031 #include "../date_func.h"
00032 #include "../autoreplace_base.h"
00033 #include "../statusbar_gui.h"
00034 #include "../fileio_func.h"
00035 #include "../gamelog.h"
00036 #include "../string_func.h"
00037 #include "../engine_base.h"
00038
00039 #include "table/strings.h"
00040
00041 #include "saveload_internal.h"
00042
00043 extern const uint16 SAVEGAME_VERSION = 114;
00044
00045 SavegameType _savegame_type;
00046
00047 uint32 _ttdp_version;
00048 uint16 _sl_version;
00049 byte _sl_minor_version;
00050 char _savegame_format[8];
00051
00052 typedef void WriterProc(size_t len);
00053 typedef size_t ReaderProc();
00054
00056 static struct {
00057 bool save;
00058 byte need_length;
00059 byte block_mode;
00060 bool error;
00061
00062 size_t obj_len;
00063 int array_index, last_array_index;
00064
00065 size_t offs_base;
00066
00067 WriterProc *write_bytes;
00068 ReaderProc *read_bytes;
00069
00070 const ChunkHandler * const *chs;
00071
00072
00073
00074 byte *bufp, *bufe;
00075
00076
00077 byte *buf;
00078 byte *buf_ori;
00079 uint bufsize;
00080 FILE *fh;
00081
00082 void (*excpt_uninit)();
00083 StringID error_str;
00084 char *extra_msg;
00085 } _sl;
00086
00087
00088 enum NeedLengthValues {NL_NONE = 0, NL_WANTLENGTH = 1, NL_CALCLENGTH = 2};
00089
00093 static void NORETURN SlError(StringID string, const char *extra_msg = NULL)
00094 {
00095 _sl.error_str = string;
00096 free(_sl.extra_msg);
00097 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00098 throw std::exception();
00099 }
00100
00101 typedef void (*AsyncSaveFinishProc)();
00102 static AsyncSaveFinishProc _async_save_finish = NULL;
00103 static ThreadObject *_save_thread;
00104
00108 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00109 {
00110 if (_exit_game) return;
00111 while (_async_save_finish != NULL) CSleep(10);
00112
00113 _async_save_finish = proc;
00114 }
00115
00119 void ProcessAsyncSaveFinish()
00120 {
00121 if (_async_save_finish == NULL) return;
00122
00123 _async_save_finish();
00124
00125 _async_save_finish = NULL;
00126
00127 if (_save_thread != NULL) {
00128 _save_thread->Join();
00129 delete _save_thread;
00130 _save_thread = NULL;
00131 }
00132 }
00133
00137 static void SlReadFill()
00138 {
00139 size_t len = _sl.read_bytes();
00140 if (len == 0) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected end of chunk");
00141
00142 _sl.bufp = _sl.buf;
00143 _sl.bufe = _sl.buf + len;
00144 _sl.offs_base += len;
00145 }
00146
00147 static inline size_t SlGetOffs() {return _sl.offs_base - (_sl.bufe - _sl.bufp);}
00148
00153 static inline byte SlCalcConvMemLen(VarType conv)
00154 {
00155 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00156 byte length = GB(conv, 4, 4);
00157 assert(length < lengthof(conv_mem_size));
00158 return conv_mem_size[length];
00159 }
00160
00165 static inline byte SlCalcConvFileLen(VarType conv)
00166 {
00167 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00168 byte length = GB(conv, 0, 4);
00169 assert(length < lengthof(conv_file_size));
00170 return conv_file_size[length];
00171 }
00172
00174 static inline size_t SlCalcRefLen() {return CheckSavegameVersion(69) ? 2 : 4;}
00175
00180 static void SlWriteFill()
00181 {
00182
00183 if (_sl.bufp != NULL) {
00184 uint len = _sl.bufp - _sl.buf;
00185 _sl.offs_base += len;
00186 if (len) _sl.write_bytes(len);
00187 }
00188
00189
00190
00191 _sl.bufp = _sl.buf;
00192 _sl.bufe = _sl.buf + _sl.bufsize;
00193 }
00194
00199 static inline byte SlReadByteInternal()
00200 {
00201 if (_sl.bufp == _sl.bufe) SlReadFill();
00202 return *_sl.bufp++;
00203 }
00204
00206 byte SlReadByte() {return SlReadByteInternal();}
00207
00212 static inline void SlWriteByteInternal(byte b)
00213 {
00214 if (_sl.bufp == _sl.bufe) SlWriteFill();
00215 *_sl.bufp++ = b;
00216 }
00217
00219 void SlWriteByte(byte b) {SlWriteByteInternal(b);}
00220
00221 static inline int SlReadUint16()
00222 {
00223 int x = SlReadByte() << 8;
00224 return x | SlReadByte();
00225 }
00226
00227 static inline uint32 SlReadUint32()
00228 {
00229 uint32 x = SlReadUint16() << 16;
00230 return x | SlReadUint16();
00231 }
00232
00233 static inline uint64 SlReadUint64()
00234 {
00235 uint32 x = SlReadUint32();
00236 uint32 y = SlReadUint32();
00237 return (uint64)x << 32 | y;
00238 }
00239
00240 static inline void SlWriteUint16(uint16 v)
00241 {
00242 SlWriteByte(GB(v, 8, 8));
00243 SlWriteByte(GB(v, 0, 8));
00244 }
00245
00246 static inline void SlWriteUint32(uint32 v)
00247 {
00248 SlWriteUint16(GB(v, 16, 16));
00249 SlWriteUint16(GB(v, 0, 16));
00250 }
00251
00252 static inline void SlWriteUint64(uint64 x)
00253 {
00254 SlWriteUint32((uint32)(x >> 32));
00255 SlWriteUint32((uint32)x);
00256 }
00257
00267 static uint SlReadSimpleGamma()
00268 {
00269 uint i = SlReadByte();
00270 if (HasBit(i, 7)) {
00271 i &= ~0x80;
00272 if (HasBit(i, 6)) {
00273 i &= ~0x40;
00274 if (HasBit(i, 5)) {
00275 i &= ~0x20;
00276 if (HasBit(i, 4))
00277 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unsupported gamma");
00278 i = (i << 8) | SlReadByte();
00279 }
00280 i = (i << 8) | SlReadByte();
00281 }
00282 i = (i << 8) | SlReadByte();
00283 }
00284 return i;
00285 }
00286
00299 static void SlWriteSimpleGamma(size_t i)
00300 {
00301 if (i >= (1 << 7)) {
00302 if (i >= (1 << 14)) {
00303 if (i >= (1 << 21)) {
00304 assert(i < (1 << 28));
00305 SlWriteByte((byte)(0xE0 | (i >> 24)));
00306 SlWriteByte((byte)(i >> 16));
00307 } else {
00308 SlWriteByte((byte)(0xC0 | (i >> 16)));
00309 }
00310 SlWriteByte((byte)(i >> 8));
00311 } else {
00312 SlWriteByte((byte)(0x80 | (i >> 8)));
00313 }
00314 }
00315 SlWriteByte((byte)i);
00316 }
00317
00319 static inline uint SlGetGammaLength(size_t i)
00320 {
00321 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00322 }
00323
00324 static inline uint SlReadSparseIndex() {return SlReadSimpleGamma();}
00325 static inline void SlWriteSparseIndex(uint index) {SlWriteSimpleGamma(index);}
00326
00327 static inline uint SlReadArrayLength() {return SlReadSimpleGamma();}
00328 static inline void SlWriteArrayLength(size_t length) {SlWriteSimpleGamma(length);}
00329 static inline uint SlGetArrayLength(size_t length) {return SlGetGammaLength(length);}
00330
00331 void SlSetArrayIndex(uint index)
00332 {
00333 _sl.need_length = NL_WANTLENGTH;
00334 _sl.array_index = index;
00335 }
00336
00337 static size_t _next_offs;
00338
00343 int SlIterateArray()
00344 {
00345 int index;
00346
00347
00348
00349 if (_next_offs != 0 && SlGetOffs() != _next_offs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
00350
00351 while (true) {
00352 uint length = SlReadArrayLength();
00353 if (length == 0) {
00354 _next_offs = 0;
00355 return -1;
00356 }
00357
00358 _sl.obj_len = --length;
00359 _next_offs = SlGetOffs() + length;
00360
00361 switch (_sl.block_mode) {
00362 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00363 case CH_ARRAY: index = _sl.array_index++; break;
00364 default:
00365 DEBUG(sl, 0, "SlIterateArray error");
00366 return -1;
00367 }
00368
00369 if (length != 0) return index;
00370 }
00371 }
00372
00378 void SlSetLength(size_t length)
00379 {
00380 assert(_sl.save);
00381
00382 switch (_sl.need_length) {
00383 case NL_WANTLENGTH:
00384 _sl.need_length = NL_NONE;
00385 switch (_sl.block_mode) {
00386 case CH_RIFF:
00387
00388
00389
00390 assert(length < (1 << 28));
00391 SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00392 break;
00393 case CH_ARRAY:
00394 assert(_sl.last_array_index <= _sl.array_index);
00395 while (++_sl.last_array_index <= _sl.array_index)
00396 SlWriteArrayLength(1);
00397 SlWriteArrayLength(length + 1);
00398 break;
00399 case CH_SPARSE_ARRAY:
00400 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00401 SlWriteSparseIndex(_sl.array_index);
00402 break;
00403 default: NOT_REACHED();
00404 } break;
00405 case NL_CALCLENGTH:
00406 _sl.obj_len += (int)length;
00407 break;
00408 }
00409 }
00410
00417 static void SlCopyBytes(void *ptr, size_t length)
00418 {
00419 byte *p = (byte*)ptr;
00420
00421 if (_sl.save) {
00422 for (; length != 0; length--) {SlWriteByteInternal(*p++);}
00423 } else {
00424 for (; length != 0; length--) {*p++ = SlReadByteInternal();}
00425 }
00426 }
00427
00432 static inline void SlSkipBytes(size_t length)
00433 {
00434 for (; length != 0; length--) SlReadByte();
00435 }
00436
00437
00438 size_t SlGetFieldLength() {return _sl.obj_len;}
00439
00445 int64 ReadValue(const void *ptr, VarType conv)
00446 {
00447 switch (GetVarMemType(conv)) {
00448 case SLE_VAR_BL: return (*(bool*)ptr != 0);
00449 case SLE_VAR_I8: return *(int8* )ptr;
00450 case SLE_VAR_U8: return *(byte* )ptr;
00451 case SLE_VAR_I16: return *(int16* )ptr;
00452 case SLE_VAR_U16: return *(uint16*)ptr;
00453 case SLE_VAR_I32: return *(int32* )ptr;
00454 case SLE_VAR_U32: return *(uint32*)ptr;
00455 case SLE_VAR_I64: return *(int64* )ptr;
00456 case SLE_VAR_U64: return *(uint64*)ptr;
00457 case SLE_VAR_NULL:return 0;
00458 default: NOT_REACHED();
00459 }
00460
00461
00462 return 0;
00463 }
00464
00470 void WriteValue(void *ptr, VarType conv, int64 val)
00471 {
00472 switch (GetVarMemType(conv)) {
00473 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00474 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00475 case SLE_VAR_U8: *(byte *)ptr = val; break;
00476 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00477 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00478 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00479 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00480 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00481 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00482 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00483 case SLE_VAR_NULL: break;
00484 default: NOT_REACHED();
00485 }
00486 }
00487
00496 static void SlSaveLoadConv(void *ptr, VarType conv)
00497 {
00498 int64 x = 0;
00499
00500 if (_sl.save) {
00501
00502 x = ReadValue(ptr, conv);
00503
00504
00505 switch (GetVarFileType(conv)) {
00506 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00507 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00508 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00509 case SLE_FILE_STRINGID:
00510 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00511 case SLE_FILE_I32:
00512 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00513 case SLE_FILE_I64:
00514 case SLE_FILE_U64: SlWriteUint64(x);break;
00515 default: NOT_REACHED();
00516 }
00517 } else {
00518
00519
00520 switch (GetVarFileType(conv)) {
00521 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00522 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00523 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00524 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00525 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00526 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00527 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00528 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00529 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00530 default: NOT_REACHED();
00531 }
00532
00533
00534 WriteValue(ptr, conv, x);
00535 }
00536 }
00537
00545 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
00546 {
00547 if (ptr == NULL) return 0;
00548 return min(strlen(ptr), length - 1);
00549 }
00550
00558 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
00559 {
00560 size_t len;
00561 const char *str;
00562
00563 switch (GetVarMemType(conv)) {
00564 default: NOT_REACHED();
00565 case SLE_VAR_STR:
00566 case SLE_VAR_STRQ:
00567 str = *(const char**)ptr;
00568 len = SIZE_MAX;
00569 break;
00570 case SLE_VAR_STRB:
00571 case SLE_VAR_STRBQ:
00572 str = (const char*)ptr;
00573 len = length;
00574 break;
00575 }
00576
00577 len = SlCalcNetStringLen(str, len);
00578 return len + SlGetArrayLength(len);
00579 }
00580
00586 static void SlString(void *ptr, size_t length, VarType conv)
00587 {
00588 size_t len;
00589
00590 if (_sl.save) {
00591 switch (GetVarMemType(conv)) {
00592 default: NOT_REACHED();
00593 case SLE_VAR_STRB:
00594 case SLE_VAR_STRBQ:
00595 len = SlCalcNetStringLen((char*)ptr, length);
00596 break;
00597 case SLE_VAR_STR:
00598 case SLE_VAR_STRQ:
00599 ptr = *(char**)ptr;
00600 len = SlCalcNetStringLen((char*)ptr, SIZE_MAX);
00601 break;
00602 }
00603
00604 SlWriteArrayLength(len);
00605 SlCopyBytes(ptr, len);
00606 } else {
00607 len = SlReadArrayLength();
00608
00609 switch (GetVarMemType(conv)) {
00610 default: NOT_REACHED();
00611 case SLE_VAR_STRB:
00612 case SLE_VAR_STRBQ:
00613 if (len >= length) {
00614 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
00615 SlCopyBytes(ptr, length);
00616 SlSkipBytes(len - length);
00617 len = length - 1;
00618 } else {
00619 SlCopyBytes(ptr, len);
00620 }
00621 break;
00622 case SLE_VAR_STR:
00623 case SLE_VAR_STRQ:
00624 free(*(char**)ptr);
00625 if (len == 0) {
00626 *(char**)ptr = NULL;
00627 } else {
00628 *(char**)ptr = MallocT<char>(len + 1);
00629 ptr = *(char**)ptr;
00630 SlCopyBytes(ptr, len);
00631 }
00632 break;
00633 }
00634
00635 ((char*)ptr)[len] = '\0';
00636 str_validate((char*)ptr, (char*)ptr + len);
00637 }
00638 }
00639
00645 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
00646 {
00647 return SlCalcConvFileLen(conv) * length;
00648 }
00649
00656 void SlArray(void *array, size_t length, VarType conv)
00657 {
00658
00659 if (_sl.need_length != NL_NONE) {
00660 SlSetLength(SlCalcArrayLen(length, conv));
00661
00662 if (_sl.need_length == NL_CALCLENGTH) return;
00663 }
00664
00665
00666
00667 if (!_sl.save && _sl_version == 0) {
00668
00669 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
00670 conv == SLE_INT32 || conv == SLE_UINT32) {
00671 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
00672 return;
00673 }
00674
00675 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
00676 for (uint i = 0; i < length; i++) {
00677 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
00678 }
00679 return;
00680 }
00681 }
00682
00683
00684
00685 if (conv == SLE_INT8 || conv == SLE_UINT8) {
00686 SlCopyBytes(array, length);
00687 } else {
00688 byte *a = (byte*)array;
00689 byte mem_size = SlCalcConvMemLen(conv);
00690
00691 for (; length != 0; length --) {
00692 SlSaveLoadConv(a, conv);
00693 a += mem_size;
00694 }
00695 }
00696 }
00697
00698
00699 static uint ReferenceToInt(const void *obj, SLRefType rt);
00700 static void *IntToReference(uint index, SLRefType rt);
00701
00702
00707 static inline size_t SlCalcListLen(const void *list)
00708 {
00709 std::list<void *> *l = (std::list<void *> *) list;
00710
00711 int type_size = CheckSavegameVersion(69) ? 2 : 4;
00712
00713
00714 return l->size() * type_size + type_size;
00715 }
00716
00717
00723 void SlList(void *list, SLRefType conv)
00724 {
00725
00726 if (_sl.need_length != NL_NONE) {
00727 SlSetLength(SlCalcListLen(list));
00728
00729 if (_sl.need_length == NL_CALCLENGTH) return;
00730 }
00731
00732 std::list<void *> *l = (std::list<void *> *) list;
00733
00734 if (_sl.save) {
00735 SlWriteUint32((uint32)l->size());
00736
00737 std::list<void *>::iterator iter;
00738 for (iter = l->begin(); iter != l->end(); ++iter) {
00739 void *ptr = *iter;
00740 SlWriteUint32(ReferenceToInt(ptr, conv));
00741 }
00742 } else {
00743 uint length = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
00744
00745
00746 for (uint i = 0; i < length; i++) {
00747 void *ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), conv);
00748 l->push_back(ptr);
00749 }
00750 }
00751 }
00752
00753
00755 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
00756 {
00757 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
00758 if (sld->conv & SLF_SAVE_NO) return false;
00759
00760 return true;
00761 }
00762
00766 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
00767 {
00768 if ((sld->conv & SLF_NETWORK_NO) && !_sl.save && _networking && !_network_server) {
00769 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
00770 return true;
00771 }
00772
00773 return false;
00774 }
00775
00782 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
00783 {
00784 size_t length = 0;
00785
00786
00787 for (; sld->cmd != SL_END; sld++) {
00788 length += SlCalcObjMemberLength(object, sld);
00789 }
00790 return length;
00791 }
00792
00793 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
00794 {
00795 assert(_sl.save);
00796
00797 switch (sld->cmd) {
00798 case SL_VAR:
00799 case SL_REF:
00800 case SL_ARR:
00801 case SL_STR:
00802 case SL_LST:
00803
00804 if (!SlIsObjectValidInSavegame(sld)) break;
00805
00806 switch (sld->cmd) {
00807 case SL_VAR: return SlCalcConvFileLen(sld->conv);
00808 case SL_REF: return SlCalcRefLen();
00809 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
00810 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
00811 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
00812 default: NOT_REACHED();
00813 }
00814 break;
00815 case SL_WRITEBYTE: return 1;
00816 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
00817 default: NOT_REACHED();
00818 }
00819 return 0;
00820 }
00821
00822
00823 bool SlObjectMember(void *ptr, const SaveLoad *sld)
00824 {
00825 VarType conv = GB(sld->conv, 0, 8);
00826 switch (sld->cmd) {
00827 case SL_VAR:
00828 case SL_REF:
00829 case SL_ARR:
00830 case SL_STR:
00831 case SL_LST:
00832
00833 if (!SlIsObjectValidInSavegame(sld)) return false;
00834 if (SlSkipVariableOnLoad(sld)) return false;
00835
00836 switch (sld->cmd) {
00837 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
00838 case SL_REF:
00839 if (_sl.save) {
00840 SlWriteUint32(ReferenceToInt(*(void**)ptr, (SLRefType)conv));
00841 } else {
00842 *(void**)ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), (SLRefType)conv);
00843 }
00844 break;
00845 case SL_ARR: SlArray(ptr, sld->length, conv); break;
00846 case SL_STR: SlString(ptr, sld->length, conv); break;
00847 case SL_LST: SlList(ptr, (SLRefType)conv); break;
00848 default: NOT_REACHED();
00849 }
00850 break;
00851
00852
00853
00854
00855
00856
00857 case SL_WRITEBYTE:
00858 if (_sl.save) {
00859 SlWriteByte(sld->version_to);
00860 } else {
00861 *(byte*)ptr = sld->version_from;
00862 }
00863 break;
00864
00865
00866 case SL_VEH_INCLUDE:
00867 SlObject(ptr, GetVehicleDescription(VEH_END));
00868 break;
00869 default: NOT_REACHED();
00870 }
00871 return true;
00872 }
00873
00879 void SlObject(void *object, const SaveLoad *sld)
00880 {
00881
00882 if (_sl.need_length != NL_NONE) {
00883 SlSetLength(SlCalcObjLength(object, sld));
00884 if (_sl.need_length == NL_CALCLENGTH) return;
00885 }
00886
00887 for (; sld->cmd != SL_END; sld++) {
00888 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
00889 SlObjectMember(ptr, sld);
00890 }
00891 }
00892
00897 void SlGlobList(const SaveLoadGlobVarList *sldg)
00898 {
00899 SlObject(NULL, (const SaveLoad*)sldg);
00900 }
00901
00907 void SlAutolength(AutolengthProc *proc, void *arg)
00908 {
00909 size_t offs;
00910
00911 assert(_sl.save);
00912
00913
00914 _sl.need_length = NL_CALCLENGTH;
00915 _sl.obj_len = 0;
00916 proc(arg);
00917
00918
00919 _sl.need_length = NL_WANTLENGTH;
00920 SlSetLength(_sl.obj_len);
00921
00922 offs = SlGetOffs() + _sl.obj_len;
00923
00924
00925 proc(arg);
00926
00927 if (offs != SlGetOffs()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
00928 }
00929
00934 static void SlLoadChunk(const ChunkHandler *ch)
00935 {
00936 byte m = SlReadByte();
00937 size_t len;
00938 size_t endoffs;
00939
00940 _sl.block_mode = m;
00941 _sl.obj_len = 0;
00942
00943 switch (m) {
00944 case CH_ARRAY:
00945 _sl.array_index = 0;
00946 ch->load_proc();
00947 break;
00948 case CH_SPARSE_ARRAY:
00949 ch->load_proc();
00950 break;
00951 default:
00952 if ((m & 0xF) == CH_RIFF) {
00953
00954 len = (SlReadByte() << 16) | ((m >> 4) << 24);
00955 len += SlReadUint16();
00956 _sl.obj_len = len;
00957 endoffs = SlGetOffs() + len;
00958 ch->load_proc();
00959 if (SlGetOffs() != endoffs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
00960 } else {
00961 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk type");
00962 }
00963 break;
00964 }
00965 }
00966
00967
00968 static ChunkSaveLoadProc *_tmp_proc_1;
00969 static inline void SlStubSaveProc2(void *arg) {_tmp_proc_1();}
00970 static void SlStubSaveProc() {SlAutolength(SlStubSaveProc2, NULL);}
00971
00976 static void SlSaveChunk(const ChunkHandler *ch)
00977 {
00978 ChunkSaveLoadProc *proc = ch->save_proc;
00979
00980
00981 if (proc == NULL) return;
00982
00983 SlWriteUint32(ch->id);
00984 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00985
00986 if (ch->flags & CH_AUTO_LENGTH) {
00987
00988 _tmp_proc_1 = proc;
00989 proc = SlStubSaveProc;
00990 }
00991
00992 _sl.block_mode = ch->flags & CH_TYPE_MASK;
00993 switch (ch->flags & CH_TYPE_MASK) {
00994 case CH_RIFF:
00995 _sl.need_length = NL_WANTLENGTH;
00996 proc();
00997 break;
00998 case CH_ARRAY:
00999 _sl.last_array_index = 0;
01000 SlWriteByte(CH_ARRAY);
01001 proc();
01002 SlWriteArrayLength(0);
01003 break;
01004 case CH_SPARSE_ARRAY:
01005 SlWriteByte(CH_SPARSE_ARRAY);
01006 proc();
01007 SlWriteArrayLength(0);
01008 break;
01009 default: NOT_REACHED();
01010 }
01011 }
01012
01014 static void SlSaveChunks()
01015 {
01016 const ChunkHandler *ch;
01017 const ChunkHandler * const *chsc;
01018 uint p;
01019
01020 for (p = 0; p != CH_NUM_PRI_LEVELS; p++) {
01021 for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
01022 while (true) {
01023 if (((ch->flags >> CH_PRI_SHL) & (CH_NUM_PRI_LEVELS - 1)) == p)
01024 SlSaveChunk(ch);
01025 if (ch->flags & CH_LAST)
01026 break;
01027 ch++;
01028 }
01029 }
01030 }
01031
01032
01033 SlWriteUint32(0);
01034 }
01035
01041 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01042 {
01043 const ChunkHandler *ch;
01044 const ChunkHandler *const *chsc;
01045 for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
01046 for (;;) {
01047 if (ch->id == id) return ch;
01048 if (ch->flags & CH_LAST) break;
01049 ch++;
01050 }
01051 }
01052 return NULL;
01053 }
01054
01056 static void SlLoadChunks()
01057 {
01058 uint32 id;
01059 const ChunkHandler *ch;
01060
01061 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01062 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01063
01064 ch = SlFindChunkHandler(id);
01065 if (ch == NULL) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unknown chunk type");
01066 SlLoadChunk(ch);
01067 }
01068 }
01069
01070
01071
01072
01073 #define LZO_SIZE 8192
01074
01075 #include "../minilzo.h"
01076
01077 static size_t ReadLZO()
01078 {
01079 byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
01080 uint32 tmp[2];
01081 uint32 size;
01082 uint len;
01083
01084
01085 if (fread(tmp, sizeof(tmp), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01086
01087
01088 ((uint32*)out)[0] = size = tmp[1];
01089
01090 if (_sl_version != 0) {
01091 tmp[0] = TO_BE32(tmp[0]);
01092 size = TO_BE32(size);
01093 }
01094
01095 if (size >= sizeof(out)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Inconsistent size");
01096
01097
01098 if (fread(out + sizeof(uint32), size, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01099
01100
01101 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Bad checksum");
01102
01103
01104 lzo1x_decompress(out + sizeof(uint32) * 1, size, _sl.buf, &len, NULL);
01105 return len;
01106 }
01107
01108
01109
01110 static void WriteLZO(size_t size)
01111 {
01112 byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
01113 byte wrkmem[sizeof(byte*) * 4096];
01114 uint outlen;
01115
01116 lzo1x_1_compress(_sl.buf, (lzo_uint)size, out + sizeof(uint32) * 2, &outlen, wrkmem);
01117 ((uint32*)out)[1] = TO_BE32(outlen);
01118 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01119 if (fwrite(out, outlen + sizeof(uint32) * 2, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01120 }
01121
01122 static bool InitLZO()
01123 {
01124 _sl.bufsize = LZO_SIZE;
01125 _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
01126 return true;
01127 }
01128
01129 static void UninitLZO()
01130 {
01131 free(_sl.buf_ori);
01132 }
01133
01134
01135
01136
01137 static size_t ReadNoComp()
01138 {
01139 return fread(_sl.buf, 1, LZO_SIZE, _sl.fh);
01140 }
01141
01142 static void WriteNoComp(size_t size)
01143 {
01144 if (fwrite(_sl.buf, 1, size, _sl.fh) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01145 }
01146
01147 static bool InitNoComp()
01148 {
01149 _sl.bufsize = LZO_SIZE;
01150 _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
01151 return true;
01152 }
01153
01154 static void UninitNoComp()
01155 {
01156 free(_sl.buf_ori);
01157 }
01158
01159
01160
01161
01162
01163 #include "../gui.h"
01164
01165 struct ThreadedSave {
01166 uint count;
01167 byte ff_state;
01168 bool saveinprogress;
01169 CursorID cursor;
01170 };
01171
01172
01173 STATIC_OLD_POOL(Savegame, byte, 17, 500, NULL, NULL)
01174 static ThreadedSave _ts;
01175
01176 static bool InitMem()
01177 {
01178 _ts.count = 0;
01179
01180 _Savegame_pool.CleanPool();
01181 _Savegame_pool.AddBlockToPool();
01182
01183
01184 _sl.bufsize = GetSavegamePoolSize();
01185 _sl.buf = GetSavegame(_ts.count);
01186 return true;
01187 }
01188
01189 static void UnInitMem()
01190 {
01191 _Savegame_pool.CleanPool();
01192 }
01193
01194 static void WriteMem(size_t size)
01195 {
01196 _ts.count += (uint)size;
01197
01198 _Savegame_pool.AddBlockIfNeeded(_ts.count);
01199 _sl.buf = GetSavegame(_ts.count);
01200 }
01201
01202
01203
01204
01205
01206 #if defined(WITH_ZLIB)
01207 #include <zlib.h>
01208
01209 static z_stream _z;
01210
01211 static bool InitReadZlib()
01212 {
01213 memset(&_z, 0, sizeof(_z));
01214 if (inflateInit(&_z) != Z_OK) return false;
01215
01216 _sl.bufsize = 4096;
01217 _sl.buf = _sl.buf_ori = MallocT<byte>(4096 + 4096);
01218 return true;
01219 }
01220
01221 static size_t ReadZlib()
01222 {
01223 int r;
01224
01225 _z.next_out = _sl.buf;
01226 _z.avail_out = 4096;
01227
01228 do {
01229
01230 if (_z.avail_in == 0) {
01231 _z.avail_in = (uint)fread(_z.next_in = _sl.buf + 4096, 1, 4096, _sl.fh);
01232 }
01233
01234
01235 r = inflate(&_z, 0);
01236 if (r == Z_STREAM_END)
01237 break;
01238
01239 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
01240 } while (_z.avail_out);
01241
01242 return 4096 - _z.avail_out;
01243 }
01244
01245 static void UninitReadZlib()
01246 {
01247 inflateEnd(&_z);
01248 free(_sl.buf_ori);
01249 }
01250
01251 static bool InitWriteZlib()
01252 {
01253 memset(&_z, 0, sizeof(_z));
01254 if (deflateInit(&_z, 6) != Z_OK) return false;
01255
01256 _sl.bufsize = 4096;
01257 _sl.buf = _sl.buf_ori = MallocT<byte>(4096);
01258 return true;
01259 }
01260
01261 static void WriteZlibLoop(z_streamp z, byte *p, size_t len, int mode)
01262 {
01263 byte buf[1024];
01264 int r;
01265 uint n;
01266 z->next_in = p;
01267 z->avail_in = (uInt)len;
01268 do {
01269 z->next_out = buf;
01270 z->avail_out = sizeof(buf);
01271
01279 r = deflate(z, mode);
01280
01281
01282 if ((n = sizeof(buf) - z->avail_out) != 0) {
01283 if (fwrite(buf, n, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01284 }
01285 if (r == Z_STREAM_END)
01286 break;
01287 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
01288 } while (z->avail_in || !z->avail_out);
01289 }
01290
01291 static void WriteZlib(size_t len)
01292 {
01293 WriteZlibLoop(&_z, _sl.buf, len, 0);
01294 }
01295
01296 static void UninitWriteZlib()
01297 {
01298
01299 if (_sl.fh) WriteZlibLoop(&_z, NULL, 0, Z_FINISH);
01300 deflateEnd(&_z);
01301 free(_sl.buf_ori);
01302 }
01303
01304 #endif
01305
01306
01307
01308
01309
01310
01311 extern const ChunkHandler _gamelog_chunk_handlers[];
01312 extern const ChunkHandler _map_chunk_handlers[];
01313 extern const ChunkHandler _misc_chunk_handlers[];
01314 extern const ChunkHandler _name_chunk_handlers[];
01315 extern const ChunkHandler _cheat_chunk_handlers[] ;
01316 extern const ChunkHandler _setting_chunk_handlers[];
01317 extern const ChunkHandler _company_chunk_handlers[];
01318 extern const ChunkHandler _engine_chunk_handlers[];
01319 extern const ChunkHandler _veh_chunk_handlers[];
01320 extern const ChunkHandler _waypoint_chunk_handlers[];
01321 extern const ChunkHandler _depot_chunk_handlers[];
01322 extern const ChunkHandler _order_chunk_handlers[];
01323 extern const ChunkHandler _town_chunk_handlers[];
01324 extern const ChunkHandler _sign_chunk_handlers[];
01325 extern const ChunkHandler _station_chunk_handlers[];
01326 extern const ChunkHandler _industry_chunk_handlers[];
01327 extern const ChunkHandler _economy_chunk_handlers[];
01328 extern const ChunkHandler _subsidy_chunk_handlers[];
01329 extern const ChunkHandler _ai_chunk_handlers[];
01330 extern const ChunkHandler _animated_tile_chunk_handlers[];
01331 extern const ChunkHandler _newgrf_chunk_handlers[];
01332 extern const ChunkHandler _group_chunk_handlers[];
01333 extern const ChunkHandler _cargopacket_chunk_handlers[];
01334 extern const ChunkHandler _autoreplace_chunk_handlers[];
01335
01336 static const ChunkHandler * const _chunk_handlers[] = {
01337 _gamelog_chunk_handlers,
01338 _map_chunk_handlers,
01339 _misc_chunk_handlers,
01340 _name_chunk_handlers,
01341 _cheat_chunk_handlers,
01342 _setting_chunk_handlers,
01343 _veh_chunk_handlers,
01344 _waypoint_chunk_handlers,
01345 _depot_chunk_handlers,
01346 _order_chunk_handlers,
01347 _industry_chunk_handlers,
01348 _economy_chunk_handlers,
01349 _subsidy_chunk_handlers,
01350 _engine_chunk_handlers,
01351 _town_chunk_handlers,
01352 _sign_chunk_handlers,
01353 _station_chunk_handlers,
01354 _company_chunk_handlers,
01355 _ai_chunk_handlers,
01356 _animated_tile_chunk_handlers,
01357 _newgrf_chunk_handlers,
01358 _group_chunk_handlers,
01359 _cargopacket_chunk_handlers,
01360 _autoreplace_chunk_handlers,
01361 NULL,
01362 };
01363
01374 static uint ReferenceToInt(const void *obj, SLRefType rt)
01375 {
01376 if (obj == NULL) return 0;
01377
01378 switch (rt) {
01379 case REF_VEHICLE_OLD:
01380 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01381 case REF_STATION: return ((const Station*)obj)->index + 1;
01382 case REF_TOWN: return ((const Town*)obj)->index + 1;
01383 case REF_ORDER: return ((const Order*)obj)->index + 1;
01384 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01385 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01386 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01387 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01388 default: NOT_REACHED();
01389 }
01390
01391 return 0;
01392 }
01393
01404 static void *IntToReference(uint index, SLRefType rt)
01405 {
01406
01407
01408 if (rt == REF_VEHICLE_OLD && !CheckSavegameVersionOldStyle(4, 4)) {
01409 rt = REF_VEHICLE;
01410 }
01411
01412
01413 if (rt != REF_VEHICLE_OLD && index == 0) {
01414 return NULL;
01415 }
01416
01417 index--;
01418
01419 switch (rt) {
01420 case REF_ORDERLIST:
01421 if (_OrderList_pool.AddBlockIfNeeded(index)) return GetOrderList(index);
01422 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "OrderList index out of range");
01423
01424 case REF_ORDER:
01425 if (_Order_pool.AddBlockIfNeeded(index)) return GetOrder(index);
01426 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Order index out of range");
01427
01428 case REF_VEHICLE:
01429 if (_Vehicle_pool.AddBlockIfNeeded(index)) return GetVehicle(index);
01430 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Vehicle index out of range");
01431
01432 case REF_STATION:
01433 if (_Station_pool.AddBlockIfNeeded(index)) return GetStation(index);
01434 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Station index out of range");
01435
01436 case REF_TOWN:
01437 if (_Town_pool.AddBlockIfNeeded(index)) return GetTown(index);
01438 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Town index out of range");
01439
01440 case REF_ROADSTOPS:
01441 if (_RoadStop_pool.AddBlockIfNeeded(index)) return GetRoadStop(index);
01442 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "RoadStop index out of range");
01443
01444 case REF_ENGINE_RENEWS:
01445 if (_EngineRenew_pool.AddBlockIfNeeded(index)) return GetEngineRenew(index);
01446 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "EngineRenew index out of range");
01447
01448 case REF_CARGO_PACKET:
01449 if (_CargoPacket_pool.AddBlockIfNeeded(index)) return GetCargoPacket(index);
01450 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "CargoPacket index out of range");
01451
01452 case REF_VEHICLE_OLD:
01453
01454
01455
01456 index++;
01457 if (index == INVALID_VEHICLE) return NULL;
01458
01459 if (_Vehicle_pool.AddBlockIfNeeded(index)) return GetVehicle(index);
01460 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Vehicle index out of range");
01461
01462 default: NOT_REACHED();
01463 }
01464
01465 return NULL;
01466 }
01467
01469 struct SaveLoadFormat {
01470 const char *name;
01471 uint32 tag;
01472
01473 bool (*init_read)();
01474 ReaderProc *reader;
01475 void (*uninit_read)();
01476
01477 bool (*init_write)();
01478 WriterProc *writer;
01479 void (*uninit_write)();
01480 };
01481
01482 static const SaveLoadFormat _saveload_formats[] = {
01483 {"memory", 0, NULL, NULL, NULL, InitMem, WriteMem, UnInitMem},
01484 {"lzo", TO_BE32X('OTTD'), InitLZO, ReadLZO, UninitLZO, InitLZO, WriteLZO, UninitLZO},
01485 {"none", TO_BE32X('OTTN'), InitNoComp, ReadNoComp, UninitNoComp, InitNoComp, WriteNoComp, UninitNoComp},
01486 #if defined(WITH_ZLIB)
01487 {"zlib", TO_BE32X('OTTZ'), InitReadZlib, ReadZlib, UninitReadZlib, InitWriteZlib, WriteZlib, UninitWriteZlib},
01488 #else
01489 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, NULL, NULL, NULL, NULL},
01490 #endif
01491 };
01492
01499 static const SaveLoadFormat *GetSavegameFormat(const char *s)
01500 {
01501 const SaveLoadFormat *def = endof(_saveload_formats) - 1;
01502
01503
01504 while (!def->init_write) def--;
01505
01506 if (s != NULL && s[0] != '\0') {
01507 const SaveLoadFormat *slf;
01508 for (slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
01509 if (slf->init_write != NULL && strcmp(s, slf->name) == 0)
01510 return slf;
01511 }
01512
01513 ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
01514 }
01515 return def;
01516 }
01517
01518
01519 void InitializeGame(uint size_x, uint size_y, bool reset_date);
01520 extern bool AfterLoadGame();
01521 extern bool LoadOldSaveGame(const char *file);
01522
01524 static inline SaveOrLoadResult AbortSaveLoad()
01525 {
01526 if (_sl.fh != NULL) fclose(_sl.fh);
01527
01528 _sl.fh = NULL;
01529 return SL_ERROR;
01530 }
01531
01535 static void SaveFileStart()
01536 {
01537 _ts.ff_state = _fast_forward;
01538 _fast_forward = 0;
01539 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
01540
01541 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
01542 _ts.saveinprogress = true;
01543 }
01544
01547 static void SaveFileDone()
01548 {
01549 if (_game_mode != GM_MENU) _fast_forward = _ts.ff_state;
01550 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
01551
01552 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
01553 _ts.saveinprogress = false;
01554 }
01555
01557 void SetSaveLoadError(StringID str)
01558 {
01559 _sl.error_str = str;
01560 }
01561
01563 const char *GetSaveLoadErrorString()
01564 {
01565 SetDParam(0, _sl.error_str);
01566 SetDParamStr(1, _sl.extra_msg);
01567
01568 static char err_str[512];
01569 GetString(err_str, _sl.save ? STR_4007_GAME_SAVE_FAILED : STR_4009_GAME_LOAD_FAILED, lastof(err_str));
01570 return err_str;
01571 }
01572
01574 static void SaveFileError()
01575 {
01576 SetDParamStr(0, GetSaveLoadErrorString());
01577 ShowErrorMessage(STR_JUST_RAW_STRING, STR_NULL, 0, 0);
01578 SaveFileDone();
01579 }
01580
01584 static SaveOrLoadResult SaveFileToDisk(bool threaded)
01585 {
01586 const SaveLoadFormat *fmt;
01587 uint32 hdr[2];
01588
01589 _sl.excpt_uninit = NULL;
01590 try {
01591 fmt = GetSavegameFormat(_savegame_format);
01592
01593
01594 hdr[0] = fmt->tag;
01595 hdr[1] = TO_BE32(SAVEGAME_VERSION << 16);
01596 if (fwrite(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01597
01598 if (!fmt->init_write()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01599
01600 {
01601 uint i;
01602 uint count = 1 << Savegame_POOL_BLOCK_SIZE_BITS;
01603
01604 if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
01605 for (i = 0; i != _Savegame_pool.GetBlockCount() - 1; i++) {
01606 _sl.buf = _Savegame_pool.blocks[i];
01607 fmt->writer(count);
01608 }
01609
01610
01611
01612 _sl.buf = _Savegame_pool.blocks[i];
01613 fmt->writer(_ts.count - (i * count));
01614 }
01615
01616 fmt->uninit_write();
01617 if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
01618 GetSavegameFormat("memory")->uninit_write();
01619 fclose(_sl.fh);
01620
01621 if (threaded) SetAsyncSaveFinish(SaveFileDone);
01622
01623 return SL_OK;
01624 }
01625 catch (...) {
01626 AbortSaveLoad();
01627 if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
01628
01629
01630 DEBUG(sl, 0, GetSaveLoadErrorString() + 3);
01631
01632 if (threaded) {
01633 SetAsyncSaveFinish(SaveFileError);
01634 } else {
01635 SaveFileError();
01636 }
01637 return SL_ERROR;
01638 }
01639 }
01640
01641 static void SaveFileToDiskThread(void *arg)
01642 {
01643 SaveFileToDisk(true);
01644 }
01645
01646 void WaitTillSaved()
01647 {
01648 if (_save_thread == NULL) return;
01649
01650 _save_thread->Join();
01651 delete _save_thread;
01652 _save_thread = NULL;
01653 }
01654
01662 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb)
01663 {
01664 uint32 hdr[2];
01665 const SaveLoadFormat *fmt;
01666
01667
01668 if (_ts.saveinprogress && mode == SL_SAVE) {
01669
01670 if (!_do_autosave) ShowErrorMessage(INVALID_STRING_ID, STR_SAVE_STILL_IN_PROGRESS, 0, 0);
01671 return SL_OK;
01672 }
01673 WaitTillSaved();
01674
01675 _next_offs = 0;
01676
01677
01678 if (mode == SL_OLD_LOAD) {
01679 _engine_mngr.ResetToDefaultMapping();
01680 InitializeGame(256, 256, true);
01681 GamelogReset();
01682 if (!LoadOldSaveGame(filename)) return SL_REINIT;
01683 _sl_version = 0;
01684 _sl_minor_version = 0;
01685 GamelogStartAction(GLAT_LOAD);
01686 if (!AfterLoadGame()) {
01687 GamelogStopAction();
01688 return SL_REINIT;
01689 }
01690 GamelogStopAction();
01691 return SL_OK;
01692 }
01693
01694 _sl.excpt_uninit = NULL;
01695 try {
01696 _sl.fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
01697
01698
01699 if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", SAVE_DIR);
01700 if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", BASE_DIR);
01701
01702 if (_sl.fh == NULL) {
01703 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01704 }
01705
01706 _sl.bufe = _sl.bufp = NULL;
01707 _sl.offs_base = 0;
01708 _sl.save = (mode != 0);
01709 _sl.chs = _chunk_handlers;
01710
01711
01712
01713 if (mode == SL_SAVE) {
01714 DEBUG(desync, 1, "save: %s\n", filename);
01715 fmt = GetSavegameFormat("memory");
01716
01717 _sl.write_bytes = fmt->writer;
01718 _sl.excpt_uninit = fmt->uninit_write;
01719 if (!fmt->init_write()) {
01720 DEBUG(sl, 0, "Initializing writer '%s' failed.", fmt->name);
01721 return AbortSaveLoad();
01722 }
01723
01724 _sl_version = SAVEGAME_VERSION;
01725
01726 SaveViewportBeforeSaveGame();
01727 SlSaveChunks();
01728 SlWriteFill();
01729
01730 SaveFileStart();
01731 if (_network_server ||
01732 !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
01733 if (!_network_server) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
01734
01735 SaveOrLoadResult result = SaveFileToDisk(false);
01736 SaveFileDone();
01737
01738 return result;
01739 }
01740 } else {
01741 assert(mode == SL_LOAD);
01742 DEBUG(desync, 1, "load: %s\n", filename);
01743
01744
01745 long pos = ftell(_sl.fh);
01746 if (fread(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01747
01748
01749 for (fmt = _saveload_formats; ; fmt++) {
01750
01751 if (fmt == endof(_saveload_formats)) {
01752 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
01753 clearerr(_sl.fh);
01754 fseek(_sl.fh, pos, SEEK_SET);
01755 _sl_version = 0;
01756 _sl_minor_version = 0;
01757 fmt = _saveload_formats + 1;
01758 break;
01759 }
01760
01761 if (fmt->tag == hdr[0]) {
01762
01763 _sl_version = TO_BE32(hdr[1]) >> 16;
01764
01765
01766
01767
01768 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
01769
01770 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
01771
01772
01773 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
01774 break;
01775 }
01776 }
01777
01778 _sl.read_bytes = fmt->reader;
01779 _sl.excpt_uninit = fmt->uninit_read;
01780
01781
01782 if (fmt->init_read == NULL) {
01783 char err_str[64];
01784 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
01785 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
01786 }
01787
01788 if (!fmt->init_read()) {
01789 char err_str[64];
01790 snprintf(err_str, lengthof(err_str), "Initializing loader '%s' failed", fmt->name);
01791 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
01792 }
01793
01794 _engine_mngr.ResetToDefaultMapping();
01795
01796
01797
01798
01799 InitializeGame(256, 256, true);
01800
01801 GamelogReset();
01802
01803 SlLoadChunks();
01804 fmt->uninit_read();
01805 fclose(_sl.fh);
01806
01807 GamelogStartAction(GLAT_LOAD);
01808
01809 _savegame_type = SGT_OTTD;
01810
01811
01812
01813 if (!AfterLoadGame()) {
01814 GamelogStopAction();
01815 return SL_REINIT;
01816 }
01817
01818 GamelogStopAction();
01819 }
01820
01821 return SL_OK;
01822 }
01823 catch (...) {
01824 AbortSaveLoad();
01825
01826
01827 if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
01828
01829
01830 DEBUG(sl, 0, GetSaveLoadErrorString() + 3);
01831
01832
01833 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
01834 }
01835 }
01836
01838 void DoExitSave()
01839 {
01840 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
01841 }
01842
01848 void GenerateDefaultSaveName(char *buf, const char *last)
01849 {
01850
01851
01852
01853 CompanyID cid = _local_company;
01854 if (!IsValidCompanyID(cid)) {
01855 const Company *c;
01856 FOR_ALL_COMPANIES(c) {
01857 cid = c->index;
01858 break;
01859 }
01860 }
01861
01862 SetDParam(0, cid);
01863
01864
01865 switch (_settings_client.gui.date_format_in_default_names) {
01866 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
01867 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
01868 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
01869 default: NOT_REACHED();
01870 }
01871 SetDParam(2, _date);
01872
01873
01874 GetString(buf, !IsValidCompanyID(cid) ? STR_GAME_SAVELOAD_SPECTATOR_SAVEGAME : STR_4004, last);
01875 SanitizeFilename(buf);
01876 }
01877
01878 #if 0
01879
01885 int GetSavegameType(char *file)
01886 {
01887 const SaveLoadFormat *fmt;
01888 uint32 hdr;
01889 FILE *f;
01890 int mode = SL_OLD_LOAD;
01891
01892 f = fopen(file, "rb");
01893 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
01894 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
01895 mode = SL_LOAD;
01896 } else {
01897
01898 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
01899 if (fmt->tag == hdr) {
01900 mode = SL_LOAD;
01901 break;
01902 }
01903 }
01904 }
01905
01906 fclose(f);
01907 return mode;
01908 }
01909 #endif