diff options
| -rw-r--r-- | engines/kyra/script.cpp | 155 | ||||
| -rw-r--r-- | engines/kyra/script.h | 43 | ||||
| -rw-r--r-- | engines/kyra/script_tim.cpp | 60 | 
3 files changed, 92 insertions, 166 deletions
| diff --git a/engines/kyra/script.cpp b/engines/kyra/script.cpp index a1297770bd..6d69b6bffb 100644 --- a/engines/kyra/script.cpp +++ b/engines/kyra/script.cpp @@ -28,6 +28,7 @@  #include "common/stream.h"  #include "common/util.h"  #include "common/system.h" +  #include "kyra/kyra_v1.h"  #include "kyra/resource.h"  #include "kyra/script.h" @@ -66,69 +67,62 @@ EMCInterpreter::EMCInterpreter(KyraEngine_v1 *vm) : _vm(vm) {  }  bool EMCInterpreter::load(const char *filename, EMCData *scriptData, const Common::Array<const Opcode*> *opcodes) { -	IFFParser file(filename, _vm->resource()); -	if (!file) { +	Common::SeekableReadStream *stream = _vm->resource()->createReadStream(filename); +	if (!stream) {  		error("Couldn't open script file '%s'", filename);  		return false;  	}  	memset(scriptData, 0, sizeof(EMCData)); -	uint32 formBlockSize = file.getFORMBlockSize(); -	if (formBlockSize == (uint32)-1) { -		error("No FORM chunk found in file: '%s'", filename); -		return false; -	} +	IFFParser iff(*stream); +	Common::IFFChunk *chunk = 0; -	uint32 chunkSize = file.getBlockSize(TEXT_CHUNK); -	if (chunkSize != (uint32)-1) { -		scriptData->text = new byte[chunkSize]; +	while ((chunk = iff.nextChunk()) != 0) { +		switch (chunk->id) { +		case MKID_BE('TEXT'): +			scriptData->text = new byte[chunk->size]; +			assert(scriptData->text); +			chunk->read(scriptData->text, chunk->size); +			break; -		if (!file.loadBlock(TEXT_CHUNK, scriptData->text, chunkSize)) { -			unload(scriptData); -			error("Couldn't load TEXT chunk from file: '%s'", filename); -			return false; -		} -	} +		case MKID_BE('ORDR'): +			scriptData->ordr = new uint16[chunk->size >> 1]; +			assert(scriptData->ordr); +			chunk->read(scriptData->ordr, chunk->size); -	chunkSize = file.getBlockSize(ORDR_CHUNK); -	if (chunkSize == (uint32)-1) { -		unload(scriptData); -		error("No ORDR chunk found in file: '%s'", filename); -		return false; -	} -	chunkSize >>= 1; +			for (int i = (chunk->size >> 1) - 1; i >= 0; --i) +				scriptData->ordr[i] = READ_BE_UINT16(&scriptData->ordr[i]); +			break; -	scriptData->ordr = new uint16[chunkSize]; +		case MKID_BE('DATA'): +			scriptData->data = new uint16[chunk->size >> 1]; +			assert(scriptData->data); +			chunk->read(scriptData->data, chunk->size); -	if (!file.loadBlock(ORDR_CHUNK, scriptData->ordr, chunkSize << 1)) { -		unload(scriptData); -		error("Couldn't load ORDR chunk from file: '%s'", filename); -		return false; -	} +			for (int i = (chunk->size >> 1) - 1; i >= 0; --i) +				scriptData->data[i] = READ_BE_UINT16(&scriptData->data[i]); +			break; -	while (chunkSize--) -		scriptData->ordr[chunkSize] = READ_BE_UINT16(&scriptData->ordr[chunkSize]); +		default: +			warning("Unexpected chunk '%s' of size %d found in file '%s'", Common::ID2string(chunk->id), chunk->size, filename); +			break; +		} +	} -	chunkSize = file.getBlockSize(DATA_CHUNK); -	if (chunkSize == (uint32)-1) { +	if (!scriptData->ordr) {  		unload(scriptData); -		error("No DATA chunk found in file: '%s'", filename); +		error("Couldn't read ORDR chunk from file: '%s'", filename);  		return false;  	} -	chunkSize >>= 1; -	scriptData->data = new uint16[chunkSize]; - -	if (!file.loadBlock(DATA_CHUNK, scriptData->data, chunkSize << 1)) { +	if (!scriptData->data) {  		unload(scriptData); -		error("Couldn't load DATA chunk from file: '%s'", filename); +		error("Couldn't read DATA chunk from file: '%s'", filename);  		return false;  	} -	scriptData->dataSize = chunkSize; -	while (chunkSize--) -		scriptData->data[chunkSize] = READ_BE_UINT16(&scriptData->data[chunkSize]); +	delete stream;  	scriptData->sysFuncs = opcodes; @@ -218,83 +212,6 @@ bool EMCInterpreter::run(EMCState *script) {  }  #pragma mark - -#pragma mark - IFFParser implementation -#pragma mark - - -void IFFParser::setFile(const char *filename, Resource *res) { -	destroy(); - -	res->exists(filename, true); -	_stream = res->createReadStream(filename); -	assert(_stream); -	_startOffset = 0; -	_endOffset = _stream->size(); -} - -void IFFParser::destroy() { -	delete _stream; -	_stream = 0; -	_startOffset = _endOffset = 0; -} - -uint32 IFFParser::getFORMBlockSize() { -	uint32 oldOffset = _stream->pos(); - -	uint32 data = _stream->readUint32LE(); - -	if (data != FORM_CHUNK) { -		_stream->seek(oldOffset); -		return (uint32)-1; -	} - -	data = _stream->readUint32BE(); -	return data; -} - -uint32 IFFParser::getBlockSize(const uint32 chunkName) { -	uint32 size = (uint32)-1; - -	_stream->seek(_startOffset + 0x0C); - -	while ((uint)_stream->pos() < _endOffset) { -		uint32 chunk = _stream->readUint32LE(); -		uint32 size_temp = _stream->readUint32BE(); - -		if (chunk != chunkName) { -			_stream->seek((size_temp + 1) & (~1), SEEK_CUR); -			assert((uint)_stream->pos() <= _endOffset); -		} else { -			size = size_temp; -			break; -		} -	} - -	return size; -} - -bool IFFParser::loadBlock(const uint32 chunkName, void *loadTo, uint32 ptrSize) { -	_stream->seek(_startOffset + 0x0C); - -	while ((uint)_stream->pos() < _endOffset) { -		uint32 chunk = _stream->readUint32LE(); -		uint32 chunkSize = _stream->readUint32BE(); - -		if (chunk != chunkName) { -			_stream->seek((chunkSize + 1) & (~1), SEEK_CUR); -			assert((uint)_stream->pos() <= _endOffset); -		} else { -			uint32 loadSize = 0; - -			loadSize = MIN(ptrSize, chunkSize); -			_stream->read(loadTo, loadSize); -			return true; -		} -	} - -	return false; -} - -#pragma mark -  #pragma mark - Command implementations  #pragma mark - diff --git a/engines/kyra/script.h b/engines/kyra/script.h index da229d7e2a..c09e4eedf1 100644 --- a/engines/kyra/script.h +++ b/engines/kyra/script.h @@ -29,6 +29,7 @@  #include "common/stream.h"  #include "common/array.h"  #include "common/func.h" +#include "common/iff_container.h"  namespace Kyra { @@ -64,34 +65,28 @@ struct EMCState {  #define stackPos(x) (script->stack[script->sp+x])  #define stackPosString(x) ((const char*)&script->dataPtr->text[READ_BE_UINT16(&script->dataPtr->text[stackPos(x)<<1])]) -#define FORM_CHUNK 0x4D524F46 -#define TEXT_CHUNK 0x54584554 -#define DATA_CHUNK 0x41544144 -#define ORDR_CHUNK 0x5244524F -#define AVTL_CHUNK 0x4C545641 -  class Resource;  class KyraEngine_v1; -class IFFParser { +class IFFParser : public Common::IFFParser {  public: -	IFFParser() : _stream(0), _startOffset(0), _endOffset(0) {} -	IFFParser(const char *filename, Resource *res) : _stream(0), _startOffset(0), _endOffset(0) { setFile(filename, res); } -	~IFFParser() { destroy(); } - -	void setFile(const char *filename, Resource *res); - -	operator bool() const { return (_startOffset != _endOffset) && _stream; } - -	uint32 getFORMBlockSize(); -	uint32 getBlockSize(const uint32 chunk); -	bool loadBlock(const uint32 chunk, void *loadTo, uint32 ptrSize); -private: -	void destroy(); - -	Common::SeekableReadStream *_stream; -	uint32 _startOffset; -	uint32 _endOffset; +	IFFParser(Common::SeekableReadStream &input) : Common::IFFParser(input) { +		// It seems Westwood missunderstood the 'size' field of the FORM chunk. +		// +		// For EMC scripts (type EMC2) it's filesize instead of filesize - 8, +		// means accidently including the 8 bytes used by the chunk header for the FORM +		// chunk. +		// +		// For TIM scripts (type AVFS) it's filesize - 12 instead of filesize - 8, +		// means it will not include the size of the 'type' field in the FORM chunk, +		// instead of only not including the chunk header size. +		// +		// Both lead to some problems in our IFF parser, either reading after the end +		// of file or producing a "Chunk overread" error message. To work around this +		// we need to adjust the size field properly. +		if (_typeId == MKID_BE('EMC2') || _typeId == MKID_BE('AVFS')) +			_formChunk.size = input.size() - 8; +	}  };  class EMCInterpreter { diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp index 6b5e0761ce..e52a36c3b5 100644 --- a/engines/kyra/script_tim.cpp +++ b/engines/kyra/script_tim.cpp @@ -34,6 +34,7 @@  #include "kyra/screen_lol.h"  #endif // ENABLE_LOL +#include "common/iff_container.h"  #include "common/endian.h"  namespace Kyra { @@ -87,7 +88,7 @@ TIMInterpreter::TIMInterpreter(KyraEngine_v1 *engine, Screen_v2 *screen_v2, OSys  #undef COMMAND_UNIMPL  #undef COMMAND -	_commands = commandProcs ; +	_commands = commandProcs;  	_commandsSize = ARRAYSIZE(commandProcs);  	_animations = new Animation[TIM::kWSASlots]; @@ -115,21 +116,17 @@ TIMInterpreter::~TIMInterpreter() {  	delete[] _animations;	  } -TIM *TIMInterpreter::load(const char *filename, const Common::Array<const TIMOpcode*> *opcodes) { +TIM *TIMInterpreter::load(const char *filename, const Common::Array<const TIMOpcode *> *opcodes) {  	if (!vm()->resource()->exists(filename))  		return 0; -	IFFParser file(filename, vm()->resource()); -	if (!file) +	Common::SeekableReadStream *stream = vm()->resource()->createReadStream(filename); +	if (!stream)  		error("Couldn't open TIM file '%s'", filename); -	uint32 formBlockSize = file.getFORMBlockSize(); -	if (formBlockSize == 0xFFFFFFFF) -		error("No FORM chunk found in TIM file '%s'", filename); - -	if (formBlockSize < 20) -		error("TIM file '%s' FORM chunk size smaller than 20", filename); - +	IFFParser iff(*stream); +	Common::IFFChunk *chunk = 0; +	  	TIM *tim = new TIM;  	assert(tim);  	memset(tim, 0, sizeof(TIM)); @@ -137,27 +134,44 @@ TIM *TIMInterpreter::load(const char *filename, const Common::Array<const TIMOpc  	tim->procFunc = -1;  	tim->opcodes = opcodes; -	uint32 avtlChunkSize = file.getBlockSize(AVTL_CHUNK); -	uint32 textChunkSize = file.getBlockSize(TEXT_CHUNK); +	int avtlChunkSize = 0; + +	while ((chunk = iff.nextChunk()) != 0) { +		switch (chunk->id) { +		case MKID_BE('TEXT'): +			tim->text = new byte[chunk->size]; +			assert(tim->text); +			if (chunk->read(tim->text, chunk->size) != chunk->size) +				error("Couldn't read TEXT chunk from file '%s'", filename); +			break; + +		case MKID_BE('AVTL'): +			avtlChunkSize = chunk->size >> 1; +			tim->avtl = new uint16[avtlChunkSize]; +			assert(tim->avtl); +			chunk->read(tim->avtl, chunk->size); + +			for (int i = avtlChunkSize - 1; i >= 0; --i) +				tim->avtl[i] = READ_LE_UINT16(&tim->avtl[i]); +			break; -	tim->avtl = new uint16[avtlChunkSize/2]; -	if (textChunkSize != 0xFFFFFFFF) -		tim->text = new byte[textChunkSize]; +		default: +			warning("Unexpected chunk '%s' of size %d found in file '%s'", Common::ID2string(chunk->id), chunk->size, filename); +			break; +		} +	} -	if (!file.loadBlock(AVTL_CHUNK, tim->avtl, avtlChunkSize)) -		error("Couldn't read AVTL chunk in TIM file '%s'", filename); -	if (textChunkSize != 0xFFFFFFFF && !file.loadBlock(TEXT_CHUNK, tim->text, textChunkSize)) -		error("Couldn't read TEXT chunk in TIM file '%s'", filename); +	delete stream; -	avtlChunkSize >>= 1; -	for (uint i = 0; i < avtlChunkSize; ++i) -		tim->avtl[i] = READ_LE_UINT16(tim->avtl + i); +	if (!tim->avtl) +		error("Couldn't read AVTL chunk from file: '%s'", filename);  	int num = (avtlChunkSize < TIM::kCountFuncs) ? avtlChunkSize : (int)TIM::kCountFuncs;  	for (int i = 0; i < num; ++i)  		tim->func[i].avtl = tim->avtl + tim->avtl[i];  	strncpy(tim->filename, filename, 13); +	tim->filename[12] = 0;  	return tim;  } | 
