saveload.cpp

Go to the documentation of this file.
00001 /* $Id: saveload.cpp 21731 2011-01-05 07:57:10Z rubidium $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00024 #include "../stdafx.h"
00025 #include "../debug.h"
00026 #include "../station_base.h"
00027 #include "../thread/thread.h"
00028 #include "../town.h"
00029 #include "../network/network.h"
00030 #include "../window_func.h"
00031 #include "../strings_func.h"
00032 #include "../core/endian_func.hpp"
00033 #include "../vehicle_base.h"
00034 #include "../company_func.h"
00035 #include "../date_func.h"
00036 #include "../autoreplace_base.h"
00037 #include "../roadstop_base.h"
00038 #include "../statusbar_gui.h"
00039 #include "../fileio_func.h"
00040 #include "../gamelog.h"
00041 #include "../string_func.h"
00042 #include "../engine_base.h"
00043 #include "../fios.h"
00044 #include "../gui.h"
00045 
00046 #include "table/strings.h"
00047 
00048 #include "saveload_internal.h"
00049 #include "saveload_filter.h"
00050 
00051 /*
00052  * Previous savegame versions, the trunk revision where they were
00053  * introduced and the released version that had that particular
00054  * savegame version.
00055  * Up to savegame version 18 there is a minor version as well.
00056  *
00057  *    1.0         0.1.x, 0.2.x
00058  *    2.0         0.3.0
00059  *    2.1         0.3.1, 0.3.2
00060  *    3.x         lost
00061  *    4.0     1
00062  *    4.1   122   0.3.3, 0.3.4
00063  *    4.2  1222   0.3.5
00064  *    4.3  1417
00065  *    4.4  1426
00066  *    5.0  1429
00067  *    5.1  1440
00068  *    5.2  1525   0.3.6
00069  *    6.0  1721
00070  *    6.1  1768
00071  *    7.0  1770
00072  *    8.0  1786
00073  *    9.0  1909
00074  *   10.0  2030
00075  *   11.0  2033
00076  *   11.1  2041
00077  *   12.1  2046
00078  *   13.1  2080   0.4.0, 0.4.0.1
00079  *   14.0  2441
00080  *   15.0  2499
00081  *   16.0  2817
00082  *   16.1  3155
00083  *   17.0  3212
00084  *   17.1  3218
00085  *   18    3227
00086  *   19    3396
00087  *   20    3403
00088  *   21    3472   0.4.x
00089  *   22    3726
00090  *   23    3915
00091  *   24    4150
00092  *   25    4259
00093  *   26    4466
00094  *   27    4757
00095  *   28    4987
00096  *   29    5070
00097  *   30    5946
00098  *   31    5999
00099  *   32    6001
00100  *   33    6440
00101  *   34    6455
00102  *   35    6602
00103  *   36    6624
00104  *   37    7182
00105  *   38    7195
00106  *   39    7269
00107  *   40    7326
00108  *   41    7348   0.5.x
00109  *   42    7573
00110  *   43    7642
00111  *   44    8144
00112  *   45    8501
00113  *   46    8705
00114  *   47    8735
00115  *   48    8935
00116  *   49    8969
00117  *   50    8973
00118  *   51    8978
00119  *   52    9066
00120  *   53    9316
00121  *   54    9613
00122  *   55    9638
00123  *   56    9667
00124  *   57    9691
00125  *   58    9762
00126  *   59    9779
00127  *   60    9874
00128  *   61    9892
00129  *   62    9905
00130  *   63    9956
00131  *   64   10006
00132  *   65   10210
00133  *   66   10211
00134  *   67   10236
00135  *   68   10266
00136  *   69   10319
00137  *   70   10541
00138  *   71   10567
00139  *   72   10601
00140  *   73   10903
00141  *   74   11030
00142  *   75   11107
00143  *   76   11139
00144  *   77   11172
00145  *   78   11176
00146  *   79   11188
00147  *   80   11228
00148  *   81   11244
00149  *   82   11410
00150  *   83   11589
00151  *   84   11822
00152  *   85   11874
00153  *   86   12042
00154  *   87   12129
00155  *   88   12134
00156  *   89   12160
00157  *   90   12293
00158  *   91   12347
00159  *   92   12381   0.6.x
00160  *   93   12648
00161  *   94   12816
00162  *   95   12924
00163  *   96   13226
00164  *   97   13256
00165  *   98   13375
00166  *   99   13838
00167  *  100   13952
00168  *  101   14233
00169  *  102   14332
00170  *  103   14598
00171  *  104   14735
00172  *  105   14803
00173  *  106   14919
00174  *  107   15027
00175  *  108   15045
00176  *  109   15075
00177  *  110   15148
00178  *  111   15190
00179  *  112   15290
00180  *  113   15340
00181  *  114   15601
00182  *  115   15695
00183  *  116   15893   0.7.x
00184  *  117   16037
00185  *  118   16129
00186  *  119   16242
00187  *  120   16439
00188  *  121   16694
00189  *  122   16855
00190  *  123   16909
00191  *  124   16993
00192  *  125   17113
00193  *  126   17433
00194  *  127   17439
00195  *  128   18281
00196  *  129   18292
00197  *  130   18404
00198  *  131   18481
00199  *  132   18522
00200  *  133   18674
00201  *  134   18703
00202  *  135   18719
00203  *  136   18764
00204  *  137   18912
00205  *  138   18942   1.0.x
00206  *  139   19346
00207  *  140   19382
00208  *  141   19799
00209  *  142   20003
00210  *  143   20048
00211  *  144   20334
00212  *  145   20376
00213  *  146   20446
00214  *  147   20621
00215  *  148   20659
00216  *  149   20832
00217  *  150   20857
00218  *  151   20918
00219  *  152   21171
00220  *  153   21263
00221  *  154   21426
00222  *  155   21453
00223  *  156   21728
00224  */
00225 extern const uint16 SAVEGAME_VERSION = 156; 
00226 
00227 SavegameType _savegame_type; 
00228 
00229 uint32 _ttdp_version;     
00230 uint16 _sl_version;       
00231 byte   _sl_minor_version; 
00232 char _savegame_format[8]; 
00233 bool _do_autosave;        
00234 
00236 enum SaveLoadAction {
00237   SLA_LOAD,        
00238   SLA_SAVE,        
00239   SLA_PTRS,        
00240   SLA_NULL,        
00241   SLA_LOAD_CHECK,  
00242 };
00243 
00244 enum NeedLength {
00245   NL_NONE = 0,       
00246   NL_WANTLENGTH = 1, 
00247   NL_CALCLENGTH = 2, 
00248 };
00249 
00251 static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
00252 
00254 struct ReadBuffer {
00255   byte buf[MEMORY_CHUNK_SIZE]; 
00256   byte *bufp;                  
00257   byte *bufe;                  
00258   LoadFilter *reader;          
00259   size_t read;                 
00260 
00265   ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0)
00266   {
00267   }
00268 
00269   FORCEINLINE byte ReadByte()
00270   {
00271     if (this->bufp == this->bufe) {
00272       size_t len = this->reader->Read(this->buf, lengthof(this->buf));
00273       if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
00274 
00275       this->read += len;
00276       this->bufp = this->buf;
00277       this->bufe = this->buf + len;
00278     }
00279 
00280     return *this->bufp++;
00281   }
00282 
00287   size_t GetSize() const
00288   {
00289     return this->read - (this->bufe - this->bufp);
00290   }
00291 };
00292 
00293 
00295 struct MemoryDumper {
00296   AutoFreeSmallVector<byte *, 16> blocks; 
00297   byte *buf;                              
00298   byte *bufe;                             
00299 
00301   MemoryDumper() : buf(NULL), bufe(NULL)
00302   {
00303   }
00304 
00309   FORCEINLINE void WriteByte(byte b)
00310   {
00311     /* Are we at the end of this chunk? */
00312     if (this->buf == this->bufe) {
00313       this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
00314       *this->blocks.Append() = this->buf;
00315       this->bufe = this->buf + MEMORY_CHUNK_SIZE;
00316     }
00317 
00318     *this->buf++ = b;
00319   }
00320 
00325   void Flush(SaveFilter *writer)
00326   {
00327     uint i = 0;
00328     size_t t = this->GetSize();
00329 
00330     while (t > 0) {
00331       size_t to_write = min(MEMORY_CHUNK_SIZE, t);
00332 
00333       writer->Write(this->blocks[i++], to_write);
00334       t -= to_write;
00335     }
00336 
00337     writer->Finish();
00338   }
00339 
00344   size_t GetSize() const
00345   {
00346     return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
00347   }
00348 };
00349 
00351 struct SaveLoadParams {
00352   SaveLoadAction action;               
00353   NeedLength need_length;              
00354   byte block_mode;                     
00355   bool error;                          
00356 
00357   size_t obj_len;                      
00358   int array_index, last_array_index;   
00359 
00360   MemoryDumper *dumper;                
00361   SaveFilter *sf;                      
00362 
00363   ReadBuffer *reader;                  
00364   LoadFilter *lf;                      
00365 
00366   StringID error_str;                  
00367   char *extra_msg;                     
00368 
00369   byte ff_state;                       
00370   bool saveinprogress;                 
00371 };
00372 
00373 static SaveLoadParams _sl; 
00374 
00375 /* these define the chunks */
00376 extern const ChunkHandler _gamelog_chunk_handlers[];
00377 extern const ChunkHandler _map_chunk_handlers[];
00378 extern const ChunkHandler _misc_chunk_handlers[];
00379 extern const ChunkHandler _name_chunk_handlers[];
00380 extern const ChunkHandler _cheat_chunk_handlers[] ;
00381 extern const ChunkHandler _setting_chunk_handlers[];
00382 extern const ChunkHandler _company_chunk_handlers[];
00383 extern const ChunkHandler _engine_chunk_handlers[];
00384 extern const ChunkHandler _veh_chunk_handlers[];
00385 extern const ChunkHandler _waypoint_chunk_handlers[];
00386 extern const ChunkHandler _depot_chunk_handlers[];
00387 extern const ChunkHandler _order_chunk_handlers[];
00388 extern const ChunkHandler _town_chunk_handlers[];
00389 extern const ChunkHandler _sign_chunk_handlers[];
00390 extern const ChunkHandler _station_chunk_handlers[];
00391 extern const ChunkHandler _industry_chunk_handlers[];
00392 extern const ChunkHandler _economy_chunk_handlers[];
00393 extern const ChunkHandler _subsidy_chunk_handlers[];
00394 extern const ChunkHandler _ai_chunk_handlers[];
00395 extern const ChunkHandler _animated_tile_chunk_handlers[];
00396 extern const ChunkHandler _newgrf_chunk_handlers[];
00397 extern const ChunkHandler _group_chunk_handlers[];
00398 extern const ChunkHandler _cargopacket_chunk_handlers[];
00399 extern const ChunkHandler _autoreplace_chunk_handlers[];
00400 extern const ChunkHandler _labelmaps_chunk_handlers[];
00401 extern const ChunkHandler _airport_chunk_handlers[];
00402 extern const ChunkHandler _object_chunk_handlers[];
00403 
00405 static const ChunkHandler * const _chunk_handlers[] = {
00406   _gamelog_chunk_handlers,
00407   _map_chunk_handlers,
00408   _misc_chunk_handlers,
00409   _name_chunk_handlers,
00410   _cheat_chunk_handlers,
00411   _setting_chunk_handlers,
00412   _veh_chunk_handlers,
00413   _waypoint_chunk_handlers,
00414   _depot_chunk_handlers,
00415   _order_chunk_handlers,
00416   _industry_chunk_handlers,
00417   _economy_chunk_handlers,
00418   _subsidy_chunk_handlers,
00419   _engine_chunk_handlers,
00420   _town_chunk_handlers,
00421   _sign_chunk_handlers,
00422   _station_chunk_handlers,
00423   _company_chunk_handlers,
00424   _ai_chunk_handlers,
00425   _animated_tile_chunk_handlers,
00426   _newgrf_chunk_handlers,
00427   _group_chunk_handlers,
00428   _cargopacket_chunk_handlers,
00429   _autoreplace_chunk_handlers,
00430   _labelmaps_chunk_handlers,
00431   _airport_chunk_handlers,
00432   _object_chunk_handlers,
00433   NULL,
00434 };
00435 
00440 #define FOR_ALL_CHUNK_HANDLERS(ch) \
00441   for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \
00442     for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1)
00443 
00445 static void SlNullPointers()
00446 {
00447   _sl.action = SLA_NULL;
00448 
00449   DEBUG(sl, 1, "Nulling pointers");
00450 
00451   FOR_ALL_CHUNK_HANDLERS(ch) {
00452     if (ch->ptrs_proc != NULL) {
00453       DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
00454       ch->ptrs_proc();
00455     }
00456   }
00457 
00458   DEBUG(sl, 1, "All pointers nulled");
00459 
00460   assert(_sl.action == SLA_NULL);
00461 }
00462 
00471 static void NORETURN SlError(StringID string, const char *extra_msg = NULL)
00472 {
00473   /* Distinguish between loading into _load_check_data vs. normal save/load. */
00474   if (_sl.action == SLA_LOAD_CHECK) {
00475     _load_check_data.error = string;
00476     free(_load_check_data.error_data);
00477     _load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00478   } else {
00479     _sl.error_str = string;
00480     free(_sl.extra_msg);
00481     _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
00482     /* We have to NULL all pointers here; we might be in a state where
00483      * the pointers are actually filled with indices, which means that
00484      * when we access them during cleaning the pool dereferences of
00485      * those indices will be made with segmentation faults as result. */
00486   }
00487   if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
00488   throw std::exception();
00489 }
00490 
00498 void NORETURN SlErrorCorrupt(const char *msg)
00499 {
00500   SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg);
00501 }
00502 
00503 
00504 typedef void (*AsyncSaveFinishProc)();                
00505 static AsyncSaveFinishProc _async_save_finish = NULL; 
00506 static ThreadObject *_save_thread;                    
00507 
00512 static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
00513 {
00514   if (_exit_game) return;
00515   while (_async_save_finish != NULL) CSleep(10);
00516 
00517   _async_save_finish = proc;
00518 }
00519 
00523 void ProcessAsyncSaveFinish()
00524 {
00525   if (_async_save_finish == NULL) return;
00526 
00527   _async_save_finish();
00528 
00529   _async_save_finish = NULL;
00530 
00531   if (_save_thread != NULL) {
00532     _save_thread->Join();
00533     delete _save_thread;
00534     _save_thread = NULL;
00535   }
00536 }
00537 
00542 byte SlReadByte()
00543 {
00544   return _sl.reader->ReadByte();
00545 }
00546 
00551 void SlWriteByte(byte b)
00552 {
00553   _sl.dumper->WriteByte(b);
00554 }
00555 
00556 static inline int SlReadUint16()
00557 {
00558   int x = SlReadByte() << 8;
00559   return x | SlReadByte();
00560 }
00561 
00562 static inline uint32 SlReadUint32()
00563 {
00564   uint32 x = SlReadUint16() << 16;
00565   return x | SlReadUint16();
00566 }
00567 
00568 static inline uint64 SlReadUint64()
00569 {
00570   uint32 x = SlReadUint32();
00571   uint32 y = SlReadUint32();
00572   return (uint64)x << 32 | y;
00573 }
00574 
00575 static inline void SlWriteUint16(uint16 v)
00576 {
00577   SlWriteByte(GB(v, 8, 8));
00578   SlWriteByte(GB(v, 0, 8));
00579 }
00580 
00581 static inline void SlWriteUint32(uint32 v)
00582 {
00583   SlWriteUint16(GB(v, 16, 16));
00584   SlWriteUint16(GB(v,  0, 16));
00585 }
00586 
00587 static inline void SlWriteUint64(uint64 x)
00588 {
00589   SlWriteUint32((uint32)(x >> 32));
00590   SlWriteUint32((uint32)x);
00591 }
00592 
00598 static inline void SlSkipBytes(size_t length)
00599 {
00600   for (; length != 0; length--) SlReadByte();
00601 }
00602 
00612 static uint SlReadSimpleGamma()
00613 {
00614   uint i = SlReadByte();
00615   if (HasBit(i, 7)) {
00616     i &= ~0x80;
00617     if (HasBit(i, 6)) {
00618       i &= ~0x40;
00619       if (HasBit(i, 5)) {
00620         i &= ~0x20;
00621         if (HasBit(i, 4)) {
00622           SlErrorCorrupt("Unsupported gamma");
00623         }
00624         i = (i << 8) | SlReadByte();
00625       }
00626       i = (i << 8) | SlReadByte();
00627     }
00628     i = (i << 8) | SlReadByte();
00629   }
00630   return i;
00631 }
00632 
00645 static void SlWriteSimpleGamma(size_t i)
00646 {
00647   if (i >= (1 << 7)) {
00648     if (i >= (1 << 14)) {
00649       if (i >= (1 << 21)) {
00650         assert(i < (1 << 28));
00651         SlWriteByte((byte)(0xE0 | (i >> 24)));
00652         SlWriteByte((byte)(i >> 16));
00653       } else {
00654         SlWriteByte((byte)(0xC0 | (i >> 16)));
00655       }
00656       SlWriteByte((byte)(i >> 8));
00657     } else {
00658       SlWriteByte((byte)(0x80 | (i >> 8)));
00659     }
00660   }
00661   SlWriteByte((byte)i);
00662 }
00663 
00665 static inline uint SlGetGammaLength(size_t i)
00666 {
00667   return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21));
00668 }
00669 
00670 static inline uint SlReadSparseIndex()
00671 {
00672   return SlReadSimpleGamma();
00673 }
00674 
00675 static inline void SlWriteSparseIndex(uint index)
00676 {
00677   SlWriteSimpleGamma(index);
00678 }
00679 
00680 static inline uint SlReadArrayLength()
00681 {
00682   return SlReadSimpleGamma();
00683 }
00684 
00685 static inline void SlWriteArrayLength(size_t length)
00686 {
00687   SlWriteSimpleGamma(length);
00688 }
00689 
00690 static inline uint SlGetArrayLength(size_t length)
00691 {
00692   return SlGetGammaLength(length);
00693 }
00694 
00701 static inline uint SlCalcConvMemLen(VarType conv)
00702 {
00703   static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
00704   byte length = GB(conv, 4, 4);
00705 
00706   switch (length << 4) {
00707     case SLE_VAR_STRB:
00708     case SLE_VAR_STRBQ:
00709     case SLE_VAR_STR:
00710     case SLE_VAR_STRQ:
00711       return SlReadArrayLength();
00712 
00713     default:
00714       assert(length < lengthof(conv_mem_size));
00715       return conv_mem_size[length];
00716   }
00717 }
00718 
00725 static inline byte SlCalcConvFileLen(VarType conv)
00726 {
00727   static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2};
00728   byte length = GB(conv, 0, 4);
00729   assert(length < lengthof(conv_file_size));
00730   return conv_file_size[length];
00731 }
00732 
00734 static inline size_t SlCalcRefLen()
00735 {
00736   return IsSavegameVersionBefore(69) ? 2 : 4;
00737 }
00738 
00739 void SlSetArrayIndex(uint index)
00740 {
00741   _sl.need_length = NL_WANTLENGTH;
00742   _sl.array_index = index;
00743 }
00744 
00745 static size_t _next_offs;
00746 
00751 int SlIterateArray()
00752 {
00753   int index;
00754 
00755   /* After reading in the whole array inside the loop
00756    * we must have read in all the data, so we must be at end of current block. */
00757   if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size");
00758 
00759   while (true) {
00760     uint length = SlReadArrayLength();
00761     if (length == 0) {
00762       _next_offs = 0;
00763       return -1;
00764     }
00765 
00766     _sl.obj_len = --length;
00767     _next_offs = _sl.reader->GetSize() + length;
00768 
00769     switch (_sl.block_mode) {
00770       case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break;
00771       case CH_ARRAY:        index = _sl.array_index++; break;
00772       default:
00773         DEBUG(sl, 0, "SlIterateArray error");
00774         return -1; // error
00775     }
00776 
00777     if (length != 0) return index;
00778   }
00779 }
00780 
00784 void SlSkipArray()
00785 {
00786   while (SlIterateArray() != -1) {
00787     SlSkipBytes(_next_offs - _sl.reader->GetSize());
00788   }
00789 }
00790 
00796 void SlSetLength(size_t length)
00797 {
00798   assert(_sl.action == SLA_SAVE);
00799 
00800   switch (_sl.need_length) {
00801     case NL_WANTLENGTH:
00802       _sl.need_length = NL_NONE;
00803       switch (_sl.block_mode) {
00804         case CH_RIFF:
00805           /* Ugly encoding of >16M RIFF chunks
00806            * The lower 24 bits are normal
00807            * The uppermost 4 bits are bits 24:27 */
00808           assert(length < (1 << 28));
00809           SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
00810           break;
00811         case CH_ARRAY:
00812           assert(_sl.last_array_index <= _sl.array_index);
00813           while (++_sl.last_array_index <= _sl.array_index) {
00814             SlWriteArrayLength(1);
00815           }
00816           SlWriteArrayLength(length + 1);
00817           break;
00818         case CH_SPARSE_ARRAY:
00819           SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index)); // Also include length of sparse index.
00820           SlWriteSparseIndex(_sl.array_index);
00821           break;
00822         default: NOT_REACHED();
00823       }
00824       break;
00825 
00826     case NL_CALCLENGTH:
00827       _sl.obj_len += (int)length;
00828       break;
00829 
00830     default: NOT_REACHED();
00831   }
00832 }
00833 
00840 static void SlCopyBytes(void *ptr, size_t length)
00841 {
00842   byte *p = (byte *)ptr;
00843 
00844   switch (_sl.action) {
00845     case SLA_LOAD_CHECK:
00846     case SLA_LOAD:
00847       for (; length != 0; length--) *p++ = SlReadByte();
00848       break;
00849     case SLA_SAVE:
00850       for (; length != 0; length--) SlWriteByte(*p++);
00851       break;
00852     default: NOT_REACHED();
00853   }
00854 }
00855 
00857 size_t SlGetFieldLength()
00858 {
00859   return _sl.obj_len;
00860 }
00861 
00869 int64 ReadValue(const void *ptr, VarType conv)
00870 {
00871   switch (GetVarMemType(conv)) {
00872     case SLE_VAR_BL:  return (*(bool *)ptr != 0);
00873     case SLE_VAR_I8:  return *(int8  *)ptr;
00874     case SLE_VAR_U8:  return *(byte  *)ptr;
00875     case SLE_VAR_I16: return *(int16 *)ptr;
00876     case SLE_VAR_U16: return *(uint16*)ptr;
00877     case SLE_VAR_I32: return *(int32 *)ptr;
00878     case SLE_VAR_U32: return *(uint32*)ptr;
00879     case SLE_VAR_I64: return *(int64 *)ptr;
00880     case SLE_VAR_U64: return *(uint64*)ptr;
00881     case SLE_VAR_NULL:return 0;
00882     default: NOT_REACHED();
00883   }
00884 }
00885 
00893 void WriteValue(void *ptr, VarType conv, int64 val)
00894 {
00895   switch (GetVarMemType(conv)) {
00896     case SLE_VAR_BL:  *(bool  *)ptr = (val != 0);  break;
00897     case SLE_VAR_I8:  *(int8  *)ptr = val; break;
00898     case SLE_VAR_U8:  *(byte  *)ptr = val; break;
00899     case SLE_VAR_I16: *(int16 *)ptr = val; break;
00900     case SLE_VAR_U16: *(uint16*)ptr = val; break;
00901     case SLE_VAR_I32: *(int32 *)ptr = val; break;
00902     case SLE_VAR_U32: *(uint32*)ptr = val; break;
00903     case SLE_VAR_I64: *(int64 *)ptr = val; break;
00904     case SLE_VAR_U64: *(uint64*)ptr = val; break;
00905     case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break;
00906     case SLE_VAR_NULL: break;
00907     default: NOT_REACHED();
00908   }
00909 }
00910 
00919 static void SlSaveLoadConv(void *ptr, VarType conv)
00920 {
00921   switch (_sl.action) {
00922     case SLA_SAVE: {
00923       int64 x = ReadValue(ptr, conv);
00924 
00925       /* Write the value to the file and check if its value is in the desired range */
00926       switch (GetVarFileType(conv)) {
00927         case SLE_FILE_I8: assert(x >= -128 && x <= 127);     SlWriteByte(x);break;
00928         case SLE_FILE_U8: assert(x >= 0 && x <= 255);        SlWriteByte(x);break;
00929         case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break;
00930         case SLE_FILE_STRINGID:
00931         case SLE_FILE_U16:assert(x >= 0 && x <= 65535);      SlWriteUint16(x);break;
00932         case SLE_FILE_I32:
00933         case SLE_FILE_U32:                                   SlWriteUint32((uint32)x);break;
00934         case SLE_FILE_I64:
00935         case SLE_FILE_U64:                                   SlWriteUint64(x);break;
00936         default: NOT_REACHED();
00937       }
00938       break;
00939     }
00940     case SLA_LOAD_CHECK:
00941     case SLA_LOAD: {
00942       int64 x;
00943       /* Read a value from the file */
00944       switch (GetVarFileType(conv)) {
00945         case SLE_FILE_I8:  x = (int8  )SlReadByte();   break;
00946         case SLE_FILE_U8:  x = (byte  )SlReadByte();   break;
00947         case SLE_FILE_I16: x = (int16 )SlReadUint16(); break;
00948         case SLE_FILE_U16: x = (uint16)SlReadUint16(); break;
00949         case SLE_FILE_I32: x = (int32 )SlReadUint32(); break;
00950         case SLE_FILE_U32: x = (uint32)SlReadUint32(); break;
00951         case SLE_FILE_I64: x = (int64 )SlReadUint64(); break;
00952         case SLE_FILE_U64: x = (uint64)SlReadUint64(); break;
00953         case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break;
00954         default: NOT_REACHED();
00955       }
00956 
00957       /* Write The value to the struct. These ARE endian safe. */
00958       WriteValue(ptr, conv, x);
00959       break;
00960     }
00961     case SLA_PTRS: break;
00962     case SLA_NULL: break;
00963     default: NOT_REACHED();
00964   }
00965 }
00966 
00976 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
00977 {
00978   if (ptr == NULL) return 0;
00979   return min(strlen(ptr), length - 1);
00980 }
00981 
00991 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
00992 {
00993   size_t len;
00994   const char *str;
00995 
00996   switch (GetVarMemType(conv)) {
00997     default: NOT_REACHED();
00998     case SLE_VAR_STR:
00999     case SLE_VAR_STRQ:
01000       str = *(const char**)ptr;
01001       len = SIZE_MAX;
01002       break;
01003     case SLE_VAR_STRB:
01004     case SLE_VAR_STRBQ:
01005       str = (const char*)ptr;
01006       len = length;
01007       break;
01008   }
01009 
01010   len = SlCalcNetStringLen(str, len);
01011   return len + SlGetArrayLength(len); // also include the length of the index
01012 }
01013 
01020 static void SlString(void *ptr, size_t length, VarType conv)
01021 {
01022   switch (_sl.action) {
01023     case SLA_SAVE: {
01024       size_t len;
01025       switch (GetVarMemType(conv)) {
01026         default: NOT_REACHED();
01027         case SLE_VAR_STRB:
01028         case SLE_VAR_STRBQ:
01029           len = SlCalcNetStringLen((char *)ptr, length);
01030           break;
01031         case SLE_VAR_STR:
01032         case SLE_VAR_STRQ:
01033           ptr = *(char **)ptr;
01034           len = SlCalcNetStringLen((char *)ptr, SIZE_MAX);
01035           break;
01036       }
01037 
01038       SlWriteArrayLength(len);
01039       SlCopyBytes(ptr, len);
01040       break;
01041     }
01042     case SLA_LOAD_CHECK:
01043     case SLA_LOAD: {
01044       size_t len = SlReadArrayLength();
01045 
01046       switch (GetVarMemType(conv)) {
01047         default: NOT_REACHED();
01048         case SLE_VAR_STRB:
01049         case SLE_VAR_STRBQ:
01050           if (len >= length) {
01051             DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
01052             SlCopyBytes(ptr, length);
01053             SlSkipBytes(len - length);
01054             len = length - 1;
01055           } else {
01056             SlCopyBytes(ptr, len);
01057           }
01058           break;
01059         case SLE_VAR_STR:
01060         case SLE_VAR_STRQ: // Malloc'd string, free previous incarnation, and allocate
01061           free(*(char **)ptr);
01062           if (len == 0) {
01063             *(char **)ptr = NULL;
01064           } else {
01065             *(char **)ptr = MallocT<char>(len + 1); // terminating '\0'
01066             ptr = *(char **)ptr;
01067             SlCopyBytes(ptr, len);
01068           }
01069           break;
01070       }
01071 
01072       ((char *)ptr)[len] = '\0'; // properly terminate the string
01073       str_validate((char *)ptr, (char *)ptr + len);
01074       break;
01075     }
01076     case SLA_PTRS: break;
01077     case SLA_NULL: break;
01078     default: NOT_REACHED();
01079   }
01080 }
01081 
01087 static inline size_t SlCalcArrayLen(size_t length, VarType conv)
01088 {
01089   return SlCalcConvFileLen(conv) * length;
01090 }
01091 
01098 void SlArray(void *array, size_t length, VarType conv)
01099 {
01100   if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return;
01101 
01102   /* Automatically calculate the length? */
01103   if (_sl.need_length != NL_NONE) {
01104     SlSetLength(SlCalcArrayLen(length, conv));
01105     /* Determine length only? */
01106     if (_sl.need_length == NL_CALCLENGTH) return;
01107   }
01108 
01109   /* NOTICE - handle some buggy stuff, in really old versions everything was saved
01110    * as a byte-type. So detect this, and adjust array size accordingly */
01111   if (_sl.action != SLA_SAVE && _sl_version == 0) {
01112     /* all arrays except difficulty settings */
01113     if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID ||
01114         conv == SLE_INT32 || conv == SLE_UINT32) {
01115       SlCopyBytes(array, length * SlCalcConvFileLen(conv));
01116       return;
01117     }
01118     /* used for conversion of Money 32bit->64bit */
01119     if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) {
01120       for (uint i = 0; i < length; i++) {
01121         ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32());
01122       }
01123       return;
01124     }
01125   }
01126 
01127   /* If the size of elements is 1 byte both in file and memory, no special
01128    * conversion is needed, use specialized copy-copy function to speed up things */
01129   if (conv == SLE_INT8 || conv == SLE_UINT8) {
01130     SlCopyBytes(array, length);
01131   } else {
01132     byte *a = (byte*)array;
01133     byte mem_size = SlCalcConvMemLen(conv);
01134 
01135     for (; length != 0; length --) {
01136       SlSaveLoadConv(a, conv);
01137       a += mem_size; // get size
01138     }
01139   }
01140 }
01141 
01142 
01153 static size_t ReferenceToInt(const void *obj, SLRefType rt)
01154 {
01155   assert(_sl.action == SLA_SAVE);
01156 
01157   if (obj == NULL) return 0;
01158 
01159   switch (rt) {
01160     case REF_VEHICLE_OLD: // Old vehicles we save as new onces
01161     case REF_VEHICLE:   return ((const  Vehicle*)obj)->index + 1;
01162     case REF_STATION:   return ((const  Station*)obj)->index + 1;
01163     case REF_TOWN:      return ((const     Town*)obj)->index + 1;
01164     case REF_ORDER:     return ((const    Order*)obj)->index + 1;
01165     case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
01166     case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
01167     case REF_CARGO_PACKET:  return ((const CargoPacket*)obj)->index + 1;
01168     case REF_ORDERLIST:     return ((const   OrderList*)obj)->index + 1;
01169     default: NOT_REACHED();
01170   }
01171 }
01172 
01183 static void *IntToReference(size_t index, SLRefType rt)
01184 {
01185   assert_compile(sizeof(size_t) <= sizeof(void *));
01186 
01187   assert(_sl.action == SLA_PTRS);
01188 
01189   /* After version 4.3 REF_VEHICLE_OLD is saved as REF_VEHICLE,
01190    * and should be loaded like that */
01191   if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) {
01192     rt = REF_VEHICLE;
01193   }
01194 
01195   /* No need to look up NULL pointers, just return immediately */
01196   if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL;
01197 
01198   /* Correct index. Old vehicles were saved differently:
01199    * invalid vehicle was 0xFFFF, now we use 0x0000 for everything invalid. */
01200   if (rt != REF_VEHICLE_OLD) index--;
01201 
01202   switch (rt) {
01203     case REF_ORDERLIST:
01204       if (OrderList::IsValidID(index)) return OrderList::Get(index);
01205       SlErrorCorrupt("Referencing invalid OrderList");
01206 
01207     case REF_ORDER:
01208       if (Order::IsValidID(index)) return Order::Get(index);
01209       /* in old versions, invalid order was used to mark end of order list */
01210       if (IsSavegameVersionBefore(5, 2)) return NULL;
01211       SlErrorCorrupt("Referencing invalid Order");
01212 
01213     case REF_VEHICLE_OLD:
01214     case REF_VEHICLE:
01215       if (Vehicle::IsValidID(index)) return Vehicle::Get(index);
01216       SlErrorCorrupt("Referencing invalid Vehicle");
01217 
01218     case REF_STATION:
01219       if (Station::IsValidID(index)) return Station::Get(index);
01220       SlErrorCorrupt("Referencing invalid Station");
01221 
01222     case REF_TOWN:
01223       if (Town::IsValidID(index)) return Town::Get(index);
01224       SlErrorCorrupt("Referencing invalid Town");
01225 
01226     case REF_ROADSTOPS:
01227       if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
01228       SlErrorCorrupt("Referencing invalid RoadStop");
01229 
01230     case REF_ENGINE_RENEWS:
01231       if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
01232       SlErrorCorrupt("Referencing invalid EngineRenew");
01233 
01234     case REF_CARGO_PACKET:
01235       if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index);
01236       SlErrorCorrupt("Referencing invalid CargoPacket");
01237 
01238     default: NOT_REACHED();
01239   }
01240 }
01241 
01246 static inline size_t SlCalcListLen(const void *list)
01247 {
01248   std::list<void *> *l = (std::list<void *> *) list;
01249 
01250   int type_size = IsSavegameVersionBefore(69) ? 2 : 4;
01251   /* Each entry is saved as type_size bytes, plus type_size bytes are used for the length
01252    * of the list */
01253   return l->size() * type_size + type_size;
01254 }
01255 
01256 
01262 static void SlList(void *list, SLRefType conv)
01263 {
01264   /* Automatically calculate the length? */
01265   if (_sl.need_length != NL_NONE) {
01266     SlSetLength(SlCalcListLen(list));
01267     /* Determine length only? */
01268     if (_sl.need_length == NL_CALCLENGTH) return;
01269   }
01270 
01271   typedef std::list<void *> PtrList;
01272   PtrList *l = (PtrList *)list;
01273 
01274   switch (_sl.action) {
01275     case SLA_SAVE: {
01276       SlWriteUint32((uint32)l->size());
01277 
01278       PtrList::iterator iter;
01279       for (iter = l->begin(); iter != l->end(); ++iter) {
01280         void *ptr = *iter;
01281         SlWriteUint32((uint32)ReferenceToInt(ptr, conv));
01282       }
01283       break;
01284     }
01285     case SLA_LOAD_CHECK:
01286     case SLA_LOAD: {
01287       size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01288 
01289       /* Load each reference and push to the end of the list */
01290       for (size_t i = 0; i < length; i++) {
01291         size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01292         l->push_back((void *)data);
01293       }
01294       break;
01295     }
01296     case SLA_PTRS: {
01297       PtrList temp = *l;
01298 
01299       l->clear();
01300       PtrList::iterator iter;
01301       for (iter = temp.begin(); iter != temp.end(); ++iter) {
01302         void *ptr = IntToReference((size_t)*iter, conv);
01303         l->push_back(ptr);
01304       }
01305       break;
01306     }
01307     case SLA_NULL:
01308       l->clear();
01309       break;
01310     default: NOT_REACHED();
01311   }
01312 }
01313 
01314 
01316 static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld)
01317 {
01318   if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false;
01319   if (sld->conv & SLF_SAVE_NO) return false;
01320 
01321   return true;
01322 }
01323 
01329 static inline bool SlSkipVariableOnLoad(const SaveLoad *sld)
01330 {
01331   if ((sld->conv & SLF_NETWORK_NO) && _sl.action != SLA_SAVE && _networking && !_network_server) {
01332     SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length);
01333     return true;
01334   }
01335 
01336   return false;
01337 }
01338 
01345 size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
01346 {
01347   size_t length = 0;
01348 
01349   /* Need to determine the length and write a length tag. */
01350   for (; sld->cmd != SL_END; sld++) {
01351     length += SlCalcObjMemberLength(object, sld);
01352   }
01353   return length;
01354 }
01355 
01356 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
01357 {
01358   assert(_sl.action == SLA_SAVE);
01359 
01360   switch (sld->cmd) {
01361     case SL_VAR:
01362     case SL_REF:
01363     case SL_ARR:
01364     case SL_STR:
01365     case SL_LST:
01366       /* CONDITIONAL saveload types depend on the savegame version */
01367       if (!SlIsObjectValidInSavegame(sld)) break;
01368 
01369       switch (sld->cmd) {
01370         case SL_VAR: return SlCalcConvFileLen(sld->conv);
01371         case SL_REF: return SlCalcRefLen();
01372         case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
01373         case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
01374         case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld));
01375         default: NOT_REACHED();
01376       }
01377       break;
01378     case SL_WRITEBYTE: return 1; // a byte is logically of size 1
01379     case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
01380     case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
01381     default: NOT_REACHED();
01382   }
01383   return 0;
01384 }
01385 
01386 
01387 bool SlObjectMember(void *ptr, const SaveLoad *sld)
01388 {
01389   VarType conv = GB(sld->conv, 0, 8);
01390   switch (sld->cmd) {
01391     case SL_VAR:
01392     case SL_REF:
01393     case SL_ARR:
01394     case SL_STR:
01395     case SL_LST:
01396       /* CONDITIONAL saveload types depend on the savegame version */
01397       if (!SlIsObjectValidInSavegame(sld)) return false;
01398       if (SlSkipVariableOnLoad(sld)) return false;
01399 
01400       switch (sld->cmd) {
01401         case SL_VAR: SlSaveLoadConv(ptr, conv); break;
01402         case SL_REF: // Reference variable, translate
01403           switch (_sl.action) {
01404             case SLA_SAVE:
01405               SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
01406               break;
01407             case SLA_LOAD_CHECK:
01408             case SLA_LOAD:
01409               *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32();
01410               break;
01411             case SLA_PTRS:
01412               *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv);
01413               break;
01414             case SLA_NULL:
01415               *(void **)ptr = NULL;
01416               break;
01417             default: NOT_REACHED();
01418           }
01419           break;
01420         case SL_ARR: SlArray(ptr, sld->length, conv); break;
01421         case SL_STR: SlString(ptr, sld->length, conv); break;
01422         case SL_LST: SlList(ptr, (SLRefType)conv); break;
01423         default: NOT_REACHED();
01424       }
01425       break;
01426 
01427     /* SL_WRITEBYTE translates a value of a variable to another one upon
01428      * saving or loading.
01429      * XXX - variable renaming abuse
01430      * game_value: the value of the variable ingame is abused by sld->version_from
01431      * file_value: the value of the variable in the savegame is abused by sld->version_to */
01432     case SL_WRITEBYTE:
01433       switch (_sl.action) {
01434         case SLA_SAVE: SlWriteByte(sld->version_to); break;
01435         case SLA_LOAD_CHECK:
01436         case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
01437         case SLA_PTRS: break;
01438         case SLA_NULL: break;
01439         default: NOT_REACHED();
01440       }
01441       break;
01442 
01443     /* SL_VEH_INCLUDE loads common code for vehicles */
01444     case SL_VEH_INCLUDE:
01445       SlObject(ptr, GetVehicleDescription(VEH_END));
01446       break;
01447 
01448     case SL_ST_INCLUDE:
01449       SlObject(ptr, GetBaseStationDescription());
01450       break;
01451 
01452     default: NOT_REACHED();
01453   }
01454   return true;
01455 }
01456 
01462 void SlObject(void *object, const SaveLoad *sld)
01463 {
01464   /* Automatically calculate the length? */
01465   if (_sl.need_length != NL_NONE) {
01466     SlSetLength(SlCalcObjLength(object, sld));
01467     if (_sl.need_length == NL_CALCLENGTH) return;
01468   }
01469 
01470   for (; sld->cmd != SL_END; sld++) {
01471     void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
01472     SlObjectMember(ptr, sld);
01473   }
01474 }
01475 
01480 void SlGlobList(const SaveLoadGlobVarList *sldg)
01481 {
01482   SlObject(NULL, (const SaveLoad*)sldg);
01483 }
01484 
01490 void SlAutolength(AutolengthProc *proc, void *arg)
01491 {
01492   size_t offs;
01493 
01494   assert(_sl.action == SLA_SAVE);
01495 
01496   /* Tell it to calculate the length */
01497   _sl.need_length = NL_CALCLENGTH;
01498   _sl.obj_len = 0;
01499   proc(arg);
01500 
01501   /* Setup length */
01502   _sl.need_length = NL_WANTLENGTH;
01503   SlSetLength(_sl.obj_len);
01504 
01505   offs = _sl.dumper->GetSize() + _sl.obj_len;
01506 
01507   /* And write the stuff */
01508   proc(arg);
01509 
01510   if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
01511 }
01512 
01517 static void SlLoadChunk(const ChunkHandler *ch)
01518 {
01519   byte m = SlReadByte();
01520   size_t len;
01521   size_t endoffs;
01522 
01523   _sl.block_mode = m;
01524   _sl.obj_len = 0;
01525 
01526   switch (m) {
01527     case CH_ARRAY:
01528       _sl.array_index = 0;
01529       ch->load_proc();
01530       break;
01531     case CH_SPARSE_ARRAY:
01532       ch->load_proc();
01533       break;
01534     default:
01535       if ((m & 0xF) == CH_RIFF) {
01536         /* Read length */
01537         len = (SlReadByte() << 16) | ((m >> 4) << 24);
01538         len += SlReadUint16();
01539         _sl.obj_len = len;
01540         endoffs = _sl.reader->GetSize() + len;
01541         ch->load_proc();
01542         if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01543       } else {
01544         SlErrorCorrupt("Invalid chunk type");
01545       }
01546       break;
01547   }
01548 }
01549 
01555 static void SlLoadCheckChunk(const ChunkHandler *ch)
01556 {
01557   byte m = SlReadByte();
01558   size_t len;
01559   size_t endoffs;
01560 
01561   _sl.block_mode = m;
01562   _sl.obj_len = 0;
01563 
01564   switch (m) {
01565     case CH_ARRAY:
01566       _sl.array_index = 0;
01567       if (ch->load_check_proc) {
01568         ch->load_check_proc();
01569       } else {
01570         SlSkipArray();
01571       }
01572       break;
01573     case CH_SPARSE_ARRAY:
01574       if (ch->load_check_proc) {
01575         ch->load_check_proc();
01576       } else {
01577         SlSkipArray();
01578       }
01579       break;
01580     default:
01581       if ((m & 0xF) == CH_RIFF) {
01582         /* Read length */
01583         len = (SlReadByte() << 16) | ((m >> 4) << 24);
01584         len += SlReadUint16();
01585         _sl.obj_len = len;
01586         endoffs = _sl.reader->GetSize() + len;
01587         if (ch->load_check_proc) {
01588           ch->load_check_proc();
01589         } else {
01590           SlSkipBytes(len);
01591         }
01592         if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size");
01593       } else {
01594         SlErrorCorrupt("Invalid chunk type");
01595       }
01596       break;
01597   }
01598 }
01599 
01604 static ChunkSaveLoadProc *_stub_save_proc;
01605 
01611 static inline void SlStubSaveProc2(void *arg)
01612 {
01613   _stub_save_proc();
01614 }
01615 
01621 static void SlStubSaveProc()
01622 {
01623   SlAutolength(SlStubSaveProc2, NULL);
01624 }
01625 
01631 static void SlSaveChunk(const ChunkHandler *ch)
01632 {
01633   ChunkSaveLoadProc *proc = ch->save_proc;
01634 
01635   /* Don't save any chunk information if there is no save handler. */
01636   if (proc == NULL) return;
01637 
01638   SlWriteUint32(ch->id);
01639   DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01640 
01641   if (ch->flags & CH_AUTO_LENGTH) {
01642     /* Need to calculate the length. Solve that by calling SlAutoLength in the save_proc. */
01643     _stub_save_proc = proc;
01644     proc = SlStubSaveProc;
01645   }
01646 
01647   _sl.block_mode = ch->flags & CH_TYPE_MASK;
01648   switch (ch->flags & CH_TYPE_MASK) {
01649     case CH_RIFF:
01650       _sl.need_length = NL_WANTLENGTH;
01651       proc();
01652       break;
01653     case CH_ARRAY:
01654       _sl.last_array_index = 0;
01655       SlWriteByte(CH_ARRAY);
01656       proc();
01657       SlWriteArrayLength(0); // Terminate arrays
01658       break;
01659     case CH_SPARSE_ARRAY:
01660       SlWriteByte(CH_SPARSE_ARRAY);
01661       proc();
01662       SlWriteArrayLength(0); // Terminate arrays
01663       break;
01664     default: NOT_REACHED();
01665   }
01666 }
01667 
01669 static void SlSaveChunks()
01670 {
01671   FOR_ALL_CHUNK_HANDLERS(ch) {
01672     SlSaveChunk(ch);
01673   }
01674 
01675   /* Terminator */
01676   SlWriteUint32(0);
01677 }
01678 
01685 static const ChunkHandler *SlFindChunkHandler(uint32 id)
01686 {
01687   FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch;
01688   return NULL;
01689 }
01690 
01692 static void SlLoadChunks()
01693 {
01694   uint32 id;
01695   const ChunkHandler *ch;
01696 
01697   for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01698     DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01699 
01700     ch = SlFindChunkHandler(id);
01701     if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01702     SlLoadChunk(ch);
01703   }
01704 }
01705 
01707 static void SlLoadCheckChunks()
01708 {
01709   uint32 id;
01710   const ChunkHandler *ch;
01711 
01712   for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
01713     DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
01714 
01715     ch = SlFindChunkHandler(id);
01716     if (ch == NULL) SlErrorCorrupt("Unknown chunk type");
01717     SlLoadCheckChunk(ch);
01718   }
01719 }
01720 
01722 static void SlFixPointers()
01723 {
01724   _sl.action = SLA_PTRS;
01725 
01726   DEBUG(sl, 1, "Fixing pointers");
01727 
01728   FOR_ALL_CHUNK_HANDLERS(ch) {
01729     if (ch->ptrs_proc != NULL) {
01730       DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id);
01731       ch->ptrs_proc();
01732     }
01733   }
01734 
01735   DEBUG(sl, 1, "All pointers fixed");
01736 
01737   assert(_sl.action == SLA_PTRS);
01738 }
01739 
01740 
01742 struct FileReader : LoadFilter {
01743   FILE *file; 
01744   long begin; 
01745 
01750   FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file))
01751   {
01752   }
01753 
01755   ~FileReader()
01756   {
01757     if (this->file != NULL) fclose(this->file);
01758     this->file = NULL;
01759 
01760     /* Make sure we don't double free. */
01761     _sl.sf = NULL;
01762   }
01763 
01764   /* virtual */ size_t Read(byte *buf, size_t size)
01765   {
01766     /* We're in the process of shutting down, i.e. in "failure" mode. */
01767     if (this->file == NULL) return 0;
01768 
01769     return fread(buf, 1, size, this->file);
01770   }
01771 
01772   /* virtual */ void Reset()
01773   {
01774     clearerr(this->file);
01775     fseek(this->file, this->begin, SEEK_SET);
01776   }
01777 };
01778 
01780 struct FileWriter : SaveFilter {
01781   FILE *file; 
01782 
01787   FileWriter(FILE *file) : SaveFilter(NULL), file(file)
01788   {
01789   }
01790 
01792   ~FileWriter()
01793   {
01794     this->Finish();
01795 
01796     /* Make sure we don't double free. */
01797     _sl.sf = NULL;
01798   }
01799 
01800   /* virtual */ void Write(byte *buf, size_t size)
01801   {
01802     /* We're in the process of shutting down, i.e. in "failure" mode. */
01803     if (this->file == NULL) return;
01804 
01805     if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
01806   }
01807 
01808   /* virtual */ void Finish()
01809   {
01810     if (this->file != NULL) fclose(this->file);
01811     this->file = NULL;
01812   }
01813 };
01814 
01815 /*******************************************
01816  ********** START OF LZO CODE **************
01817  *******************************************/
01818 
01819 #ifdef WITH_LZO
01820 #include <lzo/lzo1x.h>
01821 
01823 static const uint LZO_BUFFER_SIZE = 8192;
01824 
01826 struct LZOLoadFilter : LoadFilter {
01831   LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01832   {
01833     if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01834   }
01835 
01836   /* virtual */ size_t Read(byte *buf, size_t ssize)
01837   {
01838     assert(ssize >= LZO_BUFFER_SIZE);
01839 
01840     /* Buffer size is from the LZO docs plus the chunk header size. */
01841     byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01842     uint32 tmp[2];
01843     uint32 size;
01844     lzo_uint len;
01845 
01846     /* Read header*/
01847     if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed");
01848 
01849     /* Check if size is bad */
01850     ((uint32*)out)[0] = size = tmp[1];
01851 
01852     if (_sl_version != 0) {
01853       tmp[0] = TO_BE32(tmp[0]);
01854       size = TO_BE32(size);
01855     }
01856 
01857     if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size");
01858 
01859     /* Read block */
01860     if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
01861 
01862     /* Verify checksum */
01863     if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
01864 
01865     /* Decompress */
01866     lzo1x_decompress(out + sizeof(uint32) * 1, size, buf, &len, NULL);
01867     return len;
01868   }
01869 };
01870 
01872 struct LZOSaveFilter : SaveFilter {
01878   LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01879   {
01880     if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
01881   }
01882 
01883   /* virtual */ void Write(byte *buf, size_t size)
01884   {
01885     const lzo_bytep in = buf;
01886     /* Buffer size is from the LZO docs plus the chunk header size. */
01887     byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2];
01888     byte wrkmem[LZO1X_1_MEM_COMPRESS];
01889     lzo_uint outlen;
01890 
01891     do {
01892       /* Compress up to LZO_BUFFER_SIZE bytes at once. */
01893       lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size;
01894       lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem);
01895       ((uint32*)out)[1] = TO_BE32((uint32)outlen);
01896       ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
01897       this->chain->Write(out, outlen + sizeof(uint32) * 2);
01898 
01899       /* Move to next data chunk. */
01900       size -= len;
01901       in += len;
01902     } while (size > 0);
01903   }
01904 };
01905 
01906 #endif /* WITH_LZO */
01907 
01908 /*********************************************
01909  ******** START OF NOCOMP CODE (uncompressed)*
01910  *********************************************/
01911 
01913 struct NoCompLoadFilter : LoadFilter {
01918   NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01919   {
01920   }
01921 
01922   /* virtual */ size_t Read(byte *buf, size_t size)
01923   {
01924     return this->chain->Read(buf, size);
01925   }
01926 };
01927 
01929 struct NoCompSaveFilter : SaveFilter {
01935   NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
01936   {
01937   }
01938 
01939   /* virtual */ void Write(byte *buf, size_t size)
01940   {
01941     this->chain->Write(buf, size);
01942   }
01943 };
01944 
01945 /********************************************
01946  ********** START OF ZLIB CODE **************
01947  ********************************************/
01948 
01949 #if defined(WITH_ZLIB)
01950 #include <zlib.h>
01951 
01953 struct ZlibLoadFilter : LoadFilter {
01954   z_stream z;                        
01955   byte fread_buf[MEMORY_CHUNK_SIZE]; 
01956 
01961   ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain)
01962   {
01963     memset(&this->z, 0, sizeof(this->z));
01964     if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
01965   }
01966 
01968   ~ZlibLoadFilter()
01969   {
01970     inflateEnd(&this->z);
01971   }
01972 
01973   /* virtual */ size_t Read(byte *buf, size_t size)
01974   {
01975     this->z.next_out  = buf;
01976     this->z.avail_out = (uint)size;
01977 
01978     do {
01979       /* read more bytes from the file? */
01980       if (this->z.avail_in == 0) {
01981         this->z.next_in = this->fread_buf;
01982         this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
01983       }
01984 
01985       /* inflate the data */
01986       int r = inflate(&this->z, 0);
01987       if (r == Z_STREAM_END) break;
01988 
01989       if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed");
01990     } while (this->z.avail_out != 0);
01991 
01992     return size - this->z.avail_out;
01993   }
01994 };
01995 
01997 struct ZlibSaveFilter : SaveFilter {
01998   z_stream z; 
01999 
02005   ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain)
02006   {
02007     memset(&this->z, 0, sizeof(this->z));
02008     if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02009   }
02010 
02017   void WriteLoop(byte *p, size_t len, int mode)
02018   {
02019     byte buf[MEMORY_CHUNK_SIZE]; // output buffer
02020     uint n;
02021     this->z.next_in = p;
02022     this->z.avail_in = (uInt)len;
02023     do {
02024       this->z.next_out = buf;
02025       this->z.avail_out = sizeof(buf);
02026 
02034       int r = deflate(&this->z, mode);
02035 
02036       /* bytes were emitted? */
02037       if ((n = sizeof(buf) - this->z.avail_out) != 0) {
02038         this->chain->Write(buf, n);
02039       }
02040       if (r == Z_STREAM_END) break;
02041 
02042       if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code");
02043     } while (this->z.avail_in || !this->z.avail_out);
02044   }
02045 
02046   /* virtual */ void Write(byte *buf, size_t size)
02047   {
02048     this->WriteLoop(buf, size, 0);
02049   }
02050 
02051   /* virtual */ void Finish()
02052   {
02053     this->WriteLoop(NULL, 0, Z_FINISH);
02054     this->chain->Finish();
02055     deflateEnd(&this->z);
02056   }
02057 };
02058 
02059 #endif /* WITH_ZLIB */
02060 
02061 /********************************************
02062  ********** START OF LZMA CODE **************
02063  ********************************************/
02064 
02065 #if defined(WITH_LZMA)
02066 #include <lzma.h>
02067 
02074 static const lzma_stream _lzma_init = LZMA_STREAM_INIT;
02075 
02077 struct LZMALoadFilter : LoadFilter {
02078   lzma_stream lzma;                  
02079   byte fread_buf[MEMORY_CHUNK_SIZE]; 
02080 
02085   LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init)
02086   {
02087     /* Allow saves up to 256 MB uncompressed */
02088     if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor");
02089   }
02090 
02092   ~LZMALoadFilter()
02093   {
02094     lzma_end(&this->lzma);
02095   }
02096 
02097   /* virtual */ size_t Read(byte *buf, size_t size)
02098   {
02099     this->lzma.next_out  = buf;
02100     this->lzma.avail_out = size;
02101 
02102     do {
02103       /* read more bytes from the file? */
02104       if (this->lzma.avail_in == 0) {
02105         this->lzma.next_in  = this->fread_buf;
02106         this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf));
02107       }
02108 
02109       /* inflate the data */
02110       lzma_ret r = lzma_code(&this->lzma, LZMA_RUN);
02111       if (r == LZMA_STREAM_END) break;
02112       if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02113     } while (this->lzma.avail_out != 0);
02114 
02115     return size - this->lzma.avail_out;
02116   }
02117 };
02118 
02120 struct LZMASaveFilter : SaveFilter {
02121   lzma_stream lzma; 
02122 
02128   LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init)
02129   {
02130     if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
02131   }
02132 
02139   void WriteLoop(byte *p, size_t len, lzma_action action)
02140   {
02141     byte buf[MEMORY_CHUNK_SIZE]; // output buffer
02142     size_t n;
02143     this->lzma.next_in = p;
02144     this->lzma.avail_in = len;
02145     do {
02146       this->lzma.next_out = buf;
02147       this->lzma.avail_out = sizeof(buf);
02148 
02149       lzma_ret r = lzma_code(&this->lzma, action);
02150 
02151       /* bytes were emitted? */
02152       if ((n = sizeof(buf) - this->lzma.avail_out) != 0) {
02153         this->chain->Write(buf, n);
02154       }
02155       if (r == LZMA_STREAM_END) break;
02156       if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code");
02157     } while (this->lzma.avail_in || !this->lzma.avail_out);
02158   }
02159 
02160   /* virtual */ void Write(byte *buf, size_t size)
02161   {
02162     this->WriteLoop(buf, size, LZMA_RUN);
02163   }
02164 
02165   /* virtual */ void Finish()
02166   {
02167     this->WriteLoop(NULL, 0, LZMA_FINISH);
02168     this->chain->Finish();
02169     lzma_end(&this->lzma);
02170   }
02171 };
02172 
02173 #endif /* WITH_LZMA */
02174 
02175 /*******************************************
02176  ************* END OF CODE *****************
02177  *******************************************/
02178 
02180 struct SaveLoadFormat {
02181   const char *name;                     
02182   uint32 tag;                           
02183 
02184   LoadFilter *(*init_load)(LoadFilter *chain);                    
02185   SaveFilter *(*init_write)(SaveFilter *chain, byte compression); 
02186 
02187   byte min_compression;                 
02188   byte default_compression;             
02189   byte max_compression;                 
02190 };
02191 
02193 static const SaveLoadFormat _saveload_formats[] = {
02194 #if defined(WITH_LZO)
02195   /* Roughly 75% larger than zlib level 6 at only ~7% of the CPU usage. */
02196   {"lzo",    TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>,    CreateSaveFilter<LZOSaveFilter>,    0, 0, 0},
02197 #else
02198   {"lzo",    TO_BE32X('OTTD'), NULL,                               NULL,                               0, 0, 0},
02199 #endif
02200   /* Roughly 5 times larger at only 1% of the CPU usage over zlib level 6. */
02201   {"none",   TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
02202 #if defined(WITH_ZLIB)
02203   /* After level 6 the speed reduction is significant (1.5x to 2.5x slower per level), but the reduction in filesize is
02204    * fairly insignificant (~1% for each step). Lower levels become ~5-10% bigger by each level than level 6 while level
02205    * 1 is "only" 3 times as fast. Level 0 results in uncompressed savegames at about 8 times the cost of "none". */
02206   {"zlib",   TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>,   CreateSaveFilter<ZlibSaveFilter>,   0, 6, 9},
02207 #else
02208   {"zlib",   TO_BE32X('OTTZ'), NULL,                               NULL,                               0, 0, 0},
02209 #endif
02210 #if defined(WITH_LZMA)
02211   /* Level 2 compression is speed wise as fast as zlib level 6 compression (old default), but results in ~10% smaller saves.
02212    * Higher compression levels are possible, and might improve savegame size by up to 25%, but are also up to 10 times slower.
02213    * The next significant reduction in file size is at level 4, but that is already 4 times slower. Level 3 is primarily 50%
02214    * slower while not improving the filesize, while level 0 and 1 are faster, but don't reduce savegame size much.
02215    * It's OTTX and not e.g. OTTL because liblzma is part of xz-utils and .tar.xz is prefered over .tar.lzma. */
02216   {"lzma",   TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>,   CreateSaveFilter<LZMASaveFilter>,   0, 2, 9},
02217 #else
02218   {"lzma",   TO_BE32X('OTTX'), NULL,                               NULL,                               0, 0, 0},
02219 #endif
02220 };
02221 
02229 static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
02230 {
02231   const SaveLoadFormat *def = lastof(_saveload_formats);
02232 
02233   /* find default savegame format, the highest one with which files can be written */
02234   while (!def->init_write) def--;
02235 
02236   if (!StrEmpty(s)) {
02237     /* Get the ":..." of the compression level out of the way */
02238     char *complevel = strrchr(s, ':');
02239     if (complevel != NULL) *complevel = '\0';
02240 
02241     for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
02242       if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
02243         *compression_level = slf->default_compression;
02244         if (complevel != NULL) {
02245           /* There is a compression level in the string.
02246            * First restore the : we removed to do proper name matching,
02247            * then move the the begin of the actual version. */
02248           *complevel = ':';
02249           complevel++;
02250 
02251           /* Get the version and determine whether all went fine. */
02252           char *end;
02253           long level = strtol(complevel, &end, 10);
02254           if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
02255             ShowInfoF("Compression level '%s' is not valid.", complevel);
02256           } else {
02257             *compression_level = level;
02258           }
02259         }
02260         return slf;
02261       }
02262     }
02263 
02264     ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
02265 
02266     /* Restore the string by adding the : back */
02267     if (complevel != NULL) *complevel = ':';
02268   }
02269   *compression_level = def->default_compression;
02270   return def;
02271 }
02272 
02273 /* actual loader/saver function */
02274 void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
02275 extern bool AfterLoadGame();
02276 extern bool LoadOldSaveGame(const char *file);
02277 
02281 static inline void ClearSaveLoadState()
02282 {
02283   delete _sl.dumper;
02284   _sl.dumper = NULL;
02285 
02286   delete _sl.sf;
02287   _sl.sf = NULL;
02288 
02289   delete _sl.reader;
02290   _sl.reader = NULL;
02291 
02292   delete _sl.lf;
02293   _sl.lf = NULL;
02294 }
02295 
02301 static void SaveFileStart()
02302 {
02303   _sl.ff_state = _fast_forward;
02304   _fast_forward = 0;
02305   if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
02306 
02307   InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
02308   _sl.saveinprogress = true;
02309 }
02310 
02312 static void SaveFileDone()
02313 {
02314   if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state;
02315   if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
02316 
02317   InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
02318   _sl.saveinprogress = false;
02319 }
02320 
02322 void SetSaveLoadError(StringID str)
02323 {
02324   _sl.error_str = str;
02325 }
02326 
02328 const char *GetSaveLoadErrorString()
02329 {
02330   SetDParam(0, _sl.error_str);
02331   SetDParamStr(1, _sl.extra_msg);
02332 
02333   static char err_str[512];
02334   GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
02335   return err_str;
02336 }
02337 
02339 static void SaveFileError()
02340 {
02341   SetDParamStr(0, GetSaveLoadErrorString());
02342   ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02343   SaveFileDone();
02344 }
02345 
02350 static SaveOrLoadResult SaveFileToDisk(bool threaded)
02351 {
02352   try {
02353     byte compression;
02354     const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
02355 
02356     /* We have written our stuff to memory, now write it to file! */
02357     uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
02358     _sl.sf->Write((byte*)hdr, sizeof(hdr));
02359 
02360     _sl.sf = fmt->init_write(_sl.sf, compression);
02361     _sl.dumper->Flush(_sl.sf);
02362 
02363     ClearSaveLoadState();
02364 
02365     if (threaded) SetAsyncSaveFinish(SaveFileDone);
02366 
02367     return SL_OK;
02368   } catch (...) {
02369     ClearSaveLoadState();
02370 
02371     /* Skip the "colour" character */
02372     DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02373 
02374     if (threaded) {
02375       SetAsyncSaveFinish(SaveFileError);
02376     } else {
02377       SaveFileError();
02378     }
02379     return SL_ERROR;
02380   }
02381 }
02382 
02384 static void SaveFileToDiskThread(void *arg)
02385 {
02386   SaveFileToDisk(true);
02387 }
02388 
02389 void WaitTillSaved()
02390 {
02391   if (_save_thread == NULL) return;
02392 
02393   _save_thread->Join();
02394   delete _save_thread;
02395   _save_thread = NULL;
02396 }
02397 
02406 static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
02407 {
02408   assert(!_sl.saveinprogress);
02409 
02410   _sl.dumper = new MemoryDumper();
02411   _sl.sf = writer;
02412 
02413   _sl_version = SAVEGAME_VERSION;
02414 
02415   SaveViewportBeforeSaveGame();
02416   SlSaveChunks();
02417 
02418   SaveFileStart();
02419   if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) {
02420     if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
02421 
02422     SaveOrLoadResult result = SaveFileToDisk(false);
02423     SaveFileDone();
02424 
02425     return result;
02426   }
02427 
02428   return SL_OK;
02429 }
02430 
02437 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
02438 {
02439   try {
02440     _sl.action = SLA_SAVE;
02441     return DoSave(writer, threaded);
02442   } catch (...) {
02443     ClearSaveLoadState();
02444     return SL_ERROR;
02445   }
02446 }
02447 
02454 static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
02455 {
02456   _sl.lf = reader;
02457 
02458   if (load_check) {
02459     /* Clear previous check data */
02460     _load_check_data.Clear();
02461     /* Mark SL_LOAD_CHECK as supported for this savegame. */
02462     _load_check_data.checkable = true;
02463   }
02464 
02465   uint32 hdr[2];
02466   if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02467 
02468   /* see if we have any loader for this type. */
02469   const SaveLoadFormat *fmt = _saveload_formats;
02470   for (;;) {
02471     /* No loader found, treat as version 0 and use LZO format */
02472     if (fmt == endof(_saveload_formats)) {
02473       DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format");
02474       _sl.lf->Reset();
02475       _sl_version = 0;
02476       _sl_minor_version = 0;
02477 
02478       /* Try to find the LZO savegame format; it uses 'OTTD' as tag. */
02479       fmt = _saveload_formats;
02480       for (;;) {
02481         if (fmt == endof(_saveload_formats)) {
02482           /* Who removed LZO support? Bad bad boy! */
02483           NOT_REACHED();
02484         }
02485         if (fmt->tag == TO_BE32X('OTTD')) break;
02486         fmt++;
02487       }
02488       break;
02489     }
02490 
02491     if (fmt->tag == hdr[0]) {
02492       /* check version number */
02493       _sl_version = TO_BE32(hdr[1]) >> 16;
02494       /* Minor is not used anymore from version 18.0, but it is still needed
02495        * in versions before that (4 cases) which can't be removed easy.
02496        * Therefor it is loaded, but never saved (or, it saves a 0 in any scenario).
02497        * So never EVER use this minor version again. -- TrueLight -- 22-11-2005 */
02498       _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF;
02499 
02500       DEBUG(sl, 1, "Loading savegame version %d", _sl_version);
02501 
02502       /* Is the version higher than the current? */
02503       if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME);
02504       break;
02505     }
02506 
02507     fmt++;
02508   }
02509 
02510   /* loader for this savegame type is not implemented? */
02511   if (fmt->init_load == NULL) {
02512     char err_str[64];
02513     snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
02514     SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
02515   }
02516 
02517   _sl.lf = fmt->init_load(_sl.lf);
02518   _sl.reader = new ReadBuffer(_sl.lf);
02519   _next_offs = 0;
02520 
02521   if (!load_check) {
02522     _engine_mngr.ResetToDefaultMapping();
02523 
02524     /* Old maps were hardcoded to 256x256 and thus did not contain
02525      * any mapsize information. Pre-initialize to 256x256 to not to
02526      * confuse old games */
02527     InitializeGame(256, 256, true, true);
02528 
02529     GamelogReset();
02530 
02531     if (IsSavegameVersionBefore(4)) {
02532       /*
02533        * NewGRFs were introduced between 0.3,4 and 0.3.5, which both
02534        * shared savegame version 4. Anything before that 'obviously'
02535        * does not have any NewGRFs. Between the introduction and
02536        * savegame version 41 (just before 0.5) the NewGRF settings
02537        * were not stored in the savegame and they were loaded by
02538        * using the settings from the main menu.
02539        * So, to recap:
02540        * - savegame version  <  4:  do not load any NewGRFs.
02541        * - savegame version >= 41:  load NewGRFs from savegame, which is
02542        *                            already done at this stage by
02543        *                            overwriting the main menu settings.
02544        * - other savegame versions: use main menu settings.
02545        *
02546        * This means that users *can* crash savegame version 4..40
02547        * savegames if they set incompatible NewGRFs in the main menu,
02548        * but can't crash anymore for savegame version < 4 savegames.
02549        *
02550        * Note: this is done here because AfterLoadGame is also called
02551        * for TTO/TTD/TTDP savegames which have their own NewGRF logic.
02552        */
02553       ClearGRFConfigList(&_grfconfig);
02554     }
02555   }
02556 
02557   if (load_check) {
02558     /* Load chunks into _load_check_data.
02559      * No pools are loaded. References are not possible, and thus do not need resolving. */
02560     SlLoadCheckChunks();
02561   } else {
02562     /* Load chunks and resolve references */
02563     SlLoadChunks();
02564     SlFixPointers();
02565   }
02566 
02567   ClearSaveLoadState();
02568 
02569   _savegame_type = SGT_OTTD;
02570 
02571   if (load_check) {
02572     /* The only part from AfterLoadGame() we need */
02573     _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig);
02574   } else {
02575     GamelogStartAction(GLAT_LOAD);
02576 
02577     /* After loading fix up savegame for any internal changes that
02578      * might have occurred since then. If it fails, load back the old game. */
02579     if (!AfterLoadGame()) {
02580       GamelogStopAction();
02581       return SL_REINIT;
02582     }
02583 
02584     GamelogStopAction();
02585   }
02586 
02587   return SL_OK;
02588 }
02589 
02595 SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
02596 {
02597   try {
02598     _sl.action = SLA_LOAD;
02599     return DoLoad(reader, false);
02600   } catch (...) {
02601     ClearSaveLoadState();
02602     return SL_REINIT;
02603   }
02604 }
02605 
02615 SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded)
02616 {
02617   /* An instance of saving is already active, so don't go saving again */
02618   if (_sl.saveinprogress && mode == SL_SAVE) {
02619     /* if not an autosave, but a user action, show error message */
02620     if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
02621     return SL_OK;
02622   }
02623   WaitTillSaved();
02624 
02625   /* Load a TTDLX or TTDPatch game */
02626   if (mode == SL_OLD_LOAD) {
02627     _engine_mngr.ResetToDefaultMapping();
02628     InitializeGame(256, 256, true, true); // set a mapsize of 256x256 for TTDPatch games or it might get confused
02629 
02630     /* TTD/TTO savegames have no NewGRFs, TTDP savegame have them
02631      * and if so a new NewGRF list will be made in LoadOldSaveGame.
02632      * Note: this is done here because AfterLoadGame is also called
02633      * for OTTD savegames which have their own NewGRF logic. */
02634     ClearGRFConfigList(&_grfconfig);
02635     GamelogReset();
02636     if (!LoadOldSaveGame(filename)) return SL_REINIT;
02637     _sl_version = 0;
02638     _sl_minor_version = 0;
02639     GamelogStartAction(GLAT_LOAD);
02640     if (!AfterLoadGame()) {
02641       GamelogStopAction();
02642       return SL_REINIT;
02643     }
02644     GamelogStopAction();
02645     return SL_OK;
02646   }
02647 
02648   switch (mode) {
02649     case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
02650     case SL_LOAD: _sl.action = SLA_LOAD; break;
02651     case SL_SAVE: _sl.action = SLA_SAVE; break;
02652     default: NOT_REACHED();
02653   }
02654 
02655   try {
02656     FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
02657 
02658     /* Make it a little easier to load savegames from the console */
02659     if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
02660     if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
02661 
02662     if (fh == NULL) {
02663       SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
02664     }
02665 
02666     if (mode == SL_SAVE) { // SAVE game
02667       DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
02668       if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
02669 
02670       return DoSave(new FileWriter(fh), threaded);
02671     }
02672 
02673     /* LOAD game */
02674     assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
02675     DEBUG(desync, 1, "load: %s", filename);
02676     return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK);
02677   } catch (...) {
02678     ClearSaveLoadState();
02679 
02680     /* Skip the "colour" character */
02681     if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
02682 
02683     /* A saver/loader exception!! reinitialize all variables to prevent crash! */
02684     return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
02685   }
02686 }
02687 
02689 void DoExitSave()
02690 {
02691   SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR);
02692 }
02693 
02699 void GenerateDefaultSaveName(char *buf, const char *last)
02700 {
02701   /* Check if we have a name for this map, which is the name of the first
02702    * available company. When there's no company available we'll use
02703    * 'Spectator' as "company" name. */
02704   CompanyID cid = _local_company;
02705   if (!Company::IsValidID(cid)) {
02706     const Company *c;
02707     FOR_ALL_COMPANIES(c) {
02708       cid = c->index;
02709       break;
02710     }
02711   }
02712 
02713   SetDParam(0, cid);
02714 
02715   /* Insert current date */
02716   switch (_settings_client.gui.date_format_in_default_names) {
02717     case 0: SetDParam(1, STR_JUST_DATE_LONG); break;
02718     case 1: SetDParam(1, STR_JUST_DATE_TINY); break;
02719     case 2: SetDParam(1, STR_JUST_DATE_ISO); break;
02720     default: NOT_REACHED();
02721   }
02722   SetDParam(2, _date);
02723 
02724   /* Get the correct string (special string for when there's not company) */
02725   GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
02726   SanitizeFilename(buf);
02727 }
02728 
02729 #if 0
02730 
02736 int GetSavegameType(char *file)
02737 {
02738   const SaveLoadFormat *fmt;
02739   uint32 hdr;
02740   FILE *f;
02741   int mode = SL_OLD_LOAD;
02742 
02743   f = fopen(file, "rb");
02744   if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
02745     DEBUG(sl, 0, "Savegame is obsolete or invalid format");
02746     mode = SL_LOAD; // don't try to get filename, just show name as it is written
02747   } else {
02748     /* see if we have any loader for this type. */
02749     for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
02750       if (fmt->tag == hdr) {
02751         mode = SL_LOAD; // new type of savegame
02752         break;
02753       }
02754     }
02755   }
02756 
02757   fclose(f);
02758   return mode;
02759 }
02760 #endif

Generated on Sun Jan 9 16:02:00 2011 for OpenTTD by  doxygen 1.6.1