diff options
Diffstat (limited to 'kyra/script.cpp')
-rw-r--r-- | kyra/script.cpp | 706 |
1 files changed, 221 insertions, 485 deletions
diff --git a/kyra/script.cpp b/kyra/script.cpp index 358d65b1bb..4f941241e5 100644 --- a/kyra/script.cpp +++ b/kyra/script.cpp @@ -22,538 +22,274 @@ #include "common/stdafx.h" #include "common/stream.h" #include "common/util.h" +#include "common/system.h" #include "kyra/kyra.h" -#include "kyra/script.h" #include "kyra/resource.h" +#include "kyra/script.h" -#define COMMAND(x) { &VMContext::x, #x } -#define OPCODE(x) { &VMContext::x, #x } +#define FORM_CHUNK 0x4D524F46 +#define TEXT_CHUNK 0x54584554 +#define DATA_CHUNK 0x41544144 +#define ORDR_CHUNK 0x5244524F namespace Kyra { -VMContext::VMContext(KyraEngine* engine) { - _engine = engine; - _error = false; - +ScriptHelper::ScriptHelper(KyraEngine *vm) : _vm(vm) { +#define COMMAND(x) { &ScriptHelper::x, #x } // now we create a list of all Command/Opcode procs and so static CommandEntry commandProcs[] = { // 0x00 - COMMAND(c1_goToLine), - COMMAND(c1_setReturn), - COMMAND(c1_pushRetRec), + COMMAND(c1_jmpTo), + COMMAND(c1_setRetValue), + COMMAND(c1_pushRetOrPos), COMMAND(c1_push), // 0x04 COMMAND(c1_push), COMMAND(c1_pushVar), - COMMAND(c1_pushFrameNeg), - COMMAND(c1_pushFramePos), + COMMAND(c1_pushBPNeg), + COMMAND(c1_pushBPAdd), // 0x08 - COMMAND(c1_popRetRec), + COMMAND(c1_popRetOrPos), COMMAND(c1_popVar), - COMMAND(c1_popFrameNeg), - COMMAND(c1_popFramePos), + COMMAND(c1_popBPNeg), + COMMAND(c1_popBPAdd), // 0x0C - COMMAND(c1_addToSP), - COMMAND(c1_subFromSP), + COMMAND(c1_addSP), + COMMAND(c1_subSP), COMMAND(c1_execOpcode), - COMMAND(c1_ifNotGoTo), + COMMAND(c1_ifNotJmp), // 0x10 COMMAND(c1_negate), - COMMAND(c1_evaluate) + COMMAND(c1_eval), + COMMAND(c1_setRetAndJmp) }; - _numCommands = ARRAYSIZE(commandProcs); _commands = commandProcs; - - static OpcodeEntry opcodeProcs[] = { - // 0x00 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x04 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x08 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x0C - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x10 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x14 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x18 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x1C - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x20 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x24 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x28 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x2C - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x30 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x34 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x38 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x3C - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x40 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x44 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x48 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x4C - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x50 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x54 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x58 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x5C - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x60 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x64 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x68 - OPCODE(o1_0x68), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x6C - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x70 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x74 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x78 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x7C - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x80 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x84 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x88 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x8C - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x90 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x94 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x98 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0x9C - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xA0 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xA4 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xA8 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xAC - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xB0 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xB4 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xB8 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xBC - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xC0 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xC4 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xC8 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xCC - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xD0 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xD4 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xD8 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xDC - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xE0 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xE4 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xE8 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xEC - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xF0 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xF4 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xF8 - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - // 0xFC - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode), - OPCODE(o1_unknownOpcode) - }; - _numOpcodes = ARRAYSIZE(opcodeProcs); - _opcodes = opcodeProcs; - - _scriptFile = NULL; - _scriptFileSize = 0; +#undef COMMAND } -void VMContext::loadScript(const char* file) { - if (_scriptFile) { - delete [] _scriptFile; - _scriptFileSize = 0; - } - - memset(_stack, 0, sizeof(int32) * ARRAYSIZE(_stack)); - - // loads the new file - _scriptFile = _engine->resource()->fileData(file, &_scriptFileSize); +ScriptHelper::~ScriptHelper() { +} - if (!_scriptFileSize || !_scriptFile) { - error("couldn't load script file '%s'", file); +bool ScriptHelper::loadScript(const char *filename, ScriptData *scriptData, byte *specialPtr) { + uint32 size = 0; + uint8 *data = _vm->resource()->fileData(filename, &size); + byte *curData = data; + + uint32 formBlockSize = getFORMBlockSize(curData); + if (formBlockSize == (uint32)-1) { + delete [] data; + error("No FORM chunk found in file: '%s'", filename); + return false; } - - Common::MemoryReadStream script(_scriptFile, _scriptFileSize); - memset(_chunks, 0, sizeof(ScriptChunk) * kCountChunkTypes); - uint8 chunkName[sizeof("EMC2ORDR") + 1]; - - // so lets look for our chunks :) - while (!script.eos()) { - // lets read only the first 4 chars - script.read(chunkName, sizeof(uint8) * 4); - chunkName[4] = '\0'; - - // check name of chunk - if (!scumm_stricmp((const char *)chunkName, "FORM")) { - // FreeKyra swaps the size I only read it in BigEndian :) - _chunks[kForm]._size = script.readUint32BE(); - } else if (!scumm_stricmp((const char *)chunkName, "TEXT")) { - uint32 text_size = script.readUint32BE(); - text_size += text_size % 2 != 0 ? 1 : 0; - - _chunks[kText]._data = _scriptFile + script.pos(); - _chunks[kText]._size = READ_BE_UINT16(_chunks[kText]._data) >> 1; - _chunks[kText]._additional = _chunks[kText]._data + (_chunks[kText]._size << 1); - script.seek(script.pos() + text_size); - } else if (!scumm_stricmp((const char *)chunkName, "DATA")) { - _chunks[kData]._size = script.readUint32BE(); - _chunks[kData]._data = _scriptFile + script.pos(); - // mostly it will be the end of the file because all files should end with a 'DATA' chunk - script.seek(script.pos() + _chunks[kData]._size); + + uint32 chunkSize = getIFFBlockSize(data, curData, size, TEXT_CHUNK); + if (chunkSize != (uint32)-1) { + if (specialPtr) { + scriptData->mustBeFreed = 0; + scriptData->text = specialPtr; + specialPtr += chunkSize; } else { - // read next 4 chars - script.read(&chunkName[4], sizeof(uint8) * 4); - chunkName[8] = '\0'; - - if (!scumm_stricmp((const char *)chunkName, "EMC2ORDR")) { - _chunks[kEmc2Ordr]._size = script.readUint32BE() >> 1; - _chunks[kEmc2Ordr]._data = _scriptFile + script.pos(); - script.seek(script.pos() + _chunks[kEmc2Ordr]._size * 2); - } else { - // any unkown chunk or problems with seeking through the file - error("unknown chunk(%s)", chunkName); - } + scriptData->mustBeFreed = 1; + scriptData->text = new byte[chunkSize]; + } + if (!loadIFFBlock(data, curData, size, TEXT_CHUNK, scriptData->text, chunkSize)) { + delete [] data; + unloadScript(scriptData); + error("Couldn't load TEXT chunk from file: '%s'", filename); + return false; } } + + chunkSize = getIFFBlockSize(data, curData, size, ORDR_CHUNK); + if (chunkSize == (uint32)-1) { + delete [] data; + unloadScript(scriptData); + error("No ORDR chunk found in file: '%s'", filename); + return false; + } + if (specialPtr) { + scriptData->mustBeFreed = 0; + scriptData->ordr = specialPtr; + specialPtr += chunkSize; + } else { + scriptData->mustBeFreed = 1; + scriptData->ordr = new byte[chunkSize]; + } + if (!loadIFFBlock(data, curData, size, ORDR_CHUNK, scriptData->ordr, chunkSize)) { + delete [] data; + unloadScript(scriptData); + error("Couldn't load ORDR chunk from file: '%s'", filename); + return false; + } + chunkSize = chunkSize / 2; + while (chunkSize--) { + ((uint16*)scriptData->ordr)[chunkSize] = READ_BE_UINT16(&((uint16*)scriptData->ordr)[chunkSize]); + } + + chunkSize = getIFFBlockSize(data, curData, size, DATA_CHUNK); + if (chunkSize == (uint32)-1) { + delete [] data; + unloadScript(scriptData); + error("No DATA chunk found in file: '%s'", filename); + return false; + } + if (specialPtr) { + scriptData->mustBeFreed = 0; + scriptData->data = specialPtr; + specialPtr += chunkSize; + } else { + scriptData->mustBeFreed = 1; + scriptData->data = new byte[chunkSize]; + } + if (!loadIFFBlock(data, curData, size, DATA_CHUNK, scriptData->data, chunkSize)) { + delete [] data; + unloadScript(scriptData); + error("Couldn't load DATA chunk from file: '%s'", filename); + return false; + } + scriptData->dataSize = chunkSize / 2; + + delete [] data; + return true; } -int32 VMContext::param(int32 index) { - if (_stackPos - index - 1 >= ARRAYSIZE(_stack) || _stackPos - index - 1 < 0) - return -0xFFFF; - return _stack[_stackPos - index - 1]; +void ScriptHelper::unloadScript(ScriptData *data) { + if (data->mustBeFreed) { + delete [] data->text; + delete [] data->ordr; + delete [] data->data; + } + + data->mustBeFreed = 0; + data->text = data->ordr = data->data = 0; } -const char* VMContext::stringAtIndex(int32 index) { - if (index < 0 || (uint32)index >= _chunks[kText]._size) - return 0; - - return (const char *)(_chunks[kText]._additional + _chunks[kText]._data[index]); +void ScriptHelper::initScript(ScriptState *scriptStat, ScriptData *data) { + scriptStat->dataPtr = data; + scriptStat->ip = 0; + scriptStat->stack[60] = 0; + scriptStat->bp = 62; + scriptStat->sp = 60; } -bool VMContext::startScript(int32 func) { - if ((uint32)func >= _chunks[kEmc2Ordr]._size || func < 0) { - debug("script doesn't support function %d", func); +bool ScriptHelper::startScript(ScriptState *script, int function) { + if (!script->dataPtr) { return false; } - - _instructionPos = READ_BE_UINT16(&_chunks[kEmc2Ordr]._data[func]) << 1; - _stackPos = 0; - _tempPos = 0; - _delay = 0; - _error = false; - _scriptState = kScriptRunning; - - uint32 pos = 0xFFFFFFFE; - - // get start of next script - for (uint32 tmp = 0; tmp < _chunks[kEmc2Ordr]._size; ++tmp) { - if ((uint32)((READ_BE_UINT16(&_chunks[kEmc2Ordr]._data[tmp]) << 1)) > (uint32)_instructionPos && - (uint32)((READ_BE_UINT16(&_chunks[kEmc2Ordr]._data[tmp]) << 1)) < pos) { - pos = ((READ_BE_UINT16(&_chunks[kEmc2Ordr]._data[tmp]) << 1)); - } - } - - if (pos > _scriptFileSize) { - pos = _scriptFileSize; + uint16 functionOffset = ((uint16*)script->dataPtr->ordr)[function]; + if (functionOffset == (uint16)-1) { + return false; } - - _nextScriptPos = pos; - + script->ip = &script->dataPtr->data[functionOffset*2+2]; return true; } -uint32 VMContext::contScript(void) { - uint8* script_start = _chunks[kData]._data; - assert(script_start); - - uint32 scriptStateAtStart = _scriptState; - - // runs the script - while (true) { - if ((uint32)_instructionPos > _chunks[kData]._size) { - debug("_instructionPos( = %d) > _chunks[kData]._size( = %d)", _instructionPos, _chunks[kData]._size); - _error = true; - break; - } else if (_instructionPos >= _nextScriptPos) { - _scriptState = kScriptStopped; - break; - } - - _currentCommand = *(script_start + _instructionPos++); - - // gets out - if (_currentCommand & 0x80) { - _argument = ((_currentCommand & 0x0F) << 8) | *(script_start + _instructionPos++); - _currentCommand &= 0xF0; - } else if (_currentCommand & 0x40) { - _argument = *(script_start + _instructionPos++); - } else if (_currentCommand & 0x20) { - _instructionPos++; - - uint16 tmp = *(uint16*)(script_start + _instructionPos); - tmp &= 0xFF7F; +bool ScriptHelper::validScript(ScriptState *script) { + if (!script->ip || !script->dataPtr) + return false; + return true; +} - _argument = READ_BE_UINT16(&tmp); - _instructionPos += 2; - } else { - debug("unknown way of getting the command (0x%X)", _currentCommand); - // next thing - continue; - } +bool ScriptHelper::runScript(ScriptState *script) { + _curScript = script; + _parameter = 0; + _continue = true; + + if (!_curScript->ip) { + return false; + } + + int16 code = READ_BE_UINT16(_curScript->ip); _curScript->ip += 2; + int16 opcode = (code >> 8) & 0x1F; + + if (code & 0x8000) { + opcode = 0; + _parameter = code & 0x7FFF; + } else if (code & 0x4000) { + _parameter = code & 0xFF; + } else if (code & 0x2000) { + _parameter = READ_BE_UINT16(_curScript->ip); _curScript->ip += 2; + } else { + _parameter = 0; + } + + if (opcode > 18) { + error("Script unknown command: %d", opcode); + } else { + debug(5, "%s(%d)", _commands[opcode].desc, _parameter); + (this->*(_commands[opcode].proc))(); + } + + _curScript = 0; + return _continue; +} - _currentCommand &= 0x1f; +uint32 ScriptHelper::getFORMBlockSize(byte *&data) const { + static const uint32 chunkName = FORM_CHUNK; + if (READ_LE_UINT32(data) != chunkName) { + return (uint32)-1; + } + data += 4; + uint32 retValue = READ_BE_UINT32(data); data += 4; + return retValue; +} - if (_currentCommand < _numCommands) { - CommandProc currentProc = _commands[_currentCommand].proc; - (this->*currentProc)(); +uint32 ScriptHelper::getIFFBlockSize(byte *start, byte *&data, uint32 maxSize, const uint32 chunkName) const { + uint32 size = (uint32)-1; + bool special = false; + + if (data == (start + maxSize)) { + data = start + 0x0C; + } + while (data < (start + maxSize)) { + uint32 chunk = READ_LE_UINT32(data); data += 4; + uint32 size_temp = READ_BE_UINT32(data); data += 4; + if (chunk != chunkName) { + if (special) { + data += (size_temp + 1) & 0xFFFFFFFE; + } else { + data = start + 0x0C; + special = true; + } } else { - c1_unknownCommand(); - } - - if (_error) { - _scriptState = kScriptError; + // kill our data + data = start; + size = size_temp; break; } + } + return size; +} - if (scriptStateAtStart != _scriptState) { - break; +bool ScriptHelper::loadIFFBlock(byte *start, byte *&data, uint32 maxSize, const uint32 chunkName, byte *loadTo, uint32 ptrSize) const { + bool special = false; + + if (data == (start + maxSize)) { + data = start + 0x0C; + } + while (data < (start + maxSize)) { + uint32 chunk = READ_LE_UINT32(data); data += 4; + uint32 chunkSize = READ_BE_UINT32(data); data += 4; + if (chunk != chunkName) { + if (special) { + data += (chunkSize + 1) & 0xFFFFFFFE; + } else { + data = start + 0x0C; + special = true; + } + } else { + uint32 loadSize = 0; + if (chunkSize < ptrSize) + loadSize = chunkSize; + else + loadSize = ptrSize; + memcpy(loadTo, data, loadSize); + chunkSize = (chunkSize + 1) & 0xFFFFFFFE; + if (chunkSize > loadSize) { + data += (chunkSize - loadSize); + } + return true; } } - - return _scriptState; + return false; } } // end of namespace Kyra |