aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra
diff options
context:
space:
mode:
authorJohannes Schickel2009-05-12 14:18:08 +0000
committerJohannes Schickel2009-05-12 14:18:08 +0000
commit8524bf3a25fe8326fda5364f7691c75903b5eb32 (patch)
treec802d13990e72bd88a920f884b216aaaee1edd7a /engines/kyra
parentfa0fe7fada18be6499694f94164af3d06fdf628a (diff)
downloadscummvm-rg350-8524bf3a25fe8326fda5364f7691c75903b5eb32.tar.gz
scummvm-rg350-8524bf3a25fe8326fda5364f7691c75903b5eb32.tar.bz2
scummvm-rg350-8524bf3a25fe8326fda5364f7691c75903b5eb32.zip
Change script file loading code to use Common::IFFParser instead of a self written IFF reader.
svn-id: r40488
Diffstat (limited to 'engines/kyra')
-rw-r--r--engines/kyra/script.cpp155
-rw-r--r--engines/kyra/script.h43
-rw-r--r--engines/kyra/script_tim.cpp60
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;
}