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