diff options
-rw-r--r-- | engines/sci/console.cpp | 128 | ||||
-rw-r--r-- | engines/sci/console.h | 3 |
2 files changed, 131 insertions, 0 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index a2b065ab6c..4d8ff17c10 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -117,6 +117,7 @@ Console::Console(SciEngine *engine) : GUI::Debugger(), registerCmd("alloc_list", WRAP_METHOD(Console, cmdAllocList)); registerCmd("hexgrep", WRAP_METHOD(Console, cmdHexgrep)); registerCmd("verify_scripts", WRAP_METHOD(Console, cmdVerifyScripts)); + registerCmd("integrity_dump", WRAP_METHOD(Console, cmdResourceIntegrityDump)); // Game registerCmd("save_game", WRAP_METHOD(Console, cmdSaveGame)); registerCmd("restore_game", WRAP_METHOD(Console, cmdRestoreGame)); @@ -373,6 +374,7 @@ bool Console::cmdHelp(int argc, const char **argv) { debugPrintf(" alloc_list - Lists all allocated resources\n"); debugPrintf(" hexgrep - Searches some resources for a particular sequence of bytes, represented as hexadecimal numbers\n"); debugPrintf(" verify_scripts - Performs sanity checks on SCI1.1-SCI2.1 game scripts (e.g. if they're up to 64KB in total)\n"); + debugPrintf(" integrity_dump - Dumps integrity data about resources in the current game to disk\n"); debugPrintf("\n"); debugPrintf("Game:\n"); debugPrintf(" save_game - Saves the current game state to the hard disk\n"); @@ -919,6 +921,113 @@ bool Console::cmdList(int argc, const char **argv) { return true; } +bool Console::cmdResourceIntegrityDump(int argc, const char **argv) { + if (argc < 2) { + debugPrintf("Dumps integrity data about resources in the current game to disk.\n"); + debugPrintf("Usage: %s <filename> [<skip video file hashing>] [<skip video files altogether>]\n", argv[0]); + return true; + } + + Common::DumpFile outFile; + if (!outFile.open(argv[1])) { + debugPrintf("Failed to open output file %s.\n", argv[1]); + return true; + } + + const bool hashVideoFiles = argc < 3; + const bool videoFiles = argc < 4; + + for (int i = 0; i < kResourceTypeInvalid; ++i) { + const ResourceType resType = (ResourceType)i; + + // This will list video resources inside of resource bundles even if + // video files are skipped, but this seems fine since those files are + // small because they were intended to load into memory. (This happens + // with VMDs in GK2.) + Common::List<ResourceId> resources = _engine->getResMan()->listResources(resType); + + const char *extension; + if (videoFiles) { + switch (resType) { + case kResourceTypeRobot: + case kResourceTypeVMD: + case kResourceTypeDuck: + case kResourceTypeClut: { + extension = getResourceTypeExtension(resType); + assert(*extension != '\0'); + + const Common::String filesGlob = Common::String::format("*.%s", extension).c_str(); + Common::ArchiveMemberList files; + const int numMatches = SearchMan.listMatchingMembers(files, filesGlob); + if (numMatches > 0) { + Common::ArchiveMemberList::const_iterator it; + for (it = files.begin(); it != files.end(); ++it) { + const uint resNo = atoi((*it)->getName().c_str()); + resources.push_back(ResourceId(resType, resNo)); + } + } + + break; + } + default: + extension = ""; + } + } + + if (resources.size()) { + Common::sort(resources.begin(), resources.end()); + Common::List<ResourceId>::const_iterator it; + debugPrintf("%s: ", getResourceTypeName(resType)); + for (it = resources.begin(); it != resources.end(); ++it) { + Common::String statusName; + if (resType == kResourceTypeAudio36 || resType == kResourceTypeSync36) { + statusName = it->toPatchNameBase36(); + } else { + statusName = Common::String::format("%d", it->getNumber()); + } + + const Common::String resourceName = it->toString(); + + Resource *resource = _engine->getResMan()->findResource(*it, false); + if (resource) { + Common::MemoryReadStream stream = resource->toStream(); + writeIntegrityDumpLine(statusName, resourceName, outFile, &stream, resource->size(), true); + } else if (videoFiles && *extension != '\0') { + const Common::String fileName = Common::String::format("%u.%s", it->getNumber(), extension); + Common::File file; + Common::ReadStream *stream = nullptr; + if (file.open(fileName)) { + stream = &file; + } + writeIntegrityDumpLine(statusName, resourceName, outFile, stream, file.size(), hashVideoFiles); + } + } + + debugPrintf("\n"); + } + } + + const char *otherVideoFiles[] = { "avi", "seq" }; + for (uint i = 0; i < ARRAYSIZE(otherVideoFiles); ++i) { + const char *extension = otherVideoFiles[i]; + + Common::ArchiveMemberList files; + if (SearchMan.listMatchingMembers(files, Common::String::format("*.%s", extension).c_str()) > 0) { + debugPrintf("%s: ", extension); + Common::sort(files.begin(), files.end(), Common::ArchiveMemberListComparator()); + Common::ArchiveMemberList::const_iterator it; + for (it = files.begin(); it != files.end(); ++it) { + const Common::ArchiveMember &file = **it; + Common::ScopedPtr<Common::SeekableReadStream> stream(file.createReadStream()); + writeIntegrityDumpLine(file.getName(), file.getName(), outFile, stream.get(), stream->size(), hashVideoFiles); + } + debugPrintf("\n"); + } + } + + return true; +} + bool Console::cmdAllocList(int argc, const char **argv) { ResourceManager *resMan = _engine->getResMan(); @@ -4907,6 +5016,25 @@ void Console::printBitmap(reg_t reg) { #endif +void Console::writeIntegrityDumpLine(const Common::String &statusName, const Common::String &resourceName, Common::WriteStream &out, Common::ReadStream *const data, const int size, const bool writeHash) { + debugPrintf("%s", statusName.c_str()); + + out.writeString(resourceName); + if (!data) { + out.writeString(" ERROR\n"); + debugPrintf("[ERR] "); + } else { + out.writeString(Common::String::format(" %d ", size)); + if (writeHash) { + out.writeString(Common::computeStreamMD5AsString(*data)); + } else { + out.writeString("disabled"); + } + out.writeString("\n"); + debugPrintf("[OK] "); + } +} + static void printChar(byte c) { if (c < 32 || c >= 127) c = '.'; diff --git a/engines/sci/console.h b/engines/sci/console.h index c467b863cd..3cc19ad254 100644 --- a/engines/sci/console.h +++ b/engines/sci/console.h @@ -71,6 +71,7 @@ private: bool cmdResourceInfo(int argc, const char **argv); bool cmdResourceTypes(int argc, const char **argv); bool cmdList(int argc, const char **argv); + bool cmdResourceIntegrityDump(int argc, const char **argv); bool cmdAllocList(int argc, const char **argv); bool cmdHexgrep(int argc, const char **argv); bool cmdVerifyScripts(int argc, const char **argv); @@ -192,6 +193,8 @@ private: void printBitmap(reg_t reg); #endif + void writeIntegrityDumpLine(const Common::String &statusName, const Common::String &resourceName, Common::WriteStream &out, Common::ReadStream *const data, const int size, const bool writeHash); + SciEngine *_engine; DebugState &_debugState; Common::String _videoFile; |