diff options
author | Colin Snover | 2016-10-13 10:11:24 -0500 |
---|---|---|
committer | Colin Snover | 2016-10-20 11:33:08 -0500 |
commit | 55222ec06c030a03d288b7ad476c5dbf1444a48b (patch) | |
tree | 2034bfbd9b228650a4f302f43bdf0d80063034bf | |
parent | 950ee49382ea054ede5b7bb689add98b25075a8b (diff) | |
download | scummvm-rg350-55222ec06c030a03d288b7ad476c5dbf1444a48b.tar.gz scummvm-rg350-55222ec06c030a03d288b7ad476c5dbf1444a48b.tar.bz2 scummvm-rg350-55222ec06c030a03d288b7ad476c5dbf1444a48b.zip |
SCI32: Fix zero-offset exports
Exports with a zero offset are supposed to point to the start of
the code block in the script hunk, but they were being ignored.
This may also apply to SCI1.1 games, but until that can be
verified, this fixes the zero-offset in only SCI32 games for now.
-rw-r--r-- | engines/sci/engine/script.cpp | 45 | ||||
-rw-r--r-- | engines/sci/engine/script.h | 2 |
2 files changed, 40 insertions, 7 deletions
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index aef9cb198f..098c2e56c9 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -72,6 +72,11 @@ void Script::freeScript() { _offsetLookupSaidCount = 0; } +enum { + kSci11NumExportsOffset = 6, + kSci11ExportTableOffset = 8 +}; + void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptPatcher) { freeScript(); @@ -172,10 +177,11 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP _localsCount = (READ_LE_UINT16(_buf + _localsOffset - 2) - 4) >> 1; // half block size } } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) { - if (READ_LE_UINT16(_buf + 1 + 5) > 0) { // does the script have an export table? - _exportTable = (const uint16 *)(_buf + 1 + 5 + 2); - _numExports = READ_SCI11ENDIAN_UINT16(_exportTable - 1); + _numExports = READ_SCI11ENDIAN_UINT16(_buf + kSci11NumExportsOffset); + if (_numExports) { + _exportTable = (const uint16 *)(_buf + kSci11ExportTableOffset); } + _localsOffset = _scriptSize + 4; _localsCount = READ_SCI11ENDIAN_UINT16(_buf + _localsOffset - 2); } else if (getSciVersion() == SCI_VERSION_3) { @@ -234,6 +240,7 @@ void Script::identifyOffsets() { _offsetLookupObjectCount = 0; _offsetLookupStringCount = 0; _offsetLookupSaidCount = 0; + _codeOffset = 0; if (getSciVersion() < SCI_VERSION_1_1) { // SCI0 + SCI1 @@ -392,6 +399,16 @@ void Script::identifyOffsets() { scriptDataPtr = _heapStart; scriptDataLeft = _heapSize; + enum { + kExportSize = 2, + kPropertySize = 2, + kNumMethodsSize = 2, + kPropDictEntrySize = 2, + kMethDictEntrySize = 4 + }; + + const byte *hunkPtr = _buf + kSci11ExportTableOffset + _numExports * kExportSize; + if (scriptDataLeft < 4) error("Script::identifyOffsets(): unexpected end of script in script %d", _nr); @@ -431,11 +448,22 @@ void Script::identifyOffsets() { if (scriptDataLeft < 2) error("Script::identifyOffsets(): unexpected end of script in script %d", _nr); - blockSize = READ_SCI11ENDIAN_UINT16(scriptDataPtr) * 2; + const uint16 numProperties = READ_SCI11ENDIAN_UINT16(scriptDataPtr); + blockSize = numProperties * kPropertySize; if (blockSize < 4) error("Script::identifyOffsets(): invalid block size in script %d", _nr); scriptDataPtr += 2; scriptDataLeft -= 2; + + const uint16 scriptNum = READ_SCI11ENDIAN_UINT16(scriptDataPtr + 6); + + if (scriptNum != 0xFFFF) { + hunkPtr += numProperties * kPropDictEntrySize; + } + + const uint16 numMethods = READ_SCI11ENDIAN_UINT16(hunkPtr); + hunkPtr += kNumMethodsSize + numMethods * kMethDictEntrySize; + blockSize -= 4; // blocksize contains UINT16 type and UINT16 size if (scriptDataLeft < blockSize) error("Script::identifyOffsets(): invalid block size in script %d", _nr); @@ -444,6 +472,8 @@ void Script::identifyOffsets() { scriptDataLeft -= blockSize; } while (1); + _codeOffset = hunkPtr - _buf; + // now scriptDataPtr points to right at the start of the strings if (scriptDataPtr > endOfStringPtr) error("Script::identifyOffsets(): string block / end-of-string block mismatch in script %d", _nr); @@ -820,9 +850,10 @@ uint32 Script::validateExportFunc(int pubfunct, bool relocSci3) { } } - // Note that it's perfectly normal to return a zero offset, especially in - // SCI1.1 and newer games. Examples include script 64036 in Torin's Passage, - // script 64908 in the demo of RAMA and script 1013 in KQ6 floppy. + // TODO: Check if this should be done for SCI1.1 games as well + if (getSciVersion() >= SCI_VERSION_2 && offset == 0) { + offset = _codeOffset; + } if (offset >= _bufSize) error("Invalid export function pointer"); diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h index 755e2f3698..31f0a9e24d 100644 --- a/engines/sci/engine/script.h +++ b/engines/sci/engine/script.h @@ -81,6 +81,8 @@ private: const byte *_synonyms; /**< Synonyms block or 0 if not present */ uint16 _numSynonyms; /**< Number of entries in the synonyms block */ + int _codeOffset; /**< The absolute offset of the VM code block */ + int _localsOffset; uint16 _localsCount; |