SCI: Move some code around (no code changes)

svn-id: r47823
This commit is contained in:
Max Horn 2010-02-02 22:50:32 +00:00
parent 5d80990380
commit 6c322506dd
4 changed files with 687 additions and 684 deletions

View file

@ -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_)
#define FIND_SELECTOR2(_slc_, _slcstr_) _selectorCache._slc_ = findSelector(_slcstr_); \
printf("\t{ \"%s\", %d },\n", _slcstr_, _selectorCache._slc_)
#endif
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);
#ifdef ENABLE_SCI32
FIND_SELECTOR(data);
FIND_SELECTOR(picture);
FIND_SELECTOR(plane);
FIND_SELECTOR(top);
FIND_SELECTOR(left);
#endif
}
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;
printf("Object\n");
Common::hexdump((unsigned char *) data + seeker, objsize - 4, 16, seeker);
//-4 because the size includes the two-word header
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);
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)));
seeker += 8;
while (selectors--) {
printf(" [#%03x] = 0x%x\n", i++, (int16)READ_LE_UINT16((unsigned char *)data + seeker) & 0xffff);
seeker += 2;
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;
}
printf("Overridden functions: %x\n", selectors = overloads = (int16)READ_LE_UINT16((unsigned char *)data + seeker));
seeker += 2;
if (overloads < 100)
while (overloads--) {
int selector = (int16)READ_LE_UINT16((unsigned char *) data + (seeker));
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);
seeker += 2;
}
}
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);
printf("Class\n");
Common::hexdump((unsigned char *) data + seeker, objsize - 4, 16, seeker);
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);
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)));
seeker += 8;
selectorsize <<= 1;
while (selectors--) {
int selector = (int16)READ_LE_UINT16((unsigned char *) data + (seeker) + selectorsize);
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);
seeker += 2;
}
seeker += selectorsize;
printf("Overloaded functions: %x\n", selectors = overloads = (int16)READ_LE_UINT16((unsigned char *)data + seeker));
seeker += 2;
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);
seeker += 2;
}
}
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 (!script) {
warning("dissectScript(): Script not found!\n");
return;
}
while (_seeker < script->size) {
int objtype = (int16)READ_LE_UINT16(script->data + _seeker);
int objsize;
unsigned int seeker = _seeker + 4;
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;
}
printf("\n");
objsize = (int16)READ_LE_UINT16(script->data + _seeker + 2);
printf("Obj type #%x, size 0x%x: ", objtype, objsize);
_seeker += objsize;
objectctr[objtype]++;
switch (objtype) {
case SCI_OBJ_OBJECT:
dumpScriptObject((char *)script->data, seeker, objsize);
break;
case SCI_OBJ_CODE: {
printf("Code\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
};
break;
case 3: {
printf("<unknown>\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
};
break;
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;
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 {
nextitem = nextitem << 8 | script->data [seeker++];
printf("%s[%03x] ", vocab->getAnyWordFromGroup(nextitem), nextitem);
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;
}
}
printf("\n");
scr->init(script_nr, resMan);
reg_t reg;
reg.segment = seg_id;
reg.offset = 0;
// 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;
}
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;
Script *scr = segMan->getScript(seg_id);
if (oldScriptHeader) {
//
int locals_nr = READ_LE_UINT16(script->data);
// 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.
scr->mcpyInOut(0, script->data, script->size);
magic_pos_adder = 2; // Step over the funny prefix
if (locals_nr)
segMan->scriptInitialiseLocalsZero(seg_id, locals_nr);
} else {
scr->mcpyInOut(0, script->data, script->size);
magic_pos_adder = 0;
}
// Now do a first pass through the script objects to find the
// export table and local variable block
reg_t reg;
reg.segment = seg_id;
reg.offset = magic_pos_adder;
objlength = 0;
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;
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;
objlength = scr->getHeap(reg.offset + 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;
}
seeker++; // the ending zero byte
};
break;
case SCI_OBJ_CLASS:
dumpScriptClass((char *)script->data, seeker, objsize);
break;
data_base = reg;
data_base.offset += 4;
addr = data_base;
switch (objtype) {
case SCI_OBJ_EXPORTS: {
printf("Exports\n");
Common::hexdump((unsigned char *)script->data + seeker, objsize - 4, 16, seeker);
};
scr->setExportTableOffset(data_base.offset);
}
break;
case SCI_OBJ_POINTERS: {
printf("Pointers\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
};
case SCI_OBJ_SYNONYMS:
scr->setSynonymsOffset(addr.offset); // +4 is to step over the header
scr->setSynonymsNr((objlength) / 4);
break;
case 9: {
printf("<unknown>\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
};
case SCI_OBJ_LOCALVARS:
segMan->scriptInitialiseLocals(data_base);
break;
case SCI_OBJ_LOCALVARS: {
printf("Local vars\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
};
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;
}
}
segMan->_classtable[species].reg = addr;
segMan->_classtable[species].reg.offset = classpos;
// Set technical class position-- into the block allocated for it
}
break;
default:
printf("Unsupported!\n");
break;
}
} while (objtype != 0);
// And now a second pass to adjust objects and class pointers, and the general pointers
objlength = 0;
reg.offset = magic_pos_adder; // Reset counter
do {
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);
addr = reg;
addr.offset += 4; // Step over header
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);
// Instantiate the superclass, if neccessary
obj->setSpeciesSelector(INST_LOOKUP_CLASS(obj->getSpeciesSelector().offset));
Object *baseObj = segMan->getObject(obj->getSpeciesSelector());
if (baseObj) {
obj->setVarCount(baseObj->getVarCount());
// Copy base from species class, as we need its selector IDs
obj->_baseObj = baseObj->_baseObj;
obj->setSuperClassSelector(INST_LOOKUP_CLASS(obj->getSuperClassSelector().offset));
} else {
warning("Failed to locate base object for object at %04X:%04X; skipping", PRINT_REG(addr));
scr->scriptObjRemove(addr);
}
} // if object or class
break;
case SCI_OBJ_POINTERS: // A relocation table
relocation = addr.offset;
break;
default:
break;
}
} while (objtype != 0 && reg.offset < script->size - 2);
if (relocation >= 0)
scr->scriptRelocate(make_reg(seg_id, relocation));
return reg.segment; // instantiation successful
}
int script_instantiate_sci11(ResourceManager *resMan, SegManager *segMan, int script_nr) {
Resource *script, *heap;
int _heapStart;
reg_t reg;
int was_new;
const int seg_id = script_instantiate_common(resMan, segMan, script_nr, &script, &heap, &was_new);
if (was_new)
return seg_id;
Script *scr = segMan->getScript(seg_id);
_heapStart = script->size;
if (script->size & 2)
_heapStart ++;
scr->mcpyInOut(0, script->data, script->size);
scr->mcpyInOut(_heapStart, heap->data, heap->size);
if (READ_LE_UINT16(script->data + 6) > 0)
scr->setExportTableOffset(6);
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);
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 ??
reg.offset += 4; // Step over header
if ((objtype == SCI_OBJ_OBJECT) || (objtype == SCI_OBJ_CLASS)) { // object or class?
int superclass;
reg.offset -= SCRIPT_OBJECT_MAGIC_OFFSET;
superclass = scr->getHeap(reg.offset + SCRIPT_SUPERCLASS_OFFSET); // Get superclass...
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;
}
}
scr->decrementLockers(); // One less locker
printf("Script ends without terminator\n");
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

View file

@ -428,4 +428,241 @@ void script_debug(EngineState *s, bool bp) {
con->attach();
}
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;
printf("Object\n");
Common::hexdump((unsigned char *) data + seeker, objsize - 4, 16, seeker);
//-4 because the size includes the two-word header
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);
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)));
seeker += 8;
while (selectors--) {
printf(" [#%03x] = 0x%x\n", i++, (int16)READ_LE_UINT16((unsigned char *)data + seeker) & 0xffff);
seeker += 2;
}
printf("Overridden functions: %x\n", selectors = overloads = (int16)READ_LE_UINT16((unsigned char *)data + seeker));
seeker += 2;
if (overloads < 100)
while (overloads--) {
int selector = (int16)READ_LE_UINT16((unsigned char *) data + (seeker));
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);
seeker += 2;
}
}
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);
printf("Class\n");
Common::hexdump((unsigned char *) data + seeker, objsize - 4, 16, seeker);
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);
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)));
seeker += 8;
selectorsize <<= 1;
while (selectors--) {
int selector = (int16)READ_LE_UINT16((unsigned char *) data + (seeker) + selectorsize);
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);
seeker += 2;
}
seeker += selectorsize;
printf("Overloaded functions: %x\n", selectors = overloads = (int16)READ_LE_UINT16((unsigned char *)data + seeker));
seeker += 2;
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);
seeker += 2;
}
}
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 (!script) {
warning("dissectScript(): Script not found!\n");
return;
}
while (_seeker < script->size) {
int objtype = (int16)READ_LE_UINT16(script->data + _seeker);
int objsize;
unsigned int seeker = _seeker + 4;
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;
}
printf("\n");
objsize = (int16)READ_LE_UINT16(script->data + _seeker + 2);
printf("Obj type #%x, size 0x%x: ", objtype, objsize);
_seeker += objsize;
objectctr[objtype]++;
switch (objtype) {
case SCI_OBJ_OBJECT:
dumpScriptObject((char *)script->data, seeker, objsize);
break;
case SCI_OBJ_CODE: {
printf("Code\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
};
break;
case 3: {
printf("<unknown>\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
};
break;
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;
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;
case SCI_OBJ_CLASS:
dumpScriptClass((char *)script->data, seeker, objsize);
break;
case SCI_OBJ_EXPORTS: {
printf("Exports\n");
Common::hexdump((unsigned char *)script->data + seeker, objsize - 4, 16, seeker);
};
break;
case SCI_OBJ_POINTERS: {
printf("Pointers\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
};
break;
case 9: {
printf("<unknown>\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
};
break;
case SCI_OBJ_LOCALVARS: {
printf("Local vars\n");
Common::hexdump(script->data + seeker, objsize - 4, 16, seeker);
};
break;
default:
printf("Unsupported!\n");
return;
}
}
printf("Script ends without terminator\n");
}
} // End of namespace Sci

View file

@ -29,6 +29,145 @@
namespace Sci {
#if 1
#define FIND_SELECTOR(_slc_) _selectorCache._slc_ = findSelector(#_slc_)
#define FIND_SELECTOR2(_slc_, _slcstr_) _selectorCache._slc_ = findSelector(_slcstr_)
#else
// 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_)
#define FIND_SELECTOR2(_slc_, _slcstr_) _selectorCache._slc_ = findSelector(_slcstr_); \
printf("\t{ \"%s\", %d },\n", _slcstr_, _selectorCache._slc_)
#endif
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);
#ifdef ENABLE_SCI32
FIND_SELECTOR(data);
FIND_SELECTOR(picture);
FIND_SELECTOR(plane);
FIND_SELECTOR(top);
FIND_SELECTOR(left);
#endif
}
reg_t read_selector(SegManager *segMan, reg_t object, Selector selector_id) {
ObjVarRef address;

View file

@ -1603,355 +1603,6 @@ void run_vm(EngineState *s, int restoring) {
}
}
#define INST_LOOKUP_CLASS(id) ((id == 0xffff)? NULL_REG : segMan->getClassAddress(id, SCRIPT_GET_LOCK, reg))
int script_instantiate_common(ResourceManager *resMan, SegManager *segMan, int script_nr, Resource **script, Resource **heap, int *was_new) {
*was_new = 1;
*script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
if (getSciVersion() >= SCI_VERSION_1_1)
*heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
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;
}
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;
}
}
scr->init(script_nr, resMan);
reg_t reg;
reg.segment = seg_id;
reg.offset = 0;
// 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;
}
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;
Script *scr = segMan->getScript(seg_id);
if (oldScriptHeader) {
//
int locals_nr = READ_LE_UINT16(script->data);
// 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.
scr->mcpyInOut(0, script->data, script->size);
magic_pos_adder = 2; // Step over the funny prefix
if (locals_nr)
segMan->scriptInitialiseLocalsZero(seg_id, locals_nr);
} else {
scr->mcpyInOut(0, script->data, script->size);
magic_pos_adder = 0;
}
// Now do a first pass through the script objects to find the
// export table and local variable block
reg_t reg;
reg.segment = seg_id;
reg.offset = magic_pos_adder;
objlength = 0;
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);
// 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;
}
data_base = reg;
data_base.offset += 4;
addr = data_base;
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;
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;
}
}
segMan->_classtable[species].reg = addr;
segMan->_classtable[species].reg.offset = classpos;
// Set technical class position-- into the block allocated for it
}
break;
default:
break;
}
} while (objtype != 0);
// And now a second pass to adjust objects and class pointers, and the general pointers
objlength = 0;
reg.offset = magic_pos_adder; // Reset counter
do {
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);
addr = reg;
addr.offset += 4; // Step over header
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);
// Instantiate the superclass, if neccessary
obj->setSpeciesSelector(INST_LOOKUP_CLASS(obj->getSpeciesSelector().offset));
Object *baseObj = segMan->getObject(obj->getSpeciesSelector());
if (baseObj) {
obj->setVarCount(baseObj->getVarCount());
// Copy base from species class, as we need its selector IDs
obj->_baseObj = baseObj->_baseObj;
obj->setSuperClassSelector(INST_LOOKUP_CLASS(obj->getSuperClassSelector().offset));
} else {
warning("Failed to locate base object for object at %04X:%04X; skipping", PRINT_REG(addr));
scr->scriptObjRemove(addr);
}
} // if object or class
break;
case SCI_OBJ_POINTERS: // A relocation table
relocation = addr.offset;
break;
default:
break;
}
} while (objtype != 0 && reg.offset < script->size - 2);
if (relocation >= 0)
scr->scriptRelocate(make_reg(seg_id, relocation));
return reg.segment; // instantiation successful
}
int script_instantiate_sci11(ResourceManager *resMan, SegManager *segMan, int script_nr) {
Resource *script, *heap;
int _heapStart;
reg_t reg;
int was_new;
const int seg_id = script_instantiate_common(resMan, segMan, script_nr, &script, &heap, &was_new);
if (was_new)
return seg_id;
Script *scr = segMan->getScript(seg_id);
_heapStart = script->size;
if (script->size & 2)
_heapStart ++;
scr->mcpyInOut(0, script->data, script->size);
scr->mcpyInOut(_heapStart, heap->data, heap->size);
if (READ_LE_UINT16(script->data + 6) > 0)
scr->setExportTableOffset(6);
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);
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 ??
reg.offset += 4; // Step over header
if ((objtype == SCI_OBJ_OBJECT) || (objtype == SCI_OBJ_CLASS)) { // object or class?
int superclass;
reg.offset -= SCRIPT_OBJECT_MAGIC_OFFSET;
superclass = scr->getHeap(reg.offset + SCRIPT_SUPERCLASS_OFFSET); // Get superclass...
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;
}
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;
}
static void _init_stack_base_with_selector(EngineState *s, Selector selector) {
s->stack_base[0] = make_reg(0, (uint16)selector);
s->stack_base[1] = NULL_REG;