aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine/segment.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/engine/segment.cpp')
-rw-r--r--engines/sci/engine/segment.cpp425
1 files changed, 260 insertions, 165 deletions
diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp
index ab1a68d165..0e0a759d4b 100644
--- a/engines/sci/engine/segment.cpp
+++ b/engines/sci/engine/segment.cpp
@@ -27,6 +27,7 @@
#include "sci/sci.h"
#include "sci/engine/features.h"
+#include "sci/engine/script.h" // for SCI_OBJ_EXPORTS and SCI_OBJ_SYNONYMS
#include "sci/engine/segment.h"
#include "sci/engine/seg_manager.h"
#include "sci/engine/state.h"
@@ -100,8 +101,7 @@ Script::Script() : SegmentObj(SEG_TYPE_SCRIPT) {
_localsSegment = 0;
_localsBlock = NULL;
- _relocated = false;
- _markedAsDeleted = 0;
+ _markedAsDeleted = false;
}
Script::~Script() {
@@ -117,54 +117,39 @@ void Script::freeScript() {
_codeBlocks.clear();
}
-bool Script::init(int script_nr, ResourceManager *resMan) {
- setScriptSize(script_nr, resMan);
-
- _buf = (byte *)malloc(_bufSize);
-
- if (!_buf) {
- freeScript();
- warning("Not enough memory space for script size");
- _bufSize = 0;
- return false;
- }
+void Script::init(int script_nr, ResourceManager *resMan) {
+ Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
_localsOffset = 0;
_localsBlock = NULL;
_codeBlocks.clear();
- _relocated = false;
_markedAsDeleted = false;
_nr = script_nr;
-
- if (getSciVersion() >= SCI_VERSION_1_1)
- _heapStart = _buf + _scriptSize;
- else
- _heapStart = _buf;
-
- return true;
-}
-
-void Script::setScriptSize(int script_nr, ResourceManager *resMan) {
- Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
- Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
- bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
+ _buf = 0;
+ _heapStart = 0;
_scriptSize = script->size;
- _heapSize = 0; // Set later
+ _bufSize = script->size;
+ _heapSize = 0;
- if (!script || (getSciVersion() >= SCI_VERSION_1_1 && !heap)) {
- error("SegManager::setScriptSize: failed to load %s", !script ? "script" : "heap");
- }
- if (oldScriptHeader) {
- _bufSize = script->size + READ_LE_UINT16(script->data) * 2;
- //locals_size = READ_LE_UINT16(script->data) * 2;
- } else if (getSciVersion() < SCI_VERSION_1_1) {
- _bufSize = script->size;
- } else {
- _bufSize = script->size + heap->size;
+ _lockers = 1;
+
+ if (getSciVersion() == SCI_VERSION_0_EARLY) {
+ _bufSize += READ_LE_UINT16(script->data) * 2;
+ } else if (getSciVersion() >= SCI_VERSION_1_1) {
+ /**
+ * In SCI11, the heap was in a separate space from the script.
+ * We append it to the end of the script, and adjust addressing accordingly.
+ * However, since we address the heap with a 16-bit pointer, the combined
+ * size of the stack and the heap must be 64KB. So far this has worked
+ * for SCI11, SCI2 and SCI21 games. SCI3 games use a different script format,
+ * and theoretically they can exceed the 64KB boundary using relocation.
+ */
+ Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
+ _bufSize += heap->size;
_heapSize = heap->size;
// Ensure that the start of the heap resource can be word-aligned.
@@ -173,12 +158,56 @@ void Script::setScriptSize(int script_nr, ResourceManager *resMan) {
_scriptSize++;
}
- if (_bufSize > 65535) {
- error("Script and heap sizes combined exceed 64K."
- "This means a fundamental design bug was made in SCI\n"
- "regarding SCI1.1 games.\nPlease report this so it can be"
- "fixed in the next major version");
- return;
+ // As mentioned above, the script and the heap together should not exceed 64KB
+ if (_bufSize > 65535)
+ error("Script and heap sizes combined exceed 64K. This means a fundamental "
+ "design bug was made regarding SCI1.1 and newer games.\nPlease "
+ "report this error to the ScummVM team");
+ }
+}
+
+void Script::load(ResourceManager *resMan) {
+ Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, _nr), 0);
+ assert(script != 0);
+
+ _buf = (byte *)malloc(_bufSize);
+ assert(_buf);
+
+ assert(_bufSize >= script->size);
+ memcpy(_buf, script->data, script->size);
+
+ if (getSciVersion() >= SCI_VERSION_1_1) {
+ Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, _nr), 0);
+ assert(heap != 0);
+
+ _heapStart = _buf + _scriptSize;
+
+ assert(_bufSize - _scriptSize <= heap->size);
+ memcpy(_heapStart, heap->data, heap->size);
+ }
+
+ _codeBlocks.clear();
+
+ _exportTable = 0;
+ _numExports = 0;
+ _synonyms = 0;
+ _numSynonyms = 0;
+
+ if (getSciVersion() >= SCI_VERSION_1_1) {
+ if (READ_LE_UINT16(_buf + 1 + 5) > 0) {
+ _exportTable = (const uint16 *)(_buf + 1 + 5 + 2);
+ _numExports = READ_SCI11ENDIAN_UINT16(_exportTable - 1);
+ }
+ } else {
+ _exportTable = (const uint16 *)findBlock(SCI_OBJ_EXPORTS);
+ if (_exportTable) {
+ _numExports = READ_SCI11ENDIAN_UINT16(_exportTable + 1);
+ _exportTable += 3; // skip header plus 2 bytes (_exportTable is a uint16 pointer)
+ }
+ _synonyms = findBlock(SCI_OBJ_SYNONYMS);
+ if (_synonyms) {
+ _numSynonyms = READ_SCI11ENDIAN_UINT16(_synonyms + 2) / 4;
+ _synonyms += 4; // skip header
}
}
}
@@ -194,19 +223,26 @@ Object *Script::getObject(uint16 offset) {
return 0;
}
-Object *Script::scriptObjInit(reg_t obj_pos) {
+const Object *Script::getObject(uint16 offset) const {
+ if (_objects.contains(offset))
+ return &_objects[offset];
+ else
+ return 0;
+}
+
+Object *Script::scriptObjInit(reg_t obj_pos, bool fullObjectInit) {
Object *obj;
- if (getSciVersion() < SCI_VERSION_1_1)
+ if (getSciVersion() < SCI_VERSION_1_1 && fullObjectInit)
obj_pos.offset += 8; // magic offset (SCRIPT_OBJECT_MAGIC_OFFSET)
VERIFY(obj_pos.offset < _bufSize, "Attempt to initialize object beyond end of script\n");
obj = allocateObject(obj_pos.offset);
- VERIFY(obj_pos.offset + SCRIPT_FUNCTAREAPTR_OFFSET < (int)_bufSize, "Function area pointer stored beyond end of script\n");
+ VERIFY(obj_pos.offset + kOffsetFunctionArea < (int)_bufSize, "Function area pointer stored beyond end of script\n");
- obj->init(_buf, obj_pos);
+ obj->init(_buf, obj_pos, fullObjectInit);
return obj;
}
@@ -218,37 +254,34 @@ void Script::scriptObjRemove(reg_t obj_pos) {
_objects.erase(obj_pos.toUint16());
}
-int Script::relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location) {
+// This helper function is used by Script::relocateLocal and Object::relocate
+static bool relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location, size_t scriptSize) {
int rel = location - block_location;
if (rel < 0)
- return 0;
+ return false;
uint idx = rel >> 1;
if (idx >= block.size())
- return 0;
+ return false;
if (rel & 1) {
warning("Attempt to relocate odd variable #%d.5e (relative to %04x)\n", idx, block_location);
- return 0;
+ return false;
}
block[idx].segment = segment; // Perform relocation
if (getSciVersion() >= SCI_VERSION_1_1)
- block[idx].offset += _scriptSize;
+ block[idx].offset += scriptSize;
- return 1;
+ return true;
}
-int Script::relocateLocal(SegmentId segment, int location) {
+bool Script::relocateLocal(SegmentId segment, int location) {
if (_localsBlock)
- return relocateBlock(_localsBlock->_locals, _localsOffset, segment, location);
+ return relocateBlock(_localsBlock->_locals, _localsOffset, segment, location, _scriptSize);
else
- return 0; // No hands, no cookies
-}
-
-int Script::relocateObject(Object &obj, SegmentId segment, int location) {
- return relocateBlock(obj._variables, obj.getPos().offset, segment, location);
+ return false;
}
void Script::scriptAddCodeBlock(reg_t location) {
@@ -258,61 +291,35 @@ void Script::scriptAddCodeBlock(reg_t location) {
_codeBlocks.push_back(cb);
}
-void Script::scriptRelocate(reg_t block) {
- VERIFY(block.offset < (uint16)_bufSize && READ_SCI11ENDIAN_UINT16(_buf + block.offset) * 2 + block.offset < (uint16)_bufSize,
- "Relocation block outside of script\n");
-
- int count = READ_SCI11ENDIAN_UINT16(_buf + block.offset);
-
- for (int i = 0; i <= count; i++) {
- int pos = READ_SCI11ENDIAN_UINT16(_buf + block.offset + 2 + (i * 2));
- if (!pos)
- continue; // FIXME: A hack pending investigation
-
- if (!relocateLocal(block.segment, pos)) {
- bool done = false;
- uint k;
-
- ObjMap::iterator it;
- const ObjMap::iterator end = _objects.end();
- for (it = _objects.begin(); !done && it != end; ++it) {
- if (relocateObject(it->_value, block.segment, pos))
- done = true;
- }
-
- for (k = 0; !done && k < _codeBlocks.size(); k++) {
- if (pos >= _codeBlocks[k].pos.offset &&
- pos < _codeBlocks[k].pos.offset + _codeBlocks[k].size)
- done = true;
- }
+void Script::relocate(reg_t block) {
+ byte *heap = _buf;
+ uint16 heapSize = (uint16)_bufSize;
+ uint16 heapOffset = 0;
- if (!done) {
- printf("While processing relocation block %04x:%04x:\n", PRINT_REG(block));
- printf("Relocation failed for index %04x (%d/%d)\n", pos, i + 1, count);
- if (_localsBlock)
- printf("- locals: %d at %04x\n", _localsBlock->_locals.size(), _localsOffset);
- else
- printf("- No locals\n");
- for (it = _objects.begin(), k = 0; it != end; ++it, ++k)
- printf("- obj#%d at %04x w/ %d vars\n", k, it->_value.getPos().offset, it->_value.getVarCount());
- // SQ3 script 71 has broken relocation entries.
- printf("Trying to continue anyway...\n");
- }
- }
+ if (getSciVersion() >= SCI_VERSION_1_1) {
+ heap = _heapStart;
+ heapSize = (uint16)_heapSize;
+ heapOffset = _scriptSize;
}
-}
-void Script::heapRelocate(reg_t block) {
- VERIFY(block.offset < (uint16)_heapSize && READ_SCI11ENDIAN_UINT16(_heapStart + block.offset) * 2 + block.offset < (uint16)_bufSize,
+ VERIFY(block.offset < (uint16)heapSize && READ_SCI11ENDIAN_UINT16(heap + block.offset) * 2 + block.offset < (uint16)heapSize,
"Relocation block outside of script\n");
- if (_relocated)
- return;
- _relocated = true;
- int count = READ_SCI11ENDIAN_UINT16(_heapStart + block.offset);
+ int count = READ_SCI11ENDIAN_UINT16(heap + block.offset);
+ int exportIndex = 0;
for (int i = 0; i < count; i++) {
- int pos = READ_SCI11ENDIAN_UINT16(_heapStart + block.offset + 2 + (i * 2)) + _scriptSize;
+ int pos = READ_SCI11ENDIAN_UINT16(heap + block.offset + 2 + (exportIndex * 2)) + heapOffset;
+ // This occurs in SCI01/SCI1 games where every usually one export
+ // value is zero. It seems that in this situation, we should skip
+ // the export and move to the next one, though the total count
+ // of valid exports remains the same
+ if (!pos) {
+ exportIndex++;
+ pos = READ_SCI11ENDIAN_UINT16(heap + block.offset + 2 + (exportIndex * 2)) + heapOffset;
+ if (!pos)
+ error("Script::relocate(): Consecutive zero exports found");
+ }
if (!relocateLocal(block.segment, pos)) {
bool done = false;
@@ -321,22 +328,33 @@ void Script::heapRelocate(reg_t block) {
ObjMap::iterator it;
const ObjMap::iterator end = _objects.end();
for (it = _objects.begin(); !done && it != end; ++it) {
- if (relocateObject(it->_value, block.segment, pos))
+ if (it->_value.relocate(block.segment, pos, _scriptSize))
done = true;
}
+ // Sanity check for SCI0-SCI1
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ for (k = 0; !done && k < _codeBlocks.size(); k++) {
+ if (pos >= _codeBlocks[k].pos.offset &&
+ pos < _codeBlocks[k].pos.offset + _codeBlocks[k].size)
+ done = true;
+ }
+ }
+
if (!done) {
- printf("While processing relocation block %04x:%04x:\n", PRINT_REG(block));
- printf("Relocation failed for index %04x (%d/%d)\n", pos, i + 1, count);
+ debug("While processing relocation block %04x:%04x:\n", PRINT_REG(block));
+ debug("Relocation failed for index %04x (%d/%d)\n", pos, exportIndex + 1, count);
if (_localsBlock)
- printf("- locals: %d at %04x\n", _localsBlock->_locals.size(), _localsOffset);
+ debug("- locals: %d at %04x\n", _localsBlock->_locals.size(), _localsOffset);
else
- printf("- No locals\n");
+ debug("- No locals\n");
for (it = _objects.begin(), k = 0; it != end; ++it, ++k)
- printf("- obj#%d at %04x w/ %d vars\n", k, it->_value.getPos().offset, it->_value.getVarCount());
- error("Breakpoint in %s, line %d", __FILE__, __LINE__);
+ debug("- obj#%d at %04x w/ %d vars\n", k, it->_value.getPos().offset, it->_value.getVarCount());
+ debug("Trying to continue anyway...\n");
}
}
+
+ exportIndex++;
}
}
@@ -357,16 +375,6 @@ void Script::setLockers(int lockers) {
_lockers = lockers;
}
-void Script::setExportTableOffset(int offset) {
- if (offset) {
- _exportTable = (uint16 *)(_buf + offset + 2);
- _numExports = READ_SCI11ENDIAN_UINT16((byte *)(_exportTable - 1));
- } else {
- _exportTable = NULL;
- _numExports = 0;
- }
-}
-
uint16 Script::validateExportFunc(int pubfunct) {
bool exportsAreWide = (g_sci->_features->detectLofsType() == SCI_VERSION_1_MIDDLE);
@@ -377,28 +385,36 @@ uint16 Script::validateExportFunc(int pubfunct) {
if (exportsAreWide)
pubfunct *= 2;
- uint16 offset = READ_SCI11ENDIAN_UINT16((byte *)(_exportTable + pubfunct));
+ uint16 offset = READ_SCI11ENDIAN_UINT16(_exportTable + pubfunct);
VERIFY(offset < _bufSize, "invalid export function pointer");
return offset;
}
-void Script::setSynonymsOffset(int offset) {
- _synonyms = _buf + offset;
-}
+byte *Script::findBlock(int type) {
+ byte *buf = _buf;
+ bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
-byte *Script::getSynonyms() const {
- return _synonyms;
-}
+ if (oldScriptHeader)
+ buf += 2;
-void Script::setSynonymsNr(int n) {
- _numSynonyms = n;
-}
+ do {
+ int seekerType = READ_LE_UINT16(buf);
+
+ if (seekerType == 0)
+ break;
+ if (seekerType == type)
+ return buf;
-int Script::getSynonymsNr() const {
- return _numSynonyms;
+ int seekerSize = READ_LE_UINT16(buf + 2);
+ assert(seekerSize > 0);
+ buf += seekerSize;
+ } while (1);
+
+ return NULL;
}
+
// memory operations
void Script::mcpyInOut(int dst, const void *src, size_t n) {
@@ -511,7 +527,7 @@ SegmentRef SystemStrings::dereference(reg_t pointer) {
//-------------------- script --------------------
-reg_t Script::findCanonicAddress(SegManager *segMan, reg_t addr) {
+reg_t Script::findCanonicAddress(SegManager *segMan, reg_t addr) const {
addr.offset = 0;
return addr;
}
@@ -527,13 +543,13 @@ void Script::freeAtAddress(SegManager *segMan, reg_t addr) {
segMan->deallocateScript(_nr);
}
-void Script::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {
+void Script::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {
(*note)(param, make_reg(segId, 0));
}
-void Script::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void Script::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
if (addr.offset <= _bufSize && addr.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET && RAW_IS_OBJECT(_buf + addr.offset)) {
- Object *obj = getObject(addr.offset);
+ const Object *obj = getObject(addr.offset);
if (obj) {
// Note all local variables, if we have a local variable environment
if (_localsSegment)
@@ -553,16 +569,14 @@ void Script::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback not
//-------------------- clones --------------------
-void CloneTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
- Clone *clone;
-
+void CloneTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
// assert(addr.segment == _segId);
if (!isValidEntry(addr.offset)) {
error("Unexpected request for outgoing references from clone at %04x:%04x", PRINT_REG(addr));
}
- clone = &(_table[addr.offset]);
+ const Clone *clone = &(_table[addr.offset]);
// Emit all member variables (including references to the 'super' delegate)
for (uint i = 0; i < clone->getVarCount(); i++)
@@ -597,7 +611,7 @@ void CloneTable::freeAtAddress(SegManager *segMan, reg_t addr) {
//-------------------- locals --------------------
-reg_t LocalVariables::findCanonicAddress(SegManager *segMan, reg_t addr) {
+reg_t LocalVariables::findCanonicAddress(SegManager *segMan, reg_t addr) const {
// Reference the owning script
SegmentId owner_seg = segMan->getScriptSegment(script_id);
@@ -606,7 +620,7 @@ reg_t LocalVariables::findCanonicAddress(SegManager *segMan, reg_t addr) {
return make_reg(owner_seg, 0);
}
-void LocalVariables::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void LocalVariables::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
// assert(addr.segment == _segId);
for (uint i = 0; i < _locals.size(); i++)
@@ -615,12 +629,12 @@ void LocalVariables::listAllOutgoingReferences(reg_t addr, void *param, NoteCall
//-------------------- stack --------------------
-reg_t DataStack::findCanonicAddress(SegManager *segMan, reg_t addr) {
+reg_t DataStack::findCanonicAddress(SegManager *segMan, reg_t addr) const {
addr.offset = 0;
return addr;
}
-void DataStack::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void DataStack::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
fprintf(stderr, "Emitting %d stack entries\n", _capacity);
for (int i = 0; i < _capacity; i++)
(*note)(param, _entries[i]);
@@ -633,13 +647,13 @@ void ListTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
freeEntry(sub_addr.offset);
}
-void ListTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void ListTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
if (!isValidEntry(addr.offset)) {
warning("Invalid list referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
return;
}
- List *list = &(_table[addr.offset]);
+ const List *list = &(_table[addr.offset]);
note(param, list->first);
note(param, list->last);
@@ -653,12 +667,12 @@ void NodeTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
freeEntry(sub_addr.offset);
}
-void NodeTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void NodeTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
if (!isValidEntry(addr.offset)) {
warning("Invalid node referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
return;
}
- Node *node = &(_table[addr.offset]);
+ const Node *node = &(_table[addr.offset]);
// We need all four here. Can't just stick with 'pred' OR 'succ' because node operations allow us
// to walk around from any given node
@@ -673,20 +687,43 @@ void NodeTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback
//-------------------- object ----------------------------
-Object *Object::getClass(SegManager *segMan) {
+void Object::init(byte *buf, reg_t obj_pos, bool initVariables) {
+ byte *data = buf + obj_pos.offset;
+ _baseObj = data;
+ _pos = obj_pos;
+
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ _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 {
+ _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);
+ }
+
+ if (initVariables) {
+ for (uint i = 0; i < _variables.size(); i++)
+ _variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2)));
+ }
+}
+
+const Object *Object::getClass(SegManager *segMan) const {
return isClass() ? this : segMan->getObject(getSuperClassSelector());
}
-int Object::locateVarSelector(SegManager *segMan, Selector slc) {
- byte *buf;
+int Object::locateVarSelector(SegManager *segMan, Selector slc) const {
+ const byte *buf;
uint varnum;
if (getSciVersion() < SCI_VERSION_1_1) {
varnum = getVarCount();
- int selector_name_offset = varnum * 2 + SCRIPT_SELECTOR_OFFSET;
+ int selector_name_offset = varnum * 2 + kOffsetSelectorSegment;
buf = _baseObj + selector_name_offset;
} else {
- Object *obj = getClass(segMan);
+ const Object *obj = getClass(segMan);
varnum = obj->getVariable(1).toUint16();
buf = (byte *)obj->_baseVars;
}
@@ -698,14 +735,72 @@ int Object::locateVarSelector(SegManager *segMan, Selector slc) {
return -1; // Failed
}
+bool Object::relocate(SegmentId segment, int location, size_t scriptSize) {
+ return relocateBlock(_variables, getPos().offset, segment, location, scriptSize);
+}
+
+int Object::propertyOffsetToId(SegManager *segMan, int propertyOffset) const {
+ int selectors = getVarCount();
+
+ if (propertyOffset < 0 || (propertyOffset >> 1) >= selectors) {
+ warning("Applied propertyOffsetToId to invalid property offset %x (property #%d not in [0..%d])",
+ propertyOffset, propertyOffset >> 1, selectors - 1);
+ return -1;
+ }
+
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ const byte *selectoroffset = ((const byte *)(_baseObj)) + kOffsetSelectorSegment + selectors * 2;
+ return READ_SCI11ENDIAN_UINT16(selectoroffset + propertyOffset);
+ } else {
+ const Object *obj = this;
+ if (!isClass())
+ obj = segMan->getObject(getSuperClassSelector());
+
+ return READ_SCI11ENDIAN_UINT16((const byte *)obj->_baseVars + propertyOffset);
+ }
+}
+
+void Object::initSpecies(SegManager *segMan, reg_t addr) {
+ uint16 speciesOffset = getSpeciesSelector().offset;
+
+ if (speciesOffset == 0xffff) // -1
+ setSpeciesSelector(NULL_REG); // no species
+ else
+ setSpeciesSelector(segMan->getClassAddress(speciesOffset, SCRIPT_GET_LOCK, addr));
+}
+
+void Object::initSuperClass(SegManager *segMan, reg_t addr) {
+ uint16 superClassOffset = getSuperClassSelector().offset;
+
+ if (superClassOffset == 0xffff) // -1
+ setSuperClassSelector(NULL_REG); // no superclass
+ else
+ setSuperClassSelector(segMan->getClassAddress(superClassOffset, SCRIPT_GET_LOCK, addr));
+}
+
+bool Object::initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass) {
+ const Object *baseObj = segMan->getObject(getSpeciesSelector());
+
+ if (baseObj) {
+ _variables.resize(baseObj->getVarCount());
+ // Copy base from species class, as we need its selector IDs
+ _baseObj = baseObj->_baseObj;
+ if (doInitSuperClass)
+ initSuperClass(segMan, addr);
+ return true;
+ }
+
+ return false;
+}
+
//-------------------- dynamic memory --------------------
-reg_t DynMem::findCanonicAddress(SegManager *segMan, reg_t addr) {
+reg_t DynMem::findCanonicAddress(SegManager *segMan, reg_t addr) const {
addr.offset = 0;
return addr;
}
-void DynMem::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {
+void DynMem::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {
(*note)(param, make_reg(segId, 0));
}
@@ -724,13 +819,13 @@ void ArrayTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
freeEntry(sub_addr.offset);
}
-void ArrayTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void ArrayTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
if (!isValidEntry(addr.offset)) {
warning("Invalid array referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
return;
}
- SciArray<reg_t> *array = &(_table[addr.offset]);
+ const SciArray<reg_t> *array = &(_table[addr.offset]);
for (uint32 i = 0; i < array->getSize(); i++) {
reg_t value = array->getValue(i);
@@ -739,7 +834,7 @@ void ArrayTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback
}
}
-Common::String SciString::toString() {
+Common::String SciString::toString() const {
if (_type != 3)
error("SciString::toString(): Array is not a string");
@@ -750,7 +845,7 @@ Common::String SciString::toString() {
return string;
}
-void SciString::fromString(Common::String string) {
+void SciString::fromString(const Common::String &string) {
if (_type != 3)
error("SciString::fromString(): Array is not a string");