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