aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
authorColin Snover2016-10-29 14:32:49 -0500
committerColin Snover2016-11-02 11:27:22 -0500
commita605a891bb632cbe4a94ed4c762fbcdce3e7b89a (patch)
tree3288090a00fab94cf35445465c2c91984c742aea /engines/sci
parent26ba577aa5fb8d8855de5e0f0b38b9944b95f859 (diff)
downloadscummvm-rg350-a605a891bb632cbe4a94ed4c762fbcdce3e7b89a.tar.gz
scummvm-rg350-a605a891bb632cbe4a94ed4c762fbcdce3e7b89a.tar.bz2
scummvm-rg350-a605a891bb632cbe4a94ed4c762fbcdce3e7b89a.zip
SCI: Add reference dump to disk in debugger
This allows references in memory to be dumped to disk for examination by other tools. In the case of SCI32 bitmaps, data is output in 8-bit TGA format without transparency, which allows the current palette to also be examined. (The alternative would be to use 32-bit TGA to display transparency, and lose the palette, or dump to a more complicated format that supports 1-bit transparency.)
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/console.cpp123
-rw-r--r--engines/sci/console.h1
2 files changed, 124 insertions, 0 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 8737c8b954..04fe0f78f4 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -53,6 +53,7 @@
#ifdef ENABLE_SCI32
#include "sci/graphics/frameout.h"
#include "sci/graphics/paint32.h"
+#include "sci/graphics/palette32.h"
#include "video/coktel_decoder.h"
#endif
@@ -228,6 +229,8 @@ Console::Console(SciEngine *engine) : GUI::Debugger(),
registerCmd("view_listnode", WRAP_METHOD(Console, cmdViewListNode));
registerCmd("view_reference", WRAP_METHOD(Console, cmdViewReference));
registerCmd("vr", WRAP_METHOD(Console, cmdViewReference)); // alias
+ registerCmd("dump_reference", WRAP_METHOD(Console, cmdDumpReference));
+ registerCmd("dr", WRAP_METHOD(Console, cmdDumpReference)); // alias
registerCmd("view_object", WRAP_METHOD(Console, cmdViewObject));
registerCmd("vo", WRAP_METHOD(Console, cmdViewObject)); // alias
registerCmd("active_object", WRAP_METHOD(Console, cmdViewActiveObject));
@@ -446,6 +449,7 @@ bool Console::cmdHelp(int argc, const char **argv) {
debugPrintf(" value_type - Determines the type of a value\n");
debugPrintf(" view_listnode - Examines the list node at the given address\n");
debugPrintf(" view_reference / vr - Examines an arbitrary reference\n");
+ debugPrintf(" dump_reference / dr - Dumps an arbitrary reference to disk\n");
debugPrintf(" view_object / vo - Examines the object at the given address\n");
debugPrintf(" active_object - Shows information on the currently active object or class\n");
debugPrintf(" acc_object - Shows information on the object or class at the address indexed by the accumulator\n");
@@ -2843,6 +2847,125 @@ bool Console::cmdViewReference(int argc, const char **argv) {
return true;
}
+bool Console::cmdDumpReference(int argc, const char **argv) {
+ if (argc < 2) {
+ debugPrintf("Dumps an arbitrary reference to disk.\n");
+ debugPrintf("Usage: %s <start address> [<end address>]\n", argv[0]);
+ debugPrintf("Where <start address> is the starting address to dump\n");
+ debugPrintf("<end address>, if provided, is the address where the dump ends\n");
+ debugPrintf("Check the \"addresses\" command on how to use addresses\n");
+ return true;
+ }
+
+ reg_t reg = NULL_REG;
+ reg_t reg_end = NULL_REG;
+
+ if (parse_reg_t(_engine->_gamestate, argv[1], &reg, false)) {
+ debugPrintf("Invalid address passed.\n");
+ debugPrintf("Check the \"addresses\" command on how to use addresses\n");
+ return true;
+ }
+
+ if (argc > 2) {
+ if (parse_reg_t(_engine->_gamestate, argv[2], &reg_end, false)) {
+ debugPrintf("Invalid address passed.\n");
+ debugPrintf("Check the \"addresses\" command on how to use addresses\n");
+ return true;
+ }
+ }
+
+ if (reg.getSegment() == 0 && reg.getOffset() == 0) {
+ debugPrintf("Register is null.\n");
+ return true;
+ }
+
+ if (g_sci->getKernel()->findRegType(reg) != SIG_TYPE_REFERENCE) {
+ debugPrintf("%04x:%04x is not a reference\n", PRINT_REG(reg));
+ return true;
+ }
+
+ if (reg_end.getSegment() != reg.getSegment() && reg_end != NULL_REG) {
+ debugPrintf("Ending segment different from starting segment. Assuming no bound on dump.\n");
+ reg_end = NULL_REG;
+ }
+
+ Common::DumpFile out;
+ Common::String outFileName;
+ uint32 bytesWritten;
+
+ switch (_engine->_gamestate->_segMan->getSegmentType(reg.getSegment())) {
+#ifdef ENABLE_SCI32
+ case SEG_TYPE_BITMAP: {
+ outFileName = Common::String::format("%04x_%04x.tga", PRINT_REG(reg));
+ out.open(outFileName);
+ SciBitmap &bitmap = *_engine->_gamestate->_segMan->lookupBitmap(reg);
+ const Color *color = g_sci->_gfxPalette32->getCurrentPalette().colors;
+ const uint16 numColors = ARRAYSIZE(g_sci->_gfxPalette32->getCurrentPalette().colors);
+
+ out.writeByte(0); // image id length
+ out.writeByte(1); // color map type (present)
+ out.writeByte(1); // image type (uncompressed color-mapped)
+ out.writeSint16LE(0); // index of first color map entry
+ out.writeSint16LE(numColors); // number of color map entries
+ out.writeByte(24); // number of bits per color entry (RGB24)
+ out.writeSint16LE(0); // bottom-left x-origin
+ out.writeSint16LE(bitmap.getHeight() - 1); // bottom-left y-origin
+ out.writeSint16LE(bitmap.getWidth()); // width
+ out.writeSint16LE(bitmap.getHeight()); // height
+ out.writeByte(8); // bits per pixel
+ out.writeByte(1 << 5); // origin of pixel data (top-left)
+
+ bytesWritten = 18;
+
+ for (int i = 0; i < numColors; ++i) {
+ out.writeByte(color->b);
+ out.writeByte(color->g);
+ out.writeByte(color->r);
+ ++color;
+ }
+
+ bytesWritten += numColors * 3;
+ bytesWritten += out.write(bitmap.getPixels(), bitmap.getWidth() * bitmap.getHeight());
+ break;
+ }
+#endif
+
+ default: {
+ const SegmentRef block = _engine->_gamestate->_segMan->dereference(reg);
+ uint32 size = block.maxSize;
+
+ if (size == 0) {
+ debugPrintf("Size of reference is zero.\n");
+ return true;
+ }
+
+ if (reg_end.getSegment() != 0 && (size < reg_end.getOffset() - reg.getOffset())) {
+ debugPrintf("Block end out of bounds (size %d). Resetting.\n", size);
+ reg_end = NULL_REG;
+ }
+
+ if (reg_end.getSegment() != 0 && (size >= reg_end.getOffset() - reg.getOffset())) {
+ size = reg_end.getOffset() - reg.getOffset();
+ }
+
+ if (reg_end.getSegment() != 0) {
+ debugPrintf("Block size less than or equal to %d\n", size);
+ }
+
+ outFileName = Common::String::format("%04x_%04x.dmp", PRINT_REG(reg));
+ out.open(outFileName);
+ bytesWritten = out.write(block.raw, size);
+ break;
+ }
+ }
+
+ out.finalize();
+ out.close();
+
+ debugPrintf("Wrote %u bytes to %s\n", bytesWritten, outFileName.c_str());
+ return true;
+}
+
bool Console::cmdViewObject(int argc, const char **argv) {
if (argc != 2) {
debugPrintf("Examines the object at the given address.\n");
diff --git a/engines/sci/console.h b/engines/sci/console.h
index 0b87a4408b..d4b17ee802 100644
--- a/engines/sci/console.h
+++ b/engines/sci/console.h
@@ -163,6 +163,7 @@ private:
bool cmdValueType(int argc, const char **argv);
bool cmdViewListNode(int argc, const char **argv);
bool cmdViewReference(int argc, const char **argv);
+ bool cmdDumpReference(int argc, const char **argv);
bool cmdViewObject(int argc, const char **argv);
bool cmdViewActiveObject(int argc, const char **argv);
bool cmdViewAccumulatorObject(int argc, const char **argv);