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 = 136;
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 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 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 64 + 16 + 3 + 8];
01256 uint32 tmp[2];
01257 uint32 size;
01258 lzo_uint len;
01259
01260
01261 if (fread(tmp, sizeof(tmp), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01262
01263
01264 ((uint32*)out)[0] = size = tmp[1];
01265
01266 if (_sl_version != 0) {
01267 tmp[0] = TO_BE32(tmp[0]);
01268 size = TO_BE32(size);
01269 }
01270
01271 if (size >= sizeof(out)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Inconsistent size");
01272
01273
01274 if (fread(out + sizeof(uint32), size, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01275
01276
01277 if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Bad checksum");
01278
01279
01280 lzo1x_decompress(out + sizeof(uint32) * 1, size, _sl.buf, &len, NULL);
01281 return len;
01282 }
01283
01284
01285
01286 static void WriteLZO(size_t size)
01287 {
01288 byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 64 + 16 + 3 + 8];
01289 byte wrkmem[sizeof(byte*) * 4096];
01290 lzo_uint outlen;
01291
01292 lzo1x_1_compress(_sl.buf, (lzo_uint)size, out + sizeof(uint32) * 2, &outlen, wrkmem);
01293 ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01294 ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01295 if (fwrite(out, outlen + sizeof(uint32) * 2, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01296 }
01297
01298 static bool InitLZO(byte compression)
01299 {
01300 _sl.bufsize = LZO_BUFFER_SIZE;
01301 _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_BUFFER_SIZE);
01302 return true;
01303 }
01304
01305 static void UninitLZO()
01306 {
01307 free(_sl.buf_ori);
01308 }
01309
01310 #endif
01311
01312
01313
01314
01315
01317 static const uint NOCOMP_BUFFER_SIZE = 8192;
01318
01319 static size_t ReadNoComp()
01320 {
01321 return fread(_sl.buf, 1, NOCOMP_BUFFER_SIZE, _sl.fh);
01322 }
01323
01324 static void WriteNoComp(size_t size)
01325 {
01326 if (fwrite(_sl.buf, 1, size, _sl.fh) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01327 }
01328
01329 static bool InitNoComp(byte compression)
01330 {
01331 _sl.bufsize = NOCOMP_BUFFER_SIZE;
01332 _sl.buf = _sl.buf_ori = MallocT<byte>(NOCOMP_BUFFER_SIZE);
01333 return true;
01334 }
01335
01336 static void UninitNoComp()
01337 {
01338 free(_sl.buf_ori);
01339 }
01340
01341
01342
01343
01344
01345 #include "../gui.h"
01346
01347 struct ThreadedSave {
01348 uint count;
01349 byte ff_state;
01350 bool saveinprogress;
01351 CursorID cursor;
01352 };
01353
01355 static const int MEMORY_CHUNK_SIZE = 128 * 1024;
01357 static AutoFreeSmallVector<byte *, 16> _memory_savegame;
01358
01359 static ThreadedSave _ts;
01360
01361 static void WriteMem(size_t size)
01362 {
01363 _ts.count += (uint)size;
01364
01365 _sl.buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
01366 *_memory_savegame.Append() = _sl.buf;
01367 }
01368
01369 static void UnInitMem()
01370 {
01371 _memory_savegame.Clear();
01372 }
01373
01374 static bool InitMem()
01375 {
01376 _ts.count = 0;
01377 _sl.bufsize = MEMORY_CHUNK_SIZE;
01378
01379 UnInitMem();
01380 WriteMem(0);
01381 return true;
01382 }
01383
01384
01385
01386
01387
01388 #if defined(WITH_ZLIB)
01389 #include <zlib.h>
01390
01392 static const uint ZLIB_BUFFER_SIZE = 8192;
01393
01394 static z_stream _z;
01395
01396 static bool InitReadZlib(byte compression)
01397 {
01398 memset(&_z, 0, sizeof(_z));
01399 if (inflateInit(&_z) != Z_OK) return false;
01400
01401 _sl.bufsize = ZLIB_BUFFER_SIZE;
01402 _sl.buf = _sl.buf_ori = MallocT<byte>(ZLIB_BUFFER_SIZE + ZLIB_BUFFER_SIZE);
01403 return true;
01404 }
01405
01406 static size_t ReadZlib()
01407 {
01408 int r;
01409
01410 _z.next_out = _sl.buf;
01411 _z.avail_out = ZLIB_BUFFER_SIZE;
01412
01413 do {
01414
01415 if (_z.avail_in == 0) {
01416 _z.avail_in = (uint)fread(_z.next_in = _sl.buf + ZLIB_BUFFER_SIZE, 1, ZLIB_BUFFER_SIZE, _sl.fh);
01417 }
01418
01419
01420 r = inflate(&_z, 0);
01421 if (r == Z_STREAM_END)
01422 break;
01423
01424 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
01425 } while (_z.avail_out);
01426
01427 return ZLIB_BUFFER_SIZE - _z.avail_out;
01428 }
01429
01430 static void UninitReadZlib()
01431 {
01432 inflateEnd(&_z);
01433 free(_sl.buf_ori);
01434 }
01435
01436 static bool InitWriteZlib(byte compression)
01437 {
01438 memset(&_z, 0, sizeof(_z));
01439 if (deflateInit(&_z, compression) != Z_OK) return false;
01440
01441 _sl.bufsize = ZLIB_BUFFER_SIZE;
01442 _sl.buf = _sl.buf_ori = MallocT<byte>(ZLIB_BUFFER_SIZE);
01443 return true;
01444 }
01445
01446 static void WriteZlibLoop(z_streamp z, byte *p, size_t len, int mode)
01447 {
01448 byte buf[ZLIB_BUFFER_SIZE];
01449 int r;
01450 uint n;
01451 z->next_in = p;
01452 z->avail_in = (uInt)len;
01453 do {
01454 z->next_out = buf;
01455 z->avail_out = sizeof(buf);
01456
01464 r = deflate(z, mode);
01465
01466
01467 if ((n = sizeof(buf) - z->avail_out) != 0) {
01468 if (fwrite(buf, n, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01469 }
01470 if (r == Z_STREAM_END)
01471 break;
01472 if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
01473 } while (z->avail_in || !z->avail_out);
01474 }
01475
01476 static void WriteZlib(size_t len)
01477 {
01478 WriteZlibLoop(&_z, _sl.buf, len, 0);
01479 }
01480
01481 static void UninitWriteZlib()
01482 {
01483
01484 if (_sl.fh) WriteZlibLoop(&_z, NULL, 0, Z_FINISH);
01485 deflateEnd(&_z);
01486 free(_sl.buf_ori);
01487 }
01488
01489 #endif
01490
01491
01492
01493
01494
01505 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01506 {
01507 assert(_sl.action == SLA_SAVE);
01508
01509 if (obj == NULL) return 0;
01510
01511 switch (rt) {
01512 case REF_VEHICLE_OLD:
01513 case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1;
01514 case REF_STATION: return ((const Station*)obj)->index + 1;
01515 case REF_TOWN: return ((const Town*)obj)->index + 1;
01516 case REF_ORDER: return ((const Order*)obj)->index + 1;
01517 case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01518 case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01519 case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
01520 case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
01521 default: NOT_REACHED();
01522 }
01523 }
01524
01535 static void *IntToReference(size_t index, SLRefType rt)
01536 {
01537 assert_compile(sizeof(size_t) <= sizeof(void *));
01538
01539 assert(_sl.action == SLA_PTRS);
01540
01541
01542
01543 if (rt == REF_VEHICLE_OLD && !CheckSavegameVersionOldStyle(4, 4)) {
01544 rt = REF_VEHICLE;
01545 }
01546
01547
01548 if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01549
01550
01551
01552 if (rt != REF_VEHICLE_OLD) index--;
01553
01554 switch (rt) {
01555 case REF_ORDERLIST:
01556 if (OrderList::IsValidID(index)) return OrderList::Get(index);
01557 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid OrderList");
01558
01559 case REF_ORDER:
01560 if (Order::IsValidID(index)) return Order::Get(index);
01561
01562 if (CheckSavegameVersionOldStyle(5, 2)) return NULL;
01563 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Order");
01564
01565 case REF_VEHICLE_OLD:
01566 case REF_VEHICLE:
01567 if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01568 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Vehicle");
01569
01570 case REF_STATION:
01571 if (Station::IsValidID(index)) return Station::Get(index);
01572 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Station");
01573
01574 case REF_TOWN:
01575 if (Town::IsValidID(index)) return Town::Get(index);
01576 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Town");
01577
01578 case REF_ROADSTOPS:
01579 if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01580 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid RoadStop");
01581
01582 case REF_ENGINE_RENEWS:
01583 if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01584 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid EngineRenew");
01585
01586 case REF_CARGO_PACKET:
01587 if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01588 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid CargoPacket");
01589
01590 default: NOT_REACHED();
01591 }
01592 }
01593
01595 struct SaveLoadFormat {
01596 const char *name;
01597 uint32 tag;
01598
01599 bool (*init_read)(byte compression);
01600 ReaderProc *reader;
01601 void (*uninit_read)();
01602
01603 bool (*init_write)(byte compression);
01604 WriterProc *writer;
01605 void (*uninit_write)();
01606
01607 byte min_compression;
01608 byte default_compression;
01609 byte max_compression;
01610 };
01611
01612 static const SaveLoadFormat _saveload_formats[] = {
01613 #if defined(WITH_LZO)
01614 {"lzo", TO_BE32X('OTTD'), InitLZO, ReadLZO, UninitLZO, InitLZO, WriteLZO, UninitLZO, 0, 0, 0},
01615 #else
01616 {"lzo", TO_BE32X('OTTD'), NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0},
01617 #endif
01618 {"none", TO_BE32X('OTTN'), InitNoComp, ReadNoComp, UninitNoComp, InitNoComp, WriteNoComp, UninitNoComp, 0, 0, 0},
01619 #if defined(WITH_ZLIB)
01620 {"zlib", TO_BE32X('OTTZ'), InitReadZlib, ReadZlib, UninitReadZlib, InitWriteZlib, WriteZlib, UninitWriteZlib, 0, 6, 9},
01621 #else
01622 {"zlib", TO_BE32X('OTTZ'), NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0},
01623 #endif
01624 };
01625
01633 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
01634 {
01635 const SaveLoadFormat *def = lastof(_saveload_formats);
01636
01637
01638 while (!def->init_write) def--;
01639
01640 if (!StrEmpty(s)) {
01641
01642 char *complevel = strrchr(s, ':');
01643 if (complevel != NULL) *complevel = '\0';
01644
01645 for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
01646 if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
01647 *compression_level = slf->default_compression;
01648 if (complevel != NULL) {
01649
01650
01651
01652 *complevel = ':';
01653 complevel++;
01654
01655
01656 char *end;
01657 long level = strtol(complevel, &end, 10);
01658 if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
01659 ShowInfoF("Compression level '%s' is not valid.", complevel);
01660 } else {
01661 *compression_level = level;
01662 }
01663 }
01664 return slf;
01665 }
01666 }
01667
01668 ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
01669
01670
01671 if (complevel != NULL) *complevel = ':';
01672 }
01673 *compression_level = def->default_compression;
01674 return def;
01675 }
01676
01677
01678 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
01679 extern bool AfterLoadGame();
01680 extern bool LoadOldSaveGame(const char *file);
01681
01683 static inline SaveOrLoadResult AbortSaveLoad()
01684 {
01685 if (_sl.fh != NULL) fclose(_sl.fh);
01686
01687 _sl.fh = NULL;
01688 return SL_ERROR;
01689 }
01690
01694 static void SaveFileStart()
01695 {
01696 _ts.ff_state = _fast_forward;
01697 _fast_forward = 0;
01698 if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
01699
01700 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
01701 _ts.saveinprogress = true;
01702 }
01703
01706 static void SaveFileDone()
01707 {
01708 if (_game_mode != GM_MENU) _fast_forward = _ts.ff_state;
01709 if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
01710
01711 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
01712 _ts.saveinprogress = false;
01713 }
01714
01716 void SetSaveLoadError(StringID str)
01717 {
01718 _sl.error_str = str;
01719 }
01720
01722 const char *GetSaveLoadErrorString()
01723 {
01724 SetDParam(0, _sl.error_str);
01725 SetDParamStr(1, _sl.extra_msg);
01726
01727 static char err_str[512];
01728 GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
01729 return err_str;
01730 }
01731
01733 static void SaveFileError()
01734 {
01735 SetDParamStr(0, GetSaveLoadErrorString());
01736 ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, 0, 0);
01737 SaveFileDone();
01738 }
01739
01743 static SaveOrLoadResult SaveFileToDisk(bool threaded)
01744 {
01745 _sl.excpt_uninit = NULL;
01746 try {
01747 byte compression;
01748 const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
01749
01750
01751 uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
01752 if (fwrite(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01753
01754 if (!fmt->init_write(compression)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01755
01756 {
01757 uint i;
01758
01759 if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
01760 for (i = 0; i != _memory_savegame.Length() - 1; i++) {
01761 _sl.buf = _memory_savegame[i];
01762 fmt->writer(MEMORY_CHUNK_SIZE);
01763 }
01764
01765
01766
01767 _sl.buf = _memory_savegame[i];
01768 fmt->writer(_ts.count % MEMORY_CHUNK_SIZE);
01769 }
01770
01771 fmt->uninit_write();
01772 if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
01773 UnInitMem();
01774 fclose(_sl.fh);
01775
01776 if (threaded) SetAsyncSaveFinish(SaveFileDone);
01777
01778 return SL_OK;
01779 }
01780 catch (...) {
01781 AbortSaveLoad();
01782 if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
01783
01784
01785 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
01786
01787 if (threaded) {
01788 SetAsyncSaveFinish(SaveFileError);
01789 } else {
01790 SaveFileError();
01791 }
01792 return SL_ERROR;
01793 }
01794 }
01795
01796 static void SaveFileToDiskThread(void *arg)
01797 {
01798 SaveFileToDisk(true);
01799 }
01800
01801 void WaitTillSaved()
01802 {
01803 if (_save_thread == NULL) return;
01804
01805 _save_thread->Join();
01806 delete _save_thread;
01807 _save_thread = NULL;
01808 }
01809
01819 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
01820 {
01821 uint32 hdr[2];
01822
01823
01824 if (_ts.saveinprogress && mode == SL_SAVE) {
01825
01826 if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, 0, 0);
01827 return SL_OK;
01828 }
01829 WaitTillSaved();
01830
01831 _next_offs = 0;
01832
01833
01834 if (mode == SL_OLD_LOAD) {
01835 _engine_mngr.ResetToDefaultMapping();
01836 InitializeGame(256, 256, true, true);
01837 GamelogReset();
01838 if (!LoadOldSaveGame(filename)) return SL_REINIT;
01839 _sl_version = 0;
01840 _sl_minor_version = 0;
01841 GamelogStartAction(GLAT_LOAD);
01842 if (!AfterLoadGame()) {
01843 GamelogStopAction();
01844 return SL_REINIT;
01845 }
01846 GamelogStopAction();
01847 return SL_OK;
01848 }
01849
01850 _sl.excpt_uninit = NULL;
01851 try {
01852 _sl.fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
01853
01854
01855 if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", SAVE_DIR);
01856 if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", BASE_DIR);
01857
01858 if (_sl.fh == NULL) {
01859 SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01860 }
01861
01862 _sl.bufe = _sl.bufp = NULL;
01863 _sl.offs_base = 0;
01864 _sl.action = (mode != 0) ? SLA_SAVE : SLA_LOAD;
01865
01866
01867
01868 if (mode == SL_SAVE) {
01869 DEBUG(desync, 1, "save: %s\n", filename);
01870
01871 _sl.write_bytes = WriteMem;
01872 _sl.excpt_uninit = UnInitMem;
01873 InitMem();
01874
01875 _sl_version = SAVEGAME_VERSION;
01876
01877 SaveViewportBeforeSaveGame();
01878 SlSaveChunks();
01879 SlWriteFill();
01880
01881 SaveFileStart();
01882 if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
01883 if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
01884 if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
01885
01886 SaveOrLoadResult result = SaveFileToDisk(false);
01887 SaveFileDone();
01888
01889 return result;
01890 }
01891 } else {
01892 assert(mode == SL_LOAD);
01893 DEBUG(desync, 1, "load: %s\n", filename);
01894
01895
01896 long pos = ftell(_sl.fh);
01897 if (fread(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01898
01899
01900 const SaveLoadFormat *fmt = _saveload_formats;
01901 for (;;) {
01902
01903 if (fmt == endof(_saveload_formats)) {
01904 DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
01905 clearerr(_sl.fh);
01906 fseek(_sl.fh, pos, SEEK_SET);
01907 _sl_version = 0;
01908 _sl_minor_version = 0;
01909 fmt = _saveload_formats + 1;
01910 break;
01911 }
01912
01913 if (fmt->tag == hdr[0]) {
01914
01915 _sl_version = TO_BE32(hdr[1]) >> 16;
01916
01917
01918
01919
01920 _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
01921
01922 DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
01923
01924
01925 if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
01926 break;
01927 }
01928
01929 fmt++;
01930 }
01931
01932 _sl.read_bytes = fmt->reader;
01933 _sl.excpt_uninit = fmt->uninit_read;
01934
01935
01936 if (fmt->init_read == NULL) {
01937 char err_str[64];
01938 snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
01939 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
01940 }
01941
01942 if (!fmt->init_read(0)) {
01943 char err_str[64];
01944 snprintf(err_str, lengthof(err_str), "Initializing loader '%s' failed", fmt->name);
01945 SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
01946 }
01947
01948 _engine_mngr.ResetToDefaultMapping();
01949
01950
01951
01952
01953 InitializeGame(256, 256, true, true);
01954
01955 GamelogReset();
01956
01957 SlLoadChunks();
01958 SlFixPointers();
01959 fmt->uninit_read();
01960 fclose(_sl.fh);
01961
01962 GamelogStartAction(GLAT_LOAD);
01963
01964 _savegame_type = SGT_OTTD;
01965
01966
01967
01968 if (!AfterLoadGame()) {
01969 GamelogStopAction();
01970 return SL_REINIT;
01971 }
01972
01973 GamelogStopAction();
01974 }
01975
01976 return SL_OK;
01977 }
01978 catch (...) {
01979 AbortSaveLoad();
01980
01981
01982 if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
01983
01984
01985 DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
01986
01987
01988 return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
01989 }
01990 }
01991
01993 void DoExitSave()
01994 {
01995 SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
01996 }
01997
02003 void GenerateDefaultSaveName(char *buf, const char *last)
02004 {
02005
02006
02007
02008 CompanyID cid = _local_company;
02009 if (!Company::IsValidID(cid)) {
02010 const Company *c;
02011 FOR_ALL_COMPANIES(c) {
02012 cid = c->index;
02013 break;
02014 }
02015 }
02016
02017 SetDParam(0, cid);
02018
02019
02020 switch (_settings_client.gui.date_format_in_default_names) {
02021 case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02022 case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02023 case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02024 default: NOT_REACHED();
02025 }
02026 SetDParam(2, _date);
02027
02028
02029 GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02030 SanitizeFilename(buf);
02031 }
02032
02033 #if 0
02034
02040 int GetSavegameType(char *file)
02041 {
02042 const SaveLoadFormat *fmt;
02043 uint32 hdr;
02044 FILE *f;
02045 int mode = SL_OLD_LOAD;
02046
02047 f = fopen(file, "rb");
02048 if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02049 DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02050 mode = SL_LOAD;
02051 } else {
02052
02053 for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02054 if (fmt->tag == hdr) {
02055 mode = SL_LOAD;
02056 break;
02057 }
02058 }
02059 }
02060
02061 fclose(f);
02062 return mode;
02063 }
02064 #endif