aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine/segment.cpp
diff options
context:
space:
mode:
authorMax Horn2010-02-03 01:34:15 +0000
committerMax Horn2010-02-03 01:34:15 +0000
commitbca7c6eef385b3818e1443038f3326f8f02a895a (patch)
tree650d50fe5e5a0eb7a07ef03b778da2540bdfeb7e /engines/sci/engine/segment.cpp
parentbec3a0d539b3fc23f56e09e895d06b457034faf2 (diff)
downloadscummvm-rg350-bca7c6eef385b3818e1443038f3326f8f02a895a.tar.gz
scummvm-rg350-bca7c6eef385b3818e1443038f3326f8f02a895a.tar.bz2
scummvm-rg350-bca7c6eef385b3818e1443038f3326f8f02a895a.zip
SCI: Move more stuff around
svn-id: r47836
Diffstat (limited to 'engines/sci/engine/segment.cpp')
-rw-r--r--engines/sci/engine/segment.cpp205
1 files changed, 202 insertions, 3 deletions
diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp
index 2fee80048b..5419de6f0b 100644
--- a/engines/sci/engine/segment.cpp
+++ b/engines/sci/engine/segment.cpp
@@ -121,9 +121,6 @@ bool Script::init(int script_nr, ResourceManager *resMan) {
_buf = (byte *)malloc(_bufSize);
-#ifdef DEBUG_segMan
- printf("_buf = %p ", _buf);
-#endif
if (!_buf) {
freeScript();
warning("Not enough memory space for script size");
@@ -149,6 +146,42 @@ bool Script::init(int script_nr, ResourceManager *resMan) {
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);
+
+ _scriptSize = script->size;
+ _heapSize = 0; // Set later
+
+ 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;
+ _heapSize = heap->size;
+
+ // Ensure that the start of the heap resource can be word-aligned.
+ if (script->size & 2) {
+ _bufSize++;
+ _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;
+ }
+ }
+}
+
Object *Script::allocateObject(uint16 offset) {
return &_objects[offset];
}
@@ -160,6 +193,152 @@ Object *Script::getObject(uint16 offset) {
return 0;
}
+Object *Script::scriptObjInit(reg_t obj_pos) {
+ Object *obj;
+
+ if (getSciVersion() < SCI_VERSION_1_1)
+ 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");
+
+ obj->init(_buf, obj_pos);
+
+ return obj;
+}
+
+void Script::scriptObjRemove(reg_t obj_pos) {
+ if (getSciVersion() < SCI_VERSION_1_1)
+ obj_pos.offset += 8;
+
+ _objects.erase(obj_pos.toUint16());
+}
+
+int Script::relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location) {
+ int rel = location - block_location;
+
+ if (rel < 0)
+ return 0;
+
+ uint idx = rel >> 1;
+
+ if (idx >= block.size())
+ return 0;
+
+ if (rel & 1) {
+ warning("Attempt to relocate odd variable #%d.5e (relative to %04x)\n", idx, block_location);
+ return 0;
+ }
+ block[idx].segment = segment; // Perform relocation
+ if (getSciVersion() >= SCI_VERSION_1_1)
+ block[idx].offset += _scriptSize;
+
+ return 1;
+}
+
+int Script::relocateLocal(SegmentId segment, int location) {
+ if (_localsBlock)
+ return relocateBlock(_localsBlock->_locals, _localsOffset, segment, location);
+ 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);
+}
+
+void Script::scriptAddCodeBlock(reg_t location) {
+ CodeBlock cb;
+ cb.pos = location;
+ cb.size = READ_LE_UINT16(_buf + location.offset - 2);
+ _codeBlocks.push_back(cb);
+}
+
+void Script::scriptRelocate(reg_t block) {
+ VERIFY(block.offset < (uint16)_bufSize && READ_LE_UINT16(_buf + block.offset) * 2 + block.offset < (uint16)_bufSize,
+ "Relocation block outside of script\n");
+
+ int count = READ_LE_UINT16(_buf + block.offset);
+
+ for (int i = 0; i <= count; i++) {
+ int pos = READ_LE_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;
+ }
+
+ 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");
+ }
+ }
+ }
+}
+
+void Script::heapRelocate(reg_t block) {
+ VERIFY(block.offset < (uint16)_heapSize && READ_LE_UINT16(_heapStart + block.offset) * 2 + block.offset < (uint16)_bufSize,
+ "Relocation block outside of script\n");
+
+ if (_relocated)
+ return;
+ _relocated = true;
+ int count = READ_LE_UINT16(_heapStart + block.offset);
+
+ for (int i = 0; i < count; i++) {
+ int pos = READ_LE_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 (relocateObject(it->_value, block.segment, pos))
+ 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++;
}
@@ -187,6 +366,26 @@ void Script::setExportTableOffset(int offset) {
}
}
+// TODO: This method should be Script method. The only reason
+// that it isn't is that it uses _exportsAreWide, which is true if
+// detectLofsType() == SCI_VERSION_1_MIDDLE
+// Maybe _exportsAreWide should become a Script member var, e.g. set
+// by setExportTableOffset?
+uint16 SegManager::validateExportFunc(int pubfunct, SegmentId seg) {
+ Script *scr = getScript(seg);
+ if (scr->_numExports <= pubfunct) {
+ warning("validateExportFunc(): pubfunct is invalid");
+ return 0;
+ }
+
+ if (_exportsAreWide)
+ pubfunct *= 2;
+ uint16 offset = READ_LE_UINT16((byte *)(scr->_exportTable + pubfunct));
+ VERIFY(offset < scr->_bufSize, "invalid export function pointer");
+
+ return offset;
+}
+
void Script::setSynonymsOffset(int offset) {
_synonyms = _buf + offset;
}