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