SCI: Move some code around (no code changes)
svn-id: r47823
This commit is contained in:
parent
5d80990380
commit
6c322506dd
4 changed files with 687 additions and 684 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue