# saveload.cpp

Go to the documentation of this file.

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