diff options
-rw-r--r-- | engines/sci/engine/object.cpp | 50 | ||||
-rw-r--r-- | engines/sci/engine/object.h | 25 |
2 files changed, 56 insertions, 19 deletions
diff --git a/engines/sci/engine/object.cpp b/engines/sci/engine/object.cpp index 5d85bf6b8d..d43cf509e3 100644 --- a/engines/sci/engine/object.cpp +++ b/engines/sci/engine/object.cpp @@ -54,9 +54,29 @@ void Object::init(const Script &owner, reg_t obj_pos, bool initVariables) { } } - _methodCount = data.getUint16LEAt(header.getUint16LEAt(kOffsetHeaderFunctionArea) - 2); - for (uint i = 0; i < _methodCount * sizeof(uint16) + 2; ++i) { - _baseMethod.push_back(data.getUint16SEAt(header.getUint16LEAt(kOffsetHeaderFunctionArea) + i * sizeof(uint16))); + // method block structure: + // uint16 count; + // uint16 selectorNos[count]; + // uint16 zero; + // uint16 codeOffsets[count]; + + const uint16 methodBlockOffset = header.getUint16LEAt(kOffsetHeaderFunctionArea) - 2; + _methodCount = data.getUint16LEAt(methodBlockOffset); + const uint32 methodBlockSize = _methodCount * 2 * sizeof(uint16) + /* zero-terminator after selector list */ sizeof(uint16); + + SciSpan<const uint16> methodEntries = data.subspan<const uint16>(methodBlockOffset + /* count */ sizeof(uint16), methodBlockSize); + + // If this happens, then there is either a corrupt script or this code + // misunderstands the structure of the SCI0/1 method block + if (methodEntries.getUint16SEAt(_methodCount) != 0) { + warning("Object %04x:%04x in script %u has a value (0x%04x) in its zero-terminator field", PRINT_REG(obj_pos), owner.getScriptNumber(), methodEntries.getUint16SEAt(_methodCount)); + } + + _baseMethod.reserve(_methodCount * 2); + for (uint i = 0; i < _methodCount; ++i) { + _baseMethod.push_back(methodEntries.getUint16SEAt(0)); + _baseMethod.push_back(methodEntries.getUint16SEAt(_methodCount + /* zero-terminator */ 1)); + ++methodEntries; } } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) { _variables.resize(data.getUint16SEAt(2)); @@ -72,9 +92,27 @@ void Object::init(const Script &owner, reg_t obj_pos, bool initVariables) { } } - _methodCount = buf.getUint16SEAt(data.getUint16SEAt(6)); - for (uint i = 0; i < _methodCount * sizeof(uint16) + 3; ++i) { - _baseMethod.push_back(buf.getUint16SEAt(data.getUint16SEAt(6) + i * sizeof(uint16))); + // method block structure: + // uint16 count; + // struct { + // uint16 selectorNo; + // uint16 codeOffset; + // } entries[count]; + + const uint16 methodBlockOffset = data.getUint16SEAt(6); + _methodCount = buf.getUint16SEAt(methodBlockOffset); + + // Each entry in _baseMethod is actually two values; the first field is + // a selector number, and the second field is an offset to the method's + // code in the script + const uint32 methodBlockSize = _methodCount * 2 * sizeof(uint16); + _baseMethod.reserve(_methodCount * 2); + + SciSpan<const uint16> methodEntries = buf.subspan<const uint16>(methodBlockOffset + /* count */ sizeof(uint16), methodBlockSize); + for (uint i = 0; i < _methodCount; ++i) { + _baseMethod.push_back(methodEntries.getUint16SEAt(0)); + _baseMethod.push_back(methodEntries.getUint16SEAt(1)); + methodEntries += 2; } #ifdef ENABLE_SCI32 } else if (getSciVersion() == SCI_VERSION_3) { diff --git a/engines/sci/engine/object.h b/engines/sci/engine/object.h index 8b597b42b0..ffc4ac2f3d 100644 --- a/engines/sci/engine/object.h +++ b/engines/sci/engine/object.h @@ -230,22 +230,21 @@ public: Selector getVarSelector(uint16 i) const { return _baseVars[i]; } - reg_t getFunction(uint16 i) const { - uint16 offset = (getSciVersion() < SCI_VERSION_1_1) ? _methodCount + 1 + i : i * 2 + 2; - if (getSciVersion() == SCI_VERSION_3) - offset--; - + /** + * @returns A pointer to the code for the method at the given index. + */ + reg_t getFunction(const uint16 index) const { reg_t addr; addr.setSegment(_pos.getSegment()); - addr.setOffset(_baseMethod[offset]); + addr.setOffset(_baseMethod[index * 2 + 1]); return addr; } - Selector getFuncSelector(uint16 i) const { - uint16 offset = (getSciVersion() < SCI_VERSION_1_1) ? i : i * 2 + 1; - if (getSciVersion() == SCI_VERSION_3) - offset--; - return _baseMethod[offset]; + /** + * @returns The selector for the method at the given index. + */ + Selector getFuncSelector(const uint16 index) const { + return _baseMethod[index * 2]; } /** @@ -335,8 +334,8 @@ private: Common::Array<uint16> _baseVars; /** - * A lookup table from a method index to its corresponding selector number. - * In SCI3, the table contains selector + offset in pairs. + * A lookup table from a method index to its corresponding selector number + * or offset to code. The table contains selector + offset in pairs. */ Common::Array<uint32> _baseMethod; |