aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/sci/engine/script.cpp4
-rw-r--r--engines/sci/engine/segment.cpp85
-rw-r--r--engines/sci/engine/segment.h5
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);