saveload.cpp

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

Generated on Mon Feb 16 23:12:10 2009 for openttd by  doxygen 1.5.6