diff options
author | Walter van Niftrik | 2009-08-24 01:59:58 +0000 |
---|---|---|
committer | Walter van Niftrik | 2009-08-24 01:59:58 +0000 |
commit | 7359c8f9682fe42f430b00d729257e78b6e76b1d (patch) | |
tree | 2ffd830b694e58cbf3c0615fca51b65e76cf56a9 /engines/sci/engine | |
parent | a041ba4f48ae6a58cc795467c37fabb11bfd4163 (diff) | |
download | scummvm-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/engine')
-rw-r--r-- | engines/sci/engine/seg_manager.cpp | 135 | ||||
-rw-r--r-- | engines/sci/engine/seg_manager.h | 3 | ||||
-rw-r--r-- | engines/sci/engine/vm.cpp | 8 |
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 |