diff options
| author | Max Horn | 2010-02-02 22:50:32 +0000 |
|---|---|---|
| committer | Max Horn | 2010-02-02 22:50:32 +0000 |
| commit | 6c322506dd15b164028f8c560e55323f1b834711 (patch) | |
| tree | 2e233495329c36bb5df7c38215f0a6d89ac07a67 /engines/sci/engine/script.cpp | |
| parent | 5d80990380a8438dc474cdd5778807b7a72e2501 (diff) | |
| download | scummvm-rg350-6c322506dd15b164028f8c560e55323f1b834711.tar.gz scummvm-rg350-6c322506dd15b164028f8c560e55323f1b834711.tar.bz2 scummvm-rg350-6c322506dd15b164028f8c560e55323f1b834711.zip | |
SCI: Move some code around (no code changes)
svn-id: r47823
Diffstat (limited to 'engines/sci/engine/script.cpp')
| -rw-r--r-- | engines/sci/engine/script.cpp | 602 |
1 files changed, 289 insertions, 313 deletions
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 1c898da4e5..604aff557c 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -91,6 +91,8 @@ opcode_format g_opcode_formats[128][4] = { }; #undef END +// TODO: script_adjust_opcode_formats should probably be part of the +// constructor (?) of a VirtualMachine or a ScriptManager class. void script_adjust_opcode_formats(EngineState *s) { // TODO: Check that this is correct if (s->detectLofsType() != SCI_VERSION_0_EARLY) { @@ -112,380 +114,354 @@ void script_adjust_opcode_formats(EngineState *s) { #endif } -#if 1 +#define INST_LOOKUP_CLASS(id) ((id == 0xffff)? NULL_REG : segMan->getClassAddress(id, SCRIPT_GET_LOCK, reg)) -#define FIND_SELECTOR(_slc_) _selectorCache._slc_ = findSelector(#_slc_) -#define FIND_SELECTOR2(_slc_, _slcstr_) _selectorCache._slc_ = findSelector(_slcstr_) +int script_instantiate_common(ResourceManager *resMan, SegManager *segMan, int script_nr, Resource **script, Resource **heap, int *was_new) { + *was_new = 1; -#else + *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0); + if (getSciVersion() >= SCI_VERSION_1_1) + *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0); -// The defines below can be used to construct static selector tables for games which don't have -// a vocab.997 resource, by dumping the selector table from other similar versions or games -#define FIND_SELECTOR(_slc_) _selectorCache._slc_ = findSelector(#_slc_); \ - printf("\t{ \"%s\", %d },\n", #_slc_, _selectorCache._slc_) + if (!*script || (getSciVersion() >= SCI_VERSION_1_1 && !heap)) { + warning("Script 0x%x requested but not found", script_nr); + if (getSciVersion() >= SCI_VERSION_1_1) { + if (*heap) + warning("Inconsistency: heap resource WAS found"); + else if (*script) + warning("Inconsistency: script resource WAS found"); + } + return 0; + } -#define FIND_SELECTOR2(_slc_, _slcstr_) _selectorCache._slc_ = findSelector(_slcstr_); \ - printf("\t{ \"%s\", %d },\n", _slcstr_, _selectorCache._slc_) + SegmentId seg_id = segMan->getScriptSegment(script_nr); + Script *scr = segMan->getScriptIfLoaded(seg_id); + if (scr) { + if (!scr->isMarkedAsDeleted()) { + scr->incrementLockers(); + return seg_id; + } else { + scr->freeScript(); + } + } else { + scr = segMan->allocateScript(script_nr, &seg_id); + if (!scr) { // ALL YOUR SCRIPT BASE ARE BELONG TO US + error("Not enough heap space for script size 0x%x of script 0x%x (Should this happen?)", (*script)->size, script_nr); + return 0; + } + } -#endif + scr->init(script_nr, resMan); -void Kernel::mapSelectors() { - // species - // superClass - // -info- - FIND_SELECTOR(y); - FIND_SELECTOR(x); - FIND_SELECTOR(view); - FIND_SELECTOR(loop); - FIND_SELECTOR(cel); - FIND_SELECTOR(underBits); - FIND_SELECTOR(nsTop); - FIND_SELECTOR(nsLeft); - FIND_SELECTOR(nsBottom); - FIND_SELECTOR(lsTop); - FIND_SELECTOR(lsLeft); - FIND_SELECTOR(lsBottom); - FIND_SELECTOR(lsRight); - FIND_SELECTOR(nsRight); - FIND_SELECTOR(signal); - FIND_SELECTOR(illegalBits); - FIND_SELECTOR(brTop); - FIND_SELECTOR(brLeft); - FIND_SELECTOR(brBottom); - FIND_SELECTOR(brRight); - // name - // key - // time - FIND_SELECTOR(text); - FIND_SELECTOR(elements); - // color - // back - FIND_SELECTOR(mode); - // style - FIND_SELECTOR(state); - FIND_SELECTOR(font); - FIND_SELECTOR(type); - // window - FIND_SELECTOR(cursor); - FIND_SELECTOR(max); - // mark - // who - FIND_SELECTOR(message); - // edit - FIND_SELECTOR(play); - FIND_SELECTOR(number); - FIND_SELECTOR(handle); // nodePtr - FIND_SELECTOR(client); - FIND_SELECTOR(dx); - FIND_SELECTOR(dy); - FIND_SELECTOR2(b_movCnt, "b-moveCnt"); - FIND_SELECTOR2(b_i1, "b-i1"); - FIND_SELECTOR2(b_i2, "b-i2"); - FIND_SELECTOR2(b_di, "b-di"); - FIND_SELECTOR2(b_xAxis, "b-xAxis"); - FIND_SELECTOR2(b_incr, "b-incr"); - FIND_SELECTOR(xStep); - FIND_SELECTOR(yStep); - FIND_SELECTOR(moveSpeed); - FIND_SELECTOR(canBeHere); // cantBeHere - FIND_SELECTOR(heading); - FIND_SELECTOR(mover); - FIND_SELECTOR(doit); - FIND_SELECTOR(isBlocked); - FIND_SELECTOR(looper); - FIND_SELECTOR(priority); - FIND_SELECTOR(modifiers); - FIND_SELECTOR(replay); - // setPri - // at - // next - // done - // width - FIND_SELECTOR(wordFail); - FIND_SELECTOR(syntaxFail); - // semanticFail - // pragmaFail - // said - FIND_SELECTOR(claimed); - // value - // save - // restore - // title - // button - // icon - // draw - FIND_SELECTOR2(delete_, "delete"); - FIND_SELECTOR(z); - // ----------------------------- - FIND_SELECTOR(size); - FIND_SELECTOR(moveDone); - FIND_SELECTOR(vol); - FIND_SELECTOR(pri); - FIND_SELECTOR(min); - FIND_SELECTOR(sec); - FIND_SELECTOR(frame); - FIND_SELECTOR(dataInc); - FIND_SELECTOR(palette); - FIND_SELECTOR(cantBeHere); - FIND_SELECTOR(nodePtr); - FIND_SELECTOR(flags); - FIND_SELECTOR(points); - FIND_SELECTOR(syncCue); - FIND_SELECTOR(syncTime); - FIND_SELECTOR(printLang); - FIND_SELECTOR(subtitleLang); - FIND_SELECTOR(parseLang); - FIND_SELECTOR(overlay); - FIND_SELECTOR(setCursor); - FIND_SELECTOR(topString); - FIND_SELECTOR(scaleSignal); - FIND_SELECTOR(scaleX); - FIND_SELECTOR(scaleY); + reg_t reg; + reg.segment = seg_id; + reg.offset = 0; -#ifdef ENABLE_SCI32 - FIND_SELECTOR(data); - FIND_SELECTOR(picture); - FIND_SELECTOR(plane); - FIND_SELECTOR(top); - FIND_SELECTOR(left); -#endif + // Set heap position (beyond the size word) + scr->setLockers(1); + scr->setExportTableOffset(0); + scr->setSynonymsOffset(0); + scr->setSynonymsNr(0); + + *was_new = 0; + + return seg_id; } -void Kernel::dumpScriptObject(char *data, int seeker, int objsize) { - int selectors, overloads, selectorsize; - int species = (int16)READ_LE_UINT16((unsigned char *) data + 8 + seeker); - int superclass = (int16)READ_LE_UINT16((unsigned char *) data + 10 + seeker); - int namepos = (int16)READ_LE_UINT16((unsigned char *) data + 14 + seeker); - int i = 0; +int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int script_nr) { + int objtype; + unsigned int objlength; + int relocation = -1; + int magic_pos_adder; // Usually 0; 2 for older SCI versions + Resource *script; + int was_new; + bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY); + + const int seg_id = script_instantiate_common(resMan, segMan, script_nr, &script, NULL, &was_new); + + if (was_new) + return seg_id; - printf("Object\n"); + Script *scr = segMan->getScript(seg_id); - Common::hexdump((unsigned char *) data + seeker, objsize - 4, 16, seeker); - //-4 because the size includes the two-word header + if (oldScriptHeader) { + // + int locals_nr = READ_LE_UINT16(script->data); - printf("Name: %s\n", namepos ? ((char *)(data + namepos)) : "<unknown>"); - printf("Superclass: %x\n", superclass); - printf("Species: %x\n", species); - printf("-info-:%x\n", (int16)READ_LE_UINT16((unsigned char *) data + 12 + seeker) & 0xffff); + // Old script block + // There won't be a localvar block in this case + // Instead, the script starts with a 16 bit int specifying the + // number of locals we need; these are then allocated and zeroed. - printf("Function area offset: %x\n", (int16)READ_LE_UINT16((unsigned char *) data + seeker + 4)); - printf("Selectors [%x]:\n", selectors = (selectorsize = (int16)READ_LE_UINT16((unsigned char *) data + seeker + 6))); + scr->mcpyInOut(0, script->data, script->size); + magic_pos_adder = 2; // Step over the funny prefix - seeker += 8; + if (locals_nr) + segMan->scriptInitialiseLocalsZero(seg_id, locals_nr); - while (selectors--) { - printf(" [#%03x] = 0x%x\n", i++, (int16)READ_LE_UINT16((unsigned char *)data + seeker) & 0xffff); - seeker += 2; + } else { + scr->mcpyInOut(0, script->data, script->size); + magic_pos_adder = 0; } - printf("Overridden functions: %x\n", selectors = overloads = (int16)READ_LE_UINT16((unsigned char *)data + seeker)); + // Now do a first pass through the script objects to find the + // export table and local variable block - seeker += 2; + reg_t reg; + reg.segment = seg_id; + reg.offset = magic_pos_adder; - if (overloads < 100) - while (overloads--) { - int selector = (int16)READ_LE_UINT16((unsigned char *) data + (seeker)); + objlength = 0; - printf(" [%03x] %s: @", selector & 0xffff, (selector >= 0 && selector < (int)_selectorNames.size()) ? _selectorNames[selector].c_str() : "<?>"); - printf("%04x\n", (int16)READ_LE_UINT16((unsigned char *)data + seeker + selectors*2 + 2) & 0xffff); + do { + reg_t data_base; + reg_t addr; + reg.offset += objlength; // Step over the last checked object + objtype = scr->getHeap(reg.offset); + if (!objtype) + break; + + objlength = scr->getHeap(reg.offset + 2); - seeker += 2; + // This happens in some demos (e.g. the EcoQuest 1 demo). Not sure what is the + // actual cause of it, but the scripts of these demos can't be loaded properly + // and we're stuck forever in this loop, as objlength never changes + if (!objlength) { + warning("script_instantiate_sci0: objlength is 0, unable to parse script"); + return 0; } -} -void Kernel::dumpScriptClass(char *data, int seeker, int objsize) { - int selectors, overloads, selectorsize; - int species = (int16)READ_LE_UINT16((unsigned char *) data + 8 + seeker); - int superclass = (int16)READ_LE_UINT16((unsigned char *) data + 10 + seeker); - int namepos = (int16)READ_LE_UINT16((unsigned char *) data + 14 + seeker); + data_base = reg; + data_base.offset += 4; - printf("Class\n"); + addr = data_base; - Common::hexdump((unsigned char *) data + seeker, objsize - 4, 16, seeker); + switch (objtype) { + case SCI_OBJ_EXPORTS: { + scr->setExportTableOffset(data_base.offset); + } + break; + + case SCI_OBJ_SYNONYMS: + scr->setSynonymsOffset(addr.offset); // +4 is to step over the header + scr->setSynonymsNr((objlength) / 4); + break; + + case SCI_OBJ_LOCALVARS: + segMan->scriptInitialiseLocals(data_base); + break; - printf("Name: %s\n", namepos ? ((char *)data + namepos) : "<unknown>"); - printf("Superclass: %x\n", superclass); - printf("Species: %x\n", species); - printf("-info-:%x\n", (int16)READ_LE_UINT16((unsigned char *)data + 12 + seeker) & 0xffff); + case SCI_OBJ_CLASS: { + int classpos = addr.offset - SCRIPT_OBJECT_MAGIC_OFFSET; + int species; + species = scr->getHeap(addr.offset - SCRIPT_OBJECT_MAGIC_OFFSET + SCRIPT_SPECIES_OFFSET); + if (species < 0 || species >= (int)segMan->_classtable.size()) { + if (species == (int)segMan->_classtable.size()) { + // Happens in the LSL2 demo + warning("Applying workaround for an off-by-one invalid species access"); + segMan->_classtable.resize(segMan->_classtable.size() + 1); + } else { + warning("Invalid species %d(0x%x) not in interval " + "[0,%d) while instantiating script %d\n", + species, species, segMan->_classtable.size(), + script_nr); + return 0; + } + } - printf("Function area offset: %x\n", (int16)READ_LE_UINT16((unsigned char *)data + seeker + 4)); - printf("Selectors [%x]:\n", selectors = (selectorsize = (int16)READ_LE_UINT16((unsigned char *)data + seeker + 6))); + segMan->_classtable[species].reg = addr; + segMan->_classtable[species].reg.offset = classpos; + // Set technical class position-- into the block allocated for it + } + break; - seeker += 8; - selectorsize <<= 1; + default: + break; + } + } while (objtype != 0); - while (selectors--) { - int selector = (int16)READ_LE_UINT16((unsigned char *) data + (seeker) + selectorsize); + // And now a second pass to adjust objects and class pointers, and the general pointers - printf(" [%03x] %s = 0x%x\n", 0xffff & selector, (selector >= 0 && selector < (int)_selectorNames.size()) ? _selectorNames[selector].c_str() : "<?>", - (int16)READ_LE_UINT16((unsigned char *)data + seeker) & 0xffff); + objlength = 0; + reg.offset = magic_pos_adder; // Reset counter - seeker += 2; - } + do { + reg_t addr; + reg.offset += objlength; // Step over the last checked object + objtype = scr->getHeap(reg.offset); + if (!objtype) + break; - seeker += selectorsize; + objlength = scr->getHeap(reg.offset + 2); - printf("Overloaded functions: %x\n", selectors = overloads = (int16)READ_LE_UINT16((unsigned char *)data + seeker)); + addr = reg; + addr.offset += 4; // Step over header - seeker += 2; + switch (objtype) { + case SCI_OBJ_CODE: + scr->scriptAddCodeBlock(addr); + break; + case SCI_OBJ_OBJECT: + case SCI_OBJ_CLASS: { // object or class? + Object *obj = scr->scriptObjInit(addr); - while (overloads--) { - int selector = (int16)READ_LE_UINT16((unsigned char *)data + (seeker)); - fprintf(stderr, "selector=%d; selectorNames.size() =%d\n", selector, _selectorNames.size()); - printf(" [%03x] %s: @", selector & 0xffff, (selector >= 0 && selector < (int)_selectorNames.size()) ? - _selectorNames[selector].c_str() : "<?>"); - printf("%04x\n", (int16)READ_LE_UINT16((unsigned char *)data + seeker + selectors * 2 + 2) & 0xffff); + // Instantiate the superclass, if neccessary + obj->setSpeciesSelector(INST_LOOKUP_CLASS(obj->getSpeciesSelector().offset)); - seeker += 2; - } -} + Object *baseObj = segMan->getObject(obj->getSpeciesSelector()); -void Kernel::dissectScript(int scriptNumber, Vocabulary *vocab) { - int objectctr[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - unsigned int _seeker = 0; - Resource *script = _resMan->findResource(ResourceId(kResourceTypeScript, scriptNumber), 0); + if (baseObj) { + obj->setVarCount(baseObj->getVarCount()); + // Copy base from species class, as we need its selector IDs + obj->_baseObj = baseObj->_baseObj; - if (!script) { - warning("dissectScript(): Script not found!\n"); - return; - } + obj->setSuperClassSelector(INST_LOOKUP_CLASS(obj->getSuperClassSelector().offset)); + } else { + warning("Failed to locate base object for object at %04X:%04X; skipping", PRINT_REG(addr)); - while (_seeker < script->size) { - int objtype = (int16)READ_LE_UINT16(script->data + _seeker); - int objsize; - unsigned int seeker = _seeker + 4; + scr->scriptObjRemove(addr); + } + } // if object or class + break; + case SCI_OBJ_POINTERS: // A relocation table + relocation = addr.offset; + break; - if (!objtype) { - printf("End of script object (#0) encountered.\n"); - printf("Classes: %i, Objects: %i, Export: %i,\n Var: %i (all base 10)", - objectctr[6], objectctr[1], objectctr[7], objectctr[10]); - return; + default: + break; } - printf("\n"); + } while (objtype != 0 && reg.offset < script->size - 2); + + if (relocation >= 0) + scr->scriptRelocate(make_reg(seg_id, relocation)); - objsize = (int16)READ_LE_UINT16(script->data + _seeker + 2); + return reg.segment; // instantiation successful +} - printf("Obj type #%x, size 0x%x: ", objtype, objsize); +int script_instantiate_sci11(ResourceManager *resMan, SegManager *segMan, int script_nr) { + Resource *script, *heap; + int _heapStart; + reg_t reg; + int was_new; - _seeker += objsize; + const int seg_id = script_instantiate_common(resMan, segMan, script_nr, &script, &heap, &was_new); - objectctr[objtype]++; + if (was_new) + return seg_id; - switch (objtype) { - case SCI_OBJ_OBJECT: - dumpScriptObject((char *)script->data, seeker, objsize); - break; + Script *scr = segMan->getScript(seg_id); - case SCI_OBJ_CODE: { - printf("Code\n"); - Common::hexdump(script->data + seeker, objsize - 4, 16, seeker); - }; - break; + _heapStart = script->size; + if (script->size & 2) + _heapStart ++; - case 3: { - printf("<unknown>\n"); - Common::hexdump(script->data + seeker, objsize - 4, 16, seeker); - }; - break; + scr->mcpyInOut(0, script->data, script->size); + scr->mcpyInOut(_heapStart, heap->data, heap->size); - case SCI_OBJ_SAID: { - printf("Said\n"); - Common::hexdump(script->data + seeker, objsize - 4, 16, seeker); - - printf("%04x: ", seeker); - while (seeker < _seeker) { - unsigned char nextitem = script->data [seeker++]; - if (nextitem == 0xFF) - printf("\n%04x: ", seeker); - else if (nextitem >= 0xF0) { - switch (nextitem) { - case 0xf0: - printf(", "); - break; - case 0xf1: - printf("& "); - break; - case 0xf2: - printf("/ "); - break; - case 0xf3: - printf("( "); - break; - case 0xf4: - printf(") "); - break; - case 0xf5: - printf("[ "); - break; - case 0xf6: - printf("] "); - break; - case 0xf7: - printf("# "); - break; - case 0xf8: - printf("< "); - break; - case 0xf9: - printf("> "); - break; - } - } else { - nextitem = nextitem << 8 | script->data [seeker++]; - printf("%s[%03x] ", vocab->getAnyWordFromGroup(nextitem), nextitem); - } - } - printf("\n"); - } - break; + if (READ_LE_UINT16(script->data + 6) > 0) + scr->setExportTableOffset(6); - case SCI_OBJ_STRINGS: { - printf("Strings\n"); - while (script->data [seeker]) { - printf("%04x: %s\n", seeker, script->data + seeker); - seeker += strlen((char *)script->data + seeker) + 1; - } - seeker++; // the ending zero byte - }; - break; + reg.segment = seg_id; + reg.offset = _heapStart + 4; + segMan->scriptInitialiseLocals(reg); + + segMan->scriptRelocateExportsSci11(seg_id); + segMan->scriptInitialiseObjectsSci11(seg_id); + + reg.offset = READ_LE_UINT16(heap->data); + scr->heapRelocate(reg); - case SCI_OBJ_CLASS: - dumpScriptClass((char *)script->data, seeker, objsize); + return seg_id; +} + +int script_instantiate(ResourceManager *resMan, SegManager *segMan, int script_nr) { + if (getSciVersion() >= SCI_VERSION_1_1) + return script_instantiate_sci11(resMan, segMan, script_nr); + else + return script_instantiate_sci0(resMan, segMan, script_nr); +} + +void script_uninstantiate_sci0(SegManager *segMan, int script_nr, SegmentId seg) { + bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY); + reg_t reg = make_reg(seg, oldScriptHeader ? 2 : 0); + int objtype, objlength; + Script *scr = segMan->getScript(seg); + + // Make a pass over the object in order uninstantiate all superclasses + objlength = 0; + + do { + reg.offset += objlength; // Step over the last checked object + + objtype = scr->getHeap(reg.offset); + if (!objtype) break; + objlength = scr->getHeap(reg.offset + 2); // use SEG_UGET_HEAP ?? - case SCI_OBJ_EXPORTS: { - printf("Exports\n"); - Common::hexdump((unsigned char *)script->data + seeker, objsize - 4, 16, seeker); - }; - break; + reg.offset += 4; // Step over header - case SCI_OBJ_POINTERS: { - printf("Pointers\n"); - Common::hexdump(script->data + seeker, objsize - 4, 16, seeker); - }; - break; + if ((objtype == SCI_OBJ_OBJECT) || (objtype == SCI_OBJ_CLASS)) { // object or class? + int superclass; - case 9: { - printf("<unknown>\n"); - Common::hexdump(script->data + seeker, objsize - 4, 16, seeker); - }; - break; + reg.offset -= SCRIPT_OBJECT_MAGIC_OFFSET; - case SCI_OBJ_LOCALVARS: { - printf("Local vars\n"); - Common::hexdump(script->data + seeker, objsize - 4, 16, seeker); - }; - break; + superclass = scr->getHeap(reg.offset + SCRIPT_SUPERCLASS_OFFSET); // Get superclass... - default: - printf("Unsupported!\n"); - return; - } + if (superclass >= 0) { + int superclass_script = segMan->_classtable[superclass].script; + + if (superclass_script == script_nr) { + if (scr->getLockers()) + scr->decrementLockers(); // Decrease lockers if this is us ourselves + } else + script_uninstantiate(segMan, superclass_script); + // Recurse to assure that the superclass lockers number gets decreased + } + + reg.offset += SCRIPT_OBJECT_MAGIC_OFFSET; + } // if object or class + + reg.offset -= 4; // Step back on header + + } while (objtype != 0); +} +void script_uninstantiate(SegManager *segMan, int script_nr) { + SegmentId segment = segMan->getScriptSegment(script_nr); + Script *scr = segMan->getScriptIfLoaded(segment); + + if (!scr) { // Is it already loaded? + //warning("unloading script 0x%x requested although not loaded", script_nr); + // This is perfectly valid SCI behaviour + return; } - printf("Script ends without terminator\n"); + scr->decrementLockers(); // One less locker + + if (scr->getLockers() > 0) + return; + + // Free all classtable references to this script + for (uint i = 0; i < segMan->_classtable.size(); i++) + if (segMan->_classtable[i].reg.segment == segment) + segMan->_classtable[i].reg = NULL_REG; + + if (getSciVersion() < SCI_VERSION_1_1) + script_uninstantiate_sci0(segMan, script_nr, segment); + // FIXME: Add proper script uninstantiation for SCI 1.1 + + if (scr->getLockers()) + return; // if xxx.lockers > 0 + + // Otherwise unload it completely + // Explanation: I'm starting to believe that this work is done by SCI itself. + scr->markDeleted(); + + debugC(kDebugLevelScripts, "Unloaded script 0x%x.", script_nr); + + return; } + } // End of namespace Sci |
