diff --git a/DiskArc/Arc/AppleLink.cs b/DiskArc/Arc/AppleLink.cs index c270fb2..76e44fe 100644 --- a/DiskArc/Arc/AppleLink.cs +++ b/DiskArc/Arc/AppleLink.cs @@ -293,5 +293,8 @@ public void AddPart(IFileEntry entry, FilePart part, IPartSource partSource, public void DeletePart(IFileEntry entry, FilePart part) { throw new InvalidOperationException("This archive format is read-only"); } + + // IArchive + public string? DebugDump() { return null; } } } diff --git a/DiskArc/Arc/AppleSingle.cs b/DiskArc/Arc/AppleSingle.cs index 801f4b1..38e4f17 100644 --- a/DiskArc/Arc/AppleSingle.cs +++ b/DiskArc/Arc/AppleSingle.cs @@ -429,5 +429,8 @@ private void CheckModAccess(IFileEntry ientry) { Debug.Assert(entry.ChangeObject != null); } } + + // IArchive + public string? DebugDump() { return null; } } } diff --git a/DiskArc/Arc/AudioRecording.cs b/DiskArc/Arc/AudioRecording.cs index eb8d07e..272865f 100644 --- a/DiskArc/Arc/AudioRecording.cs +++ b/DiskArc/Arc/AudioRecording.cs @@ -397,5 +397,8 @@ public void AddPart(IFileEntry entry, FilePart part, IPartSource partSource, public void DeletePart(IFileEntry entry, FilePart part) { throw new InvalidOperationException("This archive format is read-only"); } + + // IArchive + public string? DebugDump() { return null; } } } diff --git a/DiskArc/Arc/Binary2.cs b/DiskArc/Arc/Binary2.cs index 8200068..6341b79 100644 --- a/DiskArc/Arc/Binary2.cs +++ b/DiskArc/Arc/Binary2.cs @@ -614,6 +614,9 @@ public void DeletePart(IFileEntry ientry, FilePart part) { IsReconstructionNeeded = true; } + // IArchive + public string? DebugDump() { return null; } + /// /// Confirms that we are allowed to modify this entry. /// diff --git a/DiskArc/Arc/GZip.cs b/DiskArc/Arc/GZip.cs index eca527a..e8e1186 100644 --- a/DiskArc/Arc/GZip.cs +++ b/DiskArc/Arc/GZip.cs @@ -373,5 +373,8 @@ public static string StripGZExtension(string pathName) { return pathName; } } + + // IArchive + public string? DebugDump() { return null; } } } diff --git a/DiskArc/Arc/MacBinary.cs b/DiskArc/Arc/MacBinary.cs index 42d5e9f..5fd1215 100644 --- a/DiskArc/Arc/MacBinary.cs +++ b/DiskArc/Arc/MacBinary.cs @@ -227,5 +227,8 @@ public void AddPart(IFileEntry entry, FilePart part, IPartSource partSource, public void DeletePart(IFileEntry entry, FilePart part) { throw new InvalidOperationException("This archive format is read-only"); } + + // IArchive + public string? DebugDump() { return null; } } } diff --git a/DiskArc/Arc/NuFX.cs b/DiskArc/Arc/NuFX.cs index 4d1b1df..1fa98d0 100644 --- a/DiskArc/Arc/NuFX.cs +++ b/DiskArc/Arc/NuFX.cs @@ -747,6 +747,9 @@ public void DeletePart(IFileEntry ientry, FilePart part) { ((NuFX_FileEntry)ientry).DeletePart(part); } + // IArchive + public string? DebugDump() { return null; } + /// /// Confirms that we are allowed to modify this entry. /// diff --git a/DiskArc/Arc/Zip.cs b/DiskArc/Arc/Zip.cs index e7d26ce..bfcb5f1 100644 --- a/DiskArc/Arc/Zip.cs +++ b/DiskArc/Arc/Zip.cs @@ -664,6 +664,9 @@ public void DeletePart(IFileEntry ientry, FilePart part) { ((Zip_FileEntry)ientry).DeletePart(); } + // IArchive + public string? DebugDump() { return null; } + /// /// Confirms that we are allowed to modify this entry. /// diff --git a/DiskArc/FS/CPM.cs b/DiskArc/FS/CPM.cs index a8dbb99..d0a9321 100644 --- a/DiskArc/FS/CPM.cs +++ b/DiskArc/FS/CPM.cs @@ -427,6 +427,9 @@ public override string ToString() { return "[CP/M" + rawStr + "]"; } + // IFileSystem + public string? DebugDump() { return null; } + // IDisposable generic finalizer. ~CPM() { Dispose(false); diff --git a/DiskArc/FS/DOS.cs b/DiskArc/FS/DOS.cs index 271c29c..685002d 100644 --- a/DiskArc/FS/DOS.cs +++ b/DiskArc/FS/DOS.cs @@ -383,6 +383,9 @@ public override string ToString() { return "[DOS " + id + "]"; } + // IFileSystem + public string? DebugDump() { return null; } + // IDisposable generic finalizer. ~DOS() { diff --git a/DiskArc/FS/Gutenberg.cs b/DiskArc/FS/Gutenberg.cs index 488e3cb..7710416 100644 --- a/DiskArc/FS/Gutenberg.cs +++ b/DiskArc/FS/Gutenberg.cs @@ -173,6 +173,9 @@ public override string ToString() { return "[Gutenberg (" + id + ")]"; } + // IFileSystem + public string? DebugDump() { return null; } + // IDisposable generic finalizer. ~Gutenberg() { Dispose(false); diff --git a/DiskArc/FS/HFS.cs b/DiskArc/FS/HFS.cs index 7907fee..ac4a48a 100644 --- a/DiskArc/FS/HFS.cs +++ b/DiskArc/FS/HFS.cs @@ -225,6 +225,9 @@ public override string ToString() { return "[HFS vol: " + id + "]"; } + // IFileSystem + public string? DebugDump() { return HFS_Dump.Dump(this); } + // IDisposable generic finalizer. ~HFS() { Dispose(false); diff --git a/DiskArc/FS/HFS_Dump.cs b/DiskArc/FS/HFS_Dump.cs index 51fb217..5c3708a 100644 --- a/DiskArc/FS/HFS_Dump.cs +++ b/DiskArc/FS/HFS_Dump.cs @@ -53,6 +53,7 @@ public static string Dump(HFS fs) { sb.AppendLine("Total Files : " + mdb.FileCount); sb.AppendLine("Total Dirs : " + mdb.DirCount); sb.AppendLine("Next CNID : " + mdb.NextCatalogID); + sb.AppendLine("Blessed system CNID: " + mdb.FndrInfo[0]); sb.AppendLine("Vol Bitmap Start : " + mdb.VolBitmapStart); sb.AppendLine("Free Blocks : " + mdb.FreeBlocks); diff --git a/DiskArc/FS/HFS_MDB.cs b/DiskArc/FS/HFS_MDB.cs index d9ae281..4fff80e 100644 --- a/DiskArc/FS/HFS_MDB.cs +++ b/DiskArc/FS/HFS_MDB.cs @@ -212,6 +212,13 @@ public uint DirCount { /// drFndrInfo: information used by the Macintosh Finder. private uint[] drFndrInfo = new uint[8]; + public uint[] FndrInfo { + get { + uint[] copy = new uint[8]; + Array.Copy(drFndrInfo, copy, drFndrInfo.Length); + return copy; + } + } /// drVCSize / drEmbedSigWord: originally, size (in allocation blocks) of the /// volume cache. Changed to embedded volume signature. diff --git a/DiskArc/FS/MFS.cs b/DiskArc/FS/MFS.cs index f123208..6480334 100644 --- a/DiskArc/FS/MFS.cs +++ b/DiskArc/FS/MFS.cs @@ -163,6 +163,9 @@ public override string ToString() { return "[MFS (" + id + ")]"; } + // IFileSystem + public string? DebugDump() { return null; } + // IDisposable generic finalizer. ~MFS() { Dispose(false); diff --git a/DiskArc/FS/Pascal.cs b/DiskArc/FS/Pascal.cs index 5077481..d21a68c 100644 --- a/DiskArc/FS/Pascal.cs +++ b/DiskArc/FS/Pascal.cs @@ -253,6 +253,9 @@ public override string ToString() { return "[Pascal vol '" + id + "']"; } + // IFileSystem + public string? DebugDump() { return null; } + // IDisposable generic finalizer. ~Pascal() { Dispose(false); diff --git a/DiskArc/FS/ProDOS.cs b/DiskArc/FS/ProDOS.cs index 994bf82..f8d1b61 100644 --- a/DiskArc/FS/ProDOS.cs +++ b/DiskArc/FS/ProDOS.cs @@ -246,6 +246,9 @@ public override string ToString() { return "[ProDOS vol '" + id + "']"; } + // IFileSystem + public string? DebugDump() { return null; } + // IDisposable generic finalizer. ~ProDOS() { Dispose(false); diff --git a/DiskArc/FS/RDOS.cs b/DiskArc/FS/RDOS.cs index 8804902..0bb3f1d 100644 --- a/DiskArc/FS/RDOS.cs +++ b/DiskArc/FS/RDOS.cs @@ -254,6 +254,9 @@ public override string ToString() { return "[RDOS (" + id + ")]"; } + // IFileSystem + public string? DebugDump() { return null; } + // IDisposable generic finalizer. ~RDOS() { Dispose(false); diff --git a/DiskArc/IArchive.cs b/DiskArc/IArchive.cs index cf6b45c..abfb3ba 100644 --- a/DiskArc/IArchive.cs +++ b/DiskArc/IArchive.cs @@ -296,5 +296,11 @@ void AddPart(IFileEntry entry, Defs.FilePart part, IPartSource partSource, /// This type of archive does not allow this /// part. void DeletePart(IFileEntry entry, Defs.FilePart part); + + /// + /// Generates detailed human-readable information about the archive. + /// + /// Formatted text, or null if not implemented. + string? DebugDump(); } } diff --git a/DiskArc/IFileSystem.cs b/DiskArc/IFileSystem.cs index 13df2f0..884331a 100644 --- a/DiskArc/IFileSystem.cs +++ b/DiskArc/IFileSystem.cs @@ -399,5 +399,11 @@ enum FileAccessMode { /// Closes all open files. /// void CloseAll(); + + /// + /// Generates detailed human-readable information about the filesystem. + /// + /// Formatted text, or null if not implemented. + string? DebugDump(); } } diff --git a/cp2/CP2Main.cs b/cp2/CP2Main.cs index ed1d8b8..7bf6852 100644 --- a/cp2/CP2Main.cs +++ b/cp2/CP2Main.cs @@ -247,11 +247,16 @@ public Command(string[] names, string summary, string usage, bool needsArchive, usage: "", needsArchive: false, acceptsMultipleArgs: false, handler: HandleCrash), + new Command(names: new string[] { "debug-show-info" }, + summary: "displays detailed archive-specific information", + usage: "", + needsArchive: true, acceptsMultipleArgs: false, + handler: DebugCmd.HandleShowInfo), new Command(names: new string[] { "debug-wtree" }, summary: "displays work tree for an archive", usage: "", needsArchive: true, acceptsMultipleArgs: false, - handler: Tests.DebugWorkTree.HandleDumpTree), + handler: DebugCmd.HandleDumpWTree), new Command(names: new string[] { "debug-test" }, summary: "executes program tests", usage: "", diff --git a/cp2/Tests/DebugWorkTree.cs b/cp2/DebugCmd.cs similarity index 56% rename from cp2/Tests/DebugWorkTree.cs rename to cp2/DebugCmd.cs index d0d8832..9a21571 100644 --- a/cp2/Tests/DebugWorkTree.cs +++ b/cp2/DebugCmd.cs @@ -17,29 +17,90 @@ using System.Diagnostics; using AppCommon; -using CommonUtil; +using DiskArc.Arc; +using DiskArc.Multi; using DiskArc; using static AppCommon.WorkTree; -namespace cp2.Tests { - public static class DebugWorkTree { +namespace cp2 { + public static class DebugCmd { /// - /// Handles "debug-wtree" command. + /// Handles "debug-show-info" command. /// - public static bool HandleDumpTree(string cmdName, string[] args, ParamsBag parms) { + public static bool HandleShowInfo(string cmdName, string[] args, ParamsBag parms) { + Debug.Assert(args.Length == 1); + if (!ExtArchive.OpenExtArc(args[0], false, true, parms, out DiskArcNode? rootNode, + out DiskArcNode? leafNode, out object? leaf, out IFileEntry endDirEntry)) { + return false; + } + Debug.Assert(rootNode != null && leaf != null); + + using (rootNode) { + string? hdrStr = null; + string? outStr = null; + if (leaf is IArchive) { + IArchive archive = (IArchive)leaf; + hdrStr = "--- " + ThingString.IArchive(archive) + " ---"; + outStr = archive.DebugDump(); + } else if (leaf is IDiskImage) { + IDiskImage disk = (IDiskImage)leaf; + if (disk.Contents is IFileSystem) { + IFileSystem fs = (IFileSystem)disk.Contents; + hdrStr = "--- " + ThingString.IFileSystem(fs) + " ---"; + outStr = fs.DebugDump(); + } else if (disk.Contents is IMultiPart) { + outStr = "No info available for multi-part filesystem."; + } else { + Console.Error.WriteLine("Error: disk image contents not recognized"); + return false; + } + } else if (leaf is Partition) { + Partition part = (Partition)leaf; + if (part.FileSystem == null) { + part.AnalyzePartition(); + } + if (part.FileSystem != null) { + hdrStr = "--- " + ThingString.IFileSystem(part.FileSystem) + " ---"; + outStr = part.FileSystem.DebugDump(); + } else { + outStr = "Partition has unknown contents."; + } + } else { + Console.Error.WriteLine("Internal issue: what is " + leaf); + Debug.Assert(false); + return false; + } + if (hdrStr != null) { + Console.WriteLine(hdrStr); + } + if (outStr != null) { + Console.WriteLine(outStr); + } else { + Console.WriteLine("Debug info not available."); + } + return true; + } + } + + + /// + /// Handles "debug-wtree" command. This displays the WorkTree structure, which is + /// only used by the GUI app. + /// + public static bool HandleDumpWTree(string cmdName, string[] args, ParamsBag parms) { if (args.Length != 1) { CP2Main.ShowUsage(cmdName); return false; } - string extArchive = args[0]; + string fileName = args[0]; // not processing ext-archive strings // Include the config parameters in the closure. DepthLimiter limiter = delegate (DepthParentKind parentKind, DepthChildKind childKind) { return DepthLimit(parentKind, childKind, parms.Depth); - }; - using (WorkTree tree = new WorkTree(extArchive, limiter, true, null, parms.AppHook)) { + }; + using (WorkTree tree = new WorkTree(fileName, limiter, true, null, parms.AppHook)) { Console.Write(tree.GenerateTreeSummary()); }