aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine
diff options
context:
space:
mode:
authorMartin Kiewitz2010-07-07 18:35:07 +0000
committerMartin Kiewitz2010-07-07 18:35:07 +0000
commit322d57a1dd2f72bb9d5fb4e00ddf82acab637e36 (patch)
tree62252e3558b642f7981a98bd53b442ac2ca08b84 /engines/sci/engine
parent61a200dcdd03e8b0c1f35dea50842b6356e13e17 (diff)
downloadscummvm-rg350-322d57a1dd2f72bb9d5fb4e00ddf82acab637e36.tar.gz
scummvm-rg350-322d57a1dd2f72bb9d5fb4e00ddf82acab637e36.tar.bz2
scummvm-rg350-322d57a1dd2f72bb9d5fb4e00ddf82acab637e36.zip
SCI: adding support to kernel signatures that invalid references may also get allowed - doing exactly this for kGraph(restoreBox) - fixes castle of dr. brain when quitting the game - maybe a game specific workaround would be better?!?!
svn-id: r50737
Diffstat (limited to 'engines/sci/engine')
-rw-r--r--engines/sci/engine/kernel.cpp69
-rw-r--r--engines/sci/engine/kernel.h19
2 files changed, 57 insertions, 31 deletions
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index 2a378564bb..236a310f38 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -364,7 +364,9 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(FlushResources), SIG_EVERYWHERE, "i", NULL, NULL },
{ MAP_CALL(TimesSin), SIG_EVERYWHERE, "ii", NULL, NULL },
{ MAP_CALL(TimesCos), SIG_EVERYWHERE, "ii", NULL, NULL },
- { MAP_CALL(Graph), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop
+ { MAP_CALL(Graph), SIG_EVERYWHERE, "i([!.]*)", NULL, NULL }, // subop
+ // ^^ we allow invalid references here, because kGraph(restoreBox) gets called with old non-existant handles often
+ // this should get limited to this call only as soon as subop signatures are available
{ MAP_CALL(Joystick), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop
{ MAP_CALL(FileIO), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop
{ MAP_CALL(Memory), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop
@@ -543,7 +545,8 @@ static uint16 *parseKernelSignature(const char *kernelName, const char *writtenS
// we also check, if the written signature makes any sense
curPos = writtenSig;
while (*curPos) {
- switch (*curPos) {
+ curChar = *curPos;
+ switch (curChar) {
case '[': // either or
if (eitherOr)
error("signature for k%s: '[' used within '[]'", kernelName);
@@ -584,6 +587,7 @@ static uint16 *parseKernelSignature(const char *kernelName, const char *writtenS
case 'l':
case 'n':
case '.':
+ case '!':
if ((hadOptional) & (!optional))
error("signature for k%s: non-optional type may not follow optional type", kernelName);
validType = true;
@@ -634,8 +638,13 @@ static uint16 *parseKernelSignature(const char *kernelName, const char *writtenS
case 'l':
case 'n':
case '.':
+ case '!':
// and we also got some signature pending?
if (signature) {
+ if (!(signature & SIG_MAYBE_ANY))
+ error("signature for k%s: invalid ('!') may only get used in combination with a real type", kernelName);
+ if ((signature & SIG_IS_INVALID) && ((signature & SIG_MAYBE_ANY) == (SIG_TYPE_NULL | SIG_TYPE_INTEGER)))
+ error("signature for k%s: invalid ('!') should not be used on exclusive null/integer type", kernelName);
if (optional) {
signature |= SIG_IS_OPTIONAL;
if (curChar != ')')
@@ -662,37 +671,44 @@ static uint16 *parseKernelSignature(const char *kernelName, const char *writtenS
break;
case '0':
if (signature & SIG_TYPE_NULL)
- error("signature for k%s: NULL specified more than once", kernelName);
+ error("signature for k%s: NULL ('0') specified more than once", kernelName);
signature |= SIG_TYPE_NULL;
break;
case 'i':
if (signature & SIG_TYPE_INTEGER)
- error("signature for k%s: integer specified more than once", kernelName);
+ error("signature for k%s: integer ('i') specified more than once", kernelName);
signature |= SIG_TYPE_INTEGER | SIG_TYPE_NULL;
break;
case 'o':
if (signature & SIG_TYPE_OBJECT)
- error("signature for k%s: object specified more than once", kernelName);
+ error("signature for k%s: object ('o') specified more than once", kernelName);
signature |= SIG_TYPE_OBJECT;
break;
case 'r':
if (signature & SIG_TYPE_REFERENCE)
- error("signature for k%s: reference specified more than once", kernelName);
+ error("signature for k%s: reference ('r') specified more than once", kernelName);
signature |= SIG_TYPE_REFERENCE;
break;
case 'l':
if (signature & SIG_TYPE_LIST)
- error("signature for k%s: list specified more than once", kernelName);
+ error("signature for k%s: list ('l') specified more than once", kernelName);
signature |= SIG_TYPE_LIST;
break;
case 'n':
if (signature & SIG_TYPE_NODE)
- error("signature for k%s: node specified more than once", kernelName);
+ error("signature for k%s: node ('n') specified more than once", kernelName);
signature |= SIG_TYPE_NODE;
break;
case '.':
+ if (signature & SIG_MAYBE_ANY)
+ error("signature for k%s: maybe-any ('.') shouldn't get specified with other types in front of it", kernelName);
signature |= SIG_MAYBE_ANY;
break;
+ case '!':
+ if (signature & SIG_IS_INVALID)
+ error("signature for k%s: invalid ('!') specified more than once", kernelName);
+ signature |= SIG_IS_INVALID;
+ break;
case '*': // accepts more of the same parameter
signature |= SIG_MORE_MAY_FOLLOW;
break;
@@ -708,7 +724,7 @@ static uint16 *parseKernelSignature(const char *kernelName, const char *writtenS
return result;
}
-int Kernel::findRegType(reg_t reg) {
+uint16 Kernel::findRegType(reg_t reg) {
// No segment? Must be integer
if (!reg.segment)
return SIG_TYPE_INTEGER | (reg.offset ? 0 : SIG_TYPE_NULL);
@@ -719,21 +735,24 @@ int Kernel::findRegType(reg_t reg) {
// Otherwise it's an object
SegmentObj *mobj = _segMan->getSegmentObj(reg.segment);
if (!mobj)
- return SIG_TYPE_INVALID;
+ return SIG_TYPE_ERROR;
+ uint16 result = 0;
if (!mobj->isValidOffset(reg.offset))
- return SIG_TYPE_INVALID;
+ result |= SIG_IS_INVALID;
switch (mobj->getType()) {
case SEG_TYPE_SCRIPT:
if (reg.offset <= (*(Script *)mobj).getBufSize() &&
reg.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET &&
RAW_IS_OBJECT((*(Script *)mobj).getBuf(reg.offset)) ) {
- return ((Script *)mobj)->getObject(reg.offset) ? SIG_TYPE_OBJECT : SIG_TYPE_REFERENCE;
+ result |= ((Script *)mobj)->getObject(reg.offset) ? SIG_TYPE_OBJECT : SIG_TYPE_REFERENCE;
} else
- return SIG_TYPE_REFERENCE;
+ result |= SIG_TYPE_REFERENCE;
+ break;
case SEG_TYPE_CLONES:
- return SIG_TYPE_OBJECT;
+ result |= SIG_TYPE_OBJECT;
+ break;
case SEG_TYPE_LOCALS:
case SEG_TYPE_STACK:
case SEG_TYPE_SYS_STRINGS:
@@ -743,14 +762,18 @@ int Kernel::findRegType(reg_t reg) {
case SEG_TYPE_ARRAY:
case SEG_TYPE_STRING:
#endif
- return SIG_TYPE_REFERENCE;
+ result |= SIG_TYPE_REFERENCE;
+ break;
case SEG_TYPE_LISTS:
- return SIG_TYPE_LIST;
+ result |= SIG_TYPE_LIST;
+ break;
case SEG_TYPE_NODES:
- return SIG_TYPE_NODE;
+ result |= SIG_TYPE_NODE;
+ break;
default:
- return 0;
+ return SIG_TYPE_ERROR;
}
+ return result;
}
struct SignatureDebugType {
@@ -762,11 +785,12 @@ static const SignatureDebugType signatureDebugTypeList[] = {
{ SIG_TYPE_NULL, "null" },
{ SIG_TYPE_INTEGER, "integer" },
{ SIG_TYPE_UNINITIALIZED, "uninitialized" },
- { SIG_TYPE_INVALID, "invalid" },
{ SIG_TYPE_OBJECT, "object" },
{ SIG_TYPE_REFERENCE, "reference" },
{ SIG_TYPE_LIST, "list" },
{ SIG_TYPE_NODE, "node" },
+ { SIG_TYPE_ERROR, "error" },
+ { SIG_IS_INVALID, "invalid" },
{ 0, NULL }
};
@@ -830,10 +854,11 @@ bool Kernel::signatureMatch(const uint16 *sig, int argc, const reg_t *argv) {
while (nextSig && argc) {
curSig = nextSig;
int type = findRegType(*argv);
- if (!type)
- return false; // couldn't determine type
- if (!(type & curSig))
+ if ((type & SIG_IS_INVALID) && (!(curSig & SIG_IS_INVALID)))
+ return false; // pointer is invalid and signature doesn't allow that?
+
+ if (!((type & ~SIG_IS_INVALID) & curSig))
return false; // type mismatch
if (!(curSig & SIG_MORE_MAY_FOLLOW)) {
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 719db41e8d..7aa565fe34 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -101,14 +101,15 @@ enum {
SIG_TYPE_NULL = 0x01, // may be 0:0 [0]
SIG_TYPE_INTEGER = 0x02, // may be 0:* [i], automatically also allows null
SIG_TYPE_UNINITIALIZED = 0x04, // may be FFFF:* -> not allowable, only used for comparsion
- SIG_TYPE_INVALID = 0x08, // invalid segment or offset -> not allowable, only used for comparsion
- SIG_TYPE_OBJECT = 0x10, // may be object [o]
- SIG_TYPE_REFERENCE = 0x20, // may be reference [r]
- SIG_TYPE_LIST = 0x40, // may be list [l]
- SIG_TYPE_NODE = 0x80, // may be node [n]
- SIG_IS_OPTIONAL = 0x100, // is optional
- SIG_NEEDS_MORE = 0x200, // needs at least one additional parameter following
- SIG_MORE_MAY_FOLLOW = 0x400 // may have more parameters of the same type following
+ SIG_TYPE_OBJECT = 0x08, // may be object [o]
+ SIG_TYPE_REFERENCE = 0x10, // may be reference [r]
+ SIG_TYPE_LIST = 0x20, // may be list [l]
+ SIG_TYPE_NODE = 0x40, // may be node [n]
+ SIG_TYPE_ERROR = 0x80, // happens, when there is a identification error - only used for comparsion
+ SIG_IS_INVALID = 0x100, // ptr is invalid [!] -> invalid offset
+ SIG_IS_OPTIONAL = 0x200, // is optional
+ SIG_NEEDS_MORE = 0x400, // needs at least one additional parameter following
+ SIG_MORE_MAY_FOLLOW = 0x800 // may have more parameters of the same type following
};
// this does not include SIG_TYPE_UNINITIALIZED, because we can not allow uninitialized values anywhere
@@ -196,7 +197,7 @@ public:
* KSIG_INVALID set if the type of reg can be determined, but is invalid.
* 0 on error.
*/
- int findRegType(reg_t reg);
+ uint16 findRegType(reg_t reg);
/******************** Text functionality ********************/
/**