# saveload.cpp

Go to the documentation of this file.

    00001 /* $Id: saveload.cpp 13685 2008-07-09 18:59:39Z rubidium $ */
    00002
    00016 #include "stdafx.h"
    00017 #include "openttd.h"
    00018 #include "debug.h"
    00019 #include "station.h"
    00020 #include "thread.h"
    00021 #include "town.h"
    00022 #include "saveload.h"
    00023 #include "network/network.h"
    00024 #include "variables.h"
    00025 #include "window_func.h"
    00026 #include "strings_func.h"
    00027 #include "gfx_func.h"
    00028 #include "core/alloc_func.hpp"
    00029 #include "functions.h"
    00030 #include "core/endian_func.hpp"
    00031 #include "vehicle_base.h"
    00032 #include "autoreplace_base.h"
    00033 #include <list>
    00034
    00035 #include "table/strings.h"
    00036
    00037 extern const uint16 SAVEGAME_VERSION = 92;
    00038 uint16 _sl_version;
    00039 byte   _sl_minor_version;
    00040
    00041 typedef void WriterProc(uint len);
    00042 typedef uint ReaderProc();
    00043
    00045 static struct {
    00046   bool save;
    00047   byte need_length;
    00048   byte block_mode;
    00049   bool error;
    00050
    00051   int obj_len;
    00052   int array_index, last_array_index;
    00053
    00054   uint32 offs_base;
    00055
    00056   WriterProc *write_bytes;
    00057   ReaderProc *read_bytes;
    00058
    00059   const ChunkHandler* const *chs;
    00060
    00061   /* When saving/loading savegames, they are always saved to a temporary memory-place
    00062    * to be flushed to file (save) or to final place (load) when full. */
    00063   byte *bufp, *bufe;
    00064
    00065   /* these 3 may be used by compressor/decompressors. */
    00066   byte *buf;
    00067   byte *buf_ori;
    00068   uint bufsize;
    00069   FILE *fh;
    00070
    00071   void (*excpt_uninit)();
    00072   StringID error_str;
    00073   char *extra_msg;
    00074 } _sl;
    00075
    00076
    00077 enum NeedLengthValues {NL_NONE = 0, NL_WANTLENGTH = 1, NL_CALCLENGTH = 2};
    00078
    00082 static void NORETURN SlError(StringID string, const char *extra_msg = NULL)
    00083 {
    00084   _sl.error_str = string;
    00085   free(_sl.extra_msg);
    00086   _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
    00087   throw std::exception();
    00088 }
    00089
    00093 static void SlReadFill()
    00094 {
    00095   uint len = _sl.read_bytes();
    00096   if (len == 0) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected end of chunk");
    00097
    00098   _sl.bufp = _sl.buf;
    00099   _sl.bufe = _sl.buf + len;
    00100   _sl.offs_base += len;
    00101 }
    00102
    00103 static inline uint32 SlGetOffs() {return _sl.offs_base - (_sl.bufe - _sl.bufp);}
    00104
    00109 static inline byte SlCalcConvMemLen(VarType conv)
    00110 {
    00111   static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
    00112   byte length = GB(conv, 4, 4);
    00113   assert(length < lengthof(conv_mem_size));
    00114   return conv_mem_size[length];
    00115 }
    00116
    00121 static inline byte SlCalcConvFileLen(VarType conv)
    00122 {
    00123   static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
    00124   byte length = GB(conv, 0, 4);
    00125   assert(length < lengthof(conv_file_size));
    00126   return conv_file_size[length];
    00127 }
    00128
    00130 static inline size_t SlCalcRefLen() {return CheckSavegameVersion(69) ? 2 : 4;}
    00131
    00136 static void SlWriteFill()
    00137 {
    00138   /* flush the buffer to disk (the writer) */
    00139   if (_sl.bufp != NULL) {
    00140     uint len = _sl.bufp - _sl.buf;
    00141     _sl.offs_base += len;
    00142     if (len) _sl.write_bytes(len);
    00143   }
    00144
    00145   /* All the data from the buffer has been written away, rewind to the beginning
    00146    * to start reading in more data */
    00147   _sl.bufp = _sl.buf;
    00148   _sl.bufe = _sl.buf + _sl.bufsize;
    00149 }
    00150
    00155 static inline byte SlReadByteInternal()
    00156 {
    00157   if (_sl.bufp == _sl.bufe) SlReadFill();
    00158   return *_sl.bufp++;
    00159 }
    00160
    00162 byte SlReadByte() {return SlReadByteInternal();}
    00163
    00168 static inline void SlWriteByteInternal(byte b)
    00169 {
    00170   if (_sl.bufp == _sl.bufe) SlWriteFill();
    00171   *_sl.bufp++ = b;
    00172 }
    00173
    00175 void SlWriteByte(byte b) {SlWriteByteInternal(b);}
    00176
    00177 static inline int SlReadUint16()
    00178 {
    00179   int x = SlReadByte() << 8;
    00180   return x | SlReadByte();
    00181 }
    00182
    00183 static inline uint32 SlReadUint32()
    00184 {
    00185   uint32 x = SlReadUint16() << 16;
    00186   return x | SlReadUint16();
    00187 }
    00188
    00189 static inline uint64 SlReadUint64()
    00190 {
    00191   uint32 x = SlReadUint32();
    00192   uint32 y = SlReadUint32();
    00193   return (uint64)x << 32 | y;
    00194 }
    00195
    00196 static inline void SlWriteUint16(uint16 v)
    00197 {
    00198   SlWriteByte(GB(v, 8, 8));
    00199   SlWriteByte(GB(v, 0, 8));
    00200 }
    00201
    00202 static inline void SlWriteUint32(uint32 v)
    00203 {
    00204   SlWriteUint16(GB(v, 16, 16));
    00205   SlWriteUint16(GB(v,  0, 16));
    00206 }
    00207
    00208 static inline void SlWriteUint64(uint64 x)
    00209 {
    00210   SlWriteUint32((uint32)(x >> 32));
    00211   SlWriteUint32((uint32)x);
    00212 }
    00213
    00223 static uint SlReadSimpleGamma()
    00224 {
    00225   uint i = SlReadByte();
    00226   if (HasBit(i, 7)) {
    00227     i &= ~0x80;
    00228     if (HasBit(i, 6)) {
    00229       i &= ~0x40;
    00230       if (HasBit(i, 5)) {
    00231         i &= ~0x20;
    00232         if (HasBit(i, 4))
    00233           SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unsupported gamma");
    00234         i = (i << 8) | SlReadByte();
    00235       }
    00236       i = (i << 8) | SlReadByte();
    00237     }
    00238     i = (i << 8) | SlReadByte();
    00239   }
    00240   return i;
    00241 }
    00242
    00255 static void SlWriteSimpleGamma(uint i)
    00256 {
    00257   if (i >= (1 << 7)) {
    00258     if (i >= (1 << 14)) {
    00259       if (i >= (1 << 21)) {
    00260         assert(i < (1 << 28));
    00261         SlWriteByte((byte)0xE0 | (i >> 24));
    00262         SlWriteByte((byte)(i >> 16));
    00263       } else {
    00264         SlWriteByte((byte)0xC0 | (i >> 16));
    00265       }
    00266       SlWriteByte((byte)(i >> 8));
    00267     } else {
    00268       SlWriteByte((byte)(0x80 | (i >> 8)));
    00269     }
    00270   }
    00271   SlWriteByte(i);
    00272 }
    00273
    00275 static inline uint SlGetGammaLength(uint i)
    00276 {
    00277   return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
    00278 }
    00279
    00280 static inline uint SlReadSparseIndex() {return SlReadSimpleGamma();}
    00281 static inline void SlWriteSparseIndex(uint index) {SlWriteSimpleGamma(index);}
    00282
    00283 static inline uint SlReadArrayLength() {return SlReadSimpleGamma();}
    00284 static inline void SlWriteArrayLength(uint length) {SlWriteSimpleGamma(length);}
    00285 static inline uint SlGetArrayLength(uint length) {return SlGetGammaLength(length);}
    00286
    00287 void SlSetArrayIndex(uint index)
    00288 {
    00289   _sl.need_length = NL_WANTLENGTH;
    00290   _sl.array_index = index;
    00291 }
    00292
    00293 static uint32 _next_offs;
    00294
    00299 int SlIterateArray()
    00300 {
    00301   int index;
    00302
    00303   /* After reading in the whole array inside the loop
    00304    * we must have read in all the data, so we must be at end of current block. */
    00305   if (_next_offs != 0 && SlGetOffs() != _next_offs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
    00306
    00307   while (true) {
    00308     uint length = SlReadArrayLength();
    00309     if (length == 0) {
    00310       _next_offs = 0;
    00311       return -1;
    00312     }
    00313
    00314     _sl.obj_len = --length;
    00315     _next_offs = SlGetOffs() + length;
    00316
    00317     switch (_sl.block_mode) {
    00318     case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
    00319     case CH_ARRAY:        index = _sl.array_index++; break;
    00320     default:
    00321       DEBUG(sl, 0, "SlIterateArray error");
    00322       return -1; // error
    00323     }
    00324
    00325     if (length != 0) return index;
    00326   }
    00327 }
    00328
    00334 void SlSetLength(size_t length)
    00335 {
    00336   assert(_sl.save);
    00337
    00338   switch (_sl.need_length) {
    00339   case NL_WANTLENGTH:
    00340     _sl.need_length = NL_NONE;
    00341     switch (_sl.block_mode) {
    00342     case CH_RIFF:
    00343       /* Ugly encoding of >16M RIFF chunks
    00344        * The lower 24 bits are normal
    00345        * The uppermost 4 bits are bits 24:27 */
    00346       assert(length < (1<<28));
    00347       SlWriteUint32((length & 0xFFFFFF) | ((length >> 24) << 28));
    00348       break;
    00349     case CH_ARRAY:
    00350       assert(_sl.last_array_index <= _sl.array_index);
    00351       while (++_sl.last_array_index <= _sl.array_index)
    00352         SlWriteArrayLength(1);
    00353       SlWriteArrayLength(length + 1);
    00354       break;
    00355     case CH_SPARSE_ARRAY:
    00356       SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index)); // Also include length of sparse index.
    00357       SlWriteSparseIndex(_sl.array_index);
    00358       break;
    00359     default: NOT_REACHED();
    00360     } break;
    00361   case NL_CALCLENGTH:
    00362     _sl.obj_len += length;
    00363     break;
    00364   }
    00365 }
    00366
    00373 static void SlCopyBytes(void *ptr, size_t length)
    00374 {
    00375   byte *p = (byte*)ptr;
    00376
    00377   if (_sl.save) {
    00378     for (; length != 0; length--) {SlWriteByteInternal(*p++);}
    00379   } else {
    00380     for (; length != 0; length--) {*p++ = SlReadByteInternal();}
    00381   }
    00382 }
    00383
    00388 static inline void SlSkipBytes(size_t length)
    00389 {
    00390   for (; length != 0; length--) SlReadByte();
    00391 }
    00392
    00393 /* Get the length of the current object */
    00394 uint SlGetFieldLength() {return _sl.obj_len;}
    00395
    00401 int64 ReadValue(const void *ptr, VarType conv)
    00402 {
    00403   switch (GetVarMemType(conv)) {
    00404   case SLE_VAR_BL:  return (*(bool*)ptr != 0);
    00405   case SLE_VAR_I8:  return *(int8*  )ptr;
    00406   case SLE_VAR_U8:  return *(byte*  )ptr;
    00407   case SLE_VAR_I16: return *(int16* )ptr;
    00408   case SLE_VAR_U16: return *(uint16*)ptr;
    00409   case SLE_VAR_I32: return *(int32* )ptr;
    00410   case SLE_VAR_U32: return *(uint32*)ptr;
    00411   case SLE_VAR_I64: return *(int64* )ptr;
    00412   case SLE_VAR_U64: return *(uint64*)ptr;
    00413   case SLE_VAR_NULL:return 0;
    00414   default: NOT_REACHED();
    00415   }
    00416
    00417   /* useless, but avoids compiler warning this way */
    00418   return 0;
    00419 }
    00420
    00426 void WriteValue(void *ptr, VarType conv, int64 val)
    00427 {
    00428   switch (GetVarMemType(conv)) {
    00429   case SLE_VAR_BL:  *(bool  *)ptr = (val != 0);  break;
    00430   case SLE_VAR_I8:  *(int8  *)ptr = val; break;
    00431   case SLE_VAR_U8:  *(byte  *)ptr = val; break;
    00432   case SLE_VAR_I16: *(int16 *)ptr = val; break;
    00433   case SLE_VAR_U16: *(uint16*)ptr = val; break;
    00434   case SLE_VAR_I32: *(int32 *)ptr = val; break;
    00435   case SLE_VAR_U32: *(uint32*)ptr = val; break;
    00436   case SLE_VAR_I64: *(int64 *)ptr = val; break;
    00437   case SLE_VAR_U64: *(uint64*)ptr = val; break;
    00438   case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
    00439   case SLE_VAR_NULL: break;
    00440   default: NOT_REACHED();
    00441   }
    00442 }
    00443
    00452 static void SlSaveLoadConv(void *ptr, VarType conv)
    00453 {
    00454   int64 x = 0;
    00455
    00456   if (_sl.save) { // SAVE values
    00457     /* Read a value from the struct. These ARE endian safe. */
    00458     x = ReadValue(ptr, conv);
    00459
    00460     /* Write the value to the file and check if its value is in the desired range */
    00461     switch (GetVarFileType(conv)) {
    00462     case SLE_FILE_I8: assert(x >= -128 && x <= 127);     SlWriteByte(x);break;
    00463     case SLE_FILE_U8: assert(x >= 0 && x <= 255);        SlWriteByte(x);break;
    00464     case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
    00465     case SLE_FILE_STRINGID:
    00466     case SLE_FILE_U16:assert(x >= 0 && x <= 65535);      SlWriteUint16(x);break;
    00467     case SLE_FILE_I32:
    00468     case SLE_FILE_U32:                                   SlWriteUint32((uint32)x);break;
    00469     case SLE_FILE_I64:
    00470     case SLE_FILE_U64:                                   SlWriteUint64(x);break;
    00471     default: NOT_REACHED();
    00472     }
    00473   } else { // LOAD values
    00474
    00475     /* Read a value from the file */
    00476     switch (GetVarFileType(conv)) {
    00477     case SLE_FILE_I8:  x = (int8  )SlReadByte();   break;
    00478     case SLE_FILE_U8:  x = (byte  )SlReadByte();   break;
    00479     case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
    00480     case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
    00481     case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
    00482     case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
    00483     case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
    00484     case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
    00485     case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
    00486     default: NOT_REACHED();
    00487     }
    00488
    00489     /* Write The value to the struct. These ARE endian safe. */
    00490     WriteValue(ptr, conv, x);
    00491   }
    00492 }
    00493
    00501 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
    00502 {
    00503   if (ptr == NULL) return 0;
    00504   return minu(strlen(ptr), length - 1);
    00505 }
    00506
    00514 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
    00515 {
    00516   size_t len;
    00517   const char *str;
    00518
    00519   switch (GetVarMemType(conv)) {
    00520     default: NOT_REACHED();
    00521     case SLE_VAR_STR:
    00522     case SLE_VAR_STRQ:
    00523       str = *(const char**)ptr;
    00524       len = SIZE_MAX;
    00525       break;
    00526     case SLE_VAR_STRB:
    00527     case SLE_VAR_STRBQ:
    00528       str = (const char*)ptr;
    00529       len = length;
    00530       break;
    00531   }
    00532
    00533   len = SlCalcNetStringLen(str, len);
    00534   return len + SlGetArrayLength(len); // also include the length of the index
    00535 }
    00536
    00542 static void SlString(void *ptr, size_t length, VarType conv)
    00543 {
    00544   size_t len;
    00545
    00546   if (_sl.save) { // SAVE string
    00547     switch (GetVarMemType(conv)) {
    00548       default: NOT_REACHED();
    00549       case SLE_VAR_STRB:
    00550       case SLE_VAR_STRBQ:
    00551         len = SlCalcNetStringLen((char*)ptr, length);
    00552         break;
    00553       case SLE_VAR_STR:
    00554       case SLE_VAR_STRQ:
    00555         ptr = *(char**)ptr;
    00556         len = SlCalcNetStringLen((char*)ptr, SIZE_MAX);
    00557         break;
    00558     }
    00559
    00560     SlWriteArrayLength(len);
    00561     SlCopyBytes(ptr, len);
    00562   } else { // LOAD string
    00563     len = SlReadArrayLength();
    00564
    00565     switch (GetVarMemType(conv)) {
    00566       default: NOT_REACHED();
    00567       case SLE_VAR_STRB:
    00568       case SLE_VAR_STRBQ:
    00569         if (len >= length) {
    00570           DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
    00571           SlCopyBytes(ptr, length);
    00572           SlSkipBytes(len - length);
    00573           len = length - 1;
    00574         } else {
    00575           SlCopyBytes(ptr, len);
    00576         }
    00577         break;
    00578       case SLE_VAR_STR:
    00579       case SLE_VAR_STRQ: // Malloc'd string, free previous incarnation, and allocate
    00580         free(*(char**)ptr);
    00581         if (len == 0) {
    00582           *(char**)ptr = NULL;
    00583         } else {
    00584           *(char**)ptr = MallocT<char>(len + 1); // terminating '\0'
    00585           ptr = *(char**)ptr;
    00586           SlCopyBytes(ptr, len);
    00587         }
    00588         break;
    00589     }
    00590
    00591     ((char*)ptr)[len] = '\0'; // properly terminate the string
    00592   }
    00593 }
    00594
    00600 static inline size_t SlCalcArrayLen(uint length, VarType conv)
    00601 {
    00602   return SlCalcConvFileLen(conv) * length;
    00603 }
    00604
    00611 void SlArray(void *array, uint length, VarType conv)
    00612 {
    00613   /* Automatically calculate the length? */
    00614   if (_sl.need_length != NL_NONE) {
    00615     SlSetLength(SlCalcArrayLen(length, conv));
    00616     /* Determine length only? */
    00617     if (_sl.need_length == NL_CALCLENGTH) return;
    00618   }
    00619
    00620   /* NOTICE - handle some buggy stuff, in really old versions everything was saved
    00621    * as a byte-type. So detect this, and adjust array size accordingly */
    00622   if (!_sl.save && _sl_version == 0) {
    00623     /* all arrays except difficulty settings */
    00624     if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
    00625         conv == SLE_INT32 || conv == SLE_UINT32) {
    00626       SlCopyBytes(array, length * SlCalcConvFileLen(conv));
    00627       return;
    00628     }
    00629     /* used for conversion of Money 32bit->64bit */
    00630     if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
    00631       for (uint i = 0; i < length; i++) {
    00632         ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
    00633       }
    00634       return;
    00635     }
    00636   }
    00637
    00638   /* If the size of elements is 1 byte both in file and memory, no special
    00639    * conversion is needed, use specialized copy-copy function to speed up things */
    00640   if (conv == SLE_INT8 || conv == SLE_UINT8) {
    00641     SlCopyBytes(array, length);
    00642   } else {
    00643     byte *a = (byte*)array;
    00644     byte mem_size = SlCalcConvMemLen(conv);
    00645
    00646     for (; length != 0; length --) {
    00647       SlSaveLoadConv(a, conv);
    00648       a += mem_size; // get size
    00649     }
    00650   }
    00651 }
    00652
    00653
    00654 static uint ReferenceToInt(const void* obj, SLRefType rt);
    00655 static void* IntToReference(uint index, SLRefType rt);
    00656
    00657
    00662 static inline size_t SlCalcListLen(const void *list)
    00663 {
    00664   std::list<void *> *l = (std::list<void *> *) list;
    00665
    00666   int type_size = CheckSavegameVersion(69) ? 2 : 4;
    00667   /* Each entry is saved as type_size bytes, plus type_size bytes are used for the length
    00668    * of the list */
    00669   return l->size() * type_size + type_size;
    00670 }
    00671
    00672
    00678 void SlList(void *list, SLRefType conv)
    00679 {
    00680   /* Automatically calculate the length? */
    00681   if (_sl.need_length != NL_NONE) {
    00682     SlSetLength(SlCalcListLen(list));
    00683     /* Determine length only? */
    00684     if (_sl.need_length == NL_CALCLENGTH) return;
    00685   }
    00686
    00687   std::list<void *> *l = (std::list<void *> *) list;
    00688
    00689   if (_sl.save) {
    00690     SlWriteUint32(l->size());
    00691
    00692     std::list<void *>::iterator iter;
    00693     for (iter = l->begin(); iter != l->end(); ++iter) {
    00694       void *ptr = *iter;
    00695       SlWriteUint32(ReferenceToInt(ptr, conv));
    00696     }
    00697   } else {
    00698     uint length = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
    00699
    00700     /* Load each reference and push to the end of the list */
    00701     for (uint i = 0; i < length; i++) {
    00702       void *ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), conv);
    00703       l->push_back(ptr);
    00704     }
    00705   }
    00706 }
    00707
    00708
    00710 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
    00711 {
    00712   if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
    00713   if (sld->conv & SLF_SAVE_NO) return false;
    00714
    00715   return true;
    00716 }
    00717
    00721 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
    00722 {
    00723   if ((sld->conv & SLF_NETWORK_NO) && !_sl.save && _networking && !_network_server) {
    00724     SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
    00725     return true;
    00726   }
    00727
    00728   return false;
    00729 }
    00730
    00737 static size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
    00738 {
    00739   size_t length = 0;
    00740
    00741   /* Need to determine the length and write a length tag. */
    00742   for (; sld->cmd != SL_END; sld++) {
    00743     length += SlCalcObjMemberLength(object, sld);
    00744   }
    00745   return length;
    00746 }
    00747
    00748 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
    00749 {
    00750   assert(_sl.save);
    00751
    00752   switch (sld->cmd) {
    00753     case SL_VAR:
    00754     case SL_REF:
    00755     case SL_ARR:
    00756     case SL_STR:
    00757     case SL_LST:
    00758       /* CONDITIONAL saveload types depend on the savegame version */
    00759       if (!SlIsObjectValidInSavegame(sld)) break;
    00760
    00761       switch (sld->cmd) {
    00762       case SL_VAR: return SlCalcConvFileLen(sld->conv);
    00763       case SL_REF: return SlCalcRefLen();
    00764       case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
    00765       case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
    00766       case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
    00767       default: NOT_REACHED();
    00768       }
    00769       break;
    00770     case SL_WRITEBYTE: return 1; // a byte is logically of size 1
    00771     case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
    00772     default: NOT_REACHED();
    00773   }
    00774   return 0;
    00775 }
    00776
    00777
    00778 bool SlObjectMember(void *ptr, const SaveLoad *sld)
    00779 {
    00780   VarType conv = GB(sld->conv, 0, 8);
    00781   switch (sld->cmd) {
    00782   case SL_VAR:
    00783   case SL_REF:
    00784   case SL_ARR:
    00785   case SL_STR:
    00786   case SL_LST:
    00787     /* CONDITIONAL saveload types depend on the savegame version */
    00788     if (!SlIsObjectValidInSavegame(sld)) return false;
    00789     if (SlSkipVariableOnLoad(sld)) return false;
    00790
    00791     switch (sld->cmd) {
    00792     case SL_VAR: SlSaveLoadConv(ptr, conv); break;
    00793     case SL_REF: // Reference variable, translate
    00794       if (_sl.save) {
    00795         SlWriteUint32(ReferenceToInt(*(void**)ptr, (SLRefType)conv));
    00796       } else {
    00797         *(void**)ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), (SLRefType)conv);
    00798       }
    00799       break;
    00800     case SL_ARR: SlArray(ptr, sld->length, conv); break;
    00801     case SL_STR: SlString(ptr, sld->length, conv); break;
    00802     case SL_LST: SlList(ptr, (SLRefType)conv); break;
    00803     default: NOT_REACHED();
    00804     }
    00805     break;
    00806
    00807   /* SL_WRITEBYTE translates a value of a variable to another one upon
    00808    * saving or loading.
    00809    * XXX - variable renaming abuse
    00810    * game_value: the value of the variable ingame is abused by sld->version_from
    00811    * file_value: the value of the variable in the savegame is abused by sld->version_to */
    00812   case SL_WRITEBYTE:
    00813     if (_sl.save) {
    00814       SlWriteByte(sld->version_to);
    00815     } else {
    00816       *(byte*)ptr = sld->version_from;
    00817     }
    00818     break;
    00819
    00820   /* SL_VEH_INCLUDE loads common code for vehicles */
    00821   case SL_VEH_INCLUDE:
    00822     SlObject(ptr, GetVehicleDescription(VEH_END));
    00823     break;
    00824   default: NOT_REACHED();
    00825   }
    00826   return true;
    00827 }
    00828
    00834 void SlObject(void *object, const SaveLoad *sld)
    00835 {
    00836   /* Automatically calculate the length? */
    00837   if (_sl.need_length != NL_NONE) {
    00838     SlSetLength(SlCalcObjLength(object, sld));
    00839     if (_sl.need_length == NL_CALCLENGTH) return;
    00840   }
    00841
    00842   for (; sld->cmd != SL_END; sld++) {
    00843     void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
    00844     SlObjectMember(ptr, sld);
    00845   }
    00846 }
    00847
    00852 void SlGlobList(const SaveLoadGlobVarList *sldg)
    00853 {
    00854   SlObject(NULL, (const SaveLoad*)sldg);
    00855 }
    00856
    00862 void SlAutolength(AutolengthProc *proc, void *arg)
    00863 {
    00864   uint32 offs;
    00865
    00866   assert(_sl.save);
    00867
    00868   /* Tell it to calculate the length */
    00869   _sl.need_length = NL_CALCLENGTH;
    00870   _sl.obj_len = 0;
    00871   proc(arg);
    00872
    00873   /* Setup length */
    00874   _sl.need_length = NL_WANTLENGTH;
    00875   SlSetLength(_sl.obj_len);
    00876
    00877   offs = SlGetOffs() + _sl.obj_len;
    00878
    00879   /* And write the stuff */
    00880   proc(arg);
    00881
    00882   if (offs != SlGetOffs()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
    00883 }
    00884
    00889 static void SlLoadChunk(const ChunkHandler *ch)
    00890 {
    00891   byte m = SlReadByte();
    00892   size_t len;
    00893   uint32 endoffs;
    00894
    00895   _sl.block_mode = m;
    00896   _sl.obj_len = 0;
    00897
    00898   switch (m) {
    00899   case CH_ARRAY:
    00900     _sl.array_index = 0;
    00901     ch->load_proc();
    00902     break;
    00903   case CH_SPARSE_ARRAY:
    00904     ch->load_proc();
    00905     break;
    00906   default:
    00907     if ((m & 0xF) == CH_RIFF) {
    00908       /* Read length */
    00909       len = (SlReadByte() << 16) | ((m >> 4) << 24);
    00910       len += SlReadUint16();
    00911       _sl.obj_len = len;
    00912       endoffs = SlGetOffs() + len;
    00913       ch->load_proc();
    00914       if (SlGetOffs() != endoffs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
    00915     } else {
    00916       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk type");
    00917     }
    00918     break;
    00919   }
    00920 }
    00921
    00922 /* Stub Chunk handlers to only calculate length and do nothing else */
    00923 static ChunkSaveLoadProc *_tmp_proc_1;
    00924 static inline void SlStubSaveProc2(void *arg) {_tmp_proc_1();}
    00925 static void SlStubSaveProc() {SlAutolength(SlStubSaveProc2, NULL);}
    00926
    00931 static void SlSaveChunk(const ChunkHandler *ch)
    00932 {
    00933   ChunkSaveLoadProc *proc = ch->save_proc;
    00934
    00935   /* Don't save any chunk information if there is no save handler. */
    00936   if (proc == NULL) return;
    00937
    00938   SlWriteUint32(ch->id);
    00939   DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
    00940
    00941   if (ch->flags & CH_AUTO_LENGTH) {
    00942     /* Need to calculate the length. Solve that by calling SlAutoLength in the save_proc. */
    00943     _tmp_proc_1 = proc;
    00944     proc = SlStubSaveProc;
    00945   }
    00946
    00947   _sl.block_mode = ch->flags & CH_TYPE_MASK;
    00948   switch (ch->flags & CH_TYPE_MASK) {
    00949   case CH_RIFF:
    00950     _sl.need_length = NL_WANTLENGTH;
    00951     proc();
    00952     break;
    00953   case CH_ARRAY:
    00954     _sl.last_array_index = 0;
    00955     SlWriteByte(CH_ARRAY);
    00956     proc();
    00957     SlWriteArrayLength(0); // Terminate arrays
    00958     break;
    00959   case CH_SPARSE_ARRAY:
    00960     SlWriteByte(CH_SPARSE_ARRAY);
    00961     proc();
    00962     SlWriteArrayLength(0); // Terminate arrays
    00963     break;
    00964   default: NOT_REACHED();
    00965   }
    00966 }
    00967
    00969 static void SlSaveChunks()
    00970 {
    00971   const ChunkHandler *ch;
    00972   const ChunkHandler* const *chsc;
    00973   uint p;
    00974
    00975   for (p = 0; p != CH_NUM_PRI_LEVELS; p++) {
    00976     for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
    00977       while (true) {
    00978         if (((ch->flags >> CH_PRI_SHL) & (CH_NUM_PRI_LEVELS - 1)) == p)
    00979           SlSaveChunk(ch);
    00980         if (ch->flags & CH_LAST)
    00981           break;
    00982         ch++;
    00983       }
    00984     }
    00985   }
    00986
    00987   /* Terminator */
    00988   SlWriteUint32(0);
    00989 }
    00990
    00996 static const ChunkHandler *SlFindChunkHandler(uint32 id)
    00997 {
    00998   const ChunkHandler *ch;
    00999   const ChunkHandler *const *chsc;
    01000   for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
    01001     for (;;) {
    01002       if (ch->id == id) return ch;
    01003       if (ch->flags & CH_LAST) break;
    01004       ch++;
    01005     }
    01006   }
    01007   return NULL;
    01008 }
    01009
    01011 static void SlLoadChunks()
    01012 {
    01013   uint32 id;
    01014   const ChunkHandler *ch;
    01015
    01016   for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
    01017     DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
    01018
    01019     ch = SlFindChunkHandler(id);
    01020     if (ch == NULL) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unknown chunk type");
    01021     SlLoadChunk(ch);
    01022   }
    01023 }
    01024
    01025 /*******************************************
    01026  ********** START OF LZO CODE **************
    01027  *******************************************/
    01028 #define LZO_SIZE 8192
    01029
    01030 #include "minilzo.h"
    01031
    01032 static uint ReadLZO()
    01033 {
    01034   byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
    01035   uint32 tmp[2];
    01036   uint32 size;
    01037   uint len;
    01038
    01039   /* Read header*/
    01040   if (fread(tmp, sizeof(tmp), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
    01041
    01042   /* Check if size is bad */
    01043   ((uint32*)out)[0] = size = tmp[1];
    01044
    01045   if (_sl_version != 0) {
    01046     tmp[0] = TO_BE32(tmp[0]);
    01047     size = TO_BE32(size);
    01048   }
    01049
    01050   if (size >= sizeof(out)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Inconsistent size");
    01051
    01052   /* Read block */
    01053   if (fread(out + sizeof(uint32), size, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
    01054
    01055   /* Verify checksum */
    01056   if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Bad checksum");
    01057
    01058   /* Decompress */
    01059   lzo1x_decompress(out + sizeof(uint32)*1, size, _sl.buf, &len, NULL);
    01060   return len;
    01061 }
    01062
    01063 /* p contains the pointer to the buffer, len contains the pointer to the length.
    01064  * len bytes will be written, p and l will be updated to reflect the next buffer. */
    01065 static void WriteLZO(uint size)
    01066 {
    01067   byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
    01068   byte wrkmem[sizeof(byte*)*4096];
    01069   uint outlen;
    01070
    01071   lzo1x_1_compress(_sl.buf, size, out + sizeof(uint32)*2, &outlen, wrkmem);
    01072   ((uint32*)out)[1] = TO_BE32(outlen);
    01073   ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
    01074   if (fwrite(out, outlen + sizeof(uint32)*2, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
    01075 }
    01076
    01077 static bool InitLZO()
    01078 {
    01079   _sl.bufsize = LZO_SIZE;
    01080   _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
    01081   return true;
    01082 }
    01083
    01084 static void UninitLZO()
    01085 {
    01086   free(_sl.buf_ori);
    01087 }
    01088
    01089 /*********************************************
    01090  ******** START OF NOCOMP CODE (uncompressed)*
    01091  *********************************************/
    01092 static uint ReadNoComp()
    01093 {
    01094   return fread(_sl.buf, 1, LZO_SIZE, _sl.fh);
    01095 }
    01096
    01097 static void WriteNoComp(uint size)
    01098 {
    01099   fwrite(_sl.buf, 1, size, _sl.fh);
    01100 }
    01101
    01102 static bool InitNoComp()
    01103 {
    01104   _sl.bufsize = LZO_SIZE;
    01105   _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
    01106   return true;
    01107 }
    01108
    01109 static void UninitNoComp()
    01110 {
    01111   free(_sl.buf_ori);
    01112 }
    01113
    01114 /********************************************
    01115  ********** START OF MEMORY CODE (in ram)****
    01116  ********************************************/
    01117
    01118 #include "table/sprites.h"
    01119 #include "gui.h"
    01120
    01121 struct ThreadedSave {
    01122   uint count;
    01123   byte ff_state;
    01124   bool saveinprogress;
    01125   CursorID cursor;
    01126 };
    01127
    01128 /* A maximum size of of 128K * 500 = 64.000KB savegames */
    01129 STATIC_OLD_POOL(Savegame, byte, 17, 500, NULL, NULL)
    01130 static ThreadedSave _ts;
    01131
    01132 static bool InitMem()
    01133 {
    01134   _ts.count = 0;
    01135
    01136   _Savegame_pool.CleanPool();
    01137   _Savegame_pool.AddBlockToPool();
    01138
    01139   /* A block from the pool is a contigious area of memory, so it is safe to write to it sequentially */
    01140   _sl.bufsize = GetSavegamePoolSize();
    01141   _sl.buf = GetSavegame(_ts.count);
    01142   return true;
    01143 }
    01144
    01145 static void UnInitMem()
    01146 {
    01147   _Savegame_pool.CleanPool();
    01148 }
    01149
    01150 static void WriteMem(uint size)
    01151 {
    01152   _ts.count += size;
    01153   /* Allocate new block and new buffer-pointer */
    01154   _Savegame_pool.AddBlockIfNeeded(_ts.count);
    01155   _sl.buf = GetSavegame(_ts.count);
    01156 }
    01157
    01158 /********************************************
    01159  ********** START OF ZLIB CODE **************
    01160  ********************************************/
    01161
    01162 #if defined(WITH_ZLIB)
    01163 #include <zlib.h>
    01164
    01165 static z_stream _z;
    01166
    01167 static bool InitReadZlib()
    01168 {
    01169   memset(&_z, 0, sizeof(_z));
    01170   if (inflateInit(&_z) != Z_OK) return false;
    01171
    01172   _sl.bufsize = 4096;
    01173   _sl.buf = _sl.buf_ori = MallocT<byte>(4096 + 4096); // also contains fread buffer
    01174   return true;
    01175 }
    01176
    01177 static uint ReadZlib()
    01178 {
    01179   int r;
    01180
    01181   _z.next_out = _sl.buf;
    01182   _z.avail_out = 4096;
    01183
    01184   do {
    01185     /* read more bytes from the file?*/
    01186     if (_z.avail_in == 0) {
    01187       _z.avail_in = fread(_z.next_in = _sl.buf + 4096, 1, 4096, _sl.fh);
    01188     }
    01189
    01190     /* inflate the data */
    01191     r = inflate(&_z, 0);
    01192     if (r == Z_STREAM_END)
    01193       break;
    01194
    01195     if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
    01196   } while (_z.avail_out);
    01197
    01198   return 4096 - _z.avail_out;
    01199 }
    01200
    01201 static void UninitReadZlib()
    01202 {
    01203   inflateEnd(&_z);
    01204   free(_sl.buf_ori);
    01205 }
    01206
    01207 static bool InitWriteZlib()
    01208 {
    01209   memset(&_z, 0, sizeof(_z));
    01210   if (deflateInit(&_z, 6) != Z_OK) return false;
    01211
    01212   _sl.bufsize = 4096;
    01213   _sl.buf = _sl.buf_ori = MallocT<byte>(4096); // also contains fread buffer
    01214   return true;
    01215 }
    01216
    01217 static void WriteZlibLoop(z_streamp z, byte *p, uint len, int mode)
    01218 {
    01219   byte buf[1024]; // output buffer
    01220   int r;
    01221   uint n;
    01222   z->next_in = p;
    01223   z->avail_in = len;
    01224   do {
    01225     z->next_out = buf;
    01226     z->avail_out = sizeof(buf);
    01227     r = deflate(z, mode);
    01228       /* bytes were emitted? */
    01229     if ((n=sizeof(buf) - z->avail_out) != 0) {
    01230       if (fwrite(buf, n, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
    01231     }
    01232     if (r == Z_STREAM_END)
    01233       break;
    01234     if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
    01235   } while (z->avail_in || !z->avail_out);
    01236 }
    01237
    01238 static void WriteZlib(uint len)
    01239 {
    01240   WriteZlibLoop(&_z, _sl.buf, len, 0);
    01241 }
    01242
    01243 static void UninitWriteZlib()
    01244 {
    01245   /* flush any pending output. */
    01246   if (_sl.fh) WriteZlibLoop(&_z, NULL, 0, Z_FINISH);
    01247   deflateEnd(&_z);
    01248   free(_sl.buf_ori);
    01249 }
    01250
    01251 #endif /* WITH_ZLIB */
    01252
    01253 /*******************************************
    01254  ************* END OF CODE *****************
    01255  *******************************************/
    01256
    01257 /* these define the chunks */
    01258 extern const ChunkHandler _misc_chunk_handlers[];
    01259 extern const ChunkHandler _setting_chunk_handlers[];
    01260 extern const ChunkHandler _player_chunk_handlers[];
    01261 extern const ChunkHandler _engine_chunk_handlers[];
    01262 extern const ChunkHandler _veh_chunk_handlers[];
    01263 extern const ChunkHandler _waypoint_chunk_handlers[];
    01264 extern const ChunkHandler _depot_chunk_handlers[];
    01265 extern const ChunkHandler _order_chunk_handlers[];
    01266 extern const ChunkHandler _town_chunk_handlers[];
    01267 extern const ChunkHandler _sign_chunk_handlers[];
    01268 extern const ChunkHandler _station_chunk_handlers[];
    01269 extern const ChunkHandler _industry_chunk_handlers[];
    01270 extern const ChunkHandler _economy_chunk_handlers[];
    01271 extern const ChunkHandler _animated_tile_chunk_handlers[];
    01272 extern const ChunkHandler _newgrf_chunk_handlers[];
    01273 extern const ChunkHandler _group_chunk_handlers[];
    01274 extern const ChunkHandler _cargopacket_chunk_handlers[];
    01275
    01276 static const ChunkHandler * const _chunk_handlers[] = {
    01277   _misc_chunk_handlers,
    01278   _setting_chunk_handlers,
    01279   _veh_chunk_handlers,
    01280   _waypoint_chunk_handlers,
    01281   _depot_chunk_handlers,
    01282   _order_chunk_handlers,
    01283   _industry_chunk_handlers,
    01284   _economy_chunk_handlers,
    01285   _engine_chunk_handlers,
    01286   _town_chunk_handlers,
    01287   _sign_chunk_handlers,
    01288   _station_chunk_handlers,
    01289   _player_chunk_handlers,
    01290   _animated_tile_chunk_handlers,
    01291   _newgrf_chunk_handlers,
    01292   _group_chunk_handlers,
    01293   _cargopacket_chunk_handlers,
    01294   NULL,
    01295 };
    01296
    01307 static uint ReferenceToInt(const void *obj, SLRefType rt)
    01308 {
    01309   if (obj == NULL) return 0;
    01310
    01311   switch (rt) {
    01312     case REF_VEHICLE_OLD: // Old vehicles we save as new onces
    01313     case REF_VEHICLE:   return ((const  Vehicle*)obj)->index + 1;
    01314     case REF_STATION:   return ((const  Station*)obj)->index + 1;
    01315     case REF_TOWN:      return ((const     Town*)obj)->index + 1;
    01316     case REF_ORDER:     return ((const    Order*)obj)->index + 1;
    01317     case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
    01318     case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
    01319     case REF_CARGO_PACKET:  return ((const CargoPacket*)obj)->index + 1;
    01320     default: NOT_REACHED();
    01321   }
    01322
    01323   return 0; // avoid compiler warning
    01324 }
    01325
    01336 static void *IntToReference(uint index, SLRefType rt)
    01337 {
    01338   /* After version 4.3 REF_VEHICLE_OLD is saved as REF_VEHICLE,
    01339    * and should be loaded like that */
    01340   if (rt == REF_VEHICLE_OLD && !CheckSavegameVersionOldStyle(4, 4)) {
    01341     rt = REF_VEHICLE;
    01342   }
    01343
    01344   /* No need to look up NULL pointers, just return immediately */
    01345   if (rt != REF_VEHICLE_OLD && index == 0) {
    01346     return NULL;
    01347   }
    01348
    01349   index--; // correct for the NULL index
    01350
    01351   switch (rt) {
    01352     case REF_ORDER:
    01353       if (_Order_pool.AddBlockIfNeeded(index)) return GetOrder(index);
    01354       error("Orders: failed loading savegame: too many orders");
    01355
    01356     case REF_VEHICLE:
    01357       if (_Vehicle_pool.AddBlockIfNeeded(index)) return GetVehicle(index);
    01358       error("Vehicles: failed loading savegame: too many vehicles");
    01359
    01360     case REF_STATION:
    01361       if (_Station_pool.AddBlockIfNeeded(index)) return GetStation(index);
    01362       error("Stations: failed loading savegame: too many stations");
    01363
    01364     case REF_TOWN:
    01365       if (_Town_pool.AddBlockIfNeeded(index)) return GetTown(index);
    01366       error("Towns: failed loading savegame: too many towns");
    01367
    01368     case REF_ROADSTOPS:
    01369       if (_RoadStop_pool.AddBlockIfNeeded(index)) return GetRoadStop(index);
    01370       error("RoadStops: failed loading savegame: too many RoadStops");
    01371
    01372     case REF_ENGINE_RENEWS:
    01373       if (_EngineRenew_pool.AddBlockIfNeeded(index)) return GetEngineRenew(index);
    01374       error("EngineRenews: failed loading savegame: too many EngineRenews");
    01375
    01376     case REF_CARGO_PACKET:
    01377       if (_CargoPacket_pool.AddBlockIfNeeded(index)) return GetCargoPacket(index);
    01378       error("CargoPackets: failed loading savegame: too many Cargo packets");
    01379
    01380     case REF_VEHICLE_OLD:
    01381       /* Old vehicles were saved differently:
    01382        * invalid vehicle was 0xFFFF,
    01383        * and the index was not - 1.. correct for this */
    01384       index++;
    01385       if (index == INVALID_VEHICLE) return NULL;
    01386
    01387       if (_Vehicle_pool.AddBlockIfNeeded(index)) return GetVehicle(index);
    01388       error("Vehicles: failed loading savegame: too many vehicles");
    01389
    01390     default: NOT_REACHED();
    01391   }
    01392
    01393   return NULL;
    01394 }
    01395
    01397 struct SaveLoadFormat {
    01398   const char *name;
    01399   uint32 tag;
    01400
    01401   bool (*init_read)();
    01402   ReaderProc *reader;
    01403   void (*uninit_read)();
    01404
    01405   bool (*init_write)();
    01406   WriterProc *writer;
    01407   void (*uninit_write)();
    01408 };
    01409
    01410 static const SaveLoadFormat _saveload_formats[] = {
    01411   {"memory", 0,                NULL,         NULL,       NULL,           InitMem,       WriteMem,    UnInitMem},
    01412   {"lzo",    TO_BE32X('OTTD'), InitLZO,      ReadLZO,    UninitLZO,      InitLZO,       WriteLZO,    UninitLZO},
    01413   {"none",   TO_BE32X('OTTN'), InitNoComp,   ReadNoComp, UninitNoComp,   InitNoComp,    WriteNoComp, UninitNoComp},
    01414 #if defined(WITH_ZLIB)
    01415   {"zlib",   TO_BE32X('OTTZ'), InitReadZlib, ReadZlib,   UninitReadZlib, InitWriteZlib, WriteZlib,   UninitWriteZlib},
    01416 #else
    01417   {"zlib",   TO_BE32X('OTTZ'), NULL,         NULL,       NULL,           NULL,          NULL,        NULL},
    01418 #endif
    01419 };
    01420
    01427 static const SaveLoadFormat *GetSavegameFormat(const char *s)
    01428 {
    01429   const SaveLoadFormat *def = endof(_saveload_formats) - 1;
    01430
    01431   /* find default savegame format, the highest one with which files can be written */
    01432   while (!def->init_write) def--;
    01433
    01434   if (s != NULL && s[0] != '\0') {
    01435     const SaveLoadFormat *slf;
    01436     for (slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
    01437       if (slf->init_write != NULL && strcmp(s, slf->name) == 0)
    01438         return slf;
    01439     }
    01440
    01441     ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
    01442   }
    01443   return def;
    01444 }
    01445
    01446 /* actual loader/saver function */
    01447 void InitializeGame(int mode, uint size_x, uint size_y);
    01448 extern bool AfterLoadGame();
    01449 extern void BeforeSaveGame();
    01450 extern bool LoadOldSaveGame(const char *file);
    01451
    01453 static inline SaveOrLoadResult AbortSaveLoad()
    01454 {
    01455   if (_sl.fh != NULL) fclose(_sl.fh);
    01456
    01457   _sl.fh = NULL;
    01458   return SL_ERROR;
    01459 }
    01460
    01464 void SaveFileStart()
    01465 {
    01466   _ts.ff_state = _fast_forward;
    01467   _fast_forward = 0;
    01468   if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
    01469
    01470   SendWindowMessage(WC_STATUS_BAR, 0, true, 0, 0);
    01471   _ts.saveinprogress = true;
    01472 }
    01473
    01476 void SaveFileDone()
    01477 {
    01478   _fast_forward = _ts.ff_state;
    01479   if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
    01480
    01481   SendWindowMessage(WC_STATUS_BAR, 0, false, 0, 0);
    01482   _ts.saveinprogress = false;
    01483 }
    01484
    01486 void SetSaveLoadError(StringID str)
    01487 {
    01488   _sl.error_str = str;
    01489 }
    01490
    01492 const char *GetSaveLoadErrorString()
    01493 {
    01494   SetDParam(0, _sl.error_str);
    01495   SetDParamStr(1, _sl.extra_msg);
    01496
    01497   static char err_str[512];
    01498   GetString(err_str, _sl.save ? STR_4007_GAME_SAVE_FAILED : STR_4009_GAME_LOAD_FAILED, lastof(err_str));
    01499   return err_str;
    01500 }
    01501
    01503 void SaveFileError()
    01504 {
    01505   SetDParamStr(0, GetSaveLoadErrorString());
    01506   ShowErrorMessage(STR_012D, STR_NULL, 0, 0);
    01507   SaveFileDone();
    01508 }
    01509
    01510 static OTTDThread* save_thread;
    01511
    01515 static SaveOrLoadResult SaveFileToDisk(bool threaded)
    01516 {
    01517   const SaveLoadFormat *fmt;
    01518   uint32 hdr[2];
    01519
    01520   _sl.excpt_uninit = NULL;
    01521   try {
    01522     fmt = GetSavegameFormat(_savegame_format);
    01523
    01524     /* We have written our stuff to memory, now write it to file! */
    01525     hdr[0] = fmt->tag;
    01526     hdr[1] = TO_BE32(SAVEGAME_VERSION << 16);
    01527     if (fwrite(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
    01528
    01529     if (!fmt->init_write()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
    01530
    01531     {
    01532       uint i;
    01533       uint count = 1 << Savegame_POOL_BLOCK_SIZE_BITS;
    01534
    01535       if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
    01536       for (i = 0; i != _Savegame_pool.GetBlockCount() - 1; i++) {
    01537         _sl.buf = _Savegame_pool.blocks[i];
    01538         fmt->writer(count);
    01539       }
    01540
    01541       /* The last block is (almost) always not fully filled, so only write away
    01542        * as much data as it is in there */
    01543       _sl.buf = _Savegame_pool.blocks[i];
    01544       fmt->writer(_ts.count - (i * count));
    01545     }
    01546
    01547     fmt->uninit_write();
    01548     if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
    01549     GetSavegameFormat("memory")->uninit_write(); // clean the memorypool
    01550     fclose(_sl.fh);
    01551
    01552     if (threaded) OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_DONE);
    01553
    01554     return SL_OK;
    01555   }
    01556   catch (...) {
    01557     AbortSaveLoad();
    01558     if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
    01559
    01560     ShowInfo(GetSaveLoadErrorString());
    01561     fprintf(stderr, GetSaveLoadErrorString());
    01562
    01563     if (threaded) {
    01564       OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_ERROR);
    01565     } else {
    01566       SaveFileError();
    01567     }
    01568     return SL_ERROR;
    01569   }
    01570 }
    01571
    01572 static void* SaveFileToDiskThread(void *arg)
    01573 {
    01574   SaveFileToDisk(true);
    01575   return NULL;
    01576 }
    01577
    01578 void WaitTillSaved()
    01579 {
    01580   OTTDJoinThread(save_thread);
    01581   save_thread = NULL;
    01582 }
    01583
    01591 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb)
    01592 {
    01593   uint32 hdr[2];
    01594   const SaveLoadFormat *fmt;
    01595
    01596   /* An instance of saving is already active, so don't go saving again */
    01597   if (_ts.saveinprogress && mode == SL_SAVE) {
    01598     /* if not an autosave, but a user action, show error message */
    01599     if (!_do_autosave) ShowErrorMessage(INVALID_STRING_ID, STR_SAVE_STILL_IN_PROGRESS, 0, 0);
    01600     return SL_OK;
    01601   }
    01602   WaitTillSaved();
    01603
    01604   _next_offs = 0;
    01605
    01606   /* Load a TTDLX or TTDPatch game */
    01607   if (mode == SL_OLD_LOAD) {
    01608     InitializeGame(IG_DATE_RESET, 256, 256); // set a mapsize of 256x256 for TTDPatch games or it might get confused
    01609     if (!LoadOldSaveGame(filename)) return SL_REINIT;
    01610     _sl_version = 0;
    01611     if (!AfterLoadGame()) return SL_REINIT;
    01612     return SL_OK;
    01613   }
    01614
    01615   _sl.excpt_uninit = NULL;
    01616   try {
    01617     _sl.fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
    01618
    01619     /* Make it a little easier to load savegames from the console */
    01620     if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", SAVE_DIR);
    01621     if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", BASE_DIR);
    01622
    01623     if (_sl.fh == NULL) {
    01624       SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
    01625     }
    01626
    01627     _sl.bufe = _sl.bufp = NULL;
    01628     _sl.offs_base = 0;
    01629     _sl.save = (mode != 0);
    01630     _sl.chs = _chunk_handlers;
    01631
    01632     /* General tactic is to first save the game to memory, then use an available writer
    01633      * to write it to file, either in threaded mode if possible, or single-threaded */
    01634     if (mode == SL_SAVE) { /* SAVE game */
    01635       fmt = GetSavegameFormat("memory"); // write to memory
    01636
    01637       _sl.write_bytes = fmt->writer;
    01638       _sl.excpt_uninit = fmt->uninit_write;
    01639       if (!fmt->init_write()) {
    01640         DEBUG(sl, 0, "Initializing writer '%s' failed.", fmt->name);
    01641         return AbortSaveLoad();
    01642       }
    01643
    01644       _sl_version = SAVEGAME_VERSION;
    01645
    01646       BeforeSaveGame();
    01647       SlSaveChunks();
    01648       SlWriteFill(); // flush the save buffer
    01649
    01650       SaveFileStart();
    01651       if (_network_server ||
    01652             (save_thread = OTTDCreateThread(&SaveFileToDiskThread, NULL)) == NULL) {
    01653         if (!_network_server) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
    01654
    01655         SaveOrLoadResult result = SaveFileToDisk(false);
    01656         SaveFileDone();
    01657
    01658         return result;
    01659       }
    01660     } else { /* LOAD game */
    01661       assert(mode == SL_LOAD);
    01662       DebugDumpCommands("ddc:load:%s\n", filename);
    01663
    01664       if (fread(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
    01665
    01666       /* see if we have any loader for this type. */
    01667       for (fmt = _saveload_formats; ; fmt++) {
    01668         /* No loader found, treat as version 0 and use LZO format */
    01669         if (fmt == endof(_saveload_formats)) {
    01670           DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
    01671   #if defined(WINCE)
    01672           /* Of course some system had not to support rewind ;) */
    01673           fseek(_sl.fh, 0L, SEEK_SET);
    01674           clearerr(_sl.fh);
    01675   #else
    01676           rewind(_sl.fh);
    01677   #endif
    01678           _sl_version = 0;
    01679           _sl_minor_version = 0;
    01680           fmt = _saveload_formats + 1; // LZO
    01681           break;
    01682         }
    01683
    01684         if (fmt->tag == hdr[0]) {
    01685           /* check version number */
    01686           _sl_version = TO_BE32(hdr[1]) >> 16;
    01687           /* Minor is not used anymore from version 18.0, but it is still needed
    01688            * in versions before that (4 cases) which can't be removed easy.
    01689            * Therefor it is loaded, but never saved (or, it saves a 0 in any scenario).
    01690            * So never EVER use this minor version again. -- TrueLight -- 22-11-2005 */
    01691           _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
    01692
    01693           DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
    01694
    01695           /* Is the version higher than the current? */
    01696           if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
    01697           break;
    01698         }
    01699       }
    01700
    01701       _sl.read_bytes = fmt->reader;
    01702       _sl.excpt_uninit = fmt->uninit_read;
    01703
    01704       /* loader for this savegame type is not implemented? */
    01705       if (fmt->init_read == NULL) {
    01706         char err_str[64];
    01707         snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
    01708         SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
    01709       }
    01710
    01711       if (!fmt->init_read()) {
    01712         char err_str[64];
    01713         snprintf(err_str, lengthof(err_str), "Initializing loader '%s' failed", fmt->name);
    01714         SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
    01715       }
    01716
    01717       /* Old maps were hardcoded to 256x256 and thus did not contain
    01718        * any mapsize information. Pre-initialize to 256x256 to not to
    01719        * confuse old games */
    01720       InitializeGame(IG_DATE_RESET, 256, 256);
    01721
    01722       SlLoadChunks();
    01723       fmt->uninit_read();
    01724       fclose(_sl.fh);
    01725
    01726       /* After loading fix up savegame for any internal changes that
    01727        * might've occured since then. If it fails, load back the old game */
    01728       if (!AfterLoadGame()) return SL_REINIT;
    01729     }
    01730
    01731     return SL_OK;
    01732   }
    01733   catch (...) {
    01734     AbortSaveLoad();
    01735
    01736     /* deinitialize compressor. */
    01737     if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
    01738
    01739     /* Skip the "color" character */
    01740     ShowInfoF(GetSaveLoadErrorString() + 3);
    01741
    01742     /* A saver/loader exception!! reinitialize all variables to prevent crash! */
    01743     return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
    01744   }
    01745 }
    01746
    01748 void DoExitSave()
    01749 {
    01750   SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
    01751 }
    01752
    01753 #if 0
    01754
    01760 int GetSavegameType(char *file)
    01761 {
    01762   const SaveLoadFormat *fmt;
    01763   uint32 hdr;
    01764   FILE *f;
    01765   int mode = SL_OLD_LOAD;
    01766
    01767   f = fopen(file, "rb");
    01768   if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
    01769     DEBUG(sl, 0, "Savegame is obsolete or invalid format");
    01770     mode = SL_LOAD; // don't try to get filename, just show name as it is written
    01771   } else {
    01772     /* see if we have any loader for this type. */
    01773     for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
    01774       if (fmt->tag == hdr) {
    01775         mode = SL_LOAD; // new type of savegame
    01776         break;
    01777       }
    01778     }
    01779   }
    01780
    01781   fclose(f);
    01782   return mode;
    01783 }
    01784 #endif