SCI: Add SegManager::findObjectByName() method, make parse_reg_t() local to console.cpp, and switch other code using it to use findObjectByName() instead.

svn-id: r44628
This commit is contained in:
Max Horn 2009-10-04 18:36:58 +00:00
parent 07353be65a
commit 0da9ad5ff5
6 changed files with 110 additions and 83 deletions

View file

@ -50,6 +50,9 @@ int g_debug_sleeptime_factor = 1;
int g_debug_simulated_key = 0;
bool g_debug_track_mouse_clicks = false;
// Refer to the "addresses" command on how to pass address parameters
static int parse_reg_t(EngineState *s, const char *str, reg_t *dest);
Console::Console(SciEngine *vm) : GUI::Debugger() {
_vm = vm;
@ -2720,7 +2723,7 @@ bool Console::cmdAddresses(int argc, const char **argv) {
}
// Returns 0 on success
int parse_reg_t(EngineState *s, const char *str, reg_t *dest) {
static int parse_reg_t(EngineState *s, const char *str, reg_t *dest) {
// Pointer to the part of str which contains a numeric offset (if any)
const char *offsetStr = NULL;
@ -2787,6 +2790,9 @@ int parse_reg_t(EngineState *s, const char *str, reg_t *dest) {
// The (optional) index can be used to distinguish multiple object with the same name.
int index = -1;
// Skip over the leading question mark '?'
str++;
// Look for an offset. It starts with + or -
relativeOffset = true;
offsetStr = strchr(str, '+');
@ -2795,10 +2801,10 @@ int parse_reg_t(EngineState *s, const char *str, reg_t *dest) {
// Strip away the offset and the leading '?'
Common::String str_objname;
if (offsetStr) {
str_objname = Common::String(str + 1, offsetStr);
} else
str_objname = str + 1;
if (offsetStr)
str_objname = Common::String(str, offsetStr);
else
str_objname = str;
// Scan for a period, after which (if present) we'll find an index
@ -2812,74 +2818,11 @@ int parse_reg_t(EngineState *s, const char *str, reg_t *dest) {
}
// Now all values are available; iterate over all objects.
int times_found = 0;
for (uint i = 0; i < s->segMan->_heap.size(); i++) {
SegmentObj *mobj = s->segMan->_heap[i];
int idx = 0;
int max_index = 0;
ObjMap::iterator it;
Script *scr = 0;
CloneTable *ct = 0;
if (mobj) {
if (mobj->getType() == SEG_TYPE_SCRIPT) {
scr = (Script *)mobj;
max_index = scr->_objects.size();
it = scr->_objects.begin();
} else if (mobj->getType() == SEG_TYPE_CLONES) {
ct = (CloneTable *)mobj;
max_index = ct->_table.size();
}
}
// It's a script or a clone table, scan all objects in it
for (; idx < max_index; ++idx) {
Object *obj = NULL;
reg_t objpos;
objpos.offset = 0;
objpos.segment = i;
if (mobj->getType() == SEG_TYPE_SCRIPT) {
obj = &(it->_value);
objpos.offset = obj->_pos.offset;
++it;
} else if (mobj->getType() == SEG_TYPE_CLONES) {
if (!ct->isValidEntry(idx))
continue;
obj = &(ct->_table[idx]);
objpos.offset = idx;
}
const char *objname = s->segMan->getObjectName(objpos);
if (str_objname == objname) {
// Found a match!
if ((index < 0) && (times_found > 0)) {
if (times_found == 1) {
// First time we realized the ambiguity
printf("Ambiguous:\n");
printf(" %3x: [%04x:%04x] %s\n", 0, PRINT_REG(*dest), str_objname.c_str());
}
printf(" %3x: [%04x:%04x] %s\n", times_found, PRINT_REG(objpos), str_objname.c_str());
}
if (index < 0 || times_found == index)
*dest = objpos;
++times_found;
}
}
}
if (!times_found)
*dest = s->segMan->findObjectByName(str_objname, index);
if (dest->isNull())
return 1;
if (times_found > 1 && index < 0) {
printf("Ambiguous: Aborting.\n");
return 1; // Ambiguous
}
if (times_found <= index)
return 1; // Not found
} else { // Finally, check for "SEGMENT:OFFSET" or just "OFFSET"
const char *colon = strchr(str, ':');

View file

@ -36,8 +36,6 @@ namespace Sci {
class SciEngine;
struct List;
// Refer to the "addresses" command on how to pass address parameters
int parse_reg_t(EngineState *s, const char *str, reg_t *dest);
reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecode);
class Console : public GUI::Debugger {

View file

@ -24,7 +24,6 @@
*/
#include "sci/sci.h"
#include "sci/console.h" // for parse_reg_t
#include "sci/resource.h"
#include "sci/engine/state.h"
#include "sci/engine/kernel.h"
@ -256,10 +255,10 @@ static int checksum_bytes(byte *data, int size) {
}
static void bresenham_autodetect(EngineState *s) {
reg_t motion_class;
reg_t motionClass = s->segMan->findObjectByName("Motion");
if (!parse_reg_t(s, "?Motion", &motion_class)) {
Object *obj = s->segMan->getObject(motion_class);
if (!motionClass.isNull()) {
Object *obj = s->segMan->getObject(motionClass);
reg_t fptr;
byte *buf;
@ -269,7 +268,7 @@ static void bresenham_autodetect(EngineState *s) {
return;
}
if (lookup_selector(s->segMan, motion_class, s->_kernel->_selectorCache.doit, NULL, &fptr) != kSelectorMethod) {
if (lookup_selector(s->segMan, motionClass, s->_kernel->_selectorCache.doit, NULL, &fptr) != kSelectorMethod) {
warning("bresenham_autodetect failed");
handle_movecnt = INCREMENT_MOVECNT; // Most games do this, so best guess
return;

View file

@ -272,6 +272,81 @@ const char *SegManager::getObjectName(reg_t pos) {
return name;
}
reg_t SegManager::findObjectByName(const Common::String &name, int index) {
reg_t retVal = NULL_REG;
// Now all values are available; iterate over all objects.
int timesFound = 0;
for (uint i = 0; i < _heap.size(); i++) {
SegmentObj *mobj = _heap[i];
int idx = 0;
int max_index = 0;
ObjMap::iterator it;
Script *scr = 0;
CloneTable *ct = 0;
if (mobj) {
if (mobj->getType() == SEG_TYPE_SCRIPT) {
scr = (Script *)mobj;
max_index = scr->_objects.size();
it = scr->_objects.begin();
} else if (mobj->getType() == SEG_TYPE_CLONES) {
ct = (CloneTable *)mobj;
max_index = ct->_table.size();
}
}
// It's a script or a clone table, scan all objects in it
for (; idx < max_index; ++idx) {
Object *obj = NULL;
reg_t objpos;
objpos.offset = 0;
objpos.segment = i;
if (mobj->getType() == SEG_TYPE_SCRIPT) {
obj = &(it->_value);
objpos.offset = obj->_pos.offset;
++it;
} else if (mobj->getType() == SEG_TYPE_CLONES) {
if (!ct->isValidEntry(idx))
continue;
obj = &(ct->_table[idx]);
objpos.offset = idx;
}
const char *objname = getObjectName(objpos);
if (name == objname) {
// Found a match!
if ((index < 0) && (timesFound > 0)) {
if (timesFound == 1) {
// First time we realized the ambiguity
printf("Ambiguous:\n");
printf(" %3x: [%04x:%04x] %s\n", 0, PRINT_REG(retVal), name.c_str());
}
printf(" %3x: [%04x:%04x] %s\n", timesFound, PRINT_REG(objpos), name.c_str());
}
if (index < 0 || timesFound == index)
retVal = objpos;
++timesFound;
}
}
}
if (!timesFound)
return NULL_REG;
if (timesFound > 1 && index < 0) {
printf("Ambiguous: Aborting.\n");
return NULL_REG; // Ambiguous
}
if (timesFound <= index)
return NULL_REG; // Not found
return retVal;
}
// validate the seg
// return:
// false - invalid seg
@ -623,7 +698,7 @@ void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) {
#if 0
if (obj->_variables[5].offset != 0xffff) {
obj->_variables[5] = INST_LOOKUP_CLASS(obj->_variables[5].offset);
base_obj = s->segMan->getObject(obj->_variables[5]);
base_obj = getObject(obj->_variables[5]);
obj->variable_names_nr = base_obj->variables_nr;
obj->base_obj = base_obj->base_obj;
}

View file

@ -419,6 +419,19 @@ public:
*/
const char *getObjectName(reg_t pos);
/**
* Find the address of an object by its name. In case multiple objects
* with the same name occur, the optional index parameter can be used
* to distinguish between them. If index is -1, then if there is a
* unique object with the specified name, its address is returned;
* if there are multiple matches, or none, then NULL_REG is returned.
*
* @param name the name of the object we are looking for
* @param index the index of the object in case there are multiple
* @return the address of the object, or NULL_REG
*/
reg_t findObjectByName(const Common::String &name, int index = -1);
void scriptRelocateExportsSci11(SegmentId seg);
void scriptInitialiseObjectsSci11(SegmentId seg);

View file

@ -26,7 +26,6 @@
#include "sci/engine/state.h"
#include "sci/engine/vm.h"
#include "sci/engine/script.h"
#include "sci/console.h" // For parse_reg_t
namespace Sci {
@ -266,9 +265,9 @@ int EngineState::methodChecksum(reg_t objAddress, Selector sel, int offset, uint
SciVersion EngineState::detectDoSoundType() {
if (_doSoundType == SCI_VERSION_AUTODETECT) {
reg_t soundClass;
reg_t soundClass = segMan->findObjectByName("Sound");
if (!parse_reg_t(this, "?Sound", &soundClass)) {
if (!soundClass.isNull()) {
int sum = methodChecksum(soundClass, _kernel->_selectorCache.play, -6, 6);
switch (sum) {
@ -337,10 +336,10 @@ SciVersion EngineState::detectLofsType() {
return _lofsType;
}
reg_t gameClass;
Object *obj = NULL;
reg_t gameClass = segMan->findObjectByName("Game");
if (!parse_reg_t(this, "?Game", &gameClass))
if (!gameClass.isNull())
obj = segMan->getObject(gameClass);
bool couldBeAbs = true;