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;  | 
