aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
authorFilippos Karapetis2010-11-17 11:15:52 +0000
committerFilippos Karapetis2010-11-17 11:15:52 +0000
commitb707d6e7dc1baf2fb403ecf5e6e67c5ffa1d7019 (patch)
tree6d9b657c26007671133baa2a63aaeae3f5e86574 /engines/sci
parent59ad5085bc317488ebb006737cc130c9cb100a80 (diff)
downloadscummvm-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
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/engine/script.cpp60
-rw-r--r--engines/sci/engine/script.h19
-rw-r--r--engines/sci/engine/segment.cpp126
-rw-r--r--engines/sci/engine/segment.h95
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 */