|
@@ -13,24 +13,26 @@
|
|
|
#include "../openttd.h"
|
|
|
#include "../debug.h"
|
|
|
#include "../strings_type.h"
|
|
|
#include "../string_func.h"
|
|
|
#include "../settings_type.h"
|
|
|
#include "../fileio_func.h"
|
|
|
|
|
|
#include "table/strings.h"
|
|
|
|
|
|
#include "saveload_internal.h"
|
|
|
#include "oldloader.h"
|
|
|
|
|
|
#include <exception>
|
|
|
|
|
|
static const int TTO_HEADER_SIZE = 41;
|
|
|
static const int TTD_HEADER_SIZE = 49;
|
|
|
|
|
|
uint32 _bump_assert_value;
|
|
|
|
|
|
static inline OldChunkType GetOldChunkType(OldChunkType type) {return (OldChunkType)GB(type, 0, 4);}
|
|
|
static inline OldChunkType GetOldChunkVarType(OldChunkType type) {return (OldChunkType)(GB(type, 8, 8) << 8);}
|
|
|
static inline OldChunkType GetOldChunkFileType(OldChunkType type) {return (OldChunkType)(GB(type, 16, 8) << 16);}
|
|
|
|
|
|
static inline byte CalcOldVarLen(OldChunkType type)
|
|
|
{
|
|
|
static const byte type_mem_size[] = {0, 1, 1, 2, 2, 4, 4, 8};
|
|
@@ -40,31 +42,32 @@ static inline byte CalcOldVarLen(OldChun
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
*
|
|
|
* Reads a byte from a file (do not call yourself, use ReadByte())
|
|
|
*
|
|
|
*/
|
|
|
static byte ReadByteFromFile(LoadgameState *ls)
|
|
|
{
|
|
|
/* To avoid slow reads, we read BUFFER_SIZE of bytes per time
|
|
|
and just return a byte per time */
|
|
|
if (ls->buffer_cur >= ls->buffer_count) {
|
|
|
|
|
|
/* Read some new bytes from the file */
|
|
|
int count = (int)fread(ls->buffer, 1, BUFFER_SIZE, ls->file);
|
|
|
|
|
|
/* We tried to read, but there is nothing in the file anymore.. */
|
|
|
if (count == 0) {
|
|
|
DEBUG(oldloader, 0, "Read past end of file, loading failed");
|
|
|
ls->failed = true;
|
|
|
throw std::exception();
|
|
|
}
|
|
|
|
|
|
ls->buffer_count = count;
|
|
|
ls->buffer_cur = 0;
|
|
|
}
|
|
|
|
|
|
return ls->buffer[ls->buffer_cur++];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
*
|
|
|
* Reads a byte from the buffer and decompress if needed
|
|
@@ -110,41 +113,39 @@ bool LoadChunk(LoadgameState *ls, void *
|
|
|
|
|
|
for (const OldChunks *chunk = chunks; chunk->type != OC_END; chunk++) {
|
|
|
if (((chunk->type & OC_TTD) && _savegame_type == SGT_TTO) ||
|
|
|
((chunk->type & OC_TTO) && _savegame_type != SGT_TTO)) {
|
|
|
/* TTD(P)-only chunk, but TTO savegame || TTO-only chunk, but TTD/TTDP savegame */
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
byte *ptr = (byte*)chunk->ptr;
|
|
|
if (chunk->type & OC_DEREFERENCE_POINTER) ptr = *(byte**)ptr;
|
|
|
|
|
|
for (uint i = 0; i < chunk->amount; i++) {
|
|
|
if (ls->failed) return false;
|
|
|
|
|
|
/* Handle simple types */
|
|
|
if (GetOldChunkType(chunk->type) != 0) {
|
|
|
switch (GetOldChunkType(chunk->type)) {
|
|
|
/* Just read the byte and forget about it */
|
|
|
case OC_NULL: ReadByte(ls); break;
|
|
|
|
|
|
case OC_CHUNK:
|
|
|
/* Call function, with 'i' as parameter to tell which item we
|
|
|
* are going to read */
|
|
|
if (!chunk->proc(ls, i)) return false;
|
|
|
break;
|
|
|
|
|
|
case OC_ASSERT:
|
|
|
DEBUG(oldloader, 4, "Assert point: 0x%X / 0x%X", ls->total_read, chunk->offset + _bump_assert_value);
|
|
|
if (ls->total_read != chunk->offset + _bump_assert_value) ls->failed = true;
|
|
|
if (ls->total_read != chunk->offset + _bump_assert_value) throw std::exception();
|
|
|
default: break;
|
|
|
}
|
|
|
} else {
|
|
|
uint64 res = 0;
|
|
|
|
|
|
/* Reading from the file: bits 16 to 23 have the FILE type */
|
|
|
switch (GetOldChunkFileType(chunk->type)) {
|
|
|
case OC_FILE_I8: res = (int8)ReadByte(ls); break;
|
|
|
case OC_FILE_U8: res = ReadByte(ls); break;
|
|
|
case OC_FILE_I16: res = (int16)ReadUint16(ls); break;
|
|
|
case OC_FILE_U16: res = ReadUint16(ls); break;
|
|
|
case OC_FILE_I32: res = (int32)ReadUint32(ls); break;
|
|
@@ -180,25 +181,24 @@ bool LoadChunk(LoadgameState *ls, void *
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
*
|
|
|
* Initialize some data before reading
|
|
|
*
|
|
|
*/
|
|
|
static void InitLoading(LoadgameState *ls)
|
|
|
{
|
|
|
ls->chunk_size = 0;
|
|
|
ls->total_read = 0;
|
|
|
ls->failed = false;
|
|
|
|
|
|
ls->decoding = false;
|
|
|
ls->decode_char = 0;
|
|
|
|
|
|
ls->buffer_cur = 0;
|
|
|
ls->buffer_count = 0;
|
|
|
memset(ls->buffer, 0, BUFFER_SIZE);
|
|
|
|
|
|
_bump_assert_value = 0;
|
|
|
|
|
|
_settings_game.construction.freeform_edges = false; // disable so we can convert map array (SetTileType is still used)
|
|
|
}
|
|
@@ -292,25 +292,32 @@ bool LoadOldSaveGame(const char *file)
|
|
|
SavegameType type = DetermineOldSavegameType(ls.file, NULL, NULL);
|
|
|
|
|
|
LoadOldMainProc *proc = NULL;
|
|
|
|
|
|
switch (type) {
|
|
|
case SGT_TTO: proc = &LoadTTOMain; break;
|
|
|
case SGT_TTD: proc = &LoadTTDMain; break;
|
|
|
default: break;
|
|
|
}
|
|
|
|
|
|
_savegame_type = type;
|
|
|
|
|
|
if (proc == NULL || !proc(&ls)) {
|
|
|
bool game_loaded;
|
|
|
try {
|
|
|
game_loaded = proc != NULL && proc(&ls);
|
|
|
} catch (...) {
|
|
|
game_loaded = false;
|
|
|
}
|
|
|
|
|
|
if (!game_loaded) {
|
|
|
SetSaveLoadError(STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED);
|
|
|
fclose(ls.file);
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
_pause_mode = 2;
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
void GetOldSaveGameName(const char *file, char *title, const char *last)
|
|
|
{
|