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