00001
00002
00005 #include "../stdafx.h"
00006 #include "../openttd.h"
00007 #include "../tile_type.h"
00008 #include "../debug.h"
00009 #include "../strings_type.h"
00010 #include "../string_func.h"
00011 #include "../settings_type.h"
00012
00013 #include "table/strings.h"
00014
00015 #include "saveload_internal.h"
00016 #include "oldloader.h"
00017
00018 enum {
00019 TTO_HEADER_SIZE = 41,
00020 TTD_HEADER_SIZE = 49,
00021 };
00022
00023 uint32 _bump_assert_value;
00024
00025 static inline OldChunkType GetOldChunkType(OldChunkType type) {return (OldChunkType)GB(type, 0, 4);}
00026 static inline OldChunkType GetOldChunkVarType(OldChunkType type) {return (OldChunkType)(GB(type, 8, 8) << 8);}
00027 static inline OldChunkType GetOldChunkFileType(OldChunkType type) {return (OldChunkType)(GB(type, 16, 8) << 16);}
00028
00029 static inline byte CalcOldVarLen(OldChunkType type)
00030 {
00031 static const byte type_mem_size[] = {0, 1, 1, 2, 2, 4, 4, 8};
00032 byte length = GB(type, 8, 8);
00033 assert(length != 0 && length < lengthof(type_mem_size));
00034 return type_mem_size[length];
00035 }
00036
00042 static byte ReadByteFromFile(LoadgameState *ls)
00043 {
00044
00045
00046 if (ls->buffer_cur >= ls->buffer_count) {
00047
00048 int count = (int)fread(ls->buffer, 1, BUFFER_SIZE, ls->file);
00049
00050
00051 if (count == 0) {
00052 DEBUG(oldloader, 0, "Read past end of file, loading failed");
00053 ls->failed = true;
00054 }
00055
00056 ls->buffer_count = count;
00057 ls->buffer_cur = 0;
00058 }
00059
00060 return ls->buffer[ls->buffer_cur++];
00061 }
00062
00068 byte ReadByte(LoadgameState *ls)
00069 {
00070
00071
00072
00073
00074
00075
00076 if (ls->chunk_size == 0) {
00077
00078 int8 new_byte = ReadByteFromFile(ls);
00079
00080 if (new_byte < 0) {
00081
00082 ls->decoding = true;
00083 ls->decode_char = ReadByteFromFile(ls);
00084 ls->chunk_size = -new_byte + 1;
00085 } else {
00086 ls->decoding = false;
00087 ls->chunk_size = new_byte + 1;
00088 }
00089 }
00090
00091 ls->total_read++;
00092 ls->chunk_size--;
00093
00094 return ls->decoding ? ls->decode_char : ReadByteFromFile(ls);
00095 }
00096
00102 bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks)
00103 {
00104 byte *base_ptr = (byte*)base;
00105
00106 for (const OldChunks *chunk = chunks; chunk->type != OC_END; chunk++) {
00107 if (((chunk->type & OC_TTD) && (_savegame_type == SGT_TTO)) ||
00108 ((chunk->type & OC_TTO) && (_savegame_type != SGT_TTO))) {
00109
00110 continue;
00111 }
00112
00113 byte *ptr = (byte*)chunk->ptr;
00114 if (chunk->type & OC_DEREFERENCE_POINTER) ptr = *(byte**)ptr;
00115
00116 for (uint i = 0; i < chunk->amount; i++) {
00117 if (ls->failed) return false;
00118
00119
00120 if (GetOldChunkType(chunk->type) != 0) {
00121 switch (GetOldChunkType(chunk->type)) {
00122
00123 case OC_NULL: ReadByte(ls); break;
00124
00125 case OC_CHUNK:
00126
00127
00128 if (!chunk->proc(ls, i)) return false;
00129 break;
00130
00131 case OC_ASSERT:
00132 DEBUG(oldloader, 4, "Assert point: 0x%X / 0x%X", ls->total_read, chunk->offset + _bump_assert_value);
00133 if (ls->total_read != chunk->offset + _bump_assert_value) ls->failed = true;
00134 default: break;
00135 }
00136 } else {
00137 uint64 res = 0;
00138
00139
00140 switch (GetOldChunkFileType(chunk->type)) {
00141 case OC_FILE_I8: res = (int8)ReadByte(ls); break;
00142 case OC_FILE_U8: res = ReadByte(ls); break;
00143 case OC_FILE_I16: res = (int16)ReadUint16(ls); break;
00144 case OC_FILE_U16: res = ReadUint16(ls); break;
00145 case OC_FILE_I32: res = (int32)ReadUint32(ls); break;
00146 case OC_FILE_U32: res = ReadUint32(ls); break;
00147 default: NOT_REACHED();
00148 }
00149
00150
00151 assert(base_ptr != NULL || chunk->ptr != NULL);
00152
00153
00154 if (chunk->ptr == NULL) ptr = base_ptr + chunk->offset;
00155
00156
00157 switch (GetOldChunkVarType(chunk->type)) {
00158 case OC_VAR_I8: *(int8 *)ptr = GB(res, 0, 8); break;
00159 case OC_VAR_U8: *(uint8 *)ptr = GB(res, 0, 8); break;
00160 case OC_VAR_I16:*(int16 *)ptr = GB(res, 0, 16); break;
00161 case OC_VAR_U16:*(uint16*)ptr = GB(res, 0, 16); break;
00162 case OC_VAR_I32:*(int32 *)ptr = res; break;
00163 case OC_VAR_U32:*(uint32*)ptr = res; break;
00164 case OC_VAR_I64:*(int64 *)ptr = res; break;
00165 case OC_VAR_U64:*(uint64*)ptr = res; break;
00166 default: NOT_REACHED();
00167 }
00168
00169
00170 if (chunk->amount > 1 && chunk->ptr != NULL) ptr += CalcOldVarLen(chunk->type);
00171 }
00172 }
00173 }
00174
00175 return true;
00176 }
00177
00183 static void InitLoading(LoadgameState *ls)
00184 {
00185 ls->chunk_size = 0;
00186 ls->total_read = 0;
00187 ls->failed = false;
00188
00189 ls->decoding = false;
00190 ls->decode_char = 0;
00191
00192 ls->buffer_cur = 0;
00193 ls->buffer_count = 0;
00194 memset(ls->buffer, 0, BUFFER_SIZE);
00195
00196 _bump_assert_value = 0;
00197
00198 _settings_game.construction.freeform_edges = false;
00199 }
00200
00207 static bool VerifyOldNameChecksum(char *title, uint len)
00208 {
00209 uint16 sum = 0;
00210 for (uint i = 0; i < len - 2; i++) {
00211 sum += title[i];
00212 sum = ROL(sum, 1);
00213 }
00214
00215 sum ^= 0xAAAA;
00216
00217 uint16 sum2 = title[len - 2];
00218 SB(sum2, 8, 8, title[len - 1]);
00219
00220 return sum == sum2;
00221 }
00222
00223 static inline bool CheckOldSavegameType(FILE *f, char *temp, const char *last, uint len)
00224 {
00225 assert(last - temp + 1 >= (int)len);
00226
00227 fseek(f, 0, SEEK_SET);
00228 if (fread(temp, 1, len, f) != len) {
00229 temp[0] = '\0';
00230 return false;
00231 }
00232
00233 bool ret = VerifyOldNameChecksum(temp, len);
00234 temp[len - 2] = '\0';
00235
00236 return ret;
00237 }
00238
00239 assert_compile(TTD_HEADER_SIZE >= TTO_HEADER_SIZE);
00240 static SavegameType DetermineOldSavegameType(FILE *f, char *title, const char *last)
00241 {
00242 char temp[TTD_HEADER_SIZE];
00243
00244 SavegameType type = SGT_TTO;
00245
00246 if (!CheckOldSavegameType(f, temp, lastof(temp), TTO_HEADER_SIZE)) {
00247 type = SGT_TTD;
00248 if (!CheckOldSavegameType(f, temp, lastof(temp), TTD_HEADER_SIZE)) {
00249 type = SGT_INVALID;
00250 }
00251 }
00252
00253 if (title != NULL) {
00254 switch (type) {
00255 case SGT_TTO: title = strecpy(title, "(TTO) ", last); break;
00256 case SGT_TTD: title = strecpy(title, "(TTD) ", last); break;
00257 default: title = strecpy(title, "(broken) ", last); break;
00258 }
00259 title = strecpy(title, temp, last);
00260 }
00261
00262 return type;
00263 }
00264
00265 typedef bool LoadOldMainProc(LoadgameState *ls);
00266
00267 bool LoadOldSaveGame(const char *file)
00268 {
00269 LoadgameState ls;
00270
00271 DEBUG(oldloader, 3, "Trying to load a TTD(Patch) savegame");
00272
00273 InitLoading(&ls);
00274
00275
00276 ls.file = fopen(file, "rb");
00277
00278 if (ls.file == NULL) {
00279 DEBUG(oldloader, 0, "Cannot open file '%s'", file);
00280 return false;
00281 }
00282
00283 SavegameType type = DetermineOldSavegameType(ls.file, NULL, NULL);
00284
00285 LoadOldMainProc *proc = NULL;
00286
00287 switch (type) {
00288 case SGT_TTO: proc = &LoadTTOMain; break;
00289 case SGT_TTD: proc = &LoadTTDMain; break;
00290 default: break;
00291 }
00292
00293 _savegame_type = type;
00294
00295 if (proc == NULL || !proc(&ls)) {
00296 SetSaveLoadError(STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED);
00297 fclose(ls.file);
00298 return false;
00299 }
00300
00301 _pause_game = 2;
00302
00303 return true;
00304 }
00305
00306 void GetOldSaveGameName(const char *path, const char *file, char *title, const char *last)
00307 {
00308 char filename[MAX_PATH];
00309
00310 snprintf(filename, lengthof(filename), "%s" PATHSEP "%s", path, file);
00311 FILE *f = fopen(filename, "rb");
00312
00313 if (f == NULL) {
00314 *title = '\0';
00315 return;
00316 }
00317
00318 DetermineOldSavegameType(f, title, last);
00319
00320 fclose(f);
00321 }