# saveload.cpp

Go to the documentation of this file.

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