Add support for byte addressable images to detection.

This commit is contained in:
2021-11-14 03:52:44 +00:00
parent 3f6fd587a1
commit 5e733abc8f
22 changed files with 2872 additions and 2842 deletions

View File

@@ -636,7 +636,7 @@ namespace Aaru.Core.Devices.Dumping
UpdateStatus?.Invoke("Creating sidecar.");
var filters = new FiltersList();
IFilter filter = filters.GetFilter(_outputPath);
IMediaImage inputPlugin = ImageFormat.Detect(filter);
IMediaImage inputPlugin = ImageFormat.Detect(filter) as IMediaImage;
ErrorNumber opened = inputPlugin.Open(filter);
if(opened != ErrorNumber.NoError)

View File

@@ -62,7 +62,7 @@ namespace Aaru.Core.Devices.Dumping
_dumpLog.WriteLine("Creating sidecar.");
var filters = new FiltersList();
IFilter filter = filters.GetFilter(_outputPath);
IMediaImage inputPlugin = ImageFormat.Detect(filter);
IMediaImage inputPlugin = ImageFormat.Detect(filter) as IMediaImage;
totalChkDuration = 0;
ErrorNumber opened = inputPlugin.Open(filter);

View File

@@ -693,7 +693,7 @@ namespace Aaru.Core.Devices.Dumping
_dumpLog.WriteLine("Creating sidecar.");
var filters = new FiltersList();
IFilter filter = filters.GetFilter(_outputPath);
IMediaImage inputPlugin = ImageFormat.Detect(filter);
IMediaImage inputPlugin = ImageFormat.Detect(filter) as IMediaImage;
ErrorNumber opened = inputPlugin.Open(filter);
if(opened != ErrorNumber.NoError)

View File

@@ -561,7 +561,7 @@ namespace Aaru.Core.Devices.Dumping
_dumpLog.WriteLine("Creating sidecar.");
var filters = new FiltersList();
IFilter filter = filters.GetFilter(_outputPath);
IMediaImage inputPlugin = ImageFormat.Detect(filter);
IMediaImage inputPlugin = ImageFormat.Detect(filter) as IMediaImage;
ErrorNumber opened = inputPlugin.Open(filter);
if(opened != ErrorNumber.NoError)

View File

@@ -1314,7 +1314,7 @@ namespace Aaru.Core.Devices.Dumping
_dumpLog.WriteLine("Creating sidecar.");
var filters = new FiltersList();
IFilter filter = filters.GetFilter(_outputPath);
IMediaImage inputPlugin = ImageFormat.Detect(filter);
IMediaImage inputPlugin = ImageFormat.Detect(filter) as IMediaImage;
ErrorNumber opened = inputPlugin.Open(filter);
if(opened != ErrorNumber.NoError)

View File

@@ -985,7 +985,7 @@ namespace Aaru.Core.Devices.Dumping
_dumpLog.WriteLine("Creating sidecar.");
var filters = new FiltersList();
IFilter filter = filters.GetFilter(_outputPath);
IMediaImage inputPlugin = ImageFormat.Detect(filter);
IMediaImage inputPlugin = ImageFormat.Detect(filter) as IMediaImage;
ErrorNumber opened = inputPlugin.Open(filter);
if(opened != ErrorNumber.NoError)

View File

@@ -782,7 +782,7 @@ namespace Aaru.Core.Devices.Dumping
_dumpLog.WriteLine("Creating sidecar.");
var filters = new FiltersList();
IFilter filter = filters.GetFilter(_outputPath);
IMediaImage inputPlugin = ImageFormat.Detect(filter);
IMediaImage inputPlugin = ImageFormat.Detect(filter) as IMediaImage;
ErrorNumber opened = inputPlugin.Open(filter);
if(opened != ErrorNumber.NoError)

View File

@@ -36,72 +36,94 @@ using Aaru.CommonTypes;
using Aaru.CommonTypes.Interfaces;
using Aaru.Console;
namespace Aaru.Core
namespace Aaru.Core;
/// <summary>Core media image format operations</summary>
public static class ImageFormat
{
/// <summary>Core media image format operations</summary>
public static class ImageFormat
/// <summary>Detects the image plugin that recognizes the data inside a filter</summary>
/// <param name="imageFilter">Filter</param>
/// <returns>Detected image plugin</returns>
public static IBaseImage Detect(IFilter imageFilter)
{
/// <summary>Detects the image plugin that recognizes the data inside a filter</summary>
/// <param name="imageFilter">Filter</param>
/// <returns>Detected image plugin</returns>
public static IMediaImage Detect(IFilter imageFilter)
try
{
try
{
PluginBase plugins = GetPluginBase.Instance;
PluginBase plugins = GetPluginBase.Instance;
IMediaImage imageFormat = null;
IBaseImage imageFormat = null;
// Check all but RAW plugin
foreach(IMediaImage imagePlugin in plugins.ImagePluginsList.Values.Where(imagePlugin =>
imagePlugin.Id != new Guid("12345678-AAAA-BBBB-CCCC-123456789000")))
try
{
AaruConsole.DebugWriteLine("Format detection", "Trying plugin {0}", imagePlugin.Name);
// Check all but RAW plugin
foreach(IMediaImage imagePlugin in plugins.ImagePluginsList.Values.Where(imagePlugin =>
imagePlugin.Id != new Guid("12345678-AAAA-BBBB-CCCC-123456789000")))
try
{
AaruConsole.DebugWriteLine("Format detection", "Trying plugin {0}", imagePlugin.Name);
if(!imagePlugin.Identify(imageFilter))
continue;
if(!imagePlugin.Identify(imageFilter))
continue;
imageFormat = imagePlugin;
imageFormat = imagePlugin;
break;
}
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
catch
{
// ignored
}
break;
}
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
catch
{
// ignored
}
if(imageFormat != null)
return imageFormat;
// Check only RAW plugin
foreach(IMediaImage imagePlugin in plugins.ImagePluginsList.Values.Where(imagePlugin =>
imagePlugin.Id == new Guid("12345678-AAAA-BBBB-CCCC-123456789000")))
try
{
AaruConsole.DebugWriteLine("Format detection", "Trying plugin {0}", imagePlugin.Name);
if(!imagePlugin.Identify(imageFilter))
continue;
imageFormat = imagePlugin;
break;
}
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
catch
{
// ignored
}
// Still not recognized
if(imageFormat != null)
return imageFormat;
}
catch
{
return null;
}
// Check all but RAW plugin
foreach(IByteAddressableImage imagePlugin in plugins.ByteAddressableImages.Values.Where(imagePlugin =>
imagePlugin.Id != new Guid("12345678-AAAA-BBBB-CCCC-123456789000")))
try
{
AaruConsole.DebugWriteLine("Format detection", "Trying plugin {0}", imagePlugin.Name);
if(!imagePlugin.Identify(imageFilter))
continue;
imageFormat = imagePlugin;
break;
}
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
catch
{
// ignored
}
if(imageFormat != null)
return imageFormat;
// Check only RAW plugin
foreach(IMediaImage imagePlugin in plugins.ImagePluginsList.Values.Where(imagePlugin =>
imagePlugin.Id == new Guid("12345678-AAAA-BBBB-CCCC-123456789000")))
try
{
AaruConsole.DebugWriteLine("Format detection", "Trying plugin {0}", imagePlugin.Name);
if(!imagePlugin.Identify(imageFilter))
continue;
imageFormat = imagePlugin;
break;
}
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
catch
{
// ignored
}
// Still not recognized
return imageFormat;
}
catch
{
return null;
}
}
}

View File

@@ -523,7 +523,7 @@ namespace Aaru.Gui.ViewModels.Windows
try
{
IMediaImage imageFormat = ImageFormat.Detect(inputFilter);
IMediaImage imageFormat = ImageFormat.Detect(inputFilter) as IMediaImage;
if(imageFormat == null)
{

View File

@@ -47,7 +47,7 @@ namespace Aaru.Tests.Filesystems
Assert.IsNotNull(inputFilter, $"Filter: {testFile}");
IMediaImage image = ImageFormat.Detect(inputFilter);
IMediaImage image = ImageFormat.Detect(inputFilter) as IMediaImage;
Assert.IsNotNull(image, $"Image format: {testFile}");
@@ -123,7 +123,7 @@ namespace Aaru.Tests.Filesystems
Assert.IsNotNull(inputFilter, $"Filter: {testFile}");
IMediaImage image = ImageFormat.Detect(inputFilter);
IMediaImage image = ImageFormat.Detect(inputFilter) as IMediaImage;
Assert.IsNotNull(image, $"Image format: {testFile}");
@@ -162,7 +162,7 @@ namespace Aaru.Tests.Filesystems
Assert.IsNotNull(inputFilter, $"Filter: {testFile}");
IMediaImage image = ImageFormat.Detect(inputFilter);
IMediaImage image = ImageFormat.Detect(inputFilter) as IMediaImage;
Assert.IsNotNull(image, $"Image format: {testFile}");

View File

@@ -48,7 +48,7 @@ namespace Aaru.Tests.Filesystems
Assert.IsNotNull(inputFilter, $"Filter: {testFile}");
IMediaImage image = ImageFormat.Detect(inputFilter);
IMediaImage image = ImageFormat.Detect(inputFilter) as IMediaImage;
Assert.IsNotNull(image, $"Image format: {testFile}");
@@ -163,7 +163,7 @@ namespace Aaru.Tests.Filesystems
var filtersList = new FiltersList();
IFilter inputFilter = filtersList.GetFilter(testFile);
IMediaImage image = ImageFormat.Detect(inputFilter);
IMediaImage image = ImageFormat.Detect(inputFilter) as IMediaImage;
ErrorNumber opened = image.Open(inputFilter);
if(opened != ErrorNumber.NoError)

View File

@@ -48,7 +48,7 @@ namespace Aaru.Tests.Issues
PluginBase plugins = GetPluginBase.Instance;
IMediaImage imageFormat = ImageFormat.Detect(inputFilter);
IMediaImage imageFormat = ImageFormat.Detect(inputFilter) as IMediaImage;
Assert.NotNull(imageFormat, "Image format not identified, not proceeding with analysis.");

View File

@@ -42,7 +42,7 @@ namespace Aaru.Tests.Issues
PluginBase plugins = GetPluginBase.Instance;
IMediaImage imageFormat = ImageFormat.Detect(inputFilter);
IMediaImage imageFormat = ImageFormat.Detect(inputFilter) as IMediaImage;
Assert.NotNull(imageFormat, "Image format not identified, not proceeding with analysis.");

View File

@@ -29,7 +29,7 @@ namespace Aaru.Tests.Issues
Assert.IsNotNull(inputFilter, "Filter for test file is not detected");
IMediaImage image = ImageFormat.Detect(inputFilter);
IMediaImage image = ImageFormat.Detect(inputFilter) as IMediaImage;
Assert.IsNotNull(image, "Image format for test file is not detected");

View File

@@ -55,7 +55,7 @@ namespace Aaru.Tests.Issues
Assert.IsFalse(File.Exists(outputPath), "Output file already exists, not continuing.");
IMediaImage inputFormat = ImageFormat.Detect(inputFilter);
IMediaImage inputFormat = ImageFormat.Detect(inputFilter) as IMediaImage;
Assert.IsNotNull(inputFormat, "Input image format not identified, not proceeding with conversion.");

View File

@@ -31,7 +31,7 @@ namespace Aaru.Tests.Issues
Assert.IsNotNull(inputFilter, "Filter for test file is not detected");
IMediaImage image = ImageFormat.Detect(inputFilter);
IMediaImage image = ImageFormat.Detect(inputFilter) as IMediaImage;
Assert.IsNotNull(image, "Image format for test file is not detected");

View File

@@ -36,7 +36,7 @@ namespace Aaru.Tests.Partitions
Assert.IsNotNull(inputFilter, $"Filter: {testFile}");
IMediaImage image = ImageFormat.Detect(inputFilter);
IMediaImage image = ImageFormat.Detect(inputFilter) as IMediaImage;
Assert.IsNotNull(image, $"Image format: {testFile}");

File diff suppressed because it is too large Load Diff

View File

@@ -42,339 +42,345 @@ using Aaru.Console;
using Aaru.Core;
using Spectre.Console;
namespace Aaru.Commands.Filesystem
namespace Aaru.Commands.Filesystem;
internal sealed class FilesystemInfoCommand : Command
{
internal sealed class FilesystemInfoCommand : Command
public FilesystemInfoCommand() : base("info",
"Opens a disc image and prints info on the found partitions and/or filesystems.")
{
public FilesystemInfoCommand() : base("info",
"Opens a disc image and prints info on the found partitions and/or filesystems.")
{
Add(new Option(new[]
{
"--encoding", "-e"
}, "Name of character encoding to use.")
{
Argument = new Argument<string>(() => null),
Required = false
});
Add(new Option(new[]
{
"--filesystems", "-f"
}, "Searches and prints information about filesystems.")
{
Argument = new Argument<bool>(() => true),
Required = false
});
Add(new Option(new[]
{
"--partitions", "-p"
}, "Searches and interprets partitions.")
{
Argument = new Argument<bool>(() => true),
Required = false
});
AddArgument(new Argument<string>
Add(new Option(new[]
{
Arity = ArgumentArity.ExactlyOne,
Description = "Media image path",
Name = "image-path"
"--encoding", "-e"
}, "Name of character encoding to use.")
{
Argument = new Argument<string>(() => null),
Required = false
});
Handler = CommandHandler.Create(typeof(FilesystemInfoCommand).GetMethod(nameof(Invoke)));
Add(new Option(new[]
{
"--filesystems", "-f"
}, "Searches and prints information about filesystems.")
{
Argument = new Argument<bool>(() => true),
Required = false
});
Add(new Option(new[]
{
"--partitions", "-p"
}, "Searches and interprets partitions.")
{
Argument = new Argument<bool>(() => true),
Required = false
});
AddArgument(new Argument<string>
{
Arity = ArgumentArity.ExactlyOne,
Description = "Media image path",
Name = "image-path"
});
Handler = CommandHandler.Create(typeof(FilesystemInfoCommand).GetMethod(nameof(Invoke)));
}
public static int Invoke(bool verbose, bool debug, string encoding, bool filesystems, bool partitions,
string imagePath)
{
MainClass.PrintCopyright();
if(debug)
{
IAnsiConsole stderrConsole = AnsiConsole.Create(new AnsiConsoleSettings
{
Out = new AnsiConsoleOutput(System.Console.Error)
});
AaruConsole.DebugWriteLineEvent += (format, objects) =>
{
if(objects is null)
stderrConsole.MarkupLine(format);
else
stderrConsole.MarkupLine(format, objects);
};
}
public static int Invoke(bool verbose, bool debug, string encoding, bool filesystems, bool partitions,
string imagePath)
{
MainClass.PrintCopyright();
if(debug)
if(verbose)
AaruConsole.WriteEvent += (format, objects) =>
{
IAnsiConsole stderrConsole = AnsiConsole.Create(new AnsiConsoleSettings
{
Out = new AnsiConsoleOutput(System.Console.Error)
});
if(objects is null)
AnsiConsole.Markup(format);
else
AnsiConsole.Markup(format, objects);
};
AaruConsole.DebugWriteLineEvent += (format, objects) =>
{
if(objects is null)
stderrConsole.MarkupLine(format);
else
stderrConsole.MarkupLine(format, objects);
};
Statistics.AddCommand("fs-info");
AaruConsole.DebugWriteLine("Fs-info command", "--debug={0}", debug);
AaruConsole.DebugWriteLine("Fs-info command", "--encoding={0}", encoding);
AaruConsole.DebugWriteLine("Fs-info command", "--filesystems={0}", filesystems);
AaruConsole.DebugWriteLine("Fs-info command", "--input={0}", imagePath);
AaruConsole.DebugWriteLine("Fs-info command", "--partitions={0}", partitions);
AaruConsole.DebugWriteLine("Fs-info command", "--verbose={0}", verbose);
var filtersList = new FiltersList();
IFilter inputFilter = null;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying file filter...").IsIndeterminate();
inputFilter = filtersList.GetFilter(imagePath);
});
if(inputFilter == null)
{
AaruConsole.ErrorWriteLine("Cannot open specified file.");
return (int)ErrorNumber.CannotOpenFile;
}
Encoding encodingClass = null;
if(encoding != null)
try
{
encodingClass = Claunia.Encoding.Encoding.GetEncoding(encoding);
if(verbose)
AaruConsole.VerboseWriteLine("Using encoding for {0}.", encodingClass.EncodingName);
}
catch(ArgumentException)
{
AaruConsole.ErrorWriteLine("Specified encoding is not supported.");
return (int)ErrorNumber.EncodingUnknown;
}
if(verbose)
AaruConsole.WriteEvent += (format, objects) =>
{
if(objects is null)
AnsiConsole.Markup(format);
else
AnsiConsole.Markup(format, objects);
};
PluginBase plugins = GetPluginBase.Instance;
Statistics.AddCommand("fs-info");
bool checkRaw = false;
AaruConsole.DebugWriteLine("Fs-info command", "--debug={0}", debug);
AaruConsole.DebugWriteLine("Fs-info command", "--encoding={0}", encoding);
AaruConsole.DebugWriteLine("Fs-info command", "--filesystems={0}", filesystems);
AaruConsole.DebugWriteLine("Fs-info command", "--input={0}", imagePath);
AaruConsole.DebugWriteLine("Fs-info command", "--partitions={0}", partitions);
AaruConsole.DebugWriteLine("Fs-info command", "--verbose={0}", verbose);
var filtersList = new FiltersList();
IFilter inputFilter = null;
try
{
IMediaImage imageFormat = null;
IBaseImage baseImage = null;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying file filter...").IsIndeterminate();
inputFilter = filtersList.GetFilter(imagePath);
ctx.AddTask("Identifying image format...").IsIndeterminate();
baseImage = ImageFormat.Detect(inputFilter);
imageFormat = baseImage as IMediaImage;
});
if(inputFilter == null)
if(baseImage == null)
{
AaruConsole.ErrorWriteLine("Cannot open specified file.");
AaruConsole.WriteLine("Image format not identified, not proceeding with analysis.");
return (int)ErrorNumber.CannotOpenFile;
return (int)ErrorNumber.UnrecognizedFormat;
}
Encoding encodingClass = null;
if(imageFormat == null)
{
AaruConsole.WriteLine("Command not supported for this image type.");
if(encoding != null)
try
{
encodingClass = Claunia.Encoding.Encoding.GetEncoding(encoding);
return (int)ErrorNumber.InvalidArgument;
}
if(verbose)
AaruConsole.VerboseWriteLine("Using encoding for {0}.", encodingClass.EncodingName);
}
catch(ArgumentException)
{
AaruConsole.ErrorWriteLine("Specified encoding is not supported.");
if(verbose)
AaruConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name, imageFormat.Id);
else
AaruConsole.WriteLine("Image format identified by {0}.", imageFormat.Name);
return (int)ErrorNumber.EncodingUnknown;
}
PluginBase plugins = GetPluginBase.Instance;
bool checkRaw = false;
AaruConsole.WriteLine();
try
{
IMediaImage imageFormat = null;
ErrorNumber opened = ErrorNumber.NoData;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying image format...").IsIndeterminate();
imageFormat = ImageFormat.Detect(inputFilter);
ctx.AddTask("Opening image file...").IsIndeterminate();
opened = imageFormat.Open(inputFilter);
});
if(imageFormat == null)
if(opened != ErrorNumber.NoError)
{
AaruConsole.WriteLine("Image format not identified, not proceeding with analysis.");
AaruConsole.WriteLine("Unable to open image format");
AaruConsole.WriteLine("Error {0}", opened);
return (int)ErrorNumber.UnrecognizedFormat;
return (int)opened;
}
if(verbose)
AaruConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name,
imageFormat.Id);
{
ImageInfo.PrintImageInfo(imageFormat);
AaruConsole.WriteLine();
}
Statistics.AddMediaFormat(imageFormat.Format);
Statistics.AddMedia(imageFormat.Info.MediaType, false);
Statistics.AddFilter(inputFilter.Name);
}
catch(Exception ex)
{
AaruConsole.ErrorWriteLine("Unable to open image format");
AaruConsole.ErrorWriteLine("Error: {0}", ex.Message);
AaruConsole.DebugWriteLine("Fs-info command", "Stack trace: {0}", ex.StackTrace);
return (int)ErrorNumber.CannotOpenFormat;
}
List<string> idPlugins = null;
IFilesystem plugin;
string information;
if(partitions)
{
List<Partition> partitionsList = null;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Enumerating partitions...").IsIndeterminate();
partitionsList = Core.Partitions.GetAll(imageFormat);
});
Core.Partitions.AddSchemesToStats(partitionsList);
if(partitionsList.Count == 0)
{
AaruConsole.DebugWriteLine("Fs-info command", "No partitions found");
if(!filesystems)
{
AaruConsole.WriteLine("No partitions founds, not searching for filesystems");
return (int)ErrorNumber.NothingFound;
}
checkRaw = true;
}
else
AaruConsole.WriteLine("Image format identified by {0}.", imageFormat.Name);
AaruConsole.WriteLine();
try
{
ErrorNumber opened = ErrorNumber.NoData;
AaruConsole.WriteLine("{0} partitions found.", partitionsList.Count);
Core.Spectre.ProgressSingleSpinner(ctx =>
for(int i = 0; i < partitionsList.Count; i++)
{
ctx.AddTask("Opening image file...").IsIndeterminate();
opened = imageFormat.Open(inputFilter);
});
Table table = new();
table.Title = new TableTitle($"Partition {partitionsList[i].Sequence}:");
table.AddColumn("");
table.AddColumn("");
table.HideHeaders();
if(opened != ErrorNumber.NoError)
{
AaruConsole.WriteLine("Unable to open image format");
AaruConsole.WriteLine("Error {0}", opened);
table.AddRow("Name", Markup.Escape(partitionsList[i].Name ?? ""));
table.AddRow("Type", Markup.Escape(partitionsList[i].Type ?? ""));
table.AddRow("Start", $"sector {partitionsList[i].Start}, byte {partitionsList[i].Offset}");
return (int)opened;
}
table.AddRow("Length", $"{partitionsList[i].Length} sectors, {partitionsList[i].Size} bytes");
if(verbose)
{
ImageInfo.PrintImageInfo(imageFormat);
AaruConsole.WriteLine();
}
table.AddRow("Scheme", Markup.Escape(partitionsList[i].Scheme ?? ""));
table.AddRow("Description", Markup.Escape(partitionsList[i].Description ?? ""));
Statistics.AddMediaFormat(imageFormat.Format);
Statistics.AddMedia(imageFormat.Info.MediaType, false);
Statistics.AddFilter(inputFilter.Name);
}
catch(Exception ex)
{
AaruConsole.ErrorWriteLine("Unable to open image format");
AaruConsole.ErrorWriteLine("Error: {0}", ex.Message);
AaruConsole.DebugWriteLine("Fs-info command", "Stack trace: {0}", ex.StackTrace);
return (int)ErrorNumber.CannotOpenFormat;
}
List<string> idPlugins = null;
IFilesystem plugin;
string information;
if(partitions)
{
List<Partition> partitionsList = null;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Enumerating partitions...").IsIndeterminate();
partitionsList = Core.Partitions.GetAll(imageFormat);
});
Core.Partitions.AddSchemesToStats(partitionsList);
if(partitionsList.Count == 0)
{
AaruConsole.DebugWriteLine("Fs-info command", "No partitions found");
AnsiConsole.Render(table);
if(!filesystems)
{
AaruConsole.WriteLine("No partitions founds, not searching for filesystems");
continue;
return (int)ErrorNumber.NothingFound;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying filesystems on partition...").IsIndeterminate();
Core.Filesystems.Identify(imageFormat, out idPlugins, partitionsList[i]);
});
if(idPlugins.Count == 0)
AaruConsole.WriteLine("[bold]Filesystem not identified[/]");
else if(idPlugins.Count > 1)
{
AaruConsole.WriteLine($"[italic]Identified by {idPlugins.Count} plugins[/]");
foreach(string pluginName in idPlugins)
if(plugins.PluginsList.TryGetValue(pluginName, out plugin))
{
AaruConsole.WriteLine($"[bold]As identified by {plugin.Name}.[/]");
plugin.GetInformation(imageFormat, partitionsList[i], out information,
encodingClass);
AaruConsole.Write(information);
Statistics.AddFilesystem(plugin.XmlFsType.Type);
}
}
checkRaw = true;
}
else
{
AaruConsole.WriteLine("{0} partitions found.", partitionsList.Count);
for(int i = 0; i < partitionsList.Count; i++)
else
{
Table table = new();
table.Title = new TableTitle($"Partition {partitionsList[i].Sequence}:");
table.AddColumn("");
table.AddColumn("");
table.HideHeaders();
plugins.PluginsList.TryGetValue(idPlugins[0], out plugin);
table.AddRow("Name", Markup.Escape(partitionsList[i].Name ?? ""));
table.AddRow("Type", Markup.Escape(partitionsList[i].Type ?? ""));
table.AddRow("Start", $"sector {partitionsList[i].Start}, byte {partitionsList[i].Offset}");
table.AddRow("Length",
$"{partitionsList[i].Length} sectors, {partitionsList[i].Size} bytes");
table.AddRow("Scheme", Markup.Escape(partitionsList[i].Scheme ?? ""));
table.AddRow("Description", Markup.Escape(partitionsList[i].Description ?? ""));
AnsiConsole.Render(table);
if(!filesystems)
if(plugin == null)
continue;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying filesystems on partition...").IsIndeterminate();
Core.Filesystems.Identify(imageFormat, out idPlugins, partitionsList[i]);
});
if(idPlugins.Count == 0)
AaruConsole.WriteLine("[bold]Filesystem not identified[/]");
else if(idPlugins.Count > 1)
{
AaruConsole.WriteLine($"[italic]Identified by {idPlugins.Count} plugins[/]");
foreach(string pluginName in idPlugins)
if(plugins.PluginsList.TryGetValue(pluginName, out plugin))
{
AaruConsole.WriteLine($"[bold]As identified by {plugin.Name}.[/]");
plugin.GetInformation(imageFormat, partitionsList[i], out information,
encodingClass);
AaruConsole.Write(information);
Statistics.AddFilesystem(plugin.XmlFsType.Type);
}
}
else
{
plugins.PluginsList.TryGetValue(idPlugins[0], out plugin);
if(plugin == null)
continue;
AaruConsole.WriteLine($"[bold]Identified by {plugin.Name}.[/]");
plugin.GetInformation(imageFormat, partitionsList[i], out information, encodingClass);
AaruConsole.Write("{0}", information);
Statistics.AddFilesystem(plugin.XmlFsType.Type);
}
AaruConsole.WriteLine();
AaruConsole.WriteLine($"[bold]Identified by {plugin.Name}.[/]");
plugin.GetInformation(imageFormat, partitionsList[i], out information, encodingClass);
AaruConsole.Write("{0}", information);
Statistics.AddFilesystem(plugin.XmlFsType.Type);
}
AaruConsole.WriteLine();
}
}
}
if(checkRaw)
if(checkRaw)
{
var wholePart = new Partition
{
var wholePart = new Partition
{
Name = "Whole device",
Length = imageFormat.Info.Sectors,
Size = imageFormat.Info.Sectors * imageFormat.Info.SectorSize
};
Name = "Whole device",
Length = imageFormat.Info.Sectors,
Size = imageFormat.Info.Sectors * imageFormat.Info.SectorSize
};
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying filesystems...").IsIndeterminate();
Core.Filesystems.Identify(imageFormat, out idPlugins, wholePart);
});
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying filesystems...").IsIndeterminate();
Core.Filesystems.Identify(imageFormat, out idPlugins, wholePart);
});
if(idPlugins.Count == 0)
AaruConsole.WriteLine("[bold]Filesystem not identified[/]");
else if(idPlugins.Count > 1)
{
AaruConsole.WriteLine($"[italic]Identified by {idPlugins.Count} plugins[/]");
if(idPlugins.Count == 0)
AaruConsole.WriteLine("[bold]Filesystem not identified[/]");
else if(idPlugins.Count > 1)
{
AaruConsole.WriteLine($"[italic]Identified by {idPlugins.Count} plugins[/]");
foreach(string pluginName in idPlugins)
if(plugins.PluginsList.TryGetValue(pluginName, out plugin))
{
AaruConsole.WriteLine($"[bold]As identified by {plugin.Name}.[/]");
plugin.GetInformation(imageFormat, wholePart, out information, encodingClass);
AaruConsole.Write(information);
Statistics.AddFilesystem(plugin.XmlFsType.Type);
}
}
else
{
plugins.PluginsList.TryGetValue(idPlugins[0], out plugin);
if(plugin != null)
foreach(string pluginName in idPlugins)
if(plugins.PluginsList.TryGetValue(pluginName, out plugin))
{
AaruConsole.WriteLine($"[bold]Identified by {plugin.Name}.[/]");
AaruConsole.WriteLine($"[bold]As identified by {plugin.Name}.[/]");
plugin.GetInformation(imageFormat, wholePart, out information, encodingClass);
AaruConsole.Write(information);
Statistics.AddFilesystem(plugin.XmlFsType.Type);
}
}
else
{
plugins.PluginsList.TryGetValue(idPlugins[0], out plugin);
if(plugin != null)
{
AaruConsole.WriteLine($"[bold]Identified by {plugin.Name}.[/]");
plugin.GetInformation(imageFormat, wholePart, out information, encodingClass);
AaruConsole.Write(information);
Statistics.AddFilesystem(plugin.XmlFsType.Type);
}
}
}
catch(Exception ex)
{
AaruConsole.ErrorWriteLine($"Error reading file: {ex.Message}");
AaruConsole.DebugWriteLine("Fs-info command", ex.StackTrace);
return (int)ErrorNumber.UnexpectedException;
}
return (int)ErrorNumber.NoError;
}
catch(Exception ex)
{
AaruConsole.ErrorWriteLine($"Error reading file: {ex.Message}");
AaruConsole.DebugWriteLine("Fs-info command", ex.StackTrace);
return (int)ErrorNumber.UnexpectedException;
}
return (int)ErrorNumber.NoError;
}
}

View File

@@ -45,414 +45,418 @@ using Aaru.Core;
using JetBrains.Annotations;
using Spectre.Console;
namespace Aaru.Commands.Filesystem
namespace Aaru.Commands.Filesystem;
internal sealed class LsCommand : Command
{
internal sealed class LsCommand : Command
public LsCommand() : base("list", "Lists files in disc image.")
{
public LsCommand() : base("list", "Lists files in disc image.")
{
AddAlias("ls");
AddAlias("ls");
Add(new Option(new[]
{
"--encoding", "-e"
}, "Name of character encoding to use.")
{
Argument = new Argument<string>(() => null),
Required = false
});
Add(new Option(new[]
{
"--long-format", "-l"
}, "Uses long format.")
{
Argument = new Argument<bool>(() => true),
Required = false
});
Add(new Option(new[]
{
"--options", "-O"
}, "Comma separated name=value pairs of options to pass to filesystem plugin.")
{
Argument = new Argument<string>(() => null),
Required = false
});
Add(new Option(new[]
{
"--namespace", "-n"
}, "Namespace to use for filenames.")
{
Argument = new Argument<string>(() => null),
Required = false
});
AddArgument(new Argument<string>
Add(new Option(new[]
{
Arity = ArgumentArity.ExactlyOne,
Description = "Media image path",
Name = "image-path"
"--encoding", "-e"
}, "Name of character encoding to use.")
{
Argument = new Argument<string>(() => null),
Required = false
});
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
Add(new Option(new[]
{
"--long-format", "-l"
}, "Uses long format.")
{
Argument = new Argument<bool>(() => true),
Required = false
});
Add(new Option(new[]
{
"--options", "-O"
}, "Comma separated name=value pairs of options to pass to filesystem plugin.")
{
Argument = new Argument<string>(() => null),
Required = false
});
Add(new Option(new[]
{
"--namespace", "-n"
}, "Namespace to use for filenames.")
{
Argument = new Argument<string>(() => null),
Required = false
});
AddArgument(new Argument<string>
{
Arity = ArgumentArity.ExactlyOne,
Description = "Media image path",
Name = "image-path"
});
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
}
public static int Invoke(bool debug, bool verbose, string encoding, string imagePath, bool longFormat,
string @namespace, string options)
{
MainClass.PrintCopyright();
if(debug)
{
IAnsiConsole stderrConsole = AnsiConsole.Create(new AnsiConsoleSettings
{
Out = new AnsiConsoleOutput(System.Console.Error)
});
AaruConsole.DebugWriteLineEvent += (format, objects) =>
{
if(objects is null)
stderrConsole.MarkupLine(format);
else
stderrConsole.MarkupLine(format, objects);
};
}
public static int Invoke(bool debug, bool verbose, string encoding, string imagePath, bool longFormat,
string @namespace, string options)
{
MainClass.PrintCopyright();
if(debug)
if(verbose)
AaruConsole.WriteEvent += (format, objects) =>
{
IAnsiConsole stderrConsole = AnsiConsole.Create(new AnsiConsoleSettings
{
Out = new AnsiConsoleOutput(System.Console.Error)
});
if(objects is null)
AnsiConsole.Markup(format);
else
AnsiConsole.Markup(format, objects);
};
AaruConsole.DebugWriteLineEvent += (format, objects) =>
{
if(objects is null)
stderrConsole.MarkupLine(format);
else
stderrConsole.MarkupLine(format, objects);
};
AaruConsole.DebugWriteLine("Ls command", "--debug={0}", debug);
AaruConsole.DebugWriteLine("Ls command", "--encoding={0}", encoding);
AaruConsole.DebugWriteLine("Ls command", "--input={0}", imagePath);
AaruConsole.DebugWriteLine("Ls command", "--options={0}", options);
AaruConsole.DebugWriteLine("Ls command", "--verbose={0}", verbose);
Statistics.AddCommand("ls");
var filtersList = new FiltersList();
IFilter inputFilter = null;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying file filter...").IsIndeterminate();
inputFilter = filtersList.GetFilter(imagePath);
});
Dictionary<string, string> parsedOptions = Core.Options.Parse(options);
AaruConsole.DebugWriteLine("Ls command", "Parsed options:");
foreach(KeyValuePair<string, string> parsedOption in parsedOptions)
AaruConsole.DebugWriteLine("Ls command", "{0} = {1}", parsedOption.Key, parsedOption.Value);
parsedOptions.Add("debug", debug.ToString());
if(inputFilter == null)
{
AaruConsole.ErrorWriteLine("Cannot open specified file.");
return (int)ErrorNumber.CannotOpenFile;
}
Encoding encodingClass = null;
if(encoding != null)
try
{
encodingClass = Claunia.Encoding.Encoding.GetEncoding(encoding);
if(verbose)
AaruConsole.VerboseWriteLine("Using encoding for {0}.", encodingClass.EncodingName);
}
catch(ArgumentException)
{
AaruConsole.ErrorWriteLine("Specified encoding is not supported.");
return (int)ErrorNumber.EncodingUnknown;
}
PluginBase plugins = GetPluginBase.Instance;
try
{
IMediaImage imageFormat = null;
IBaseImage baseImage = null;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying image format...").IsIndeterminate();
baseImage = ImageFormat.Detect(inputFilter);
imageFormat = baseImage as IMediaImage;
});
if(baseImage == null)
{
AaruConsole.WriteLine("Image format not identified, not proceeding with analysis.");
return (int)ErrorNumber.UnrecognizedFormat;
}
if(imageFormat == null)
{
AaruConsole.WriteLine("Command not supported for this image type.");
return (int)ErrorNumber.InvalidArgument;
}
if(verbose)
AaruConsole.WriteEvent += (format, objects) =>
{
if(objects is null)
AnsiConsole.Markup(format);
else
AnsiConsole.Markup(format, objects);
};
AaruConsole.DebugWriteLine("Ls command", "--debug={0}", debug);
AaruConsole.DebugWriteLine("Ls command", "--encoding={0}", encoding);
AaruConsole.DebugWriteLine("Ls command", "--input={0}", imagePath);
AaruConsole.DebugWriteLine("Ls command", "--options={0}", options);
AaruConsole.DebugWriteLine("Ls command", "--verbose={0}", verbose);
Statistics.AddCommand("ls");
var filtersList = new FiltersList();
IFilter inputFilter = null;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying file filter...").IsIndeterminate();
inputFilter = filtersList.GetFilter(imagePath);
});
Dictionary<string, string> parsedOptions = Core.Options.Parse(options);
AaruConsole.DebugWriteLine("Ls command", "Parsed options:");
foreach(KeyValuePair<string, string> parsedOption in parsedOptions)
AaruConsole.DebugWriteLine("Ls command", "{0} = {1}", parsedOption.Key, parsedOption.Value);
parsedOptions.Add("debug", debug.ToString());
if(inputFilter == null)
{
AaruConsole.ErrorWriteLine("Cannot open specified file.");
return (int)ErrorNumber.CannotOpenFile;
}
Encoding encodingClass = null;
if(encoding != null)
try
{
encodingClass = Claunia.Encoding.Encoding.GetEncoding(encoding);
if(verbose)
AaruConsole.VerboseWriteLine("Using encoding for {0}.", encodingClass.EncodingName);
}
catch(ArgumentException)
{
AaruConsole.ErrorWriteLine("Specified encoding is not supported.");
return (int)ErrorNumber.EncodingUnknown;
}
PluginBase plugins = GetPluginBase.Instance;
AaruConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name, imageFormat.Id);
else
AaruConsole.WriteLine("Image format identified by {0}.", imageFormat.Name);
try
{
IMediaImage imageFormat = null;
ErrorNumber opened = ErrorNumber.NoData;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying image format...").IsIndeterminate();
imageFormat = ImageFormat.Detect(inputFilter);
ctx.AddTask("Opening image file...").IsIndeterminate();
opened = imageFormat.Open(inputFilter);
});
if(imageFormat == null)
if(opened != ErrorNumber.NoError)
{
AaruConsole.WriteLine("Image format not identified, not proceeding with analysis.");
AaruConsole.WriteLine("Unable to open image format");
AaruConsole.WriteLine("Error {0}", opened);
return (int)ErrorNumber.UnrecognizedFormat;
return (int)opened;
}
if(verbose)
AaruConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name,
imageFormat.Id);
else
AaruConsole.WriteLine("Image format identified by {0}.", imageFormat.Name);
AaruConsole.DebugWriteLine("Ls command", "Correctly opened image file.");
try
{
ErrorNumber opened = ErrorNumber.NoData;
AaruConsole.DebugWriteLine("Ls command", "Image without headers is {0} bytes.",
imageFormat.Info.ImageSize);
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Opening image file...").IsIndeterminate();
opened = imageFormat.Open(inputFilter);
});
AaruConsole.DebugWriteLine("Ls command", "Image has {0} sectors.", imageFormat.Info.Sectors);
if(opened != ErrorNumber.NoError)
{
AaruConsole.WriteLine("Unable to open image format");
AaruConsole.WriteLine("Error {0}", opened);
AaruConsole.DebugWriteLine("Ls command", "Image identifies disk type as {0}.",
imageFormat.Info.MediaType);
return (int)opened;
}
AaruConsole.DebugWriteLine("Ls command", "Correctly opened image file.");
AaruConsole.DebugWriteLine("Ls command", "Image without headers is {0} bytes.",
imageFormat.Info.ImageSize);
AaruConsole.DebugWriteLine("Ls command", "Image has {0} sectors.", imageFormat.Info.Sectors);
AaruConsole.DebugWriteLine("Ls command", "Image identifies disk type as {0}.",
imageFormat.Info.MediaType);
Statistics.AddMediaFormat(imageFormat.Format);
Statistics.AddMedia(imageFormat.Info.MediaType, false);
Statistics.AddFilter(inputFilter.Name);
}
catch(Exception ex)
{
AaruConsole.ErrorWriteLine("Unable to open image format");
AaruConsole.ErrorWriteLine("Error: {0}", ex.Message);
return (int)ErrorNumber.CannotOpenFormat;
}
List<Partition> partitions = null;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Enumerating partitions...").IsIndeterminate();
partitions = Core.Partitions.GetAll(imageFormat);
});
Core.Partitions.AddSchemesToStats(partitions);
if(partitions.Count == 0)
{
AaruConsole.DebugWriteLine("Ls command", "No partitions found");
partitions.Add(new Partition
{
Description = "Whole device",
Length = imageFormat.Info.Sectors,
Offset = 0,
Size = imageFormat.Info.SectorSize * imageFormat.Info.Sectors,
Sequence = 1,
Start = 0
});
}
AaruConsole.WriteLine("{0} partitions found.", partitions.Count);
for(int i = 0; i < partitions.Count; i++)
{
AaruConsole.WriteLine();
AaruConsole.WriteLine("[bold]Partition {0}:[/]", partitions[i].Sequence);
List<string> idPlugins = null;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying filesystems on partition...").IsIndeterminate();
Core.Filesystems.Identify(imageFormat, out idPlugins, partitions[i]);
});
if(idPlugins.Count == 0)
AaruConsole.WriteLine("Filesystem not identified");
else
{
IReadOnlyFilesystem plugin;
ErrorNumber error = ErrorNumber.InvalidArgument;
if(idPlugins.Count > 1)
{
AaruConsole.WriteLine($"[italic]Identified by {idPlugins.Count} plugins[/]");
foreach(string pluginName in idPlugins)
if(plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out plugin))
{
AaruConsole.WriteLine($"[bold]As identified by {plugin.Name}.[/]");
var fs = (IReadOnlyFilesystem)plugin.GetType().GetConstructor(Type.EmptyTypes)?.
Invoke(new object[]
{});
if(fs == null)
continue;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Mounting filesystem...").IsIndeterminate();
error = fs.Mount(imageFormat, partitions[i], encodingClass, parsedOptions,
@namespace);
});
if(error == ErrorNumber.NoError)
{
ListFilesInDir("/", fs, longFormat);
Statistics.AddFilesystem(fs.XmlFsType.Type);
}
else
AaruConsole.ErrorWriteLine("Unable to mount device, error {0}",
error.ToString());
}
}
else
{
plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out plugin);
if(plugin == null)
continue;
AaruConsole.WriteLine($"[bold]Identified by {plugin.Name}.[/]");
var fs = (IReadOnlyFilesystem)plugin.GetType().GetConstructor(Type.EmptyTypes)?.
Invoke(new object[]
{});
if(fs == null)
continue;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Mounting filesystem...").IsIndeterminate();
error = fs.Mount(imageFormat, partitions[i], encodingClass, parsedOptions, @namespace);
});
if(error == ErrorNumber.NoError)
{
ListFilesInDir("/", fs, longFormat);
Statistics.AddFilesystem(fs.XmlFsType.Type);
}
else
AaruConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString());
}
}
}
Statistics.AddMediaFormat(imageFormat.Format);
Statistics.AddMedia(imageFormat.Info.MediaType, false);
Statistics.AddFilter(inputFilter.Name);
}
catch(Exception ex)
{
AaruConsole.ErrorWriteLine($"Error reading file: {ex.Message}");
AaruConsole.DebugWriteLine("Ls command", ex.StackTrace);
AaruConsole.ErrorWriteLine("Unable to open image format");
AaruConsole.ErrorWriteLine("Error: {0}", ex.Message);
return (int)ErrorNumber.UnexpectedException;
return (int)ErrorNumber.CannotOpenFormat;
}
return (int)ErrorNumber.NoError;
}
static void ListFilesInDir(string path, [NotNull] IReadOnlyFilesystem fs, bool longFormat)
{
ErrorNumber error = ErrorNumber.InvalidArgument;
List<string> directory = new();
if(path.StartsWith('/'))
path = path.Substring(1);
AaruConsole.WriteLine(string.IsNullOrEmpty(path) ? "Root directory" : $"Directory: {Markup.Escape(path)}");
List<Partition> partitions = null;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Reading directory...").IsIndeterminate();
error = fs.ReadDir(path, out directory);
ctx.AddTask("Enumerating partitions...").IsIndeterminate();
partitions = Core.Partitions.GetAll(imageFormat);
});
if(error != ErrorNumber.NoError)
{
AaruConsole.ErrorWriteLine("Error {0} reading root directory {1}", error.ToString(), path);
Core.Partitions.AddSchemesToStats(partitions);
return;
if(partitions.Count == 0)
{
AaruConsole.DebugWriteLine("Ls command", "No partitions found");
partitions.Add(new Partition
{
Description = "Whole device",
Length = imageFormat.Info.Sectors,
Offset = 0,
Size = imageFormat.Info.SectorSize * imageFormat.Info.Sectors,
Sequence = 1,
Start = 0
});
}
Dictionary<string, FileEntryInfo> stats = new();
AaruConsole.WriteLine("{0} partitions found.", partitions.Count);
AnsiConsole.Progress().AutoClear(true).HideCompleted(true).
Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()).
Start(ctx =>
{
ProgressTask task = ctx.AddTask("Retrieving file information...");
task.MaxValue = directory.Count;
for(int i = 0; i < partitions.Count; i++)
{
AaruConsole.WriteLine();
AaruConsole.WriteLine("[bold]Partition {0}:[/]", partitions[i].Sequence);
foreach(string entry in directory)
{
task.Increment(1);
fs.Stat(path + "/" + entry, out FileEntryInfo stat);
List<string> idPlugins = null;
stats.Add(entry, stat);
}
});
foreach(KeyValuePair<string, FileEntryInfo> entry in
stats.OrderBy(e => e.Value?.Attributes.HasFlag(FileAttributes.Directory) == false))
if(longFormat)
Core.Spectre.ProgressSingleSpinner(ctx =>
{
if(entry.Value != null)
{
if(entry.Value.Attributes.HasFlag(FileAttributes.Directory))
AaruConsole.WriteLine("{0, 10:d} {0, 12:T} {1, -20} {2}", entry.Value.CreationTimeUtc,
"<DIR>", Markup.Escape(entry.Key));
else
AaruConsole.WriteLine("{0, 10:d} {0, 12:T} {1, 6}{2, 14:N0} {3}",
entry.Value.CreationTimeUtc, entry.Value.Inode, entry.Value.Length,
Markup.Escape(entry.Key));
ctx.AddTask("Identifying filesystems on partition...").IsIndeterminate();
Core.Filesystems.Identify(imageFormat, out idPlugins, partitions[i]);
});
error = fs.ListXAttr(path + "/" + entry.Key, out List<string> xattrs);
if(error != ErrorNumber.NoError)
continue;
foreach(string xattr in xattrs)
{
byte[] xattrBuf = Array.Empty<byte>();
error = fs.GetXattr(path + "/" + entry.Key, xattr, ref xattrBuf);
if(error == ErrorNumber.NoError)
AaruConsole.WriteLine("\t\t{0}\t{1:##,#}", Markup.Escape(xattr), xattrBuf.Length);
}
}
else
AaruConsole.WriteLine("{0, 47}{1}", string.Empty, Markup.Escape(entry.Key));
}
if(idPlugins.Count == 0)
AaruConsole.WriteLine("Filesystem not identified");
else
{
AaruConsole.
WriteLine(entry.Value?.Attributes.HasFlag(FileAttributes.Directory) == true ? "{0}/" : "{0}",
entry.Key);
IReadOnlyFilesystem plugin;
ErrorNumber error = ErrorNumber.InvalidArgument;
if(idPlugins.Count > 1)
{
AaruConsole.WriteLine($"[italic]Identified by {idPlugins.Count} plugins[/]");
foreach(string pluginName in idPlugins)
if(plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out plugin))
{
AaruConsole.WriteLine($"[bold]As identified by {plugin.Name}.[/]");
var fs = (IReadOnlyFilesystem)plugin.GetType().GetConstructor(Type.EmptyTypes)?.
Invoke(new object[]
{});
if(fs == null)
continue;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Mounting filesystem...").IsIndeterminate();
error = fs.Mount(imageFormat, partitions[i], encodingClass, parsedOptions,
@namespace);
});
if(error == ErrorNumber.NoError)
{
ListFilesInDir("/", fs, longFormat);
Statistics.AddFilesystem(fs.XmlFsType.Type);
}
else
AaruConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString());
}
}
else
{
plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out plugin);
if(plugin == null)
continue;
AaruConsole.WriteLine($"[bold]Identified by {plugin.Name}.[/]");
var fs = (IReadOnlyFilesystem)plugin.GetType().GetConstructor(Type.EmptyTypes)?.
Invoke(new object[]
{});
if(fs == null)
continue;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Mounting filesystem...").IsIndeterminate();
error = fs.Mount(imageFormat, partitions[i], encodingClass, parsedOptions, @namespace);
});
if(error == ErrorNumber.NoError)
{
ListFilesInDir("/", fs, longFormat);
Statistics.AddFilesystem(fs.XmlFsType.Type);
}
else
AaruConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString());
}
}
AaruConsole.WriteLine();
foreach(KeyValuePair<string, FileEntryInfo> subdirectory in
stats.Where(e => e.Value?.Attributes.HasFlag(FileAttributes.Directory) == true))
ListFilesInDir(path + "/" + subdirectory.Key, fs, longFormat);
}
}
catch(Exception ex)
{
AaruConsole.ErrorWriteLine($"Error reading file: {ex.Message}");
AaruConsole.DebugWriteLine("Ls command", ex.StackTrace);
return (int)ErrorNumber.UnexpectedException;
}
return (int)ErrorNumber.NoError;
}
static void ListFilesInDir(string path, [NotNull] IReadOnlyFilesystem fs, bool longFormat)
{
ErrorNumber error = ErrorNumber.InvalidArgument;
List<string> directory = new();
if(path.StartsWith('/'))
path = path.Substring(1);
AaruConsole.WriteLine(string.IsNullOrEmpty(path) ? "Root directory" : $"Directory: {Markup.Escape(path)}");
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Reading directory...").IsIndeterminate();
error = fs.ReadDir(path, out directory);
});
if(error != ErrorNumber.NoError)
{
AaruConsole.ErrorWriteLine("Error {0} reading root directory {1}", error.ToString(), path);
return;
}
Dictionary<string, FileEntryInfo> stats = new();
AnsiConsole.Progress().AutoClear(true).HideCompleted(true).
Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()).Start(ctx =>
{
ProgressTask task = ctx.AddTask("Retrieving file information...");
task.MaxValue = directory.Count;
foreach(string entry in directory)
{
task.Increment(1);
fs.Stat(path + "/" + entry, out FileEntryInfo stat);
stats.Add(entry, stat);
}
});
foreach(KeyValuePair<string, FileEntryInfo> entry in
stats.OrderBy(e => e.Value?.Attributes.HasFlag(FileAttributes.Directory) == false))
if(longFormat)
{
if(entry.Value != null)
{
if(entry.Value.Attributes.HasFlag(FileAttributes.Directory))
AaruConsole.WriteLine("{0, 10:d} {0, 12:T} {1, -20} {2}", entry.Value.CreationTimeUtc,
"<DIR>", Markup.Escape(entry.Key));
else
AaruConsole.WriteLine("{0, 10:d} {0, 12:T} {1, 6}{2, 14:N0} {3}", entry.Value.CreationTimeUtc,
entry.Value.Inode, entry.Value.Length, Markup.Escape(entry.Key));
error = fs.ListXAttr(path + "/" + entry.Key, out List<string> xattrs);
if(error != ErrorNumber.NoError)
continue;
foreach(string xattr in xattrs)
{
byte[] xattrBuf = Array.Empty<byte>();
error = fs.GetXattr(path + "/" + entry.Key, xattr, ref xattrBuf);
if(error == ErrorNumber.NoError)
AaruConsole.WriteLine("\t\t{0}\t{1:##,#}", Markup.Escape(xattr), xattrBuf.Length);
}
}
else
AaruConsole.WriteLine("{0, 47}{1}", string.Empty, Markup.Escape(entry.Key));
}
else
{
AaruConsole.
WriteLine(entry.Value?.Attributes.HasFlag(FileAttributes.Directory) == true ? "{0}/" : "{0}",
entry.Key);
}
AaruConsole.WriteLine();
foreach(KeyValuePair<string, FileEntryInfo> subdirectory in
stats.Where(e => e.Value?.Attributes.HasFlag(FileAttributes.Directory) == true))
ListFilesInDir(path + "/" + subdirectory.Key, fs, longFormat);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -42,389 +42,393 @@ using Aaru.Decoders.CD;
using Aaru.Decoders.SCSI;
using Spectre.Console;
namespace Aaru.Commands.Image
namespace Aaru.Commands.Image;
internal sealed class DecodeCommand : Command
{
internal sealed class DecodeCommand : Command
public DecodeCommand() : base("decode", "Decodes and pretty prints disk and/or sector tags.")
{
public DecodeCommand() : base("decode", "Decodes and pretty prints disk and/or sector tags.")
{
Add(new Option(new[]
{
"--disk-tags", "-f"
}, "Decode disk tags.")
{
Argument = new Argument<bool>(() => true),
Required = false
});
Add(new Option(new[]
{
"--length", "-l"
}, "How many sectors to decode, or \"all\".")
{
Argument = new Argument<string>(() => "all"),
Required = false
});
Add(new Option(new[]
{
"--sector-tags", "-p"
}, "Decode sector tags.")
{
Argument = new Argument<bool>(() => true),
Required = false
});
Add(new Option(new[]
{
"--start", "-s"
}, "Sector to start decoding from.")
{
Argument = new Argument<ulong>(() => 0),
Required = false
});
AddArgument(new Argument<string>
Add(new Option(new[]
{
Arity = ArgumentArity.ExactlyOne,
Description = "Media image path",
Name = "image-path"
"--disk-tags", "-f"
}, "Decode disk tags.")
{
Argument = new Argument<bool>(() => true),
Required = false
});
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
Add(new Option(new[]
{
"--length", "-l"
}, "How many sectors to decode, or \"all\".")
{
Argument = new Argument<string>(() => "all"),
Required = false
});
Add(new Option(new[]
{
"--sector-tags", "-p"
}, "Decode sector tags.")
{
Argument = new Argument<bool>(() => true),
Required = false
});
Add(new Option(new[]
{
"--start", "-s"
}, "Sector to start decoding from.")
{
Argument = new Argument<ulong>(() => 0),
Required = false
});
AddArgument(new Argument<string>
{
Arity = ArgumentArity.ExactlyOne,
Description = "Media image path",
Name = "image-path"
});
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
}
public static int Invoke(bool verbose, bool debug, bool diskTags, string imagePath, string length, bool sectorTags,
ulong startSector)
{
MainClass.PrintCopyright();
if(debug)
{
IAnsiConsole stderrConsole = AnsiConsole.Create(new AnsiConsoleSettings
{
Out = new AnsiConsoleOutput(System.Console.Error)
});
AaruConsole.DebugWriteLineEvent += (format, objects) =>
{
if(objects is null)
stderrConsole.MarkupLine(format);
else
stderrConsole.MarkupLine(format, objects);
};
}
public static int Invoke(bool verbose, bool debug, bool diskTags, string imagePath, string length,
bool sectorTags, ulong startSector)
if(verbose)
AaruConsole.WriteEvent += (format, objects) =>
{
if(objects is null)
AnsiConsole.Markup(format);
else
AnsiConsole.Markup(format, objects);
};
Statistics.AddCommand("decode");
AaruConsole.DebugWriteLine("Decode command", "--debug={0}", debug);
AaruConsole.DebugWriteLine("Decode command", "--disk-tags={0}", diskTags);
AaruConsole.DebugWriteLine("Decode command", "--input={0}", imagePath);
AaruConsole.DebugWriteLine("Decode command", "--length={0}", length);
AaruConsole.DebugWriteLine("Decode command", "--sector-tags={0}", sectorTags);
AaruConsole.DebugWriteLine("Decode command", "--start={0}", startSector);
AaruConsole.DebugWriteLine("Decode command", "--verbose={0}", verbose);
var filtersList = new FiltersList();
IFilter inputFilter = null;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
MainClass.PrintCopyright();
if(debug)
{
IAnsiConsole stderrConsole = AnsiConsole.Create(new AnsiConsoleSettings
{
Out = new AnsiConsoleOutput(System.Console.Error)
});
AaruConsole.DebugWriteLineEvent += (format, objects) =>
{
if(objects is null)
stderrConsole.MarkupLine(format);
else
stderrConsole.MarkupLine(format, objects);
};
}
if(verbose)
AaruConsole.WriteEvent += (format, objects) =>
{
if(objects is null)
AnsiConsole.Markup(format);
else
AnsiConsole.Markup(format, objects);
};
Statistics.AddCommand("decode");
AaruConsole.DebugWriteLine("Decode command", "--debug={0}", debug);
AaruConsole.DebugWriteLine("Decode command", "--disk-tags={0}", diskTags);
AaruConsole.DebugWriteLine("Decode command", "--input={0}", imagePath);
AaruConsole.DebugWriteLine("Decode command", "--length={0}", length);
AaruConsole.DebugWriteLine("Decode command", "--sector-tags={0}", sectorTags);
AaruConsole.DebugWriteLine("Decode command", "--start={0}", startSector);
AaruConsole.DebugWriteLine("Decode command", "--verbose={0}", verbose);
var filtersList = new FiltersList();
IFilter inputFilter = null;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying file filter...").IsIndeterminate();
inputFilter = filtersList.GetFilter(imagePath);
});
if(inputFilter == null)
{
AaruConsole.ErrorWriteLine("Cannot open specified file.");
return (int)ErrorNumber.CannotOpenFile;
}
IMediaImage inputFormat = null;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying image format...").IsIndeterminate();
inputFormat = ImageFormat.Detect(inputFilter);
});
if(inputFormat == null)
{
AaruConsole.ErrorWriteLine("Unable to recognize image format, not decoding");
return (int)ErrorNumber.UnrecognizedFormat;
}
ErrorNumber opened = ErrorNumber.NoData;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Opening image file...").IsIndeterminate();
opened = inputFormat.Open(inputFilter);
});
if(opened != ErrorNumber.NoError)
{
AaruConsole.WriteLine("Error {opened} opening image format");
return (int)opened;
}
Statistics.AddMediaFormat(inputFormat.Format);
Statistics.AddMedia(inputFormat.Info.MediaType, false);
Statistics.AddFilter(inputFilter.Name);
ErrorNumber errno;
if(diskTags)
if(inputFormat.Info.ReadableMediaTags.Count == 0)
AaruConsole.WriteLine("There are no disk tags in chosen disc image.");
else
foreach(MediaTagType tag in inputFormat.Info.ReadableMediaTags)
switch(tag)
{
case MediaTagType.SCSI_INQUIRY:
{
errno = inputFormat.ReadMediaTag(MediaTagType.SCSI_INQUIRY, out byte[] inquiry);
if(inquiry == null)
AaruConsole.WriteLine("Error {0} reading SCSI INQUIRY response from disc image",
errno);
else
{
AaruConsole.WriteLine("[bold]SCSI INQUIRY command response:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(Inquiry.Prettify(inquiry));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
case MediaTagType.ATA_IDENTIFY:
{
errno = inputFormat.ReadMediaTag(MediaTagType.ATA_IDENTIFY, out byte[] identify);
if(errno != ErrorNumber.NoError)
AaruConsole.
WriteLine("Error {0} reading ATA IDENTIFY DEVICE response from disc image",
errno);
else
{
AaruConsole.WriteLine("[bold]ATA IDENTIFY DEVICE command response:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(Identify.Prettify(identify));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
case MediaTagType.ATAPI_IDENTIFY:
{
errno = inputFormat.ReadMediaTag(MediaTagType.ATAPI_IDENTIFY, out byte[] identify);
if(identify == null)
AaruConsole.
WriteLine("Error {0} reading ATA IDENTIFY PACKET DEVICE response from disc image",
errno);
else
{
AaruConsole.WriteLine("[bold]ATA IDENTIFY PACKET DEVICE command response:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(Identify.Prettify(identify));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
case MediaTagType.CD_ATIP:
{
errno = inputFormat.ReadMediaTag(MediaTagType.CD_ATIP, out byte[] atip);
if(errno != ErrorNumber.NoError)
AaruConsole.WriteLine("Error {0} reading CD ATIP from disc image", errno);
else
{
AaruConsole.WriteLine("[bold]CD ATIP:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(ATIP.Prettify(atip));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
case MediaTagType.CD_FullTOC:
{
errno = inputFormat.ReadMediaTag(MediaTagType.CD_FullTOC, out byte[] fullToc);
if(errno != ErrorNumber.NoError)
AaruConsole.WriteLine("Error {0} reading CD full TOC from disc image", errno);
else
{
AaruConsole.WriteLine("[bold]CD full TOC:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(FullTOC.Prettify(fullToc));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
case MediaTagType.CD_PMA:
{
errno = inputFormat.ReadMediaTag(MediaTagType.CD_PMA, out byte[] pma);
if(errno != ErrorNumber.NoError)
AaruConsole.WriteLine("Error {0} reading CD PMA from disc image", errno);
else
{
AaruConsole.WriteLine("[bold]CD PMA:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(PMA.Prettify(pma));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
case MediaTagType.CD_SessionInfo:
{
errno = inputFormat.ReadMediaTag(MediaTagType.CD_SessionInfo, out byte[] sessionInfo);
if(errno != ErrorNumber.NoError)
AaruConsole.WriteLine("Error {0} reading CD session information from disc image",
errno);
else
{
AaruConsole.WriteLine("[bold]CD session information:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(Session.Prettify(sessionInfo));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
case MediaTagType.CD_TEXT:
{
errno = inputFormat.ReadMediaTag(MediaTagType.CD_TEXT, out byte[] cdText);
if(errno != ErrorNumber.NoError)
AaruConsole.WriteLine("Error reading CD-TEXT from disc image");
else
{
AaruConsole.WriteLine("[bold]CD-TEXT:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(CDTextOnLeadIn.Prettify(cdText));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
case MediaTagType.CD_TOC:
{
errno = inputFormat.ReadMediaTag(MediaTagType.CD_TOC, out byte[] toc);
if(toc == null)
AaruConsole.WriteLine("Error reading CD TOC from disc image");
else
{
AaruConsole.WriteLine("[bold]CD TOC:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(TOC.Prettify(toc));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
default:
AaruConsole.WriteLine("Decoder for disk tag type \"{0}\" not yet implemented, sorry.",
tag);
break;
}
if(sectorTags)
{
if(length.ToLowerInvariant() == "all") {}
else
{
if(!ulong.TryParse(length, out ulong _))
ctx.AddTask("Identifying file filter...").IsIndeterminate();
inputFilter = filtersList.GetFilter(imagePath);
});
if(inputFilter == null)
{
AaruConsole.ErrorWriteLine("Cannot open specified file.");
return (int)ErrorNumber.CannotOpenFile;
}
IMediaImage inputFormat = null;
IBaseImage baseImage = null;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying image format...").IsIndeterminate();
baseImage = ImageFormat.Detect(inputFilter);
inputFormat = baseImage as IMediaImage;
});
if(baseImage == null)
{
AaruConsole.ErrorWriteLine("Unable to recognize image format, not decoding");
return (int)ErrorNumber.UnrecognizedFormat;
}
if(inputFormat == null)
{
AaruConsole.WriteLine("Command not supported for this image type.");
return (int)ErrorNumber.InvalidArgument;
}
ErrorNumber opened = ErrorNumber.NoData;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Opening image file...").IsIndeterminate();
opened = inputFormat.Open(inputFilter);
});
if(opened != ErrorNumber.NoError)
{
AaruConsole.WriteLine("Error {opened} opening image format");
return (int)opened;
}
Statistics.AddMediaFormat(inputFormat.Format);
Statistics.AddMedia(inputFormat.Info.MediaType, false);
Statistics.AddFilter(inputFilter.Name);
ErrorNumber errno;
if(diskTags)
if(inputFormat.Info.ReadableMediaTags.Count == 0)
AaruConsole.WriteLine("There are no disk tags in chosen disc image.");
else
foreach(MediaTagType tag in inputFormat.Info.ReadableMediaTags)
switch(tag)
{
AaruConsole.WriteLine("Value \"{0}\" is not a valid number for length.", length);
AaruConsole.WriteLine("Not decoding sectors tags");
return 3;
}
}
if(inputFormat.Info.ReadableSectorTags.Count == 0)
AaruConsole.WriteLine("There are no sector tags in chosen disc image.");
else
foreach(SectorTagType tag in inputFormat.Info.ReadableSectorTags)
switch(tag)
case MediaTagType.SCSI_INQUIRY:
{
default:
AaruConsole.WriteLine("Decoder for disk tag type \"{0}\" not yet implemented, sorry.",
tag);
errno = inputFormat.ReadMediaTag(MediaTagType.SCSI_INQUIRY, out byte[] inquiry);
break;
if(inquiry == null)
AaruConsole.WriteLine("Error {0} reading SCSI INQUIRY response from disc image", errno);
else
{
AaruConsole.WriteLine("[bold]SCSI INQUIRY command response:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(Inquiry.Prettify(inquiry));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
case MediaTagType.ATA_IDENTIFY:
{
errno = inputFormat.ReadMediaTag(MediaTagType.ATA_IDENTIFY, out byte[] identify);
// TODO: Not implemented
if(errno != ErrorNumber.NoError)
AaruConsole.WriteLine("Error {0} reading ATA IDENTIFY DEVICE response from disc image",
errno);
else
{
AaruConsole.WriteLine("[bold]ATA IDENTIFY DEVICE command response:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(Identify.Prettify(identify));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
case MediaTagType.ATAPI_IDENTIFY:
{
errno = inputFormat.ReadMediaTag(MediaTagType.ATAPI_IDENTIFY, out byte[] identify);
if(identify == null)
AaruConsole.
WriteLine("Error {0} reading ATA IDENTIFY PACKET DEVICE response from disc image",
errno);
else
{
AaruConsole.WriteLine("[bold]ATA IDENTIFY PACKET DEVICE command response:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(Identify.Prettify(identify));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
case MediaTagType.CD_ATIP:
{
errno = inputFormat.ReadMediaTag(MediaTagType.CD_ATIP, out byte[] atip);
if(errno != ErrorNumber.NoError)
AaruConsole.WriteLine("Error {0} reading CD ATIP from disc image", errno);
else
{
AaruConsole.WriteLine("[bold]CD ATIP:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(ATIP.Prettify(atip));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
case MediaTagType.CD_FullTOC:
{
errno = inputFormat.ReadMediaTag(MediaTagType.CD_FullTOC, out byte[] fullToc);
if(errno != ErrorNumber.NoError)
AaruConsole.WriteLine("Error {0} reading CD full TOC from disc image", errno);
else
{
AaruConsole.WriteLine("[bold]CD full TOC:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(FullTOC.Prettify(fullToc));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
case MediaTagType.CD_PMA:
{
errno = inputFormat.ReadMediaTag(MediaTagType.CD_PMA, out byte[] pma);
if(errno != ErrorNumber.NoError)
AaruConsole.WriteLine("Error {0} reading CD PMA from disc image", errno);
else
{
AaruConsole.WriteLine("[bold]CD PMA:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(PMA.Prettify(pma));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
case MediaTagType.CD_SessionInfo:
{
errno = inputFormat.ReadMediaTag(MediaTagType.CD_SessionInfo, out byte[] sessionInfo);
if(errno != ErrorNumber.NoError)
AaruConsole.WriteLine("Error {0} reading CD session information from disc image",
errno);
else
{
AaruConsole.WriteLine("[bold]CD session information:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(Session.Prettify(sessionInfo));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
case MediaTagType.CD_TEXT:
{
errno = inputFormat.ReadMediaTag(MediaTagType.CD_TEXT, out byte[] cdText);
if(errno != ErrorNumber.NoError)
AaruConsole.WriteLine("Error reading CD-TEXT from disc image");
else
{
AaruConsole.WriteLine("[bold]CD-TEXT:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(CDTextOnLeadIn.Prettify(cdText));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
case MediaTagType.CD_TOC:
{
errno = inputFormat.ReadMediaTag(MediaTagType.CD_TOC, out byte[] toc);
if(toc == null)
AaruConsole.WriteLine("Error reading CD TOC from disc image");
else
{
AaruConsole.WriteLine("[bold]CD TOC:[/]");
AaruConsole.
WriteLine("================================================================================");
AaruConsole.WriteLine(TOC.Prettify(toc));
AaruConsole.
WriteLine("================================================================================");
}
break;
}
default:
AaruConsole.WriteLine("Decoder for disk tag type \"{0}\" not yet implemented, sorry.", tag);
break;
}
if(sectorTags)
{
if(length.ToLowerInvariant() == "all") {}
else
{
if(!ulong.TryParse(length, out ulong _))
{
AaruConsole.WriteLine("Value \"{0}\" is not a valid number for length.", length);
AaruConsole.WriteLine("Not decoding sectors tags");
return 3;
}
}
return (int)ErrorNumber.NoError;
if(inputFormat.Info.ReadableSectorTags.Count == 0)
AaruConsole.WriteLine("There are no sector tags in chosen disc image.");
else
foreach(SectorTagType tag in inputFormat.Info.ReadableSectorTags)
switch(tag)
{
default:
AaruConsole.WriteLine("Decoder for disk tag type \"{0}\" not yet implemented, sorry.", tag);
break;
}
// TODO: Not implemented
}
return (int)ErrorNumber.NoError;
}
}