aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/sci/engine/object.cpp50
-rw-r--r--engines/sci/engine/object.h25
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;