# saveload.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00023 #include "../stdafx.h"
    00024 #include "../openttd.h"
    00025 #include "../debug.h"
    00026 #include "../station_base.h"
    00027 #include "../thread/thread.h"
    00028 #include "../town.h"
    00029 #include "../network/network.h"
    00030 #include "../variables.h"
    00031 #include "../window_func.h"
    00032 #include "../strings_func.h"
    00033 #include "../gfx_func.h"
    00034 #include "../core/endian_func.hpp"
    00035 #include "../vehicle_base.h"
    00036 #include "../company_func.h"
    00037 #include "../date_func.h"
    00038 #include "../autoreplace_base.h"
    00039 #include "../roadstop_base.h"
    00040 #include "../statusbar_gui.h"
    00041 #include "../fileio_func.h"
    00042 #include "../gamelog.h"
    00043 #include "../string_func.h"
    00044 #include "../engine_base.h"
    00045
    00046 #include "table/strings.h"
    00047
    00048 #include "saveload_internal.h"
    00049
    00050 extern const uint16 SAVEGAME_VERSION = 133;
    00051
    00052 SavegameType _savegame_type;
    00053
    00054 uint32 _ttdp_version;
    00055 uint16 _sl_version;
    00056 byte   _sl_minor_version;
    00057 char _savegame_format[8];
    00058
    00059 typedef void WriterProc(size_t len);
    00060 typedef size_t ReaderProc();
    00061
    00063 enum SaveLoadAction {
    00064   SLA_LOAD,
    00065   SLA_SAVE,
    00066   SLA_PTRS,
    00067   SLA_NULL,
    00068 };
    00069
    00070 enum NeedLength {
    00071   NL_NONE = 0,
    00072   NL_WANTLENGTH = 1,
    00073   NL_CALCLENGTH = 2,
    00074 };
    00075
    00077 struct SaveLoadParams {
    00078   SaveLoadAction action;
    00079   NeedLength need_length;
    00080   byte block_mode;
    00081   bool error;
    00082
    00083   size_t obj_len;
    00084   int array_index, last_array_index;
    00085
    00086   size_t offs_base;
    00087
    00088   WriterProc *write_bytes;
    00089   ReaderProc *read_bytes;
    00090
    00091   const ChunkHandler * const *chs;
    00092
    00093   /* When saving/loading savegames, they are always saved to a temporary memory-place
    00094    * to be flushed to file (save) or to final place (load) when full. */
    00095   byte *bufp, *bufe;
    00096
    00097   /* these 3 may be used by compressor/decompressors. */
    00098   byte *buf;
    00099   byte *buf_ori;
    00100   uint bufsize;
    00101   FILE *fh;
    00102
    00103   void (*excpt_uninit)();
    00104   StringID error_str;
    00105   char *extra_msg;
    00106 };
    00107
    00108 static SaveLoadParams _sl;
    00109
    00111 static void SlNullPointers()
    00112 {
    00113   const ChunkHandler *ch;
    00114   const ChunkHandler * const *chsc;
    00115
    00116   _sl.action = SLA_NULL;
    00117
    00118   DEBUG(sl, 1, "Nulling pointers");
    00119
    00120   for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
    00121     while (true) {
    00122       if (ch->ptrs_proc != NULL) {
    00123         DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
    00124         ch->ptrs_proc();
    00125       }
    00126       if (ch->flags & CH_LAST) break;
    00127       ch++;
    00128     }
    00129   }
    00130
    00131   DEBUG(sl, 1, "All pointers nulled");
    00132
    00133   assert(_sl.action == SLA_NULL);
    00134 }
    00135
    00139 static void NORETURN SlError(StringID string, const char *extra_msg = NULL)
    00140 {
    00141   _sl.error_str = string;
    00142   free(_sl.extra_msg);
    00143   _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
    00144   /* We have to NULL all pointers here; we might be in a state where
    00145    * the pointers are actually filled with indices, which means that
    00146    * when we access them during cleaning the pool dereferences of
    00147    * those indices will be made with segmentation faults as result. */
    00148   SlNullPointers();
    00149   throw std::exception();
    00150 }
    00151
    00152 typedef void (*AsyncSaveFinishProc)();
    00153 static AsyncSaveFinishProc _async_save_finish = NULL;
    00154 static ThreadObject *_save_thread;
    00155
    00159 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
    00160 {
    00161   if (_exit_game) return;
    00162   while (_async_save_finish != NULL) CSleep(10);
    00163
    00164   _async_save_finish = proc;
    00165 }
    00166
    00170 void ProcessAsyncSaveFinish()
    00171 {
    00172   if (_async_save_finish == NULL) return;
    00173
    00174   _async_save_finish();
    00175
    00176   _async_save_finish = NULL;
    00177
    00178   if (_save_thread != NULL) {
    00179     _save_thread->Join();
    00180     delete _save_thread;
    00181     _save_thread = NULL;
    00182   }
    00183 }
    00184
    00188 static void SlReadFill()
    00189 {
    00190   size_t len = _sl.read_bytes();
    00191   if (len == 0) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected end of chunk");
    00192
    00193   _sl.bufp = _sl.buf;
    00194   _sl.bufe = _sl.buf + len;
    00195   _sl.offs_base += len;
    00196 }
    00197
    00198 static inline size_t SlGetOffs() {return _sl.offs_base - (_sl.bufe - _sl.bufp);}
    00199 static inline uint SlReadArrayLength();
    00200
    00205 static inline uint SlCalcConvMemLen(VarType conv)
    00206 {
    00207   static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
    00208   byte length = GB(conv, 4, 4);
    00209
    00210   switch (length << 4) {
    00211     case SLE_VAR_STRB:
    00212     case SLE_VAR_STRBQ:
    00213     case SLE_VAR_STR:
    00214     case SLE_VAR_STRQ:
    00215       return SlReadArrayLength();
    00216
    00217     default:
    00218       assert(length < lengthof(conv_mem_size));
    00219       return conv_mem_size[length];
    00220   }
    00221 }
    00222
    00227 static inline byte SlCalcConvFileLen(VarType conv)
    00228 {
    00229   static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
    00230   byte length = GB(conv, 0, 4);
    00231   assert(length < lengthof(conv_file_size));
    00232   return conv_file_size[length];
    00233 }
    00234
    00236 static inline size_t SlCalcRefLen() {return CheckSavegameVersion(69) ? 2 : 4;}
    00237
    00242 static void SlWriteFill()
    00243 {
    00244   /* flush the buffer to disk (the writer) */
    00245   if (_sl.bufp != NULL) {
    00246     uint len = _sl.bufp - _sl.buf;
    00247     _sl.offs_base += len;
    00248     if (len) _sl.write_bytes(len);
    00249   }
    00250
    00251   /* All the data from the buffer has been written away, rewind to the beginning
    00252    * to start reading in more data */
    00253   _sl.bufp = _sl.buf;
    00254   _sl.bufe = _sl.buf + _sl.bufsize;
    00255 }
    00256
    00261 static inline byte SlReadByteInternal()
    00262 {
    00263   if (_sl.bufp == _sl.bufe) SlReadFill();
    00264   return *_sl.bufp++;
    00265 }
    00266
    00268 byte SlReadByte() {return SlReadByteInternal();}
    00269
    00274 static inline void SlWriteByteInternal(byte b)
    00275 {
    00276   if (_sl.bufp == _sl.bufe) SlWriteFill();
    00277   *_sl.bufp++ = b;
    00278 }
    00279
    00281 void SlWriteByte(byte b) {SlWriteByteInternal(b);}
    00282
    00283 static inline int SlReadUint16()
    00284 {
    00285   int x = SlReadByte() << 8;
    00286   return x | SlReadByte();
    00287 }
    00288
    00289 static inline uint32 SlReadUint32()
    00290 {
    00291   uint32 x = SlReadUint16() << 16;
    00292   return x | SlReadUint16();
    00293 }
    00294
    00295 static inline uint64 SlReadUint64()
    00296 {
    00297   uint32 x = SlReadUint32();
    00298   uint32 y = SlReadUint32();
    00299   return (uint64)x << 32 | y;
    00300 }
    00301
    00302 static inline void SlWriteUint16(uint16 v)
    00303 {
    00304   SlWriteByte(GB(v, 8, 8));
    00305   SlWriteByte(GB(v, 0, 8));
    00306 }
    00307
    00308 static inline void SlWriteUint32(uint32 v)
    00309 {
    00310   SlWriteUint16(GB(v, 16, 16));
    00311   SlWriteUint16(GB(v,  0, 16));
    00312 }
    00313
    00314 static inline void SlWriteUint64(uint64 x)
    00315 {
    00316   SlWriteUint32((uint32)(x >> 32));
    00317   SlWriteUint32((uint32)x);
    00318 }
    00319
    00329 static uint SlReadSimpleGamma()
    00330 {
    00331   uint i = SlReadByte();
    00332   if (HasBit(i, 7)) {
    00333     i &= ~0x80;
    00334     if (HasBit(i, 6)) {
    00335       i &= ~0x40;
    00336       if (HasBit(i, 5)) {
    00337         i &= ~0x20;
    00338         if (HasBit(i, 4))
    00339           SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unsupported gamma");
    00340         i = (i << 8) | SlReadByte();
    00341       }
    00342       i = (i << 8) | SlReadByte();
    00343     }
    00344     i = (i << 8) | SlReadByte();
    00345   }
    00346   return i;
    00347 }
    00348
    00361 static void SlWriteSimpleGamma(size_t i)
    00362 {
    00363   if (i >= (1 << 7)) {
    00364     if (i >= (1 << 14)) {
    00365       if (i >= (1 << 21)) {
    00366         assert(i < (1 << 28));
    00367         SlWriteByte((byte)(0xE0 | (i >> 24)));
    00368         SlWriteByte((byte)(i >> 16));
    00369       } else {
    00370         SlWriteByte((byte)(0xC0 | (i >> 16)));
    00371       }
    00372       SlWriteByte((byte)(i >> 8));
    00373     } else {
    00374       SlWriteByte((byte)(0x80 | (i >> 8)));
    00375     }
    00376   }
    00377   SlWriteByte((byte)i);
    00378 }
    00379
    00381 static inline uint SlGetGammaLength(size_t i)
    00382 {
    00383   return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
    00384 }
    00385
    00386 static inline uint SlReadSparseIndex() {return SlReadSimpleGamma();}
    00387 static inline void SlWriteSparseIndex(uint index) {SlWriteSimpleGamma(index);}
    00388
    00389 static inline uint SlReadArrayLength() {return SlReadSimpleGamma();}
    00390 static inline void SlWriteArrayLength(size_t length) {SlWriteSimpleGamma(length);}
    00391 static inline uint SlGetArrayLength(size_t length) {return SlGetGammaLength(length);}
    00392
    00393 void SlSetArrayIndex(uint index)
    00394 {
    00395   _sl.need_length = NL_WANTLENGTH;
    00396   _sl.array_index = index;
    00397 }
    00398
    00399 static size_t _next_offs;
    00400
    00405 int SlIterateArray()
    00406 {
    00407   int index;
    00408
    00409   /* After reading in the whole array inside the loop
    00410    * we must have read in all the data, so we must be at end of current block. */
    00411   if (_next_offs != 0 && SlGetOffs() != _next_offs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
    00412
    00413   while (true) {
    00414     uint length = SlReadArrayLength();
    00415     if (length == 0) {
    00416       _next_offs = 0;
    00417       return -1;
    00418     }
    00419
    00420     _sl.obj_len = --length;
    00421     _next_offs = SlGetOffs() + length;
    00422
    00423     switch (_sl.block_mode) {
    00424       case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
    00425       case CH_ARRAY:        index = _sl.array_index++; break;
    00426       default:
    00427         DEBUG(sl, 0, "SlIterateArray error");
    00428         return -1; // error
    00429     }
    00430
    00431     if (length != 0) return index;
    00432   }
    00433 }
    00434
    00440 void SlSetLength(size_t length)
    00441 {
    00442   assert(_sl.action == SLA_SAVE);
    00443
    00444   switch (_sl.need_length) {
    00445     case NL_WANTLENGTH:
    00446       _sl.need_length = NL_NONE;
    00447       switch (_sl.block_mode) {
    00448         case CH_RIFF:
    00449           /* Ugly encoding of >16M RIFF chunks
    00450            * The lower 24 bits are normal
    00451            * The uppermost 4 bits are bits 24:27 */
    00452           assert(length < (1 << 28));
    00453           SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
    00454           break;
    00455         case CH_ARRAY:
    00456           assert(_sl.last_array_index <= _sl.array_index);
    00457           while (++_sl.last_array_index <= _sl.array_index)
    00458             SlWriteArrayLength(1);
    00459           SlWriteArrayLength(length + 1);
    00460           break;
    00461         case CH_SPARSE_ARRAY:
    00462           SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index)); // Also include length of sparse index.
    00463           SlWriteSparseIndex(_sl.array_index);
    00464           break;
    00465         default: NOT_REACHED();
    00466       }
    00467       break;
    00468
    00469     case NL_CALCLENGTH:
    00470       _sl.obj_len += (int)length;
    00471       break;
    00472
    00473     default: NOT_REACHED();
    00474   }
    00475 }
    00476
    00483 static void SlCopyBytes(void *ptr, size_t length)
    00484 {
    00485   byte *p = (byte *)ptr;
    00486
    00487   switch (_sl.action) {
    00488     case SLA_LOAD:
    00489       for (; length != 0; length--) { *p++ = SlReadByteInternal(); }
    00490       break;
    00491     case SLA_SAVE:
    00492       for (; length != 0; length--) { SlWriteByteInternal(*p++); }
    00493       break;
    00494     default: NOT_REACHED();
    00495   }
    00496 }
    00497
    00502 static inline void SlSkipBytes(size_t length)
    00503 {
    00504   for (; length != 0; length--) SlReadByte();
    00505 }
    00506
    00507 /* Get the length of the current object */
    00508 size_t SlGetFieldLength() {return _sl.obj_len;}
    00509
    00515 int64 ReadValue(const void *ptr, VarType conv)
    00516 {
    00517   switch (GetVarMemType(conv)) {
    00518     case SLE_VAR_BL:  return (*(bool *)ptr != 0);
    00519     case SLE_VAR_I8:  return *(int8  *)ptr;
    00520     case SLE_VAR_U8:  return *(byte  *)ptr;
    00521     case SLE_VAR_I16: return *(int16 *)ptr;
    00522     case SLE_VAR_U16: return *(uint16*)ptr;
    00523     case SLE_VAR_I32: return *(int32 *)ptr;
    00524     case SLE_VAR_U32: return *(uint32*)ptr;
    00525     case SLE_VAR_I64: return *(int64 *)ptr;
    00526     case SLE_VAR_U64: return *(uint64*)ptr;
    00527     case SLE_VAR_NULL:return 0;
    00528     default: NOT_REACHED();
    00529   }
    00530 }
    00531
    00537 void WriteValue(void *ptr, VarType conv, int64 val)
    00538 {
    00539   switch (GetVarMemType(conv)) {
    00540     case SLE_VAR_BL:  *(bool  *)ptr = (val != 0);  break;
    00541     case SLE_VAR_I8:  *(int8  *)ptr = val; break;
    00542     case SLE_VAR_U8:  *(byte  *)ptr = val; break;
    00543     case SLE_VAR_I16: *(int16 *)ptr = val; break;
    00544     case SLE_VAR_U16: *(uint16*)ptr = val; break;
    00545     case SLE_VAR_I32: *(int32 *)ptr = val; break;
    00546     case SLE_VAR_U32: *(uint32*)ptr = val; break;
    00547     case SLE_VAR_I64: *(int64 *)ptr = val; break;
    00548     case SLE_VAR_U64: *(uint64*)ptr = val; break;
    00549     case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
    00550     case SLE_VAR_NULL: break;
    00551     default: NOT_REACHED();
    00552   }
    00553 }
    00554
    00563 static void SlSaveLoadConv(void *ptr, VarType conv)
    00564 {
    00565   switch (_sl.action) {
    00566     case SLA_SAVE: {
    00567       int64 x = ReadValue(ptr, conv);
    00568
    00569       /* Write the value to the file and check if its value is in the desired range */
    00570       switch (GetVarFileType(conv)) {
    00571         case SLE_FILE_I8: assert(x >= -128 && x <= 127);     SlWriteByte(x);break;
    00572         case SLE_FILE_U8: assert(x >= 0 && x <= 255);        SlWriteByte(x);break;
    00573         case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
    00574         case SLE_FILE_STRINGID:
    00575         case SLE_FILE_U16:assert(x >= 0 && x <= 65535);      SlWriteUint16(x);break;
    00576         case SLE_FILE_I32:
    00577         case SLE_FILE_U32:                                   SlWriteUint32((uint32)x);break;
    00578         case SLE_FILE_I64:
    00579         case SLE_FILE_U64:                                   SlWriteUint64(x);break;
    00580         default: NOT_REACHED();
    00581       }
    00582       break;
    00583     }
    00584     case SLA_LOAD: {
    00585       int64 x;
    00586       /* Read a value from the file */
    00587       switch (GetVarFileType(conv)) {
    00588         case SLE_FILE_I8:  x = (int8  )SlReadByte();   break;
    00589         case SLE_FILE_U8:  x = (byte  )SlReadByte();   break;
    00590         case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
    00591         case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
    00592         case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
    00593         case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
    00594         case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
    00595         case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
    00596         case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
    00597         default: NOT_REACHED();
    00598       }
    00599
    00600       /* Write The value to the struct. These ARE endian safe. */
    00601       WriteValue(ptr, conv, x);
    00602       break;
    00603     }
    00604     case SLA_PTRS: break;
    00605     case SLA_NULL: break;
    00606     default: NOT_REACHED();
    00607   }
    00608 }
    00609
    00617 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
    00618 {
    00619   if (ptr == NULL) return 0;
    00620   return min(strlen(ptr), length - 1);
    00621 }
    00622
    00630 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
    00631 {
    00632   size_t len;
    00633   const char *str;
    00634
    00635   switch (GetVarMemType(conv)) {
    00636     default: NOT_REACHED();
    00637     case SLE_VAR_STR:
    00638     case SLE_VAR_STRQ:
    00639       str = *(const char**)ptr;
    00640       len = SIZE_MAX;
    00641       break;
    00642     case SLE_VAR_STRB:
    00643     case SLE_VAR_STRBQ:
    00644       str = (const char*)ptr;
    00645       len = length;
    00646       break;
    00647   }
    00648
    00649   len = SlCalcNetStringLen(str, len);
    00650   return len + SlGetArrayLength(len); // also include the length of the index
    00651 }
    00652
    00658 static void SlString(void *ptr, size_t length, VarType conv)
    00659 {
    00660   switch (_sl.action) {
    00661     case SLA_SAVE: {
    00662       size_t len;
    00663       switch (GetVarMemType(conv)) {
    00664         default: NOT_REACHED();
    00665         case SLE_VAR_STRB:
    00666         case SLE_VAR_STRBQ:
    00667           len = SlCalcNetStringLen((char *)ptr, length);
    00668           break;
    00669         case SLE_VAR_STR:
    00670         case SLE_VAR_STRQ:
    00671           ptr = *(char **)ptr;
    00672           len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
    00673           break;
    00674       }
    00675
    00676       SlWriteArrayLength(len);
    00677       SlCopyBytes(ptr, len);
    00678       break;
    00679     }
    00680     case SLA_LOAD: {
    00681       size_t len = SlReadArrayLength();
    00682
    00683       switch (GetVarMemType(conv)) {
    00684         default: NOT_REACHED();
    00685         case SLE_VAR_STRB:
    00686         case SLE_VAR_STRBQ:
    00687           if (len >= length) {
    00688             DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
    00689             SlCopyBytes(ptr, length);
    00690             SlSkipBytes(len - length);
    00691             len = length - 1;
    00692           } else {
    00693             SlCopyBytes(ptr, len);
    00694           }
    00695           break;
    00696         case SLE_VAR_STR:
    00697         case SLE_VAR_STRQ: // Malloc'd string, free previous incarnation, and allocate
    00698           free(*(char **)ptr);
    00699           if (len == 0) {
    00700             *(char **)ptr = NULL;
    00701           } else {
    00702             *(char **)ptr = MallocT<char>(len + 1); // terminating '\0'
    00703             ptr = *(char **)ptr;
    00704             SlCopyBytes(ptr, len);
    00705           }
    00706           break;
    00707       }
    00708
    00709       ((char *)ptr)[len] = '\0'; // properly terminate the string
    00710       str_validate((char *)ptr, (char *)ptr + len);
    00711       break;
    00712     }
    00713     case SLA_PTRS: break;
    00714     case SLA_NULL: break;
    00715     default: NOT_REACHED();
    00716   }
    00717 }
    00718
    00724 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
    00725 {
    00726   return SlCalcConvFileLen(conv) * length;
    00727 }
    00728
    00735 void SlArray(void *array, size_t length, VarType conv)
    00736 {
    00737   if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
    00738
    00739   /* Automatically calculate the length? */
    00740   if (_sl.need_length != NL_NONE) {
    00741     SlSetLength(SlCalcArrayLen(length, conv));
    00742     /* Determine length only? */
    00743     if (_sl.need_length == NL_CALCLENGTH) return;
    00744   }
    00745
    00746   /* NOTICE - handle some buggy stuff, in really old versions everything was saved
    00747    * as a byte-type. So detect this, and adjust array size accordingly */
    00748   if (_sl.action != SLA_SAVE && _sl_version == 0) {
    00749     /* all arrays except difficulty settings */
    00750     if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
    00751         conv == SLE_INT32 || conv == SLE_UINT32) {
    00752       SlCopyBytes(array, length * SlCalcConvFileLen(conv));
    00753       return;
    00754     }
    00755     /* used for conversion of Money 32bit->64bit */
    00756     if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
    00757       for (uint i = 0; i < length; i++) {
    00758         ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
    00759       }
    00760       return;
    00761     }
    00762   }
    00763
    00764   /* If the size of elements is 1 byte both in file and memory, no special
    00765    * conversion is needed, use specialized copy-copy function to speed up things */
    00766   if (conv == SLE_INT8 || conv == SLE_UINT8) {
    00767     SlCopyBytes(array, length);
    00768   } else {
    00769     byte *a = (byte*)array;
    00770     byte mem_size = SlCalcConvMemLen(conv);
    00771
    00772     for (; length != 0; length --) {
    00773       SlSaveLoadConv(a, conv);
    00774       a += mem_size; // get size
    00775     }
    00776   }
    00777 }
    00778
    00779
    00780 static size_t ReferenceToInt(const void *obj, SLRefType rt);
    00781 static void *IntToReference(size_t index, SLRefType rt);
    00782
    00783
    00788 static inline size_t SlCalcListLen(const void *list)
    00789 {
    00790   std::list<void *> *l = (std::list<void *> *) list;
    00791
    00792   int type_size = CheckSavegameVersion(69) ? 2 : 4;
    00793   /* Each entry is saved as type_size bytes, plus type_size bytes are used for the length
    00794    * of the list */
    00795   return l->size() * type_size + type_size;
    00796 }
    00797
    00798
    00804 static void SlList(void *list, SLRefType conv)
    00805 {
    00806   /* Automatically calculate the length? */
    00807   if (_sl.need_length != NL_NONE) {
    00808     SlSetLength(SlCalcListLen(list));
    00809     /* Determine length only? */
    00810     if (_sl.need_length == NL_CALCLENGTH) return;
    00811   }
    00812
    00813   typedef std::list<void *> PtrList;
    00814   PtrList *l = (PtrList *)list;
    00815
    00816   switch (_sl.action) {
    00817     case SLA_SAVE: {
    00818       SlWriteUint32((uint32)l->size());
    00819
    00820       PtrList::iterator iter;
    00821       for (iter = l->begin(); iter != l->end(); ++iter) {
    00822         void *ptr = *iter;
    00823         SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
    00824       }
    00825       break;
    00826     }
    00827     case SLA_LOAD: {
    00828       size_t length = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
    00829
    00830       /* Load each reference and push to the end of the list */
    00831       for (size_t i = 0; i < length; i++) {
    00832         size_t data = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
    00833         l->push_back((void *)data);
    00834       }
    00835       break;
    00836     }
    00837     case SLA_PTRS: {
    00838       PtrList temp = *l;
    00839
    00840       l->clear();
    00841       PtrList::iterator iter;
    00842       for (iter = temp.begin(); iter != temp.end(); ++iter) {
    00843         void *ptr = IntToReference((size_t)*iter, conv);
    00844         l->push_back(ptr);
    00845       }
    00846       break;
    00847     }
    00848     case SLA_NULL:
    00849       l->clear();
    00850       break;
    00851     default: NOT_REACHED();
    00852   }
    00853 }
    00854
    00855
    00857 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
    00858 {
    00859   if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
    00860   if (sld->conv & SLF_SAVE_NO) return false;
    00861
    00862   return true;
    00863 }
    00864
    00868 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
    00869 {
    00870   if ((sld->conv & SLF_NETWORK_NO) && _sl.action != SLA_SAVE && _networking && !_network_server) {
    00871     SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
    00872     return true;
    00873   }
    00874
    00875   return false;
    00876 }
    00877
    00884 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
    00885 {
    00886   size_t length = 0;
    00887
    00888   /* Need to determine the length and write a length tag. */
    00889   for (; sld->cmd != SL_END; sld++) {
    00890     length += SlCalcObjMemberLength(object, sld);
    00891   }
    00892   return length;
    00893 }
    00894
    00895 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
    00896 {
    00897   assert(_sl.action == SLA_SAVE);
    00898
    00899   switch (sld->cmd) {
    00900     case SL_VAR:
    00901     case SL_REF:
    00902     case SL_ARR:
    00903     case SL_STR:
    00904     case SL_LST:
    00905       /* CONDITIONAL saveload types depend on the savegame version */
    00906       if (!SlIsObjectValidInSavegame(sld)) break;
    00907
    00908       switch (sld->cmd) {
    00909         case SL_VAR: return SlCalcConvFileLen(sld->conv);
    00910         case SL_REF: return SlCalcRefLen();
    00911         case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
    00912         case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
    00913         case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
    00914         default: NOT_REACHED();
    00915       }
    00916       break;
    00917     case SL_WRITEBYTE: return 1; // a byte is logically of size 1
    00918     case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
    00919     case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
    00920     default: NOT_REACHED();
    00921   }
    00922   return 0;
    00923 }
    00924
    00925
    00926 bool SlObjectMember(void *ptr, const SaveLoad *sld)
    00927 {
    00928   VarType conv = GB(sld->conv, 0, 8);
    00929   switch (sld->cmd) {
    00930     case SL_VAR:
    00931     case SL_REF:
    00932     case SL_ARR:
    00933     case SL_STR:
    00934     case SL_LST:
    00935       /* CONDITIONAL saveload types depend on the savegame version */
    00936       if (!SlIsObjectValidInSavegame(sld)) return false;
    00937       if (SlSkipVariableOnLoad(sld)) return false;
    00938
    00939       switch (sld->cmd) {
    00940         case SL_VAR: SlSaveLoadConv(ptr, conv); break;
    00941         case SL_REF: // Reference variable, translate
    00942           switch (_sl.action) {
    00943             case SLA_SAVE:
    00944               SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
    00945               break;
    00946             case SLA_LOAD:
    00947               *(size_t *)ptr = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
    00948               break;
    00949             case SLA_PTRS:
    00950               *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
    00951               break;
    00952             case SLA_NULL:
    00953               *(void **)ptr = NULL;
    00954               break;
    00955             default: NOT_REACHED();
    00956           }
    00957           break;
    00958         case SL_ARR: SlArray(ptr, sld->length, conv); break;
    00959         case SL_STR: SlString(ptr, sld->length, conv); break;
    00960         case SL_LST: SlList(ptr, (SLRefType)conv); break;
    00961         default: NOT_REACHED();
    00962       }
    00963       break;
    00964
    00965     /* SL_WRITEBYTE translates a value of a variable to another one upon
    00966      * saving or loading.
    00967      * XXX - variable renaming abuse
    00968      * game_value: the value of the variable ingame is abused by sld->version_from
    00969      * file_value: the value of the variable in the savegame is abused by sld->version_to */
    00970     case SL_WRITEBYTE:
    00971       switch (_sl.action) {
    00972         case SLA_SAVE: SlWriteByte(sld->version_to); break;
    00973         case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
    00974         case SLA_PTRS: break;
    00975         case SLA_NULL: break;
    00976         default: NOT_REACHED();
    00977       }
    00978       break;
    00979
    00980     /* SL_VEH_INCLUDE loads common code for vehicles */
    00981     case SL_VEH_INCLUDE:
    00982       SlObject(ptr, GetVehicleDescription(VEH_END));
    00983       break;
    00984
    00985     case SL_ST_INCLUDE:
    00986       SlObject(ptr, GetBaseStationDescription());
    00987       break;
    00988
    00989     default: NOT_REACHED();
    00990   }
    00991   return true;
    00992 }
    00993
    00999 void SlObject(void *object, const SaveLoad *sld)
    01000 {
    01001   /* Automatically calculate the length? */
    01002   if (_sl.need_length != NL_NONE) {
    01003     SlSetLength(SlCalcObjLength(object, sld));
    01004     if (_sl.need_length == NL_CALCLENGTH) return;
    01005   }
    01006
    01007   for (; sld->cmd != SL_END; sld++) {
    01008     void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
    01009     SlObjectMember(ptr, sld);
    01010   }
    01011 }
    01012
    01017 void SlGlobList(const SaveLoadGlobVarList *sldg)
    01018 {
    01019   SlObject(NULL, (const SaveLoad*)sldg);
    01020 }
    01021
    01027 void SlAutolength(AutolengthProc *proc, void *arg)
    01028 {
    01029   size_t offs;
    01030
    01031   assert(_sl.action == SLA_SAVE);
    01032
    01033   /* Tell it to calculate the length */
    01034   _sl.need_length = NL_CALCLENGTH;
    01035   _sl.obj_len = 0;
    01036   proc(arg);
    01037
    01038   /* Setup length */
    01039   _sl.need_length = NL_WANTLENGTH;
    01040   SlSetLength(_sl.obj_len);
    01041
    01042   offs = SlGetOffs() + _sl.obj_len;
    01043
    01044   /* And write the stuff */
    01045   proc(arg);
    01046
    01047   if (offs != SlGetOffs()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
    01048 }
    01049
    01054 static void SlLoadChunk(const ChunkHandler *ch)
    01055 {
    01056   byte m = SlReadByte();
    01057   size_t len;
    01058   size_t endoffs;
    01059
    01060   _sl.block_mode = m;
    01061   _sl.obj_len = 0;
    01062
    01063   switch (m) {
    01064     case CH_ARRAY:
    01065       _sl.array_index = 0;
    01066       ch->load_proc();
    01067       break;
    01068     case CH_SPARSE_ARRAY:
    01069       ch->load_proc();
    01070       break;
    01071     default:
    01072       if ((m & 0xF) == CH_RIFF) {
    01073         /* Read length */
    01074         len = (SlReadByte() << 16) | ((m >> 4) << 24);
    01075         len += SlReadUint16();
    01076         _sl.obj_len = len;
    01077         endoffs = SlGetOffs() + len;
    01078         ch->load_proc();
    01079         if (SlGetOffs() != endoffs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
    01080       } else {
    01081         SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk type");
    01082       }
    01083       break;
    01084   }
    01085 }
    01086
    01087 /* Stub Chunk handlers to only calculate length and do nothing else */
    01088 static ChunkSaveLoadProc *_tmp_proc_1;
    01089 static inline void SlStubSaveProc2(void *arg) {_tmp_proc_1();}
    01090 static void SlStubSaveProc() {SlAutolength(SlStubSaveProc2, NULL);}
    01091
    01096 static void SlSaveChunk(const ChunkHandler *ch)
    01097 {
    01098   ChunkSaveLoadProc *proc = ch->save_proc;
    01099
    01100   /* Don't save any chunk information if there is no save handler. */
    01101   if (proc == NULL) return;
    01102
    01103   SlWriteUint32(ch->id);
    01104   DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
    01105
    01106   if (ch->flags & CH_AUTO_LENGTH) {
    01107     /* Need to calculate the length. Solve that by calling SlAutoLength in the save_proc. */
    01108     _tmp_proc_1 = proc;
    01109     proc = SlStubSaveProc;
    01110   }
    01111
    01112   _sl.block_mode = ch->flags & CH_TYPE_MASK;
    01113   switch (ch->flags & CH_TYPE_MASK) {
    01114     case CH_RIFF:
    01115       _sl.need_length = NL_WANTLENGTH;
    01116       proc();
    01117       break;
    01118     case CH_ARRAY:
    01119       _sl.last_array_index = 0;
    01120       SlWriteByte(CH_ARRAY);
    01121       proc();
    01122       SlWriteArrayLength(0); // Terminate arrays
    01123       break;
    01124     case CH_SPARSE_ARRAY:
    01125       SlWriteByte(CH_SPARSE_ARRAY);
    01126       proc();
    01127       SlWriteArrayLength(0); // Terminate arrays
    01128       break;
    01129     default: NOT_REACHED();
    01130   }
    01131 }
    01132
    01134 static void SlSaveChunks()
    01135 {
    01136   const ChunkHandler *ch;
    01137   const ChunkHandler * const *chsc;
    01138   uint p;
    01139
    01140   for (p = 0; p != CH_NUM_PRI_LEVELS; p++) {
    01141     for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
    01142       while (true) {
    01143         if (((ch->flags >> CH_PRI_SHL) & (CH_NUM_PRI_LEVELS - 1)) == p)
    01144           SlSaveChunk(ch);
    01145         if (ch->flags & CH_LAST)
    01146           break;
    01147         ch++;
    01148       }
    01149     }
    01150   }
    01151
    01152   /* Terminator */
    01153   SlWriteUint32(0);
    01154 }
    01155
    01161 static const ChunkHandler *SlFindChunkHandler(uint32 id)
    01162 {
    01163   const ChunkHandler *ch;
    01164   const ChunkHandler *const *chsc;
    01165   for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
    01166     for (;;) {
    01167       if (ch->id == id) return ch;
    01168       if (ch->flags & CH_LAST) break;
    01169       ch++;
    01170     }
    01171   }
    01172   return NULL;
    01173 }
    01174
    01176 static void SlLoadChunks()
    01177 {
    01178   uint32 id;
    01179   const ChunkHandler *ch;
    01180
    01181   for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
    01182     DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
    01183
    01184     ch = SlFindChunkHandler(id);
    01185     if (ch == NULL) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unknown chunk type");
    01186     SlLoadChunk(ch);
    01187   }
    01188 }
    01189
    01191 static void SlFixPointers()
    01192 {
    01193   const ChunkHandler *ch;
    01194   const ChunkHandler * const *chsc;
    01195
    01196   _sl.action = SLA_PTRS;
    01197
    01198   DEBUG(sl, 1, "Fixing pointers");
    01199
    01200   for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
    01201     while (true) {
    01202       if (ch->ptrs_proc != NULL) {
    01203         DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
    01204         ch->ptrs_proc();
    01205       }
    01206       if (ch->flags & CH_LAST)
    01207         break;
    01208       ch++;
    01209     }
    01210   }
    01211
    01212   DEBUG(sl, 1, "All pointers fixed");
    01213
    01214   assert(_sl.action == SLA_PTRS);
    01215 }
    01216
    01217 /*******************************************
    01218  ********** START OF LZO CODE **************
    01219  *******************************************/
    01220 #define LZO_SIZE 8192
    01221
    01222 #include "../3rdparty/minilzo/minilzo.h"
    01223
    01224 static size_t ReadLZO()
    01225 {
    01226   byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
    01227   uint32 tmp[2];
    01228   uint32 size;
    01229   lzo_uint len;
    01230
    01231   /* Read header*/
    01232   if (fread(tmp, sizeof(tmp), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
    01233
    01234   /* Check if size is bad */
    01235   ((uint32*)out)[0] = size = tmp[1];
    01236
    01237   if (_sl_version != 0) {
    01238     tmp[0] = TO_BE32(tmp[0]);
    01239     size = TO_BE32(size);
    01240   }
    01241
    01242   if (size >= sizeof(out)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Inconsistent size");
    01243
    01244   /* Read block */
    01245   if (fread(out + sizeof(uint32), size, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
    01246
    01247   /* Verify checksum */
    01248   if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Bad checksum");
    01249
    01250   /* Decompress */
    01251   lzo1x_decompress(out + sizeof(uint32) * 1, size, _sl.buf, &len, NULL);
    01252   return len;
    01253 }
    01254
    01255 /* p contains the pointer to the buffer, len contains the pointer to the length.
    01256  * len bytes will be written, p and l will be updated to reflect the next buffer. */
    01257 static void WriteLZO(size_t size)
    01258 {
    01259   byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
    01260   byte wrkmem[sizeof(byte*) * 4096];
    01261   lzo_uint outlen;
    01262
    01263   lzo1x_1_compress(_sl.buf, (lzo_uint)size, out + sizeof(uint32) * 2, &outlen, wrkmem);
    01264   ((uint32*)out)[1] = TO_BE32((uint32)outlen);
    01265   ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
    01266   if (fwrite(out, outlen + sizeof(uint32) * 2, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
    01267 }
    01268
    01269 static bool InitLZO()
    01270 {
    01271   _sl.bufsize = LZO_SIZE;
    01272   _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
    01273   return true;
    01274 }
    01275
    01276 static void UninitLZO()
    01277 {
    01278   free(_sl.buf_ori);
    01279 }
    01280
    01281 /*********************************************
    01282  ******** START OF NOCOMP CODE (uncompressed)*
    01283  *********************************************/
    01284 static size_t ReadNoComp()
    01285 {
    01286   return fread(_sl.buf, 1, LZO_SIZE, _sl.fh);
    01287 }
    01288
    01289 static void WriteNoComp(size_t size)
    01290 {
    01291   if (fwrite(_sl.buf, 1, size, _sl.fh) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
    01292 }
    01293
    01294 static bool InitNoComp()
    01295 {
    01296   _sl.bufsize = LZO_SIZE;
    01297   _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
    01298   return true;
    01299 }
    01300
    01301 static void UninitNoComp()
    01302 {
    01303   free(_sl.buf_ori);
    01304 }
    01305
    01306 /********************************************
    01307  ********** START OF MEMORY CODE (in ram)****
    01308  ********************************************/
    01309
    01310 #include "../gui.h"
    01311
    01312 struct ThreadedSave {
    01313   uint count;
    01314   byte ff_state;
    01315   bool saveinprogress;
    01316   CursorID cursor;
    01317 };
    01318
    01320 static const int MEMORY_CHUNK_SIZE = 128 * 1024;
    01322 static AutoFreeSmallVector<byte *, 16> _memory_savegame;
    01323
    01324 static ThreadedSave _ts;
    01325
    01326 static void WriteMem(size_t size)
    01327 {
    01328   _ts.count += (uint)size;
    01329
    01330   _sl.buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
    01331   *_memory_savegame.Append() = _sl.buf;
    01332 }
    01333
    01334 static void UnInitMem()
    01335 {
    01336   _memory_savegame.Clear();
    01337 }
    01338
    01339 static bool InitMem()
    01340 {
    01341   _ts.count = 0;
    01342   _sl.bufsize = MEMORY_CHUNK_SIZE;
    01343
    01344   UnInitMem();
    01345   WriteMem(0);
    01346   return true;
    01347 }
    01348
    01349 /********************************************
    01350  ********** START OF ZLIB CODE **************
    01351  ********************************************/
    01352
    01353 #if defined(WITH_ZLIB)
    01354 #include <zlib.h>
    01355
    01356 static z_stream _z;
    01357
    01358 static bool InitReadZlib()
    01359 {
    01360   memset(&_z, 0, sizeof(_z));
    01361   if (inflateInit(&_z) != Z_OK) return false;
    01362
    01363   _sl.bufsize = 4096;
    01364   _sl.buf = _sl.buf_ori = MallocT<byte>(4096 + 4096); // also contains fread buffer
    01365   return true;
    01366 }
    01367
    01368 static size_t ReadZlib()
    01369 {
    01370   int r;
    01371
    01372   _z.next_out = _sl.buf;
    01373   _z.avail_out = 4096;
    01374
    01375   do {
    01376     /* read more bytes from the file? */
    01377     if (_z.avail_in == 0) {
    01378       _z.avail_in = (uint)fread(_z.next_in = _sl.buf + 4096, 1, 4096, _sl.fh);
    01379     }
    01380
    01381     /* inflate the data */
    01382     r = inflate(&_z, 0);
    01383     if (r == Z_STREAM_END)
    01384       break;
    01385
    01386     if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
    01387   } while (_z.avail_out);
    01388
    01389   return 4096 - _z.avail_out;
    01390 }
    01391
    01392 static void UninitReadZlib()
    01393 {
    01394   inflateEnd(&_z);
    01395   free(_sl.buf_ori);
    01396 }
    01397
    01398 static bool InitWriteZlib()
    01399 {
    01400   memset(&_z, 0, sizeof(_z));
    01401   if (deflateInit(&_z, 6) != Z_OK) return false;
    01402
    01403   _sl.bufsize = 4096;
    01404   _sl.buf = _sl.buf_ori = MallocT<byte>(4096);
    01405   return true;
    01406 }
    01407
    01408 static void WriteZlibLoop(z_streamp z, byte *p, size_t len, int mode)
    01409 {
    01410   byte buf[1024]; // output buffer
    01411   int r;
    01412   uint n;
    01413   z->next_in = p;
    01414   z->avail_in = (uInt)len;
    01415   do {
    01416     z->next_out = buf;
    01417     z->avail_out = sizeof(buf);
    01418
    01426     r = deflate(z, mode);
    01427
    01428     /* bytes were emitted? */
    01429     if ((n = sizeof(buf) - z->avail_out) != 0) {
    01430       if (fwrite(buf, n, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
    01431     }
    01432     if (r == Z_STREAM_END)
    01433       break;
    01434     if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
    01435   } while (z->avail_in || !z->avail_out);
    01436 }
    01437
    01438 static void WriteZlib(size_t len)
    01439 {
    01440   WriteZlibLoop(&_z, _sl.buf, len, 0);
    01441 }
    01442
    01443 static void UninitWriteZlib()
    01444 {
    01445   /* flush any pending output. */
    01446   if (_sl.fh) WriteZlibLoop(&_z, NULL, 0, Z_FINISH);
    01447   deflateEnd(&_z);
    01448   free(_sl.buf_ori);
    01449 }
    01450
    01451 #endif /* WITH_ZLIB */
    01452
    01453 /*******************************************
    01454  ************* END OF CODE *****************
    01455  *******************************************/
    01456
    01457 /* these define the chunks */
    01458 extern const ChunkHandler _gamelog_chunk_handlers[];
    01459 extern const ChunkHandler _map_chunk_handlers[];
    01460 extern const ChunkHandler _misc_chunk_handlers[];
    01461 extern const ChunkHandler _name_chunk_handlers[];
    01462 extern const ChunkHandler _cheat_chunk_handlers[] ;
    01463 extern const ChunkHandler _setting_chunk_handlers[];
    01464 extern const ChunkHandler _company_chunk_handlers[];
    01465 extern const ChunkHandler _engine_chunk_handlers[];
    01466 extern const ChunkHandler _veh_chunk_handlers[];
    01467 extern const ChunkHandler _waypoint_chunk_handlers[];
    01468 extern const ChunkHandler _depot_chunk_handlers[];
    01469 extern const ChunkHandler _order_chunk_handlers[];
    01470 extern const ChunkHandler _town_chunk_handlers[];
    01471 extern const ChunkHandler _sign_chunk_handlers[];
    01472 extern const ChunkHandler _station_chunk_handlers[];
    01473 extern const ChunkHandler _industry_chunk_handlers[];
    01474 extern const ChunkHandler _economy_chunk_handlers[];
    01475 extern const ChunkHandler _subsidy_chunk_handlers[];
    01476 extern const ChunkHandler _ai_chunk_handlers[];
    01477 extern const ChunkHandler _animated_tile_chunk_handlers[];
    01478 extern const ChunkHandler _newgrf_chunk_handlers[];
    01479 extern const ChunkHandler _group_chunk_handlers[];
    01480 extern const ChunkHandler _cargopacket_chunk_handlers[];
    01481 extern const ChunkHandler _autoreplace_chunk_handlers[];
    01482 extern const ChunkHandler _labelmaps_chunk_handlers[];
    01483
    01484 static const ChunkHandler * const _chunk_handlers[] = {
    01485   _gamelog_chunk_handlers,
    01486   _map_chunk_handlers,
    01487   _misc_chunk_handlers,
    01488   _name_chunk_handlers,
    01489   _cheat_chunk_handlers,
    01490   _setting_chunk_handlers,
    01491   _veh_chunk_handlers,
    01492   _waypoint_chunk_handlers,
    01493   _depot_chunk_handlers,
    01494   _order_chunk_handlers,
    01495   _industry_chunk_handlers,
    01496   _economy_chunk_handlers,
    01497   _subsidy_chunk_handlers,
    01498   _engine_chunk_handlers,
    01499   _town_chunk_handlers,
    01500   _sign_chunk_handlers,
    01501   _station_chunk_handlers,
    01502   _company_chunk_handlers,
    01503   _ai_chunk_handlers,
    01504   _animated_tile_chunk_handlers,
    01505   _newgrf_chunk_handlers,
    01506   _group_chunk_handlers,
    01507   _cargopacket_chunk_handlers,
    01508   _autoreplace_chunk_handlers,
    01509   _labelmaps_chunk_handlers,
    01510   NULL,
    01511 };
    01512
    01523 static size_t ReferenceToInt(const void *obj, SLRefType rt)
    01524 {
    01525   assert(_sl.action == SLA_SAVE);
    01526
    01527   if (obj == NULL) return 0;
    01528
    01529   switch (rt) {
    01530     case REF_VEHICLE_OLD: // Old vehicles we save as new onces
    01531     case REF_VEHICLE:   return ((const  Vehicle*)obj)->index + 1;
    01532     case REF_STATION:   return ((const  Station*)obj)->index + 1;
    01533     case REF_TOWN:      return ((const     Town*)obj)->index + 1;
    01534     case REF_ORDER:     return ((const    Order*)obj)->index + 1;
    01535     case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
    01536     case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
    01537     case REF_CARGO_PACKET:  return ((const CargoPacket*)obj)->index + 1;
    01538     case REF_ORDERLIST:     return ((const   OrderList*)obj)->index + 1;
    01539     default: NOT_REACHED();
    01540   }
    01541 }
    01542
    01553 static void *IntToReference(size_t index, SLRefType rt)
    01554 {
    01555   assert_compile(sizeof(size_t) <= sizeof(void *));
    01556
    01557   assert(_sl.action == SLA_PTRS);
    01558
    01559   /* After version 4.3 REF_VEHICLE_OLD is saved as REF_VEHICLE,
    01560    * and should be loaded like that */
    01561   if (rt == REF_VEHICLE_OLD && !CheckSavegameVersionOldStyle(4, 4)) {
    01562     rt = REF_VEHICLE;
    01563   }
    01564
    01565   /* No need to look up NULL pointers, just return immediately */
    01566   if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
    01567
    01568   /* Correct index. Old vehicles were saved differently:
    01569    * invalid vehicle was 0xFFFF, now we use 0x0000 for everything invalid. */
    01570   if (rt != REF_VEHICLE_OLD) index--;
    01571
    01572   switch (rt) {
    01573     case REF_ORDERLIST:
    01574       if (OrderList::IsValidID(index)) return OrderList::Get(index);
    01575       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid OrderList");
    01576
    01577     case REF_ORDER:
    01578       if (Order::IsValidID(index)) return Order::Get(index);
    01579       /* in old versions, invalid order was used to mark end of order list */
    01580       if (CheckSavegameVersionOldStyle(5, 2)) return NULL;
    01581       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Order");
    01582
    01583     case REF_VEHICLE_OLD:
    01584     case REF_VEHICLE:
    01585       if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
    01586       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Vehicle");
    01587
    01588     case REF_STATION:
    01589       if (Station::IsValidID(index)) return Station::Get(index);
    01590       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Station");
    01591
    01592     case REF_TOWN:
    01593       if (Town::IsValidID(index)) return Town::Get(index);
    01594       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Town");
    01595
    01596     case REF_ROADSTOPS:
    01597       if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
    01598       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid RoadStop");
    01599
    01600     case REF_ENGINE_RENEWS:
    01601       if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
    01602       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid EngineRenew");
    01603
    01604     case REF_CARGO_PACKET:
    01605       if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
    01606       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid CargoPacket");
    01607
    01608     default: NOT_REACHED();
    01609   }
    01610 }
    01611
    01613 struct SaveLoadFormat {
    01614   const char *name;
    01615   uint32 tag;
    01616
    01617   bool (*init_read)();
    01618   ReaderProc *reader;
    01619   void (*uninit_read)();
    01620
    01621   bool (*init_write)();
    01622   WriterProc *writer;
    01623   void (*uninit_write)();
    01624 };
    01625
    01626 static const SaveLoadFormat _saveload_formats[] = {
    01627   {"memory", 0,                NULL,         NULL,       NULL,           InitMem,       WriteMem,    UnInitMem},
    01628   {"lzo",    TO_BE32X('OTTD'), InitLZO,      ReadLZO,    UninitLZO,      InitLZO,       WriteLZO,    UninitLZO},
    01629   {"none",   TO_BE32X('OTTN'), InitNoComp,   ReadNoComp, UninitNoComp,   InitNoComp,    WriteNoComp, UninitNoComp},
    01630 #if defined(WITH_ZLIB)
    01631   {"zlib",   TO_BE32X('OTTZ'), InitReadZlib, ReadZlib,   UninitReadZlib, InitWriteZlib, WriteZlib,   UninitWriteZlib},
    01632 #else
    01633   {"zlib",   TO_BE32X('OTTZ'), NULL,         NULL,       NULL,           NULL,          NULL,        NULL},
    01634 #endif
    01635 };
    01636
    01643 static const SaveLoadFormat *GetSavegameFormat(const char *s)
    01644 {
    01645   const SaveLoadFormat *def = endof(_saveload_formats) - 1;
    01646
    01647   /* find default savegame format, the highest one with which files can be written */
    01648   while (!def->init_write) def--;
    01649
    01650   if (s != NULL && s[0] != '\0') {
    01651     const SaveLoadFormat *slf;
    01652     for (slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
    01653       if (slf->init_write != NULL && strcmp(s, slf->name) == 0)
    01654         return slf;
    01655     }
    01656
    01657     ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
    01658   }
    01659   return def;
    01660 }
    01661
    01662 /* actual loader/saver function */
    01663 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
    01664 extern bool AfterLoadGame();
    01665 extern bool LoadOldSaveGame(const char *file);
    01666
    01668 static inline SaveOrLoadResult AbortSaveLoad()
    01669 {
    01670   if (_sl.fh != NULL) fclose(_sl.fh);
    01671
    01672   _sl.fh = NULL;
    01673   return SL_ERROR;
    01674 }
    01675
    01679 static void SaveFileStart()
    01680 {
    01681   _ts.ff_state = _fast_forward;
    01682   _fast_forward = 0;
    01683   if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
    01684
    01685   InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
    01686   _ts.saveinprogress = true;
    01687 }
    01688
    01691 static void SaveFileDone()
    01692 {
    01693   if (_game_mode != GM_MENU) _fast_forward = _ts.ff_state;
    01694   if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
    01695
    01696   InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
    01697   _ts.saveinprogress = false;
    01698 }
    01699
    01701 void SetSaveLoadError(StringID str)
    01702 {
    01703   _sl.error_str = str;
    01704 }
    01705
    01707 const char *GetSaveLoadErrorString()
    01708 {
    01709   SetDParam(0, _sl.error_str);
    01710   SetDParamStr(1, _sl.extra_msg);
    01711
    01712   static char err_str[512];
    01713   GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
    01714   return err_str;
    01715 }
    01716
    01718 static void SaveFileError()
    01719 {
    01720   SetDParamStr(0, GetSaveLoadErrorString());
    01721   ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, 0, 0);
    01722   SaveFileDone();
    01723 }
    01724
    01728 static SaveOrLoadResult SaveFileToDisk(bool threaded)
    01729 {
    01730   const SaveLoadFormat *fmt;
    01731   uint32 hdr[2];
    01732
    01733   _sl.excpt_uninit = NULL;
    01734   try {
    01735     fmt = GetSavegameFormat(_savegame_format);
    01736
    01737     /* We have written our stuff to memory, now write it to file! */
    01738     hdr[0] = fmt->tag;
    01739     hdr[1] = TO_BE32(SAVEGAME_VERSION << 16);
    01740     if (fwrite(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
    01741
    01742     if (!fmt->init_write()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
    01743
    01744     {
    01745       uint i;
    01746
    01747       if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
    01748       for (i = 0; i != _memory_savegame.Length() - 1; i++) {
    01749         _sl.buf = _memory_savegame[i];
    01750         fmt->writer(MEMORY_CHUNK_SIZE);
    01751       }
    01752
    01753       /* The last block is (almost) always not fully filled, so only write away
    01754        * as much data as it is in there */
    01755       _sl.buf = _memory_savegame[i];
    01756       fmt->writer(_ts.count % MEMORY_CHUNK_SIZE);
    01757     }
    01758
    01759     fmt->uninit_write();
    01760     if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
    01761     GetSavegameFormat("memory")->uninit_write(); // clean the memorypool
    01762     fclose(_sl.fh);
    01763
    01764     if (threaded) SetAsyncSaveFinish(SaveFileDone);
    01765
    01766     return SL_OK;
    01767   }
    01768   catch (...) {
    01769     AbortSaveLoad();
    01770     if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
    01771
    01772     /* Skip the "colour" character */
    01773     DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
    01774
    01775     if (threaded) {
    01776       SetAsyncSaveFinish(SaveFileError);
    01777     } else {
    01778       SaveFileError();
    01779     }
    01780     return SL_ERROR;
    01781   }
    01782 }
    01783
    01784 static void SaveFileToDiskThread(void *arg)
    01785 {
    01786   SaveFileToDisk(true);
    01787 }
    01788
    01789 void WaitTillSaved()
    01790 {
    01791   if (_save_thread == NULL) return;
    01792
    01793   _save_thread->Join();
    01794   delete _save_thread;
    01795   _save_thread = NULL;
    01796 }
    01797
    01807 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
    01808 {
    01809   uint32 hdr[2];
    01810   const SaveLoadFormat *fmt;
    01811
    01812   /* An instance of saving is already active, so don't go saving again */
    01813   if (_ts.saveinprogress && mode == SL_SAVE) {
    01814     /* if not an autosave, but a user action, show error message */
    01815     if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, 0, 0);
    01816     return SL_OK;
    01817   }
    01818   WaitTillSaved();
    01819
    01820   _next_offs = 0;
    01821
    01822   /* Load a TTDLX or TTDPatch game */
    01823   if (mode == SL_OLD_LOAD) {
    01824     _engine_mngr.ResetToDefaultMapping();
    01825     InitializeGame(256, 256, true, true); // set a mapsize of 256x256 for TTDPatch games or it might get confused
    01826     GamelogReset();
    01827     if (!LoadOldSaveGame(filename)) return SL_REINIT;
    01828     _sl_version = 0;
    01829     _sl_minor_version = 0;
    01830     GamelogStartAction(GLAT_LOAD);
    01831     if (!AfterLoadGame()) {
    01832       GamelogStopAction();
    01833       return SL_REINIT;
    01834     }
    01835     GamelogStopAction();
    01836     return SL_OK;
    01837   }
    01838
    01839   _sl.excpt_uninit = NULL;
    01840   try {
    01841     _sl.fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
    01842
    01843     /* Make it a little easier to load savegames from the console */
    01844     if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", SAVE_DIR);
    01845     if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", BASE_DIR);
    01846
    01847     if (_sl.fh == NULL) {
    01848       SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
    01849     }
    01850
    01851     _sl.bufe = _sl.bufp = NULL;
    01852     _sl.offs_base = 0;
    01853     _sl.action = (mode != 0) ? SLA_SAVE : SLA_LOAD;
    01854     _sl.chs = _chunk_handlers;
    01855
    01856     /* General tactic is to first save the game to memory, then use an available writer
    01857      * to write it to file, either in threaded mode if possible, or single-threaded */
    01858     if (mode == SL_SAVE) { // SAVE game
    01859       DEBUG(desync, 1, "save: %s\n", filename);
    01860       fmt = GetSavegameFormat("memory"); // write to memory
    01861
    01862       _sl.write_bytes = fmt->writer;
    01863       _sl.excpt_uninit = fmt->uninit_write;
    01864       if (!fmt->init_write()) {
    01865         DEBUG(sl, 0, "Initializing writer '%s' failed.", fmt->name);
    01866         return AbortSaveLoad();
    01867       }
    01868
    01869       _sl_version = SAVEGAME_VERSION;
    01870
    01871       SaveViewportBeforeSaveGame();
    01872       SlSaveChunks();
    01873       SlWriteFill(); // flush the save buffer
    01874
    01875       SaveFileStart();
    01876       if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
    01877       if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
    01878         if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
    01879
    01880         SaveOrLoadResult result = SaveFileToDisk(false);
    01881         SaveFileDone();
    01882
    01883         return result;
    01884       }
    01885     } else { // LOAD game
    01886       assert(mode == SL_LOAD);
    01887       DEBUG(desync, 1, "load: %s\n", filename);
    01888
    01889       /* Can't fseek to 0 as in tar files that is not correct */
    01890       long pos = ftell(_sl.fh);
    01891       if (fread(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
    01892
    01893       /* see if we have any loader for this type. */
    01894       for (fmt = _saveload_formats; ; fmt++) {
    01895         /* No loader found, treat as version 0 and use LZO format */
    01896         if (fmt == endof(_saveload_formats)) {
    01897           DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
    01898           clearerr(_sl.fh);
    01899           fseek(_sl.fh, pos, SEEK_SET);
    01900           _sl_version = 0;
    01901           _sl_minor_version = 0;
    01902           fmt = _saveload_formats + 1; // LZO
    01903           break;
    01904         }
    01905
    01906         if (fmt->tag == hdr[0]) {
    01907           /* check version number */
    01908           _sl_version = TO_BE32(hdr[1]) >> 16;
    01909           /* Minor is not used anymore from version 18.0, but it is still needed
    01910            * in versions before that (4 cases) which can't be removed easy.
    01911            * Therefor it is loaded, but never saved (or, it saves a 0 in any scenario).
    01912            * So never EVER use this minor version again. -- TrueLight -- 22-11-2005 */
    01913           _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
    01914
    01915           DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
    01916
    01917           /* Is the version higher than the current? */
    01918           if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
    01919           break;
    01920         }
    01921       }
    01922
    01923       _sl.read_bytes = fmt->reader;
    01924       _sl.excpt_uninit = fmt->uninit_read;
    01925
    01926       /* loader for this savegame type is not implemented? */
    01927       if (fmt->init_read == NULL) {
    01928         char err_str[64];
    01929         snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
    01930         SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
    01931       }
    01932
    01933       if (!fmt->init_read()) {
    01934         char err_str[64];
    01935         snprintf(err_str, lengthof(err_str), "Initializing loader '%s' failed", fmt->name);
    01936         SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
    01937       }
    01938
    01939       _engine_mngr.ResetToDefaultMapping();
    01940
    01941       /* Old maps were hardcoded to 256x256 and thus did not contain
    01942        * any mapsize information. Pre-initialize to 256x256 to not to
    01943        * confuse old games */
    01944       InitializeGame(256, 256, true, true);
    01945
    01946       GamelogReset();
    01947
    01948       SlLoadChunks();
    01949       SlFixPointers();
    01950       fmt->uninit_read();
    01951       fclose(_sl.fh);
    01952
    01953       GamelogStartAction(GLAT_LOAD);
    01954
    01955       _savegame_type = SGT_OTTD;
    01956
    01957       /* After loading fix up savegame for any internal changes that
    01958        * might've occured since then. If it fails, load back the old game */
    01959       if (!AfterLoadGame()) {
    01960         GamelogStopAction();
    01961         return SL_REINIT;
    01962       }
    01963
    01964       GamelogStopAction();
    01965     }
    01966
    01967     return SL_OK;
    01968   }
    01969   catch (...) {
    01970     AbortSaveLoad();
    01971
    01972     /* deinitialize compressor. */
    01973     if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
    01974
    01975     /* Skip the "colour" character */
    01976     DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
    01977
    01978     /* A saver/loader exception!! reinitialize all variables to prevent crash! */
    01979     return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
    01980   }
    01981 }
    01982
    01984 void DoExitSave()
    01985 {
    01986   SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
    01987 }
    01988
    01994 void GenerateDefaultSaveName(char *buf, const char *last)
    01995 {
    01996   /* Check if we have a name for this map, which is the name of the first
    01997    * available company. When there's no company available we'll use
    01998    * 'Spectator' as "company" name. */
    01999   CompanyID cid = _local_company;
    02000   if (!Company::IsValidID(cid)) {
    02001     const Company *c;
    02002     FOR_ALL_COMPANIES(c) {
    02003       cid = c->index;
    02004       break;
    02005     }
    02006   }
    02007
    02008   SetDParam(0, cid);
    02009
    02010   /* Insert current date */
    02011   switch (_settings_client.gui.date_format_in_default_names) {
    02012     case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
    02013     case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
    02014     case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
    02015     default: NOT_REACHED();
    02016   }
    02017   SetDParam(2, _date);
    02018
    02019   /* Get the correct string (special string for when there's not company) */
    02020   GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
    02021   SanitizeFilename(buf);
    02022 }
    02023
    02024 #if 0
    02025
    02031 int GetSavegameType(char *file)
    02032 {
    02033   const SaveLoadFormat *fmt;
    02034   uint32 hdr;
    02035   FILE *f;
    02036   int mode = SL_OLD_LOAD;
    02037
    02038   f = fopen(file, "rb");
    02039   if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
    02040     DEBUG(sl, 0, "Savegame is obsolete or invalid format");
    02041     mode = SL_LOAD; // don't try to get filename, just show name as it is written
    02042   } else {
    02043     /* see if we have any loader for this type. */
    02044     for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
    02045       if (fmt->tag == hdr) {
    02046         mode = SL_LOAD; // new type of savegame
    02047         break;
    02048       }
    02049     }
    02050   }
    02051
    02052   fclose(f);
    02053   return mode;
    02054 }
    02055 #endif