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