From 106bc3cd51c7334b0a66abdb9c9aba539bf202c2 Mon Sep 17 00:00:00 2001 From: Deterous <138427222+Deterous@users.noreply.github.com> Date: Thu, 21 May 2026 09:51:01 +0900 Subject: [PATCH 1/6] Recursive InfoPrint for XDVDFS / XboxISO --- InfoPrint/Features/MainFeature.cs | 8 +++-- SabreTools.Wrappers/XDVDFS.Printing.cs | 42 ++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/InfoPrint/Features/MainFeature.cs b/InfoPrint/Features/MainFeature.cs index 43d3c8072..388f31899 100644 --- a/InfoPrint/Features/MainFeature.cs +++ b/InfoPrint/Features/MainFeature.cs @@ -38,6 +38,9 @@ internal sealed class MainFeature : Feature private const string _jsonName = "json"; internal readonly FlagInput JsonInput = new(_jsonName, ["-j", "--json"], "Print info as JSON"); + private const string _recursiveName = "recursive"; + internal readonly FlagInput RecursiveInput = new(_recursiveName, ["-r", "--recursive"], "Recursively print info from embedded files"); + #endregion /// @@ -74,6 +77,7 @@ public MainFeature() Add(HashInput); Add(FileOnlyInput); Add(JsonInput); + Add(RecursiveInput); } /// @@ -84,9 +88,7 @@ public override bool Execute() Hash = GetBoolean(_hashName); FileOnly = GetBoolean(_fileOnlyName); Json = GetBoolean(_jsonName); - - // TODO: Add flag for this once there are examples of it - Recursive = false; + Recursive = GetBoolean(_recursiveName); // Loop through the input paths for (int i = 0; i < Inputs.Count; i++) diff --git a/SabreTools.Wrappers/XDVDFS.Printing.cs b/SabreTools.Wrappers/XDVDFS.Printing.cs index f6a58ef7f..2ad32d127 100644 --- a/SabreTools.Wrappers/XDVDFS.Printing.cs +++ b/SabreTools.Wrappers/XDVDFS.Printing.cs @@ -1,6 +1,10 @@ using System; +using System.Collections.Generic; +using System.IO; using System.Text; using SabreTools.Data.Models.XDVDFS; +using SabreTools.IO.Extensions; +using SabreTools.Numerics.Extensions; using SabreTools.Text.Extensions; namespace SabreTools.Wrappers @@ -28,9 +32,34 @@ public void PrintInformation(StringBuilder builder, bool recursive) if (Model.LayoutDescriptor is not null) Print(builder, Model.LayoutDescriptor); + List subFiles = []; foreach (var kvp in Model.DirectoryDescriptors) { - Print(builder, kvp.Value, kvp.Key); + var files = Print(builder, kvp.Value, kvp.Key); + if (recursive) + subFiles.AddRange(files); + } + + if (recursive) + { + long initialOffset = _dataSource.Position; + foreach (DirectoryRecord dr in subFiles) + { + // Parse embedded file + _dataSource.Seek(initialOffset + Constants.SectorSize * dr.ExtentOffset, SeekOrigin.Begin); + byte[] magic = _dataSource.PeekBytes(16); + string filename = Encoding.UTF8.GetString(dr.Filename); + string extension = Path.GetExtension(filename).TrimStart('.'); + WrapperType ft = WrapperFactory.GetFileType(magic, extension); + var wrapper = WrapperFactory.CreateWrapper(ft, _dataSource); + if (wrapper is null || wrapper is not IPrintable printable) + continue; + + // Print info for embedded file + builder.AppendLine($"Information for {filename}"); + builder.AppendLine("-------------------------"); + printable.PrintInformation(builder, recursive); + } } } @@ -91,14 +120,21 @@ private static string GetVersionString(FourPartVersionType ver) return $"{ver.Major}.{ver.Minor}.{ver.Build}.{ver.Revision}"; } - internal static void Print(StringBuilder builder, DirectoryDescriptor dd, uint sectorNumber) + internal static List Print(StringBuilder builder, DirectoryDescriptor dd, uint sectorNumber) { builder.AppendLine($" Directory Descriptor (Sector {sectorNumber}):"); builder.AppendLine(" -------------------------"); + List files = []; foreach (DirectoryRecord dr in dd.DirectoryRecords) + { Print(builder, dr); + // Append files to queue for recursive printing + if ((dr.FileFlags & FileFlags.DIRECTORY) != FileFlags.DIRECTORY) + files.Add(dr); + } + if (dd.Padding is null) builder.AppendLine("None", " Padding"); else if (Array.TrueForAll(dd.Padding, b => b == 0xFF)) @@ -107,6 +143,8 @@ internal static void Print(StringBuilder builder, DirectoryDescriptor dd, uint s builder.AppendLine("Not all 0xFF", " Padding"); builder.AppendLine(); + + return files; } private static void Print(StringBuilder builder, DirectoryRecord dr) From 753e1e4d4248ecc9ad195e5f332fbb3cdafa06dc Mon Sep 17 00:00:00 2001 From: Deterous <138427222+Deterous@users.noreply.github.com> Date: Thu, 21 May 2026 10:40:30 +0900 Subject: [PATCH 2/6] Cleanup, full file paths --- SabreTools.Wrappers/XDVDFS.Printing.cs | 60 +++++++++++++------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/SabreTools.Wrappers/XDVDFS.Printing.cs b/SabreTools.Wrappers/XDVDFS.Printing.cs index 2ad32d127..cf099e49d 100644 --- a/SabreTools.Wrappers/XDVDFS.Printing.cs +++ b/SabreTools.Wrappers/XDVDFS.Printing.cs @@ -32,34 +32,45 @@ public void PrintInformation(StringBuilder builder, bool recursive) if (Model.LayoutDescriptor is not null) Print(builder, Model.LayoutDescriptor); - List subFiles = []; foreach (var kvp in Model.DirectoryDescriptors) { - var files = Print(builder, kvp.Value, kvp.Key); - if (recursive) - subFiles.AddRange(files); + Print(builder, kvp.Value, kvp.Key); } if (recursive) { long initialOffset = _dataSource.Position; - foreach (DirectoryRecord dr in subFiles) + RecursivePrint(builder, Model.VolumeDescriptor.RootOffset, "\\", initialOffset); + } + } + + private void RecursivePrint(StringBuilder builder, uint sectorNumber, string filePath, long initialOffset) + { + foreach (DirectoryRecord dr in Model.DirectoryDescriptors[sectorNumber].DirectoryRecords) + { + string filename = Encoding.UTF8.GetString(dr.Filename); + string path = Path.Combine(filePath, filename); + + // Recurse into directory + if ((dr.FileFlags & FileFlags.DIRECTORY) == FileFlags.DIRECTORY) { - // Parse embedded file - _dataSource.Seek(initialOffset + Constants.SectorSize * dr.ExtentOffset, SeekOrigin.Begin); - byte[] magic = _dataSource.PeekBytes(16); - string filename = Encoding.UTF8.GetString(dr.Filename); - string extension = Path.GetExtension(filename).TrimStart('.'); - WrapperType ft = WrapperFactory.GetFileType(magic, extension); - var wrapper = WrapperFactory.CreateWrapper(ft, _dataSource); - if (wrapper is null || wrapper is not IPrintable printable) - continue; - - // Print info for embedded file - builder.AppendLine($"Information for {filename}"); - builder.AppendLine("-------------------------"); - printable.PrintInformation(builder, recursive); + RecursivePrint(builder, dr.ExtentOffset, path, initialOffset); + continue; } + + // Parse embedded file + _dataSource.Seek(initialOffset + Constants.SectorSize * dr.ExtentOffset, SeekOrigin.Begin); + byte[] magic = _dataSource.PeekBytes(16); + string extension = Path.GetExtension(filename).TrimStart('.'); + WrapperType ft = WrapperFactory.GetFileType(magic, extension); + var wrapper = WrapperFactory.CreateWrapper(ft, _dataSource); + if (wrapper is null || wrapper is not IPrintable printable) + continue; + + // Print info for embedded file + builder.AppendLine($"Information for {path}"); + builder.AppendLine("-------------------------"); + printable.PrintInformation(builder, true); } } @@ -120,21 +131,14 @@ private static string GetVersionString(FourPartVersionType ver) return $"{ver.Major}.{ver.Minor}.{ver.Build}.{ver.Revision}"; } - internal static List Print(StringBuilder builder, DirectoryDescriptor dd, uint sectorNumber) + internal static void Print(StringBuilder builder, DirectoryDescriptor dd, uint sectorNumber) { builder.AppendLine($" Directory Descriptor (Sector {sectorNumber}):"); builder.AppendLine(" -------------------------"); - List files = []; foreach (DirectoryRecord dr in dd.DirectoryRecords) - { Print(builder, dr); - // Append files to queue for recursive printing - if ((dr.FileFlags & FileFlags.DIRECTORY) != FileFlags.DIRECTORY) - files.Add(dr); - } - if (dd.Padding is null) builder.AppendLine("None", " Padding"); else if (Array.TrueForAll(dd.Padding, b => b == 0xFF)) @@ -143,8 +147,6 @@ internal static List Print(StringBuilder builder, DirectoryDesc builder.AppendLine("Not all 0xFF", " Padding"); builder.AppendLine(); - - return files; } private static void Print(StringBuilder builder, DirectoryRecord dr) From 81914c2363fea1aab8a1ee62055739781fb98ce4 Mon Sep 17 00:00:00 2001 From: Deterous <138427222+Deterous@users.noreply.github.com> Date: Thu, 21 May 2026 12:45:42 +0900 Subject: [PATCH 3/6] Add safety --- SabreTools.Wrappers/XDVDFS.Printing.cs | 33 +++++++++++++++++--------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/SabreTools.Wrappers/XDVDFS.Printing.cs b/SabreTools.Wrappers/XDVDFS.Printing.cs index cf099e49d..7d5507ccf 100644 --- a/SabreTools.Wrappers/XDVDFS.Printing.cs +++ b/SabreTools.Wrappers/XDVDFS.Printing.cs @@ -46,6 +46,9 @@ public void PrintInformation(StringBuilder builder, bool recursive) private void RecursivePrint(StringBuilder builder, uint sectorNumber, string filePath, long initialOffset) { + if (!Model.DirectoryDescriptors.ContainsKey(sectorNumber)) + return; + foreach (DirectoryRecord dr in Model.DirectoryDescriptors[sectorNumber].DirectoryRecords) { string filename = Encoding.UTF8.GetString(dr.Filename); @@ -59,18 +62,26 @@ private void RecursivePrint(StringBuilder builder, uint sectorNumber, string fil } // Parse embedded file - _dataSource.Seek(initialOffset + Constants.SectorSize * dr.ExtentOffset, SeekOrigin.Begin); - byte[] magic = _dataSource.PeekBytes(16); - string extension = Path.GetExtension(filename).TrimStart('.'); - WrapperType ft = WrapperFactory.GetFileType(magic, extension); - var wrapper = WrapperFactory.CreateWrapper(ft, _dataSource); - if (wrapper is null || wrapper is not IPrintable printable) + try + { + _dataSource.Seek(initialOffset + Constants.SectorSize * dr.ExtentOffset, SeekOrigin.Begin); + byte[] magic = _dataSource.PeekBytes(16); + string extension = Path.GetExtension(filename).TrimStart('.'); + WrapperType ft = WrapperFactory.GetFileType(magic, extension); + var wrapper = WrapperFactory.CreateWrapper(ft, _dataSource); + if (wrapper is null || wrapper is not IPrintable printable) + continue; + + // Print info for embedded file + builder.AppendLine($"Information for {path}"); + builder.AppendLine("-------------------------"); + printable.PrintInformation(builder, true); + } + catch + { + // Ignore the actual error continue; - - // Print info for embedded file - builder.AppendLine($"Information for {path}"); - builder.AppendLine("-------------------------"); - printable.PrintInformation(builder, true); + } } } From deb2cb631151814d0996105e5b9859b2e855892c Mon Sep 17 00:00:00 2001 From: Deterous <138427222+Deterous@users.noreply.github.com> Date: Thu, 21 May 2026 15:02:14 +0900 Subject: [PATCH 4/6] Recursive ISO9660 printing --- SabreTools.Wrappers/ISO9660.Extraction.cs | 13 +- SabreTools.Wrappers/ISO9660.Printing.cs | 157 ++++++++++++++++++++++ SabreTools.Wrappers/XDVDFS.Printing.cs | 20 +++ 3 files changed, 184 insertions(+), 6 deletions(-) diff --git a/SabreTools.Wrappers/ISO9660.Extraction.cs b/SabreTools.Wrappers/ISO9660.Extraction.cs index 3e29afb11..da5f0d707 100644 --- a/SabreTools.Wrappers/ISO9660.Extraction.cs +++ b/SabreTools.Wrappers/ISO9660.Extraction.cs @@ -127,8 +127,9 @@ private bool ExtractExtent(int extentLocation, Encoding encoding, int blockLengt succeeded &= ExtractFile(dr, encoding, blockLength, false, outputDirectory, includeDebug); // Also extract from BigEndian values if ambiguous - if (!dr.ExtentLocation.IsValid) - succeeded &= ExtractFile(dr, encoding, blockLength, true, outputDirectory, includeDebug); + // TODO: How to treat files with same name but different location? + // if (!dr.ExtentLocation.IsValid) + // succeeded &= ExtractFile(dr, encoding, blockLength, true, outputDirectory, includeDebug); } } @@ -151,7 +152,7 @@ private bool ExtractFile(DirectoryRecord dr, Encoding encoding, int blockLength, int extentLocation = bigEndian ? dr.ExtentLocation.BigEndian : dr.ExtentLocation.LittleEndian; // Check that the file hasn't been extracted already - if (extractedFiles.ContainsKey(dr.ExtentLocation)) + if (extractedFiles.ContainsKey(extentLocation)) return true; // TODO: Decode properly (Use VD's separator characters and encoding) @@ -183,7 +184,7 @@ private bool ExtractFile(DirectoryRecord dr, Encoding encoding, int blockLength, else if (dr.FileUnitSize != 0 || dr.InterleaveGapSize != 0) { Console.WriteLine($"Extraction of interleaved files is currently not supported: {filename}"); - extractedFiles.Add(dr.ExtentLocation, dr.ExtentLength); + extractedFiles.Add(extentLocation, dr.ExtentLength); return false; } @@ -201,7 +202,7 @@ private bool ExtractFile(DirectoryRecord dr, Encoding encoding, int blockLength, const uint chunkSize = 2048 * 1024; lock (_dataSourceLock) { - long fileOffset = ((long)dr.ExtentLocation + dr.ExtendedAttributeRecordLength) * blockLength; + long fileOffset = ((long)extentLocation + dr.ExtendedAttributeRecordLength) * blockLength; _dataSource.SeekIfPossible(fileOffset, SeekOrigin.Begin); // Get the length, and make sure it won't EOF @@ -224,7 +225,7 @@ private bool ExtractFile(DirectoryRecord dr, Encoding encoding, int blockLength, } // Mark the file as extracted - extractedFiles.Add(dr.ExtentLocation, dr.ExtentLength); + extractedFiles.Add(extentLocation, dr.ExtentLength); } return true; diff --git a/SabreTools.Wrappers/ISO9660.Printing.cs b/SabreTools.Wrappers/ISO9660.Printing.cs index b7cc763f2..508a8e6a5 100644 --- a/SabreTools.Wrappers/ISO9660.Printing.cs +++ b/SabreTools.Wrappers/ISO9660.Printing.cs @@ -1,7 +1,11 @@ using System; using System.Collections.Generic; +using System.IO; using System.Text; +using SabreTools.Data.Extensions; using SabreTools.Data.Models.ISO9660; +using SabreTools.IO.Extensions; +using SabreTools.Matching; using SabreTools.Numerics.Extensions; using SabreTools.Text.Extensions; @@ -9,6 +13,15 @@ namespace SabreTools.Wrappers { public partial class ISO9660 : IPrintable { + #region Printing State + + /// + /// List of printed embedded files by their sector offset + /// + private readonly HashSet printedFiles = []; + + #endregion + #if NETCOREAPP /// public string ExportJSON(bool recursive) => System.Text.Json.JsonSerializer.Serialize(Model, _jsonSerializerOptions); @@ -20,6 +33,8 @@ public partial class ISO9660 : IPrintable /// public void PrintInformation(StringBuilder builder, bool recursive) { + printedFiles.Clear(); + builder.AppendLine("ISO 9660 Information:"); builder.AppendLine("-------------------------"); builder.AppendLine(); @@ -32,6 +47,148 @@ public void PrintInformation(StringBuilder builder, bool recursive) Encoding encoding = Encoding.UTF8; Print(builder, Model.PathTableGroups); Print(builder, Model.DirectoryDescriptors, encoding); + + if (recursive) + { + long initialOffset = _dataSource.Position; + + // Determine and validate sector length, default to 2048 + short sectorLength = (short)(Model.SystemArea.Length / 16); + if (sectorLength < 2048 || (sectorLength & (sectorLength - 1)) != 0) + sectorLength = 2048; + + // Loop through all Volume Descriptors to print files from each directory hierarchy + // Note: This will prioritize the last volume descriptor directory hierarchies first (prioritises those filenames) + // This is useful as the Unicode filenames are in the + for (int i = VolumeDescriptorSet.Length - 1; i >= 0; i--) + { + var vd = VolumeDescriptorSet[i]; + + DirectoryRecord rootDirectoryRecord; + if (vd is PrimaryVolumeDescriptor pvd) + rootDirectoryRecord = pvd.RootDirectoryRecord; + else if (vd is SupplementaryVolumeDescriptor svd) + rootDirectoryRecord = svd.RootDirectoryRecord; + else + continue; + + var blockLength = vd.GetLogicalBlockSize(sectorLength); + + // TODO: Better encoding detection (EscapeSequences) + encoding = Encoding.UTF8; + if (vd is SupplementaryVolumeDescriptor) + encoding = Encoding.BigEndianUnicode; + + RecursivePrint(builder, rootDirectoryRecord.ExtentLocation.LittleEndian, "\\", encoding, blockLength, initialOffset); + if (!rootDirectoryRecord.ExtentLocation.IsValid) + RecursivePrint(builder, rootDirectoryRecord.ExtentLocation.BigEndian, "\\", encoding, blockLength, initialOffset); + } + } + } + + private void RecursivePrint(StringBuilder builder, int sectorNumber, string filePath, Encoding encoding, short blockLength, long initialOffset) + { + // Check that directory exists in model + if (!Model.DirectoryDescriptors.TryGetValue(sectorNumber, out FileExtent? value)) + return; + + // Expect a directory + if (value is not DirectoryExtent dir) + return; + + foreach (var dr in dir.DirectoryRecords) + { + string filename = encoding.GetString(dr.FileIdentifier); + string path = Path.Combine(filePath, filename); + + // Recurse if record is directory +#if NET20 || NET35 + if ((dr.FileFlags & FileFlags.DIRECTORY) != 0) +#else + if (dr.FileFlags.HasFlag(FileFlags.DIRECTORY)) +#endif + { + // Don't recurse up or self + if (dr.FileIdentifier.EqualsExactly(Constants.CurrentDirectory) || dr.FileIdentifier.EqualsExactly(Constants.ParentDirectory)) + continue; + + // Add extent before recursion + if (!printedFiles.Contains(dr.ExtentLocation.LittleEndian)) + { + printedFiles.Add(dr.ExtentLocation.LittleEndian); + RecursivePrint(builder, dr.ExtentLocation.LittleEndian, path, encoding, blockLength, initialOffset); + } + + if (!dr.ExtentLocation.IsValid && !printedFiles.Contains(dr.ExtentLocation.BigEndian)) + { + printedFiles.Add(dr.ExtentLocation.BigEndian); + RecursivePrint(builder, dr.ExtentLocation.BigEndian, path, encoding, blockLength, initialOffset); + } + } + else + { + // Skip multi-extent and interleaved files + if ((dr.FileFlags & FileFlags.MULTI_EXTENT) != 0 || dr.FileUnitSize != 0 || dr.InterleaveGapSize != 0) + continue; + + // Print embedded file from LittleEndian location + if (!printedFiles.Contains(dr.ExtentLocation.LittleEndian)) + { + try + { + long offset = initialOffset + ((long)dr.ExtentLocation.LittleEndian + (long)dr.ExtendedAttributeRecordLength) * (long)blockLength; + var wrapper = GetFileWrapper(offset, filename); + if (wrapper is not null && wrapper is IPrintable printable) + { + // Print info for embedded file + builder.AppendLine($"Information for {path}"); + builder.AppendLine("-------------------------"); + printable.PrintInformation(builder, true); + + printedFiles.Add(dr.ExtentLocation.LittleEndian); + } + } + catch + { + // Ignore the actual error + continue; + } + } + + // Print embedded file from BigEndian location + if (!dr.ExtentLocation.IsValid && !printedFiles.Contains(dr.ExtentLocation.BigEndian)) + { + try + { + long offset = initialOffset + (dr.ExtentLocation.BigEndian + dr.ExtendedAttributeRecordLength) * blockLength; + var wrapper = GetFileWrapper(offset, filename); + if (wrapper is not null && wrapper is IPrintable printable) + { + // Print info for embedded file + builder.AppendLine($"Information for {path}"); + builder.AppendLine("-------------------------"); + printable.PrintInformation(builder, true); + + printedFiles.Add(dr.ExtentLocation.BigEndian); + } + } + catch + { + // Ignore the actual error + continue; + } + } + } + } + } + + private IWrapper? GetFileWrapper(long offset, string filename) + { + _dataSource.Seek(offset, SeekOrigin.Begin); + byte[] magic = _dataSource.PeekBytes(16); + string extension = Path.GetExtension(filename).TrimStart('.'); + WrapperType ft = WrapperFactory.GetFileType(magic, extension); + return WrapperFactory.CreateWrapper(ft, _dataSource); } protected static void Print(StringBuilder builder, byte[] systemArea) diff --git a/SabreTools.Wrappers/XDVDFS.Printing.cs b/SabreTools.Wrappers/XDVDFS.Printing.cs index 7d5507ccf..70a502178 100644 --- a/SabreTools.Wrappers/XDVDFS.Printing.cs +++ b/SabreTools.Wrappers/XDVDFS.Printing.cs @@ -11,6 +11,15 @@ namespace SabreTools.Wrappers { public partial class XDVDFS : IPrintable { + #region Printing State + + /// + /// List of printed embedded files by their sector offset + /// + private readonly HashSet printedFiles = []; + + #endregion + #if NETCOREAPP /// public string ExportJSON(bool recursive) => System.Text.Json.JsonSerializer.Serialize(Model, _jsonSerializerOptions); @@ -22,6 +31,8 @@ public partial class XDVDFS : IPrintable /// public void PrintInformation(StringBuilder builder, bool recursive) { + printedFiles.Clear(); + builder.AppendLine("Xbox DVD Filesystem Information:"); builder.AppendLine("-------------------------"); builder.AppendLine(); @@ -54,9 +65,16 @@ private void RecursivePrint(StringBuilder builder, uint sectorNumber, string fil string filename = Encoding.UTF8.GetString(dr.Filename); string path = Path.Combine(filePath, filename); + // Skip already printed files + if (printedFiles.Contains(dr.ExtentOffset)) + continue; + // Recurse into directory if ((dr.FileFlags & FileFlags.DIRECTORY) == FileFlags.DIRECTORY) { + // Add directory extent before recursing + printedFiles.Add(dr.ExtentOffset); + RecursivePrint(builder, dr.ExtentOffset, path, initialOffset); continue; } @@ -76,6 +94,8 @@ private void RecursivePrint(StringBuilder builder, uint sectorNumber, string fil builder.AppendLine($"Information for {path}"); builder.AppendLine("-------------------------"); printable.PrintInformation(builder, true); + + printedFiles.Add(dr.ExtentOffset); } catch { From 912a5313e34c6f089602c29c6f2cabaea81892a0 Mon Sep 17 00:00:00 2001 From: Deterous <138427222+Deterous@users.noreply.github.com> Date: Thu, 21 May 2026 15:57:08 +0900 Subject: [PATCH 5/6] Naive decode filename --- SabreTools.Wrappers/ISO9660.Printing.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/SabreTools.Wrappers/ISO9660.Printing.cs b/SabreTools.Wrappers/ISO9660.Printing.cs index 508a8e6a5..cea438253 100644 --- a/SabreTools.Wrappers/ISO9660.Printing.cs +++ b/SabreTools.Wrappers/ISO9660.Printing.cs @@ -325,7 +325,7 @@ private static void Print(StringBuilder builder, BaseVolumeDescriptor vd) builder.AppendLine(vd.OptionalPathTableLocationM, " Optional Type-M Path Table Location"); builder.AppendLine(" Root Directory Record:"); - Print(builder, vd.RootDirectoryRecord); + Print(builder, vd.RootDirectoryRecord, encoding); builder.AppendLine(encoding.GetString(vd.VolumeSetIdentifier), " Volume Set Identifier"); builder.AppendLine(encoding.GetString(vd.PublisherIdentifier), " Publisher Identifier"); @@ -542,7 +542,7 @@ private static void Print(StringBuilder builder, FileExtent extent, Encoding enc { builder.AppendLine($" Directory Record {recordNum}:"); builder.AppendLine(" -------------------------"); - Print(builder, dir.DirectoryRecords[recordNum]); + Print(builder, dir.DirectoryRecords[recordNum], encoding); builder.AppendLine(); } } @@ -555,7 +555,7 @@ private static void Print(StringBuilder builder, FileExtent extent, Encoding enc builder.AppendLine(); } - private static void Print(StringBuilder builder, DirectoryRecord dr) + private static void Print(StringBuilder builder, DirectoryRecord dr, Encoding encoding) { builder.AppendLine(dr.DirectoryRecordLength, " Directory Record Length"); builder.AppendLine(dr.ExtendedAttributeRecordLength, " Extended Attribute Record Length"); @@ -582,6 +582,9 @@ private static void Print(StringBuilder builder, DirectoryRecord dr) builder.AppendLine(dr.FileIdentifierLength, " File Identifier Length"); builder.AppendLine(dr.FileIdentifier, " File Identifier"); + if (dr.FileIdentifier is not null && dr.FileIdentifier.Length > 0) + builder.AppendLine(encoding.GetString(dr.FileIdentifier), " File Identifier (Decoded)"); + builder.AppendLine(dr.PaddingField, " Padding Field"); if (dr.SystemUse.Length == 0) From 8c3806e6190e36321260f5ce9a33d4a8bcf81135 Mon Sep 17 00:00:00 2001 From: Deterous <138427222+Deterous@users.noreply.github.com> Date: Thu, 21 May 2026 22:30:14 +0900 Subject: [PATCH 6/6] comment --- SabreTools.Wrappers/ISO9660.Printing.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SabreTools.Wrappers/ISO9660.Printing.cs b/SabreTools.Wrappers/ISO9660.Printing.cs index cea438253..8eb5546b2 100644 --- a/SabreTools.Wrappers/ISO9660.Printing.cs +++ b/SabreTools.Wrappers/ISO9660.Printing.cs @@ -59,7 +59,7 @@ public void PrintInformation(StringBuilder builder, bool recursive) // Loop through all Volume Descriptors to print files from each directory hierarchy // Note: This will prioritize the last volume descriptor directory hierarchies first (prioritises those filenames) - // This is useful as the Unicode filenames are in the + // This is useful as ASCII filenames are usually in the first VD for (int i = VolumeDescriptorSet.Length - 1; i >= 0; i--) { var vd = VolumeDescriptorSet[i];