aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
authorWalter van Niftrik2009-08-24 01:59:58 +0000
committerWalter van Niftrik2009-08-24 01:59:58 +0000
commit7359c8f9682fe42f430b00d729257e78b6e76b1d (patch)
tree2ffd830b694e58cbf3c0615fca51b65e76cf56a9 /engines/sci
parenta041ba4f48ae6a58cc795467c37fabb11bfd4163 (diff)
downloadscummvm-rg350-7359c8f9682fe42f430b00d729257e78b6e76b1d.tar.gz
scummvm-rg350-7359c8f9682fe42f430b00d729257e78b6e76b1d.tar.bz2
scummvm-rg350-7359c8f9682fe42f430b00d729257e78b6e76b1d.zip
SCI: Read class table from vocab resource instead of scanning. This fixes
several "invalid selector" VM crashes caused by duplicate classes. svn-id: r43680
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/engine/seg_manager.cpp135
-rw-r--r--engines/sci/engine/seg_manager.h3
-rw-r--r--engines/sci/engine/vm.cpp8
3 files changed, 10 insertions, 136 deletions
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index 0c731d449c..0c88481125 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -71,10 +71,7 @@ SegManager::SegManager(ResourceManager *resMgr, SciVersion version) {
int result = 0;
- if (version >= SCI_VERSION_1_1)
- result = createSci11ClassTable();
- else
- result = createSci0ClassTable();
+ result = createClassTable();
if (result)
error("SegManager: Failed to initialize class table");
@@ -692,7 +689,6 @@ void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) {
return;
}
- _classtable[species].script = scr->nr;
_classtable[species].reg.segment = seg;
_classtable[species].reg.offset = classpos;
}
@@ -916,137 +912,24 @@ int SegManager::freeDynmem(reg_t addr) {
return 0; // OK
}
-int SegManager::createSci11ClassTable() {
- int scriptnr;
- unsigned int seeker_offset;
- char *seeker_ptr;
- int classnr;
-
+int SegManager::createClassTable() {
Resource *vocab996 = _resMgr->findResource(ResourceId(kResourceTypeVocab, 996), 1);
if (!vocab996)
- _classtable.resize(20);
- else
- _classtable.resize(vocab996->size >> 2);
-
- for (scriptnr = 0; scriptnr < 1000; scriptnr++) {
- Resource *heap = _resMgr->findResource(ResourceId(kResourceTypeHeap, scriptnr), 0);
-
- if (heap) {
- int global_vars = READ_LE_UINT16(heap->data + 2);
-
- seeker_ptr = (char*)heap->data + 4 + global_vars * 2;
- seeker_offset = 4 + global_vars * 2;
+ error("SegManager: failed to open vocab 996");
- while (READ_LE_UINT16((byte*)seeker_ptr) == SCRIPT_OBJECT_MAGIC_NUMBER) {
- if (READ_LE_UINT16((byte*)seeker_ptr + 14) & SCRIPT_INFO_CLASS) {
- classnr = READ_LE_UINT16((byte*)seeker_ptr + 10);
- if (classnr >= (int)_classtable.size()) {
- if (classnr >= SCRIPT_MAX_CLASSTABLE_SIZE) {
- warning("Invalid class number 0x%x in script.%d(0x%x), offset %04x",
- classnr, scriptnr, scriptnr, seeker_offset);
- return 1;
- }
+ int totalClasses = vocab996->size >> 2;
+ _classtable.resize(totalClasses);
- _classtable.resize(classnr + 1); // Adjust maximum number of entries
- }
+ for (uint16 classNr = 0; classNr < totalClasses; classNr++) {
+ uint16 scriptNr = READ_LE_UINT16(vocab996->data + classNr * 4 + 2);
- _classtable[classnr].reg.offset = seeker_offset;
- _classtable[classnr].reg.segment = 0;
- _classtable[classnr].script = scriptnr;
- }
-
- seeker_ptr += READ_LE_UINT16((byte*)seeker_ptr + 2) * 2;
- seeker_offset += READ_LE_UINT16((byte*)seeker_ptr + 2) * 2;
- }
- }
+ _classtable[classNr].reg = NULL_REG;
+ _classtable[classNr].script = scriptNr;
}
_resMgr->unlockResource(vocab996);
- vocab996 = NULL;
- return 0;
-}
-int SegManager::createSci0ClassTable() {
- int scriptnr;
- unsigned int seeker;
- int classnr;
- int magic_offset; // For strange scripts in older SCI versions
-
- Resource *vocab996 = _resMgr->findResource(ResourceId(kResourceTypeVocab, 996), 1);
- SciVersion version = _version; // for the offset defines
-
- if (!vocab996)
- _classtable.resize(20);
- else
- _classtable.resize(vocab996->size >> 2);
-
- for (scriptnr = 0; scriptnr < 1000; scriptnr++) {
- int objtype = 0;
- Resource *script = _resMgr->findResource(ResourceId(kResourceTypeScript, scriptnr), 0);
-
- if (script) {
- if (version == SCI_VERSION_0_EARLY) // check if we got an old script header
- magic_offset = seeker = 2;
- else
- magic_offset = seeker = 0;
-
- do {
- while (seeker < script->size) {
- unsigned int lastseeker = seeker;
- objtype = (int16)READ_LE_UINT16(script->data + seeker);
- if (objtype == SCI_OBJ_CLASS || objtype == SCI_OBJ_TERMINATOR)
- break;
- seeker += (int16)READ_LE_UINT16(script->data + seeker + 2);
- if (seeker <= lastseeker) {
- _classtable.clear();
- error("Script version is invalid");
- }
- }
-
- if (objtype == SCI_OBJ_CLASS) {
- int sugg_script;
-
- seeker -= SCRIPT_OBJECT_MAGIC_OFFSET; // Adjust position; script home is base +8 bytes
-
- classnr = (int16)READ_LE_UINT16(script->data + seeker + 4 + SCRIPT_SPECIES_OFFSET);
- if (classnr >= (int)_classtable.size()) {
-
- if (classnr >= SCRIPT_MAX_CLASSTABLE_SIZE) {
- warning("Invalid class number 0x%x in script.%d(0x%x), offset %04x",
- classnr, scriptnr, scriptnr, seeker);
- return 1;
- }
-
- _classtable.resize(classnr + 1); // Adjust maximum number of entries
- }
-
- // Map the class ID to the script the corresponding class is contained in
- // The script number is found in vocab.996, if it exists
- if (!vocab996 || (uint32)classnr >= vocab996->size >> 2)
- sugg_script = -1;
- else
- sugg_script = (int16)READ_LE_UINT16(vocab996->data + 2 + (classnr << 2));
-
- // First, test whether the script hasn't been claimed, or if it's been claimed by the wrong script
-
- if (sugg_script == -1 || scriptnr == sugg_script /*|| !s->_classtable[classnr].reg.segment*/) {
- // Now set the home script of the class
- _classtable[classnr].reg.offset = seeker + 4 - magic_offset;
- _classtable[classnr].reg.segment = 0;
- _classtable[classnr].script = scriptnr;
- }
-
- seeker += SCRIPT_OBJECT_MAGIC_OFFSET; // Re-adjust position
- seeker += (int16)READ_LE_UINT16(script->data + seeker + 2); // Move to next
- }
-
- } while (objtype != SCI_OBJ_TERMINATOR && seeker <= script->size);
-
- }
- }
- _resMgr->unlockResource(vocab996);
- vocab996 = NULL;
return 0;
}
diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h
index 5676990343..27c8ad446a 100644
--- a/engines/sci/engine/seg_manager.h
+++ b/engines/sci/engine/seg_manager.h
@@ -360,8 +360,7 @@ private:
LocalVariables *allocLocalsSegment(Script *scr, int count);
MemObject *memObjAllocate(SegmentId segid, int hash_id, MemObjectType type);
int deallocate(SegmentId seg, bool recursive);
- int createSci0ClassTable();
- int createSci11ClassTable();
+ int createClassTable();
Hunk *alloc_Hunk(reg_t *);
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index 613de69f05..fbdb3d1c85 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -312,13 +312,6 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
ObjVarRef varp;
switch (lookup_selector(s, send_obj, selector, &varp, &funcp)) {
case kSelectorNone:
- // WORKAROUND: LSL6 tries to access the invalid 'keep' selector of the game object.
- // FIXME: Find out if this is a game bug.
- if ((s->_gameName == "LSL6") && (selector == 0x18c)) {
- debug("LSL6 detected, continuing...");
- break;
- }
-
error("Send to invalid selector 0x%x of object at %04x:%04x", 0xffff & selector, PRINT_REG(send_obj));
break;
@@ -1660,7 +1653,6 @@ int script_instantiate_sci0(ResourceManager *resMgr, SegManager *segManager, Sci
return 1;
}
- segManager->_classtable[species].script = script_nr;
segManager->_classtable[species].reg = addr;
segManager->_classtable[species].reg.offset = classpos;
// Set technical class position-- into the block allocated for it