diff options
-rw-r--r-- | engines/sci/engine/script.cpp | 4 | ||||
-rw-r--r-- | engines/sci/engine/segment.cpp | 85 | ||||
-rw-r--r-- | engines/sci/engine/segment.h | 5 |
3 files changed, 38 insertions, 56 deletions
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 99a567d1e7..aa975cc1d0 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -419,7 +419,7 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr } while (objType != 0 && curOffset < scr->getScriptSize() - 2); if (relocation >= 0) - scr->scriptRelocate(make_reg(seg_id, relocation)); + scr->relocate(make_reg(seg_id, relocation)); return seg_id; // instantiation successful } @@ -439,7 +439,7 @@ int script_instantiate_sci11(ResourceManager *resMan, SegManager *segMan, int sc int heapStart = scr->getScriptSize(); segMan->scriptInitialiseLocals(make_reg(seg_id, heapStart + 4)); segMan->scriptInitialiseObjectsSci11(seg_id); - scr->heapRelocate(make_reg(seg_id, READ_SCI11ENDIAN_UINT16(scr->_heapStart))); + scr->relocate(make_reg(seg_id, READ_SCI11ENDIAN_UINT16(scr->_heapStart))); return seg_id; } diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index a8c4eb73f6..bdd9fbc966 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -100,7 +100,6 @@ Script::Script() : SegmentObj(SEG_TYPE_SCRIPT) { _localsSegment = 0; _localsBlock = NULL; - _relocated = false; _markedAsDeleted = 0; } @@ -125,7 +124,6 @@ void Script::init(int script_nr, ResourceManager *resMan) { _codeBlocks.clear(); - _relocated = false; _markedAsDeleted = false; _nr = script_nr; @@ -139,6 +137,14 @@ void Script::init(int script_nr, ResourceManager *resMan) { 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; @@ -149,7 +155,11 @@ void Script::init(int script_nr, ResourceManager *resMan) { _scriptSize++; } - assert(_bufSize <= 65535); + // 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"); } } @@ -253,14 +263,24 @@ 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, +void Script::relocate(reg_t block) { + byte *heap = _buf; + uint16 heapSize = (uint16)_bufSize; + uint16 heapOffset = 0; + + if (getSciVersion() >= SCI_VERSION_1_1) { + heap = _heapStart; + heapSize = (uint16)_heapSize; + heapOffset = _scriptSize; + } + + VERIFY(block.offset < (uint16)heapSize && READ_SCI11ENDIAN_UINT16(heap + block.offset) * 2 + block.offset < (uint16)heapSize, "Relocation block outside of script\n"); - int count = READ_SCI11ENDIAN_UINT16(_buf + block.offset); + int count = READ_SCI11ENDIAN_UINT16(heap + block.offset); - for (int i = 0; i <= count; i++) { - int pos = READ_SCI11ENDIAN_UINT16(_buf + block.offset + 2 + (i * 2)); + for (int i = 0; i < count; i++) { + int pos = READ_SCI11ENDIAN_UINT16(heap + block.offset + 2 + (i * 2)) + heapOffset; // This occurs in SCI01/SCI1 games where every other export // value is zero. I have no idea what it's supposed to mean. // @@ -281,10 +301,13 @@ void Script::scriptRelocate(reg_t block) { 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; + // 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) { @@ -303,44 +326,6 @@ void Script::scriptRelocate(reg_t block) { } } -void Script::heapRelocate(reg_t block) { - VERIFY(block.offset < (uint16)_heapSize && READ_SCI11ENDIAN_UINT16(_heapStart + block.offset) * 2 + block.offset < (uint16)_bufSize, - "Relocation block outside of script\n"); - - if (_relocated) - return; - _relocated = true; - int count = READ_SCI11ENDIAN_UINT16(_heapStart + block.offset); - - for (int i = 0; i < count; i++) { - int pos = READ_SCI11ENDIAN_UINT16(_heapStart + block.offset + 2 + (i * 2)) + _scriptSize; - - 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 (it->_value.relocate(block.segment, pos, _scriptSize)) - 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); - 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()); - error("Breakpoint in %s, line %d", __FILE__, __LINE__); - } - } - } -} - void Script::incrementLockers() { _lockers++; } diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 127ab28b7e..7b0828ab6b 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -355,7 +355,6 @@ public: LocalVariables *_localsBlock; Common::Array<CodeBlock> _codeBlocks; - bool _relocated; bool _markedAsDeleted; public: @@ -409,9 +408,7 @@ public: * @param obj_pos Location (segment, offset) of the block * @return Location of the relocation block */ - void scriptRelocate(reg_t block); - - void heapRelocate(reg_t block); + void relocate(reg_t block); private: bool relocateLocal(SegmentId segment, int location); |