saveload.cpp

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

Generated on Tue Jan 5 21:02:58 2010 for OpenTTD by  doxygen 1.5.6