saveload.cpp

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

Generated on Tue Dec 1 00:06:18 2009 for OpenTTD by  doxygen 1.5.6