aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Snover2017-07-14 17:05:18 -0500
committerColin Snover2017-07-15 20:10:38 -0500
commit051366a48a30e68efcfe9ebb584a3774ca357e1e (patch)
treed6a07abce85057d892f81390d24cfa7bf211801f
parent2032ca8ca1bf932ffbd4d6c1b2337caa4d585787 (diff)
downloadscummvm-rg350-051366a48a30e68efcfe9ebb584a3774ca357e1e.tar.gz
scummvm-rg350-051366a48a30e68efcfe9ebb584a3774ca357e1e.tar.bz2
scummvm-rg350-051366a48a30e68efcfe9ebb584a3774ca357e1e.zip
SCI: Fix up Object::_baseMethod implementation
1. In SCI0/1, selectors and offsets in the method block are stored contiguously (all selectors, then all offsets), with a null separator between the two runs. All the later versions of SCI instead interleave selectors & offsets. Since these values are already being copied into a new array anyway, code for reading method selectors/offsets is now simplified by interleaving this data when it is written into _baseMethod for SCI0/1, so the same equation for retrieving method selectors/offsets can be used across all SCI versions. 2. In SCI1.1-2.1 branch, the method count was being copied into the first entry of the array, which meant that SCI1.1-2.1 had extra code for dealing with the fact that the first entry was not an entry. This has been fixed, and the extra code removed. 3. Data was being overread into _baseMethod in all games SCI0-2.1. (SCI0/1 had an extra magic value of 2, and SCI1.1-2.1 had an extra magic value of 3). Reviewing history, it's not clear why this happened, other than that it appears to have been introduced at 7b0760f1bc5c28abcede041a6e3930f84ff3d319. My best guess is that this was a confusion between byte count and record count, where the intent was to read an extra 2 bytes for the null separator in SCI0/1, but it actually read 2 records instead. (I do not have a guess on why SCI1.1 ended up with a 3.) This overreading has been removed.
-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;