mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-05 17:20:30 +00:00
SCI: Scripts: identify strings + debug command
debug command is called "script_strings" / "scrs"
This commit is contained in:
parent
3d0c691694
commit
ed7007162a
@ -209,6 +209,8 @@ Console::Console(SciEngine *engine) : GUI::Debugger(),
|
||||
registerCmd("bpe", WRAP_METHOD(Console, cmdBreakpointFunction)); // alias
|
||||
// VM
|
||||
registerCmd("script_steps", WRAP_METHOD(Console, cmdScriptSteps));
|
||||
registerCmd("script_strings", WRAP_METHOD(Console, cmdScriptStrings));
|
||||
registerCmd("scrs", WRAP_METHOD(Console, cmdScriptStrings));
|
||||
registerCmd("vm_varlist", WRAP_METHOD(Console, cmdVMVarlist));
|
||||
registerCmd("vmvarlist", WRAP_METHOD(Console, cmdVMVarlist)); // alias
|
||||
registerCmd("vl", WRAP_METHOD(Console, cmdVMVarlist)); // alias
|
||||
@ -2828,6 +2830,71 @@ bool Console::cmdScriptSteps(int argc, const char **argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::cmdScriptStrings(int argc, const char **argv) {
|
||||
SegManager *segMan = _engine->_gamestate->_segMan;
|
||||
int curScriptNr = -1;
|
||||
SegmentId curSegmentNr;
|
||||
Common::List<SegmentId> segmentNrList;
|
||||
|
||||
SegmentType curSegmentType = SEG_TYPE_INVALID;
|
||||
SegmentObj *curSegmentObj = NULL;
|
||||
Script *curScriptObj = NULL;
|
||||
|
||||
if (argc < 2) {
|
||||
debugPrintf("Shows the strings inside a specified script.\n");
|
||||
debugPrintf("Usage: %s <script number>\n", argv[0]);
|
||||
debugPrintf("Example: %s 999\n", argv[0]);
|
||||
debugPrintf("<script number> may be * to show strings inside all loaded scripts\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
segmentNrList.clear();
|
||||
|
||||
if (strcmp(argv[1], "*") == 0) {
|
||||
// get strings of all currently loaded scripts
|
||||
for (curSegmentNr = 0; curSegmentNr < segMan->_heap.size(); curSegmentNr++) {
|
||||
curSegmentObj = segMan->_heap[curSegmentNr];
|
||||
if (curSegmentObj && curSegmentObj->getType() == SEG_TYPE_SCRIPT) {
|
||||
segmentNrList.push_back(curSegmentNr);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
curScriptNr = atoi(argv[1]);
|
||||
curSegmentNr = segMan->getScriptSegment(curScriptNr);
|
||||
if (!curSegmentNr) {
|
||||
debugPrintf("Script %d is currently not loaded/available\n", curScriptNr);
|
||||
return true;
|
||||
}
|
||||
segmentNrList.push_back(curSegmentNr);
|
||||
}
|
||||
|
||||
Common::List<SegmentId>::iterator it;
|
||||
const Common::List<SegmentId>::iterator end = segmentNrList.end();
|
||||
|
||||
for (it = segmentNrList.begin(); it != end; it++) {
|
||||
curSegmentNr = *it;
|
||||
// get object of this segment
|
||||
curSegmentObj = segMan->getSegmentObj(curSegmentNr);
|
||||
if (!curSegmentObj)
|
||||
continue;
|
||||
|
||||
curSegmentType = curSegmentObj->getType();
|
||||
if (curSegmentType != SEG_TYPE_SCRIPT) // safety check
|
||||
continue;
|
||||
|
||||
curScriptObj = (Script *)curSegmentObj;
|
||||
debugPrintf("=== SCRIPT %d from Segment %d ===\n", curScriptObj->getScriptNumber(), curSegmentNr);
|
||||
debugN("=== SCRIPT %d from Segment %d ===\n", curScriptObj->getScriptNumber(), curSegmentNr);
|
||||
|
||||
// now print the string list
|
||||
curScriptObj->debugPrintStrings(this);
|
||||
debugPrintf("\n");
|
||||
debugN("\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::cmdBacktrace(int argc, const char **argv) {
|
||||
debugPrintf("Call stack (current base: 0x%x):\n", _engine->_gamestate->executionStackBase);
|
||||
Common::List<ExecStack>::const_iterator iter;
|
||||
|
@ -147,6 +147,7 @@ private:
|
||||
bool cmdBreakpointFunction(int argc, const char **argv);
|
||||
// VM
|
||||
bool cmdScriptSteps(int argc, const char **argv);
|
||||
bool cmdScriptStrings(int argc, const char **argv);
|
||||
bool cmdVMVarlist(int argc, const char **argv);
|
||||
bool cmdVMVars(int argc, const char **argv);
|
||||
bool cmdStack(int argc, const char **argv);
|
||||
|
@ -20,6 +20,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sci/console.h"
|
||||
#include "sci/sci.h"
|
||||
#include "sci/resource.h"
|
||||
#include "sci/util.h"
|
||||
@ -64,6 +65,7 @@ void Script::freeScript() {
|
||||
_lockers = 1;
|
||||
_markedAsDeleted = false;
|
||||
_objects.clear();
|
||||
_stringLookupList.clear();
|
||||
}
|
||||
|
||||
void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptPatcher) {
|
||||
@ -204,6 +206,191 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP
|
||||
//_localsCount = (_bufSize - _localsOffset) >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
// find all strings of this script
|
||||
identifyStrings();
|
||||
}
|
||||
|
||||
void Script::identifyStrings() {
|
||||
stringLookupListEntry listEntry;
|
||||
byte *scriptDataPtr = NULL;
|
||||
byte *stringStartPtr = NULL;
|
||||
byte *stringDataPtr = NULL;
|
||||
int scriptDataLeft = 0;
|
||||
int stringDataLeft = 0;
|
||||
byte stringDataByte = 0;
|
||||
|
||||
_stringLookupList.clear();
|
||||
//stringLookupListType _stringLookupList; // Table of string data, that is inside the currently loaded script
|
||||
|
||||
if (getSciVersion() < SCI_VERSION_1_1) {
|
||||
scriptDataPtr = _buf;
|
||||
scriptDataLeft = _bufSize;
|
||||
|
||||
// Go through all SCI_OBJ_STRINGS blocks
|
||||
if (getSciVersion() == SCI_VERSION_0_EARLY) {
|
||||
if (scriptDataLeft < 2)
|
||||
error("Script::identifyStrings(): unexpected end of script");
|
||||
scriptDataPtr += 2;
|
||||
scriptDataLeft -= 2;
|
||||
}
|
||||
|
||||
uint16 blockType;
|
||||
uint16 blockSize;
|
||||
|
||||
do {
|
||||
if (scriptDataLeft < 2)
|
||||
error("Script::identifyStrings(): unexpected end of script");
|
||||
|
||||
blockType = READ_LE_UINT16(scriptDataPtr);
|
||||
scriptDataPtr += 2;
|
||||
scriptDataLeft -= 2;
|
||||
if (blockType == 0) // end of blocks detected
|
||||
break;
|
||||
|
||||
if (scriptDataLeft < 2)
|
||||
error("Script::identifyStrings(): unexpected end of script");
|
||||
|
||||
blockSize = READ_LE_UINT16(scriptDataPtr);
|
||||
if (blockSize < 4)
|
||||
error("Script::identifyStrings(): invalid block size");
|
||||
blockSize -= 4; // block size includes block-type UINT16 and block-size UINT16
|
||||
scriptDataPtr += 2;
|
||||
scriptDataLeft -= 2;
|
||||
|
||||
if (scriptDataLeft < blockSize)
|
||||
error("Script::identifyStrings(): invalid block size");
|
||||
|
||||
if (blockType == SCI_OBJ_STRINGS) {
|
||||
// string block detected, we now grab all NUL terminated strings out of this block
|
||||
stringDataPtr = scriptDataPtr;
|
||||
stringDataLeft = blockSize;
|
||||
|
||||
do {
|
||||
if (stringDataLeft < 1) // no more bytes left
|
||||
break;
|
||||
|
||||
stringStartPtr = stringDataPtr;
|
||||
listEntry.ptrOffset = stringStartPtr - _buf; // Calculate offset inside script data
|
||||
// now look for terminating [NUL]
|
||||
do {
|
||||
stringDataByte = READ_SCI11ENDIAN_UINT16(stringDataPtr);
|
||||
stringDataPtr++;
|
||||
stringDataLeft--;
|
||||
if (!stringDataByte) // NUL found, exit this loop
|
||||
break;
|
||||
if (stringDataLeft < 1) // no more bytes left
|
||||
error("Script::identifyStrings(): string without terminating NUL");
|
||||
} while (1);
|
||||
|
||||
listEntry.stringSize = stringDataPtr - stringStartPtr;
|
||||
_stringLookupList.push_back(listEntry);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
scriptDataPtr += blockSize;
|
||||
scriptDataLeft -= blockSize;
|
||||
} while (1);
|
||||
|
||||
} else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
|
||||
// Strings in SCI1.1 come after the object instances
|
||||
scriptDataPtr = _heapStart;
|
||||
scriptDataLeft = _heapSize;
|
||||
|
||||
if (scriptDataLeft < 4)
|
||||
error("Script::identifyStrings(): unexpected end of script");
|
||||
|
||||
uint16 endOfStringOffset = READ_SCI11ENDIAN_UINT16(scriptDataPtr);
|
||||
uint16 objectStartOffset = READ_SCI11ENDIAN_UINT16(scriptDataPtr + 2) * 2 + 4;
|
||||
|
||||
if (scriptDataLeft < objectStartOffset)
|
||||
error("Script::identifyStrings(): object start is beyond heap size");
|
||||
if (scriptDataLeft < endOfStringOffset)
|
||||
error("Script::identifyStrings(): end of string is beyond heap size");
|
||||
|
||||
byte *endOfStringPtr = scriptDataPtr + endOfStringOffset;
|
||||
|
||||
scriptDataPtr += objectStartOffset;
|
||||
scriptDataLeft -= objectStartOffset;
|
||||
|
||||
uint16 blockType;
|
||||
uint16 blockSize;
|
||||
|
||||
// skip all objects
|
||||
do {
|
||||
if (scriptDataLeft < 2)
|
||||
error("Script::identifyStrings(): unexpected end of script");
|
||||
|
||||
blockType = READ_SCI11ENDIAN_UINT16(scriptDataPtr);
|
||||
scriptDataPtr += 2;
|
||||
scriptDataLeft -= 2;
|
||||
if (blockType != SCRIPT_OBJECT_MAGIC_NUMBER)
|
||||
break;
|
||||
|
||||
if (scriptDataLeft < 2)
|
||||
error("Script::identifyStrings(): unexpected end of script");
|
||||
|
||||
blockSize = READ_SCI11ENDIAN_UINT16(scriptDataPtr) * 2;
|
||||
scriptDataPtr += 2;
|
||||
scriptDataLeft -= 2;
|
||||
blockSize -= 4; // blocksize contains UINT16 type and UINT16 size
|
||||
if (scriptDataLeft < blockSize)
|
||||
error("Script::identifyStrings(): invalid block size");
|
||||
|
||||
scriptDataPtr += blockSize;
|
||||
scriptDataLeft -= blockSize;
|
||||
} while (1);
|
||||
|
||||
// now scriptDataPtr points to right at the start of the strings
|
||||
if (scriptDataPtr > endOfStringPtr)
|
||||
error("Script::identifyStrings(): string block / end-of-string block mismatch");
|
||||
|
||||
stringDataPtr = scriptDataPtr;
|
||||
stringDataLeft = endOfStringPtr - scriptDataPtr; // Calculate byte count within string-block
|
||||
|
||||
do {
|
||||
if (stringDataLeft < 1) // no more bytes left
|
||||
break;
|
||||
|
||||
stringStartPtr = stringDataPtr;
|
||||
listEntry.ptrOffset = stringStartPtr - _buf; // Calculate offset inside script data
|
||||
// now look for terminating [NUL]
|
||||
do {
|
||||
stringDataByte = READ_SCI11ENDIAN_UINT16(stringDataPtr);
|
||||
stringDataPtr++;
|
||||
stringDataLeft--;
|
||||
if (!stringDataByte) // NUL found, exit this loop
|
||||
break;
|
||||
if (stringDataLeft < 1) // no more bytes left
|
||||
error("Script::identifyStrings(): string without terminating NUL");
|
||||
} while (1);
|
||||
|
||||
listEntry.stringSize = stringDataPtr - stringStartPtr;
|
||||
_stringLookupList.push_back(listEntry);
|
||||
} while (1);
|
||||
|
||||
} else if (getSciVersion() == SCI_VERSION_3) {
|
||||
warning("TODO: identifyStrings(): Implement SCI3 variant");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Script::debugPrintStrings(Console *con) {
|
||||
stringLookupListType::iterator it;
|
||||
const stringLookupListType::iterator end = _stringLookupList.end();
|
||||
byte *stringPtr;
|
||||
|
||||
if (!_stringLookupList.size()) {
|
||||
con->debugPrintf(" no strings\n");
|
||||
debugN(" no strings\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (it = _stringLookupList.begin(); it != end; ++it) {
|
||||
stringPtr = _buf + it->ptrOffset;
|
||||
con->debugPrintf(" %04x: '%s' (size %d)\n", it->ptrOffset, stringPtr, it->stringSize);
|
||||
debugN(" %04x: '%s' (size %d)\n", it->ptrOffset, stringPtr, it->stringSize);
|
||||
}
|
||||
}
|
||||
|
||||
const byte *Script::getSci3ObjectsPointer() {
|
||||
|
@ -49,6 +49,13 @@ enum ScriptObjectTypes {
|
||||
|
||||
typedef Common::HashMap<uint16, Object> ObjMap;
|
||||
|
||||
struct stringLookupListEntry {
|
||||
uint16 ptrOffset; // offset of the string
|
||||
uint16 stringSize; // size of string, including terminating [NUL]
|
||||
};
|
||||
|
||||
typedef Common::List<stringLookupListEntry> stringLookupListType;
|
||||
|
||||
class Script : public SegmentObj {
|
||||
private:
|
||||
int _nr; /**< Script number */
|
||||
@ -75,6 +82,8 @@ private:
|
||||
|
||||
ObjMap _objects; /**< Table for objects, contains property variables */
|
||||
|
||||
stringLookupListType _stringLookupList; // Table of string data, that is inside the currently loaded script
|
||||
|
||||
public:
|
||||
int getLocalsOffset() const { return _localsOffset; }
|
||||
uint16 getLocalsCount() const { return _localsCount; }
|
||||
@ -248,6 +257,11 @@ public:
|
||||
*/
|
||||
int getCodeBlockOffsetSci3() { return READ_SCI11ENDIAN_UINT32(_buf); }
|
||||
|
||||
/**
|
||||
* Print string lookup table (list) to debug console
|
||||
*/
|
||||
void debugPrintStrings(Console *con);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Processes a relocation block within a SCI0-SCI2.1 script
|
||||
@ -294,6 +308,11 @@ private:
|
||||
void initializeObjectsSci3(SegManager *segMan, SegmentId segmentId);
|
||||
|
||||
LocalVariables *allocLocalsSegment(SegManager *segMan);
|
||||
|
||||
/**
|
||||
* Identifies strings within script data and set up lookup-table
|
||||
*/
|
||||
void identifyStrings();
|
||||
};
|
||||
|
||||
} // End of namespace Sci
|
||||
|
Loading…
Reference in New Issue
Block a user