Changeset - r15577:a61e44bed2f3
[Not reviewed]
master
0 3 0
rubidium - 14 years ago 2010-07-30 22:57:46
rubidium@openttd.org
(svn r20247) -Fix: when it is known the loading an old savegame is going to fail, bail out immediately (using an exception) instead of going on until e.g. the expected number of byte is read
3 files changed with 25 insertions and 13 deletions:
0 comments (0 inline, 0 general)
src/saveload/oldloader.cpp
Show inline comments
 
@@ -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)
 
{
src/saveload/oldloader.h
Show inline comments
 
@@ -22,25 +22,24 @@ struct LoadgameState {
 
	FILE *file;
 

	
 
	uint chunk_size;
 

	
 
	bool decoding;
 
	byte decode_char;
 

	
 
	uint buffer_count;
 
	uint buffer_cur;
 
	byte buffer[BUFFER_SIZE];
 

	
 
	uint total_read;
 
	bool failed;
 
};
 

	
 
/* OldChunk-Type */
 
enum OldChunkType {
 
	OC_SIMPLE    = 0,
 
	OC_NULL      = 1,
 
	OC_CHUNK     = 2,
 
	OC_ASSERT    = 3,
 
	/* 4 bits allocated (16 max) */
 

	
 
	OC_TTD       = 1 << 4, ///< chunk is valid ONLY for TTD savegames
 
	OC_TTO       = 1 << 5, ///< -//- TTO (default is neither of these)
src/saveload/oldloader_sl.cpp
Show inline comments
 
@@ -1470,39 +1470,39 @@ static bool LoadOldMapPart1(LoadgameStat
 
			_old_map3[i * 2] = ReadByte(ls);
 
			_old_map3[i * 2 + 1] = ReadByte(ls);
 
		}
 
		for (uint i = 0; i < OLD_MAP_SIZE / 4; i++) {
 
			byte b = ReadByte(ls);
 
			_m[i * 4 + 0].m6 = GB(b, 0, 2);
 
			_m[i * 4 + 1].m6 = GB(b, 2, 2);
 
			_m[i * 4 + 2].m6 = GB(b, 4, 2);
 
			_m[i * 4 + 3].m6 = GB(b, 6, 2);
 
		}
 
	}
 

	
 
	return !ls->failed;
 
	return true;
 
}
 

	
 
static bool LoadOldMapPart2(LoadgameState *ls, int num)
 
{
 
	uint i;
 

	
 
	for (i = 0; i < OLD_MAP_SIZE; i++) {
 
		_m[i].type_height = ReadByte(ls);
 
	}
 
	for (i = 0; i < OLD_MAP_SIZE; i++) {
 
		_m[i].m5 = ReadByte(ls);
 
	}
 

	
 
	return !ls->failed;
 
	return true;
 
}
 

	
 
static bool LoadTTDPatchExtraChunks(LoadgameState *ls, int num)
 
{
 
	ReadTTDPatchFlags();
 

	
 
	DEBUG(oldloader, 2, "Found %d extra chunk(s)", _old_extra_chunk_nums);
 

	
 
	for (int i = 0; i != _old_extra_chunk_nums; i++) {
 
		uint16 id = ReadUint16(ls);
 
		uint32 len = ReadUint32(ls);
 

	
 
@@ -1539,25 +1539,25 @@ static bool LoadTTDPatchExtraChunks(Load
 
					GB(_ttdp_version, 24, 8), GB(_ttdp_version, 20, 4), GB(_ttdp_version, 16, 4), GB(_ttdp_version, 0, 16));
 
				len -= 4;
 
				while (len-- != 0) ReadByte(ls); // skip the configuration
 
				break;
 

	
 
			default:
 
				DEBUG(oldloader, 4, "Skipping unknown extra chunk %X", id);
 
				while (len-- != 0) ReadByte(ls);
 
				break;
 
		}
 
	}
 

	
 
	return !ls->failed;
 
	return true;
 
}
 

	
 
extern TileIndex _cur_tileloop_tile;
 
extern uint16 _disaster_delay;
 
extern byte _trees_tick_ctr;
 
static const OldChunks main_chunk[] = {
 
	OCL_ASSERT( OC_TTD, 0 ),
 
	OCL_ASSERT( OC_TTO, 0 ),
 
	OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_date ),
 
	OCL_VAR ( OC_UINT16,   1, &_date_fract ),
 
	OCL_NULL( 600 ),            ///< TextEffects
 
	OCL_VAR ( OC_UINT32,   2, &_random.state ),
 
@@ -1725,29 +1725,35 @@ static const OldChunks main_chunk[] = {
 
};
 

	
 
bool LoadTTDMain(LoadgameState *ls)
 
{
 
	_read_ttdpatch_flags = false;
 
	_ttdp_version = 0;
 

	
 
	DEBUG(oldloader, 3, "Reading main chunk...");
 
	/* Load the biggest chunk */
 
	SmallStackSafeStackAlloc<byte, OLD_MAP_SIZE * 2> map3;
 
	_old_map3 = map3.data;
 
	_old_vehicle_names = NULL;
 
	if (!LoadChunk(ls, NULL, main_chunk)) {
 
		DEBUG(oldloader, 0, "Loading failed");
 
	try {
 
		if (!LoadChunk(ls, NULL, main_chunk)) {
 
			DEBUG(oldloader, 0, "Loading failed");
 
			free(_old_vehicle_names);
 
			return false;
 
		}
 
	} catch (...) {
 
		free(_old_vehicle_names);
 
		return false;
 
		throw;
 
	}
 

	
 
	DEBUG(oldloader, 3, "Done, converting game data...");
 

	
 
	FixTTDMapArray();
 
	FixTTDDepots();
 

	
 
	/* Fix some general stuff */
 
	_settings_game.game_creation.landscape = _settings_game.game_creation.landscape & 0xF;
 

	
 
	/* Fix the game to be compatible with OpenTTD */
 
	FixOldTowns();
 
	FixOldVehicles();
 

	
0 comments (0 inline, 0 general)