# saveload.cpp

Go to the documentation of this file.

    00001 /* $Id: saveload.cpp 15428 2009-02-09 02:57:15Z rubidium $ */
    00002
    00016 #include "../stdafx.h"
    00017 #include "../openttd.h"
    00018 #include "../debug.h"
    00019 #include "../station_base.h"
    00020 #include "../thread.h"
    00021 #include "../town.h"
    00022 #include "../network/network.h"
    00023 #include "../variables.h"
    00024 #include "../window_func.h"
    00025 #include "../strings_func.h"
    00026 #include "../gfx_func.h"
    00027 #include "../core/alloc_func.hpp"
    00028 #include "../core/endian_func.hpp"
    00029 #include "../vehicle_base.h"
    00030 #include "../company_func.h"
    00031 #include "../date_func.h"
    00032 #include "../autoreplace_base.h"
    00033 #include "../statusbar_gui.h"
    00034 #include "../fileio_func.h"
    00035 #include "../gamelog.h"
    00036
    00037 #include "table/strings.h"
    00038
    00039 #include "saveload_internal.h"
    00040
    00041 extern const uint16 SAVEGAME_VERSION = 113;
    00042
    00043 SavegameType _savegame_type;
    00044
    00045 uint32 _ttdp_version;
    00046 uint16 _sl_version;
    00047 byte   _sl_minor_version;
    00048
    00049 typedef void WriterProc(size_t len);
    00050 typedef size_t ReaderProc();
    00051
    00053 static struct {
    00054   bool save;
    00055   byte need_length;
    00056   byte block_mode;
    00057   bool error;
    00058
    00059   size_t obj_len;
    00060   int array_index, last_array_index;
    00061
    00062   size_t offs_base;
    00063
    00064   WriterProc *write_bytes;
    00065   ReaderProc *read_bytes;
    00066
    00067   const ChunkHandler * const *chs;
    00068
    00069   /* When saving/loading savegames, they are always saved to a temporary memory-place
    00070    * to be flushed to file (save) or to final place (load) when full. */
    00071   byte *bufp, *bufe;
    00072
    00073   /* these 3 may be used by compressor/decompressors. */
    00074   byte *buf;
    00075   byte *buf_ori;
    00076   uint bufsize;
    00077   FILE *fh;
    00078
    00079   void (*excpt_uninit)();
    00080   StringID error_str;
    00081   char *extra_msg;
    00082 } _sl;
    00083
    00084
    00085 enum NeedLengthValues {NL_NONE = 0, NL_WANTLENGTH = 1, NL_CALCLENGTH = 2};
    00086
    00090 static void NORETURN SlError(StringID string, const char *extra_msg = NULL)
    00091 {
    00092   _sl.error_str = string;
    00093   free(_sl.extra_msg);
    00094   _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
    00095   throw std::exception();
    00096 }
    00097
    00098 typedef void (*AsyncSaveFinishProc)();
    00099 static AsyncSaveFinishProc _async_save_finish = NULL;
    00100 static ThreadObject *_save_thread;
    00101
    00105 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
    00106 {
    00107   if (_exit_game) return;
    00108   while (_async_save_finish != NULL) CSleep(10);
    00109
    00110   _async_save_finish = proc;
    00111 }
    00112
    00116 void ProcessAsyncSaveFinish()
    00117 {
    00118   if (_async_save_finish == NULL) return;
    00119
    00120   _async_save_finish();
    00121
    00122   _async_save_finish = NULL;
    00123
    00124   if (_save_thread != NULL) {
    00125     _save_thread->Join();
    00126     delete _save_thread;
    00127     _save_thread = NULL;
    00128   }
    00129 }
    00130
    00134 static void SlReadFill()
    00135 {
    00136   size_t len = _sl.read_bytes();
    00137   if (len == 0) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected end of chunk");
    00138
    00139   _sl.bufp = _sl.buf;
    00140   _sl.bufe = _sl.buf + len;
    00141   _sl.offs_base += len;
    00142 }
    00143
    00144 static inline size_t SlGetOffs() {return _sl.offs_base - (_sl.bufe - _sl.bufp);}
    00145
    00150 static inline byte SlCalcConvMemLen(VarType conv)
    00151 {
    00152   static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
    00153   byte length = GB(conv, 4, 4);
    00154   assert(length < lengthof(conv_mem_size));
    00155   return conv_mem_size[length];
    00156 }
    00157
    00162 static inline byte SlCalcConvFileLen(VarType conv)
    00163 {
    00164   static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
    00165   byte length = GB(conv, 0, 4);
    00166   assert(length < lengthof(conv_file_size));
    00167   return conv_file_size[length];
    00168 }
    00169
    00171 static inline size_t SlCalcRefLen() {return CheckSavegameVersion(69) ? 2 : 4;}
    00172
    00177 static void SlWriteFill()
    00178 {
    00179   /* flush the buffer to disk (the writer) */
    00180   if (_sl.bufp != NULL) {
    00181     uint len = _sl.bufp - _sl.buf;
    00182     _sl.offs_base += len;
    00183     if (len) _sl.write_bytes(len);
    00184   }
    00185
    00186   /* All the data from the buffer has been written away, rewind to the beginning
    00187    * to start reading in more data */
    00188   _sl.bufp = _sl.buf;
    00189   _sl.bufe = _sl.buf + _sl.bufsize;
    00190 }
    00191
    00196 static inline byte SlReadByteInternal()
    00197 {
    00198   if (_sl.bufp == _sl.bufe) SlReadFill();
    00199   return *_sl.bufp++;
    00200 }
    00201
    00203 byte SlReadByte() {return SlReadByteInternal();}
    00204
    00209 static inline void SlWriteByteInternal(byte b)
    00210 {
    00211   if (_sl.bufp == _sl.bufe) SlWriteFill();
    00212   *_sl.bufp++ = b;
    00213 }
    00214
    00216 void SlWriteByte(byte b) {SlWriteByteInternal(b);}
    00217
    00218 static inline int SlReadUint16()
    00219 {
    00220   int x = SlReadByte() << 8;
    00221   return x | SlReadByte();
    00222 }
    00223
    00224 static inline uint32 SlReadUint32()
    00225 {
    00226   uint32 x = SlReadUint16() << 16;
    00227   return x | SlReadUint16();
    00228 }
    00229
    00230 static inline uint64 SlReadUint64()
    00231 {
    00232   uint32 x = SlReadUint32();
    00233   uint32 y = SlReadUint32();
    00234   return (uint64)x << 32 | y;
    00235 }
    00236
    00237 static inline void SlWriteUint16(uint16 v)
    00238 {
    00239   SlWriteByte(GB(v, 8, 8));
    00240   SlWriteByte(GB(v, 0, 8));
    00241 }
    00242
    00243 static inline void SlWriteUint32(uint32 v)
    00244 {
    00245   SlWriteUint16(GB(v, 16, 16));
    00246   SlWriteUint16(GB(v,  0, 16));
    00247 }
    00248
    00249 static inline void SlWriteUint64(uint64 x)
    00250 {
    00251   SlWriteUint32((uint32)(x >> 32));
    00252   SlWriteUint32((uint32)x);
    00253 }
    00254
    00264 static uint SlReadSimpleGamma()
    00265 {
    00266   uint i = SlReadByte();
    00267   if (HasBit(i, 7)) {
    00268     i &= ~0x80;
    00269     if (HasBit(i, 6)) {
    00270       i &= ~0x40;
    00271       if (HasBit(i, 5)) {
    00272         i &= ~0x20;
    00273         if (HasBit(i, 4))
    00274           SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unsupported gamma");
    00275         i = (i << 8) | SlReadByte();
    00276       }
    00277       i = (i << 8) | SlReadByte();
    00278     }
    00279     i = (i << 8) | SlReadByte();
    00280   }
    00281   return i;
    00282 }
    00283
    00296 static void SlWriteSimpleGamma(size_t i)
    00297 {
    00298   if (i >= (1 << 7)) {
    00299     if (i >= (1 << 14)) {
    00300       if (i >= (1 << 21)) {
    00301         assert(i < (1 << 28));
    00302         SlWriteByte((byte)(0xE0 | (i >> 24)));
    00303         SlWriteByte((byte)(i >> 16));
    00304       } else {
    00305         SlWriteByte((byte)(0xC0 | (i >> 16)));
    00306       }
    00307       SlWriteByte((byte)(i >> 8));
    00308     } else {
    00309       SlWriteByte((byte)(0x80 | (i >> 8)));
    00310     }
    00311   }
    00312   SlWriteByte((byte)i);
    00313 }
    00314
    00316 static inline uint SlGetGammaLength(size_t i)
    00317 {
    00318   return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
    00319 }
    00320
    00321 static inline uint SlReadSparseIndex() {return SlReadSimpleGamma();}
    00322 static inline void SlWriteSparseIndex(uint index) {SlWriteSimpleGamma(index);}
    00323
    00324 static inline uint SlReadArrayLength() {return SlReadSimpleGamma();}
    00325 static inline void SlWriteArrayLength(size_t length) {SlWriteSimpleGamma(length);}
    00326 static inline uint SlGetArrayLength(size_t length) {return SlGetGammaLength(length);}
    00327
    00328 void SlSetArrayIndex(uint index)
    00329 {
    00330   _sl.need_length = NL_WANTLENGTH;
    00331   _sl.array_index = index;
    00332 }
    00333
    00334 static size_t _next_offs;
    00335
    00340 int SlIterateArray()
    00341 {
    00342   int index;
    00343
    00344   /* After reading in the whole array inside the loop
    00345    * we must have read in all the data, so we must be at end of current block. */
    00346   if (_next_offs != 0 && SlGetOffs() != _next_offs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
    00347
    00348   while (true) {
    00349     uint length = SlReadArrayLength();
    00350     if (length == 0) {
    00351       _next_offs = 0;
    00352       return -1;
    00353     }
    00354
    00355     _sl.obj_len = --length;
    00356     _next_offs = SlGetOffs() + length;
    00357
    00358     switch (_sl.block_mode) {
    00359     case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
    00360     case CH_ARRAY:        index = _sl.array_index++; break;
    00361     default:
    00362       DEBUG(sl, 0, "SlIterateArray error");
    00363       return -1; // error
    00364     }
    00365
    00366     if (length != 0) return index;
    00367   }
    00368 }
    00369
    00375 void SlSetLength(size_t length)
    00376 {
    00377   assert(_sl.save);
    00378
    00379   switch (_sl.need_length) {
    00380   case NL_WANTLENGTH:
    00381     _sl.need_length = NL_NONE;
    00382     switch (_sl.block_mode) {
    00383     case CH_RIFF:
    00384       /* Ugly encoding of >16M RIFF chunks
    00385        * The lower 24 bits are normal
    00386        * The uppermost 4 bits are bits 24:27 */
    00387       assert(length < (1 << 28));
    00388       SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
    00389       break;
    00390     case CH_ARRAY:
    00391       assert(_sl.last_array_index <= _sl.array_index);
    00392       while (++_sl.last_array_index <= _sl.array_index)
    00393         SlWriteArrayLength(1);
    00394       SlWriteArrayLength(length + 1);
    00395       break;
    00396     case CH_SPARSE_ARRAY:
    00397       SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index)); // Also include length of sparse index.
    00398       SlWriteSparseIndex(_sl.array_index);
    00399       break;
    00400     default: NOT_REACHED();
    00401     } break;
    00402   case NL_CALCLENGTH:
    00403     _sl.obj_len += (int)length;
    00404     break;
    00405   }
    00406 }
    00407
    00414 static void SlCopyBytes(void *ptr, size_t length)
    00415 {
    00416   byte *p = (byte*)ptr;
    00417
    00418   if (_sl.save) {
    00419     for (; length != 0; length--) {SlWriteByteInternal(*p++);}
    00420   } else {
    00421     for (; length != 0; length--) {*p++ = SlReadByteInternal();}
    00422   }
    00423 }
    00424
    00429 static inline void SlSkipBytes(size_t length)
    00430 {
    00431   for (; length != 0; length--) SlReadByte();
    00432 }
    00433
    00434 /* Get the length of the current object */
    00435 size_t SlGetFieldLength() {return _sl.obj_len;}
    00436
    00442 int64 ReadValue(const void *ptr, VarType conv)
    00443 {
    00444   switch (GetVarMemType(conv)) {
    00445   case SLE_VAR_BL:  return (*(bool*)ptr != 0);
    00446   case SLE_VAR_I8:  return *(int8*  )ptr;
    00447   case SLE_VAR_U8:  return *(byte*  )ptr;
    00448   case SLE_VAR_I16: return *(int16* )ptr;
    00449   case SLE_VAR_U16: return *(uint16*)ptr;
    00450   case SLE_VAR_I32: return *(int32* )ptr;
    00451   case SLE_VAR_U32: return *(uint32*)ptr;
    00452   case SLE_VAR_I64: return *(int64* )ptr;
    00453   case SLE_VAR_U64: return *(uint64*)ptr;
    00454   case SLE_VAR_NULL:return 0;
    00455   default: NOT_REACHED();
    00456   }
    00457
    00458   /* useless, but avoids compiler warning this way */
    00459   return 0;
    00460 }
    00461
    00467 void WriteValue(void *ptr, VarType conv, int64 val)
    00468 {
    00469   switch (GetVarMemType(conv)) {
    00470   case SLE_VAR_BL:  *(bool  *)ptr = (val != 0);  break;
    00471   case SLE_VAR_I8:  *(int8  *)ptr = val; break;
    00472   case SLE_VAR_U8:  *(byte  *)ptr = val; break;
    00473   case SLE_VAR_I16: *(int16 *)ptr = val; break;
    00474   case SLE_VAR_U16: *(uint16*)ptr = val; break;
    00475   case SLE_VAR_I32: *(int32 *)ptr = val; break;
    00476   case SLE_VAR_U32: *(uint32*)ptr = val; break;
    00477   case SLE_VAR_I64: *(int64 *)ptr = val; break;
    00478   case SLE_VAR_U64: *(uint64*)ptr = val; break;
    00479   case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
    00480   case SLE_VAR_NULL: break;
    00481   default: NOT_REACHED();
    00482   }
    00483 }
    00484
    00493 static void SlSaveLoadConv(void *ptr, VarType conv)
    00494 {
    00495   int64 x = 0;
    00496
    00497   if (_sl.save) { // SAVE values
    00498     /* Read a value from the struct. These ARE endian safe. */
    00499     x = ReadValue(ptr, conv);
    00500
    00501     /* Write the value to the file and check if its value is in the desired range */
    00502     switch (GetVarFileType(conv)) {
    00503     case SLE_FILE_I8: assert(x >= -128 && x <= 127);     SlWriteByte(x);break;
    00504     case SLE_FILE_U8: assert(x >= 0 && x <= 255);        SlWriteByte(x);break;
    00505     case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
    00506     case SLE_FILE_STRINGID:
    00507     case SLE_FILE_U16:assert(x >= 0 && x <= 65535);      SlWriteUint16(x);break;
    00508     case SLE_FILE_I32:
    00509     case SLE_FILE_U32:                                   SlWriteUint32((uint32)x);break;
    00510     case SLE_FILE_I64:
    00511     case SLE_FILE_U64:                                   SlWriteUint64(x);break;
    00512     default: NOT_REACHED();
    00513     }
    00514   } else { // LOAD values
    00515
    00516     /* Read a value from the file */
    00517     switch (GetVarFileType(conv)) {
    00518     case SLE_FILE_I8:  x = (int8  )SlReadByte();   break;
    00519     case SLE_FILE_U8:  x = (byte  )SlReadByte();   break;
    00520     case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
    00521     case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
    00522     case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
    00523     case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
    00524     case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
    00525     case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
    00526     case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
    00527     default: NOT_REACHED();
    00528     }
    00529
    00530     /* Write The value to the struct. These ARE endian safe. */
    00531     WriteValue(ptr, conv, x);
    00532   }
    00533 }
    00534
    00542 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
    00543 {
    00544   if (ptr == NULL) return 0;
    00545   return min(strlen(ptr), length - 1);
    00546 }
    00547
    00555 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
    00556 {
    00557   size_t len;
    00558   const char *str;
    00559
    00560   switch (GetVarMemType(conv)) {
    00561     default: NOT_REACHED();
    00562     case SLE_VAR_STR:
    00563     case SLE_VAR_STRQ:
    00564       str = *(const char**)ptr;
    00565       len = SIZE_MAX;
    00566       break;
    00567     case SLE_VAR_STRB:
    00568     case SLE_VAR_STRBQ:
    00569       str = (const char*)ptr;
    00570       len = length;
    00571       break;
    00572   }
    00573
    00574   len = SlCalcNetStringLen(str, len);
    00575   return len + SlGetArrayLength(len); // also include the length of the index
    00576 }
    00577
    00583 static void SlString(void *ptr, size_t length, VarType conv)
    00584 {
    00585   size_t len;
    00586
    00587   if (_sl.save) { // SAVE string
    00588     switch (GetVarMemType(conv)) {
    00589       default: NOT_REACHED();
    00590       case SLE_VAR_STRB:
    00591       case SLE_VAR_STRBQ:
    00592         len = SlCalcNetStringLen((char*)ptr, length);
    00593         break;
    00594       case SLE_VAR_STR:
    00595       case SLE_VAR_STRQ:
    00596         ptr = *(char**)ptr;
    00597         len = SlCalcNetStringLen((char*)ptr, SIZE_MAX);
    00598         break;
    00599     }
    00600
    00601     SlWriteArrayLength(len);
    00602     SlCopyBytes(ptr, len);
    00603   } else { // LOAD string
    00604     len = SlReadArrayLength();
    00605
    00606     switch (GetVarMemType(conv)) {
    00607       default: NOT_REACHED();
    00608       case SLE_VAR_STRB:
    00609       case SLE_VAR_STRBQ:
    00610         if (len >= length) {
    00611           DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
    00612           SlCopyBytes(ptr, length);
    00613           SlSkipBytes(len - length);
    00614           len = length - 1;
    00615         } else {
    00616           SlCopyBytes(ptr, len);
    00617         }
    00618         break;
    00619       case SLE_VAR_STR:
    00620       case SLE_VAR_STRQ: // Malloc'd string, free previous incarnation, and allocate
    00621         free(*(char**)ptr);
    00622         if (len == 0) {
    00623           *(char**)ptr = NULL;
    00624         } else {
    00625           *(char**)ptr = MallocT<char>(len + 1); // terminating '\0'
    00626           ptr = *(char**)ptr;
    00627           SlCopyBytes(ptr, len);
    00628         }
    00629         break;
    00630     }
    00631
    00632     ((char*)ptr)[len] = '\0'; // properly terminate the string
    00633   }
    00634 }
    00635
    00641 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
    00642 {
    00643   return SlCalcConvFileLen(conv) * length;
    00644 }
    00645
    00652 void SlArray(void *array, size_t length, VarType conv)
    00653 {
    00654   /* Automatically calculate the length? */
    00655   if (_sl.need_length != NL_NONE) {
    00656     SlSetLength(SlCalcArrayLen(length, conv));
    00657     /* Determine length only? */
    00658     if (_sl.need_length == NL_CALCLENGTH) return;
    00659   }
    00660
    00661   /* NOTICE - handle some buggy stuff, in really old versions everything was saved
    00662    * as a byte-type. So detect this, and adjust array size accordingly */
    00663   if (!_sl.save && _sl_version == 0) {
    00664     /* all arrays except difficulty settings */
    00665     if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
    00666         conv == SLE_INT32 || conv == SLE_UINT32) {
    00667       SlCopyBytes(array, length * SlCalcConvFileLen(conv));
    00668       return;
    00669     }
    00670     /* used for conversion of Money 32bit->64bit */
    00671     if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
    00672       for (uint i = 0; i < length; i++) {
    00673         ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
    00674       }
    00675       return;
    00676     }
    00677   }
    00678
    00679   /* If the size of elements is 1 byte both in file and memory, no special
    00680    * conversion is needed, use specialized copy-copy function to speed up things */
    00681   if (conv == SLE_INT8 || conv == SLE_UINT8) {
    00682     SlCopyBytes(array, length);
    00683   } else {
    00684     byte *a = (byte*)array;
    00685     byte mem_size = SlCalcConvMemLen(conv);
    00686
    00687     for (; length != 0; length --) {
    00688       SlSaveLoadConv(a, conv);
    00689       a += mem_size; // get size
    00690     }
    00691   }
    00692 }
    00693
    00694
    00695 static uint ReferenceToInt(const void *obj, SLRefType rt);
    00696 static void *IntToReference(uint index, SLRefType rt);
    00697
    00698
    00703 static inline size_t SlCalcListLen(const void *list)
    00704 {
    00705   std::list<void *> *l = (std::list<void *> *) list;
    00706
    00707   int type_size = CheckSavegameVersion(69) ? 2 : 4;
    00708   /* Each entry is saved as type_size bytes, plus type_size bytes are used for the length
    00709    * of the list */
    00710   return l->size() * type_size + type_size;
    00711 }
    00712
    00713
    00719 void SlList(void *list, SLRefType conv)
    00720 {
    00721   /* Automatically calculate the length? */
    00722   if (_sl.need_length != NL_NONE) {
    00723     SlSetLength(SlCalcListLen(list));
    00724     /* Determine length only? */
    00725     if (_sl.need_length == NL_CALCLENGTH) return;
    00726   }
    00727
    00728   std::list<void *> *l = (std::list<void *> *) list;
    00729
    00730   if (_sl.save) {
    00731     SlWriteUint32((uint32)l->size());
    00732
    00733     std::list<void *>::iterator iter;
    00734     for (iter = l->begin(); iter != l->end(); ++iter) {
    00735       void *ptr = *iter;
    00736       SlWriteUint32(ReferenceToInt(ptr, conv));
    00737     }
    00738   } else {
    00739     uint length = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
    00740
    00741     /* Load each reference and push to the end of the list */
    00742     for (uint i = 0; i < length; i++) {
    00743       void *ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), conv);
    00744       l->push_back(ptr);
    00745     }
    00746   }
    00747 }
    00748
    00749
    00751 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
    00752 {
    00753   if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
    00754   if (sld->conv & SLF_SAVE_NO) return false;
    00755
    00756   return true;
    00757 }
    00758
    00762 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
    00763 {
    00764   if ((sld->conv & SLF_NETWORK_NO) && !_sl.save && _networking && !_network_server) {
    00765     SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
    00766     return true;
    00767   }
    00768
    00769   return false;
    00770 }
    00771
    00778 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
    00779 {
    00780   size_t length = 0;
    00781
    00782   /* Need to determine the length and write a length tag. */
    00783   for (; sld->cmd != SL_END; sld++) {
    00784     length += SlCalcObjMemberLength(object, sld);
    00785   }
    00786   return length;
    00787 }
    00788
    00789 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
    00790 {
    00791   assert(_sl.save);
    00792
    00793   switch (sld->cmd) {
    00794     case SL_VAR:
    00795     case SL_REF:
    00796     case SL_ARR:
    00797     case SL_STR:
    00798     case SL_LST:
    00799       /* CONDITIONAL saveload types depend on the savegame version */
    00800       if (!SlIsObjectValidInSavegame(sld)) break;
    00801
    00802       switch (sld->cmd) {
    00803       case SL_VAR: return SlCalcConvFileLen(sld->conv);
    00804       case SL_REF: return SlCalcRefLen();
    00805       case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
    00806       case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
    00807       case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
    00808       default: NOT_REACHED();
    00809       }
    00810       break;
    00811     case SL_WRITEBYTE: return 1; // a byte is logically of size 1
    00812     case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
    00813     default: NOT_REACHED();
    00814   }
    00815   return 0;
    00816 }
    00817
    00818
    00819 bool SlObjectMember(void *ptr, const SaveLoad *sld)
    00820 {
    00821   VarType conv = GB(sld->conv, 0, 8);
    00822   switch (sld->cmd) {
    00823   case SL_VAR:
    00824   case SL_REF:
    00825   case SL_ARR:
    00826   case SL_STR:
    00827   case SL_LST:
    00828     /* CONDITIONAL saveload types depend on the savegame version */
    00829     if (!SlIsObjectValidInSavegame(sld)) return false;
    00830     if (SlSkipVariableOnLoad(sld)) return false;
    00831
    00832     switch (sld->cmd) {
    00833     case SL_VAR: SlSaveLoadConv(ptr, conv); break;
    00834     case SL_REF: // Reference variable, translate
    00835       if (_sl.save) {
    00836         SlWriteUint32(ReferenceToInt(*(void**)ptr, (SLRefType)conv));
    00837       } else {
    00838         *(void**)ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), (SLRefType)conv);
    00839       }
    00840       break;
    00841     case SL_ARR: SlArray(ptr, sld->length, conv); break;
    00842     case SL_STR: SlString(ptr, sld->length, conv); break;
    00843     case SL_LST: SlList(ptr, (SLRefType)conv); break;
    00844     default: NOT_REACHED();
    00845     }
    00846     break;
    00847
    00848   /* SL_WRITEBYTE translates a value of a variable to another one upon
    00849    * saving or loading.
    00850    * XXX - variable renaming abuse
    00851    * game_value: the value of the variable ingame is abused by sld->version_from
    00852    * file_value: the value of the variable in the savegame is abused by sld->version_to */
    00853   case SL_WRITEBYTE:
    00854     if (_sl.save) {
    00855       SlWriteByte(sld->version_to);
    00856     } else {
    00857       *(byte*)ptr = sld->version_from;
    00858     }
    00859     break;
    00860
    00861   /* SL_VEH_INCLUDE loads common code for vehicles */
    00862   case SL_VEH_INCLUDE:
    00863     SlObject(ptr, GetVehicleDescription(VEH_END));
    00864     break;
    00865   default: NOT_REACHED();
    00866   }
    00867   return true;
    00868 }
    00869
    00875 void SlObject(void *object, const SaveLoad *sld)
    00876 {
    00877   /* Automatically calculate the length? */
    00878   if (_sl.need_length != NL_NONE) {
    00879     SlSetLength(SlCalcObjLength(object, sld));
    00880     if (_sl.need_length == NL_CALCLENGTH) return;
    00881   }
    00882
    00883   for (; sld->cmd != SL_END; sld++) {
    00884     void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
    00885     SlObjectMember(ptr, sld);
    00886   }
    00887 }
    00888
    00893 void SlGlobList(const SaveLoadGlobVarList *sldg)
    00894 {
    00895   SlObject(NULL, (const SaveLoad*)sldg);
    00896 }
    00897
    00903 void SlAutolength(AutolengthProc *proc, void *arg)
    00904 {
    00905   size_t offs;
    00906
    00907   assert(_sl.save);
    00908
    00909   /* Tell it to calculate the length */
    00910   _sl.need_length = NL_CALCLENGTH;
    00911   _sl.obj_len = 0;
    00912   proc(arg);
    00913
    00914   /* Setup length */
    00915   _sl.need_length = NL_WANTLENGTH;
    00916   SlSetLength(_sl.obj_len);
    00917
    00918   offs = SlGetOffs() + _sl.obj_len;
    00919
    00920   /* And write the stuff */
    00921   proc(arg);
    00922
    00923   if (offs != SlGetOffs()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
    00924 }
    00925
    00930 static void SlLoadChunk(const ChunkHandler *ch)
    00931 {
    00932   byte m = SlReadByte();
    00933   size_t len;
    00934   size_t endoffs;
    00935
    00936   _sl.block_mode = m;
    00937   _sl.obj_len = 0;
    00938
    00939   switch (m) {
    00940   case CH_ARRAY:
    00941     _sl.array_index = 0;
    00942     ch->load_proc();
    00943     break;
    00944   case CH_SPARSE_ARRAY:
    00945     ch->load_proc();
    00946     break;
    00947   default:
    00948     if ((m & 0xF) == CH_RIFF) {
    00949       /* Read length */
    00950       len = (SlReadByte() << 16) | ((m >> 4) << 24);
    00951       len += SlReadUint16();
    00952       _sl.obj_len = len;
    00953       endoffs = SlGetOffs() + len;
    00954       ch->load_proc();
    00955       if (SlGetOffs() != endoffs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
    00956     } else {
    00957       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk type");
    00958     }
    00959     break;
    00960   }
    00961 }
    00962
    00963 /* Stub Chunk handlers to only calculate length and do nothing else */
    00964 static ChunkSaveLoadProc *_tmp_proc_1;
    00965 static inline void SlStubSaveProc2(void *arg) {_tmp_proc_1();}
    00966 static void SlStubSaveProc() {SlAutolength(SlStubSaveProc2, NULL);}
    00967
    00972 static void SlSaveChunk(const ChunkHandler *ch)
    00973 {
    00974   ChunkSaveLoadProc *proc = ch->save_proc;
    00975
    00976   /* Don't save any chunk information if there is no save handler. */
    00977   if (proc == NULL) return;
    00978
    00979   SlWriteUint32(ch->id);
    00980   DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
    00981
    00982   if (ch->flags & CH_AUTO_LENGTH) {
    00983     /* Need to calculate the length. Solve that by calling SlAutoLength in the save_proc. */
    00984     _tmp_proc_1 = proc;
    00985     proc = SlStubSaveProc;
    00986   }
    00987
    00988   _sl.block_mode = ch->flags & CH_TYPE_MASK;
    00989   switch (ch->flags & CH_TYPE_MASK) {
    00990   case CH_RIFF:
    00991     _sl.need_length = NL_WANTLENGTH;
    00992     proc();
    00993     break;
    00994   case CH_ARRAY:
    00995     _sl.last_array_index = 0;
    00996     SlWriteByte(CH_ARRAY);
    00997     proc();
    00998     SlWriteArrayLength(0); // Terminate arrays
    00999     break;
    01000   case CH_SPARSE_ARRAY:
    01001     SlWriteByte(CH_SPARSE_ARRAY);
    01002     proc();
    01003     SlWriteArrayLength(0); // Terminate arrays
    01004     break;
    01005   default: NOT_REACHED();
    01006   }
    01007 }
    01008
    01010 static void SlSaveChunks()
    01011 {
    01012   const ChunkHandler *ch;
    01013   const ChunkHandler * const *chsc;
    01014   uint p;
    01015
    01016   for (p = 0; p != CH_NUM_PRI_LEVELS; p++) {
    01017     for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
    01018       while (true) {
    01019         if (((ch->flags >> CH_PRI_SHL) & (CH_NUM_PRI_LEVELS - 1)) == p)
    01020           SlSaveChunk(ch);
    01021         if (ch->flags & CH_LAST)
    01022           break;
    01023         ch++;
    01024       }
    01025     }
    01026   }
    01027
    01028   /* Terminator */
    01029   SlWriteUint32(0);
    01030 }
    01031
    01037 static const ChunkHandler *SlFindChunkHandler(uint32 id)
    01038 {
    01039   const ChunkHandler *ch;
    01040   const ChunkHandler *const *chsc;
    01041   for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
    01042     for (;;) {
    01043       if (ch->id == id) return ch;
    01044       if (ch->flags & CH_LAST) break;
    01045       ch++;
    01046     }
    01047   }
    01048   return NULL;
    01049 }
    01050
    01052 static void SlLoadChunks()
    01053 {
    01054   uint32 id;
    01055   const ChunkHandler *ch;
    01056
    01057   for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
    01058     DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
    01059
    01060     ch = SlFindChunkHandler(id);
    01061     if (ch == NULL) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unknown chunk type");
    01062     SlLoadChunk(ch);
    01063   }
    01064 }
    01065
    01066 /*******************************************
    01067  ********** START OF LZO CODE **************
    01068  *******************************************/
    01069 #define LZO_SIZE 8192
    01070
    01071 #include "../minilzo.h"
    01072
    01073 static size_t ReadLZO()
    01074 {
    01075   byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
    01076   uint32 tmp[2];
    01077   uint32 size;
    01078   uint len;
    01079
    01080   /* Read header*/
    01081   if (fread(tmp, sizeof(tmp), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
    01082
    01083   /* Check if size is bad */
    01084   ((uint32*)out)[0] = size = tmp[1];
    01085
    01086   if (_sl_version != 0) {
    01087     tmp[0] = TO_BE32(tmp[0]);
    01088     size = TO_BE32(size);
    01089   }
    01090
    01091   if (size >= sizeof(out)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Inconsistent size");
    01092
    01093   /* Read block */
    01094   if (fread(out + sizeof(uint32), size, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
    01095
    01096   /* Verify checksum */
    01097   if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Bad checksum");
    01098
    01099   /* Decompress */
    01100   lzo1x_decompress(out + sizeof(uint32) * 1, size, _sl.buf, &len, NULL);
    01101   return len;
    01102 }
    01103
    01104 /* p contains the pointer to the buffer, len contains the pointer to the length.
    01105  * len bytes will be written, p and l will be updated to reflect the next buffer. */
    01106 static void WriteLZO(size_t size)
    01107 {
    01108   byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
    01109   byte wrkmem[sizeof(byte*) * 4096];
    01110   uint outlen;
    01111
    01112   lzo1x_1_compress(_sl.buf, (lzo_uint)size, out + sizeof(uint32) * 2, &outlen, wrkmem);
    01113   ((uint32*)out)[1] = TO_BE32(outlen);
    01114   ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
    01115   if (fwrite(out, outlen + sizeof(uint32) * 2, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
    01116 }
    01117
    01118 static bool InitLZO()
    01119 {
    01120   _sl.bufsize = LZO_SIZE;
    01121   _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
    01122   return true;
    01123 }
    01124
    01125 static void UninitLZO()
    01126 {
    01127   free(_sl.buf_ori);
    01128 }
    01129
    01130 /*********************************************
    01131  ******** START OF NOCOMP CODE (uncompressed)*
    01132  *********************************************/
    01133 static size_t ReadNoComp()
    01134 {
    01135   return fread(_sl.buf, 1, LZO_SIZE, _sl.fh);
    01136 }
    01137
    01138 static void WriteNoComp(size_t size)
    01139 {
    01140   if (fwrite(_sl.buf, 1, size, _sl.fh) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
    01141 }
    01142
    01143 static bool InitNoComp()
    01144 {
    01145   _sl.bufsize = LZO_SIZE;
    01146   _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
    01147   return true;
    01148 }
    01149
    01150 static void UninitNoComp()
    01151 {
    01152   free(_sl.buf_ori);
    01153 }
    01154
    01155 /********************************************
    01156  ********** START OF MEMORY CODE (in ram)****
    01157  ********************************************/
    01158
    01159 #include "../gui.h"
    01160
    01161 struct ThreadedSave {
    01162   uint count;
    01163   byte ff_state;
    01164   bool saveinprogress;
    01165   CursorID cursor;
    01166 };
    01167
    01168 /* A maximum size of of 128K * 500 = 64.000KB savegames */
    01169 STATIC_OLD_POOL(Savegame, byte, 17, 500, NULL, NULL)
    01170 static ThreadedSave _ts;
    01171
    01172 static bool InitMem()
    01173 {
    01174   _ts.count = 0;
    01175
    01176   _Savegame_pool.CleanPool();
    01177   _Savegame_pool.AddBlockToPool();
    01178
    01179   /* A block from the pool is a contigious area of memory, so it is safe to write to it sequentially */
    01180   _sl.bufsize = GetSavegamePoolSize();
    01181   _sl.buf = GetSavegame(_ts.count);
    01182   return true;
    01183 }
    01184
    01185 static void UnInitMem()
    01186 {
    01187   _Savegame_pool.CleanPool();
    01188 }
    01189
    01190 static void WriteMem(size_t size)
    01191 {
    01192   _ts.count += (uint)size;
    01193   /* Allocate new block and new buffer-pointer */
    01194   _Savegame_pool.AddBlockIfNeeded(_ts.count);
    01195   _sl.buf = GetSavegame(_ts.count);
    01196 }
    01197
    01198 /********************************************
    01199  ********** START OF ZLIB CODE **************
    01200  ********************************************/
    01201
    01202 #if defined(WITH_ZLIB)
    01203 #include <zlib.h>
    01204
    01205 static z_stream _z;
    01206
    01207 static bool InitReadZlib()
    01208 {
    01209   memset(&_z, 0, sizeof(_z));
    01210   if (inflateInit(&_z) != Z_OK) return false;
    01211
    01212   _sl.bufsize = 4096;
    01213   _sl.buf = _sl.buf_ori = MallocT<byte>(4096 + 4096); // also contains fread buffer
    01214   return true;
    01215 }
    01216
    01217 static size_t ReadZlib()
    01218 {
    01219   int r;
    01220
    01221   _z.next_out = _sl.buf;
    01222   _z.avail_out = 4096;
    01223
    01224   do {
    01225     /* read more bytes from the file? */
    01226     if (_z.avail_in == 0) {
    01227       _z.avail_in = (uint)fread(_z.next_in = _sl.buf + 4096, 1, 4096, _sl.fh);
    01228     }
    01229
    01230     /* inflate the data */
    01231     r = inflate(&_z, 0);
    01232     if (r == Z_STREAM_END)
    01233       break;
    01234
    01235     if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
    01236   } while (_z.avail_out);
    01237
    01238   return 4096 - _z.avail_out;
    01239 }
    01240
    01241 static void UninitReadZlib()
    01242 {
    01243   inflateEnd(&_z);
    01244   free(_sl.buf_ori);
    01245 }
    01246
    01247 static bool InitWriteZlib()
    01248 {
    01249   memset(&_z, 0, sizeof(_z));
    01250   if (deflateInit(&_z, 6) != Z_OK) return false;
    01251
    01252   _sl.bufsize = 4096;
    01253   _sl.buf = _sl.buf_ori = MallocT<byte>(4096);
    01254   return true;
    01255 }
    01256
    01257 static void WriteZlibLoop(z_streamp z, byte *p, size_t len, int mode)
    01258 {
    01259   byte buf[1024]; // output buffer
    01260   int r;
    01261   uint n;
    01262   z->next_in = p;
    01263   z->avail_in = (uInt)len;
    01264   do {
    01265     z->next_out = buf;
    01266     z->avail_out = sizeof(buf);
    01267
    01275     r = deflate(z, mode);
    01276
    01277     /* bytes were emitted? */
    01278     if ((n = sizeof(buf) - z->avail_out) != 0) {
    01279       if (fwrite(buf, n, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
    01280     }
    01281     if (r == Z_STREAM_END)
    01282       break;
    01283     if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
    01284   } while (z->avail_in || !z->avail_out);
    01285 }
    01286
    01287 static void WriteZlib(size_t len)
    01288 {
    01289   WriteZlibLoop(&_z, _sl.buf, len, 0);
    01290 }
    01291
    01292 static void UninitWriteZlib()
    01293 {
    01294   /* flush any pending output. */
    01295   if (_sl.fh) WriteZlibLoop(&_z, NULL, 0, Z_FINISH);
    01296   deflateEnd(&_z);
    01297   free(_sl.buf_ori);
    01298 }
    01299
    01300 #endif /* WITH_ZLIB */
    01301
    01302 /*******************************************
    01303  ************* END OF CODE *****************
    01304  *******************************************/
    01305
    01306 /* these define the chunks */
    01307 extern const ChunkHandler _gamelog_chunk_handlers[];
    01308 extern const ChunkHandler _map_chunk_handlers[];
    01309 extern const ChunkHandler _misc_chunk_handlers[];
    01310 extern const ChunkHandler _name_chunk_handlers[];
    01311 extern const ChunkHandler _cheat_chunk_handlers[] ;
    01312 extern const ChunkHandler _setting_chunk_handlers[];
    01313 extern const ChunkHandler _company_chunk_handlers[];
    01314 extern const ChunkHandler _engine_chunk_handlers[];
    01315 extern const ChunkHandler _veh_chunk_handlers[];
    01316 extern const ChunkHandler _waypoint_chunk_handlers[];
    01317 extern const ChunkHandler _depot_chunk_handlers[];
    01318 extern const ChunkHandler _order_chunk_handlers[];
    01319 extern const ChunkHandler _town_chunk_handlers[];
    01320 extern const ChunkHandler _sign_chunk_handlers[];
    01321 extern const ChunkHandler _station_chunk_handlers[];
    01322 extern const ChunkHandler _industry_chunk_handlers[];
    01323 extern const ChunkHandler _economy_chunk_handlers[];
    01324 extern const ChunkHandler _subsidy_chunk_handlers[];
    01325 extern const ChunkHandler _ai_chunk_handlers[];
    01326 extern const ChunkHandler _animated_tile_chunk_handlers[];
    01327 extern const ChunkHandler _newgrf_chunk_handlers[];
    01328 extern const ChunkHandler _group_chunk_handlers[];
    01329 extern const ChunkHandler _cargopacket_chunk_handlers[];
    01330 extern const ChunkHandler _autoreplace_chunk_handlers[];
    01331
    01332 static const ChunkHandler * const _chunk_handlers[] = {
    01333   _gamelog_chunk_handlers,
    01334   _map_chunk_handlers,
    01335   _misc_chunk_handlers,
    01336   _name_chunk_handlers,
    01337   _cheat_chunk_handlers,
    01338   _setting_chunk_handlers,
    01339   _veh_chunk_handlers,
    01340   _waypoint_chunk_handlers,
    01341   _depot_chunk_handlers,
    01342   _order_chunk_handlers,
    01343   _industry_chunk_handlers,
    01344   _economy_chunk_handlers,
    01345   _subsidy_chunk_handlers,
    01346   _engine_chunk_handlers,
    01347   _town_chunk_handlers,
    01348   _sign_chunk_handlers,
    01349   _station_chunk_handlers,
    01350   _company_chunk_handlers,
    01351   _ai_chunk_handlers,
    01352   _animated_tile_chunk_handlers,
    01353   _newgrf_chunk_handlers,
    01354   _group_chunk_handlers,
    01355   _cargopacket_chunk_handlers,
    01356   _autoreplace_chunk_handlers,
    01357   NULL,
    01358 };
    01359
    01370 static uint ReferenceToInt(const void *obj, SLRefType rt)
    01371 {
    01372   if (obj == NULL) return 0;
    01373
    01374   switch (rt) {
    01375     case REF_VEHICLE_OLD: // Old vehicles we save as new onces
    01376     case REF_VEHICLE:   return ((const  Vehicle*)obj)->index + 1;
    01377     case REF_STATION:   return ((const  Station*)obj)->index + 1;
    01378     case REF_TOWN:      return ((const     Town*)obj)->index + 1;
    01379     case REF_ORDER:     return ((const    Order*)obj)->index + 1;
    01380     case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
    01381     case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
    01382     case REF_CARGO_PACKET:  return ((const CargoPacket*)obj)->index + 1;
    01383     case REF_ORDERLIST:     return ((const   OrderList*)obj)->index + 1;
    01384     default: NOT_REACHED();
    01385   }
    01386
    01387   return 0; // avoid compiler warning
    01388 }
    01389
    01400 static void *IntToReference(uint index, SLRefType rt)
    01401 {
    01402   /* After version 4.3 REF_VEHICLE_OLD is saved as REF_VEHICLE,
    01403    * and should be loaded like that */
    01404   if (rt == REF_VEHICLE_OLD && !CheckSavegameVersionOldStyle(4, 4)) {
    01405     rt = REF_VEHICLE;
    01406   }
    01407
    01408   /* No need to look up NULL pointers, just return immediately */
    01409   if (rt != REF_VEHICLE_OLD && index == 0) {
    01410     return NULL;
    01411   }
    01412
    01413   index--; // correct for the NULL index
    01414
    01415   switch (rt) {
    01416     case REF_ORDERLIST:
    01417       if (_OrderList_pool.AddBlockIfNeeded(index)) return GetOrderList(index);
    01418       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "OrderList index out of range");
    01419
    01420     case REF_ORDER:
    01421       if (_Order_pool.AddBlockIfNeeded(index)) return GetOrder(index);
    01422       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Order index out of range");
    01423
    01424     case REF_VEHICLE:
    01425       if (_Vehicle_pool.AddBlockIfNeeded(index)) return GetVehicle(index);
    01426       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Vehicle index out of range");
    01427
    01428     case REF_STATION:
    01429       if (_Station_pool.AddBlockIfNeeded(index)) return GetStation(index);
    01430       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Station index out of range");
    01431
    01432     case REF_TOWN:
    01433       if (_Town_pool.AddBlockIfNeeded(index)) return GetTown(index);
    01434       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Town index out of range");
    01435
    01436     case REF_ROADSTOPS:
    01437       if (_RoadStop_pool.AddBlockIfNeeded(index)) return GetRoadStop(index);
    01438       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "RoadStop index out of range");
    01439
    01440     case REF_ENGINE_RENEWS:
    01441       if (_EngineRenew_pool.AddBlockIfNeeded(index)) return GetEngineRenew(index);
    01442       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "EngineRenew index out of range");
    01443
    01444     case REF_CARGO_PACKET:
    01445       if (_CargoPacket_pool.AddBlockIfNeeded(index)) return GetCargoPacket(index);
    01446       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "CargoPacket index out of range");
    01447
    01448     case REF_VEHICLE_OLD:
    01449       /* Old vehicles were saved differently:
    01450        * invalid vehicle was 0xFFFF,
    01451        * and the index was not - 1.. correct for this */
    01452       index++;
    01453       if (index == INVALID_VEHICLE) return NULL;
    01454
    01455       if (_Vehicle_pool.AddBlockIfNeeded(index)) return GetVehicle(index);
    01456       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Vehicle index out of range");
    01457
    01458     default: NOT_REACHED();
    01459   }
    01460
    01461   return NULL;
    01462 }
    01463
    01465 struct SaveLoadFormat {
    01466   const char *name;
    01467   uint32 tag;
    01468
    01469   bool (*init_read)();
    01470   ReaderProc *reader;
    01471   void (*uninit_read)();
    01472
    01473   bool (*init_write)();
    01474   WriterProc *writer;
    01475   void (*uninit_write)();
    01476 };
    01477
    01478 static const SaveLoadFormat _saveload_formats[] = {
    01479   {"memory", 0,                NULL,         NULL,       NULL,           InitMem,       WriteMem,    UnInitMem},
    01480   {"lzo",    TO_BE32X('OTTD'), InitLZO,      ReadLZO,    UninitLZO,      InitLZO,       WriteLZO,    UninitLZO},
    01481   {"none",   TO_BE32X('OTTN'), InitNoComp,   ReadNoComp, UninitNoComp,   InitNoComp,    WriteNoComp, UninitNoComp},
    01482 #if defined(WITH_ZLIB)
    01483   {"zlib",   TO_BE32X('OTTZ'), InitReadZlib, ReadZlib,   UninitReadZlib, InitWriteZlib, WriteZlib,   UninitWriteZlib},
    01484 #else
    01485   {"zlib",   TO_BE32X('OTTZ'), NULL,         NULL,       NULL,           NULL,          NULL,        NULL},
    01486 #endif
    01487 };
    01488
    01495 static const SaveLoadFormat *GetSavegameFormat(const char *s)
    01496 {
    01497   const SaveLoadFormat *def = endof(_saveload_formats) - 1;
    01498
    01499   /* find default savegame format, the highest one with which files can be written */
    01500   while (!def->init_write) def--;
    01501
    01502   if (s != NULL && s[0] != '\0') {
    01503     const SaveLoadFormat *slf;
    01504     for (slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
    01505       if (slf->init_write != NULL && strcmp(s, slf->name) == 0)
    01506         return slf;
    01507     }
    01508
    01509     ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
    01510   }
    01511   return def;
    01512 }
    01513
    01514 /* actual loader/saver function */
    01515 void InitializeGame(uint size_x, uint size_y, bool reset_date);
    01516 extern bool AfterLoadGame();
    01517 extern bool LoadOldSaveGame(const char *file);
    01518
    01520 static inline SaveOrLoadResult AbortSaveLoad()
    01521 {
    01522   if (_sl.fh != NULL) fclose(_sl.fh);
    01523
    01524   _sl.fh = NULL;
    01525   return SL_ERROR;
    01526 }
    01527
    01531 static void SaveFileStart()
    01532 {
    01533   _ts.ff_state = _fast_forward;
    01534   _fast_forward = 0;
    01535   if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
    01536
    01537   InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
    01538   _ts.saveinprogress = true;
    01539 }
    01540
    01543 static void SaveFileDone()
    01544 {
    01545   if (_game_mode != GM_MENU) _fast_forward = _ts.ff_state;
    01546   if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
    01547
    01548   InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
    01549   _ts.saveinprogress = false;
    01550 }
    01551
    01553 void SetSaveLoadError(StringID str)
    01554 {
    01555   _sl.error_str = str;
    01556 }
    01557
    01559 const char *GetSaveLoadErrorString()
    01560 {
    01561   SetDParam(0, _sl.error_str);
    01562   SetDParamStr(1, _sl.extra_msg);
    01563
    01564   static char err_str[512];
    01565   GetString(err_str, _sl.save ? STR_4007_GAME_SAVE_FAILED : STR_4009_GAME_LOAD_FAILED, lastof(err_str));
    01566   return err_str;
    01567 }
    01568
    01570 static void SaveFileError()
    01571 {
    01572   SetDParamStr(0, GetSaveLoadErrorString());
    01573   ShowErrorMessage(STR_JUST_RAW_STRING, STR_NULL, 0, 0);
    01574   SaveFileDone();
    01575 }
    01576
    01580 static SaveOrLoadResult SaveFileToDisk(bool threaded)
    01581 {
    01582   const SaveLoadFormat *fmt;
    01583   uint32 hdr[2];
    01584
    01585   _sl.excpt_uninit = NULL;
    01586   try {
    01587     fmt = GetSavegameFormat(_savegame_format);
    01588
    01589     /* We have written our stuff to memory, now write it to file! */
    01590     hdr[0] = fmt->tag;
    01591     hdr[1] = TO_BE32(SAVEGAME_VERSION << 16);
    01592     if (fwrite(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
    01593
    01594     if (!fmt->init_write()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
    01595
    01596     {
    01597       uint i;
    01598       uint count = 1 << Savegame_POOL_BLOCK_SIZE_BITS;
    01599
    01600       if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
    01601       for (i = 0; i != _Savegame_pool.GetBlockCount() - 1; i++) {
    01602         _sl.buf = _Savegame_pool.blocks[i];
    01603         fmt->writer(count);
    01604       }
    01605
    01606       /* The last block is (almost) always not fully filled, so only write away
    01607        * as much data as it is in there */
    01608       _sl.buf = _Savegame_pool.blocks[i];
    01609       fmt->writer(_ts.count - (i * count));
    01610     }
    01611
    01612     fmt->uninit_write();
    01613     if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
    01614     GetSavegameFormat("memory")->uninit_write(); // clean the memorypool
    01615     fclose(_sl.fh);
    01616
    01617     if (threaded) SetAsyncSaveFinish(SaveFileDone);
    01618
    01619     return SL_OK;
    01620   }
    01621   catch (...) {
    01622     AbortSaveLoad();
    01623     if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
    01624
    01625     /* Skip the "colour" character */
    01626     DEBUG(sl, 0, GetSaveLoadErrorString() + 3);
    01627
    01628     if (threaded) {
    01629       SetAsyncSaveFinish(SaveFileError);
    01630     } else {
    01631       SaveFileError();
    01632     }
    01633     return SL_ERROR;
    01634   }
    01635 }
    01636
    01637 static void SaveFileToDiskThread(void *arg)
    01638 {
    01639   SaveFileToDisk(true);
    01640 }
    01641
    01642 void WaitTillSaved()
    01643 {
    01644   if (_save_thread == NULL) return;
    01645
    01646   _save_thread->Join();
    01647   delete _save_thread;
    01648   _save_thread = NULL;
    01649 }
    01650
    01658 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb)
    01659 {
    01660   uint32 hdr[2];
    01661   const SaveLoadFormat *fmt;
    01662
    01663   /* An instance of saving is already active, so don't go saving again */
    01664   if (_ts.saveinprogress && mode == SL_SAVE) {
    01665     /* if not an autosave, but a user action, show error message */
    01666     if (!_do_autosave) ShowErrorMessage(INVALID_STRING_ID, STR_SAVE_STILL_IN_PROGRESS, 0, 0);
    01667     return SL_OK;
    01668   }
    01669   WaitTillSaved();
    01670
    01671   _next_offs = 0;
    01672
    01673   /* Load a TTDLX or TTDPatch game */
    01674   if (mode == SL_OLD_LOAD) {
    01675     InitializeGame(256, 256, true); // set a mapsize of 256x256 for TTDPatch games or it might get confused
    01676     GamelogReset();
    01677     if (!LoadOldSaveGame(filename)) return SL_REINIT;
    01678     _sl_version = 0;
    01679     _sl_minor_version = 0;
    01680     GamelogStartAction(GLAT_LOAD);
    01681     if (!AfterLoadGame()) {
    01682       GamelogStopAction();
    01683       return SL_REINIT;
    01684     }
    01685     GamelogStopAction();
    01686     return SL_OK;
    01687   }
    01688
    01689   _sl.excpt_uninit = NULL;
    01690   try {
    01691     _sl.fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
    01692
    01693     /* Make it a little easier to load savegames from the console */
    01694     if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", SAVE_DIR);
    01695     if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", BASE_DIR);
    01696
    01697     if (_sl.fh == NULL) {
    01698       SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
    01699     }
    01700
    01701     _sl.bufe = _sl.bufp = NULL;
    01702     _sl.offs_base = 0;
    01703     _sl.save = (mode != 0);
    01704     _sl.chs = _chunk_handlers;
    01705
    01706     /* General tactic is to first save the game to memory, then use an available writer
    01707      * to write it to file, either in threaded mode if possible, or single-threaded */
    01708     if (mode == SL_SAVE) { /* SAVE game */
    01709       DEBUG(desync, 1, "save: %s\n", filename);
    01710       fmt = GetSavegameFormat("memory"); // write to memory
    01711
    01712       _sl.write_bytes = fmt->writer;
    01713       _sl.excpt_uninit = fmt->uninit_write;
    01714       if (!fmt->init_write()) {
    01715         DEBUG(sl, 0, "Initializing writer '%s' failed.", fmt->name);
    01716         return AbortSaveLoad();
    01717       }
    01718
    01719       _sl_version = SAVEGAME_VERSION;
    01720
    01721       SaveViewportBeforeSaveGame();
    01722       SlSaveChunks();
    01723       SlWriteFill(); // flush the save buffer
    01724
    01725       SaveFileStart();
    01726       if (_network_server ||
    01727             !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
    01728         if (!_network_server) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
    01729
    01730         SaveOrLoadResult result = SaveFileToDisk(false);
    01731         SaveFileDone();
    01732
    01733         return result;
    01734       }
    01735     } else { /* LOAD game */
    01736       assert(mode == SL_LOAD);
    01737       DEBUG(desync, 1, "load: %s\n", filename);
    01738
    01739       if (fread(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
    01740
    01741       /* see if we have any loader for this type. */
    01742       for (fmt = _saveload_formats; ; fmt++) {
    01743         /* No loader found, treat as version 0 and use LZO format */
    01744         if (fmt == endof(_saveload_formats)) {
    01745           DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
    01746   #if defined(WINCE)
    01747           /* Of course some system had not to support rewind ;) */
    01748           fseek(_sl.fh, 0L, SEEK_SET);
    01749           clearerr(_sl.fh);
    01750   #else
    01751           rewind(_sl.fh);
    01752   #endif
    01753           _sl_version = 0;
    01754           _sl_minor_version = 0;
    01755           fmt = _saveload_formats + 1; // LZO
    01756           break;
    01757         }
    01758
    01759         if (fmt->tag == hdr[0]) {
    01760           /* check version number */
    01761           _sl_version = TO_BE32(hdr[1]) >> 16;
    01762           /* Minor is not used anymore from version 18.0, but it is still needed
    01763            * in versions before that (4 cases) which can't be removed easy.
    01764            * Therefor it is loaded, but never saved (or, it saves a 0 in any scenario).
    01765            * So never EVER use this minor version again. -- TrueLight -- 22-11-2005 */
    01766           _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
    01767
    01768           DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
    01769
    01770           /* Is the version higher than the current? */
    01771           if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
    01772           break;
    01773         }
    01774       }
    01775
    01776       _sl.read_bytes = fmt->reader;
    01777       _sl.excpt_uninit = fmt->uninit_read;
    01778
    01779       /* loader for this savegame type is not implemented? */
    01780       if (fmt->init_read == NULL) {
    01781         char err_str[64];
    01782         snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
    01783         SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
    01784       }
    01785
    01786       if (!fmt->init_read()) {
    01787         char err_str[64];
    01788         snprintf(err_str, lengthof(err_str), "Initializing loader '%s' failed", fmt->name);
    01789         SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
    01790       }
    01791
    01792       /* Old maps were hardcoded to 256x256 and thus did not contain
    01793        * any mapsize information. Pre-initialize to 256x256 to not to
    01794        * confuse old games */
    01795       InitializeGame(256, 256, true);
    01796
    01797       GamelogReset();
    01798
    01799       SlLoadChunks();
    01800       fmt->uninit_read();
    01801       fclose(_sl.fh);
    01802
    01803       GamelogStartAction(GLAT_LOAD);
    01804
    01805       _savegame_type = SGT_OTTD;
    01806
    01807       /* After loading fix up savegame for any internal changes that
    01808        * might've occured since then. If it fails, load back the old game */
    01809       if (!AfterLoadGame()) {
    01810         GamelogStopAction();
    01811         return SL_REINIT;
    01812       }
    01813
    01814       GamelogStopAction();
    01815     }
    01816
    01817     return SL_OK;
    01818   }
    01819   catch (...) {
    01820     AbortSaveLoad();
    01821
    01822     /* deinitialize compressor. */
    01823     if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
    01824
    01825     /* Skip the "colour" character */
    01826     DEBUG(sl, 0, GetSaveLoadErrorString() + 3);
    01827
    01828     /* A saver/loader exception!! reinitialize all variables to prevent crash! */
    01829     return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
    01830   }
    01831 }
    01832
    01834 void DoExitSave()
    01835 {
    01836   SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
    01837 }
    01838
    01844 void GenerateDefaultSaveName(char *buf, const char *last)
    01845 {
    01846   /* Check if we have a name for this map, which is the name of the first
    01847    * available company. When there's no company available we'll use
    01848    * 'Spectator' as "company" name. */
    01849   CompanyID cid = _local_company;
    01850   if (!IsValidCompanyID(cid)) {
    01851     const Company *c;
    01852     FOR_ALL_COMPANIES(c) {
    01853       cid = c->index;
    01854       break;
    01855     }
    01856   }
    01857
    01858   SetDParam(0, cid);
    01859
    01860   /* Insert current date */
    01861   switch (_settings_client.gui.date_format_in_default_names) {
    01862     case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
    01863     case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
    01864     case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
    01865     default: NOT_REACHED();
    01866   }
    01867   SetDParam(2, _date);
    01868
    01869   /* Get the correct string (special string for when there's not company) */
    01870   GetString(buf, !IsValidCompanyID(cid) ? STR_GAME_SAVELOAD_SPECTATOR_SAVEGAME : STR_4004, last);
    01871   SanitizeFilename(buf);
    01872 }
    01873
    01874 #if 0
    01875
    01881 int GetSavegameType(char *file)
    01882 {
    01883   const SaveLoadFormat *fmt;
    01884   uint32 hdr;
    01885   FILE *f;
    01886   int mode = SL_OLD_LOAD;
    01887
    01888   f = fopen(file, "rb");
    01889   if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
    01890     DEBUG(sl, 0, "Savegame is obsolete or invalid format");
    01891     mode = SL_LOAD; // don't try to get filename, just show name as it is written
    01892   } else {
    01893     /* see if we have any loader for this type. */
    01894     for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
    01895       if (fmt->tag == hdr) {
    01896         mode = SL_LOAD; // new type of savegame
    01897         break;
    01898       }
    01899     }
    01900   }
    01901
    01902   fclose(f);
    01903   return mode;
    01904 }
    01905 #endif