diff options
author | Filippos Karapetis | 2010-11-17 11:15:52 +0000 |
---|---|---|
committer | Filippos Karapetis | 2010-11-17 11:15:52 +0000 |
commit | b707d6e7dc1baf2fb403ecf5e6e67c5ffa1d7019 (patch) | |
tree | 6d9b657c26007671133baa2a63aaeae3f5e86574 | |
parent | 59ad5085bc317488ebb006737cc130c9cb100a80 (diff) | |
download | scummvm-rg350-b707d6e7dc1baf2fb403ecf5e6e67c5ffa1d7019.tar.gz scummvm-rg350-b707d6e7dc1baf2fb403ecf5e6e67c5ffa1d7019.tar.bz2 scummvm-rg350-b707d6e7dc1baf2fb403ecf5e6e67c5ffa1d7019.zip |
SCI: More work on SCI3, based on a patch by lskovlun
- Added SCI3 equivalents for access to object selectors
- Added SCI3 implementation of object relocation
- Added SCI3 implementation of Script::initialiseClasses()
svn-id: r54283
-rw-r--r-- | engines/sci/engine/script.cpp | 60 | ||||
-rw-r--r-- | engines/sci/engine/script.h | 19 | ||||
-rw-r--r-- | engines/sci/engine/segment.cpp | 126 | ||||
-rw-r--r-- | engines/sci/engine/segment.h | 95 |
4 files changed, 267 insertions, 33 deletions
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 7f5a4c75be..a18ef6ce10 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -276,6 +276,22 @@ static bool relocateBlock(Common::Array<reg_t> &block, int block_location, Segme return true; } +int Script::relocateOffsetSci3(uint32 offset) { + int relocStart = READ_LE_UINT32(_buf + 8); + int relocCount = READ_LE_UINT16(_buf + 18); + const byte *seeker = _buf + relocStart; + + for (int i = 0; i < relocCount; ++i) { + if (READ_SCI11ENDIAN_UINT32(seeker) == offset) { + // TODO: Find out what UINT16 at (seeker + 8) means + return READ_SCI11ENDIAN_UINT16(_buf + offset) + READ_SCI11ENDIAN_UINT32(seeker + 4); + } + seeker += 10; + } + + return -1; +} + bool Script::relocateLocal(SegmentId segment, int location) { if (_localsBlock) return relocateBlock(_localsBlock->_locals, _localsOffset, segment, location, _scriptSize); @@ -283,7 +299,7 @@ bool Script::relocateLocal(SegmentId segment, int location) { return false; } -void Script::relocate(reg_t block) { +void Script::relocateSci0Sci21(reg_t block) { const byte *heap = _buf; uint16 heapSize = (uint16)_bufSize; uint16 heapOffset = 0; @@ -323,7 +339,7 @@ void Script::relocate(reg_t block) { // object, relocate it. const ObjMap::iterator end = _objects.end(); for (ObjMap::iterator it = _objects.begin(); it != end; ++it) - if (it->_value.relocate(block.segment, pos, _scriptSize)) + if (it->_value.relocateSci0Sci21(block.segment, pos, _scriptSize)) break; } @@ -331,6 +347,30 @@ void Script::relocate(reg_t block) { } } +void Script::relocateSci3(reg_t block) { + const byte *relocStart = _buf + READ_SCI11ENDIAN_UINT32(_buf + 8); + //int count = _bufSize - READ_SCI11ENDIAN_UINT32(_buf + 8); + + ObjMap::iterator it; + for (it = _objects.begin(); it != _objects.end(); ++it) { + unsigned int ofs = it->_value.getPos().offset; + unsigned int size = READ_SCI11ENDIAN_UINT16(_buf + ofs + 2); + const byte *seeker = relocStart; + while (READ_SCI11ENDIAN_UINT32(seeker) < ofs + size && + seeker < _buf + _bufSize) { + while (READ_SCI11ENDIAN_UINT32(seeker) < ofs) + seeker += 10; + + // TODO: Find out what UINT16 at (seeker + 8) means + it->_value.relocateSci3(block.segment, + READ_SCI11ENDIAN_UINT32(seeker), + READ_SCI11ENDIAN_UINT32(seeker + 4), + _scriptSize); + seeker += 10; + } + } +} + void Script::incrementLockers() { _lockers++; } @@ -467,7 +507,7 @@ void Script::initialiseClasses(SegManager *segMan) { return; uint16 marker; - bool isClass; + bool isClass = false; uint16 classpos; int16 species = 0; @@ -476,7 +516,10 @@ void Script::initialiseClasses(SegManager *segMan) { marker = READ_SCI11ENDIAN_UINT16(seeker); classpos = seeker - _buf; - if (!marker) + if (getSciVersion() <= SCI_VERSION_1_LATE && !marker) + break; + + if (getSciVersion() >= SCI_VERSION_1_1 && marker != 0x1234) break; if (getSciVersion() <= SCI_VERSION_1_LATE) { @@ -488,7 +531,8 @@ void Script::initialiseClasses(SegManager *segMan) { isClass = (READ_SCI11ENDIAN_UINT16(seeker + 14) & kInfoFlagClass); // -info- selector species = READ_SCI11ENDIAN_UINT16(seeker + 10); } else if (getSciVersion() == SCI_VERSION_3) { - // TODO: SCI3 equivalent + isClass = (READ_SCI11ENDIAN_UINT16(seeker + 10) & kInfoFlagClass); + species = READ_SCI11ENDIAN_UINT16(seeker + 4); } if (isClass) { @@ -553,7 +597,7 @@ void Script::initialiseObjectsSci0(SegManager *segMan, SegmentId segmentId) { byte *relocationBlock = findBlockSCI0(SCI_OBJ_POINTERS); if (relocationBlock) - relocate(make_reg(segmentId, relocationBlock - getBuf() + 4)); + relocateSci0Sci21(make_reg(segmentId, relocationBlock - getBuf() + 4)); } void Script::initialiseObjectsSci11(SegManager *segMan, SegmentId segmentId) { @@ -588,7 +632,7 @@ void Script::initialiseObjectsSci11(SegManager *segMan, SegmentId segmentId) { seeker += READ_SCI11ENDIAN_UINT16(seeker + 2) * 2; } - relocate(make_reg(segmentId, READ_SCI11ENDIAN_UINT16(_heapStart))); + relocateSci0Sci21(make_reg(segmentId, READ_SCI11ENDIAN_UINT16(_heapStart))); } void Script::initialiseObjectsSci3(SegManager *segMan, SegmentId segmentId) { @@ -602,7 +646,7 @@ void Script::initialiseObjectsSci3(SegManager *segMan, SegmentId segmentId) { seeker += READ_SCI11ENDIAN_UINT16(seeker + 2); } - relocate(make_reg(segmentId, 0)); + relocateSci3(make_reg(segmentId, 0)); } void Script::initialiseObjects(SegManager *segMan, SegmentId segmentId) { diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h index 2105d1e6de..313f53600c 100644 --- a/engines/sci/engine/script.h +++ b/engines/sci/engine/script.h @@ -250,17 +250,30 @@ public: private: /** - * Processes a relocation block witin a script + * Processes a relocation block within a SCI0-SCI2.1 script * This function is idempotent, but it must only be called after all * objects have been instantiated, or a run-time error will occur. * @param obj_pos Location (segment, offset) of the block - * @return Location of the relocation block */ - void relocate(reg_t block); + void relocateSci0Sci21(reg_t block); + + /** + * Processes a relocation block within a SCI3 script + * This function is idempotent, but it must only be called after all + * objects have been instantiated, or a run-time error will occur. + * @param obj_pos Location (segment, offset) of the block + */ + void relocateSci3(reg_t block); bool relocateLocal(SegmentId segment, int location); /** + * Resolve a relocation in an SCI3 script + * @param offset The offset to relocate from + */ + int relocateOffsetSci3(uint32 offset); + + /** * Gets a pointer to the beginning of the objects in a SCI3 script */ const byte *getSci3ObjectsPointer(); diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index 2ee027b846..688c35f996 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -26,6 +26,7 @@ #include "common/endian.h" #include "sci/sci.h" +#include "sci/engine/kernel.h" #include "sci/engine/features.h" #include "sci/engine/script.h" // for SCI_OBJ_EXPORTS and SCI_OBJ_SYNONYMS #include "sci/engine/segment.h" @@ -379,21 +380,25 @@ void Object::init(byte *buf, reg_t obj_pos, bool initVariables) { _baseObj = data; _pos = obj_pos; - if (getSciVersion() < SCI_VERSION_1_1) { + if (getSciVersion() <= SCI_VERSION_1_LATE) { _variables.resize(READ_LE_UINT16(data + kOffsetSelectorCounter)); _baseVars = (const uint16 *)(_baseObj + _variables.size() * 2); _baseMethod = (const uint16 *)(data + READ_LE_UINT16(data + kOffsetFunctionArea)); _methodCount = READ_LE_UINT16(_baseMethod - 1); - } else { + } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { _variables.resize(READ_SCI11ENDIAN_UINT16(data + 2)); _baseVars = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 4)); _baseMethod = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 6)); _methodCount = READ_SCI11ENDIAN_UINT16(_baseMethod); + } else if (getSciVersion() == SCI_VERSION_3) { + initSelectorsSci3(buf); } if (initVariables) { - for (uint i = 0; i < _variables.size(); i++) - _variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2))); + if (getSciVersion() <= SCI_VERSION_2_1) { + for (uint i = 0; i < _variables.size(); i++) + _variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2))); + } } } @@ -402,17 +407,20 @@ const Object *Object::getClass(SegManager *segMan) const { } int Object::locateVarSelector(SegManager *segMan, Selector slc) const { - const byte *buf; - uint varnum; + const byte *buf = 0; + uint varnum = 0; - if (getSciVersion() < SCI_VERSION_1_1) { + if (getSciVersion() <= SCI_VERSION_1_LATE) { varnum = getVarCount(); int selector_name_offset = varnum * 2 + kOffsetSelectorSegment; buf = _baseObj + selector_name_offset; - } else { + } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { const Object *obj = getClass(segMan); varnum = obj->getVariable(1).toUint16(); buf = (const byte *)obj->_baseVars; + } else if (getSciVersion() == SCI_VERSION_3) { + varnum = _variables.size(); + buf = (const byte *)_baseVars; } for (uint i = 0; i < varnum; i++) @@ -422,10 +430,24 @@ int Object::locateVarSelector(SegManager *segMan, Selector slc) const { return -1; // Failed } -bool Object::relocate(SegmentId segment, int location, size_t scriptSize) { +bool Object::relocateSci0Sci21(SegmentId segment, int location, size_t scriptSize) { return relocateBlock(_variables, getPos().offset, segment, location, scriptSize); } +bool Object::relocateSci3(SegmentId segment, int location, int offset, size_t scriptSize) { + assert(_propertyOffsetsSci3); + + for (uint i = 0; i < _variables.size(); ++i) { + if (location == _propertyOffsetsSci3[i]) { + _variables[i].segment = segment; + _variables[i].offset += offset; + return 1; + } + } + + return -1; +} + int Object::propertyOffsetToId(SegManager *segMan, int propertyOffset) const { int selectors = getVarCount(); @@ -480,6 +502,92 @@ bool Object::initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClas return false; } +const int EXTRA_GROUPS = 3; + +void Object::initSelectorsSci3(const byte *buf) { + const byte *groupInfo = _baseObj + 16; + const byte *selectorBase = groupInfo + EXTRA_GROUPS * 32 * 2; + int groups = g_sci->getKernel()->getSelectorNamesSize()/32; + int methods, properties; + + if (g_sci->getKernel()->getSelectorNamesSize() % 32) + ++groups; + + methods = properties = 0; + + // Selectors are divided into groups of 32, of which the first + // two selectors are always reserved (because their storage + // space is used by the typeMask). + // We don't know beforehand how many methods and properties + // there are, so we count them first. + for (int groupNr = 0; groupNr < groups; ++groupNr) { + byte groupLocation = groupInfo[groupNr]; + const byte *seeker = selectorBase + groupLocation * 32 * 2; + + if (groupLocation != 0) { + // This object actually has selectors belonging to this group + int typeMask = READ_SCI11ENDIAN_UINT32(seeker); + + for (int bit = 2; bit < 32; ++bit) { + int value = READ_SCI11ENDIAN_UINT16(seeker + bit * 2); + if (typeMask & (1 << bit)) { // Property + ++properties; + } else if (value != 0xffff) { // Method + ++methods; + } else { + // Undefined selector + } + + } + } + } + + _variables.resize(properties); + uint16 *methodIds = (uint16*) malloc(sizeof(uint16)*2*methods); + uint16 *propertyIds = (uint16*) malloc(sizeof(uint16)*properties); + uint16 *methodOffsets = (uint16*) malloc(sizeof(uint16)*2*methods); + uint16 *propertyOffsets = (uint16*) malloc(sizeof(uint16)*properties); + int propertyCounter = 0; + int methodCounter = 0; + + // Go through the whole thing again to get the property values + // and method pointers + for (int groupNr = 0; groupNr < groups; ++groupNr) { + byte groupLocation = groupInfo[groupNr]; + const byte *seeker = selectorBase + groupLocation * 32 * 2; + + if (groupLocation != 0) { + // This object actually has selectors belonging to this group + int typeMask = READ_SCI11ENDIAN_UINT32(seeker); + int groupBaseId = groupNr * 32; + + for (int bit = 2; bit < 32; ++bit) { + int value = READ_SCI11ENDIAN_UINT16(seeker + bit * 2); + if (typeMask & (1 << bit)) { // Property + propertyIds[propertyCounter] = groupBaseId + bit; + _variables[propertyCounter] = make_reg(0, value); + propertyOffsets[propertyCounter] = (seeker + bit * 2) - buf; + ++propertyCounter; + } else if (value != 0xffff) { // Method + methodIds[methodCounter * 2] = groupBaseId + bit; + methodIds[methodCounter * 2 + 1] = value + READ_SCI11ENDIAN_UINT32(buf); + methodOffsets[methodCounter] = (seeker + bit * 2) - buf; + ++methodCounter; + } else /* Undefined selector */ {}; + + } + } + } + + _superClassPosSci3 = make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 8)); + + _baseVars = propertyIds; + _baseMethod = methodIds; + _methodCount = methods; + _propertyOffsetsSci3 = propertyOffsets; + //_methodOffsetsSci3 = methodOffsets; +} + //-------------------- dynamic memory -------------------- reg_t DynMem::findCanonicAddress(SegManager *segMan, reg_t addr) const { diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index a2fe61729a..a674100673 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -233,37 +233,101 @@ public: _baseVars = 0; _baseMethod = 0; _methodCount = 0; + _propertyOffsetsSci3 = 0; } ~Object() { } - reg_t getSpeciesSelector() const { return _variables[_offset]; } - void setSpeciesSelector(reg_t value) { _variables[_offset] = value; } + reg_t getSpeciesSelector() const { + if (getSciVersion() <= SCI_VERSION_2_1) + return _variables[_offset]; + else // SCI3 + return make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 4)); + } - reg_t getSuperClassSelector() const { return _variables[_offset + 1]; } - void setSuperClassSelector(reg_t value) { _variables[_offset + 1] = value; } + void setSpeciesSelector(reg_t value) { + if (getSciVersion() <= SCI_VERSION_2_1) + _variables[_offset] = value; + else // SCI3 + warning("TODO: setSpeciesSelector called for SCI3"); + } - reg_t getInfoSelector() const { return _variables[_offset + 2]; } - void setInfoSelector(reg_t value) { _variables[_offset + 2] = value; } + reg_t getSuperClassSelector() const { + if (getSciVersion() <= SCI_VERSION_2_1) + return _variables[_offset + 1]; + else // SCI3 + return _superClassPosSci3; + } - reg_t getNameSelector() const { return _offset + 3 < (uint16)_variables.size() ? _variables[_offset + 3] : NULL_REG; } - void setNameSelector(reg_t value) { _variables[_offset + 3] = value; } + void setSuperClassSelector(reg_t value) { + if (getSciVersion() <= SCI_VERSION_2_1) + _variables[_offset + 1] = value; + else // SCI3 + _superClassPosSci3 = value; + } - reg_t getPropDictSelector() const { return _variables[2]; } - void setPropDictSelector(reg_t value) { _variables[2] = value; } + reg_t getInfoSelector() const { + if (getSciVersion() <= SCI_VERSION_2_1) + return _variables[_offset + 2]; + else // SCI3 + return make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 10)); + } - reg_t getClassScriptSelector() const { return _variables[4]; } - void setClassScriptSelector(reg_t value) { _variables[4] = value; } + // No setter for the -info- selector + + reg_t getNameSelector() const { + if (getSciVersion() <= SCI_VERSION_2_1) + return _offset + 3 < (uint16)_variables.size() ? _variables[_offset + 3] : NULL_REG; + else // SCI3 + return _variables.size() ? _variables[0] : NULL_REG; + } + + // No setter for the name selector + + reg_t getPropDictSelector() const { + if (getSciVersion() <= SCI_VERSION_2_1) + return _variables[2]; + else + // This should never occur, this is called from a SCI1.1 - SCI2.1 only function + error("getPropDictSelector called for SCI3"); + } + + void setPropDictSelector(reg_t value) { + if (getSciVersion() <= SCI_VERSION_2_1) + _variables[2] = value; + else + // This should never occur, this is called from a SCI1.1 - SCI2.1 only function + error("setPropDictSelector called for SCI3"); + } + + reg_t getClassScriptSelector() const { + if (getSciVersion() <= SCI_VERSION_2_1) + return _variables[4]; + else // SCI3 + return make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 6)); + } + + void setClassScriptSelector(reg_t value) { + if (getSciVersion() <= SCI_VERSION_2_1) + _variables[4] = value; + else // SCI3 + // This should never occur, this is called from a SCI1.1 - SCI2.1 only function + error("setClassScriptSelector called for SCI3"); + } Selector getVarSelector(uint16 i) const { return READ_SCI11ENDIAN_UINT16(_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--; return make_reg(_pos.segment, READ_SCI11ENDIAN_UINT16(_baseMethod + offset)); } Selector getFuncSelector(uint16 i) const { uint16 offset = (getSciVersion() < SCI_VERSION_1_1) ? i : i * 2 + 1; + if (getSciVersion() == SCI_VERSION_3) + offset--; return READ_SCI11ENDIAN_UINT16(_baseMethod + offset); } @@ -311,7 +375,8 @@ public: _baseVars = obj ? obj->_baseVars : NULL; } - bool relocate(SegmentId segment, int location, size_t scriptSize); + bool relocateSci0Sci21(SegmentId segment, int location, size_t scriptSize); + bool relocateSci3(SegmentId segment, int location, int offset, size_t scriptSize); int propertyOffsetToId(SegManager *segMan, int propertyOffset) const; @@ -321,15 +386,19 @@ public: void syncBaseObject(const byte *ptr) { _baseObj = ptr; } private: + void initSelectorsSci3(const byte *buf); + const byte *_baseObj; /**< base + object offset within base */ const uint16 *_baseVars; /**< Pointer to the varselector area for this object */ const uint16 *_baseMethod; /**< Pointer to the method selector area for this object */ + const uint16 *_propertyOffsetsSci3; Common::Array<reg_t> _variables; uint16 _methodCount; int _flags; uint16 _offset; reg_t _pos; /**< Object offset within its script; for clones, this is their base */ + reg_t _superClassPosSci3; /**< reg_t pointing to superclass for SCI3 */ }; /** Data stack */ |