saveload.cpp

Go to the documentation of this file.
00001 /* $Id: saveload.cpp 13685 2008-07-09 18:59:39Z rubidium $ */
00002 
00016 #include "stdafx.h"
00017 #include "openttd.h"
00018 #include "debug.h"
00019 #include "station.h"
00020 #include "thread.h"
00021 #include "town.h"
00022 #include "saveload.h"
00023 #include "network/network.h"
00024 #include "variables.h"
00025 #include "window_func.h"
00026 #include "strings_func.h"
00027 #include "gfx_func.h"
00028 #include "core/alloc_func.hpp"
00029 #include "functions.h"
00030 #include "core/endian_func.hpp"
00031 #include "vehicle_base.h"
00032 #include "autoreplace_base.h"
00033 #include <list>
00034 
00035 #include "table/strings.h"
00036 
00037 extern const uint16 SAVEGAME_VERSION = 92;
00038 uint16 _sl_version;       
00039 byte   _sl_minor_version; 
00040 
00041 typedef void WriterProc(uint len);
00042 typedef uint ReaderProc();
00043 
00045 static struct {
00046   bool save;                           
00047   byte need_length;                    
00048   byte block_mode;                     
00049   bool error;                          
00050 
00051   int obj_len;                         
00052   int array_index, last_array_index;   
00053 
00054   uint32 offs_base;                    
00055 
00056   WriterProc *write_bytes;             
00057   ReaderProc *read_bytes;              
00058 
00059   const ChunkHandler* const *chs;      
00060 
00061   /* When saving/loading savegames, they are always saved to a temporary memory-place
00062    * to be flushed to file (save) or to final place (load) when full. */
00063   byte *bufp, *bufe;                   
00064 
00065   /* these 3 may be used by compressor/decompressors. */
00066   byte *buf;                           
00067   byte *buf_ori;                       
00068   uint bufsize;                        
00069   FILE *fh;                            
00070 
00071   void (*excpt_uninit)();              
00072   StringID error_str;                  
00073   char *extra_msg;                     
00074 } _sl;
00075 
00076 
00077 enum NeedLengthValues {NL_NONE = 0, NL_WANTLENGTH = 1, NL_CALCLENGTH = 2};
00078 
00082 static void NORETURN SlError(StringID string, const char *extra_msg = NULL)
00083 {
00084   _sl.error_str = string;
00085   free(_sl.extra_msg);
00086   _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00087   throw std::exception();
00088 }
00089 
00093 static void SlReadFill()
00094 {
00095   uint len = _sl.read_bytes();
00096   if (len == 0) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected end of chunk");
00097 
00098   _sl.bufp = _sl.buf;
00099   _sl.bufe = _sl.buf + len;
00100   _sl.offs_base += len;
00101 }
00102 
00103 static inline uint32 SlGetOffs() {return _sl.offs_base - (_sl.bufe - _sl.bufp);}
00104 
00109 static inline byte SlCalcConvMemLen(VarType conv)
00110 {
00111   static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00112   byte length = GB(conv, 4, 4);
00113   assert(length < lengthof(conv_mem_size));
00114   return conv_mem_size[length];
00115 }
00116 
00121 static inline byte SlCalcConvFileLen(VarType conv)
00122 {
00123   static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00124   byte length = GB(conv, 0, 4);
00125   assert(length < lengthof(conv_file_size));
00126   return conv_file_size[length];
00127 }
00128 
00130 static inline size_t SlCalcRefLen() {return CheckSavegameVersion(69) ? 2 : 4;}
00131 
00136 static void SlWriteFill()
00137 {
00138   /* flush the buffer to disk (the writer) */
00139   if (_sl.bufp != NULL) {
00140     uint len = _sl.bufp - _sl.buf;
00141     _sl.offs_base += len;
00142     if (len) _sl.write_bytes(len);
00143   }
00144 
00145   /* All the data from the buffer has been written away, rewind to the beginning
00146    * to start reading in more data */
00147   _sl.bufp = _sl.buf;
00148   _sl.bufe = _sl.buf + _sl.bufsize;
00149 }
00150 
00155 static inline byte SlReadByteInternal()
00156 {
00157   if (_sl.bufp == _sl.bufe) SlReadFill();
00158   return *_sl.bufp++;
00159 }
00160 
00162 byte SlReadByte() {return SlReadByteInternal();}
00163 
00168 static inline void SlWriteByteInternal(byte b)
00169 {
00170   if (_sl.bufp == _sl.bufe) SlWriteFill();
00171   *_sl.bufp++ = b;
00172 }
00173 
00175 void SlWriteByte(byte b) {SlWriteByteInternal(b);}
00176 
00177 static inline int SlReadUint16()
00178 {
00179   int x = SlReadByte() << 8;
00180   return x | SlReadByte();
00181 }
00182 
00183 static inline uint32 SlReadUint32()
00184 {
00185   uint32 x = SlReadUint16() << 16;
00186   return x | SlReadUint16();
00187 }
00188 
00189 static inline uint64 SlReadUint64()
00190 {
00191   uint32 x = SlReadUint32();
00192   uint32 y = SlReadUint32();
00193   return (uint64)x << 32 | y;
00194 }
00195 
00196 static inline void SlWriteUint16(uint16 v)
00197 {
00198   SlWriteByte(GB(v, 8, 8));
00199   SlWriteByte(GB(v, 0, 8));
00200 }
00201 
00202 static inline void SlWriteUint32(uint32 v)
00203 {
00204   SlWriteUint16(GB(v, 16, 16));
00205   SlWriteUint16(GB(v,  0, 16));
00206 }
00207 
00208 static inline void SlWriteUint64(uint64 x)
00209 {
00210   SlWriteUint32((uint32)(x >> 32));
00211   SlWriteUint32((uint32)x);
00212 }
00213 
00223 static uint SlReadSimpleGamma()
00224 {
00225   uint i = SlReadByte();
00226   if (HasBit(i, 7)) {
00227     i &= ~0x80;
00228     if (HasBit(i, 6)) {
00229       i &= ~0x40;
00230       if (HasBit(i, 5)) {
00231         i &= ~0x20;
00232         if (HasBit(i, 4))
00233           SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unsupported gamma");
00234         i = (i << 8) | SlReadByte();
00235       }
00236       i = (i << 8) | SlReadByte();
00237     }
00238     i = (i << 8) | SlReadByte();
00239   }
00240   return i;
00241 }
00242 
00255 static void SlWriteSimpleGamma(uint i)
00256 {
00257   if (i >= (1 << 7)) {
00258     if (i >= (1 << 14)) {
00259       if (i >= (1 << 21)) {
00260         assert(i < (1 << 28));
00261         SlWriteByte((byte)0xE0 | (i >> 24));
00262         SlWriteByte((byte)(i >> 16));
00263       } else {
00264         SlWriteByte((byte)0xC0 | (i >> 16));
00265       }
00266       SlWriteByte((byte)(i >> 8));
00267     } else {
00268       SlWriteByte((byte)(0x80 | (i >> 8)));
00269     }
00270   }
00271   SlWriteByte(i);
00272 }
00273 
00275 static inline uint SlGetGammaLength(uint i)
00276 {
00277   return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00278 }
00279 
00280 static inline uint SlReadSparseIndex() {return SlReadSimpleGamma();}
00281 static inline void SlWriteSparseIndex(uint index) {SlWriteSimpleGamma(index);}
00282 
00283 static inline uint SlReadArrayLength() {return SlReadSimpleGamma();}
00284 static inline void SlWriteArrayLength(uint length) {SlWriteSimpleGamma(length);}
00285 static inline uint SlGetArrayLength(uint length) {return SlGetGammaLength(length);}
00286 
00287 void SlSetArrayIndex(uint index)
00288 {
00289   _sl.need_length = NL_WANTLENGTH;
00290   _sl.array_index = index;
00291 }
00292 
00293 static uint32 _next_offs;
00294 
00299 int SlIterateArray()
00300 {
00301   int index;
00302 
00303   /* After reading in the whole array inside the loop
00304    * we must have read in all the data, so we must be at end of current block. */
00305   if (_next_offs != 0 && SlGetOffs() != _next_offs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
00306 
00307   while (true) {
00308     uint length = SlReadArrayLength();
00309     if (length == 0) {
00310       _next_offs = 0;
00311       return -1;
00312     }
00313 
00314     _sl.obj_len = --length;
00315     _next_offs = SlGetOffs() + length;
00316 
00317     switch (_sl.block_mode) {
00318     case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00319     case CH_ARRAY:        index = _sl.array_index++; break;
00320     default:
00321       DEBUG(sl, 0, "SlIterateArray error");
00322       return -1; // error
00323     }
00324 
00325     if (length != 0) return index;
00326   }
00327 }
00328 
00334 void SlSetLength(size_t length)
00335 {
00336   assert(_sl.save);
00337 
00338   switch (_sl.need_length) {
00339   case NL_WANTLENGTH:
00340     _sl.need_length = NL_NONE;
00341     switch (_sl.block_mode) {
00342     case CH_RIFF:
00343       /* Ugly encoding of >16M RIFF chunks
00344        * The lower 24 bits are normal
00345        * The uppermost 4 bits are bits 24:27 */
00346       assert(length < (1<<28));
00347       SlWriteUint32((length & 0xFFFFFF) | ((length >> 24) << 28));
00348       break;
00349     case CH_ARRAY:
00350       assert(_sl.last_array_index <= _sl.array_index);
00351       while (++_sl.last_array_index <= _sl.array_index)
00352         SlWriteArrayLength(1);
00353       SlWriteArrayLength(length + 1);
00354       break;
00355     case CH_SPARSE_ARRAY:
00356       SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index)); // Also include length of sparse index.
00357       SlWriteSparseIndex(_sl.array_index);
00358       break;
00359     default: NOT_REACHED();
00360     } break;
00361   case NL_CALCLENGTH:
00362     _sl.obj_len += length;
00363     break;
00364   }
00365 }
00366 
00373 static void SlCopyBytes(void *ptr, size_t length)
00374 {
00375   byte *p = (byte*)ptr;
00376 
00377   if (_sl.save) {
00378     for (; length != 0; length--) {SlWriteByteInternal(*p++);}
00379   } else {
00380     for (; length != 0; length--) {*p++ = SlReadByteInternal();}
00381   }
00382 }
00383 
00388 static inline void SlSkipBytes(size_t length)
00389 {
00390   for (; length != 0; length--) SlReadByte();
00391 }
00392 
00393 /* Get the length of the current object */
00394 uint SlGetFieldLength() {return _sl.obj_len;}
00395 
00401 int64 ReadValue(const void *ptr, VarType conv)
00402 {
00403   switch (GetVarMemType(conv)) {
00404   case SLE_VAR_BL:  return (*(bool*)ptr != 0);
00405   case SLE_VAR_I8:  return *(int8*  )ptr;
00406   case SLE_VAR_U8:  return *(byte*  )ptr;
00407   case SLE_VAR_I16: return *(int16* )ptr;
00408   case SLE_VAR_U16: return *(uint16*)ptr;
00409   case SLE_VAR_I32: return *(int32* )ptr;
00410   case SLE_VAR_U32: return *(uint32*)ptr;
00411   case SLE_VAR_I64: return *(int64* )ptr;
00412   case SLE_VAR_U64: return *(uint64*)ptr;
00413   case SLE_VAR_NULL:return 0;
00414   default: NOT_REACHED();
00415   }
00416 
00417   /* useless, but avoids compiler warning this way */
00418   return 0;
00419 }
00420 
00426 void WriteValue(void *ptr, VarType conv, int64 val)
00427 {
00428   switch (GetVarMemType(conv)) {
00429   case SLE_VAR_BL:  *(bool  *)ptr = (val != 0);  break;
00430   case SLE_VAR_I8:  *(int8  *)ptr = val; break;
00431   case SLE_VAR_U8:  *(byte  *)ptr = val; break;
00432   case SLE_VAR_I16: *(int16 *)ptr = val; break;
00433   case SLE_VAR_U16: *(uint16*)ptr = val; break;
00434   case SLE_VAR_I32: *(int32 *)ptr = val; break;
00435   case SLE_VAR_U32: *(uint32*)ptr = val; break;
00436   case SLE_VAR_I64: *(int64 *)ptr = val; break;
00437   case SLE_VAR_U64: *(uint64*)ptr = val; break;
00438   case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00439   case SLE_VAR_NULL: break;
00440   default: NOT_REACHED();
00441   }
00442 }
00443 
00452 static void SlSaveLoadConv(void *ptr, VarType conv)
00453 {
00454   int64 x = 0;
00455 
00456   if (_sl.save) { // SAVE values
00457     /* Read a value from the struct. These ARE endian safe. */
00458     x = ReadValue(ptr, conv);
00459 
00460     /* Write the value to the file and check if its value is in the desired range */
00461     switch (GetVarFileType(conv)) {
00462     case SLE_FILE_I8: assert(x >= -128 && x <= 127);     SlWriteByte(x);break;
00463     case SLE_FILE_U8: assert(x >= 0 && x <= 255);        SlWriteByte(x);break;
00464     case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00465     case SLE_FILE_STRINGID:
00466     case SLE_FILE_U16:assert(x >= 0 && x <= 65535);      SlWriteUint16(x);break;
00467     case SLE_FILE_I32:
00468     case SLE_FILE_U32:                                   SlWriteUint32((uint32)x);break;
00469     case SLE_FILE_I64:
00470     case SLE_FILE_U64:                                   SlWriteUint64(x);break;
00471     default: NOT_REACHED();
00472     }
00473   } else { // LOAD values
00474 
00475     /* Read a value from the file */
00476     switch (GetVarFileType(conv)) {
00477     case SLE_FILE_I8:  x = (int8  )SlReadByte();   break;
00478     case SLE_FILE_U8:  x = (byte  )SlReadByte();   break;
00479     case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00480     case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00481     case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00482     case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00483     case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00484     case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00485     case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00486     default: NOT_REACHED();
00487     }
00488 
00489     /* Write The value to the struct. These ARE endian safe. */
00490     WriteValue(ptr, conv, x);
00491   }
00492 }
00493 
00501 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
00502 {
00503   if (ptr == NULL) return 0;
00504   return minu(strlen(ptr), length - 1);
00505 }
00506 
00514 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
00515 {
00516   size_t len;
00517   const char *str;
00518 
00519   switch (GetVarMemType(conv)) {
00520     default: NOT_REACHED();
00521     case SLE_VAR_STR:
00522     case SLE_VAR_STRQ:
00523       str = *(const char**)ptr;
00524       len = SIZE_MAX;
00525       break;
00526     case SLE_VAR_STRB:
00527     case SLE_VAR_STRBQ:
00528       str = (const char*)ptr;
00529       len = length;
00530       break;
00531   }
00532 
00533   len = SlCalcNetStringLen(str, len);
00534   return len + SlGetArrayLength(len); // also include the length of the index
00535 }
00536 
00542 static void SlString(void *ptr, size_t length, VarType conv)
00543 {
00544   size_t len;
00545 
00546   if (_sl.save) { // SAVE string
00547     switch (GetVarMemType(conv)) {
00548       default: NOT_REACHED();
00549       case SLE_VAR_STRB:
00550       case SLE_VAR_STRBQ:
00551         len = SlCalcNetStringLen((char*)ptr, length);
00552         break;
00553       case SLE_VAR_STR:
00554       case SLE_VAR_STRQ:
00555         ptr = *(char**)ptr;
00556         len = SlCalcNetStringLen((char*)ptr, SIZE_MAX);
00557         break;
00558     }
00559 
00560     SlWriteArrayLength(len);
00561     SlCopyBytes(ptr, len);
00562   } else { // LOAD string
00563     len = SlReadArrayLength();
00564 
00565     switch (GetVarMemType(conv)) {
00566       default: NOT_REACHED();
00567       case SLE_VAR_STRB:
00568       case SLE_VAR_STRBQ:
00569         if (len >= length) {
00570           DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
00571           SlCopyBytes(ptr, length);
00572           SlSkipBytes(len - length);
00573           len = length - 1;
00574         } else {
00575           SlCopyBytes(ptr, len);
00576         }
00577         break;
00578       case SLE_VAR_STR:
00579       case SLE_VAR_STRQ: // Malloc'd string, free previous incarnation, and allocate
00580         free(*(char**)ptr);
00581         if (len == 0) {
00582           *(char**)ptr = NULL;
00583         } else {
00584           *(char**)ptr = MallocT<char>(len + 1); // terminating '\0'
00585           ptr = *(char**)ptr;
00586           SlCopyBytes(ptr, len);
00587         }
00588         break;
00589     }
00590 
00591     ((char*)ptr)[len] = '\0'; // properly terminate the string
00592   }
00593 }
00594 
00600 static inline size_t SlCalcArrayLen(uint length, VarType conv)
00601 {
00602   return SlCalcConvFileLen(conv) * length;
00603 }
00604 
00611 void SlArray(void *array, uint length, VarType conv)
00612 {
00613   /* Automatically calculate the length? */
00614   if (_sl.need_length != NL_NONE) {
00615     SlSetLength(SlCalcArrayLen(length, conv));
00616     /* Determine length only? */
00617     if (_sl.need_length == NL_CALCLENGTH) return;
00618   }
00619 
00620   /* NOTICE - handle some buggy stuff, in really old versions everything was saved
00621    * as a byte-type. So detect this, and adjust array size accordingly */
00622   if (!_sl.save && _sl_version == 0) {
00623     /* all arrays except difficulty settings */
00624     if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
00625         conv == SLE_INT32 || conv == SLE_UINT32) {
00626       SlCopyBytes(array, length * SlCalcConvFileLen(conv));
00627       return;
00628     }
00629     /* used for conversion of Money 32bit->64bit */
00630     if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
00631       for (uint i = 0; i < length; i++) {
00632         ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
00633       }
00634       return;
00635     }
00636   }
00637 
00638   /* If the size of elements is 1 byte both in file and memory, no special
00639    * conversion is needed, use specialized copy-copy function to speed up things */
00640   if (conv == SLE_INT8 || conv == SLE_UINT8) {
00641     SlCopyBytes(array, length);
00642   } else {
00643     byte *a = (byte*)array;
00644     byte mem_size = SlCalcConvMemLen(conv);
00645 
00646     for (; length != 0; length --) {
00647       SlSaveLoadConv(a, conv);
00648       a += mem_size; // get size
00649     }
00650   }
00651 }
00652 
00653 
00654 static uint ReferenceToInt(const void* obj, SLRefType rt);
00655 static void* IntToReference(uint index, SLRefType rt);
00656 
00657 
00662 static inline size_t SlCalcListLen(const void *list)
00663 {
00664   std::list<void *> *l = (std::list<void *> *) list;
00665 
00666   int type_size = CheckSavegameVersion(69) ? 2 : 4;
00667   /* Each entry is saved as type_size bytes, plus type_size bytes are used for the length
00668    * of the list */
00669   return l->size() * type_size + type_size;
00670 }
00671 
00672 
00678 void SlList(void *list, SLRefType conv)
00679 {
00680   /* Automatically calculate the length? */
00681   if (_sl.need_length != NL_NONE) {
00682     SlSetLength(SlCalcListLen(list));
00683     /* Determine length only? */
00684     if (_sl.need_length == NL_CALCLENGTH) return;
00685   }
00686 
00687   std::list<void *> *l = (std::list<void *> *) list;
00688 
00689   if (_sl.save) {
00690     SlWriteUint32(l->size());
00691 
00692     std::list<void *>::iterator iter;
00693     for (iter = l->begin(); iter != l->end(); ++iter) {
00694       void *ptr = *iter;
00695       SlWriteUint32(ReferenceToInt(ptr, conv));
00696     }
00697   } else {
00698     uint length = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
00699 
00700     /* Load each reference and push to the end of the list */
00701     for (uint i = 0; i < length; i++) {
00702       void *ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), conv);
00703       l->push_back(ptr);
00704     }
00705   }
00706 }
00707 
00708 
00710 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
00711 {
00712   if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
00713   if (sld->conv & SLF_SAVE_NO) return false;
00714 
00715   return true;
00716 }
00717 
00721 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
00722 {
00723   if ((sld->conv & SLF_NETWORK_NO) && !_sl.save && _networking && !_network_server) {
00724     SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
00725     return true;
00726   }
00727 
00728   return false;
00729 }
00730 
00737 static size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
00738 {
00739   size_t length = 0;
00740 
00741   /* Need to determine the length and write a length tag. */
00742   for (; sld->cmd != SL_END; sld++) {
00743     length += SlCalcObjMemberLength(object, sld);
00744   }
00745   return length;
00746 }
00747 
00748 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
00749 {
00750   assert(_sl.save);
00751 
00752   switch (sld->cmd) {
00753     case SL_VAR:
00754     case SL_REF:
00755     case SL_ARR:
00756     case SL_STR:
00757     case SL_LST:
00758       /* CONDITIONAL saveload types depend on the savegame version */
00759       if (!SlIsObjectValidInSavegame(sld)) break;
00760 
00761       switch (sld->cmd) {
00762       case SL_VAR: return SlCalcConvFileLen(sld->conv);
00763       case SL_REF: return SlCalcRefLen();
00764       case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
00765       case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
00766       case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
00767       default: NOT_REACHED();
00768       }
00769       break;
00770     case SL_WRITEBYTE: return 1; // a byte is logically of size 1
00771     case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
00772     default: NOT_REACHED();
00773   }
00774   return 0;
00775 }
00776 
00777 
00778 bool SlObjectMember(void *ptr, const SaveLoad *sld)
00779 {
00780   VarType conv = GB(sld->conv, 0, 8);
00781   switch (sld->cmd) {
00782   case SL_VAR:
00783   case SL_REF:
00784   case SL_ARR:
00785   case SL_STR:
00786   case SL_LST:
00787     /* CONDITIONAL saveload types depend on the savegame version */
00788     if (!SlIsObjectValidInSavegame(sld)) return false;
00789     if (SlSkipVariableOnLoad(sld)) return false;
00790 
00791     switch (sld->cmd) {
00792     case SL_VAR: SlSaveLoadConv(ptr, conv); break;
00793     case SL_REF: // Reference variable, translate
00794       if (_sl.save) {
00795         SlWriteUint32(ReferenceToInt(*(void**)ptr, (SLRefType)conv));
00796       } else {
00797         *(void**)ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), (SLRefType)conv);
00798       }
00799       break;
00800     case SL_ARR: SlArray(ptr, sld->length, conv); break;
00801     case SL_STR: SlString(ptr, sld->length, conv); break;
00802     case SL_LST: SlList(ptr, (SLRefType)conv); break;
00803     default: NOT_REACHED();
00804     }
00805     break;
00806 
00807   /* SL_WRITEBYTE translates a value of a variable to another one upon
00808    * saving or loading.
00809    * XXX - variable renaming abuse
00810    * game_value: the value of the variable ingame is abused by sld->version_from
00811    * file_value: the value of the variable in the savegame is abused by sld->version_to */
00812   case SL_WRITEBYTE:
00813     if (_sl.save) {
00814       SlWriteByte(sld->version_to);
00815     } else {
00816       *(byte*)ptr = sld->version_from;
00817     }
00818     break;
00819 
00820   /* SL_VEH_INCLUDE loads common code for vehicles */
00821   case SL_VEH_INCLUDE:
00822     SlObject(ptr, GetVehicleDescription(VEH_END));
00823     break;
00824   default: NOT_REACHED();
00825   }
00826   return true;
00827 }
00828 
00834 void SlObject(void *object, const SaveLoad *sld)
00835 {
00836   /* Automatically calculate the length? */
00837   if (_sl.need_length != NL_NONE) {
00838     SlSetLength(SlCalcObjLength(object, sld));
00839     if (_sl.need_length == NL_CALCLENGTH) return;
00840   }
00841 
00842   for (; sld->cmd != SL_END; sld++) {
00843     void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
00844     SlObjectMember(ptr, sld);
00845   }
00846 }
00847 
00852 void SlGlobList(const SaveLoadGlobVarList *sldg)
00853 {
00854   SlObject(NULL, (const SaveLoad*)sldg);
00855 }
00856 
00862 void SlAutolength(AutolengthProc *proc, void *arg)
00863 {
00864   uint32 offs;
00865 
00866   assert(_sl.save);
00867 
00868   /* Tell it to calculate the length */
00869   _sl.need_length = NL_CALCLENGTH;
00870   _sl.obj_len = 0;
00871   proc(arg);
00872 
00873   /* Setup length */
00874   _sl.need_length = NL_WANTLENGTH;
00875   SlSetLength(_sl.obj_len);
00876 
00877   offs = SlGetOffs() + _sl.obj_len;
00878 
00879   /* And write the stuff */
00880   proc(arg);
00881 
00882   if (offs != SlGetOffs()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
00883 }
00884 
00889 static void SlLoadChunk(const ChunkHandler *ch)
00890 {
00891   byte m = SlReadByte();
00892   size_t len;
00893   uint32 endoffs;
00894 
00895   _sl.block_mode = m;
00896   _sl.obj_len = 0;
00897 
00898   switch (m) {
00899   case CH_ARRAY:
00900     _sl.array_index = 0;
00901     ch->load_proc();
00902     break;
00903   case CH_SPARSE_ARRAY:
00904     ch->load_proc();
00905     break;
00906   default:
00907     if ((m & 0xF) == CH_RIFF) {
00908       /* Read length */
00909       len = (SlReadByte() << 16) | ((m >> 4) << 24);
00910       len += SlReadUint16();
00911       _sl.obj_len = len;
00912       endoffs = SlGetOffs() + len;
00913       ch->load_proc();
00914       if (SlGetOffs() != endoffs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
00915     } else {
00916       SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk type");
00917     }
00918     break;
00919   }
00920 }
00921 
00922 /* Stub Chunk handlers to only calculate length and do nothing else */
00923 static ChunkSaveLoadProc *_tmp_proc_1;
00924 static inline void SlStubSaveProc2(void *arg) {_tmp_proc_1();}
00925 static void SlStubSaveProc() {SlAutolength(SlStubSaveProc2, NULL);}
00926 
00931 static void SlSaveChunk(const ChunkHandler *ch)
00932 {
00933   ChunkSaveLoadProc *proc = ch->save_proc;
00934 
00935   /* Don't save any chunk information if there is no save handler. */
00936   if (proc == NULL) return;
00937 
00938   SlWriteUint32(ch->id);
00939   DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00940 
00941   if (ch->flags & CH_AUTO_LENGTH) {
00942     /* Need to calculate the length. Solve that by calling SlAutoLength in the save_proc. */
00943     _tmp_proc_1 = proc;
00944     proc = SlStubSaveProc;
00945   }
00946 
00947   _sl.block_mode = ch->flags & CH_TYPE_MASK;
00948   switch (ch->flags & CH_TYPE_MASK) {
00949   case CH_RIFF:
00950     _sl.need_length = NL_WANTLENGTH;
00951     proc();
00952     break;
00953   case CH_ARRAY:
00954     _sl.last_array_index = 0;
00955     SlWriteByte(CH_ARRAY);
00956     proc();
00957     SlWriteArrayLength(0); // Terminate arrays
00958     break;
00959   case CH_SPARSE_ARRAY:
00960     SlWriteByte(CH_SPARSE_ARRAY);
00961     proc();
00962     SlWriteArrayLength(0); // Terminate arrays
00963     break;
00964   default: NOT_REACHED();
00965   }
00966 }
00967 
00969 static void SlSaveChunks()
00970 {
00971   const ChunkHandler *ch;
00972   const ChunkHandler* const *chsc;
00973   uint p;
00974 
00975   for (p = 0; p != CH_NUM_PRI_LEVELS; p++) {
00976     for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
00977       while (true) {
00978         if (((ch->flags >> CH_PRI_SHL) & (CH_NUM_PRI_LEVELS - 1)) == p)
00979           SlSaveChunk(ch);
00980         if (ch->flags & CH_LAST)
00981           break;
00982         ch++;
00983       }
00984     }
00985   }
00986 
00987   /* Terminator */
00988   SlWriteUint32(0);
00989 }
00990 
00996 static const ChunkHandler *SlFindChunkHandler(uint32 id)
00997 {
00998   const ChunkHandler *ch;
00999   const ChunkHandler *const *chsc;
01000   for (chsc = _sl.chs; (ch = *chsc++) != NULL;) {
01001     for (;;) {
01002       if (ch->id == id) return ch;
01003       if (ch->flags & CH_LAST) break;
01004       ch++;
01005     }
01006   }
01007   return NULL;
01008 }
01009 
01011 static void SlLoadChunks()
01012 {
01013   uint32 id;
01014   const ChunkHandler *ch;
01015 
01016   for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01017     DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01018 
01019     ch = SlFindChunkHandler(id);
01020     if (ch == NULL) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unknown chunk type");
01021     SlLoadChunk(ch);
01022   }
01023 }
01024 
01025 /*******************************************
01026  ********** START OF LZO CODE **************
01027  *******************************************/
01028 #define LZO_SIZE 8192
01029 
01030 #include "minilzo.h"
01031 
01032 static uint ReadLZO()
01033 {
01034   byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
01035   uint32 tmp[2];
01036   uint32 size;
01037   uint len;
01038 
01039   /* Read header*/
01040   if (fread(tmp, sizeof(tmp), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01041 
01042   /* Check if size is bad */
01043   ((uint32*)out)[0] = size = tmp[1];
01044 
01045   if (_sl_version != 0) {
01046     tmp[0] = TO_BE32(tmp[0]);
01047     size = TO_BE32(size);
01048   }
01049 
01050   if (size >= sizeof(out)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Inconsistent size");
01051 
01052   /* Read block */
01053   if (fread(out + sizeof(uint32), size, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01054 
01055   /* Verify checksum */
01056   if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Bad checksum");
01057 
01058   /* Decompress */
01059   lzo1x_decompress(out + sizeof(uint32)*1, size, _sl.buf, &len, NULL);
01060   return len;
01061 }
01062 
01063 /* p contains the pointer to the buffer, len contains the pointer to the length.
01064  * len bytes will be written, p and l will be updated to reflect the next buffer. */
01065 static void WriteLZO(uint size)
01066 {
01067   byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
01068   byte wrkmem[sizeof(byte*)*4096];
01069   uint outlen;
01070 
01071   lzo1x_1_compress(_sl.buf, size, out + sizeof(uint32)*2, &outlen, wrkmem);
01072   ((uint32*)out)[1] = TO_BE32(outlen);
01073   ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01074   if (fwrite(out, outlen + sizeof(uint32)*2, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01075 }
01076 
01077 static bool InitLZO()
01078 {
01079   _sl.bufsize = LZO_SIZE;
01080   _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
01081   return true;
01082 }
01083 
01084 static void UninitLZO()
01085 {
01086   free(_sl.buf_ori);
01087 }
01088 
01089 /*********************************************
01090  ******** START OF NOCOMP CODE (uncompressed)*
01091  *********************************************/
01092 static uint ReadNoComp()
01093 {
01094   return fread(_sl.buf, 1, LZO_SIZE, _sl.fh);
01095 }
01096 
01097 static void WriteNoComp(uint size)
01098 {
01099   fwrite(_sl.buf, 1, size, _sl.fh);
01100 }
01101 
01102 static bool InitNoComp()
01103 {
01104   _sl.bufsize = LZO_SIZE;
01105   _sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
01106   return true;
01107 }
01108 
01109 static void UninitNoComp()
01110 {
01111   free(_sl.buf_ori);
01112 }
01113 
01114 /********************************************
01115  ********** START OF MEMORY CODE (in ram)****
01116  ********************************************/
01117 
01118 #include "table/sprites.h"
01119 #include "gui.h"
01120 
01121 struct ThreadedSave {
01122   uint count;
01123   byte ff_state;
01124   bool saveinprogress;
01125   CursorID cursor;
01126 };
01127 
01128 /* A maximum size of of 128K * 500 = 64.000KB savegames */
01129 STATIC_OLD_POOL(Savegame, byte, 17, 500, NULL, NULL)
01130 static ThreadedSave _ts;
01131 
01132 static bool InitMem()
01133 {
01134   _ts.count = 0;
01135 
01136   _Savegame_pool.CleanPool();
01137   _Savegame_pool.AddBlockToPool();
01138 
01139   /* A block from the pool is a contigious area of memory, so it is safe to write to it sequentially */
01140   _sl.bufsize = GetSavegamePoolSize();
01141   _sl.buf = GetSavegame(_ts.count);
01142   return true;
01143 }
01144 
01145 static void UnInitMem()
01146 {
01147   _Savegame_pool.CleanPool();
01148 }
01149 
01150 static void WriteMem(uint size)
01151 {
01152   _ts.count += size;
01153   /* Allocate new block and new buffer-pointer */
01154   _Savegame_pool.AddBlockIfNeeded(_ts.count);
01155   _sl.buf = GetSavegame(_ts.count);
01156 }
01157 
01158 /********************************************
01159  ********** START OF ZLIB CODE **************
01160  ********************************************/
01161 
01162 #if defined(WITH_ZLIB)
01163 #include <zlib.h>
01164 
01165 static z_stream _z;
01166 
01167 static bool InitReadZlib()
01168 {
01169   memset(&_z, 0, sizeof(_z));
01170   if (inflateInit(&_z) != Z_OK) return false;
01171 
01172   _sl.bufsize = 4096;
01173   _sl.buf = _sl.buf_ori = MallocT<byte>(4096 + 4096); // also contains fread buffer
01174   return true;
01175 }
01176 
01177 static uint ReadZlib()
01178 {
01179   int r;
01180 
01181   _z.next_out = _sl.buf;
01182   _z.avail_out = 4096;
01183 
01184   do {
01185     /* read more bytes from the file?*/
01186     if (_z.avail_in == 0) {
01187       _z.avail_in = fread(_z.next_in = _sl.buf + 4096, 1, 4096, _sl.fh);
01188     }
01189 
01190     /* inflate the data */
01191     r = inflate(&_z, 0);
01192     if (r == Z_STREAM_END)
01193       break;
01194 
01195     if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
01196   } while (_z.avail_out);
01197 
01198   return 4096 - _z.avail_out;
01199 }
01200 
01201 static void UninitReadZlib()
01202 {
01203   inflateEnd(&_z);
01204   free(_sl.buf_ori);
01205 }
01206 
01207 static bool InitWriteZlib()
01208 {
01209   memset(&_z, 0, sizeof(_z));
01210   if (deflateInit(&_z, 6) != Z_OK) return false;
01211 
01212   _sl.bufsize = 4096;
01213   _sl.buf = _sl.buf_ori = MallocT<byte>(4096); // also contains fread buffer
01214   return true;
01215 }
01216 
01217 static void WriteZlibLoop(z_streamp z, byte *p, uint len, int mode)
01218 {
01219   byte buf[1024]; // output buffer
01220   int r;
01221   uint n;
01222   z->next_in = p;
01223   z->avail_in = len;
01224   do {
01225     z->next_out = buf;
01226     z->avail_out = sizeof(buf);
01227     r = deflate(z, mode);
01228       /* bytes were emitted? */
01229     if ((n=sizeof(buf) - z->avail_out) != 0) {
01230       if (fwrite(buf, n, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01231     }
01232     if (r == Z_STREAM_END)
01233       break;
01234     if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
01235   } while (z->avail_in || !z->avail_out);
01236 }
01237 
01238 static void WriteZlib(uint len)
01239 {
01240   WriteZlibLoop(&_z, _sl.buf, len, 0);
01241 }
01242 
01243 static void UninitWriteZlib()
01244 {
01245   /* flush any pending output. */
01246   if (_sl.fh) WriteZlibLoop(&_z, NULL, 0, Z_FINISH);
01247   deflateEnd(&_z);
01248   free(_sl.buf_ori);
01249 }
01250 
01251 #endif /* WITH_ZLIB */
01252 
01253 /*******************************************
01254  ************* END OF CODE *****************
01255  *******************************************/
01256 
01257 /* these define the chunks */
01258 extern const ChunkHandler _misc_chunk_handlers[];
01259 extern const ChunkHandler _setting_chunk_handlers[];
01260 extern const ChunkHandler _player_chunk_handlers[];
01261 extern const ChunkHandler _engine_chunk_handlers[];
01262 extern const ChunkHandler _veh_chunk_handlers[];
01263 extern const ChunkHandler _waypoint_chunk_handlers[];
01264 extern const ChunkHandler _depot_chunk_handlers[];
01265 extern const ChunkHandler _order_chunk_handlers[];
01266 extern const ChunkHandler _town_chunk_handlers[];
01267 extern const ChunkHandler _sign_chunk_handlers[];
01268 extern const ChunkHandler _station_chunk_handlers[];
01269 extern const ChunkHandler _industry_chunk_handlers[];
01270 extern const ChunkHandler _economy_chunk_handlers[];
01271 extern const ChunkHandler _animated_tile_chunk_handlers[];
01272 extern const ChunkHandler _newgrf_chunk_handlers[];
01273 extern const ChunkHandler _group_chunk_handlers[];
01274 extern const ChunkHandler _cargopacket_chunk_handlers[];
01275 
01276 static const ChunkHandler * const _chunk_handlers[] = {
01277   _misc_chunk_handlers,
01278   _setting_chunk_handlers,
01279   _veh_chunk_handlers,
01280   _waypoint_chunk_handlers,
01281   _depot_chunk_handlers,
01282   _order_chunk_handlers,
01283   _industry_chunk_handlers,
01284   _economy_chunk_handlers,
01285   _engine_chunk_handlers,
01286   _town_chunk_handlers,
01287   _sign_chunk_handlers,
01288   _station_chunk_handlers,
01289   _player_chunk_handlers,
01290   _animated_tile_chunk_handlers,
01291   _newgrf_chunk_handlers,
01292   _group_chunk_handlers,
01293   _cargopacket_chunk_handlers,
01294   NULL,
01295 };
01296 
01307 static uint ReferenceToInt(const void *obj, SLRefType rt)
01308 {
01309   if (obj == NULL) return 0;
01310 
01311   switch (rt) {
01312     case REF_VEHICLE_OLD: // Old vehicles we save as new onces
01313     case REF_VEHICLE:   return ((const  Vehicle*)obj)->index + 1;
01314     case REF_STATION:   return ((const  Station*)obj)->index + 1;
01315     case REF_TOWN:      return ((const     Town*)obj)->index + 1;
01316     case REF_ORDER:     return ((const    Order*)obj)->index + 1;
01317     case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01318     case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01319     case REF_CARGO_PACKET:  return ((const CargoPacket*)obj)->index + 1;
01320     default: NOT_REACHED();
01321   }
01322 
01323   return 0; // avoid compiler warning
01324 }
01325 
01336 static void *IntToReference(uint index, SLRefType rt)
01337 {
01338   /* After version 4.3 REF_VEHICLE_OLD is saved as REF_VEHICLE,
01339    * and should be loaded like that */
01340   if (rt == REF_VEHICLE_OLD && !CheckSavegameVersionOldStyle(4, 4)) {
01341     rt = REF_VEHICLE;
01342   }
01343 
01344   /* No need to look up NULL pointers, just return immediately */
01345   if (rt != REF_VEHICLE_OLD && index == 0) {
01346     return NULL;
01347   }
01348 
01349   index--; // correct for the NULL index
01350 
01351   switch (rt) {
01352     case REF_ORDER:
01353       if (_Order_pool.AddBlockIfNeeded(index)) return GetOrder(index);
01354       error("Orders: failed loading savegame: too many orders");
01355 
01356     case REF_VEHICLE:
01357       if (_Vehicle_pool.AddBlockIfNeeded(index)) return GetVehicle(index);
01358       error("Vehicles: failed loading savegame: too many vehicles");
01359 
01360     case REF_STATION:
01361       if (_Station_pool.AddBlockIfNeeded(index)) return GetStation(index);
01362       error("Stations: failed loading savegame: too many stations");
01363 
01364     case REF_TOWN:
01365       if (_Town_pool.AddBlockIfNeeded(index)) return GetTown(index);
01366       error("Towns: failed loading savegame: too many towns");
01367 
01368     case REF_ROADSTOPS:
01369       if (_RoadStop_pool.AddBlockIfNeeded(index)) return GetRoadStop(index);
01370       error("RoadStops: failed loading savegame: too many RoadStops");
01371 
01372     case REF_ENGINE_RENEWS:
01373       if (_EngineRenew_pool.AddBlockIfNeeded(index)) return GetEngineRenew(index);
01374       error("EngineRenews: failed loading savegame: too many EngineRenews");
01375 
01376     case REF_CARGO_PACKET:
01377       if (_CargoPacket_pool.AddBlockIfNeeded(index)) return GetCargoPacket(index);
01378       error("CargoPackets: failed loading savegame: too many Cargo packets");
01379 
01380     case REF_VEHICLE_OLD:
01381       /* Old vehicles were saved differently:
01382        * invalid vehicle was 0xFFFF,
01383        * and the index was not - 1.. correct for this */
01384       index++;
01385       if (index == INVALID_VEHICLE) return NULL;
01386 
01387       if (_Vehicle_pool.AddBlockIfNeeded(index)) return GetVehicle(index);
01388       error("Vehicles: failed loading savegame: too many vehicles");
01389 
01390     default: NOT_REACHED();
01391   }
01392 
01393   return NULL;
01394 }
01395 
01397 struct SaveLoadFormat {
01398   const char *name;           
01399   uint32 tag;                 
01400 
01401   bool (*init_read)();        
01402   ReaderProc *reader;         
01403   void (*uninit_read)();      
01404 
01405   bool (*init_write)();       
01406   WriterProc *writer;         
01407   void (*uninit_write)();     
01408 };
01409 
01410 static const SaveLoadFormat _saveload_formats[] = {
01411   {"memory", 0,                NULL,         NULL,       NULL,           InitMem,       WriteMem,    UnInitMem},
01412   {"lzo",    TO_BE32X('OTTD'), InitLZO,      ReadLZO,    UninitLZO,      InitLZO,       WriteLZO,    UninitLZO},
01413   {"none",   TO_BE32X('OTTN'), InitNoComp,   ReadNoComp, UninitNoComp,   InitNoComp,    WriteNoComp, UninitNoComp},
01414 #if defined(WITH_ZLIB)
01415   {"zlib",   TO_BE32X('OTTZ'), InitReadZlib, ReadZlib,   UninitReadZlib, InitWriteZlib, WriteZlib,   UninitWriteZlib},
01416 #else
01417   {"zlib",   TO_BE32X('OTTZ'), NULL,         NULL,       NULL,           NULL,          NULL,        NULL},
01418 #endif
01419 };
01420 
01427 static const SaveLoadFormat *GetSavegameFormat(const char *s)
01428 {
01429   const SaveLoadFormat *def = endof(_saveload_formats) - 1;
01430 
01431   /* find default savegame format, the highest one with which files can be written */
01432   while (!def->init_write) def--;
01433 
01434   if (s != NULL && s[0] != '\0') {
01435     const SaveLoadFormat *slf;
01436     for (slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
01437       if (slf->init_write != NULL && strcmp(s, slf->name) == 0)
01438         return slf;
01439     }
01440 
01441     ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
01442   }
01443   return def;
01444 }
01445 
01446 /* actual loader/saver function */
01447 void InitializeGame(int mode, uint size_x, uint size_y);
01448 extern bool AfterLoadGame();
01449 extern void BeforeSaveGame();
01450 extern bool LoadOldSaveGame(const char *file);
01451 
01453 static inline SaveOrLoadResult AbortSaveLoad()
01454 {
01455   if (_sl.fh != NULL) fclose(_sl.fh);
01456 
01457   _sl.fh = NULL;
01458   return SL_ERROR;
01459 }
01460 
01464 void SaveFileStart()
01465 {
01466   _ts.ff_state = _fast_forward;
01467   _fast_forward = 0;
01468   if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
01469 
01470   SendWindowMessage(WC_STATUS_BAR, 0, true, 0, 0);
01471   _ts.saveinprogress = true;
01472 }
01473 
01476 void SaveFileDone()
01477 {
01478   _fast_forward = _ts.ff_state;
01479   if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
01480 
01481   SendWindowMessage(WC_STATUS_BAR, 0, false, 0, 0);
01482   _ts.saveinprogress = false;
01483 }
01484 
01486 void SetSaveLoadError(StringID str)
01487 {
01488   _sl.error_str = str;
01489 }
01490 
01492 const char *GetSaveLoadErrorString()
01493 {
01494   SetDParam(0, _sl.error_str);
01495   SetDParamStr(1, _sl.extra_msg);
01496 
01497   static char err_str[512];
01498   GetString(err_str, _sl.save ? STR_4007_GAME_SAVE_FAILED : STR_4009_GAME_LOAD_FAILED, lastof(err_str));
01499   return err_str;
01500 }
01501 
01503 void SaveFileError()
01504 {
01505   SetDParamStr(0, GetSaveLoadErrorString());
01506   ShowErrorMessage(STR_012D, STR_NULL, 0, 0);
01507   SaveFileDone();
01508 }
01509 
01510 static OTTDThread* save_thread;
01511 
01515 static SaveOrLoadResult SaveFileToDisk(bool threaded)
01516 {
01517   const SaveLoadFormat *fmt;
01518   uint32 hdr[2];
01519 
01520   _sl.excpt_uninit = NULL;
01521   try {
01522     fmt = GetSavegameFormat(_savegame_format);
01523 
01524     /* We have written our stuff to memory, now write it to file! */
01525     hdr[0] = fmt->tag;
01526     hdr[1] = TO_BE32(SAVEGAME_VERSION << 16);
01527     if (fwrite(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01528 
01529     if (!fmt->init_write()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01530 
01531     {
01532       uint i;
01533       uint count = 1 << Savegame_POOL_BLOCK_SIZE_BITS;
01534 
01535       if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
01536       for (i = 0; i != _Savegame_pool.GetBlockCount() - 1; i++) {
01537         _sl.buf = _Savegame_pool.blocks[i];
01538         fmt->writer(count);
01539       }
01540 
01541       /* The last block is (almost) always not fully filled, so only write away
01542        * as much data as it is in there */
01543       _sl.buf = _Savegame_pool.blocks[i];
01544       fmt->writer(_ts.count - (i * count));
01545     }
01546 
01547     fmt->uninit_write();
01548     if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
01549     GetSavegameFormat("memory")->uninit_write(); // clean the memorypool
01550     fclose(_sl.fh);
01551 
01552     if (threaded) OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_DONE);
01553 
01554     return SL_OK;
01555   }
01556   catch (...) {
01557     AbortSaveLoad();
01558     if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
01559 
01560     ShowInfo(GetSaveLoadErrorString());
01561     fprintf(stderr, GetSaveLoadErrorString());
01562 
01563     if (threaded) {
01564       OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_ERROR);
01565     } else {
01566       SaveFileError();
01567     }
01568     return SL_ERROR;
01569   }
01570 }
01571 
01572 static void* SaveFileToDiskThread(void *arg)
01573 {
01574   SaveFileToDisk(true);
01575   return NULL;
01576 }
01577 
01578 void WaitTillSaved()
01579 {
01580   OTTDJoinThread(save_thread);
01581   save_thread = NULL;
01582 }
01583 
01591 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb)
01592 {
01593   uint32 hdr[2];
01594   const SaveLoadFormat *fmt;
01595 
01596   /* An instance of saving is already active, so don't go saving again */
01597   if (_ts.saveinprogress && mode == SL_SAVE) {
01598     /* if not an autosave, but a user action, show error message */
01599     if (!_do_autosave) ShowErrorMessage(INVALID_STRING_ID, STR_SAVE_STILL_IN_PROGRESS, 0, 0);
01600     return SL_OK;
01601   }
01602   WaitTillSaved();
01603 
01604   _next_offs = 0;
01605 
01606   /* Load a TTDLX or TTDPatch game */
01607   if (mode == SL_OLD_LOAD) {
01608     InitializeGame(IG_DATE_RESET, 256, 256); // set a mapsize of 256x256 for TTDPatch games or it might get confused
01609     if (!LoadOldSaveGame(filename)) return SL_REINIT;
01610     _sl_version = 0;
01611     if (!AfterLoadGame()) return SL_REINIT;
01612     return SL_OK;
01613   }
01614 
01615   _sl.excpt_uninit = NULL;
01616   try {
01617     _sl.fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
01618 
01619     /* Make it a little easier to load savegames from the console */
01620     if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", SAVE_DIR);
01621     if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", BASE_DIR);
01622 
01623     if (_sl.fh == NULL) {
01624       SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01625     }
01626 
01627     _sl.bufe = _sl.bufp = NULL;
01628     _sl.offs_base = 0;
01629     _sl.save = (mode != 0);
01630     _sl.chs = _chunk_handlers;
01631 
01632     /* General tactic is to first save the game to memory, then use an available writer
01633      * to write it to file, either in threaded mode if possible, or single-threaded */
01634     if (mode == SL_SAVE) { /* SAVE game */
01635       fmt = GetSavegameFormat("memory"); // write to memory
01636 
01637       _sl.write_bytes = fmt->writer;
01638       _sl.excpt_uninit = fmt->uninit_write;
01639       if (!fmt->init_write()) {
01640         DEBUG(sl, 0, "Initializing writer '%s' failed.", fmt->name);
01641         return AbortSaveLoad();
01642       }
01643 
01644       _sl_version = SAVEGAME_VERSION;
01645 
01646       BeforeSaveGame();
01647       SlSaveChunks();
01648       SlWriteFill(); // flush the save buffer
01649 
01650       SaveFileStart();
01651       if (_network_server ||
01652             (save_thread = OTTDCreateThread(&SaveFileToDiskThread, NULL)) == NULL) {
01653         if (!_network_server) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
01654 
01655         SaveOrLoadResult result = SaveFileToDisk(false);
01656         SaveFileDone();
01657 
01658         return result;
01659       }
01660     } else { /* LOAD game */
01661       assert(mode == SL_LOAD);
01662       DebugDumpCommands("ddc:load:%s\n", filename);
01663 
01664       if (fread(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01665 
01666       /* see if we have any loader for this type. */
01667       for (fmt = _saveload_formats; ; fmt++) {
01668         /* No loader found, treat as version 0 and use LZO format */
01669         if (fmt == endof(_saveload_formats)) {
01670           DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
01671   #if defined(WINCE)
01672           /* Of course some system had not to support rewind ;) */
01673           fseek(_sl.fh, 0L, SEEK_SET);
01674           clearerr(_sl.fh);
01675   #else
01676           rewind(_sl.fh);
01677   #endif
01678           _sl_version = 0;
01679           _sl_minor_version = 0;
01680           fmt = _saveload_formats + 1; // LZO
01681           break;
01682         }
01683 
01684         if (fmt->tag == hdr[0]) {
01685           /* check version number */
01686           _sl_version = TO_BE32(hdr[1]) >> 16;
01687           /* Minor is not used anymore from version 18.0, but it is still needed
01688            * in versions before that (4 cases) which can't be removed easy.
01689            * Therefor it is loaded, but never saved (or, it saves a 0 in any scenario).
01690            * So never EVER use this minor version again. -- TrueLight -- 22-11-2005 */
01691           _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
01692 
01693           DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
01694 
01695           /* Is the version higher than the current? */
01696           if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
01697           break;
01698         }
01699       }
01700 
01701       _sl.read_bytes = fmt->reader;
01702       _sl.excpt_uninit = fmt->uninit_read;
01703 
01704       /* loader for this savegame type is not implemented? */
01705       if (fmt->init_read == NULL) {
01706         char err_str[64];
01707         snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
01708         SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
01709       }
01710 
01711       if (!fmt->init_read()) {
01712         char err_str[64];
01713         snprintf(err_str, lengthof(err_str), "Initializing loader '%s' failed", fmt->name);
01714         SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
01715       }
01716 
01717       /* Old maps were hardcoded to 256x256 and thus did not contain
01718        * any mapsize information. Pre-initialize to 256x256 to not to
01719        * confuse old games */
01720       InitializeGame(IG_DATE_RESET, 256, 256);
01721 
01722       SlLoadChunks();
01723       fmt->uninit_read();
01724       fclose(_sl.fh);
01725 
01726       /* After loading fix up savegame for any internal changes that
01727        * might've occured since then. If it fails, load back the old game */
01728       if (!AfterLoadGame()) return SL_REINIT;
01729     }
01730 
01731     return SL_OK;
01732   }
01733   catch (...) {
01734     AbortSaveLoad();
01735 
01736     /* deinitialize compressor. */
01737     if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
01738 
01739     /* Skip the "color" character */
01740     ShowInfoF(GetSaveLoadErrorString() + 3);
01741 
01742     /* A saver/loader exception!! reinitialize all variables to prevent crash! */
01743     return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
01744   }
01745 }
01746 
01748 void DoExitSave()
01749 {
01750   SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
01751 }
01752 
01753 #if 0
01754 
01760 int GetSavegameType(char *file)
01761 {
01762   const SaveLoadFormat *fmt;
01763   uint32 hdr;
01764   FILE *f;
01765   int mode = SL_OLD_LOAD;
01766 
01767   f = fopen(file, "rb");
01768   if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
01769     DEBUG(sl, 0, "Savegame is obsolete or invalid format");
01770     mode = SL_LOAD; // don't try to get filename, just show name as it is written
01771   } else {
01772     /* see if we have any loader for this type. */
01773     for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
01774       if (fmt->tag == hdr) {
01775         mode = SL_LOAD; // new type of savegame
01776         break;
01777       }
01778     }
01779   }
01780 
01781   fclose(f);
01782   return mode;
01783 }
01784 #endif

Generated on Mon Sep 22 20:34:18 2008 for openttd by  doxygen 1.5.6