saveload.cpp

Go to the documentation of this file.
00001 /* $Id: saveload.cpp 21047 2010-10-27 20:15:18Z rubidium $ */
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   if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00203   throw std::exception();
00204 }
00205 
00213 void NORETURN SlErrorCorrupt(const char *msg)
00214 {
00215   SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00216 }
00217 
00218 typedef void (*AsyncSaveFinishProc)();
00219 static AsyncSaveFinishProc _async_save_finish = NULL;
00220 static ThreadObject *_save_thread;
00221 
00225 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00226 {
00227   if (_exit_game) return;
00228   while (_async_save_finish != NULL) CSleep(10);
00229 
00230   _async_save_finish = proc;
00231 }
00232 
00236 void ProcessAsyncSaveFinish()
00237 {
00238   if (_async_save_finish == NULL) return;
00239 
00240   _async_save_finish();
00241 
00242   _async_save_finish = NULL;
00243 
00244   if (_save_thread != NULL) {
00245     _save_thread->Join();
00246     delete _save_thread;
00247     _save_thread = NULL;
00248   }
00249 }
00250 
00254 static void SlReadFill()
00255 {
00256   size_t len = _sl.read_bytes();
00257   if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00258 
00259   _sl.bufp = _sl.buf;
00260   _sl.bufe = _sl.buf + len;
00261   _sl.offs_base += len;
00262 }
00263 
00264 static inline size_t SlGetOffs() {return _sl.offs_base - (_sl.bufe - _sl.bufp);}
00265 static inline uint SlReadArrayLength();
00266 
00271 static inline uint SlCalcConvMemLen(VarType conv)
00272 {
00273   static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00274   byte length = GB(conv, 4, 4);
00275 
00276   switch (length << 4) {
00277     case SLE_VAR_STRB:
00278     case SLE_VAR_STRBQ:
00279     case SLE_VAR_STR:
00280     case SLE_VAR_STRQ:
00281       return SlReadArrayLength();
00282 
00283     default:
00284       assert(length < lengthof(conv_mem_size));
00285       return conv_mem_size[length];
00286   }
00287 }
00288 
00293 static inline byte SlCalcConvFileLen(VarType conv)
00294 {
00295   static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00296   byte length = GB(conv, 0, 4);
00297   assert(length < lengthof(conv_file_size));
00298   return conv_file_size[length];
00299 }
00300 
00302 static inline size_t SlCalcRefLen() {return CheckSavegameVersion(69) ? 2 : 4;}
00303 
00308 static void SlWriteFill()
00309 {
00310   /* flush the buffer to disk (the writer) */
00311   if (_sl.bufp != NULL) {
00312     uint len = _sl.bufp - _sl.buf;
00313     _sl.offs_base += len;
00314     if (len) _sl.write_bytes(len);
00315   }
00316 
00317   /* All the data from the buffer has been written away, rewind to the beginning
00318    * to start reading in more data */
00319   _sl.bufp = _sl.buf;
00320   _sl.bufe = _sl.buf + _sl.bufsize;
00321 }
00322 
00327 static inline byte SlReadByteInternal()
00328 {
00329   if (_sl.bufp == _sl.bufe) SlReadFill();
00330   return *_sl.bufp++;
00331 }
00332 
00334 byte SlReadByte() {return SlReadByteInternal();}
00335 
00340 static inline void SlWriteByteInternal(byte b)
00341 {
00342   if (_sl.bufp == _sl.bufe) SlWriteFill();
00343   *_sl.bufp++ = b;
00344 }
00345 
00347 void SlWriteByte(byte b) {SlWriteByteInternal(b);}
00348 
00349 static inline int SlReadUint16()
00350 {
00351   int x = SlReadByte() << 8;
00352   return x | SlReadByte();
00353 }
00354 
00355 static inline uint32 SlReadUint32()
00356 {
00357   uint32 x = SlReadUint16() << 16;
00358   return x | SlReadUint16();
00359 }
00360 
00361 static inline uint64 SlReadUint64()
00362 {
00363   uint32 x = SlReadUint32();
00364   uint32 y = SlReadUint32();
00365   return (uint64)x << 32 | y;
00366 }
00367 
00368 static inline void SlWriteUint16(uint16 v)
00369 {
00370   SlWriteByte(GB(v, 8, 8));
00371   SlWriteByte(GB(v, 0, 8));
00372 }
00373 
00374 static inline void SlWriteUint32(uint32 v)
00375 {
00376   SlWriteUint16(GB(v, 16, 16));
00377   SlWriteUint16(GB(v,  0, 16));
00378 }
00379 
00380 static inline void SlWriteUint64(uint64 x)
00381 {
00382   SlWriteUint32((uint32)(x >> 32));
00383   SlWriteUint32((uint32)x);
00384 }
00385 
00395 static uint SlReadSimpleGamma()
00396 {
00397   uint i = SlReadByte();
00398   if (HasBit(i, 7)) {
00399     i &= ~0x80;
00400     if (HasBit(i, 6)) {
00401       i &= ~0x40;
00402       if (HasBit(i, 5)) {
00403         i &= ~0x20;
00404         if (HasBit(i, 4))
00405           SlErrorCorrupt("Unsupported gamma");
00406         i = (i << 8) | SlReadByte();
00407       }
00408       i = (i << 8) | SlReadByte();
00409     }
00410     i = (i << 8) | SlReadByte();
00411   }
00412   return i;
00413 }
00414 
00427 static void SlWriteSimpleGamma(size_t i)
00428 {
00429   if (i >= (1 << 7)) {
00430     if (i >= (1 << 14)) {
00431       if (i >= (1 << 21)) {
00432         assert(i < (1 << 28));
00433         SlWriteByte((byte)(0xE0 | (i >> 24)));
00434         SlWriteByte((byte)(i >> 16));
00435       } else {
00436         SlWriteByte((byte)(0xC0 | (i >> 16)));
00437       }
00438       SlWriteByte((byte)(i >> 8));
00439     } else {
00440       SlWriteByte((byte)(0x80 | (i >> 8)));
00441     }
00442   }
00443   SlWriteByte((byte)i);
00444 }
00445 
00447 static inline uint SlGetGammaLength(size_t i)
00448 {
00449   return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00450 }
00451 
00452 static inline uint SlReadSparseIndex() {return SlReadSimpleGamma();}
00453 static inline void SlWriteSparseIndex(uint index) {SlWriteSimpleGamma(index);}
00454 
00455 static inline uint SlReadArrayLength() {return SlReadSimpleGamma();}
00456 static inline void SlWriteArrayLength(size_t length) {SlWriteSimpleGamma(length);}
00457 static inline uint SlGetArrayLength(size_t length) {return SlGetGammaLength(length);}
00458 
00459 void SlSetArrayIndex(uint index)
00460 {
00461   _sl.need_length = NL_WANTLENGTH;
00462   _sl.array_index = index;
00463 }
00464 
00465 static size_t _next_offs;
00466 
00471 int SlIterateArray()
00472 {
00473   int index;
00474 
00475   /* After reading in the whole array inside the loop
00476    * we must have read in all the data, so we must be at end of current block. */
00477   if (_next_offs != 0 && SlGetOffs() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00478 
00479   while (true) {
00480     uint length = SlReadArrayLength();
00481     if (length == 0) {
00482       _next_offs = 0;
00483       return -1;
00484     }
00485 
00486     _sl.obj_len = --length;
00487     _next_offs = SlGetOffs() + length;
00488 
00489     switch (_sl.block_mode) {
00490       case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00491       case CH_ARRAY:        index = _sl.array_index++; break;
00492       default:
00493         DEBUG(sl, 0, "SlIterateArray error");
00494         return -1; // error
00495     }
00496 
00497     if (length != 0) return index;
00498   }
00499 }
00500 
00506 void SlSetLength(size_t length)
00507 {
00508   assert(_sl.action == SLA_SAVE);
00509 
00510   switch (_sl.need_length) {
00511     case NL_WANTLENGTH:
00512       _sl.need_length = NL_NONE;
00513       switch (_sl.block_mode) {
00514         case CH_RIFF:
00515           /* Ugly encoding of >16M RIFF chunks
00516            * The lower 24 bits are normal
00517            * The uppermost 4 bits are bits 24:27 */
00518           assert(length < (1 << 28));
00519           SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00520           break;
00521         case CH_ARRAY:
00522           assert(_sl.last_array_index <= _sl.array_index);
00523           while (++_sl.last_array_index <= _sl.array_index)
00524             SlWriteArrayLength(1);
00525           SlWriteArrayLength(length + 1);
00526           break;
00527         case CH_SPARSE_ARRAY:
00528           SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index)); // Also include length of sparse index.
00529           SlWriteSparseIndex(_sl.array_index);
00530           break;
00531         default: NOT_REACHED();
00532       }
00533       break;
00534 
00535     case NL_CALCLENGTH:
00536       _sl.obj_len += (int)length;
00537       break;
00538 
00539     default: NOT_REACHED();
00540   }
00541 }
00542 
00549 static void SlCopyBytes(void *ptr, size_t length)
00550 {
00551   byte *p = (byte *)ptr;
00552 
00553   switch (_sl.action) {
00554     case SLA_LOAD:
00555       for (; length != 0; length--) { *p++ = SlReadByteInternal(); }
00556       break;
00557     case SLA_SAVE:
00558       for (; length != 0; length--) { SlWriteByteInternal(*p++); }
00559       break;
00560     default: NOT_REACHED();
00561   }
00562 }
00563 
00568 static inline void SlSkipBytes(size_t length)
00569 {
00570   for (; length != 0; length--) SlReadByte();
00571 }
00572 
00573 /* Get the length of the current object */
00574 size_t SlGetFieldLength() {return _sl.obj_len;}
00575 
00581 int64 ReadValue(const void *ptr, VarType conv)
00582 {
00583   switch (GetVarMemType(conv)) {
00584     case SLE_VAR_BL:  return (*(bool *)ptr != 0);
00585     case SLE_VAR_I8:  return *(int8  *)ptr;
00586     case SLE_VAR_U8:  return *(byte  *)ptr;
00587     case SLE_VAR_I16: return *(int16 *)ptr;
00588     case SLE_VAR_U16: return *(uint16*)ptr;
00589     case SLE_VAR_I32: return *(int32 *)ptr;
00590     case SLE_VAR_U32: return *(uint32*)ptr;
00591     case SLE_VAR_I64: return *(int64 *)ptr;
00592     case SLE_VAR_U64: return *(uint64*)ptr;
00593     case SLE_VAR_NULL:return 0;
00594     default: NOT_REACHED();
00595   }
00596 }
00597 
00603 void WriteValue(void *ptr, VarType conv, int64 val)
00604 {
00605   switch (GetVarMemType(conv)) {
00606     case SLE_VAR_BL:  *(bool  *)ptr = (val != 0);  break;
00607     case SLE_VAR_I8:  *(int8  *)ptr = val; break;
00608     case SLE_VAR_U8:  *(byte  *)ptr = val; break;
00609     case SLE_VAR_I16: *(int16 *)ptr = val; break;
00610     case SLE_VAR_U16: *(uint16*)ptr = val; break;
00611     case SLE_VAR_I32: *(int32 *)ptr = val; break;
00612     case SLE_VAR_U32: *(uint32*)ptr = val; break;
00613     case SLE_VAR_I64: *(int64 *)ptr = val; break;
00614     case SLE_VAR_U64: *(uint64*)ptr = val; break;
00615     case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00616     case SLE_VAR_NULL: break;
00617     default: NOT_REACHED();
00618   }
00619 }
00620 
00629 static void SlSaveLoadConv(void *ptr, VarType conv)
00630 {
00631   switch (_sl.action) {
00632     case SLA_SAVE: {
00633       int64 x = ReadValue(ptr, conv);
00634 
00635       /* Write the value to the file and check if its value is in the desired range */
00636       switch (GetVarFileType(conv)) {
00637         case SLE_FILE_I8: assert(x >= -128 && x <= 127);     SlWriteByte(x);break;
00638         case SLE_FILE_U8: assert(x >= 0 && x <= 255);        SlWriteByte(x);break;
00639         case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00640         case SLE_FILE_STRINGID:
00641         case SLE_FILE_U16:assert(x >= 0 && x <= 65535);      SlWriteUint16(x);break;
00642         case SLE_FILE_I32:
00643         case SLE_FILE_U32:                                   SlWriteUint32((uint32)x);break;
00644         case SLE_FILE_I64:
00645         case SLE_FILE_U64:                                   SlWriteUint64(x);break;
00646         default: NOT_REACHED();
00647       }
00648       break;
00649     }
00650     case SLA_LOAD: {
00651       int64 x;
00652       /* Read a value from the file */
00653       switch (GetVarFileType(conv)) {
00654         case SLE_FILE_I8:  x = (int8  )SlReadByte();   break;
00655         case SLE_FILE_U8:  x = (byte  )SlReadByte();   break;
00656         case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00657         case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00658         case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00659         case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00660         case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00661         case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00662         case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00663         default: NOT_REACHED();
00664       }
00665 
00666       /* Write The value to the struct. These ARE endian safe. */
00667       WriteValue(ptr, conv, x);
00668       break;
00669     }
00670     case SLA_PTRS: break;
00671     case SLA_NULL: break;
00672     default: NOT_REACHED();
00673   }
00674 }
00675 
00683 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
00684 {
00685   if (ptr == NULL) return 0;
00686   return min(strlen(ptr), length - 1);
00687 }
00688 
00696 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
00697 {
00698   size_t len;
00699   const char *str;
00700 
00701   switch (GetVarMemType(conv)) {
00702     default: NOT_REACHED();
00703     case SLE_VAR_STR:
00704     case SLE_VAR_STRQ:
00705       str = *(const char**)ptr;
00706       len = SIZE_MAX;
00707       break;
00708     case SLE_VAR_STRB:
00709     case SLE_VAR_STRBQ:
00710       str = (const char*)ptr;
00711       len = length;
00712       break;
00713   }
00714 
00715   len = SlCalcNetStringLen(str, len);
00716   return len + SlGetArrayLength(len); // also include the length of the index
00717 }
00718 
00724 static void SlString(void *ptr, size_t length, VarType conv)
00725 {
00726   switch (_sl.action) {
00727     case SLA_SAVE: {
00728       size_t len;
00729       switch (GetVarMemType(conv)) {
00730         default: NOT_REACHED();
00731         case SLE_VAR_STRB:
00732         case SLE_VAR_STRBQ:
00733           len = SlCalcNetStringLen((char *)ptr, length);
00734           break;
00735         case SLE_VAR_STR:
00736         case SLE_VAR_STRQ:
00737           ptr = *(char **)ptr;
00738           len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
00739           break;
00740       }
00741 
00742       SlWriteArrayLength(len);
00743       SlCopyBytes(ptr, len);
00744       break;
00745     }
00746     case SLA_LOAD: {
00747       size_t len = SlReadArrayLength();
00748 
00749       switch (GetVarMemType(conv)) {
00750         default: NOT_REACHED();
00751         case SLE_VAR_STRB:
00752         case SLE_VAR_STRBQ:
00753           if (len >= length) {
00754             DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
00755             SlCopyBytes(ptr, length);
00756             SlSkipBytes(len - length);
00757             len = length - 1;
00758           } else {
00759             SlCopyBytes(ptr, len);
00760           }
00761           break;
00762         case SLE_VAR_STR:
00763         case SLE_VAR_STRQ: // Malloc'd string, free previous incarnation, and allocate
00764           free(*(char **)ptr);
00765           if (len == 0) {
00766             *(char **)ptr = NULL;
00767           } else {
00768             *(char **)ptr = MallocT<char>(len + 1); // terminating '\0'
00769             ptr = *(char **)ptr;
00770             SlCopyBytes(ptr, len);
00771           }
00772           break;
00773       }
00774 
00775       ((char *)ptr)[len] = '\0'; // properly terminate the string
00776       str_validate((char *)ptr, (char *)ptr + len);
00777       break;
00778     }
00779     case SLA_PTRS: break;
00780     case SLA_NULL: break;
00781     default: NOT_REACHED();
00782   }
00783 }
00784 
00790 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
00791 {
00792   return SlCalcConvFileLen(conv) * length;
00793 }
00794 
00801 void SlArray(void *array, size_t length, VarType conv)
00802 {
00803   if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
00804 
00805   /* Automatically calculate the length? */
00806   if (_sl.need_length != NL_NONE) {
00807     SlSetLength(SlCalcArrayLen(length, conv));
00808     /* Determine length only? */
00809     if (_sl.need_length == NL_CALCLENGTH) return;
00810   }
00811 
00812   /* NOTICE - handle some buggy stuff, in really old versions everything was saved
00813    * as a byte-type. So detect this, and adjust array size accordingly */
00814   if (_sl.action != SLA_SAVE && _sl_version == 0) {
00815     /* all arrays except difficulty settings */
00816     if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
00817         conv == SLE_INT32 || conv == SLE_UINT32) {
00818       SlCopyBytes(array, length * SlCalcConvFileLen(conv));
00819       return;
00820     }
00821     /* used for conversion of Money 32bit->64bit */
00822     if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
00823       for (uint i = 0; i < length; i++) {
00824         ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
00825       }
00826       return;
00827     }
00828   }
00829 
00830   /* If the size of elements is 1 byte both in file and memory, no special
00831    * conversion is needed, use specialized copy-copy function to speed up things */
00832   if (conv == SLE_INT8 || conv == SLE_UINT8) {
00833     SlCopyBytes(array, length);
00834   } else {
00835     byte *a = (byte*)array;
00836     byte mem_size = SlCalcConvMemLen(conv);
00837 
00838     for (; length != 0; length --) {
00839       SlSaveLoadConv(a, conv);
00840       a += mem_size; // get size
00841     }
00842   }
00843 }
00844 
00845 
00846 static size_t ReferenceToInt(const void *obj, SLRefType rt);
00847 static void *IntToReference(size_t index, SLRefType rt);
00848 
00849 
00854 static inline size_t SlCalcListLen(const void *list)
00855 {
00856   std::list<void *> *l = (std::list<void *> *) list;
00857 
00858   int type_size = CheckSavegameVersion(69) ? 2 : 4;
00859   /* Each entry is saved as type_size bytes, plus type_size bytes are used for the length
00860    * of the list */
00861   return l->size() * type_size + type_size;
00862 }
00863 
00864 
00870 static void SlList(void *list, SLRefType conv)
00871 {
00872   /* Automatically calculate the length? */
00873   if (_sl.need_length != NL_NONE) {
00874     SlSetLength(SlCalcListLen(list));
00875     /* Determine length only? */
00876     if (_sl.need_length == NL_CALCLENGTH) return;
00877   }
00878 
00879   typedef std::list<void *> PtrList;
00880   PtrList *l = (PtrList *)list;
00881 
00882   switch (_sl.action) {
00883     case SLA_SAVE: {
00884       SlWriteUint32((uint32)l->size());
00885 
00886       PtrList::iterator iter;
00887       for (iter = l->begin(); iter != l->end(); ++iter) {
00888         void *ptr = *iter;
00889         SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
00890       }
00891       break;
00892     }
00893     case SLA_LOAD: {
00894       size_t length = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
00895 
00896       /* Load each reference and push to the end of the list */
00897       for (size_t i = 0; i < length; i++) {
00898         size_t data = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
00899         l->push_back((void *)data);
00900       }
00901       break;
00902     }
00903     case SLA_PTRS: {
00904       PtrList temp = *l;
00905 
00906       l->clear();
00907       PtrList::iterator iter;
00908       for (iter = temp.begin(); iter != temp.end(); ++iter) {
00909         void *ptr = IntToReference((size_t)*iter, conv);
00910         l->push_back(ptr);
00911       }
00912       break;
00913     }
00914     case SLA_NULL:
00915       l->clear();
00916       break;
00917     default: NOT_REACHED();
00918   }
00919 }
00920 
00921 
00923 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
00924 {
00925   if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
00926   if (sld->conv & SLF_SAVE_NO) return false;
00927 
00928   return true;
00929 }
00930 
00934 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
00935 {
00936   if ((sld->conv & SLF_NETWORK_NO) && _sl.action != SLA_SAVE && _networking && !_network_server) {
00937     SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
00938     return true;
00939   }
00940 
00941   return false;
00942 }
00943 
00950 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
00951 {
00952   size_t length = 0;
00953 
00954   /* Need to determine the length and write a length tag. */
00955   for (; sld->cmd != SL_END; sld++) {
00956     length += SlCalcObjMemberLength(object, sld);
00957   }
00958   return length;
00959 }
00960 
00961 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
00962 {
00963   assert(_sl.action == SLA_SAVE);
00964 
00965   switch (sld->cmd) {
00966     case SL_VAR:
00967     case SL_REF:
00968     case SL_ARR:
00969     case SL_STR:
00970     case SL_LST:
00971       /* CONDITIONAL saveload types depend on the savegame version */
00972       if (!SlIsObjectValidInSavegame(sld)) break;
00973 
00974       switch (sld->cmd) {
00975         case SL_VAR: return SlCalcConvFileLen(sld->conv);
00976         case SL_REF: return SlCalcRefLen();
00977         case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
00978         case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
00979         case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
00980         default: NOT_REACHED();
00981       }
00982       break;
00983     case SL_WRITEBYTE: return 1; // a byte is logically of size 1
00984     case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
00985     case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
00986     default: NOT_REACHED();
00987   }
00988   return 0;
00989 }
00990 
00991 
00992 bool SlObjectMember(void *ptr, const SaveLoad *sld)
00993 {
00994   VarType conv = GB(sld->conv, 0, 8);
00995   switch (sld->cmd) {
00996     case SL_VAR:
00997     case SL_REF:
00998     case SL_ARR:
00999     case SL_STR:
01000     case SL_LST:
01001       /* CONDITIONAL saveload types depend on the savegame version */
01002       if (!SlIsObjectValidInSavegame(sld)) return false;
01003       if (SlSkipVariableOnLoad(sld)) return false;
01004 
01005       switch (sld->cmd) {
01006         case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01007         case SL_REF: // Reference variable, translate
01008           switch (_sl.action) {
01009             case SLA_SAVE:
01010               SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01011               break;
01012             case SLA_LOAD:
01013               *(size_t *)ptr = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
01014               break;
01015             case SLA_PTRS:
01016               *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01017               break;
01018             case SLA_NULL:
01019               *(void **)ptr = NULL;
01020               break;
01021             default: NOT_REACHED();
01022           }
01023           break;
01024         case SL_ARR: SlArray(ptr, sld->length, conv); break;
01025         case SL_STR: SlString(ptr, sld->length, conv); break;
01026         case SL_LST: SlList(ptr, (SLRefType)conv); break;
01027         default: NOT_REACHED();
01028       }
01029       break;
01030 
01031     /* SL_WRITEBYTE translates a value of a variable to another one upon
01032      * saving or loading.
01033      * XXX - variable renaming abuse
01034      * game_value: the value of the variable ingame is abused by sld->version_from
01035      * file_value: the value of the variable in the savegame is abused by sld->version_to */
01036     case SL_WRITEBYTE:
01037       switch (_sl.action) {
01038         case SLA_SAVE: SlWriteByte(sld->version_to); break;
01039         case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01040         case SLA_PTRS: break;
01041         case SLA_NULL: break;
01042         default: NOT_REACHED();
01043       }
01044       break;
01045 
01046     /* SL_VEH_INCLUDE loads common code for vehicles */
01047     case SL_VEH_INCLUDE:
01048       SlObject(ptr, GetVehicleDescription(VEH_END));
01049       break;
01050 
01051     case SL_ST_INCLUDE:
01052       SlObject(ptr, GetBaseStationDescription());
01053       break;
01054 
01055     default: NOT_REACHED();
01056   }
01057   return true;
01058 }
01059 
01065 void SlObject(void *object, const SaveLoad *sld)
01066 {
01067   /* Automatically calculate the length? */
01068   if (_sl.need_length != NL_NONE) {
01069     SlSetLength(SlCalcObjLength(object, sld));
01070     if (_sl.need_length == NL_CALCLENGTH) return;
01071   }
01072 
01073   for (; sld->cmd != SL_END; sld++) {
01074     void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01075     SlObjectMember(ptr, sld);
01076   }
01077 }
01078 
01083 void SlGlobList(const SaveLoadGlobVarList *sldg)
01084 {
01085   SlObject(NULL, (const SaveLoad*)sldg);
01086 }
01087 
01093 void SlAutolength(AutolengthProc *proc, void *arg)
01094 {
01095   size_t offs;
01096 
01097   assert(_sl.action == SLA_SAVE);
01098 
01099   /* Tell it to calculate the length */
01100   _sl.need_length = NL_CALCLENGTH;
01101   _sl.obj_len = 0;
01102   proc(arg);
01103 
01104   /* Setup length */
01105   _sl.need_length = NL_WANTLENGTH;
01106   SlSetLength(_sl.obj_len);
01107 
01108   offs = SlGetOffs() + _sl.obj_len;
01109 
01110   /* And write the stuff */
01111   proc(arg);
01112 
01113   if (offs != SlGetOffs()) SlErrorCorrupt("Invalid chunk size");
01114 }
01115 
01120 static void SlLoadChunk(const ChunkHandler *ch)
01121 {
01122   byte m = SlReadByte();
01123   size_t len;
01124   size_t endoffs;
01125 
01126   _sl.block_mode = m;
01127   _sl.obj_len = 0;
01128 
01129   switch (m) {
01130     case CH_ARRAY:
01131       _sl.array_index = 0;
01132       ch->load_proc();
01133       break;
01134     case CH_SPARSE_ARRAY:
01135       ch->load_proc();
01136       break;
01137     default:
01138       if ((m & 0xF) == CH_RIFF) {
01139         /* Read length */
01140         len = (SlReadByte() << 16) | ((m >> 4) << 24);
01141         len += SlReadUint16();
01142         _sl.obj_len = len;
01143         endoffs = SlGetOffs() + len;
01144         ch->load_proc();
01145         if (SlGetOffs() != endoffs) SlErrorCorrupt("Invalid chunk size");
01146       } else {
01147         SlErrorCorrupt("Invalid chunk type");
01148       }
01149       break;
01150   }
01151 }
01152 
01153 /* Stub Chunk handlers to only calculate length and do nothing else */
01154 static ChunkSaveLoadProc *_tmp_proc_1;
01155 static inline void SlStubSaveProc2(void *arg) {_tmp_proc_1();}
01156 static void SlStubSaveProc() {SlAutolength(SlStubSaveProc2, NULL);}
01157 
01162 static void SlSaveChunk(const ChunkHandler *ch)
01163 {
01164   ChunkSaveLoadProc *proc = ch->save_proc;
01165 
01166   /* Don't save any chunk information if there is no save handler. */
01167   if (proc == NULL) return;
01168 
01169   SlWriteUint32(ch->id);
01170   DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01171 
01172   if (ch->flags & CH_AUTO_LENGTH) {
01173     /* Need to calculate the length. Solve that by calling SlAutoLength in the save_proc. */
01174     _tmp_proc_1 = proc;
01175     proc = SlStubSaveProc;
01176   }
01177 
01178   _sl.block_mode = ch->flags & CH_TYPE_MASK;
01179   switch (ch->flags & CH_TYPE_MASK) {
01180     case CH_RIFF:
01181       _sl.need_length = NL_WANTLENGTH;
01182       proc();
01183       break;
01184     case CH_ARRAY:
01185       _sl.last_array_index = 0;
01186       SlWriteByte(CH_ARRAY);
01187       proc();
01188       SlWriteArrayLength(0); // Terminate arrays
01189       break;
01190     case CH_SPARSE_ARRAY:
01191       SlWriteByte(CH_SPARSE_ARRAY);
01192       proc();
01193       SlWriteArrayLength(0); // Terminate arrays
01194       break;
01195     default: NOT_REACHED();
01196   }
01197 }
01198 
01200 static void SlSaveChunks()
01201 {
01202   FOR_ALL_CHUNK_HANDLERS(ch) {
01203     SlSaveChunk(ch);
01204   }
01205 
01206   /* Terminator */
01207   SlWriteUint32(0);
01208 }
01209 
01215 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01216 {
01217   FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01218   return NULL;
01219 }
01220 
01222 static void SlLoadChunks()
01223 {
01224   uint32 id;
01225   const ChunkHandler *ch;
01226 
01227   for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01228     DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01229 
01230     ch = SlFindChunkHandler(id);
01231     if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01232     SlLoadChunk(ch);
01233   }
01234 }
01235 
01237 static void SlFixPointers()
01238 {
01239   _sl.action = SLA_PTRS;
01240 
01241   DEBUG(sl, 1, "Fixing pointers");
01242 
01243   FOR_ALL_CHUNK_HANDLERS(ch) {
01244     if (ch->ptrs_proc != NULL) {
01245       DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01246       ch->ptrs_proc();
01247     }
01248   }
01249 
01250   DEBUG(sl, 1, "All pointers fixed");
01251 
01252   assert(_sl.action == SLA_PTRS);
01253 }
01254 
01255 /*******************************************
01256  ********** START OF LZO CODE **************
01257  *******************************************/
01258 
01259 #ifdef WITH_LZO
01260 #include <lzo/lzo1x.h>
01261 
01263 static const uint LZO_BUFFER_SIZE = 8192;
01264 
01265 static size_t ReadLZO()
01266 {
01267   /* Buffer size is from the LZO docs plus the chunk header size. */
01268   byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01269   uint32 tmp[2];
01270   uint32 size;
01271   lzo_uint len;
01272 
01273   /* Read header*/
01274   if (fread(tmp, sizeof(tmp), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01275 
01276   /* Check if size is bad */
01277   ((uint32*)out)[0] = size = tmp[1];
01278 
01279   if (_sl_version != 0) {
01280     tmp[0] = TO_BE32(tmp[0]);
01281     size = TO_BE32(size);
01282   }
01283 
01284   if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01285 
01286   /* Read block */
01287   if (fread(out + sizeof(uint32), size, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01288 
01289   /* Verify checksum */
01290   if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01291 
01292   /* Decompress */
01293   lzo1x_decompress(out + sizeof(uint32) * 1, size, _sl.buf, &len, NULL);
01294   return len;
01295 }
01296 
01297 static void WriteLZO(size_t size)
01298 {
01299   const lzo_bytep in = _sl.buf;
01300   /* Buffer size is from the LZO docs plus the chunk header size. */
01301   byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01302   byte wrkmem[LZO1X_1_MEM_COMPRESS];
01303   lzo_uint outlen;
01304 
01305   do {
01306     /* Compress up to LZO_BUFFER_SIZE bytes at once. */
01307     lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01308     lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01309     ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01310     ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01311     if (fwrite(out, outlen + sizeof(uint32) * 2, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01312 
01313     /* Move to next data chunk. */
01314     size -= len;
01315     in += len;
01316   } while (size > 0);
01317 }
01318 
01319 static bool InitLZO(byte compression)
01320 {
01321   if (lzo_init() != LZO_E_OK) return false;
01322   _sl.bufsize = LZO_BUFFER_SIZE;
01323   _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_BUFFER_SIZE);
01324   return true;
01325 }
01326 
01327 static void UninitLZO()
01328 {
01329   free(_sl.buf_ori);
01330 }
01331 
01332 #endif /* WITH_LZO */
01333 
01334 /*********************************************
01335  ******** START OF NOCOMP CODE (uncompressed)*
01336  *********************************************/
01337 
01339 static const uint NOCOMP_BUFFER_SIZE = 8192;
01340 
01341 static size_t ReadNoComp()
01342 {
01343   return fread(_sl.buf, 1, NOCOMP_BUFFER_SIZE, _sl.fh);
01344 }
01345 
01346 static void WriteNoComp(size_t size)
01347 {
01348   if (fwrite(_sl.buf, 1, size, _sl.fh) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01349 }
01350 
01351 static bool InitNoComp(byte compression)
01352 {
01353   _sl.bufsize = NOCOMP_BUFFER_SIZE;
01354   _sl.buf = _sl.buf_ori = MallocT<byte>(NOCOMP_BUFFER_SIZE);
01355   return true;
01356 }
01357 
01358 static void UninitNoComp()
01359 {
01360   free(_sl.buf_ori);
01361 }
01362 
01363 /********************************************
01364  ********** START OF MEMORY CODE (in ram)****
01365  ********************************************/
01366 
01367 #include "../gui.h"
01368 
01369 struct ThreadedSave {
01370   uint count;
01371   byte ff_state;
01372   bool saveinprogress;
01373   CursorID cursor;
01374 };
01375 
01377 static const int MEMORY_CHUNK_SIZE = 128 * 1024;
01379 static AutoFreeSmallVector<byte *, 16> _memory_savegame;
01380 
01381 static ThreadedSave _ts;
01382 
01383 static void WriteMem(size_t size)
01384 {
01385   _ts.count += (uint)size;
01386 
01387   _sl.buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
01388   *_memory_savegame.Append() = _sl.buf;
01389 }
01390 
01391 static void UnInitMem()
01392 {
01393   _memory_savegame.Clear();
01394 }
01395 
01396 static bool InitMem()
01397 {
01398   _ts.count = 0;
01399   _sl.bufsize = MEMORY_CHUNK_SIZE;
01400 
01401   UnInitMem();
01402   WriteMem(0);
01403   return true;
01404 }
01405 
01406 /********************************************
01407  ********** START OF ZLIB CODE **************
01408  ********************************************/
01409 
01410 #if defined(WITH_ZLIB)
01411 #include <zlib.h>
01412 
01414 static const uint ZLIB_BUFFER_SIZE = 8192;
01415 
01416 static z_stream _z;
01417 
01418 static bool InitReadZlib(byte compression)
01419 {
01420   memset(&_z, 0, sizeof(_z));
01421   if (inflateInit(&_z) != Z_OK) return false;
01422 
01423   _sl.bufsize = ZLIB_BUFFER_SIZE;
01424   _sl.buf = _sl.buf_ori = MallocT<byte>(ZLIB_BUFFER_SIZE + ZLIB_BUFFER_SIZE); // also contains fread buffer
01425   return true;
01426 }
01427 
01428 static size_t ReadZlib()
01429 {
01430   int r;
01431 
01432   _z.next_out = _sl.buf;
01433   _z.avail_out = ZLIB_BUFFER_SIZE;
01434 
01435   do {
01436     /* read more bytes from the file? */
01437     if (_z.avail_in == 0) {
01438       _z.avail_in = (uint)fread(_z.next_in = _sl.buf + ZLIB_BUFFER_SIZE, 1, ZLIB_BUFFER_SIZE, _sl.fh);
01439     }
01440 
01441     /* inflate the data */
01442     r = inflate(&_z, 0);
01443     if (r == Z_STREAM_END)
01444       break;
01445 
01446     if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
01447   } while (_z.avail_out);
01448 
01449   return ZLIB_BUFFER_SIZE - _z.avail_out;
01450 }
01451 
01452 static void UninitReadZlib()
01453 {
01454   inflateEnd(&_z);
01455   free(_sl.buf_ori);
01456 }
01457 
01458 static bool InitWriteZlib(byte compression)
01459 {
01460   memset(&_z, 0, sizeof(_z));
01461   if (deflateInit(&_z, compression) != Z_OK) return false;
01462 
01463   _sl.bufsize = ZLIB_BUFFER_SIZE;
01464   _sl.buf = _sl.buf_ori = MallocT<byte>(ZLIB_BUFFER_SIZE);
01465   return true;
01466 }
01467 
01468 static void WriteZlibLoop(z_streamp z, byte *p, size_t len, int mode)
01469 {
01470   byte buf[ZLIB_BUFFER_SIZE]; // output buffer
01471   int r;
01472   uint n;
01473   z->next_in = p;
01474   z->avail_in = (uInt)len;
01475   do {
01476     z->next_out = buf;
01477     z->avail_out = sizeof(buf);
01478 
01486     r = deflate(z, mode);
01487 
01488     /* bytes were emitted? */
01489     if ((n = sizeof(buf) - z->avail_out) != 0) {
01490       if (fwrite(buf, n, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01491     }
01492     if (r == Z_STREAM_END)
01493       break;
01494     if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
01495   } while (z->avail_in || !z->avail_out);
01496 }
01497 
01498 static void WriteZlib(size_t len)
01499 {
01500   WriteZlibLoop(&_z, _sl.buf, len, 0);
01501 }
01502 
01503 static void UninitWriteZlib()
01504 {
01505   /* flush any pending output. */
01506   if (_sl.fh) WriteZlibLoop(&_z, NULL, 0, Z_FINISH);
01507   deflateEnd(&_z);
01508   free(_sl.buf_ori);
01509 }
01510 
01511 #endif /* WITH_ZLIB */
01512 
01513 /*******************************************
01514  ************* END OF CODE *****************
01515  *******************************************/
01516 
01527 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01528 {
01529   assert(_sl.action == SLA_SAVE);
01530 
01531   if (obj == NULL) return 0;
01532 
01533   switch (rt) {
01534     case REF_VEHICLE_OLD: // Old vehicles we save as new onces
01535     case REF_VEHICLE:   return ((const  Vehicle*)obj)->index + 1;
01536     case REF_STATION:   return ((const  Station*)obj)->index + 1;
01537     case REF_TOWN:      return ((const     Town*)obj)->index + 1;
01538     case REF_ORDER:     return ((const    Order*)obj)->index + 1;
01539     case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01540     case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01541     case REF_CARGO_PACKET:  return ((const CargoPacket*)obj)->index + 1;
01542     case REF_ORDERLIST:     return ((const   OrderList*)obj)->index + 1;
01543     default: NOT_REACHED();
01544   }
01545 }
01546 
01557 static void *IntToReference(size_t index, SLRefType rt)
01558 {
01559   assert_compile(sizeof(size_t) <= sizeof(void *));
01560 
01561   assert(_sl.action == SLA_PTRS);
01562 
01563   /* After version 4.3 REF_VEHICLE_OLD is saved as REF_VEHICLE,
01564    * and should be loaded like that */
01565   if (rt == REF_VEHICLE_OLD && !CheckSavegameVersionOldStyle(4, 4)) {
01566     rt = REF_VEHICLE;
01567   }
01568 
01569   /* No need to look up NULL pointers, just return immediately */
01570   if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01571 
01572   /* Correct index. Old vehicles were saved differently:
01573    * invalid vehicle was 0xFFFF, now we use 0x0000 for everything invalid. */
01574   if (rt != REF_VEHICLE_OLD) index--;
01575 
01576   switch (rt) {
01577     case REF_ORDERLIST:
01578       if (OrderList::IsValidID(index)) return OrderList::Get(index);
01579       SlErrorCorrupt("Referencing invalid OrderList");
01580 
01581     case REF_ORDER:
01582       if (Order::IsValidID(index)) return Order::Get(index);
01583       /* in old versions, invalid order was used to mark end of order list */
01584       if (CheckSavegameVersionOldStyle(5, 2)) return NULL;
01585       SlErrorCorrupt("Referencing invalid Order");
01586 
01587     case REF_VEHICLE_OLD:
01588     case REF_VEHICLE:
01589       if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01590       SlErrorCorrupt("Referencing invalid Vehicle");
01591 
01592     case REF_STATION:
01593       if (Station::IsValidID(index)) return Station::Get(index);
01594       SlErrorCorrupt("Referencing invalid Station");
01595 
01596     case REF_TOWN:
01597       if (Town::IsValidID(index)) return Town::Get(index);
01598       SlErrorCorrupt("Referencing invalid Town");
01599 
01600     case REF_ROADSTOPS:
01601       if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01602       SlErrorCorrupt("Referencing invalid RoadStop");
01603 
01604     case REF_ENGINE_RENEWS:
01605       if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01606       SlErrorCorrupt("Referencing invalid EngineRenew");
01607 
01608     case REF_CARGO_PACKET:
01609       if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01610       SlErrorCorrupt("Referencing invalid CargoPacket");
01611 
01612     default: NOT_REACHED();
01613   }
01614 }
01615 
01617 struct SaveLoadFormat {
01618   const char *name;                     
01619   uint32 tag;                           
01620 
01621   bool (*init_read)(byte compression);  
01622   ReaderProc *reader;                   
01623   void (*uninit_read)();                
01624 
01625   bool (*init_write)(byte compression); 
01626   WriterProc *writer;                   
01627   void (*uninit_write)();               
01628 
01629   byte min_compression;                 
01630   byte default_compression;             
01631   byte max_compression;                 
01632 };
01633 
01634 static const SaveLoadFormat _saveload_formats[] = {
01635 #if defined(WITH_LZO)
01636   {"lzo",    TO_BE32X('OTTD'), InitLZO,      ReadLZO,    UninitLZO,      InitLZO,       WriteLZO,    UninitLZO,       0, 0, 0},
01637 #else
01638   {"lzo",    TO_BE32X('OTTD'), NULL,         NULL,       NULL,           NULL,          NULL,        NULL,            0, 0, 0},
01639 #endif
01640   {"none",   TO_BE32X('OTTN'), InitNoComp,   ReadNoComp, UninitNoComp,   InitNoComp,    WriteNoComp, UninitNoComp,    0, 0, 0},
01641 #if defined(WITH_ZLIB)
01642   {"zlib",   TO_BE32X('OTTZ'), InitReadZlib, ReadZlib,   UninitReadZlib, InitWriteZlib, WriteZlib,   UninitWriteZlib, 0, 6, 9},
01643 #else
01644   {"zlib",   TO_BE32X('OTTZ'), NULL,         NULL,       NULL,           NULL,          NULL,        NULL,            0, 0, 0},
01645 #endif
01646   {"lzma",   TO_BE32X('OTTX'), NULL,         NULL,       NULL,           NULL,          NULL,        NULL,            0, 0, 0},
01647 };
01648 
01656 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
01657 {
01658   const SaveLoadFormat *def = lastof(_saveload_formats);
01659 
01660   /* find default savegame format, the highest one with which files can be written */
01661   while (!def->init_write) def--;
01662 
01663   if (!StrEmpty(s)) {
01664     /* Get the ":..." of the compression level out of the way */
01665     char *complevel = strrchr(s, ':');
01666     if (complevel != NULL) *complevel = '\0';
01667 
01668     for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
01669       if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
01670         *compression_level = slf->default_compression;
01671         if (complevel != NULL) {
01672           /* There is a compression level in the string.
01673            * First restore the : we removed to do proper name matching,
01674            * then move the the begin of the actual version. */
01675           *complevel = ':';
01676           complevel++;
01677 
01678           /* Get the version and determine whether all went fine. */
01679           char *end;
01680           long level = strtol(complevel, &end, 10);
01681           if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
01682             ShowInfoF("Compression level '%s' is not valid.", complevel);
01683           } else {
01684             *compression_level = level;
01685           }
01686         }
01687         return slf;
01688       }
01689     }
01690 
01691     ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
01692 
01693     /* Restore the string by adding the : back */
01694     if (complevel != NULL) *complevel = ':';
01695   }
01696   *compression_level = def->default_compression;
01697   return def;
01698 }
01699 
01700 /* actual loader/saver function */
01701 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
01702 extern bool AfterLoadGame();
01703 extern bool LoadOldSaveGame(const char *file);
01704 
01706 static inline SaveOrLoadResult AbortSaveLoad()
01707 {
01708   if (_sl.fh != NULL) fclose(_sl.fh);
01709 
01710   _sl.fh = NULL;
01711   return SL_ERROR;
01712 }
01713 
01717 static void SaveFileStart()
01718 {
01719   _ts.ff_state = _fast_forward;
01720   _fast_forward = 0;
01721   if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
01722 
01723   InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
01724   _ts.saveinprogress = true;
01725 }
01726 
01729 static void SaveFileDone()
01730 {
01731   if (_game_mode != GM_MENU) _fast_forward = _ts.ff_state;
01732   if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
01733 
01734   InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
01735   _ts.saveinprogress = false;
01736 }
01737 
01739 void SetSaveLoadError(StringID str)
01740 {
01741   _sl.error_str = str;
01742 }
01743 
01745 const char *GetSaveLoadErrorString()
01746 {
01747   SetDParam(0, _sl.error_str);
01748   SetDParamStr(1, _sl.extra_msg);
01749 
01750   static char err_str[512];
01751   GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
01752   return err_str;
01753 }
01754 
01756 static void SaveFileError()
01757 {
01758   SetDParamStr(0, GetSaveLoadErrorString());
01759   ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, 0, 0);
01760   SaveFileDone();
01761 }
01762 
01766 static SaveOrLoadResult SaveFileToDisk(bool threaded)
01767 {
01768   _sl.excpt_uninit = NULL;
01769   try {
01770     byte compression;
01771     const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
01772 
01773     /* We have written our stuff to memory, now write it to file! */
01774     uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
01775     if (fwrite(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01776 
01777     if (!fmt->init_write(compression)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01778 
01779     {
01780       uint i;
01781 
01782       if (_ts.count != _sl.offs_base) SlErrorCorrupt("Unexpected size of chunk");
01783       for (i = 0; i != _memory_savegame.Length() - 1; i++) {
01784         _sl.buf = _memory_savegame[i];
01785         fmt->writer(MEMORY_CHUNK_SIZE);
01786       }
01787 
01788       /* The last block is (almost) always not fully filled, so only write away
01789        * as much data as it is in there */
01790       _sl.buf = _memory_savegame[i];
01791       fmt->writer(_ts.count % MEMORY_CHUNK_SIZE);
01792     }
01793 
01794     fmt->uninit_write();
01795     if (_ts.count != _sl.offs_base) SlErrorCorrupt("Unexpected size of chunk");
01796     UnInitMem();
01797     fclose(_sl.fh);
01798 
01799     if (threaded) SetAsyncSaveFinish(SaveFileDone);
01800 
01801     return SL_OK;
01802   }
01803   catch (...) {
01804     AbortSaveLoad();
01805     if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
01806 
01807     /* Skip the "colour" character */
01808     DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
01809 
01810     if (threaded) {
01811       SetAsyncSaveFinish(SaveFileError);
01812     } else {
01813       SaveFileError();
01814     }
01815     return SL_ERROR;
01816   }
01817 }
01818 
01819 static void SaveFileToDiskThread(void *arg)
01820 {
01821   SaveFileToDisk(true);
01822 }
01823 
01824 void WaitTillSaved()
01825 {
01826   if (_save_thread == NULL) return;
01827 
01828   _save_thread->Join();
01829   delete _save_thread;
01830   _save_thread = NULL;
01831 }
01832 
01842 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
01843 {
01844   uint32 hdr[2];
01845 
01846   /* An instance of saving is already active, so don't go saving again */
01847   if (_ts.saveinprogress && mode == SL_SAVE) {
01848     /* if not an autosave, but a user action, show error message */
01849     if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, 0, 0);
01850     return SL_OK;
01851   }
01852   WaitTillSaved();
01853 
01854   _next_offs = 0;
01855 
01856   /* Load a TTDLX or TTDPatch game */
01857   if (mode == SL_OLD_LOAD) {
01858     _engine_mngr.ResetToDefaultMapping();
01859     InitializeGame(256, 256, true, true); // set a mapsize of 256x256 for TTDPatch games or it might get confused
01860 
01861     /* TTD/TTO savegames have no NewGRFs, TTDP savegame have them
01862      * and if so a new NewGRF list will be made in LoadOldSaveGame.
01863      * Note: this is done here because AfterLoadGame is also called
01864      * for OTTD savegames which have their own NewGRF logic. */
01865     ClearGRFConfigList(&_grfconfig);
01866     GamelogReset();
01867     if (!LoadOldSaveGame(filename)) return SL_REINIT;
01868     _sl_version = 0;
01869     _sl_minor_version = 0;
01870     GamelogStartAction(GLAT_LOAD);
01871     if (!AfterLoadGame()) {
01872       GamelogStopAction();
01873       return SL_REINIT;
01874     }
01875     GamelogStopAction();
01876     return SL_OK;
01877   }
01878 
01879   _sl.excpt_uninit = NULL;
01880   _sl.bufe = _sl.bufp = NULL;
01881   _sl.offs_base = 0;
01882   _sl.action = (mode != 0) ? SLA_SAVE : SLA_LOAD;
01883 
01884   try {
01885     _sl.fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
01886 
01887     /* Make it a little easier to load savegames from the console */
01888     if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", SAVE_DIR);
01889     if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", BASE_DIR);
01890 
01891     if (_sl.fh == NULL) {
01892       SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01893     }
01894 
01895     /* General tactic is to first save the game to memory, then use an available writer
01896      * to write it to file, either in threaded mode if possible, or single-threaded */
01897     if (mode == SL_SAVE) { // SAVE game
01898       DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
01899 
01900       _sl.write_bytes = WriteMem;
01901       _sl.excpt_uninit = UnInitMem;
01902       InitMem();
01903 
01904       _sl_version = SAVEGAME_VERSION;
01905 
01906       SaveViewportBeforeSaveGame();
01907       SlSaveChunks();
01908       SlWriteFill(); // flush the save buffer
01909 
01910       SaveFileStart();
01911       if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
01912       if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
01913         if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
01914 
01915         SaveOrLoadResult result = SaveFileToDisk(false);
01916         SaveFileDone();
01917 
01918         return result;
01919       }
01920     } else { // LOAD game
01921       assert(mode == SL_LOAD);
01922       DEBUG(desync, 1, "load: %s", filename);
01923 
01924       /* Can't fseek to 0 as in tar files that is not correct */
01925       long pos = ftell(_sl.fh);
01926       if (fread(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01927 
01928       /* see if we have any loader for this type. */
01929       const SaveLoadFormat *fmt = _saveload_formats;
01930       for (;;) {
01931         /* No loader found, treat as version 0 and use LZO format */
01932         if (fmt == endof(_saveload_formats)) {
01933           DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
01934           clearerr(_sl.fh);
01935           fseek(_sl.fh, pos, SEEK_SET);
01936           _sl_version = 0;
01937           _sl_minor_version = 0;
01938 
01939           /* Try to find the LZO savegame format; it uses 'OTTD' as tag. */
01940           fmt = _saveload_formats;
01941           for (;;) {
01942             if (fmt == endof(_saveload_formats)) {
01943               /* Who removed LZO support? Bad bad boy! */
01944               NOT_REACHED();
01945             }
01946             if (fmt->tag == TO_BE32X('OTTD')) break;
01947             fmt++;
01948           }
01949           break;
01950         }
01951 
01952         if (fmt->tag == hdr[0]) {
01953           /* check version number */
01954           _sl_version = TO_BE32(hdr[1]) >> 16;
01955           /* Minor is not used anymore from version 18.0, but it is still needed
01956            * in versions before that (4 cases) which can't be removed easy.
01957            * Therefor it is loaded, but never saved (or, it saves a 0 in any scenario).
01958            * So never EVER use this minor version again. -- TrueLight -- 22-11-2005 */
01959           _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
01960 
01961           DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
01962 
01963           /* Is the version higher than the current? */
01964           if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
01965           break;
01966         }
01967 
01968         fmt++;
01969       }
01970 
01971       _sl.read_bytes = fmt->reader;
01972       _sl.excpt_uninit = fmt->uninit_read;
01973 
01974       /* loader for this savegame type is not implemented? */
01975       if (fmt->init_read == NULL) {
01976         char err_str[64];
01977         snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
01978         SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
01979       }
01980 
01981       if (!fmt->init_read(0)) {
01982         char err_str[64];
01983         snprintf(err_str, lengthof(err_str), "Initializing loader '%s' failed", fmt->name);
01984         SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
01985       }
01986 
01987       _engine_mngr.ResetToDefaultMapping();
01988 
01989       /* Old maps were hardcoded to 256x256 and thus did not contain
01990        * any mapsize information. Pre-initialize to 256x256 to not to
01991        * confuse old games */
01992       InitializeGame(256, 256, true, true);
01993 
01994       GamelogReset();
01995 
01996       if (CheckSavegameVersion(4)) {
01997         /*
01998          * NewGRFs were introduced between 0.3,4 and 0.3.5, which both
01999          * shared savegame version 4. Anything before that 'obviously'
02000          * does not have any NewGRFs. Between the introduction and
02001          * savegame version 41 (just before 0.5) the NewGRF settings
02002          * were not stored in the savegame and they were loaded by
02003          * using the settings from the main menu.
02004          * So, to recap:
02005          * - savegame version  <  4:  do not load any NewGRFs.
02006          * - savegame version >= 41:  load NewGRFs from savegame, which is
02007          *                            already done at this stage by
02008          *                            overwriting the main menu settings.
02009          * - other savegame versions: use main menu settings.
02010          *
02011          * This means that users *can* crash savegame version 4..40
02012          * savegames if they set incompatible NewGRFs in the main menu,
02013          * but can't crash anymore for savegame version < 4 savegames.
02014          *
02015          * Note: this is done here because AfterLoadGame is also called
02016          * for TTO/TTD/TTDP savegames which have their own NewGRF logic.
02017          */
02018         ClearGRFConfigList(&_grfconfig);
02019       }
02020 
02021       SlLoadChunks();
02022       SlFixPointers();
02023       fmt->uninit_read();
02024       fclose(_sl.fh);
02025 
02026       GamelogStartAction(GLAT_LOAD);
02027 
02028       _savegame_type = SGT_OTTD;
02029 
02030       /* After loading fix up savegame for any internal changes that
02031        * might've occured since then. If it fails, load back the old game */
02032       if (!AfterLoadGame()) {
02033         GamelogStopAction();
02034         return SL_REINIT;
02035       }
02036 
02037       GamelogStopAction();
02038     }
02039 
02040     return SL_OK;
02041   }
02042   catch (...) {
02043     AbortSaveLoad();
02044 
02045     /* deinitialize compressor. */
02046     if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
02047 
02048     /* Skip the "colour" character */
02049     DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02050 
02051     /* A saver/loader exception!! reinitialize all variables to prevent crash! */
02052     return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02053   }
02054 }
02055 
02057 void DoExitSave()
02058 {
02059   SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02060 }
02061 
02067 void GenerateDefaultSaveName(char *buf, const char *last)
02068 {
02069   /* Check if we have a name for this map, which is the name of the first
02070    * available company. When there's no company available we'll use
02071    * 'Spectator' as "company" name. */
02072   CompanyID cid = _local_company;
02073   if (!Company::IsValidID(cid)) {
02074     const Company *c;
02075     FOR_ALL_COMPANIES(c) {
02076       cid = c->index;
02077       break;
02078     }
02079   }
02080 
02081   SetDParam(0, cid);
02082 
02083   /* Insert current date */
02084   switch (_settings_client.gui.date_format_in_default_names) {
02085     case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02086     case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02087     case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02088     default: NOT_REACHED();
02089   }
02090   SetDParam(2, _date);
02091 
02092   /* Get the correct string (special string for when there's not company) */
02093   GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02094   SanitizeFilename(buf);
02095 }
02096 
02097 #if 0
02098 
02104 int GetSavegameType(char *file)
02105 {
02106   const SaveLoadFormat *fmt;
02107   uint32 hdr;
02108   FILE *f;
02109   int mode = SL_OLD_LOAD;
02110 
02111   f = fopen(file, "rb");
02112   if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02113     DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02114     mode = SL_LOAD; // don't try to get filename, just show name as it is written
02115   } else {
02116     /* see if we have any loader for this type. */
02117     for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02118       if (fmt->tag == hdr) {
02119         mode = SL_LOAD; // new type of savegame
02120         break;
02121       }
02122     }
02123   }
02124 
02125   fclose(f);
02126   return mode;
02127 }
02128 #endif

Generated on Sun Nov 14 14:41:56 2010 for OpenTTD by  doxygen 1.6.1