00001
00002
00016 #include "stdafx.h"
00017 #include "openttd.h"
00018 #include "debug.h"
00019 #include "station.h"
00020 #include "thread.h"
00021 #include "town.h"
00022 #include "saveload.h"
00023 #include "network/network.h"
00024 #include "variables.h"
00025 #include "window_func.h"
00026 #include "strings_func.h"
00027 #include "gfx_func.h"
00028 #include "core/alloc_func.hpp"
00029 #include "functions.h"
00030 #include "core/endian_func.hpp"
00031 #include "vehicle_base.h"
00032 #include "autoreplace_base.h"
00033 #include <list>
00034
00035 #include "table/strings.h"
00036
00037 extern const uint16 SAVEGAME_VERSION = 92;
00038 uint16 _sl_version;
00039 byte _sl_minor_version;
00040
00041 typedef void WriterProc(uint len);
00042 typedef uint ReaderProc();
00043
00045 static struct {
00046 bool save;
00047 byte need_length;
00048 byte block_mode;
00049 bool error;
00050
00051 int obj_len;
00052 int array_index, last_array_index;
00053
00054 uint32 offs_base;
00055
00056 WriterProc *write_bytes;
00057 ReaderProc *read_bytes;
00058
00059 const ChunkHandler* const *chs;
00060
00061
00062
00063 byte *bufp, *bufe;
00064
00065
00066 byte *buf;
00067 byte *buf_ori;
00068 uint bufsize;
00069 FILE *fh;
00070
00071 void (*excpt_uninit)();
00072 StringID error_str;
00073 char *extra_msg;
00074 } _sl;
00075
00076
00077 enum NeedLengthValues {NL_NONE = 0, NL_WANTLENGTH = 1, NL_CALCLENGTH = 2};
00078
00082 static void NORETURN SlError(StringID string, const char *extra_msg = NULL)
00083 {
00084 _sl.error_str = string;
00085 free(_sl.extra_msg);
00086 _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00087 throw std::exception();
00088 }
00089
00093 static void SlReadFill()
00094 {
00095 uint len = _sl.read_bytes();
00096 if (len == 0) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected end of chunk");
00097
00098 _sl.bufp = _sl.buf;
00099 _sl.bufe = _sl.buf + len;
00100 _sl.offs_base += len;
00101 }
00102
00103 static inline uint32 SlGetOffs() {return _sl.offs_base - (_sl.bufe - _sl.bufp);}
00104
00109 static inline byte SlCalcConvMemLen(VarType conv)
00110 {
00111 static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00112 byte length = GB(conv, 4, 4);
00113 assert(length < lengthof(conv_mem_size));
00114 return conv_mem_size[length];
00115 }
00116
00121 static inline byte SlCalcConvFileLen(VarType conv)
00122 {
00123 static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00124 byte length = GB(conv, 0, 4);
00125 assert(length < lengthof(conv_file_size));
00126 return conv_file_size[length];
00127 }
00128
00130 static inline size_t SlCalcRefLen() {return CheckSavegameVersion(69) ? 2 : 4;}
00131
00136 static void SlWriteFill()
00137 {
00138
00139 if (_sl.bufp != NULL) {
00140 uint len = _sl.bufp - _sl.buf;
00141 _sl.offs_base += len;
00142 if (len) _sl.write_bytes(len);
00143 }
00144
00145
00146
00147 _sl.bufp = _sl.buf;
00148 _sl.bufe = _sl.buf + _sl.bufsize;
00149 }
00150
00155 static inline byte SlReadByteInternal()
00156 {
00157 if (_sl.bufp == _sl.bufe) SlReadFill();
00158 return *_sl.bufp++;
00159 }
00160
00162 byte SlReadByte() {return SlReadByteInternal();}
00163
00168 static inline void SlWriteByteInternal(byte b)
00169 {
00170 if (_sl.bufp == _sl.bufe) SlWriteFill();
00171 *_sl.bufp++ = b;
00172 }
00173
00175 void SlWriteByte(byte b) {SlWriteByteInternal(b);}
00176
00177 static inline int SlReadUint16()
00178 {
00179 int x = SlReadByte() << 8;
00180 return x | SlReadByte();
00181 }
00182
00183 static inline uint32 SlReadUint32()
00184 {
00185 uint32 x = SlReadUint16() << 16;
00186 return x | SlReadUint16();
00187 }
00188
00189 static inline uint64 SlReadUint64()
00190 {
00191 uint32 x = SlReadUint32();
00192 uint32 y = SlReadUint32();
00193 return (uint64)x << 32 | y;
00194 }
00195
00196 static inline void SlWriteUint16(uint16 v)
00197 {
00198 SlWriteByte(GB(v, 8, 8));
00199 SlWriteByte(GB(v, 0, 8));
00200 }
00201
00202 static inline void SlWriteUint32(uint32 v)
00203 {
00204 SlWriteUint16(GB(v, 16, 16));
00205 SlWriteUint16(GB(v, 0, 16));
00206 }
00207
00208 static inline void SlWriteUint64(uint64 x)
00209 {
00210 SlWriteUint32((uint32)(x >> 32));
00211 SlWriteUint32((uint32)x);
00212 }
00213
00223 static uint SlReadSimpleGamma()
00224 {
00225 uint i = SlReadByte();
00226 if (HasBit(i, 7)) {
00227 i &= ~0x80;
00228 if (HasBit(i, 6)) {
00229 i &= ~0x40;
00230 if (HasBit(i, 5)) {
00231 i &= ~0x20;
00232 if (HasBit(i, 4))
00233 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unsupported gamma");
00234 i = (i << 8) | SlReadByte();
00235 }
00236 i = (i << 8) | SlReadByte();
00237 }
00238 i = (i << 8) | SlReadByte();
00239 }
00240 return i;
00241 }
00242
00255 static void SlWriteSimpleGamma(uint i)
00256 {
00257 if (i >= (1 << 7)) {
00258 if (i >= (1 << 14)) {
00259 if (i >= (1 << 21)) {
00260 assert(i < (1 << 28));
00261 SlWriteByte((byte)0xE0 | (i >> 24));
00262 SlWriteByte((byte)(i >> 16));
00263 } else {
00264 SlWriteByte((byte)0xC0 | (i >> 16));
00265 }
00266 SlWriteByte((byte)(i >> 8));
00267 } else {
00268 SlWriteByte((byte)(0x80 | (i >> 8)));
00269 }
00270 }
00271 SlWriteByte(i);
00272 }
00273
00275 static inline uint SlGetGammaLength(uint i)
00276 {
00277 return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00278 }
00279
00280 static inline uint SlReadSparseIndex() {return SlReadSimpleGamma();}
00281 static inline void SlWriteSparseIndex(uint index) {SlWriteSimpleGamma(index);}
00282
00283 static inline uint SlReadArrayLength() {return SlReadSimpleGamma();}
00284 static inline void SlWriteArrayLength(uint length) {SlWriteSimpleGamma(length);}
00285 static inline uint SlGetArrayLength(uint length) {return SlGetGammaLength(length);}
00286
00287 void SlSetArrayIndex(uint index)
00288 {
00289 _sl.need_length = NL_WANTLENGTH;
00290 _sl.array_index = index;
00291 }
00292
00293 static uint32 _next_offs;
00294
00299 int SlIterateArray()
00300 {
00301 int index;
00302
00303
00304
00305 if (_next_offs != 0 && SlGetOffs() != _next_offs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
00306
00307 while (true) {
00308 uint length = SlReadArrayLength();
00309 if (length == 0) {
00310 _next_offs = 0;
00311 return -1;
00312 }
00313
00314 _sl.obj_len = --length;
00315 _next_offs = SlGetOffs() + length;
00316
00317 switch (_sl.block_mode) {
00318 case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00319 case CH_ARRAY: index = _sl.array_index++; break;
00320 default:
00321 DEBUG(sl, 0, "SlIterateArray error");
00322 return -1;
00323 }
00324
00325 if (length != 0) return index;
00326 }
00327 }
00328
00334 void SlSetLength(size_t length)
00335 {
00336 assert(_sl.save);
00337
00338 switch (_sl.need_length) {
00339 case NL_WANTLENGTH:
00340 _sl.need_length = NL_NONE;
00341 switch (_sl.block_mode) {
00342 case CH_RIFF:
00343
00344
00345
00346 assert(length < (1<<28));
00347 SlWriteUint32((length & 0xFFFFFF) | ((length >> 24) << 28));
00348 break;
00349 case CH_ARRAY:
00350 assert(_sl.last_array_index <= _sl.array_index);
00351 while (++_sl.last_array_index <= _sl.array_index)
00352 SlWriteArrayLength(1);
00353 SlWriteArrayLength(length + 1);
00354 break;
00355 case CH_SPARSE_ARRAY:
00356 SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index));
00357 SlWriteSparseIndex(_sl.array_index);
00358 break;
00359 default: NOT_REACHED();
00360 } break;
00361 case NL_CALCLENGTH:
00362 _sl.obj_len += length;
00363 break;
00364 }
00365 }
00366
00373 static void SlCopyBytes(void *ptr, size_t length)
00374 {
00375 byte *p = (byte*)ptr;
00376
00377 if (_sl.save) {
00378 for (; length != 0; length--) {SlWriteByteInternal(*p++);}
00379 } else {
00380 for (; length != 0; length--) {*p++ = SlReadByteInternal();}
00381 }
00382 }
00383
00388 static inline void SlSkipBytes(size_t length)
00389 {
00390 for (; length != 0; length--) SlReadByte();
00391 }
00392
00393
00394 uint SlGetFieldLength() {return _sl.obj_len;}
00395
00401 int64 ReadValue(const void *ptr, VarType conv)
00402 {
00403 switch (GetVarMemType(conv)) {
00404 case SLE_VAR_BL: return (*(bool*)ptr != 0);
00405 case SLE_VAR_I8: return *(int8* )ptr;
00406 case SLE_VAR_U8: return *(byte* )ptr;
00407 case SLE_VAR_I16: return *(int16* )ptr;
00408 case SLE_VAR_U16: return *(uint16*)ptr;
00409 case SLE_VAR_I32: return *(int32* )ptr;
00410 case SLE_VAR_U32: return *(uint32*)ptr;
00411 case SLE_VAR_I64: return *(int64* )ptr;
00412 case SLE_VAR_U64: return *(uint64*)ptr;
00413 case SLE_VAR_NULL:return 0;
00414 default: NOT_REACHED();
00415 }
00416
00417
00418 return 0;
00419 }
00420
00426 void WriteValue(void *ptr, VarType conv, int64 val)
00427 {
00428 switch (GetVarMemType(conv)) {
00429 case SLE_VAR_BL: *(bool *)ptr = (val != 0); break;
00430 case SLE_VAR_I8: *(int8 *)ptr = val; break;
00431 case SLE_VAR_U8: *(byte *)ptr = val; break;
00432 case SLE_VAR_I16: *(int16 *)ptr = val; break;
00433 case SLE_VAR_U16: *(uint16*)ptr = val; break;
00434 case SLE_VAR_I32: *(int32 *)ptr = val; break;
00435 case SLE_VAR_U32: *(uint32*)ptr = val; break;
00436 case SLE_VAR_I64: *(int64 *)ptr = val; break;
00437 case SLE_VAR_U64: *(uint64*)ptr = val; break;
00438 case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00439 case SLE_VAR_NULL: break;
00440 default: NOT_REACHED();
00441 }
00442 }
00443
00452 static void SlSaveLoadConv(void *ptr, VarType conv)
00453 {
00454 int64 x = 0;
00455
00456 if (_sl.save) {
00457
00458 x = ReadValue(ptr, conv);
00459
00460
00461 switch (GetVarFileType(conv)) {
00462 case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break;
00463 case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break;
00464 case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00465 case SLE_FILE_STRINGID:
00466 case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break;
00467 case SLE_FILE_I32:
00468 case SLE_FILE_U32: SlWriteUint32((uint32)x);break;
00469 case SLE_FILE_I64:
00470 case SLE_FILE_U64: SlWriteUint64(x);break;
00471 default: NOT_REACHED();
00472 }
00473 } else {
00474
00475
00476 switch (GetVarFileType(conv)) {
00477 case SLE_FILE_I8: x = (int8 )SlReadByte(); break;
00478 case SLE_FILE_U8: x = (byte )SlReadByte(); break;
00479 case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00480 case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00481 case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00482 case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00483 case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00484 case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00485 case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00486 default: NOT_REACHED();
00487 }
00488
00489
00490 WriteValue(ptr, conv, x);
00491 }
00492 }
00493
00501 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
00502 {
00503 if (ptr == NULL) return 0;
00504 return minu(strlen(ptr), length - 1);
00505 }
00506
00514 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
00515 {
00516 size_t len;
00517 const char *str;
00518
00519 switch (GetVarMemType(conv)) {
00520 default: NOT_REACHED();
00521 case SLE_VAR_STR:
00522 case SLE_VAR_STRQ:
00523 str = *(const char**)ptr;
00524 len = SIZE_MAX;
00525 break;
00526 case SLE_VAR_STRB:
00527 case SLE_VAR_STRBQ:
00528 str = (const char*)ptr;
00529 len = length;
00530 break;
00531 }
00532
00533 len = SlCalcNetStringLen(str, len);
00534 return len + SlGetArrayLength(len);
00535 }
00536
00542 static void SlString(void *ptr, size_t length, VarType conv)
00543 {
00544 size_t len;
00545
00546 if (_sl.save) {
00547 switch (GetVarMemType(conv)) {
00548 default: NOT_REACHED();
00549 case SLE_VAR_STRB:
00550 case SLE_VAR_STRBQ:
00551 len = SlCalcNetStringLen((char*)ptr, length);
00552 break;
00553 case SLE_VAR_STR:
00554 case SLE_VAR_STRQ:
00555 ptr = *(char**)ptr;
00556 len = SlCalcNetStringLen((char*)ptr, SIZE_MAX);
00557 break;
00558 }
00559
00560 SlWriteArrayLength(len);
00561 SlCopyBytes(ptr, len);
00562 } else {
00563 len = SlReadArrayLength();
00564
00565 switch (GetVarMemType(conv)) {
00566 default: NOT_REACHED();
00567 case SLE_VAR_STRB:
00568 case SLE_VAR_STRBQ:
00569 if (len >= length) {
00570 DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
00571 SlCopyBytes(ptr, length);
00572 SlSkipBytes(len - length);
00573 len = length - 1;
00574 } else {
00575 SlCopyBytes(ptr, len);
00576 }
00577 break;
00578 case SLE_VAR_STR:
00579 case SLE_VAR_STRQ:
00580 free(*(char**)ptr);
00581 if (len == 0) {
00582 *(char**)ptr = NULL;
00583 } else {
00584 *(char**)ptr = MallocT<char>(len + 1);
00585 ptr = *(char**)ptr;
00586 SlCopyBytes(ptr, len);
00587 }
00588 break;
00589 }
00590
00591 ((char*)ptr)[len] = '\0';
00592 }
00593 }
00594
00600 static inline size_t SlCalcArrayLen(uint length, VarType conv)
00601 {
00602 return SlCalcConvFileLen(conv) * length;
00603 }
00604
00611 void SlArray(void *array, uint length, VarType conv)
00612 {
00613
00614 if (_sl.need_length != NL_NONE) {
00615 SlSetLength(SlCalcArrayLen(length, conv));
00616
00617 if (_sl.need_length == NL_CALCLENGTH) return;
00618 }
00619
00620
00621
00622 if (!_sl.save && _sl_version == 0) {
00623
00624 if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
00625 conv == SLE_INT32 || conv == SLE_UINT32) {
00626 SlCopyBytes(array, length * SlCalcConvFileLen(conv));
00627 return;
00628 }
00629
00630 if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
00631 for (uint i = 0; i < length; i++) {
00632 ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
00633 }
00634 return;
00635 }
00636 }
00637
00638
00639
00640 if (conv == SLE_INT8 || conv == SLE_UINT8) {
00641 SlCopyBytes(array, length);
00642 } else {
00643 byte *a = (byte*)array;
00644 byte mem_size = SlCalcConvMemLen(conv);
00645
00646 for (; length != 0; length --) {
00647 SlSaveLoadConv(a, conv);
00648 a += mem_size;
00649 }
00650 }
00651 }
00652
00653
00654 static uint ReferenceToInt(const void* obj, SLRefType rt);
00655 static void* IntToReference(uint index, SLRefType rt);
00656
00657
00662 static inline size_t SlCalcListLen(const void *list)
00663 {
00664 std::list<void *> *l = (std::list<void *> *) list;
00665
00666 int type_size = CheckSavegameVersion(69) ? 2 : 4;
00667
00668
00669 return l->size() * type_size + type_size;
00670 }
00671
00672
00678 void SlList(void *list, SLRefType conv)
00679 {
00680
00681 if (_sl.need_length != NL_NONE) {
00682 SlSetLength(SlCalcListLen(list));
00683
00684 if (_sl.need_length == NL_CALCLENGTH) return;
00685 }
00686
00687 std::list<void *> *l = (std::list<void *> *) list;
00688
00689 if (_sl.save) {
00690 SlWriteUint32(l->size());
00691
00692 std::list<void *>::iterator iter;
00693 for (iter = l->begin(); iter != l->end(); ++iter) {
00694 void *ptr = *iter;
00695 SlWriteUint32(ReferenceToInt(ptr, conv));
00696 }
00697 } else {
00698 uint length = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
00699
00700
00701 for (uint i = 0; i < length; i++) {
00702 void *ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), conv);
00703 l->push_back(ptr);
00704 }
00705 }
00706 }
00707
00708
00710 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
00711 {
00712 if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
00713 if (sld->conv & SLF_SAVE_NO) return false;
00714
00715 return true;
00716 }
00717
00721 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
00722 {
00723 if ((sld->conv & SLF_NETWORK_NO) && !_sl.save && _networking && !_network_server) {
00724 SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
00725 return true;
00726 }
00727
00728 return false;
00729 }
00730
00737 static size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
00738 {
00739 size_t length = 0;
00740
00741
00742 for (; sld->cmd != SL_END; sld++) {
00743 length += SlCalcObjMemberLength(object, sld);
00744 }
00745 return length;
00746 }
00747
00748 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
00749 {
00750 assert(_sl.save);
00751
00752 switch (sld->cmd) {
00753 case SL_VAR:
00754 case SL_REF:
00755 case SL_ARR:
00756 case SL_STR:
00757 case SL_LST:
00758
00759 if (!SlIsObjectValidInSavegame(sld)) break;
00760
00761 switch (sld->cmd) {
00762 case SL_VAR: return SlCalcConvFileLen(sld->conv);
00763 case SL_REF: return SlCalcRefLen();
00764 case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
00765 case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
00766 case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
00767 default: NOT_REACHED();
00768 }
00769 break;
00770 case SL_WRITEBYTE: return 1;
00771 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
00772 default: NOT_REACHED();
00773 }
00774 return 0;
00775 }
00776
00777
00778 bool SlObjectMember(void *ptr, const SaveLoad *sld)
00779 {
00780 VarType conv = GB(sld->conv, 0, 8);
00781 switch (sld->cmd) {
00782 case SL_VAR:
00783 case SL_REF:
00784 case SL_ARR:
00785 case SL_STR:
00786 case SL_LST:
00787
00788 if (!SlIsObjectValidInSavegame(sld)) return false;
00789 if (SlSkipVariableOnLoad(sld)) return false;
00790
00791 switch (sld->cmd) {
00792 case SL_VAR: SlSaveLoadConv(ptr, conv); break;
00793 case SL_REF:
00794 if (_sl.save) {
00795 SlWriteUint32(ReferenceToInt(*(void**)ptr, (SLRefType)conv));
00796 } else {
00797 *(void**)ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), (SLRefType)conv);
00798 }
00799 break;
00800 case SL_ARR: SlArray(ptr, sld->length, conv); break;
00801 case SL_STR: SlString(ptr, sld->length, conv); break;
00802 case SL_LST: SlList(ptr, (SLRefType)conv); break;
00803 default: NOT_REACHED();
00804 }
00805 break;
00806
00807
00808
00809
00810
00811
00812 case SL_WRITEBYTE:
00813 if (_sl.save) {
00814 SlWriteByte(sld->version_to);
00815 } else {
00816 *(byte*)ptr = sld->version_from;
00817 }
00818 break;
00819
00820
00821 case SL_VEH_INCLUDE:
00822 SlObject(ptr, GetVehicleDescription(VEH_END));
00823 break;
00824 default: NOT_REACHED();
00825 }
00826 return true;
00827 }
00828
00834 void SlObject(void *object, const SaveLoad *sld)
00835 {
00836
00837 if (_sl.need_length != NL_NONE) {
00838 SlSetLength(SlCalcObjLength(object, sld));
00839 if (_sl.need_length == NL_CALCLENGTH) return;
00840 }
00841
00842 for (; sld->cmd != SL_END; sld++) {
00843 void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
00844 SlObjectMember(ptr, sld);
00845 }
00846 }
00847
00852 void SlGlobList(const SaveLoadGlobVarList *sldg)
00853 {
00854 SlObject(NULL, (const SaveLoad*)sldg);
00855 }
00856
00862 void SlAutolength(AutolengthProc *proc, void *arg)
00863 {
00864 uint32 offs;
00865
00866 assert(_sl.save);
00867
00868
00869 _sl.need_length = NL_CALCLENGTH;
00870 _sl.obj_len = 0;
00871 proc(arg);
00872
00873
00874 _sl.need_length = NL_WANTLENGTH;
00875 SlSetLength(_sl.obj_len);
00876
00877 offs = SlGetOffs() + _sl.obj_len;
00878
00879
00880 proc(arg);
00881
00882 if (offs != SlGetOffs()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
00883 }
00884
00889 static void SlLoadChunk(const ChunkHandler *ch)
00890 {
00891 byte m = SlReadByte();
00892 size_t len;
00893 uint32 endoffs;
00894
00895 _sl.block_mode = m;
00896 _sl.obj_len = 0;
00897
00898 switch (m) {
00899 case CH_ARRAY:
00900 _sl.array_index = 0;
00901 ch->load_proc();
00902 break;
00903 case CH_SPARSE_ARRAY:
00904 ch->load_proc();
00905 break;
00906 default:
00907 if ((m & 0xF) == CH_RIFF) {
00908
00909 len = (SlReadByte() << 16) | ((m >> 4) << 24);
00910 len += SlReadUint16();
00911 _sl.obj_len = len;
00912 endoffs = SlGetOffs() + len;
00913 ch->load_proc();
00914 if (SlGetOffs() != endoffs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
00915 } else {
00916 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk type");
00917 }
00918 break;
00919 }
00920 }
00921
00922
00923 static ChunkSaveLoadProc *_tmp_proc_1;
00924 static inline void SlStubSaveProc2(void *arg) {_tmp_proc_1();}
00925 static void SlStubSaveProc() {SlAutolength(SlStubSaveProc2, NULL);}
00926
00931 static void SlSaveChunk(const ChunkHandler *ch)
00932 {
00933 ChunkSaveLoadProc *proc = ch->save_proc;
00934
00935
00936 if (proc == NULL) return;
00937
00938 SlWriteUint32(ch->id);
00939 DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00940
00941 if (ch->flags & CH_AUTO_LENGTH) {
00942
00943 _tmp_proc_1 = proc;
00944 proc = SlStubSaveProc;
00945 }
00946
00947 _sl.block_mode = ch->flags & CH_TYPE_MASK;
00948 switch (ch->flags & CH_TYPE_MASK) {
00949 case CH_RIFF:
00950 _sl.need_length = NL_WANTLENGTH;
00951 proc();
00952 break;
00953 case CH_ARRAY:
00954 _sl.last_array_index = 0;
00955 SlWriteByte(CH_ARRAY);
00956 proc();
00957 SlWriteArrayLength(0);
00958 break;
00959 case CH_SPARSE_ARRAY:
00960 SlWriteByte(CH_SPARSE_ARRAY);
00961 proc();
00962 SlWriteArrayLength(0);
00963 break;
00964 default: NOT_REACHED();
00965 }
00966 }
00967
00969 static void SlSaveChunks()
00970 {
00971 const ChunkHandler *ch;
00972 const ChunkHandler* const *chsc;
00973 uint p;
00974
00975 for (p = 0; p != CH_NUM_PRI_LEVELS; p++) {
00976 for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
00977 while (true) {
00978 if (((ch->flags >> CH_PRI_SHL) & (CH_NUM_PRI_LEVELS - 1)) == p)
00979 SlSaveChunk(ch);
00980 if (ch->flags & CH_LAST)
00981 break;
00982 ch++;
00983 }
00984 }
00985 }
00986
00987
00988 SlWriteUint32(0);
00989 }
00990
00996 static const ChunkHandler *SlFindChunkHandler(uint32 id)
00997 {
00998 const ChunkHandler *ch;
00999 const ChunkHandler *const *chsc;
01000 for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
01001 for (;;) {
01002 if (ch->id == id) return ch;
01003 if (ch->flags & CH_LAST) break;
01004 ch++;
01005 }
01006 }
01007 return NULL;
01008 }
01009
01011 static void SlLoadChunks()
01012 {
01013 uint32 id;
01014 const ChunkHandler *ch;
01015
01016 for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01017 DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01018
01019 ch = SlFindChunkHandler(id);
01020 if (ch == NULL) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unknown chunk type");
01021 SlLoadChunk(ch);
01022 }
01023 }
01024
01025
01026
01027
01028 #define LZO_SIZE 8192
01029
01030 #include "minilzo.h"
01031
01032 static uint ReadLZO()
01033 {
01034 byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
01035 uint32 tmp[2];
01036 uint32 size;
01037 uint len;
01038
01039
01040 if (fread(tmp, sizeof(tmp), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01041
01042
01043 ((uint32*)out)[0] = size = tmp[1];
01044
01045 if (_sl_version != 0) {
01046 tmp[0] = TO_BE32(tmp[0]);
01047 size = TO_BE32(size);
01048 }
01049
01050 if (size >= sizeof(out)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Inconsistent size");
01051
01052
01053 if (fread(out + sizeof(uint32), size, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01054
01055
01056 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Bad checksum");
01057
01058
01059 lzo1x_decompress(out + sizeof(uint32)*1, size, _sl.buf, &len, NULL);
01060 return len;
01061 }
01062
01063
01064
01065 static void WriteLZO(uint size)
01066 {
01067 byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
01068 byte wrkmem[sizeof(byte*)*4096];
01069 uint outlen;
01070
01071 lzo1x_1_compress(_sl.buf, size, out + sizeof(uint32)*2, &outlen, wrkmem);
01072 ((uint32*)out)[1] = TO_BE32(outlen);
01073 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01074 if (fwrite(out, outlen + sizeof(uint32)*2, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01075 }
01076
01077 static bool InitLZO()
01078 {
01079 _sl.bufsize = LZO_SIZE;
01080 _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
01081 return true;
01082 }
01083
01084 static void UninitLZO()
01085 {
01086 free(_sl.buf_ori);
01087 }
01088
01089
01090
01091
01092 static uint ReadNoComp()
01093 {
01094 return fread(_sl.buf, 1, LZO_SIZE, _sl.fh);
01095 }
01096
01097 static void WriteNoComp(uint size)
01098 {
01099 fwrite(_sl.buf, 1, size, _sl.fh);
01100 }
01101
01102 static bool InitNoComp()
01103 {
01104 _sl.bufsize = LZO_SIZE;
01105 _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
01106 return true;
01107 }
01108
01109 static void UninitNoComp()
01110 {
01111 free(_sl.buf_ori);
01112 }
01113
01114
01115
01116
01117
01118 #include "table/sprites.h"
01119 #include "gui.h"
01120
01121 struct ThreadedSave {
01122 uint count;
01123 byte ff_state;
01124 bool saveinprogress;
01125 CursorID cursor;
01126 };
01127
01128
01129 STATIC_OLD_POOL(Savegame, byte, 17, 500, NULL, NULL)
01130 static ThreadedSave _ts;
01131
01132 static bool InitMem()
01133 {
01134 _ts.count = 0;
01135
01136 _Savegame_pool.CleanPool();
01137 _Savegame_pool.AddBlockToPool();
01138
01139
01140 _sl.bufsize = GetSavegamePoolSize();
01141 _sl.buf = GetSavegame(_ts.count);
01142 return true;
01143 }
01144
01145 static void UnInitMem()
01146 {
01147 _Savegame_pool.CleanPool();
01148 }
01149
01150 static void WriteMem(uint size)
01151 {
01152 _ts.count += size;
01153
01154 _Savegame_pool.AddBlockIfNeeded(_ts.count);
01155 _sl.buf = GetSavegame(_ts.count);
01156 }
01157
01158
01159
01160
01161
01162 #if defined(WITH_ZLIB)
01163 #include <zlib.h>
01164
01165 static z_stream _z;
01166
01167 static bool InitReadZlib()
01168 {
01169 memset(&_z, 0, sizeof(_z));
01170 if (inflateInit(&_z) != Z_OK) return false;
01171
01172 _sl.bufsize = 4096;
01173 _sl.buf = _sl.buf_ori = MallocT<byte>(4096 + 4096);
01174 return true;
01175 }
01176
01177 static uint ReadZlib()
01178 {
01179 int r;
01180
01181 _z.next_out = _sl.buf;
01182 _z.avail_out = 4096;
01183
01184 do {
01185
01186 if (_z.avail_in == 0) {
01187 _z.avail_in = fread(_z.next_in = _sl.buf + 4096, 1, 4096, _sl.fh);
01188 }
01189
01190
01191 r = inflate(&_z, 0);
01192 if (r == Z_STREAM_END)
01193 break;
01194
01195 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
01196 } while (_z.avail_out);
01197
01198 return 4096 - _z.avail_out;
01199 }
01200
01201 static void UninitReadZlib()
01202 {
01203 inflateEnd(&_z);
01204 free(_sl.buf_ori);
01205 }
01206
01207 static bool InitWriteZlib()
01208 {
01209 memset(&_z, 0, sizeof(_z));
01210 if (deflateInit(&_z, 6) != Z_OK) return false;
01211
01212 _sl.bufsize = 4096;
01213 _sl.buf = _sl.buf_ori = MallocT<byte>(4096);
01214 return true;
01215 }
01216
01217 static void WriteZlibLoop(z_streamp z, byte *p, uint len, int mode)
01218 {
01219 byte buf[1024];
01220 int r;
01221 uint n;
01222 z->next_in = p;
01223 z->avail_in = len;
01224 do {
01225 z->next_out = buf;
01226 z->avail_out = sizeof(buf);
01227 r = deflate(z, mode);
01228
01229 if ((n=sizeof(buf) - z->avail_out) != 0) {
01230 if (fwrite(buf, n, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01231 }
01232 if (r == Z_STREAM_END)
01233 break;
01234 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
01235 } while (z->avail_in || !z->avail_out);
01236 }
01237
01238 static void WriteZlib(uint len)
01239 {
01240 WriteZlibLoop(&_z, _sl.buf, len, 0);
01241 }
01242
01243 static void UninitWriteZlib()
01244 {
01245
01246 if (_sl.fh) WriteZlibLoop(&_z, NULL, 0, Z_FINISH);
01247 deflateEnd(&_z);
01248 free(_sl.buf_ori);
01249 }
01250
01251 #endif
01252
01253
01254
01255
01256
01257
01258 extern const ChunkHandler _misc_chunk_handlers[];
01259 extern const ChunkHandler _setting_chunk_handlers[];
01260 extern const ChunkHandler _player_chunk_handlers[];
01261 extern const ChunkHandler _engine_chunk_handlers[];
01262 extern const ChunkHandler _veh_chunk_handlers[];
01263 extern const ChunkHandler _waypoint_chunk_handlers[];
01264 extern const ChunkHandler _depot_chunk_handlers[];
01265 extern const ChunkHandler _order_chunk_handlers[];
01266 extern const ChunkHandler _town_chunk_handlers[];
01267 extern const ChunkHandler _sign_chunk_handlers[];
01268 extern const ChunkHandler _station_chunk_handlers[];
01269 extern const ChunkHandler _industry_chunk_handlers[];
01270 extern const ChunkHandler _economy_chunk_handlers[];
01271 extern const ChunkHandler _animated_tile_chunk_handlers[];
01272 extern const ChunkHandler _newgrf_chunk_handlers[];
01273 extern const ChunkHandler _group_chunk_handlers[];
01274 extern const ChunkHandler _cargopacket_chunk_handlers[];
01275
01276 static const ChunkHandler * const _chunk_handlers[] = {
01277 _misc_chunk_handlers,
01278 _setting_chunk_handlers,
01279 _veh_chunk_handlers,
01280 _waypoint_chunk_handlers,
01281 _depot_chunk_handlers,
01282 _order_chunk_handlers,
01283 _industry_chunk_handlers,
01284 _economy_chunk_handlers,
01285 _engine_chunk_handlers,
01286 _town_chunk_handlers,
01287 _sign_chunk_handlers,
01288 _station_chunk_handlers,
01289 _player_chunk_handlers,
01290 _animated_tile_chunk_handlers,
01291 _newgrf_chunk_handlers,
01292 _group_chunk_handlers,
01293 _cargopacket_chunk_handlers,
01294 NULL,
01295 };
01296
01307 static uint ReferenceToInt(const void *obj, SLRefType rt)
01308 {
01309 if (obj == NULL) return 0;
01310
01311 switch (rt) {
01312 case REF_VEHICLE_OLD:
01313 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01314 case REF_STATION: return ((const Station*)obj)->index + 1;
01315 case REF_TOWN: return ((const Town*)obj)->index + 1;
01316 case REF_ORDER: return ((const Order*)obj)->index + 1;
01317 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01318 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01319 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01320 default: NOT_REACHED();
01321 }
01322
01323 return 0;
01324 }
01325
01336 static void *IntToReference(uint index, SLRefType rt)
01337 {
01338
01339
01340 if (rt == REF_VEHICLE_OLD && !CheckSavegameVersionOldStyle(4, 4)) {
01341 rt = REF_VEHICLE;
01342 }
01343
01344
01345 if (rt != REF_VEHICLE_OLD && index == 0) {
01346 return NULL;
01347 }
01348
01349 index--;
01350
01351 switch (rt) {
01352 case REF_ORDER:
01353 if (_Order_pool.AddBlockIfNeeded(index)) return GetOrder(index);
01354 error("Orders: failed loading savegame: too many orders");
01355
01356 case REF_VEHICLE:
01357 if (_Vehicle_pool.AddBlockIfNeeded(index)) return GetVehicle(index);
01358 error("Vehicles: failed loading savegame: too many vehicles");
01359
01360 case REF_STATION:
01361 if (_Station_pool.AddBlockIfNeeded(index)) return GetStation(index);
01362 error("Stations: failed loading savegame: too many stations");
01363
01364 case REF_TOWN:
01365 if (_Town_pool.AddBlockIfNeeded(index)) return GetTown(index);
01366 error("Towns: failed loading savegame: too many towns");
01367
01368 case REF_ROADSTOPS:
01369 if (_RoadStop_pool.AddBlockIfNeeded(index)) return GetRoadStop(index);
01370 error("RoadStops: failed loading savegame: too many RoadStops");
01371
01372 case REF_ENGINE_RENEWS:
01373 if (_EngineRenew_pool.AddBlockIfNeeded(index)) return GetEngineRenew(index);
01374 error("EngineRenews: failed loading savegame: too many EngineRenews");
01375
01376 case REF_CARGO_PACKET:
01377 if (_CargoPacket_pool.AddBlockIfNeeded(index)) return GetCargoPacket(index);
01378 error("CargoPackets: failed loading savegame: too many Cargo packets");
01379
01380 case REF_VEHICLE_OLD:
01381
01382
01383
01384 index++;
01385 if (index == INVALID_VEHICLE) return NULL;
01386
01387 if (_Vehicle_pool.AddBlockIfNeeded(index)) return GetVehicle(index);
01388 error("Vehicles: failed loading savegame: too many vehicles");
01389
01390 default: NOT_REACHED();
01391 }
01392
01393 return NULL;
01394 }
01395
01397 struct SaveLoadFormat {
01398 const char *name;
01399 uint32 tag;
01400
01401 bool (*init_read)();
01402 ReaderProc *reader;
01403 void (*uninit_read)();
01404
01405 bool (*init_write)();
01406 WriterProc *writer;
01407 void (*uninit_write)();
01408 };
01409
01410 static const SaveLoadFormat _saveload_formats[] = {
01411 {"memory", 0, NULL, NULL, NULL, InitMem, WriteMem, UnInitMem},
01412 {"lzo", TO_BE32X('OTTD'), InitLZO, ReadLZO, UninitLZO, InitLZO, WriteLZO, UninitLZO},
01413 {"none", TO_BE32X('OTTN'), InitNoComp, ReadNoComp, UninitNoComp, InitNoComp, WriteNoComp, UninitNoComp},
01414 #if defined(WITH_ZLIB)
01415 {"zlib", TO_BE32X('OTTZ'), InitReadZlib, ReadZlib, UninitReadZlib, InitWriteZlib, WriteZlib, UninitWriteZlib},
01416 #else
01417 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, NULL, NULL, NULL, NULL},
01418 #endif
01419 };
01420
01427 static const SaveLoadFormat *GetSavegameFormat(const char *s)
01428 {
01429 const SaveLoadFormat *def = endof(_saveload_formats) - 1;
01430
01431
01432 while (!def->init_write) def--;
01433
01434 if (s != NULL && s[0] != '\0') {
01435 const SaveLoadFormat *slf;
01436 for (slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
01437 if (slf->init_write != NULL && strcmp(s, slf->name) == 0)
01438 return slf;
01439 }
01440
01441 ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
01442 }
01443 return def;
01444 }
01445
01446
01447 void InitializeGame(int mode, uint size_x, uint size_y);
01448 extern bool AfterLoadGame();
01449 extern void BeforeSaveGame();
01450 extern bool LoadOldSaveGame(const char *file);
01451
01453 static inline SaveOrLoadResult AbortSaveLoad()
01454 {
01455 if (_sl.fh != NULL) fclose(_sl.fh);
01456
01457 _sl.fh = NULL;
01458 return SL_ERROR;
01459 }
01460
01464 void SaveFileStart()
01465 {
01466 _ts.ff_state = _fast_forward;
01467 _fast_forward = 0;
01468 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
01469
01470 SendWindowMessage(WC_STATUS_BAR, 0, true, 0, 0);
01471 _ts.saveinprogress = true;
01472 }
01473
01476 void SaveFileDone()
01477 {
01478 _fast_forward = _ts.ff_state;
01479 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
01480
01481 SendWindowMessage(WC_STATUS_BAR, 0, false, 0, 0);
01482 _ts.saveinprogress = false;
01483 }
01484
01486 void SetSaveLoadError(StringID str)
01487 {
01488 _sl.error_str = str;
01489 }
01490
01492 const char *GetSaveLoadErrorString()
01493 {
01494 SetDParam(0, _sl.error_str);
01495 SetDParamStr(1, _sl.extra_msg);
01496
01497 static char err_str[512];
01498 GetString(err_str, _sl.save ? STR_4007_GAME_SAVE_FAILED : STR_4009_GAME_LOAD_FAILED, lastof(err_str));
01499 return err_str;
01500 }
01501
01503 void SaveFileError()
01504 {
01505 SetDParamStr(0, GetSaveLoadErrorString());
01506 ShowErrorMessage(STR_012D, STR_NULL, 0, 0);
01507 SaveFileDone();
01508 }
01509
01510 static OTTDThread* save_thread;
01511
01515 static SaveOrLoadResult SaveFileToDisk(bool threaded)
01516 {
01517 const SaveLoadFormat *fmt;
01518 uint32 hdr[2];
01519
01520 _sl.excpt_uninit = NULL;
01521 try {
01522 fmt = GetSavegameFormat(_savegame_format);
01523
01524
01525 hdr[0] = fmt->tag;
01526 hdr[1] = TO_BE32(SAVEGAME_VERSION << 16);
01527 if (fwrite(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01528
01529 if (!fmt->init_write()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01530
01531 {
01532 uint i;
01533 uint count = 1 << Savegame_POOL_BLOCK_SIZE_BITS;
01534
01535 if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
01536 for (i = 0; i != _Savegame_pool.GetBlockCount() - 1; i++) {
01537 _sl.buf = _Savegame_pool.blocks[i];
01538 fmt->writer(count);
01539 }
01540
01541
01542
01543 _sl.buf = _Savegame_pool.blocks[i];
01544 fmt->writer(_ts.count - (i * count));
01545 }
01546
01547 fmt->uninit_write();
01548 if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
01549 GetSavegameFormat("memory")->uninit_write();
01550 fclose(_sl.fh);
01551
01552 if (threaded) OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_DONE);
01553
01554 return SL_OK;
01555 }
01556 catch (...) {
01557 AbortSaveLoad();
01558 if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
01559
01560 ShowInfo(GetSaveLoadErrorString());
01561 fprintf(stderr, GetSaveLoadErrorString());
01562
01563 if (threaded) {
01564 OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_ERROR);
01565 } else {
01566 SaveFileError();
01567 }
01568 return SL_ERROR;
01569 }
01570 }
01571
01572 static void* SaveFileToDiskThread(void *arg)
01573 {
01574 SaveFileToDisk(true);
01575 return NULL;
01576 }
01577
01578 void WaitTillSaved()
01579 {
01580 OTTDJoinThread(save_thread);
01581 save_thread = NULL;
01582 }
01583
01591 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb)
01592 {
01593 uint32 hdr[2];
01594 const SaveLoadFormat *fmt;
01595
01596
01597 if (_ts.saveinprogress && mode == SL_SAVE) {
01598
01599 if (!_do_autosave) ShowErrorMessage(INVALID_STRING_ID, STR_SAVE_STILL_IN_PROGRESS, 0, 0);
01600 return SL_OK;
01601 }
01602 WaitTillSaved();
01603
01604 _next_offs = 0;
01605
01606
01607 if (mode == SL_OLD_LOAD) {
01608 InitializeGame(IG_DATE_RESET, 256, 256);
01609 if (!LoadOldSaveGame(filename)) return SL_REINIT;
01610 _sl_version = 0;
01611 if (!AfterLoadGame()) return SL_REINIT;
01612 return SL_OK;
01613 }
01614
01615 _sl.excpt_uninit = NULL;
01616 try {
01617 _sl.fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
01618
01619
01620 if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", SAVE_DIR);
01621 if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", BASE_DIR);
01622
01623 if (_sl.fh == NULL) {
01624 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01625 }
01626
01627 _sl.bufe = _sl.bufp = NULL;
01628 _sl.offs_base = 0;
01629 _sl.save = (mode != 0);
01630 _sl.chs = _chunk_handlers;
01631
01632
01633
01634 if (mode == SL_SAVE) {
01635 fmt = GetSavegameFormat("memory");
01636
01637 _sl.write_bytes = fmt->writer;
01638 _sl.excpt_uninit = fmt->uninit_write;
01639 if (!fmt->init_write()) {
01640 DEBUG(sl, 0, "Initializing writer '%s' failed.", fmt->name);
01641 return AbortSaveLoad();
01642 }
01643
01644 _sl_version = SAVEGAME_VERSION;
01645
01646 BeforeSaveGame();
01647 SlSaveChunks();
01648 SlWriteFill();
01649
01650 SaveFileStart();
01651 if (_network_server ||
01652 (save_thread = OTTDCreateThread(&SaveFileToDiskThread, NULL)) == NULL) {
01653 if (!_network_server) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
01654
01655 SaveOrLoadResult result = SaveFileToDisk(false);
01656 SaveFileDone();
01657
01658 return result;
01659 }
01660 } else {
01661 assert(mode == SL_LOAD);
01662 DebugDumpCommands("ddc:load:%s\n", filename);
01663
01664 if (fread(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01665
01666
01667 for (fmt = _saveload_formats; ; fmt++) {
01668
01669 if (fmt == endof(_saveload_formats)) {
01670 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
01671 #if defined(WINCE)
01672
01673 fseek(_sl.fh, 0L, SEEK_SET);
01674 clearerr(_sl.fh);
01675 #else
01676 rewind(_sl.fh);
01677 #endif
01678 _sl_version = 0;
01679 _sl_minor_version = 0;
01680 fmt = _saveload_formats + 1;
01681 break;
01682 }
01683
01684 if (fmt->tag == hdr[0]) {
01685
01686 _sl_version = TO_BE32(hdr[1]) >> 16;
01687
01688
01689
01690
01691 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
01692
01693 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
01694
01695
01696 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
01697 break;
01698 }
01699 }
01700
01701 _sl.read_bytes = fmt->reader;
01702 _sl.excpt_uninit = fmt->uninit_read;
01703
01704
01705 if (fmt->init_read == NULL) {
01706 char err_str[64];
01707 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
01708 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
01709 }
01710
01711 if (!fmt->init_read()) {
01712 char err_str[64];
01713 snprintf(err_str, lengthof(err_str), "Initializing loader '%s' failed", fmt->name);
01714 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
01715 }
01716
01717
01718
01719
01720 InitializeGame(IG_DATE_RESET, 256, 256);
01721
01722 SlLoadChunks();
01723 fmt->uninit_read();
01724 fclose(_sl.fh);
01725
01726
01727
01728 if (!AfterLoadGame()) return SL_REINIT;
01729 }
01730
01731 return SL_OK;
01732 }
01733 catch (...) {
01734 AbortSaveLoad();
01735
01736
01737 if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
01738
01739
01740 ShowInfoF(GetSaveLoadErrorString() + 3);
01741
01742
01743 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
01744 }
01745 }
01746
01748 void DoExitSave()
01749 {
01750 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
01751 }
01752
01753 #if 0
01754
01760 int GetSavegameType(char *file)
01761 {
01762 const SaveLoadFormat *fmt;
01763 uint32 hdr;
01764 FILE *f;
01765 int mode = SL_OLD_LOAD;
01766
01767 f = fopen(file, "rb");
01768 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
01769 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
01770 mode = SL_LOAD;
01771 } else {
01772
01773 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
01774 if (fmt->tag == hdr) {
01775 mode = SL_LOAD;
01776 break;
01777 }
01778 }
01779 }
01780
01781 fclose(f);
01782 return mode;
01783 }
01784 #endif