[Scummvm-cvs-logs] scummvm master -> ed7007162a092e4b9e3d9306b078af5a8984cad0

m-kiewitz m_kiewitz at users.sourceforge.net
Mon May 4 21:19:55 CEST 2015


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
ed7007162a SCI: Scripts: identify strings + debug command


Commit: ed7007162a092e4b9e3d9306b078af5a8984cad0
    https://github.com/scummvm/scummvm/commit/ed7007162a092e4b9e3d9306b078af5a8984cad0
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2015-05-04T21:19:05+02:00

Commit Message:
SCI: Scripts: identify strings + debug command

debug command is called "script_strings" / "scrs"

Changed paths:
    engines/sci/console.cpp
    engines/sci/console.h
    engines/sci/engine/script.cpp
    engines/sci/engine/script.h



diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 3f5548a..bc9ad36 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -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;
diff --git a/engines/sci/console.h b/engines/sci/console.h
index 6d02408..00d95b5 100644
--- a/engines/sci/console.h
+++ b/engines/sci/console.h
@@ -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);
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index 88becc8..70e5588 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -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() {
diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h
index 46d6ace..fe774ae 100644
--- a/engines/sci/engine/script.h
+++ b/engines/sci/engine/script.h
@@ -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






More information about the Scummvm-git-logs mailing list