Replace Mono.Options with System.CommandLine

This commit is contained in:
2020-01-02 04:09:39 +00:00
parent 4a74de5843
commit 758d4dd364
30 changed files with 2389 additions and 2147 deletions

View File

@@ -186,8 +186,11 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=ATAPI/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=ATAPI/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ATIP/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=ATIP/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=BANDAI/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=BANDAI/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=bitsetting/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Bluray/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Bluray/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cartstatus/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=CDDA/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=CDDA/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cdtext/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=CDTV/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=CDTV/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cdrom/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=cdrom/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=certance/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=certance/@EntryIndexedValue">True</s:Boolean>
@@ -196,20 +199,39 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=cicm/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=cicm/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Claunia/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Claunia/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=DDCD/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=DDCD/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=dicremote/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Drive_0027s/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Drive_0027s/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=dvdr/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=dvdram/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ecsd/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=eeprom/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=EVPD/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=EVPD/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=formatlayers/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=getconfiguration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=hddvd/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=hddvdr/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Hldtst/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Hldtst/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=iomega/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=iomega/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=isrc/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=isrc/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Kreon/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Kreon/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=lastrmd/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=lastsequence/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=layercap/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Lbas/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=leadout/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=leadout/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=manuallj/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=mapfile/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=mediaid/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=mediaserialnumber/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=mhdd/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=mhdd/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=mhddlog/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=mhddlog/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=milcd/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=milcd/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=MINIX/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=MINIX/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=modesense/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=NTFS/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=NTFS/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=NTSC/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=NTSC/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Nuon/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Nuon/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Nvme/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=opticals/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=opticals/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=PCMCIA/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=PCMCIA/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Plextor/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Plextor/@EntryIndexedValue">True</s:Boolean>
@@ -219,18 +241,34 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Plextor/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Plextor/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=pmin/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=pmin/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Portillo/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Portillo/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Powe/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=pregap/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=pregap/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=pregaps/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=pregaps/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=printhex/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=psec/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=psec/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=rawtoc/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=readblocklimits/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=readcapacity/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=readcd/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=readcd/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=readdiscinformation/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=readdiscstructure/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Recordables/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Recordables/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Reiser/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Reiser/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=remapanchor/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=reportdensitysupport/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=SDHCI/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=SDHCI/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Secu/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=spamsum/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=subchannels/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=subchannels/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=subpages/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=subpages/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=subchannel/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=subchannel/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=subchannels/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=subchannels/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=umounting/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=umounting/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=undecoded/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Vari/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=writeprotection/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Wxripper/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Wxripper/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=xattr/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=xattrs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=xeto/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=xeto/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Xtreme/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> <s:Boolean x:Key="/Default/UserDictionary/Words/=Xtreme/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -32,104 +32,103 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.Text; using System.Text;
using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using Mono.Options;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class AnalyzeCommand : Command internal class AnalyzeCommand : Command
{ {
string encodingName;
string inputFile;
bool searchForFilesystems = true;
bool searchForPartitions = true;
bool showHelp;
public AnalyzeCommand() : base("analyze", public AnalyzeCommand() : base("analyze",
"Analyzes a disc image and searches for partitions and/or filesystems.") "Analyzes a disc image and searches for partitions and/or filesystems.")
{ {
Options = new OptionSet 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 analyzes 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>
{ {
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", Arity = ArgumentArity.ExactlyOne, Description = "Disc image path", Name = "image-path"
$"{MainClass.AssemblyCopyright}", });
"",
$"usage: DiscImageChef {Name} [OPTIONS] imagefile", Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
"",
Help,
{"encoding|e=", "Name of character encoding to use.", s => encodingName = s},
{"filesystems|f", "Searches and analyzes filesystems.", b => searchForFilesystems = b != null},
{"partitions|p", "Searches and interprets partitions.", b => searchForPartitions = b != null},
{"help|h|?", "Show this message and exit.", v => showHelp = v != null}
};
} }
public override int Invoke(IEnumerable<string> arguments) int Invoke(bool verbose, bool debug, string encoding, bool filesystems, bool partitions, string imagePath)
{ {
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("analyze"); Statistics.AddCommand("analyze");
if(extra.Count > 1) DicConsole.DebugWriteLine("Analyze command", "--debug={0}", debug);
{ DicConsole.DebugWriteLine("Analyze command", "--encoding={0}", encoding);
DicConsole.ErrorWriteLine("Too many arguments."); DicConsole.DebugWriteLine("Analyze command", "--filesystems={0}", filesystems);
return (int)ErrorNumber.UnexpectedArgumentCount; DicConsole.DebugWriteLine("Analyze command", "--input={0}", imagePath);
} DicConsole.DebugWriteLine("Analyze command", "--partitions={0}", partitions);
DicConsole.DebugWriteLine("Analyze command", "--verbose={0}", verbose);
if(extra.Count == 0) var filtersList = new FiltersList();
{ IFilter inputFilter = filtersList.GetFilter(imagePath);
DicConsole.ErrorWriteLine("Missing input image.");
return (int)ErrorNumber.MissingArgument;
}
inputFile = extra[0];
DicConsole.DebugWriteLine("Analyze command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("Analyze command", "--encoding={0}", encodingName);
DicConsole.DebugWriteLine("Analyze command", "--filesystems={0}", searchForFilesystems);
DicConsole.DebugWriteLine("Analyze command", "--input={0}", inputFile);
DicConsole.DebugWriteLine("Analyze command", "--partitions={0}", searchForPartitions);
DicConsole.DebugWriteLine("Analyze command", "--verbose={0}", MainClass.Verbose);
FiltersList filtersList = new FiltersList();
IFilter inputFilter = filtersList.GetFilter(inputFile);
if(inputFilter == null) if(inputFilter == null)
{ {
DicConsole.ErrorWriteLine("Cannot open specified file."); DicConsole.ErrorWriteLine("Cannot open specified file.");
return (int)ErrorNumber.CannotOpenFile;
return(int)ErrorNumber.CannotOpenFile;
} }
Encoding encoding = null; Encoding encodingClass = null;
if(encodingName != null) if(encoding != null)
try try
{ {
encoding = Claunia.Encoding.Encoding.GetEncoding(encodingName); encodingClass = Claunia.Encoding.Encoding.GetEncoding(encoding);
if(MainClass.Verbose) DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName);
if(verbose)
DicConsole.VerboseWriteLine("Using encoding for {0}.", encodingClass.EncodingName);
} }
catch(ArgumentException) catch(ArgumentException)
{ {
DicConsole.ErrorWriteLine("Specified encoding is not supported."); DicConsole.ErrorWriteLine("Specified encoding is not supported.");
return (int)ErrorNumber.EncodingUnknown;
return(int)ErrorNumber.EncodingUnknown;
} }
PluginBase plugins = GetPluginBase.Instance; PluginBase plugins = GetPluginBase.Instance;
bool checkraw = false; bool checkRaw = false;
try try
{ {
@@ -138,13 +137,16 @@ namespace DiscImageChef.Commands
if(imageFormat == null) if(imageFormat == null)
{ {
DicConsole.WriteLine("Image format not identified, not proceeding with analysis."); DicConsole.WriteLine("Image format not identified, not proceeding with analysis.");
return (int)ErrorNumber.UnrecognizedFormat;
return(int)ErrorNumber.UnrecognizedFormat;
} }
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name, DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name,
imageFormat.Id); imageFormat.Id);
else DicConsole.WriteLine("Image format identified by {0}.", imageFormat.Name); else
DicConsole.WriteLine("Image format identified by {0}.", imageFormat.Name);
DicConsole.WriteLine(); DicConsole.WriteLine();
try try
@@ -153,10 +155,11 @@ namespace DiscImageChef.Commands
{ {
DicConsole.WriteLine("Unable to open image format"); DicConsole.WriteLine("Unable to open image format");
DicConsole.WriteLine("No error given"); DicConsole.WriteLine("No error given");
return (int)ErrorNumber.CannotOpenFormat;
return(int)ErrorNumber.CannotOpenFormat;
} }
if(MainClass.Verbose) if(verbose)
{ {
ImageInfo.PrintImageInfo(imageFormat); ImageInfo.PrintImageInfo(imageFormat);
DicConsole.WriteLine(); DicConsole.WriteLine();
@@ -171,52 +174,62 @@ namespace DiscImageChef.Commands
DicConsole.ErrorWriteLine("Unable to open image format"); DicConsole.ErrorWriteLine("Unable to open image format");
DicConsole.ErrorWriteLine("Error: {0}", ex.Message); DicConsole.ErrorWriteLine("Error: {0}", ex.Message);
DicConsole.DebugWriteLine("Analyze command", "Stack trace: {0}", ex.StackTrace); DicConsole.DebugWriteLine("Analyze command", "Stack trace: {0}", ex.StackTrace);
return (int)ErrorNumber.CannotOpenFormat;
return(int)ErrorNumber.CannotOpenFormat;
} }
List<string> idPlugins; List<string> idPlugins;
IFilesystem plugin; IFilesystem plugin;
string information; string information;
if(searchForPartitions)
{
List<Partition> partitions = Core.Partitions.GetAll(imageFormat);
Core.Partitions.AddSchemesToStats(partitions);
if(partitions.Count == 0) if(partitions)
{
List<Partition> partitionsList = Core.Partitions.GetAll(imageFormat);
Core.Partitions.AddSchemesToStats(partitionsList);
if(partitionsList.Count == 0)
{ {
DicConsole.DebugWriteLine("Analyze command", "No partitions found"); DicConsole.DebugWriteLine("Analyze command", "No partitions found");
if(!searchForFilesystems)
if(!filesystems)
{ {
DicConsole.WriteLine("No partitions founds, not searching for filesystems"); DicConsole.WriteLine("No partitions founds, not searching for filesystems");
return (int)ErrorNumber.NothingFound;
return(int)ErrorNumber.NothingFound;
} }
checkraw = true; checkRaw = true;
} }
else else
{ {
DicConsole.WriteLine("{0} partitions found.", partitions.Count); DicConsole.WriteLine("{0} partitions found.", partitionsList.Count);
for(int i = 0; i < partitions.Count; i++) for(int i = 0; i < partitionsList.Count; i++)
{ {
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Partition {0}:", partitions[i].Sequence); DicConsole.WriteLine("Partition {0}:", partitionsList[i].Sequence);
DicConsole.WriteLine("Partition name: {0}", partitions[i].Name); DicConsole.WriteLine("Partition name: {0}", partitionsList[i].Name);
DicConsole.WriteLine("Partition type: {0}", partitions[i].Type); DicConsole.WriteLine("Partition type: {0}", partitionsList[i].Type);
DicConsole.WriteLine("Partition start: sector {0}, byte {1}", partitions[i].Start,
partitions[i].Offset);
DicConsole.WriteLine("Partition length: {0} sectors, {1} bytes", partitions[i].Length,
partitions[i].Size);
DicConsole.WriteLine("Partition scheme: {0}", partitions[i].Scheme);
DicConsole.WriteLine("Partition description:");
DicConsole.WriteLine(partitions[i].Description);
if(!searchForFilesystems) continue; DicConsole.WriteLine("Partition start: sector {0}, byte {1}", partitionsList[i].Start,
partitionsList[i].Offset);
DicConsole.WriteLine("Partition length: {0} sectors, {1} bytes", partitionsList[i].Length,
partitionsList[i].Size);
DicConsole.WriteLine("Partition scheme: {0}", partitionsList[i].Scheme);
DicConsole.WriteLine("Partition description:");
DicConsole.WriteLine(partitionsList[i].Description);
if(!filesystems)
continue;
DicConsole.WriteLine("Identifying filesystem on partition"); DicConsole.WriteLine("Identifying filesystem on partition");
Core.Filesystems.Identify(imageFormat, out idPlugins, partitions[i]); Core.Filesystems.Identify(imageFormat, out idPlugins, partitionsList[i]);
if(idPlugins.Count == 0) DicConsole.WriteLine("Filesystem not identified");
if(idPlugins.Count == 0)
DicConsole.WriteLine("Filesystem not identified");
else if(idPlugins.Count > 1) else if(idPlugins.Count > 1)
{ {
DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins"); DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins");
@@ -225,7 +238,10 @@ namespace DiscImageChef.Commands
if(plugins.PluginsList.TryGetValue(pluginName, out plugin)) if(plugins.PluginsList.TryGetValue(pluginName, out plugin))
{ {
DicConsole.WriteLine($"As identified by {plugin.Name}."); DicConsole.WriteLine($"As identified by {plugin.Name}.");
plugin.GetInformation(imageFormat, partitions[i], out information, encoding);
plugin.GetInformation(imageFormat, partitionsList[i], out information,
encodingClass);
DicConsole.Write(information); DicConsole.Write(information);
Statistics.AddFilesystem(plugin.XmlFsType.Type); Statistics.AddFilesystem(plugin.XmlFsType.Type);
} }
@@ -233,10 +249,12 @@ namespace DiscImageChef.Commands
else else
{ {
plugins.PluginsList.TryGetValue(idPlugins[0], out plugin); plugins.PluginsList.TryGetValue(idPlugins[0], out plugin);
if(plugin == null) continue;
if(plugin == null)
continue;
DicConsole.WriteLine($"Identified by {plugin.Name}."); DicConsole.WriteLine($"Identified by {plugin.Name}.");
plugin.GetInformation(imageFormat, partitions[i], out information, encoding); plugin.GetInformation(imageFormat, partitionsList[i], out information, encodingClass);
DicConsole.Write("{0}", information); DicConsole.Write("{0}", information);
Statistics.AddFilesystem(plugin.XmlFsType.Type); Statistics.AddFilesystem(plugin.XmlFsType.Type);
} }
@@ -244,17 +262,18 @@ namespace DiscImageChef.Commands
} }
} }
if(checkraw) if(checkRaw)
{ {
Partition wholePart = new Partition var wholePart = new Partition
{ {
Name = "Whole device", Name = "Whole device", Length = imageFormat.Info.Sectors,
Length = imageFormat.Info.Sectors, Size = imageFormat.Info.Sectors * imageFormat.Info.SectorSize
Size = imageFormat.Info.Sectors * imageFormat.Info.SectorSize
}; };
Core.Filesystems.Identify(imageFormat, out idPlugins, wholePart); Core.Filesystems.Identify(imageFormat, out idPlugins, wholePart);
if(idPlugins.Count == 0) DicConsole.WriteLine("Filesystem not identified");
if(idPlugins.Count == 0)
DicConsole.WriteLine("Filesystem not identified");
else if(idPlugins.Count > 1) else if(idPlugins.Count > 1)
{ {
DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins"); DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins");
@@ -263,7 +282,7 @@ namespace DiscImageChef.Commands
if(plugins.PluginsList.TryGetValue(pluginName, out plugin)) if(plugins.PluginsList.TryGetValue(pluginName, out plugin))
{ {
DicConsole.WriteLine($"As identified by {plugin.Name}."); DicConsole.WriteLine($"As identified by {plugin.Name}.");
plugin.GetInformation(imageFormat, wholePart, out information, encoding); plugin.GetInformation(imageFormat, wholePart, out information, encodingClass);
DicConsole.Write(information); DicConsole.Write(information);
Statistics.AddFilesystem(plugin.XmlFsType.Type); Statistics.AddFilesystem(plugin.XmlFsType.Type);
} }
@@ -271,10 +290,11 @@ namespace DiscImageChef.Commands
else else
{ {
plugins.PluginsList.TryGetValue(idPlugins[0], out plugin); plugins.PluginsList.TryGetValue(idPlugins[0], out plugin);
if(plugin != null) if(plugin != null)
{ {
DicConsole.WriteLine($"Identified by {plugin.Name}."); DicConsole.WriteLine($"Identified by {plugin.Name}.");
plugin.GetInformation(imageFormat, wholePart, out information, encoding); plugin.GetInformation(imageFormat, wholePart, out information, encodingClass);
DicConsole.Write(information); DicConsole.Write(information);
Statistics.AddFilesystem(plugin.XmlFsType.Type); Statistics.AddFilesystem(plugin.XmlFsType.Type);
} }
@@ -285,10 +305,11 @@ namespace DiscImageChef.Commands
{ {
DicConsole.ErrorWriteLine($"Error reading file: {ex.Message}"); DicConsole.ErrorWriteLine($"Error reading file: {ex.Message}");
DicConsole.DebugWriteLine("Analyze command", ex.StackTrace); DicConsole.DebugWriteLine("Analyze command", ex.StackTrace);
return (int)ErrorNumber.UnexpectedException;
return(int)ErrorNumber.UnexpectedException;
} }
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
} }
} }

View File

@@ -31,58 +31,56 @@
// ****************************************************************************/ // ****************************************************************************/
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using Mono.Options;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class BenchmarkCommand : Command internal class BenchmarkCommand : Command
{ {
int blockSize = 512;
int bufferSize = 128;
bool showHelp;
public BenchmarkCommand() : base("benchmark", "Benchmarks hashing and entropy calculation.") public BenchmarkCommand() : base("benchmark", "Benchmarks hashing and entropy calculation.")
{ {
Options = new OptionSet Add(new Option(new[]
{
"--block-size", "-b"
}, "Block size.")
{
Argument = new Argument<int>(() => 512), Required = false
});
Add(new Option(new[]
{
"--buffer-size", "-s"
}, "Buffer size in mebibytes.")
{
Argument = new Argument<int>(() => 128), Required = false
});
AddArgument(new Argument<string>
{ {
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", Arity = ArgumentArity.ExactlyOne, Description = "Disc image path", Name = "image-path"
$"{MainClass.AssemblyCopyright}", });
"",
$"usage: DiscImageChef {Name} [OPTIONS]", Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
"",
Help,
{"block-size|b=", "Block size.", (int i) => blockSize = i},
{"buffer-size|s=", "Buffer size in mebibytes.", (int i) => bufferSize = i},
{"help|h|?", "Show this message and exit.", v => showHelp = v != null}
};
} }
public override int Invoke(IEnumerable<string> arguments) static int Invoke(bool debug, bool verbose, int blockSize, int bufferSize)
{ {
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("benchmark"); Statistics.AddCommand("benchmark");
if(extra.Count != 0) DicConsole.DebugWriteLine("Benchmark command", "--debug={0}", debug);
{ DicConsole.DebugWriteLine("Benchmark command", "--verbose={0}", verbose);
DicConsole.ErrorWriteLine("Too many arguments.");
return (int)ErrorNumber.UnexpectedArgumentCount;
}
DicConsole.DebugWriteLine("Benchmark command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("Benchmark command", "--verbose={0}", MainClass.Verbose);
Benchmark.InitProgressEvent += Progress.InitProgress; Benchmark.InitProgressEvent += Progress.InitProgress;
Benchmark.UpdateProgressEvent += Progress.UpdateProgress; Benchmark.UpdateProgressEvent += Progress.UpdateProgress;
@@ -92,8 +90,10 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Took {0} seconds to fill buffer, {1:F3} MiB/sec.", results.FillTime, DicConsole.WriteLine("Took {0} seconds to fill buffer, {1:F3} MiB/sec.", results.FillTime,
results.FillSpeed); results.FillSpeed);
DicConsole.WriteLine("Took {0} seconds to read buffer, {1:F3} MiB/sec.", results.ReadTime, DicConsole.WriteLine("Took {0} seconds to read buffer, {1:F3} MiB/sec.", results.ReadTime,
results.ReadSpeed); results.ReadSpeed);
DicConsole.WriteLine("Took {0} seconds to entropy buffer, {1:F3} MiB/sec.", results.EntropyTime, DicConsole.WriteLine("Took {0} seconds to entropy buffer, {1:F3} MiB/sec.", results.EntropyTime,
results.EntropySpeed); results.EntropySpeed);
@@ -103,6 +103,7 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Took {0} seconds to do all algorithms at the same time, {1:F3} MiB/sec.", DicConsole.WriteLine("Took {0} seconds to do all algorithms at the same time, {1:F3} MiB/sec.",
results.TotalTime, results.TotalSpeed); results.TotalTime, results.TotalSpeed);
DicConsole.WriteLine("Took {0} seconds to do all algorithms sequentially, {1:F3} MiB/sec.", DicConsole.WriteLine("Took {0} seconds to do all algorithms sequentially, {1:F3} MiB/sec.",
results.SeparateTime, results.SeparateSpeed); results.SeparateTime, results.SeparateSpeed);
@@ -110,7 +111,7 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Max memory used is {0} bytes", results.MaxMemory); DicConsole.WriteLine("Max memory used is {0} bytes", results.MaxMemory);
DicConsole.WriteLine("Min memory used is {0} bytes", results.MinMemory); DicConsole.WriteLine("Min memory used is {0} bytes", results.MinMemory);
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
} }
} }

View File

@@ -32,121 +32,167 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.CommonTypes.Structs; using DiscImageChef.CommonTypes.Structs;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using Mono.Options;
using Schemas; using Schemas;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class ChecksumCommand : Command internal class ChecksumCommand : Command
{ {
// How many sectors to read at once // How many sectors to read at once
const uint SECTORS_TO_READ = 256; const uint SECTORS_TO_READ = 256;
bool doAdler32 = true;
bool doCrc16 = true;
bool doCrc32 = true;
bool doCrc64;
bool doFletcher16;
bool doFletcher32;
bool doMd5 = true;
bool doSha1 = true;
bool doSha256;
bool doSha384;
bool doSha512;
bool doSpamSum = true;
string inputFile;
bool separatedTracks = true;
bool showHelp;
bool wholeDisc = true;
public ChecksumCommand() : base("checksum", "Checksums an image.") public ChecksumCommand() : base("checksum", "Checksums an image.")
{ {
Options = new OptionSet Add(new Option(new[]
{
"--adler32", "-a"
}, "Calculates Adler32.")
{
Argument = new Argument<bool>(() => true), Required = false
});
Add(new Option("--crc16", "Calculates CRC16.")
{ {
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", Argument = new Argument<bool>(() => true), Required = false
$"{MainClass.AssemblyCopyright}", });
"",
$"usage: DiscImageChef {Name} [OPTIONS] imagefile", Add(new Option(new[]
"", {
Help, "--crc32", "-c"
{"adler32|a", "Calculates Adler-32.", b => doAdler32 = b != null}, }, "Calculates CRC32.")
{"crc16", "Calculates CRC16.", b => doCrc16 = b != null}, {
{"crc32|c", "Calculates CRC32.", b => doCrc32 = b != null}, Argument = new Argument<bool>(() => true), Required = false
{"crc64", "Calculates CRC64 (ECMA).", b => doCrc64 = b != null}, });
{"fletcher16", "Calculates Fletcher-16.", b => doFletcher16 = b != null},
{"fletcher32", "Calculates Fletcher-32.", b => doFletcher32 = b != null}, Add(new Option("--crc64", "Calculates CRC64.")
{"md5|m", "Calculates MD5.", b => doMd5 = b != null}, {
{"separated-tracks|t", "Checksums each track separately.", b => separatedTracks = b != null}, Argument = new Argument<bool>(() => true), Required = false
{"sha1|s", "Calculates SHA1.", b => doSha1 = b != null}, });
{"sha256", "Calculates SHA256.", b => doSha256 = b != null},
{"sha384", "Calculates SHA384.", b => doSha384 = b != null}, Add(new Option("--fletcher16", "Calculates Fletcher-16.")
{"sha512", "Calculates SHA512.", b => doSha512 = b != null}, {
{"spamsum|f", "Calculates SpamSum fuzzy hash.", b => doSpamSum = b != null}, Argument = new Argument<bool>(() => true), Required = false
{"whole-disc|w", "Checksums the whole disc.", b => wholeDisc = b != null}, });
{"help|h|?", "Show this message and exit.", v => showHelp = v != null}
}; Add(new Option("--fletcher32", "Calculates Fletcher-32.")
{
Argument = new Argument<bool>(() => true), Required = false
});
Add(new Option(new[]
{
"--md5", "-m"
}, "Calculates MD5.")
{
Argument = new Argument<bool>(() => true), Required = false
});
Add(new Option(new[]
{
"--separated-tracks", "-t"
}, "Checksums each track separately.")
{
Argument = new Argument<bool>(() => true), Required = false
});
Add(new Option(new[]
{
"--sha1", "-s"
}, "Calculates SHA1.")
{
Argument = new Argument<bool>(() => true), Required = false
});
Add(new Option(new[]
{
"--sha256", "-a"
}, "Calculates SHA256.")
{
Argument = new Argument<bool>(() => true), Required = false
});
Add(new Option("--sha384", "Calculates SHA384.")
{
Argument = new Argument<bool>(() => true), Required = false
});
Add(new Option("--sha512", "Calculates SHA512.")
{
Argument = new Argument<bool>(() => true), Required = false
});
Add(new Option(new[]
{
"--spamsum", "-f"
}, "Calculates SpamSum fuzzy hash.")
{
Argument = new Argument<bool>(() => true), Required = false
});
Add(new Option(new[]
{
"--whole-disc", "-w"
}, "Checksums the whole disc.")
{
Argument = new Argument<bool>(() => true), Required = false
});
AddArgument(new Argument<string>
{
Arity = ArgumentArity.ExactlyOne, Description = "Media image path", Name = "image-path"
});
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
} }
public override int Invoke(IEnumerable<string> arguments) static int Invoke(bool debug, bool verbose, bool adler32, bool crc16, bool crc32, bool crc64, bool fletcher16,
bool fletcher32, bool md5, bool sha1, bool sha256, bool sha384, bool sha512, bool spamSum,
string imagePath, bool separatedTracks, bool wholeDisc)
{ {
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("checksum"); Statistics.AddCommand("checksum");
if(extra.Count > 1) DicConsole.DebugWriteLine("Checksum command", "--adler32={0}", adler32);
{ DicConsole.DebugWriteLine("Checksum command", "--crc16={0}", crc16);
DicConsole.ErrorWriteLine("Too many arguments."); DicConsole.DebugWriteLine("Checksum command", "--crc32={0}", crc32);
return (int)ErrorNumber.UnexpectedArgumentCount; DicConsole.DebugWriteLine("Checksum command", "--crc64={0}", crc64);
} DicConsole.DebugWriteLine("Checksum command", "--debug={0}", debug);
DicConsole.DebugWriteLine("Checksum command", "--fletcher16={0}", fletcher16);
if(extra.Count == 0) DicConsole.DebugWriteLine("Checksum command", "--fletcher32={0}", fletcher32);
{ DicConsole.DebugWriteLine("Checksum command", "--input={0}", imagePath);
DicConsole.ErrorWriteLine("Missing input image."); DicConsole.DebugWriteLine("Checksum command", "--md5={0}", md5);
return (int)ErrorNumber.MissingArgument;
}
inputFile = extra[0];
DicConsole.DebugWriteLine("Checksum command", "--adler32={0}", doAdler32);
DicConsole.DebugWriteLine("Checksum command", "--crc16={0}", doCrc16);
DicConsole.DebugWriteLine("Checksum command", "--crc32={0}", doCrc32);
DicConsole.DebugWriteLine("Checksum command", "--crc64={0}", doCrc64);
DicConsole.DebugWriteLine("Checksum command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("Checksum command", "--fletcher16={0}", doFletcher16);
DicConsole.DebugWriteLine("Checksum command", "--fletcher32={0}", doFletcher32);
DicConsole.DebugWriteLine("Checksum command", "--input={0}", inputFile);
DicConsole.DebugWriteLine("Checksum command", "--md5={0}", doMd5);
DicConsole.DebugWriteLine("Checksum command", "--separated-tracks={0}", separatedTracks); DicConsole.DebugWriteLine("Checksum command", "--separated-tracks={0}", separatedTracks);
DicConsole.DebugWriteLine("Checksum command", "--sha1={0}", doSha1); DicConsole.DebugWriteLine("Checksum command", "--sha1={0}", sha1);
DicConsole.DebugWriteLine("Checksum command", "--sha256={0}", doSha256); DicConsole.DebugWriteLine("Checksum command", "--sha256={0}", sha256);
DicConsole.DebugWriteLine("Checksum command", "--sha384={0}", doSha384); DicConsole.DebugWriteLine("Checksum command", "--sha384={0}", sha384);
DicConsole.DebugWriteLine("Checksum command", "--sha512={0}", doSha512); DicConsole.DebugWriteLine("Checksum command", "--sha512={0}", sha512);
DicConsole.DebugWriteLine("Checksum command", "--spamsum={0}", doSpamSum); DicConsole.DebugWriteLine("Checksum command", "--spamsum={0}", spamSum);
DicConsole.DebugWriteLine("Checksum command", "--verbose={0}", MainClass.Verbose); DicConsole.DebugWriteLine("Checksum command", "--verbose={0}", verbose);
DicConsole.DebugWriteLine("Checksum command", "--whole-disc={0}", wholeDisc); DicConsole.DebugWriteLine("Checksum command", "--whole-disc={0}", wholeDisc);
FiltersList filtersList = new FiltersList(); var filtersList = new FiltersList();
IFilter inputFilter = filtersList.GetFilter(inputFile); IFilter inputFilter = filtersList.GetFilter(imagePath);
if(inputFilter == null) if(inputFilter == null)
{ {
DicConsole.ErrorWriteLine("Cannot open specified file."); DicConsole.ErrorWriteLine("Cannot open specified file.");
return (int)ErrorNumber.CannotOpenFile;
return(int)ErrorNumber.CannotOpenFile;
} }
IMediaImage inputFormat = ImageFormat.Detect(inputFilter); IMediaImage inputFormat = ImageFormat.Detect(inputFilter);
@@ -154,27 +200,51 @@ namespace DiscImageChef.Commands
if(inputFormat == null) if(inputFormat == null)
{ {
DicConsole.ErrorWriteLine("Unable to recognize image format, not checksumming"); DicConsole.ErrorWriteLine("Unable to recognize image format, not checksumming");
return (int)ErrorNumber.UnrecognizedFormat;
return(int)ErrorNumber.UnrecognizedFormat;
} }
inputFormat.Open(inputFilter); inputFormat.Open(inputFilter);
Statistics.AddMediaFormat(inputFormat.Format); Statistics.AddMediaFormat(inputFormat.Format);
Statistics.AddMedia(inputFormat.Info.MediaType, false); Statistics.AddMedia(inputFormat.Info.MediaType, false);
Statistics.AddFilter(inputFilter.Name); Statistics.AddFilter(inputFilter.Name);
EnableChecksum enabledChecksums = new EnableChecksum(); var enabledChecksums = new EnableChecksum();
if(doAdler32) enabledChecksums |= EnableChecksum.Adler32; if(adler32)
if(doCrc16) enabledChecksums |= EnableChecksum.Crc16; enabledChecksums |= EnableChecksum.Adler32;
if(doCrc32) enabledChecksums |= EnableChecksum.Crc32;
if(doCrc64) enabledChecksums |= EnableChecksum.Crc64; if(crc16)
if(doMd5) enabledChecksums |= EnableChecksum.Md5; enabledChecksums |= EnableChecksum.Crc16;
if(doSha1) enabledChecksums |= EnableChecksum.Sha1;
if(doSha256) enabledChecksums |= EnableChecksum.Sha256; if(crc32)
if(doSha384) enabledChecksums |= EnableChecksum.Sha384; enabledChecksums |= EnableChecksum.Crc32;
if(doSha512) enabledChecksums |= EnableChecksum.Sha512;
if(doSpamSum) enabledChecksums |= EnableChecksum.SpamSum; if(crc64)
if(doFletcher16) enabledChecksums |= EnableChecksum.Fletcher16; enabledChecksums |= EnableChecksum.Crc64;
if(doFletcher32) enabledChecksums |= EnableChecksum.Fletcher32;
if(md5)
enabledChecksums |= EnableChecksum.Md5;
if(sha1)
enabledChecksums |= EnableChecksum.Sha1;
if(sha256)
enabledChecksums |= EnableChecksum.Sha256;
if(sha384)
enabledChecksums |= EnableChecksum.Sha384;
if(sha512)
enabledChecksums |= EnableChecksum.Sha512;
if(spamSum)
enabledChecksums |= EnableChecksum.SpamSum;
if(fletcher16)
enabledChecksums |= EnableChecksum.Fletcher16;
if(fletcher32)
enabledChecksums |= EnableChecksum.Fletcher32;
Checksum mediaChecksum = null; Checksum mediaChecksum = null;
@@ -185,11 +255,13 @@ namespace DiscImageChef.Commands
{ {
Checksum trackChecksum = null; Checksum trackChecksum = null;
if(wholeDisc) mediaChecksum = new Checksum(enabledChecksums); if(wholeDisc)
mediaChecksum = new Checksum(enabledChecksums);
ulong previousTrackEnd = 0; ulong previousTrackEnd = 0;
List<Track> inputTracks = opticalInput.Tracks; List<Track> inputTracks = opticalInput.Tracks;
foreach(Track currentTrack in inputTracks) foreach(Track currentTrack in inputTracks)
{ {
if(currentTrack.TrackStartSector - previousTrackEnd != 0 && wholeDisc) if(currentTrack.TrackStartSector - previousTrackEnd != 0 && wholeDisc)
@@ -207,9 +279,10 @@ namespace DiscImageChef.Commands
currentTrack.TrackSequence, currentTrack.TrackStartSector, currentTrack.TrackSequence, currentTrack.TrackStartSector,
currentTrack.TrackEndSector); currentTrack.TrackEndSector);
if(separatedTracks) trackChecksum = new Checksum(enabledChecksums); if(separatedTracks)
trackChecksum = new Checksum(enabledChecksums);
ulong sectors = currentTrack.TrackEndSector - currentTrack.TrackStartSector + 1; ulong sectors = (currentTrack.TrackEndSector - currentTrack.TrackStartSector) + 1;
ulong doneSectors = 0; ulong doneSectors = 0;
DicConsole.WriteLine("Track {0} has {1} sectors", currentTrack.TrackSequence, sectors); DicConsole.WriteLine("Track {0} has {1} sectors", currentTrack.TrackSequence, sectors);
@@ -221,22 +294,28 @@ namespace DiscImageChef.Commands
{ {
sector = opticalInput.ReadSectors(doneSectors, SECTORS_TO_READ, sector = opticalInput.ReadSectors(doneSectors, SECTORS_TO_READ,
currentTrack.TrackSequence); currentTrack.TrackSequence);
DicConsole.Write("\rHashings sectors {0} to {2} of track {1}", doneSectors,
DicConsole.Write("\rHashing sectors {0} to {2} of track {1}", doneSectors,
currentTrack.TrackSequence, doneSectors + SECTORS_TO_READ); currentTrack.TrackSequence, doneSectors + SECTORS_TO_READ);
doneSectors += SECTORS_TO_READ; doneSectors += SECTORS_TO_READ;
} }
else else
{ {
sector = opticalInput.ReadSectors(doneSectors, (uint)(sectors - doneSectors), sector = opticalInput.ReadSectors(doneSectors, (uint)(sectors - doneSectors),
currentTrack.TrackSequence); currentTrack.TrackSequence);
DicConsole.Write("\rHashings sectors {0} to {2} of track {1}", doneSectors,
DicConsole.Write("\rHashing sectors {0} to {2} of track {1}", doneSectors,
currentTrack.TrackSequence, doneSectors + (sectors - doneSectors)); currentTrack.TrackSequence, doneSectors + (sectors - doneSectors));
doneSectors += sectors - doneSectors; doneSectors += sectors - doneSectors;
} }
if(wholeDisc) mediaChecksum?.Update(sector); if(wholeDisc)
mediaChecksum?.Update(sector);
if(separatedTracks) trackChecksum?.Update(sector); if(separatedTracks)
trackChecksum?.Update(sector);
} }
DicConsole.WriteLine(); DicConsole.WriteLine();
@@ -266,8 +345,10 @@ namespace DiscImageChef.Commands
} }
catch(Exception ex) catch(Exception ex)
{ {
if(MainClass.Debug) DicConsole.DebugWriteLine("Could not get tracks because {0}", ex.Message); if(debug)
else DicConsole.WriteLine("Unable to get separate tracks, not checksumming them"); DicConsole.DebugWriteLine("Could not get tracks because {0}", ex.Message);
else
DicConsole.WriteLine("Unable to get separate tracks, not checksumming them");
} }
break; break;
@@ -276,7 +357,8 @@ namespace DiscImageChef.Commands
{ {
Checksum trackChecksum = null; Checksum trackChecksum = null;
if(wholeDisc) mediaChecksum = new Checksum(enabledChecksums); if(wholeDisc)
mediaChecksum = new Checksum(enabledChecksums);
ulong previousTrackEnd = 0; ulong previousTrackEnd = 0;
@@ -296,9 +378,10 @@ namespace DiscImageChef.Commands
"Track {0} starts at sector {1} and ends at block {2}", "Track {0} starts at sector {1} and ends at block {2}",
currentFile.File, currentFile.FirstBlock, currentFile.LastBlock); currentFile.File, currentFile.FirstBlock, currentFile.LastBlock);
if(separatedTracks) trackChecksum = new Checksum(enabledChecksums); if(separatedTracks)
trackChecksum = new Checksum(enabledChecksums);
ulong sectors = currentFile.LastBlock - currentFile.FirstBlock + 1; ulong sectors = (currentFile.LastBlock - currentFile.FirstBlock) + 1;
ulong doneSectors = 0; ulong doneSectors = 0;
DicConsole.WriteLine("File {0} has {1} sectors", currentFile.File, sectors); DicConsole.WriteLine("File {0} has {1} sectors", currentFile.File, sectors);
@@ -309,22 +392,28 @@ namespace DiscImageChef.Commands
if(sectors - doneSectors >= SECTORS_TO_READ) if(sectors - doneSectors >= SECTORS_TO_READ)
{ {
sector = tapeImage.ReadSectors(doneSectors + currentFile.FirstBlock, SECTORS_TO_READ); sector = tapeImage.ReadSectors(doneSectors + currentFile.FirstBlock, SECTORS_TO_READ);
DicConsole.Write("\rHashings blocks {0} to {2} of file {1}", doneSectors,
DicConsole.Write("\rHashing blocks {0} to {2} of file {1}", doneSectors,
currentFile.File, doneSectors + SECTORS_TO_READ); currentFile.File, doneSectors + SECTORS_TO_READ);
doneSectors += SECTORS_TO_READ; doneSectors += SECTORS_TO_READ;
} }
else else
{ {
sector = tapeImage.ReadSectors(doneSectors + currentFile.FirstBlock, sector = tapeImage.ReadSectors(doneSectors + currentFile.FirstBlock,
(uint)(sectors - doneSectors)); (uint)(sectors - doneSectors));
DicConsole.Write("\rHashings blocks {0} to {2} of file {1}", doneSectors,
DicConsole.Write("\rHashing blocks {0} to {2} of file {1}", doneSectors,
currentFile.File, doneSectors + (sectors - doneSectors)); currentFile.File, doneSectors + (sectors - doneSectors));
doneSectors += sectors - doneSectors; doneSectors += sectors - doneSectors;
} }
if(wholeDisc) mediaChecksum?.Update(sector); if(wholeDisc)
mediaChecksum?.Update(sector);
if(separatedTracks) trackChecksum?.Update(sector); if(separatedTracks)
trackChecksum?.Update(sector);
} }
DicConsole.WriteLine(); DicConsole.WriteLine();
@@ -350,6 +439,7 @@ namespace DiscImageChef.Commands
if(mediaChecksum != null) if(mediaChecksum != null)
foreach(ChecksumType chk in mediaChecksum.End()) foreach(ChecksumType chk in mediaChecksum.End())
DicConsole.WriteLine("Tape's {0}: {1}", chk.type, chk.Value); DicConsole.WriteLine("Tape's {0}: {1}", chk.type, chk.Value);
break; break;
} }
@@ -368,15 +458,19 @@ namespace DiscImageChef.Commands
if(sectors - doneSectors >= SECTORS_TO_READ) if(sectors - doneSectors >= SECTORS_TO_READ)
{ {
sector = inputFormat.ReadSectors(doneSectors, SECTORS_TO_READ); sector = inputFormat.ReadSectors(doneSectors, SECTORS_TO_READ);
DicConsole.Write("\rHashings sectors {0} to {1}", doneSectors,
DicConsole.Write("\rHashing sectors {0} to {1}", doneSectors,
doneSectors + SECTORS_TO_READ); doneSectors + SECTORS_TO_READ);
doneSectors += SECTORS_TO_READ; doneSectors += SECTORS_TO_READ;
} }
else else
{ {
sector = inputFormat.ReadSectors(doneSectors, (uint)(sectors - doneSectors)); sector = inputFormat.ReadSectors(doneSectors, (uint)(sectors - doneSectors));
DicConsole.Write("\rHashings sectors {0} to {1}", doneSectors,
DicConsole.Write("\rHashing sectors {0} to {1}", doneSectors,
doneSectors + (sectors - doneSectors)); doneSectors + (sectors - doneSectors));
doneSectors += sectors - doneSectors; doneSectors += sectors - doneSectors;
} }
@@ -387,11 +481,12 @@ namespace DiscImageChef.Commands
foreach(ChecksumType chk in mediaChecksum.End()) foreach(ChecksumType chk in mediaChecksum.End())
DicConsole.WriteLine("Disk's {0}: {1}", chk.type, chk.Value); DicConsole.WriteLine("Disk's {0}: {1}", chk.type, chk.Value);
break; break;
} }
} }
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
} }
} }

View File

@@ -32,6 +32,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.Text; using System.Text;
using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
@@ -39,81 +41,61 @@ using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.CommonTypes.Structs; using DiscImageChef.CommonTypes.Structs;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using Mono.Options;
using ImageInfo = DiscImageChef.CommonTypes.Structs.ImageInfo; using ImageInfo = DiscImageChef.CommonTypes.Structs.ImageInfo;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class CompareCommand : Command internal class CompareCommand : Command
{ {
string inputFile1;
string inputFile2;
bool showHelp;
public CompareCommand() : base("compare", "Compares two disc images.") public CompareCommand() : base("compare", "Compares two disc images.")
{ {
Options = new OptionSet AddArgument(new Argument<string>
{ {
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", Arity = ArgumentArity.ExactlyOne, Description = "First media image path", Name = "image-path1"
$"{MainClass.AssemblyCopyright}", });
"",
$"usage: DiscImageChef {Name} imagefile1 imagefile2", AddArgument(new Argument<string>
"", {
Help, Arity = ArgumentArity.ExactlyOne, Description = "Second media image path", Name = "image-path2"
{"help|h|?", "Show this message and exit.", v => showHelp = v != null} });
};
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
} }
public override int Invoke(IEnumerable<string> arguments) static int Invoke(bool debug, bool verbose, string imagePath1, string imagePath2)
{ {
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("compare"); Statistics.AddCommand("compare");
if(extra.Count > 2) DicConsole.DebugWriteLine("Compare command", "--debug={0}", debug);
{ DicConsole.DebugWriteLine("Compare command", "--input1={0}", imagePath1);
DicConsole.ErrorWriteLine("Too many arguments."); DicConsole.DebugWriteLine("Compare command", "--input2={0}", imagePath2);
return (int)ErrorNumber.UnexpectedArgumentCount; DicConsole.DebugWriteLine("Compare command", "--verbose={0}", verbose);
}
if(extra.Count <= 1) var filtersList = new FiltersList();
{ IFilter inputFilter1 = filtersList.GetFilter(imagePath1);
DicConsole.ErrorWriteLine("Missing input image.");
return (int)ErrorNumber.MissingArgument;
}
inputFile1 = extra[0];
inputFile2 = extra[1];
DicConsole.DebugWriteLine("Compare command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("Compare command", "--input1={0}", inputFile1);
DicConsole.DebugWriteLine("Compare command", "--input2={0}", inputFile2);
DicConsole.DebugWriteLine("Compare command", "--verbose={0}", MainClass.Verbose);
FiltersList filtersList = new FiltersList();
IFilter inputFilter1 = filtersList.GetFilter(inputFile1);
filtersList = new FiltersList(); filtersList = new FiltersList();
IFilter inputFilter2 = filtersList.GetFilter(inputFile2); IFilter inputFilter2 = filtersList.GetFilter(imagePath2);
if(inputFilter1 == null) if(inputFilter1 == null)
{ {
DicConsole.ErrorWriteLine("Cannot open input file 1"); DicConsole.ErrorWriteLine("Cannot open input file 1");
return (int)ErrorNumber.CannotOpenFile;
return(int)ErrorNumber.CannotOpenFile;
} }
if(inputFilter2 == null) if(inputFilter2 == null)
{ {
DicConsole.ErrorWriteLine("Cannot open input file 2"); DicConsole.ErrorWriteLine("Cannot open input file 2");
return (int)ErrorNumber.CannotOpenFile;
return(int)ErrorNumber.CannotOpenFile;
} }
IMediaImage input1Format = ImageFormat.Detect(inputFilter1); IMediaImage input1Format = ImageFormat.Detect(inputFilter1);
@@ -122,24 +104,28 @@ namespace DiscImageChef.Commands
if(input1Format == null) if(input1Format == null)
{ {
DicConsole.ErrorWriteLine("Input file 1 format not identified, not proceeding with comparison."); DicConsole.ErrorWriteLine("Input file 1 format not identified, not proceeding with comparison.");
return (int)ErrorNumber.UnrecognizedFormat;
return(int)ErrorNumber.UnrecognizedFormat;
} }
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLine("Input file 1 format identified by {0} ({1}).", input1Format.Name, DicConsole.VerboseWriteLine("Input file 1 format identified by {0} ({1}).", input1Format.Name,
input1Format.Id); input1Format.Id);
else DicConsole.WriteLine("Input file 1 format identified by {0}.", input1Format.Name); else
DicConsole.WriteLine("Input file 1 format identified by {0}.", input1Format.Name);
if(input2Format == null) if(input2Format == null)
{ {
DicConsole.ErrorWriteLine("Input file 2 format not identified, not proceeding with comparison."); DicConsole.ErrorWriteLine("Input file 2 format not identified, not proceeding with comparison.");
return (int)ErrorNumber.UnrecognizedFormat;
return(int)ErrorNumber.UnrecognizedFormat;
} }
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLine("Input file 2 format identified by {0} ({1}).", input2Format.Name, DicConsole.VerboseWriteLine("Input file 2 format identified by {0} ({1}).", input2Format.Name,
input2Format.Id); input2Format.Id);
else DicConsole.WriteLine("Input file 2 format identified by {0}.", input2Format.Name); else
DicConsole.WriteLine("Input file 2 format identified by {0}.", input2Format.Name);
input1Format.Open(inputFilter1); input1Format.Open(inputFilter1);
input2Format.Open(inputFilter2); input2Format.Open(inputFilter2);
@@ -151,19 +137,19 @@ namespace DiscImageChef.Commands
Statistics.AddFilter(inputFilter1.Name); Statistics.AddFilter(inputFilter1.Name);
Statistics.AddFilter(inputFilter2.Name); Statistics.AddFilter(inputFilter2.Name);
StringBuilder sb = new StringBuilder(); var sb = new StringBuilder();
if(MainClass.Verbose) if(verbose)
{ {
sb.AppendLine("\tDisc image 1\tDisc image 2"); sb.AppendLine("\tDisc image 1\tDisc image 2");
sb.AppendLine("================================"); sb.AppendLine("================================");
sb.AppendFormat("File\t{0}\t{1}", inputFile1, inputFile2).AppendLine(); sb.AppendFormat("File\t{0}\t{1}", imagePath1, imagePath2).AppendLine();
sb.AppendFormat("Disc image format\t{0}\t{1}", input1Format.Name, input2Format.Name).AppendLine(); sb.AppendFormat("Disc image format\t{0}\t{1}", input1Format.Name, input2Format.Name).AppendLine();
} }
else else
{ {
sb.AppendFormat("Disc image 1: {0}", inputFile1).AppendLine(); sb.AppendFormat("Disc image 1: {0}", imagePath1).AppendLine();
sb.AppendFormat("Disc image 2: {0}", inputFile2).AppendLine(); sb.AppendFormat("Disc image 2: {0}", imagePath2).AppendLine();
} }
bool imagesDiffer = false; bool imagesDiffer = false;
@@ -205,47 +191,66 @@ namespace DiscImageChef.Commands
#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
} }
if(MainClass.Verbose) if(verbose)
{ {
sb.AppendFormat("Has partitions?\t{0}\t{1}", image1Info.HasPartitions, image2Info.HasPartitions) sb.AppendFormat("Has partitions?\t{0}\t{1}", image1Info.HasPartitions, image2Info.HasPartitions).
.AppendLine(); AppendLine();
sb.AppendFormat("Has sessions?\t{0}\t{1}", image1Info.HasSessions, image2Info.HasSessions).AppendLine(); sb.AppendFormat("Has sessions?\t{0}\t{1}", image1Info.HasSessions, image2Info.HasSessions).AppendLine();
sb.AppendFormat("Image size\t{0}\t{1}", image1Info.ImageSize, image2Info.ImageSize).AppendLine(); sb.AppendFormat("Image size\t{0}\t{1}", image1Info.ImageSize, image2Info.ImageSize).AppendLine();
sb.AppendFormat("Sectors\t{0}\t{1}", image1Info.Sectors, image2Info.Sectors).AppendLine(); sb.AppendFormat("Sectors\t{0}\t{1}", image1Info.Sectors, image2Info.Sectors).AppendLine();
sb.AppendFormat("Sector size\t{0}\t{1}", image1Info.SectorSize, image2Info.SectorSize).AppendLine(); sb.AppendFormat("Sector size\t{0}\t{1}", image1Info.SectorSize, image2Info.SectorSize).AppendLine();
sb.AppendFormat("Creation time\t{0}\t{1}", image1Info.CreationTime, image2Info.CreationTime)
.AppendLine(); sb.AppendFormat("Creation time\t{0}\t{1}", image1Info.CreationTime, image2Info.CreationTime).
AppendLine();
sb.AppendFormat("Last modification time\t{0}\t{1}", image1Info.LastModificationTime, sb.AppendFormat("Last modification time\t{0}\t{1}", image1Info.LastModificationTime,
image2Info.LastModificationTime).AppendLine(); image2Info.LastModificationTime).AppendLine();
sb.AppendFormat("Disk type\t{0}\t{1}", image1Info.MediaType, image2Info.MediaType).AppendLine(); sb.AppendFormat("Disk type\t{0}\t{1}", image1Info.MediaType, image2Info.MediaType).AppendLine();
sb.AppendFormat("Image version\t{0}\t{1}", image1Info.Version, image2Info.Version).AppendLine(); sb.AppendFormat("Image version\t{0}\t{1}", image1Info.Version, image2Info.Version).AppendLine();
sb.AppendFormat("Image application\t{0}\t{1}", image1Info.Application, image2Info.Application)
.AppendLine(); sb.AppendFormat("Image application\t{0}\t{1}", image1Info.Application, image2Info.Application).
AppendLine();
sb.AppendFormat("Image application version\t{0}\t{1}", image1Info.ApplicationVersion, sb.AppendFormat("Image application version\t{0}\t{1}", image1Info.ApplicationVersion,
image2Info.ApplicationVersion).AppendLine(); image2Info.ApplicationVersion).AppendLine();
sb.AppendFormat("Image creator\t{0}\t{1}", image1Info.Creator, image2Info.Creator).AppendLine(); sb.AppendFormat("Image creator\t{0}\t{1}", image1Info.Creator, image2Info.Creator).AppendLine();
sb.AppendFormat("Image name\t{0}\t{1}", image1Info.MediaTitle, image2Info.MediaTitle).AppendLine(); sb.AppendFormat("Image name\t{0}\t{1}", image1Info.MediaTitle, image2Info.MediaTitle).AppendLine();
sb.AppendFormat("Image comments\t{0}\t{1}", image1Info.Comments, image2Info.Comments).AppendLine(); sb.AppendFormat("Image comments\t{0}\t{1}", image1Info.Comments, image2Info.Comments).AppendLine();
sb.AppendFormat("Disk manufacturer\t{0}\t{1}", image1Info.MediaManufacturer, sb.AppendFormat("Disk manufacturer\t{0}\t{1}", image1Info.MediaManufacturer,
image2Info.MediaManufacturer).AppendLine(); image2Info.MediaManufacturer).AppendLine();
sb.AppendFormat("Disk model\t{0}\t{1}", image1Info.MediaModel, image2Info.MediaModel).AppendLine(); sb.AppendFormat("Disk model\t{0}\t{1}", image1Info.MediaModel, image2Info.MediaModel).AppendLine();
sb.AppendFormat("Disk serial number\t{0}\t{1}", image1Info.MediaSerialNumber, sb.AppendFormat("Disk serial number\t{0}\t{1}", image1Info.MediaSerialNumber,
image2Info.MediaSerialNumber).AppendLine(); image2Info.MediaSerialNumber).AppendLine();
sb.AppendFormat("Disk barcode\t{0}\t{1}", image1Info.MediaBarcode, image2Info.MediaBarcode)
.AppendLine(); sb.AppendFormat("Disk barcode\t{0}\t{1}", image1Info.MediaBarcode, image2Info.MediaBarcode).
sb.AppendFormat("Disk part no.\t{0}\t{1}", image1Info.MediaPartNumber, image2Info.MediaPartNumber) AppendLine();
.AppendLine();
sb.AppendFormat("Disk sequence\t{0}\t{1}", image1Info.MediaSequence, image2Info.MediaSequence) sb.AppendFormat("Disk part no.\t{0}\t{1}", image1Info.MediaPartNumber, image2Info.MediaPartNumber).
.AppendLine(); AppendLine();
sb.AppendFormat("Disk sequence\t{0}\t{1}", image1Info.MediaSequence, image2Info.MediaSequence).
AppendLine();
sb.AppendFormat("Last disk on sequence\t{0}\t{1}", image1Info.LastMediaSequence, sb.AppendFormat("Last disk on sequence\t{0}\t{1}", image1Info.LastMediaSequence,
image2Info.LastMediaSequence).AppendLine(); image2Info.LastMediaSequence).AppendLine();
sb.AppendFormat("Drive manufacturer\t{0}\t{1}", image1Info.DriveManufacturer, sb.AppendFormat("Drive manufacturer\t{0}\t{1}", image1Info.DriveManufacturer,
image2Info.DriveManufacturer).AppendLine(); image2Info.DriveManufacturer).AppendLine();
sb.AppendFormat("Drive firmware revision\t{0}\t{1}", image1Info.DriveFirmwareRevision, sb.AppendFormat("Drive firmware revision\t{0}\t{1}", image1Info.DriveFirmwareRevision,
image2Info.DriveFirmwareRevision).AppendLine(); image2Info.DriveFirmwareRevision).AppendLine();
sb.AppendFormat("Drive model\t{0}\t{1}", image1Info.DriveModel, image2Info.DriveModel).AppendLine(); sb.AppendFormat("Drive model\t{0}\t{1}", image1Info.DriveModel, image2Info.DriveModel).AppendLine();
sb.AppendFormat("Drive serial number\t{0}\t{1}", image1Info.DriveSerialNumber, sb.AppendFormat("Drive serial number\t{0}\t{1}", image1Info.DriveSerialNumber,
image2Info.DriveSerialNumber).AppendLine(); image2Info.DriveSerialNumber).AppendLine();
foreach(MediaTagType disktag in Enum.GetValues(typeof(MediaTagType))) foreach(MediaTagType disktag in Enum.GetValues(typeof(MediaTagType)))
sb.AppendFormat("Has {0}?\t{1}\t{2}", disktag, image1DiskTags.ContainsKey(disktag), sb.AppendFormat("Has {0}?\t{1}\t{2}", disktag, image1DiskTags.ContainsKey(disktag),
image2DiskTags.ContainsKey(disktag)).AppendLine(); image2DiskTags.ContainsKey(disktag)).AppendLine();
@@ -256,58 +261,76 @@ namespace DiscImageChef.Commands
if(image1Info.HasPartitions != image2Info.HasPartitions) if(image1Info.HasPartitions != image2Info.HasPartitions)
{ {
imagesDiffer = true; imagesDiffer = true;
if(!MainClass.Verbose) sb.AppendLine("Image partitioned status differ");
if(!verbose)
sb.AppendLine("Image partitioned status differ");
} }
if(image1Info.HasSessions != image2Info.HasSessions) if(image1Info.HasSessions != image2Info.HasSessions)
{ {
imagesDiffer = true; imagesDiffer = true;
if(!MainClass.Verbose) sb.AppendLine("Image session status differ");
if(!verbose)
sb.AppendLine("Image session status differ");
} }
if(image1Info.Sectors != image2Info.Sectors) if(image1Info.Sectors != image2Info.Sectors)
{ {
imagesDiffer = true; imagesDiffer = true;
if(!MainClass.Verbose) sb.AppendLine("Image sectors differ");
if(!verbose)
sb.AppendLine("Image sectors differ");
} }
if(image1Info.SectorSize != image2Info.SectorSize) if(image1Info.SectorSize != image2Info.SectorSize)
{ {
imagesDiffer = true; imagesDiffer = true;
if(!MainClass.Verbose) sb.AppendLine("Image sector size differ");
if(!verbose)
sb.AppendLine("Image sector size differ");
} }
if(image1Info.MediaType != image2Info.MediaType) if(image1Info.MediaType != image2Info.MediaType)
{ {
imagesDiffer = true; imagesDiffer = true;
if(!MainClass.Verbose) sb.AppendLine("Disk type differ");
if(!verbose)
sb.AppendLine("Disk type differ");
} }
ulong leastSectors; ulong leastSectors;
if(image1Info.Sectors < image2Info.Sectors) if(image1Info.Sectors < image2Info.Sectors)
{ {
imagesDiffer = true; imagesDiffer = true;
leastSectors = image1Info.Sectors; leastSectors = image1Info.Sectors;
if(!MainClass.Verbose) sb.AppendLine("Image 2 has more sectors");
if(!verbose)
sb.AppendLine("Image 2 has more sectors");
} }
else if(image1Info.Sectors > image2Info.Sectors) else if(image1Info.Sectors > image2Info.Sectors)
{ {
imagesDiffer = true; imagesDiffer = true;
leastSectors = image2Info.Sectors; leastSectors = image2Info.Sectors;
if(!MainClass.Verbose) sb.AppendLine("Image 1 has more sectors");
if(!verbose)
sb.AppendLine("Image 1 has more sectors");
} }
else leastSectors = image1Info.Sectors; else
leastSectors = image1Info.Sectors;
DicConsole.WriteLine("Comparing sectors..."); DicConsole.WriteLine("Comparing sectors...");
for(ulong sector = 0; sector < leastSectors; sector++) for(ulong sector = 0; sector < leastSectors; sector++)
{ {
DicConsole.Write("\rComparing sector {0} of {1}...", sector + 1, leastSectors); DicConsole.Write("\rComparing sector {0} of {1}...", sector + 1, leastSectors);
try try
{ {
byte[] image1Sector = input1Format.ReadSector(sector); byte[] image1Sector = input1Format.ReadSector(sector);
byte[] image2Sector = input2Format.ReadSector(sector); byte[] image2Sector = input2Format.ReadSector(sector);
ArrayHelpers.CompareBytes(out bool different, out bool sameSize, image1Sector, image2Sector); ArrayHelpers.CompareBytes(out bool different, out bool sameSize, image1Sector, image2Sector);
if(different) if(different)
{ {
imagesDiffer = true; imagesDiffer = true;
@@ -316,8 +339,9 @@ namespace DiscImageChef.Commands
else if(!sameSize) else if(!sameSize)
{ {
imagesDiffer = true; imagesDiffer = true;
sb
.AppendFormat("Sector {0} has different sizes ({1} bytes in image 1, {2} in image 2) but are otherwise identical", sb.
AppendFormat("Sector {0} has different sizes ({1} bytes in image 1, {2} in image 2) but are otherwise identical",
sector, image1Sector.LongLength, image2Sector.LongLength).AppendLine(); sector, image1Sector.LongLength, image2Sector.LongLength).AppendLine();
} }
} }
@@ -335,7 +359,7 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine(sb.ToString()); DicConsole.WriteLine(sb.ToString());
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
} }
} }

View File

@@ -31,79 +31,65 @@
// ****************************************************************************/ // ****************************************************************************/
using System; using System;
using System.Collections.Generic; using System.CommandLine;
using System.CommandLine.Invocation;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Settings; using DiscImageChef.Settings;
using Mono.Options;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class ConfigureCommand : Command internal class ConfigureCommand : Command
{ {
readonly bool gdprChange; readonly bool _autoCall;
bool autoCall; readonly bool _gdprChange;
bool showHelp;
public ConfigureCommand(bool gdprChange, bool autoCall) : base("configure", public ConfigureCommand(bool gdprChange, bool autoCall) : base("configure",
"Configures user settings and statistics.") "Configures user settings and statistics.")
{ {
this.gdprChange = gdprChange; _gdprChange = gdprChange;
this.autoCall = autoCall; _autoCall = autoCall;
Options = new OptionSet
{ Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}",
$"{MainClass.AssemblyCopyright}",
"",
$"usage: DiscImageChef {Name}",
"",
Help,
{"help|h|?", "Show this message and exit.", v => showHelp = v != null}
};
} }
public override int Invoke(IEnumerable<string> arguments) int Invoke(bool debug, bool verbose)
{ {
if(!autoCall) if(!_autoCall)
{ {
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
if(extra.Count != 0) if(debug)
{ DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
DicConsole.ErrorWriteLine("Too many arguments.");
return (int)ErrorNumber.UnexpectedArgumentCount; if(verbose)
} DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
} }
if(gdprChange) if(_gdprChange)
{ {
DicConsole.WriteLine("In compliance with the European Union General Data Protection Regulation 2016/679 (GDPR),\n" + DicConsole.WriteLine("In compliance with the European Union General Data Protection Regulation 2016/679 (GDPR),\n" +
"we must give you the following information about DiscImageChef and ask if you want to opt-in\n" + "we must give you the following information about DiscImageChef and ask if you want to opt-in\n" +
"in some information sharing."); "in some information sharing.");
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Disclaimer: Because DiscImageChef is an open source software this information, and therefore,\n" + DicConsole.WriteLine("Disclaimer: Because DiscImageChef is an open source software this information, and therefore,\n" +
"compliance with GDPR only holds true if you obtained a certificated copy from its original\n" + "compliance with GDPR only holds true if you obtained a certificated copy from its original\n" +
"authors. In case of doubt, close DiscImageChef now and ask in our IRC support channel."); "authors. In case of doubt, close DiscImageChef now and ask in our IRC support channel.");
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("For any information sharing your IP address may be stored in our server, in a way that is not\n" + DicConsole.WriteLine("For any information sharing your IP address may be stored in our server, in a way that is not\n" +
"possible for any person, manual, or automated process, to link with your identity, unless\n" + "possible for any person, manual, or automated process, to link with your identity, unless\n" +
"specified otherwise."); "specified otherwise.");
} }
ConsoleKeyInfo pressedKey = new ConsoleKeyInfo(); var pressedKey = new ConsoleKeyInfo();
#region Device reports #region Device reports
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine( DicConsole.WriteLine(
"With the 'device-report' command, DiscImageChef creates a report of a device, that includes its\n" + "With the 'device-report' command, DiscImageChef creates a report of a device, that includes its\n" +
"manufacturer, model, firmware revision and/or version, attached bus, size, and supported commands.\n" + "manufacturer, model, firmware revision and/or version, attached bus, size, and supported commands.\n" +
@@ -113,7 +99,8 @@ namespace DiscImageChef.Commands
"of devices. A human-readable copy of the report in XML format is always created in the same directory\n" + "of devices. A human-readable copy of the report in XML format is always created in the same directory\n" +
"where DiscImageChef is being run from."); "where DiscImageChef is being run from.");
while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N) while(pressedKey.Key != ConsoleKey.Y &&
pressedKey.Key != ConsoleKey.N)
{ {
DicConsole.Write("Do you want to save device reports in shared folder of your computer? (Y/N): "); DicConsole.Write("Do you want to save device reports in shared folder of your computer? (Y/N): ");
pressedKey = System.Console.ReadKey(); pressedKey = System.Console.ReadKey();
@@ -124,12 +111,15 @@ namespace DiscImageChef.Commands
pressedKey = new ConsoleKeyInfo(); pressedKey = new ConsoleKeyInfo();
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Sharing a report with us will send it to our server, that's in the european union territory, where it\n" + DicConsole.WriteLine("Sharing a report with us will send it to our server, that's in the european union territory, where it\n" +
"will be manually analized by an european union citizen to remove any trace of personal identification\n" + "will be manually analyzed by an european union citizen to remove any trace of personal identification\n" +
"from it. Once that is done, it will be shared in our stats website, https://www.discimagechef.app\n" + "from it. Once that is done, it will be shared in our stats website, https://www.discimagechef.app\n" +
"These report will be used to improve DiscImageChef support, and in some cases, to provide emulation of the\n" + "These report will be used to improve DiscImageChef support, and in some cases, to provide emulation of the\n" +
"devices to other open-source projects. In any case, no information linking the report to you will be stored."); "devices to other open-source projects. In any case, no information linking the report to you will be stored.");
while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N)
while(pressedKey.Key != ConsoleKey.Y &&
pressedKey.Key != ConsoleKey.N)
{ {
DicConsole.Write("Do you want to share your device reports with us? (Y/N): "); DicConsole.Write("Do you want to share your device reports with us? (Y/N): ");
pressedKey = System.Console.ReadKey(); pressedKey = System.Console.ReadKey();
@@ -141,13 +131,16 @@ namespace DiscImageChef.Commands
#region Statistics #region Statistics
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("DiscImageChef can store some usage statistics. These statistics are limited to the number of times a\n" + DicConsole.WriteLine("DiscImageChef can store some usage statistics. These statistics are limited to the number of times a\n" +
"command is executed, a filesystem, partition, or device is used, the operating system version, and other.\n" + "command is executed, a filesystem, partition, or device is used, the operating system version, and other.\n" +
"In no case, any information besides pure statistical usage numbers is stored, and they're just joint to the\n" + "In no case, any information besides pure statistical usage numbers is stored, and they're just joint to the\n" +
"pool with no way of using them to identify you."); "pool with no way of using them to identify you.");
pressedKey = new ConsoleKeyInfo(); pressedKey = new ConsoleKeyInfo();
while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N)
while(pressedKey.Key != ConsoleKey.Y &&
pressedKey.Key != ConsoleKey.N)
{ {
DicConsole.Write("Do you want to save stats about your DiscImageChef usage? (Y/N): "); DicConsole.Write("Do you want to save stats about your DiscImageChef usage? (Y/N): ");
pressedKey = System.Console.ReadKey(); pressedKey = System.Console.ReadKey();
@@ -159,7 +152,9 @@ namespace DiscImageChef.Commands
Settings.Settings.Current.Stats = new StatsSettings(); Settings.Settings.Current.Stats = new StatsSettings();
pressedKey = new ConsoleKeyInfo(); pressedKey = new ConsoleKeyInfo();
while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N)
while(pressedKey.Key != ConsoleKey.Y &&
pressedKey.Key != ConsoleKey.N)
{ {
DicConsole.Write("Do you want to share your stats anonymously? (Y/N): "); DicConsole.Write("Do you want to share your stats anonymously? (Y/N): ");
pressedKey = System.Console.ReadKey(); pressedKey = System.Console.ReadKey();
@@ -169,7 +164,9 @@ namespace DiscImageChef.Commands
Settings.Settings.Current.Stats.ShareStats = pressedKey.Key == ConsoleKey.Y; Settings.Settings.Current.Stats.ShareStats = pressedKey.Key == ConsoleKey.Y;
pressedKey = new ConsoleKeyInfo(); pressedKey = new ConsoleKeyInfo();
while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N)
while(pressedKey.Key != ConsoleKey.Y &&
pressedKey.Key != ConsoleKey.N)
{ {
DicConsole.Write("Do you want to gather statistics about benchmarks? (Y/N): "); DicConsole.Write("Do you want to gather statistics about benchmarks? (Y/N): ");
pressedKey = System.Console.ReadKey(); pressedKey = System.Console.ReadKey();
@@ -179,7 +176,9 @@ namespace DiscImageChef.Commands
Settings.Settings.Current.Stats.BenchmarkStats = pressedKey.Key == ConsoleKey.Y; Settings.Settings.Current.Stats.BenchmarkStats = pressedKey.Key == ConsoleKey.Y;
pressedKey = new ConsoleKeyInfo(); pressedKey = new ConsoleKeyInfo();
while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N)
while(pressedKey.Key != ConsoleKey.Y &&
pressedKey.Key != ConsoleKey.N)
{ {
DicConsole.Write("Do you want to gather statistics about command usage? (Y/N): "); DicConsole.Write("Do you want to gather statistics about command usage? (Y/N): ");
pressedKey = System.Console.ReadKey(); pressedKey = System.Console.ReadKey();
@@ -189,7 +188,9 @@ namespace DiscImageChef.Commands
Settings.Settings.Current.Stats.CommandStats = pressedKey.Key == ConsoleKey.Y; Settings.Settings.Current.Stats.CommandStats = pressedKey.Key == ConsoleKey.Y;
pressedKey = new ConsoleKeyInfo(); pressedKey = new ConsoleKeyInfo();
while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N)
while(pressedKey.Key != ConsoleKey.Y &&
pressedKey.Key != ConsoleKey.N)
{ {
DicConsole.Write("Do you want to gather statistics about found devices? (Y/N): "); DicConsole.Write("Do you want to gather statistics about found devices? (Y/N): ");
pressedKey = System.Console.ReadKey(); pressedKey = System.Console.ReadKey();
@@ -199,7 +200,9 @@ namespace DiscImageChef.Commands
Settings.Settings.Current.Stats.DeviceStats = pressedKey.Key == ConsoleKey.Y; Settings.Settings.Current.Stats.DeviceStats = pressedKey.Key == ConsoleKey.Y;
pressedKey = new ConsoleKeyInfo(); pressedKey = new ConsoleKeyInfo();
while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N)
while(pressedKey.Key != ConsoleKey.Y &&
pressedKey.Key != ConsoleKey.N)
{ {
DicConsole.Write("Do you want to gather statistics about found filesystems? (Y/N): "); DicConsole.Write("Do you want to gather statistics about found filesystems? (Y/N): ");
pressedKey = System.Console.ReadKey(); pressedKey = System.Console.ReadKey();
@@ -209,7 +212,9 @@ namespace DiscImageChef.Commands
Settings.Settings.Current.Stats.FilesystemStats = pressedKey.Key == ConsoleKey.Y; Settings.Settings.Current.Stats.FilesystemStats = pressedKey.Key == ConsoleKey.Y;
pressedKey = new ConsoleKeyInfo(); pressedKey = new ConsoleKeyInfo();
while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N)
while(pressedKey.Key != ConsoleKey.Y &&
pressedKey.Key != ConsoleKey.N)
{ {
DicConsole.Write("Do you want to gather statistics about found file filters? (Y/N): "); DicConsole.Write("Do you want to gather statistics about found file filters? (Y/N): ");
pressedKey = System.Console.ReadKey(); pressedKey = System.Console.ReadKey();
@@ -219,7 +224,9 @@ namespace DiscImageChef.Commands
Settings.Settings.Current.Stats.FilterStats = pressedKey.Key == ConsoleKey.Y; Settings.Settings.Current.Stats.FilterStats = pressedKey.Key == ConsoleKey.Y;
pressedKey = new ConsoleKeyInfo(); pressedKey = new ConsoleKeyInfo();
while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N)
while(pressedKey.Key != ConsoleKey.Y &&
pressedKey.Key != ConsoleKey.N)
{ {
DicConsole.Write("Do you want to gather statistics about found media image formats? (Y/N): "); DicConsole.Write("Do you want to gather statistics about found media image formats? (Y/N): ");
pressedKey = System.Console.ReadKey(); pressedKey = System.Console.ReadKey();
@@ -229,7 +236,9 @@ namespace DiscImageChef.Commands
Settings.Settings.Current.Stats.MediaImageStats = pressedKey.Key == ConsoleKey.Y; Settings.Settings.Current.Stats.MediaImageStats = pressedKey.Key == ConsoleKey.Y;
pressedKey = new ConsoleKeyInfo(); pressedKey = new ConsoleKeyInfo();
while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N)
while(pressedKey.Key != ConsoleKey.Y &&
pressedKey.Key != ConsoleKey.N)
{ {
DicConsole.Write("Do you want to gather statistics about scanned media? (Y/N): "); DicConsole.Write("Do you want to gather statistics about scanned media? (Y/N): ");
pressedKey = System.Console.ReadKey(); pressedKey = System.Console.ReadKey();
@@ -239,7 +248,9 @@ namespace DiscImageChef.Commands
Settings.Settings.Current.Stats.MediaScanStats = pressedKey.Key == ConsoleKey.Y; Settings.Settings.Current.Stats.MediaScanStats = pressedKey.Key == ConsoleKey.Y;
pressedKey = new ConsoleKeyInfo(); pressedKey = new ConsoleKeyInfo();
while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N)
while(pressedKey.Key != ConsoleKey.Y &&
pressedKey.Key != ConsoleKey.N)
{ {
DicConsole.Write("Do you want to gather statistics about found partitioning schemes? (Y/N): "); DicConsole.Write("Do you want to gather statistics about found partitioning schemes? (Y/N): ");
pressedKey = System.Console.ReadKey(); pressedKey = System.Console.ReadKey();
@@ -249,7 +260,9 @@ namespace DiscImageChef.Commands
Settings.Settings.Current.Stats.PartitionStats = pressedKey.Key == ConsoleKey.Y; Settings.Settings.Current.Stats.PartitionStats = pressedKey.Key == ConsoleKey.Y;
pressedKey = new ConsoleKeyInfo(); pressedKey = new ConsoleKeyInfo();
while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N)
while(pressedKey.Key != ConsoleKey.Y &&
pressedKey.Key != ConsoleKey.N)
{ {
DicConsole.Write("Do you want to gather statistics about media types? (Y/N): "); DicConsole.Write("Do you want to gather statistics about media types? (Y/N): ");
pressedKey = System.Console.ReadKey(); pressedKey = System.Console.ReadKey();
@@ -259,7 +272,9 @@ namespace DiscImageChef.Commands
Settings.Settings.Current.Stats.MediaStats = pressedKey.Key == ConsoleKey.Y; Settings.Settings.Current.Stats.MediaStats = pressedKey.Key == ConsoleKey.Y;
pressedKey = new ConsoleKeyInfo(); pressedKey = new ConsoleKeyInfo();
while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N)
while(pressedKey.Key != ConsoleKey.Y &&
pressedKey.Key != ConsoleKey.N)
{ {
DicConsole.Write("Do you want to gather statistics about media image verifications? (Y/N): "); DicConsole.Write("Do you want to gather statistics about media image verifications? (Y/N): ");
pressedKey = System.Console.ReadKey(); pressedKey = System.Console.ReadKey();
@@ -268,12 +283,14 @@ namespace DiscImageChef.Commands
Settings.Settings.Current.Stats.VerifyStats = pressedKey.Key == ConsoleKey.Y; Settings.Settings.Current.Stats.VerifyStats = pressedKey.Key == ConsoleKey.Y;
} }
else Settings.Settings.Current.Stats = null; else
Settings.Settings.Current.Stats = null;
#endregion Statistics #endregion Statistics
Settings.Settings.Current.GdprCompliance = DicSettings.GdprLevel; Settings.Settings.Current.GdprCompliance = DicSettings.GdprLevel;
Settings.Settings.SaveSettings(); Settings.Settings.SaveSettings();
return (int)ErrorNumber.NoError;
return(int)ErrorNumber.NoError;
} }
} }
} }

View File

@@ -32,6 +32,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Xml.Serialization; using System.Xml.Serialization;
@@ -42,235 +44,271 @@ using DiscImageChef.CommonTypes.Metadata;
using DiscImageChef.CommonTypes.Structs; using DiscImageChef.CommonTypes.Structs;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using Mono.Options;
using Schemas; using Schemas;
using ImageInfo = DiscImageChef.CommonTypes.Structs.ImageInfo; using ImageInfo = DiscImageChef.CommonTypes.Structs.ImageInfo;
using Version = DiscImageChef.CommonTypes.Interop.Version; using Version = DiscImageChef.CommonTypes.Interop.Version;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class ConvertImageCommand : Command internal class ConvertImageCommand : Command
{ {
string cicmXml;
string comments;
int count = 64;
string creator;
string driveFirmwareRevision;
string driveManufacturer;
string driveModel;
string driveSerialNumber;
bool force;
string inputFile;
int lastMediaSequence;
string mediaBarcode;
string mediaManufacturer;
string mediaModel;
string mediaPartNumber;
int mediaSequence;
string mediaSerialNumber;
string mediaTitle;
string outputFile;
string outputOptions;
string resumeFile;
bool showHelp;
string wantedOutputFormat;
public ConvertImageCommand() : base("convert-image", "Converts one image to another format.") public ConvertImageCommand() : base("convert-image", "Converts one image to another format.")
{ {
Options = new OptionSet Add(new Option(new[]
{
"--cicm-xml", "-x"
}, "Take metadata from existing CICM XML sidecar.")
{
Argument = new Argument<string>(() => null), Required = false
});
Add(new Option("--comments", "Image comments.")
{ {
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", Argument = new Argument<string>(() => null), Required = false
$"{MainClass.AssemblyCopyright}", });
"",
$"usage: DiscImageChef {Name} [OPTIONS] inputimage outputimage", Add(new Option(new[]
"",
Help,
{"cicm-xml|x=", "Take metadata from existing CICM XML sidecar.", s => cicmXml = s},
{"comments=", "Image comments.", s => comments = s},
{"count|c=", "How many sectors to convert at once.", (int i) => count = i},
{"creator=", "Who (person) created the image?.", s => creator = s},
{ {
"drive-manufacturer=", "--count", "-c"
"Manufacturer of the drive used to read the media represented by the image.", }, "How many sectors to convert at once.")
s => driveManufacturer = s
},
{ {
"drive-model=", "Model of the drive used to read the media represented by the image.", Argument = new Argument<int>(() => 64), Required = false
s => driveModel = s });
},
Add(new Option("--creator", "Who (person) created the image?.")
{
Argument = new Argument<string>(() => null), Required = false
});
Add(new Option("--drive-manufacturer",
"Manufacturer of the drive used to read the media represented by the image.")
{
Argument = new Argument<string>(() => null), Required = false
});
Add(new Option("--drive-model", "Model of the drive used to read the media represented by the image.")
{
Argument = new Argument<string>(() => null), Required = false
});
Add(new Option("--drive-revision",
"Firmware revision of the drive used to read the media represented by the image.")
{
Argument = new Argument<string>(() => null), Required = false
});
Add(new Option("--drive-serial",
"Serial number of the drive used to read the media represented by the image.")
{
Argument = new Argument<string>(() => null), Required = false
});
Add(new Option(new[]
{ {
"drive-revision=", "--force", "-f"
"Firmware revision of the drive used to read the media represented by the image.", }, "Continue conversion even if sector or media tags will be lost in the process.")
s => driveFirmwareRevision = s
},
{ {
"drive-serial=", "Serial number of the drive used to read the media represented by the image.", Argument = new Argument<bool>(() => false), Required = false
s => driveSerialNumber = s });
},
Add(new Option(new[]
{
"--format", "-p"
},
"Format of the output image, as plugin name or plugin id. If not present, will try to detect it from output image extension.")
{
Argument = new Argument<string>(() => null), Required = false
});
Add(new Option("--media-barcode", "Barcode of the media represented by the image.")
{
Argument = new Argument<string>(() => null), Required = false
});
Add(new Option("--media-lastsequence",
"Last media of the sequence the media represented by the image corresponds to.")
{
Argument = new Argument<int>(() => 0), Required = false
});
Add(new Option("--media-manufacturer", "Manufacturer of the media represented by the image.")
{
Argument = new Argument<string>(() => null), Required = false
});
Add(new Option("--media-model", "Model of the media represented by the image.")
{
Argument = new Argument<string>(() => null), Required = false
});
Add(new Option("--media-partnumber", "Part number of the media represented by the image.")
{
Argument = new Argument<string>(() => null), Required = false
});
Add(new Option("--media-sequence", "Number in sequence for the media represented by the image.")
{
Argument = new Argument<int>(() => 0), Required = false
});
Add(new Option("--media-serial", "Serial number of the media represented by the image.")
{
Argument = new Argument<string>(() => null), Required = false
});
Add(new Option("--media-title", "Title of the media represented by the image.")
{
Argument = new Argument<string>(() => null), Required = false
});
Add(new Option(new[]
{ {
"force|f", "Continue conversion even if sector or media tags will be lost in the process.", "--options", "-O"
b => force = b != null }, "Comma separated name=value pairs of options to pass to output image plugin.")
},
{ {
"format|p=", Argument = new Argument<string>(() => null), Required = false
"Format of the output image, as plugin name or plugin id. If not present, will try to detect it from output image extension.", });
s => wantedOutputFormat = s
}, Add(new Option(new[]
{"media-barcode=", "Barcode of the media represented by the image.", s => mediaBarcode = s},
{ {
"media-lastsequence=", "--resume-file", "-r"
"Last media of the sequence the media represented by the image corresponds to.", }, "Take list of dump hardware from existing resume file.")
(int i) => lastMediaSequence = i
},
{ {
"media-manufacturer=", "Manufacturer of the media represented by the image.", Argument = new Argument<string>(() => null), Required = false
s => mediaManufacturer = s });
},
{"media-model=", "Model of the media represented by the image.", s => mediaModel = s}, AddArgument(new Argument<string>
{ {
"media-partnumber=", "Part number of the media represented by the image.", Arity = ArgumentArity.ExactlyOne, Description = "Input image path", Name = "input-path"
s => mediaPartNumber = s });
},
{ AddArgument(new Argument<string>
"media-sequence=", "Number in sequence for the media represented by the image.", {
(int i) => mediaSequence = i Arity = ArgumentArity.ExactlyOne, Description = "Output image path", Name = "output-path"
}, });
{
"media-serial=", "Serial number of the media represented by the image.", Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
s => mediaSerialNumber = s
},
{"media-title=", "Title of the media represented by the image.", s => mediaTitle = s},
{
"options|O=", "Comma separated name=value pairs of options to pass to output image plugin.",
s => outputOptions = s
},
{"resume-file|r=", "Take list of dump hardware from existing resume file.", s => resumeFile = s},
{"help|h|?", "Show this message and exit.", v => showHelp = v != null}
};
} }
public override int Invoke(IEnumerable<string> arguments) static int Invoke(bool verbose, bool debug, string cicmXml, string comments, int count, string creator,
string driveFirmwareRevision, string driveManufacturer, string driveModel,
string driveSerialNumber, bool force, string inputPath, int lastMediaSequence,
string mediaBarcode, string mediaManufacturer, string mediaModel, string mediaPartNumber,
int mediaSequence, string mediaSerialNumber, string mediaTitle, string outputPath,
string outputOptions, string resumeFile, string format)
{ {
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("convert-image"); Statistics.AddCommand("convert-image");
if(extra.Count > 2) DicConsole.DebugWriteLine("Analyze command", "--cicm-xml={0}", cicmXml);
{ DicConsole.DebugWriteLine("Analyze command", "--comments={0}", comments);
DicConsole.ErrorWriteLine("Too many arguments."); DicConsole.DebugWriteLine("Analyze command", "--count={0}", count);
return (int)ErrorNumber.UnexpectedArgumentCount; DicConsole.DebugWriteLine("Analyze command", "--creator={0}", creator);
} DicConsole.DebugWriteLine("Analyze command", "--debug={0}", debug);
if(extra.Count <= 1)
{
DicConsole.ErrorWriteLine("Missing input image.");
return (int)ErrorNumber.MissingArgument;
}
inputFile = extra[0];
outputFile = extra[1];
DicConsole.DebugWriteLine("Analyze command", "--cicm-xml={0}", cicmXml);
DicConsole.DebugWriteLine("Analyze command", "--comments={0}", comments);
DicConsole.DebugWriteLine("Analyze command", "--count={0}", count);
DicConsole.DebugWriteLine("Analyze command", "--creator={0}", creator);
DicConsole.DebugWriteLine("Analyze command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("Analyze command", "--drive-manufacturer={0}", driveManufacturer); DicConsole.DebugWriteLine("Analyze command", "--drive-manufacturer={0}", driveManufacturer);
DicConsole.DebugWriteLine("Analyze command", "--drive-model={0}", driveModel); DicConsole.DebugWriteLine("Analyze command", "--drive-model={0}", driveModel);
DicConsole.DebugWriteLine("Analyze command", "--drive-revision={0}", driveFirmwareRevision); DicConsole.DebugWriteLine("Analyze command", "--drive-revision={0}", driveFirmwareRevision);
DicConsole.DebugWriteLine("Analyze command", "--drive-serial={0}", driveSerialNumber); DicConsole.DebugWriteLine("Analyze command", "--drive-serial={0}", driveSerialNumber);
DicConsole.DebugWriteLine("Analyze command", "--force={0}", force); DicConsole.DebugWriteLine("Analyze command", "--force={0}", force);
DicConsole.DebugWriteLine("Analyze command", "--format={0}", wantedOutputFormat); DicConsole.DebugWriteLine("Analyze command", "--format={0}", format);
DicConsole.DebugWriteLine("Analyze command", "--input={0}", inputFile); DicConsole.DebugWriteLine("Analyze command", "--input={0}", inputPath);
DicConsole.DebugWriteLine("Analyze command", "--media-barcode={0}", mediaBarcode); DicConsole.DebugWriteLine("Analyze command", "--media-barcode={0}", mediaBarcode);
DicConsole.DebugWriteLine("Analyze command", "--media-lastsequence={0}", lastMediaSequence); DicConsole.DebugWriteLine("Analyze command", "--media-lastsequence={0}", lastMediaSequence);
DicConsole.DebugWriteLine("Analyze command", "--media-manufacturer={0}", mediaManufacturer); DicConsole.DebugWriteLine("Analyze command", "--media-manufacturer={0}", mediaManufacturer);
DicConsole.DebugWriteLine("Analyze command", "--media-model={0}", mediaModel); DicConsole.DebugWriteLine("Analyze command", "--media-model={0}", mediaModel);
DicConsole.DebugWriteLine("Analyze command", "--media-partnumber={0}", mediaPartNumber); DicConsole.DebugWriteLine("Analyze command", "--media-partnumber={0}", mediaPartNumber);
DicConsole.DebugWriteLine("Analyze command", "--media-sequence={0}", mediaSequence); DicConsole.DebugWriteLine("Analyze command", "--media-sequence={0}", mediaSequence);
DicConsole.DebugWriteLine("Analyze command", "--media-serial={0}", mediaSerialNumber); DicConsole.DebugWriteLine("Analyze command", "--media-serial={0}", mediaSerialNumber);
DicConsole.DebugWriteLine("Analyze command", "--media-title={0}", mediaTitle); DicConsole.DebugWriteLine("Analyze command", "--media-title={0}", mediaTitle);
DicConsole.DebugWriteLine("Analyze command", "--options={0}", outputOptions); DicConsole.DebugWriteLine("Analyze command", "--options={0}", outputOptions);
DicConsole.DebugWriteLine("Analyze command", "--output={0}", outputFile); DicConsole.DebugWriteLine("Analyze command", "--output={0}", outputPath);
DicConsole.DebugWriteLine("Analyze command", "--resume-file={0}", resumeFile); DicConsole.DebugWriteLine("Analyze command", "--resume-file={0}", resumeFile);
DicConsole.DebugWriteLine("Analyze command", "--verbose={0}", MainClass.Verbose); DicConsole.DebugWriteLine("Analyze command", "--verbose={0}", verbose);
Dictionary<string, string> parsedOptions = Core.Options.Parse(outputOptions); Dictionary<string, string> parsedOptions = Core.Options.Parse(outputOptions);
DicConsole.DebugWriteLine("Analyze command", "Parsed options:"); DicConsole.DebugWriteLine("Analyze command", "Parsed options:");
foreach(KeyValuePair<string, string> parsedOption in parsedOptions) foreach(KeyValuePair<string, string> parsedOption in parsedOptions)
DicConsole.DebugWriteLine("Analyze command", "{0} = {1}", parsedOption.Key, parsedOption.Value); DicConsole.DebugWriteLine("Analyze command", "{0} = {1}", parsedOption.Key, parsedOption.Value);
if(count == 0) if(count == 0)
{ {
DicConsole.ErrorWriteLine("Need to specify more than 0 sectors to copy at once"); DicConsole.ErrorWriteLine("Need to specify more than 0 sectors to copy at once");
return (int)ErrorNumber.InvalidArgument;
return(int)ErrorNumber.InvalidArgument;
} }
Resume resume = null; Resume resume = null;
CICMMetadataType sidecar = null; CICMMetadataType sidecar = null;
XmlSerializer xs = new XmlSerializer(typeof(CICMMetadataType)); var xs = new XmlSerializer(typeof(CICMMetadataType));
if(cicmXml != null) if(cicmXml != null)
if(File.Exists(cicmXml)) if(File.Exists(cicmXml))
try try
{ {
StreamReader sr = new StreamReader(cicmXml); var sr = new StreamReader(cicmXml);
sidecar = (CICMMetadataType)xs.Deserialize(sr); sidecar = (CICMMetadataType)xs.Deserialize(sr);
sr.Close(); sr.Close();
} }
catch catch
{ {
DicConsole.ErrorWriteLine("Incorrect metadata sidecar file, not continuing..."); DicConsole.ErrorWriteLine("Incorrect metadata sidecar file, not continuing...");
return (int)ErrorNumber.InvalidSidecar;
return(int)ErrorNumber.InvalidSidecar;
} }
else else
{ {
DicConsole.ErrorWriteLine("Could not find metadata sidecar, not continuing..."); DicConsole.ErrorWriteLine("Could not find metadata sidecar, not continuing...");
return (int)ErrorNumber.FileNotFound;
return(int)ErrorNumber.FileNotFound;
} }
xs = new XmlSerializer(typeof(Resume)); xs = new XmlSerializer(typeof(Resume));
if(resumeFile != null) if(resumeFile != null)
if(File.Exists(resumeFile)) if(File.Exists(resumeFile))
try try
{ {
StreamReader sr = new StreamReader(resumeFile); var sr = new StreamReader(resumeFile);
resume = (Resume)xs.Deserialize(sr); resume = (Resume)xs.Deserialize(sr);
sr.Close(); sr.Close();
} }
catch catch
{ {
DicConsole.ErrorWriteLine("Incorrect resume file, not continuing..."); DicConsole.ErrorWriteLine("Incorrect resume file, not continuing...");
return (int)ErrorNumber.InvalidResume;
return(int)ErrorNumber.InvalidResume;
} }
else else
{ {
DicConsole.ErrorWriteLine("Could not find resume file, not continuing..."); DicConsole.ErrorWriteLine("Could not find resume file, not continuing...");
return (int)ErrorNumber.FileNotFound;
return(int)ErrorNumber.FileNotFound;
} }
FiltersList filtersList = new FiltersList(); var filtersList = new FiltersList();
IFilter inputFilter = filtersList.GetFilter(inputFile); IFilter inputFilter = filtersList.GetFilter(inputPath);
if(inputFilter == null) if(inputFilter == null)
{ {
DicConsole.ErrorWriteLine("Cannot open specified file."); DicConsole.ErrorWriteLine("Cannot open specified file.");
return (int)ErrorNumber.CannotOpenFile;
return(int)ErrorNumber.CannotOpenFile;
} }
if(File.Exists(outputFile)) if(File.Exists(outputPath))
{ {
DicConsole.ErrorWriteLine("Output file already exists, not continuing."); DicConsole.ErrorWriteLine("Output file already exists, not continuing.");
return (int)ErrorNumber.DestinationExists;
return(int)ErrorNumber.DestinationExists;
} }
PluginBase plugins = GetPluginBase.Instance; PluginBase plugins = GetPluginBase.Instance;
@@ -279,13 +317,15 @@ namespace DiscImageChef.Commands
if(inputFormat == null) if(inputFormat == null)
{ {
DicConsole.WriteLine("Input image format not identified, not proceeding with conversion."); DicConsole.WriteLine("Input image format not identified, not proceeding with conversion.");
return (int)ErrorNumber.UnrecognizedFormat;
return(int)ErrorNumber.UnrecognizedFormat;
} }
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLine("Input image format identified by {0} ({1}).", inputFormat.Name, DicConsole.VerboseWriteLine("Input image format identified by {0} ({1}).", inputFormat.Name,
inputFormat.Id); inputFormat.Id);
else DicConsole.WriteLine("Input image format identified by {0}.", inputFormat.Name); else
DicConsole.WriteLine("Input image format identified by {0}.", inputFormat.Name);
try try
{ {
@@ -293,13 +333,17 @@ namespace DiscImageChef.Commands
{ {
DicConsole.WriteLine("Unable to open image format"); DicConsole.WriteLine("Unable to open image format");
DicConsole.WriteLine("No error given"); DicConsole.WriteLine("No error given");
return (int)ErrorNumber.CannotOpenFormat;
return(int)ErrorNumber.CannotOpenFormat;
} }
DicConsole.DebugWriteLine("Convert-image command", "Correctly opened image file."); DicConsole.DebugWriteLine("Convert-image command", "Correctly opened image file.");
DicConsole.DebugWriteLine("Convert-image command", "Image without headers is {0} bytes.", DicConsole.DebugWriteLine("Convert-image command", "Image without headers is {0} bytes.",
inputFormat.Info.ImageSize); inputFormat.Info.ImageSize);
DicConsole.DebugWriteLine("Convert-image command", "Image has {0} sectors.", inputFormat.Info.Sectors); DicConsole.DebugWriteLine("Convert-image command", "Image has {0} sectors.", inputFormat.Info.Sectors);
DicConsole.DebugWriteLine("Convert-image command", "Image identifies media type as {0}.", DicConsole.DebugWriteLine("Convert-image command", "Image identifies media type as {0}.",
inputFormat.Info.MediaType); inputFormat.Info.MediaType);
@@ -312,85 +356,101 @@ namespace DiscImageChef.Commands
DicConsole.ErrorWriteLine("Unable to open image format"); DicConsole.ErrorWriteLine("Unable to open image format");
DicConsole.ErrorWriteLine("Error: {0}", ex.Message); DicConsole.ErrorWriteLine("Error: {0}", ex.Message);
DicConsole.DebugWriteLine("Convert-image command", "Stack trace: {0}", ex.StackTrace); DicConsole.DebugWriteLine("Convert-image command", "Stack trace: {0}", ex.StackTrace);
return (int)ErrorNumber.CannotOpenFormat;
return(int)ErrorNumber.CannotOpenFormat;
} }
List<IWritableImage> candidates = new List<IWritableImage>(); List<IWritableImage> candidates = new List<IWritableImage>();
// Try extension // Try extension
if(string.IsNullOrEmpty(wantedOutputFormat)) if(string.IsNullOrEmpty(format))
candidates.AddRange(plugins.WritableImages.Values.Where(t => candidates.AddRange(plugins.WritableImages.Values.Where(t =>
t.KnownExtensions t.KnownExtensions.
.Contains(Path.GetExtension(outputFile)))); Contains(Path.GetExtension(outputPath))));
// Try Id // Try Id
else if(Guid.TryParse(wantedOutputFormat, out Guid outId)) else if(Guid.TryParse(format, out Guid outId))
candidates.AddRange(plugins.WritableImages.Values.Where(t => t.Id.Equals(outId))); candidates.AddRange(plugins.WritableImages.Values.Where(t => t.Id.Equals(outId)));
// Try name // Try name
else else
candidates.AddRange(plugins.WritableImages.Values.Where(t => string.Equals(t.Name, wantedOutputFormat, candidates.AddRange(plugins.WritableImages.Values.Where(t => string.Equals(t.Name, format,
StringComparison StringComparison.
.InvariantCultureIgnoreCase))); InvariantCultureIgnoreCase)));
if(candidates.Count == 0) if(candidates.Count == 0)
{ {
DicConsole.WriteLine("No plugin supports requested extension."); DicConsole.WriteLine("No plugin supports requested extension.");
return (int)ErrorNumber.FormatNotFound;
return(int)ErrorNumber.FormatNotFound;
} }
if(candidates.Count > 1) if(candidates.Count > 1)
{ {
DicConsole.WriteLine("More than one plugin supports requested extension."); DicConsole.WriteLine("More than one plugin supports requested extension.");
return (int)ErrorNumber.TooManyFormats;
return(int)ErrorNumber.TooManyFormats;
} }
IWritableImage outputFormat = candidates[0]; IWritableImage outputFormat = candidates[0];
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLine("Output image format: {0} ({1}).", outputFormat.Name, outputFormat.Id); DicConsole.VerboseWriteLine("Output image format: {0} ({1}).", outputFormat.Name, outputFormat.Id);
else DicConsole.WriteLine("Output image format: {0}.", outputFormat.Name); else
DicConsole.WriteLine("Output image format: {0}.", outputFormat.Name);
if(!outputFormat.SupportedMediaTypes.Contains(inputFormat.Info.MediaType)) if(!outputFormat.SupportedMediaTypes.Contains(inputFormat.Info.MediaType))
{ {
DicConsole.ErrorWriteLine("Output format does not support media type, cannot continue..."); DicConsole.ErrorWriteLine("Output format does not support media type, cannot continue...");
return (int)ErrorNumber.UnsupportedMedia;
return(int)ErrorNumber.UnsupportedMedia;
} }
foreach(MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags) foreach(MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags)
{ {
if(outputFormat.SupportedMediaTags.Contains(mediaTag) || force) continue; if(outputFormat.SupportedMediaTags.Contains(mediaTag) || force)
continue;
DicConsole.ErrorWriteLine("Converting image will lose media tag {0}, not continuing...", mediaTag); DicConsole.ErrorWriteLine("Converting image will lose media tag {0}, not continuing...", mediaTag);
DicConsole.ErrorWriteLine("If you don't care, use force option."); DicConsole.ErrorWriteLine("If you don't care, use force option.");
return (int)ErrorNumber.DataWillBeLost;
return(int)ErrorNumber.DataWillBeLost;
} }
bool useLong = inputFormat.Info.ReadableSectorTags.Count != 0; bool useLong = inputFormat.Info.ReadableSectorTags.Count != 0;
foreach(SectorTagType sectorTag in inputFormat.Info.ReadableSectorTags) foreach(SectorTagType sectorTag in inputFormat.Info.ReadableSectorTags)
{ {
if(outputFormat.SupportedSectorTags.Contains(sectorTag)) continue; if(outputFormat.SupportedSectorTags.Contains(sectorTag))
continue;
if(force) if(force)
{ {
if(sectorTag != SectorTagType.CdTrackFlags && sectorTag != SectorTagType.CdTrackIsrc && if(sectorTag != SectorTagType.CdTrackFlags &&
sectorTag != SectorTagType.CdSectorSubchannel) useLong = false; sectorTag != SectorTagType.CdTrackIsrc &&
sectorTag != SectorTagType.CdSectorSubchannel)
useLong = false;
continue; continue;
} }
DicConsole.ErrorWriteLine("Converting image will lose sector tag {0}, not continuing...", sectorTag); DicConsole.ErrorWriteLine("Converting image will lose sector tag {0}, not continuing...", sectorTag);
DicConsole
.ErrorWriteLine("If you don't care, use force option. This will skip all sector tags converting only user data."); DicConsole.
return (int)ErrorNumber.DataWillBeLost; ErrorWriteLine("If you don't care, use force option. This will skip all sector tags converting only user data.");
return(int)ErrorNumber.DataWillBeLost;
} }
if(!outputFormat.Create(outputFile, inputFormat.Info.MediaType, parsedOptions, inputFormat.Info.Sectors, if(!outputFormat.Create(outputPath, inputFormat.Info.MediaType, parsedOptions, inputFormat.Info.Sectors,
inputFormat.Info.SectorSize)) inputFormat.Info.SectorSize))
{ {
DicConsole.ErrorWriteLine("Error {0} creating output image.", outputFormat.ErrorMessage); DicConsole.ErrorWriteLine("Error {0} creating output image.", outputFormat.ErrorMessage);
return (int)ErrorNumber.CannotCreateFormat;
return(int)ErrorNumber.CannotCreateFormat;
} }
ImageInfo metadata = new ImageInfo var metadata = new ImageInfo
{ {
Application = "DiscImageChef", Application = "DiscImageChef",
ApplicationVersion = Version.GetVersion(), ApplicationVersion = Version.GetVersion(),
@@ -413,10 +473,12 @@ namespace DiscImageChef.Commands
if(!outputFormat.SetMetadata(metadata)) if(!outputFormat.SetMetadata(metadata))
{ {
DicConsole.ErrorWrite("Error {0} setting metadata, ", outputFormat.ErrorMessage); DicConsole.ErrorWrite("Error {0} setting metadata, ", outputFormat.ErrorMessage);
if(!force) if(!force)
{ {
DicConsole.ErrorWriteLine("not continuing..."); DicConsole.ErrorWriteLine("not continuing...");
return (int)ErrorNumber.WriteError;
return(int)ErrorNumber.WriteError;
} }
DicConsole.ErrorWriteLine("continuing..."); DicConsole.ErrorWriteLine("continuing...");
@@ -427,11 +489,14 @@ namespace DiscImageChef.Commands
foreach(MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags) foreach(MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags)
{ {
if(force && !outputFormat.SupportedMediaTags.Contains(mediaTag)) continue; if(force && !outputFormat.SupportedMediaTags.Contains(mediaTag))
continue;
DicConsole.WriteLine("Converting media tag {0}", mediaTag); DicConsole.WriteLine("Converting media tag {0}", mediaTag);
byte[] tag = inputFormat.ReadDiskTag(mediaTag); byte[] tag = inputFormat.ReadDiskTag(mediaTag);
if(outputFormat.WriteMediaTag(tag, mediaTag)) continue;
if(outputFormat.WriteMediaTag(tag, mediaTag))
continue;
if(force) if(force)
DicConsole.ErrorWriteLine("Error {0} writing media tag, continuing...", outputFormat.ErrorMessage); DicConsole.ErrorWriteLine("Error {0} writing media tag, continuing...", outputFormat.ErrorMessage);
@@ -439,35 +504,41 @@ namespace DiscImageChef.Commands
{ {
DicConsole.ErrorWriteLine("Error {0} writing media tag, not continuing...", DicConsole.ErrorWriteLine("Error {0} writing media tag, not continuing...",
outputFormat.ErrorMessage); outputFormat.ErrorMessage);
return (int)ErrorNumber.WriteError;
return(int)ErrorNumber.WriteError;
} }
} }
DicConsole.WriteLine("{0} sectors to convert", inputFormat.Info.Sectors); DicConsole.WriteLine("{0} sectors to convert", inputFormat.Info.Sectors);
ulong doneSectors = 0; ulong doneSectors = 0;
if(inputFormat is IOpticalMediaImage inputOptical && outputFormat is IWritableOpticalImage outputOptical && if(inputFormat is IOpticalMediaImage inputOptical &&
outputFormat is IWritableOpticalImage outputOptical &&
inputOptical.Tracks != null) inputOptical.Tracks != null)
{ {
if(!outputOptical.SetTracks(inputOptical.Tracks)) if(!outputOptical.SetTracks(inputOptical.Tracks))
{ {
DicConsole.ErrorWriteLine("Error {0} sending tracks list to output image.", DicConsole.ErrorWriteLine("Error {0} sending tracks list to output image.",
outputFormat.ErrorMessage); outputFormat.ErrorMessage);
return (int)ErrorNumber.WriteError;
return(int)ErrorNumber.WriteError;
} }
foreach(Track track in inputOptical.Tracks) foreach(Track track in inputOptical.Tracks)
{ {
doneSectors = 0; doneSectors = 0;
ulong trackSectors = track.TrackEndSector - track.TrackStartSector + 1; ulong trackSectors = (track.TrackEndSector - track.TrackStartSector) + 1;
while(doneSectors < trackSectors) while(doneSectors < trackSectors)
{ {
byte[] sector; byte[] sector;
uint sectorsToDo; uint sectorsToDo;
if(trackSectors - doneSectors >= (ulong)count) sectorsToDo = (uint)count;
else sectorsToDo = (uint)(trackSectors - doneSectors); if(trackSectors - doneSectors >= (ulong)count)
sectorsToDo = (uint)count;
else
sectorsToDo = (uint)(trackSectors - doneSectors);
DicConsole.Write("\rConverting sectors {0} to {1} in track {3} ({2:P2} done)", DicConsole.Write("\rConverting sectors {0} to {1} in track {3} ({2:P2} done)",
doneSectors + track.TrackStartSector, doneSectors + track.TrackStartSector,
@@ -476,6 +547,7 @@ namespace DiscImageChef.Commands
track.TrackSequence); track.TrackSequence);
bool result; bool result;
if(useLong) if(useLong)
if(sectorsToDo == 1) if(sectorsToDo == 1)
{ {
@@ -485,6 +557,7 @@ namespace DiscImageChef.Commands
else else
{ {
sector = inputFormat.ReadSectorsLong(doneSectors + track.TrackStartSector, sectorsToDo); sector = inputFormat.ReadSectorsLong(doneSectors + track.TrackStartSector, sectorsToDo);
result = outputFormat.WriteSectorsLong(sector, doneSectors + track.TrackStartSector, result = outputFormat.WriteSectorsLong(sector, doneSectors + track.TrackStartSector,
sectorsToDo); sectorsToDo);
} }
@@ -498,6 +571,7 @@ namespace DiscImageChef.Commands
else else
{ {
sector = inputFormat.ReadSectors(doneSectors + track.TrackStartSector, sectorsToDo); sector = inputFormat.ReadSectors(doneSectors + track.TrackStartSector, sectorsToDo);
result = outputFormat.WriteSectors(sector, doneSectors + track.TrackStartSector, result = outputFormat.WriteSectors(sector, doneSectors + track.TrackStartSector,
sectorsToDo); sectorsToDo);
} }
@@ -511,7 +585,8 @@ namespace DiscImageChef.Commands
{ {
DicConsole.ErrorWriteLine("Error {0} writing sector {1}, not continuing...", DicConsole.ErrorWriteLine("Error {0} writing sector {1}, not continuing...",
outputFormat.ErrorMessage, doneSectors); outputFormat.ErrorMessage, doneSectors);
return (int)ErrorNumber.WriteError;
return(int)ErrorNumber.WriteError;
} }
doneSectors += sectorsToDo; doneSectors += sectorsToDo;
@@ -520,11 +595,13 @@ namespace DiscImageChef.Commands
DicConsole.Write("\rConverting sectors {0} to {1} in track {3} ({2:P2} done)", inputFormat.Info.Sectors, DicConsole.Write("\rConverting sectors {0} to {1} in track {3} ({2:P2} done)", inputFormat.Info.Sectors,
inputFormat.Info.Sectors, 1.0, inputOptical.Tracks.Count); inputFormat.Info.Sectors, 1.0, inputOptical.Tracks.Count);
DicConsole.WriteLine(); DicConsole.WriteLine();
foreach(SectorTagType tag in inputFormat.Info.ReadableSectorTags.OrderBy(t => t)) foreach(SectorTagType tag in inputFormat.Info.ReadableSectorTags.OrderBy(t => t))
{ {
if(!useLong) break; if(!useLong)
break;
switch(tag) switch(tag)
{ {
@@ -540,12 +617,13 @@ namespace DiscImageChef.Commands
continue; continue;
} }
if(force && !outputFormat.SupportedSectorTags.Contains(tag)) continue; if(force && !outputFormat.SupportedSectorTags.Contains(tag))
continue;
foreach(Track track in inputOptical.Tracks) foreach(Track track in inputOptical.Tracks)
{ {
doneSectors = 0; doneSectors = 0;
ulong trackSectors = track.TrackEndSector - track.TrackStartSector + 1; ulong trackSectors = (track.TrackEndSector - track.TrackStartSector) + 1;
byte[] sector; byte[] sector;
bool result; bool result;
@@ -556,8 +634,10 @@ namespace DiscImageChef.Commands
DicConsole.Write("\rConverting tag {0} in track {1} ({2:P2} done).", tag, DicConsole.Write("\rConverting tag {0} in track {1} ({2:P2} done).", tag,
track.TrackSequence, track.TrackSequence,
track.TrackSequence / (double)inputOptical.Tracks.Count); track.TrackSequence / (double)inputOptical.Tracks.Count);
sector = inputFormat.ReadSectorTag(track.TrackStartSector, tag); sector = inputFormat.ReadSectorTag(track.TrackStartSector, tag);
result = outputFormat.WriteSectorTag(sector, track.TrackStartSector, tag); result = outputFormat.WriteSectorTag(sector, track.TrackStartSector, tag);
if(!result) if(!result)
if(force) if(force)
DicConsole.ErrorWriteLine("Error {0} writing tag, continuing...", DicConsole.ErrorWriteLine("Error {0} writing tag, continuing...",
@@ -566,7 +646,8 @@ namespace DiscImageChef.Commands
{ {
DicConsole.ErrorWriteLine("Error {0} writing tag, not continuing...", DicConsole.ErrorWriteLine("Error {0} writing tag, not continuing...",
outputFormat.ErrorMessage); outputFormat.ErrorMessage);
return (int)ErrorNumber.WriteError;
return(int)ErrorNumber.WriteError;
} }
continue; continue;
@@ -575,10 +656,11 @@ namespace DiscImageChef.Commands
while(doneSectors < trackSectors) while(doneSectors < trackSectors)
{ {
uint sectorsToDo; uint sectorsToDo;
if(trackSectors - doneSectors >= (ulong)count) sectorsToDo = (uint)count;
if(trackSectors - doneSectors >= (ulong)count)
sectorsToDo = (uint)count;
else else
sectorsToDo = sectorsToDo = (uint)(trackSectors - doneSectors);
(uint)(trackSectors - doneSectors);
DicConsole.Write("\rConverting tag {4} for sectors {0} to {1} in track {3} ({2:P2} done)", DicConsole.Write("\rConverting tag {4} for sectors {0} to {1} in track {3} ({2:P2} done)",
doneSectors + track.TrackStartSector, doneSectors + track.TrackStartSector,
@@ -595,6 +677,7 @@ namespace DiscImageChef.Commands
{ {
sector = inputFormat.ReadSectorsTag(doneSectors + track.TrackStartSector, sectorsToDo, sector = inputFormat.ReadSectorsTag(doneSectors + track.TrackStartSector, sectorsToDo,
tag); tag);
result = outputFormat.WriteSectorsTag(sector, doneSectors + track.TrackStartSector, result = outputFormat.WriteSectorsTag(sector, doneSectors + track.TrackStartSector,
sectorsToDo, tag); sectorsToDo, tag);
} }
@@ -607,7 +690,8 @@ namespace DiscImageChef.Commands
{ {
DicConsole.ErrorWriteLine("Error {0} writing tag for sector {1}, not continuing...", DicConsole.ErrorWriteLine("Error {0} writing tag for sector {1}, not continuing...",
outputFormat.ErrorMessage, doneSectors); outputFormat.ErrorMessage, doneSectors);
return (int)ErrorNumber.WriteError;
return(int)ErrorNumber.WriteError;
} }
doneSectors += sectorsToDo; doneSectors += sectorsToDo;
@@ -620,11 +704,13 @@ namespace DiscImageChef.Commands
case SectorTagType.CdTrackIsrc: case SectorTagType.CdTrackIsrc:
DicConsole.Write("\rConverting tag {0} in track {1} ({2:P2} done).", tag, DicConsole.Write("\rConverting tag {0} in track {1} ({2:P2} done).", tag,
inputOptical.Tracks.Count, 1.0); inputOptical.Tracks.Count, 1.0);
break; break;
default: default:
DicConsole.Write("\rConverting tag {4} for sectors {0} to {1} in track {3} ({2:P2} done)", DicConsole.Write("\rConverting tag {4} for sectors {0} to {1} in track {3} ({2:P2} done)",
inputFormat.Info.Sectors, inputFormat.Info.Sectors, 1.0, inputFormat.Info.Sectors, inputFormat.Info.Sectors, 1.0,
inputOptical.Tracks.Count, tag); inputOptical.Tracks.Count, tag);
break; break;
} }
@@ -636,6 +722,7 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Setting geometry to {0} cylinders, {1} heads and {2} sectors per track", DicConsole.WriteLine("Setting geometry to {0} cylinders, {1} heads and {2} sectors per track",
inputFormat.Info.Cylinders, inputFormat.Info.Heads, inputFormat.Info.Cylinders, inputFormat.Info.Heads,
inputFormat.Info.SectorsPerTrack); inputFormat.Info.SectorsPerTrack);
if(!outputFormat.SetGeometry(inputFormat.Info.Cylinders, inputFormat.Info.Heads, if(!outputFormat.SetGeometry(inputFormat.Info.Cylinders, inputFormat.Info.Heads,
inputFormat.Info.SectorsPerTrack)) inputFormat.Info.SectorsPerTrack))
DicConsole.ErrorWriteLine("Error {0} setting geometry, image may be incorrect, continuing...", DicConsole.ErrorWriteLine("Error {0} setting geometry, image may be incorrect, continuing...",
@@ -646,15 +733,17 @@ namespace DiscImageChef.Commands
byte[] sector; byte[] sector;
uint sectorsToDo; uint sectorsToDo;
if(inputFormat.Info.Sectors - doneSectors >= (ulong)count) sectorsToDo = (uint)count;
if(inputFormat.Info.Sectors - doneSectors >= (ulong)count)
sectorsToDo = (uint)count;
else else
sectorsToDo = sectorsToDo = (uint)(inputFormat.Info.Sectors - doneSectors);
(uint)(inputFormat.Info.Sectors - doneSectors);
DicConsole.Write("\rConverting sectors {0} to {1} ({2:P2} done)", doneSectors, DicConsole.Write("\rConverting sectors {0} to {1} ({2:P2} done)", doneSectors,
doneSectors + sectorsToDo, doneSectors / (double)inputFormat.Info.Sectors); doneSectors + sectorsToDo, doneSectors / (double)inputFormat.Info.Sectors);
bool result; bool result;
if(useLong) if(useLong)
if(sectorsToDo == 1) if(sectorsToDo == 1)
{ {
@@ -688,7 +777,8 @@ namespace DiscImageChef.Commands
{ {
DicConsole.ErrorWriteLine("Error {0} writing sector {1}, not continuing...", DicConsole.ErrorWriteLine("Error {0} writing sector {1}, not continuing...",
outputFormat.ErrorMessage, doneSectors); outputFormat.ErrorMessage, doneSectors);
return (int)ErrorNumber.WriteError;
return(int)ErrorNumber.WriteError;
} }
doneSectors += sectorsToDo; doneSectors += sectorsToDo;
@@ -696,11 +786,13 @@ namespace DiscImageChef.Commands
DicConsole.Write("\rConverting sectors {0} to {1} ({2:P2} done)", inputFormat.Info.Sectors, DicConsole.Write("\rConverting sectors {0} to {1} ({2:P2} done)", inputFormat.Info.Sectors,
inputFormat.Info.Sectors, 1.0); inputFormat.Info.Sectors, 1.0);
DicConsole.WriteLine(); DicConsole.WriteLine();
foreach(SectorTagType tag in inputFormat.Info.ReadableSectorTags) foreach(SectorTagType tag in inputFormat.Info.ReadableSectorTags)
{ {
if(!useLong) break; if(!useLong)
break;
switch(tag) switch(tag)
{ {
@@ -716,24 +808,28 @@ namespace DiscImageChef.Commands
continue; continue;
} }
if(force && !outputFormat.SupportedSectorTags.Contains(tag)) continue; if(force && !outputFormat.SupportedSectorTags.Contains(tag))
continue;
doneSectors = 0; doneSectors = 0;
while(doneSectors < inputFormat.Info.Sectors) while(doneSectors < inputFormat.Info.Sectors)
{ {
byte[] sector; byte[] sector;
uint sectorsToDo; uint sectorsToDo;
if(inputFormat.Info.Sectors - doneSectors >= (ulong)count) sectorsToDo = (uint)count;
if(inputFormat.Info.Sectors - doneSectors >= (ulong)count)
sectorsToDo = (uint)count;
else else
sectorsToDo = sectorsToDo = (uint)(inputFormat.Info.Sectors - doneSectors);
(uint)(inputFormat.Info.Sectors - doneSectors);
DicConsole.Write("\rConverting tag {2} for sectors {0} to {1} ({2:P2} done)", doneSectors, DicConsole.Write("\rConverting tag {2} for sectors {0} to {1} ({2:P2} done)", doneSectors,
doneSectors + sectorsToDo, doneSectors / (double)inputFormat.Info.Sectors, doneSectors + sectorsToDo, doneSectors / (double)inputFormat.Info.Sectors,
tag); tag);
bool result; bool result;
if(sectorsToDo == 1) if(sectorsToDo == 1)
{ {
sector = inputFormat.ReadSectorTag(doneSectors, tag); sector = inputFormat.ReadSectorTag(doneSectors, tag);
@@ -753,7 +849,8 @@ namespace DiscImageChef.Commands
{ {
DicConsole.ErrorWriteLine("Error {0} writing sector {1}, not continuing...", DicConsole.ErrorWriteLine("Error {0} writing sector {1}, not continuing...",
outputFormat.ErrorMessage, doneSectors); outputFormat.ErrorMessage, doneSectors);
return (int)ErrorNumber.WriteError;
return(int)ErrorNumber.WriteError;
} }
doneSectors += sectorsToDo; doneSectors += sectorsToDo;
@@ -761,24 +858,37 @@ namespace DiscImageChef.Commands
DicConsole.Write("\rConverting tag {2} for sectors {0} to {1} ({2:P2} done)", DicConsole.Write("\rConverting tag {2} for sectors {0} to {1} ({2:P2} done)",
inputFormat.Info.Sectors, inputFormat.Info.Sectors, 1.0, tag); inputFormat.Info.Sectors, inputFormat.Info.Sectors, 1.0, tag);
DicConsole.WriteLine(); DicConsole.WriteLine();
} }
} }
bool ret = false; bool ret = false;
if(resume != null || dumpHardware != null)
if(resume != null ||
dumpHardware != null)
{ {
if(resume != null) ret = outputFormat.SetDumpHardware(resume.Tries); if(resume != null)
else if(dumpHardware != null) ret = outputFormat.SetDumpHardware(dumpHardware); ret = outputFormat.SetDumpHardware(resume.Tries);
if(ret) DicConsole.WriteLine("Written dump hardware list to output image."); else if(dumpHardware != null)
ret = outputFormat.SetDumpHardware(dumpHardware);
if(ret)
DicConsole.WriteLine("Written dump hardware list to output image.");
} }
ret = false; ret = false;
if(sidecar != null || cicmMetadata != null)
if(sidecar != null ||
cicmMetadata != null)
{ {
if(sidecar != null) ret = outputFormat.SetCicmMetadata(sidecar); if(sidecar != null)
else if(cicmMetadata != null) ret = outputFormat.SetCicmMetadata(cicmMetadata); ret = outputFormat.SetCicmMetadata(sidecar);
if(ret) DicConsole.WriteLine("Written CICM XML metadata to output image."); else if(cicmMetadata != null)
ret = outputFormat.SetCicmMetadata(cicmMetadata);
if(ret)
DicConsole.WriteLine("Written CICM XML metadata to output image.");
} }
DicConsole.WriteLine("Closing output image."); DicConsole.WriteLine("Closing output image.");
@@ -790,7 +900,7 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Conversion done."); DicConsole.WriteLine("Conversion done.");
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
} }
} }

View File

@@ -32,6 +32,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -41,109 +43,109 @@ using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using Mono.Options;
using Schemas; using Schemas;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class CreateSidecarCommand : Command internal class CreateSidecarCommand : Command
{ {
uint blockSize;
string encodingName;
string inputFile;
bool showHelp;
bool tape;
public CreateSidecarCommand() : base("create-sidecar", "Creates CICM Metadata XML sidecar.") public CreateSidecarCommand() : base("create-sidecar", "Creates CICM Metadata XML sidecar.")
{ {
Options = new OptionSet Add(new Option(new[]
{
"--block-size", "-b"
},
"Only used for tapes, indicates block size. Files in the folder whose size is not a multiple of this value will simply be ignored.")
{ {
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", Argument = new Argument<int>(() => 512), Required = false
$"{MainClass.AssemblyCopyright}", });
"",
$"usage: DiscImageChef {Name} [OPTIONS] input", Add(new Option(new[]
"",
Help,
{ {
"block-size|b=", "--encoding", "-e"
"Only used for tapes, indicates block size. Files in the folder whose size is not a multiple of this value will simply be ignored.", }, "Name of character encoding to use.")
(uint i) => blockSize = i
},
{"encoding|e=", "Name of character encoding to use.", s => encodingName = s},
{ {
"tape|t", Argument = new Argument<string>(() => null), Required = false
"When used indicates that input is a folder containing alphabetically sorted files extracted from a linear block-based tape with fixed block size (e.g. a SCSI tape device).", });
b => tape = b != null
}, Add(new Option(new[]
{"help|h|?", "Show this message and exit.", v => showHelp = v != null} {
}; "--encoding", "-e"
}, "Name of character encoding to use.")
{
Argument = new Argument<string>(() => null), Required = false
});
Add(new Option(new[]
{
"--tape", "-t"
},
"When used indicates that input is a folder containing alphabetically sorted files extracted from a linear block-based tape with fixed block size (e.g. a SCSI tape device).")
{
Argument = new Argument<bool>(() => false), Required = false
});
AddArgument(new Argument<string>
{
Arity = ArgumentArity.ExactlyOne, Description = "Media image path", Name = "image-path"
});
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
} }
public override int Invoke(IEnumerable<string> arguments) static int Invoke(bool debug, bool verbose, uint blockSize, string encodingName, string imagePath, bool tape)
{ {
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("create-sidecar"); Statistics.AddCommand("create-sidecar");
if(extra.Count > 1)
{
DicConsole.ErrorWriteLine("Too many arguments.");
return (int)ErrorNumber.UnexpectedArgumentCount;
}
if(extra.Count == 0)
{
DicConsole.ErrorWriteLine("Missing input image.");
return (int)ErrorNumber.MissingArgument;
}
inputFile = extra[0];
DicConsole.DebugWriteLine("Create sidecar command", "--block-size={0}", blockSize); DicConsole.DebugWriteLine("Create sidecar command", "--block-size={0}", blockSize);
DicConsole.DebugWriteLine("Create sidecar command", "--debug={0}", MainClass.Debug); DicConsole.DebugWriteLine("Create sidecar command", "--debug={0}", debug);
DicConsole.DebugWriteLine("Create sidecar command", "--encoding={0}", encodingName); DicConsole.DebugWriteLine("Create sidecar command", "--encoding={0}", encodingName);
DicConsole.DebugWriteLine("Create sidecar command", "--input={0}", inputFile); DicConsole.DebugWriteLine("Create sidecar command", "--input={0}", imagePath);
DicConsole.DebugWriteLine("Create sidecar command", "--tape={0}", tape); DicConsole.DebugWriteLine("Create sidecar command", "--tape={0}", tape);
DicConsole.DebugWriteLine("Create sidecar command", "--verbose={0}", MainClass.Verbose); DicConsole.DebugWriteLine("Create sidecar command", "--verbose={0}", verbose);
Encoding encoding = null; Encoding encodingClass = null;
if(encodingName != null) if(encodingName != null)
try try
{ {
encoding = Claunia.Encoding.Encoding.GetEncoding(encodingName); encodingClass = Claunia.Encoding.Encoding.GetEncoding(encodingName);
if(MainClass.Verbose) DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName);
if(verbose)
DicConsole.VerboseWriteLine("Using encoding for {0}.", encodingClass.EncodingName);
} }
catch(ArgumentException) catch(ArgumentException)
{ {
DicConsole.ErrorWriteLine("Specified encoding is not supported."); DicConsole.ErrorWriteLine("Specified encoding is not supported.");
return (int)ErrorNumber.EncodingUnknown;
return(int)ErrorNumber.EncodingUnknown;
} }
if(File.Exists(inputFile)) if(File.Exists(imagePath))
{ {
if(tape) if(tape)
{ {
DicConsole.ErrorWriteLine("You cannot use --tape option when input is a file."); DicConsole.ErrorWriteLine("You cannot use --tape option when input is a file.");
return (int)ErrorNumber.ExpectedDirectory;
return(int)ErrorNumber.ExpectedDirectory;
} }
FiltersList filtersList = new FiltersList(); var filtersList = new FiltersList();
IFilter inputFilter = filtersList.GetFilter(inputFile); IFilter inputFilter = filtersList.GetFilter(imagePath);
if(inputFilter == null) if(inputFilter == null)
{ {
DicConsole.ErrorWriteLine("Cannot open specified file."); DicConsole.ErrorWriteLine("Cannot open specified file.");
return (int)ErrorNumber.CannotOpenFile;
return(int)ErrorNumber.CannotOpenFile;
} }
try try
@@ -153,13 +155,15 @@ namespace DiscImageChef.Commands
if(imageFormat == null) if(imageFormat == null)
{ {
DicConsole.WriteLine("Image format not identified, not proceeding with analysis."); DicConsole.WriteLine("Image format not identified, not proceeding with analysis.");
return (int)ErrorNumber.UnrecognizedFormat;
return(int)ErrorNumber.UnrecognizedFormat;
} }
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name, DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name,
imageFormat.Id); imageFormat.Id);
else DicConsole.WriteLine("Image format identified by {0}.", imageFormat.Name); else
DicConsole.WriteLine("Image format identified by {0}.", imageFormat.Name);
try try
{ {
@@ -167,7 +171,8 @@ namespace DiscImageChef.Commands
{ {
DicConsole.WriteLine("Unable to open image format"); DicConsole.WriteLine("Unable to open image format");
DicConsole.WriteLine("No error given"); DicConsole.WriteLine("No error given");
return (int)ErrorNumber.CannotOpenFormat;
return(int)ErrorNumber.CannotOpenFormat;
} }
DicConsole.DebugWriteLine("Analyze command", "Correctly opened image file."); DicConsole.DebugWriteLine("Analyze command", "Correctly opened image file.");
@@ -176,13 +181,14 @@ namespace DiscImageChef.Commands
{ {
DicConsole.ErrorWriteLine("Unable to open image format"); DicConsole.ErrorWriteLine("Unable to open image format");
DicConsole.ErrorWriteLine("Error: {0}", ex.Message); DicConsole.ErrorWriteLine("Error: {0}", ex.Message);
return (int)ErrorNumber.CannotOpenFormat;
return(int)ErrorNumber.CannotOpenFormat;
} }
Statistics.AddMediaFormat(imageFormat.Format); Statistics.AddMediaFormat(imageFormat.Format);
Statistics.AddFilter(inputFilter.Name); Statistics.AddFilter(inputFilter.Name);
Sidecar sidecarClass = new Sidecar(imageFormat, inputFile, inputFilter.Id, encoding); var sidecarClass = new Sidecar(imageFormat, imagePath, inputFilter.Id, encodingClass);
sidecarClass.InitProgressEvent += Progress.InitProgress; sidecarClass.InitProgressEvent += Progress.InitProgress;
sidecarClass.UpdateProgressEvent += Progress.UpdateProgress; sidecarClass.UpdateProgressEvent += Progress.UpdateProgress;
sidecarClass.EndProgressEvent += Progress.EndProgress; sidecarClass.EndProgressEvent += Progress.EndProgress;
@@ -190,21 +196,23 @@ namespace DiscImageChef.Commands
sidecarClass.UpdateProgressEvent2 += Progress.UpdateProgress2; sidecarClass.UpdateProgressEvent2 += Progress.UpdateProgress2;
sidecarClass.EndProgressEvent2 += Progress.EndProgress2; sidecarClass.EndProgressEvent2 += Progress.EndProgress2;
sidecarClass.UpdateStatusEvent += Progress.UpdateStatus; sidecarClass.UpdateStatusEvent += Progress.UpdateStatus;
System.Console.CancelKeyPress += (sender, e) => System.Console.CancelKeyPress += (sender, e) =>
{ {
e.Cancel = true; e.Cancel = true;
sidecarClass.Abort(); sidecarClass.Abort();
}; };
CICMMetadataType sidecar = sidecarClass.Create(); CICMMetadataType sidecar = sidecarClass.Create();
DicConsole.WriteLine("Writing metadata sidecar"); DicConsole.WriteLine("Writing metadata sidecar");
FileStream xmlFs = var xmlFs =
new new
FileStream(Path.Combine(Path.GetDirectoryName(inputFile) ?? throw new InvalidOperationException(), Path.GetFileNameWithoutExtension(inputFile) + ".cicm.xml"), FileStream(Path.Combine(Path.GetDirectoryName(imagePath) ?? throw new InvalidOperationException(), Path.GetFileNameWithoutExtension(imagePath) + ".cicm.xml"),
FileMode.CreateNew); FileMode.CreateNew);
XmlSerializer xmlSer = new XmlSerializer(typeof(CICMMetadataType)); var xmlSer = new XmlSerializer(typeof(CICMMetadataType));
xmlSer.Serialize(xmlFs, sidecar); xmlSer.Serialize(xmlFs, sidecar);
xmlFs.Close(); xmlFs.Close();
} }
@@ -212,23 +220,25 @@ namespace DiscImageChef.Commands
{ {
DicConsole.ErrorWriteLine($"Error reading file: {ex.Message}"); DicConsole.ErrorWriteLine($"Error reading file: {ex.Message}");
DicConsole.DebugWriteLine("Analyze command", ex.StackTrace); DicConsole.DebugWriteLine("Analyze command", ex.StackTrace);
return (int)ErrorNumber.UnexpectedException;
return(int)ErrorNumber.UnexpectedException;
} }
} }
else if(Directory.Exists(inputFile)) else if(Directory.Exists(imagePath))
{ {
if(!tape) if(!tape)
{ {
DicConsole.ErrorWriteLine("Cannot create a sidecar from a directory."); DicConsole.ErrorWriteLine("Cannot create a sidecar from a directory.");
return (int)ErrorNumber.ExpectedFile;
return(int)ErrorNumber.ExpectedFile;
} }
string[] contents = Directory.GetFiles(inputFile, "*", SearchOption.TopDirectoryOnly); string[] contents = Directory.GetFiles(imagePath, "*", SearchOption.TopDirectoryOnly);
List<string> files = contents.Where(file => new FileInfo(file).Length % blockSize == 0).ToList(); List<string> files = contents.Where(file => new FileInfo(file).Length % blockSize == 0).ToList();
files.Sort(StringComparer.CurrentCultureIgnoreCase); files.Sort(StringComparer.CurrentCultureIgnoreCase);
Sidecar sidecarClass = new Sidecar(); var sidecarClass = new Sidecar();
sidecarClass.InitProgressEvent += Progress.InitProgress; sidecarClass.InitProgressEvent += Progress.InitProgress;
sidecarClass.UpdateProgressEvent += Progress.UpdateProgress; sidecarClass.UpdateProgressEvent += Progress.UpdateProgress;
sidecarClass.EndProgressEvent += Progress.EndProgress; sidecarClass.EndProgressEvent += Progress.EndProgress;
@@ -236,22 +246,23 @@ namespace DiscImageChef.Commands
sidecarClass.UpdateProgressEvent2 += Progress.UpdateProgress2; sidecarClass.UpdateProgressEvent2 += Progress.UpdateProgress2;
sidecarClass.EndProgressEvent2 += Progress.EndProgress2; sidecarClass.EndProgressEvent2 += Progress.EndProgress2;
sidecarClass.UpdateStatusEvent += Progress.UpdateStatus; sidecarClass.UpdateStatusEvent += Progress.UpdateStatus;
CICMMetadataType sidecar = sidecarClass.BlockTape(Path.GetFileName(inputFile), files, blockSize); CICMMetadataType sidecar = sidecarClass.BlockTape(Path.GetFileName(imagePath), files, blockSize);
DicConsole.WriteLine("Writing metadata sidecar"); DicConsole.WriteLine("Writing metadata sidecar");
FileStream xmlFs = var xmlFs =
new new
FileStream(Path.Combine(Path.GetDirectoryName(inputFile) ?? throw new InvalidOperationException(), Path.GetFileNameWithoutExtension(inputFile) + ".cicm.xml"), FileStream(Path.Combine(Path.GetDirectoryName(imagePath) ?? throw new InvalidOperationException(), Path.GetFileNameWithoutExtension(imagePath) + ".cicm.xml"),
FileMode.CreateNew); FileMode.CreateNew);
XmlSerializer xmlSer = new XmlSerializer(typeof(CICMMetadataType)); var xmlSer = new XmlSerializer(typeof(CICMMetadataType));
xmlSer.Serialize(xmlFs, sidecar); xmlSer.Serialize(xmlFs, sidecar);
xmlFs.Close(); xmlFs.Close();
} }
else DicConsole.ErrorWriteLine("The specified input file cannot be found."); else
DicConsole.ErrorWriteLine("The specified input file cannot be found.");
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
} }
} }

View File

@@ -30,7 +30,8 @@
// Copyright © 2011-2019 Natalia Portillo // Copyright © 2011-2019 Natalia Portillo
// ****************************************************************************/ // ****************************************************************************/
using System.Collections.Generic; using System.CommandLine;
using System.CommandLine.Invocation;
using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.CommonTypes.Interfaces;
@@ -39,81 +40,82 @@ using DiscImageChef.Core;
using DiscImageChef.Decoders.ATA; using DiscImageChef.Decoders.ATA;
using DiscImageChef.Decoders.CD; using DiscImageChef.Decoders.CD;
using DiscImageChef.Decoders.SCSI; using DiscImageChef.Decoders.SCSI;
using Mono.Options;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class DecodeCommand : Command internal class DecodeCommand : Command
{ {
bool diskTags = true;
string inputFile;
string length = "all";
bool sectorTags = true;
bool showHelp;
ulong startSector;
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.")
{ {
Options = new OptionSet 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>
{ {
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", Arity = ArgumentArity.ExactlyOne, Description = "Media image path", Name = "image-path"
$"{MainClass.AssemblyCopyright}", });
"",
$"usage: DiscImageChef {Name} [OPTIONS] imagefile", Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
"",
Help,
{"disk-tags|f", "Decode disk tags.", b => diskTags = b != null},
{"length|l=", "How many sectors to decode, or \"all\".", s => length = s},
{"sector-tags|p", "Decode sector tags.", b => sectorTags = b != null},
{"start|s=", "Name of character encoding to use.", (ulong ul) => startSector = ul},
{"help|h|?", "Show this message and exit.", v => showHelp = v != null}
};
} }
public override int Invoke(IEnumerable<string> arguments) static int Invoke(bool verbose, bool debug, bool diskTags, string imagePath, string length, bool sectorTags,
ulong startSector)
{ {
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("decode"); Statistics.AddCommand("decode");
if(extra.Count > 1) DicConsole.DebugWriteLine("Decode command", "--debug={0}", debug);
{ DicConsole.DebugWriteLine("Decode command", "--disk-tags={0}", diskTags);
DicConsole.ErrorWriteLine("Too many arguments."); DicConsole.DebugWriteLine("Decode command", "--input={0}", imagePath);
return (int)ErrorNumber.UnexpectedArgumentCount; DicConsole.DebugWriteLine("Decode command", "--length={0}", length);
}
if(extra.Count == 0)
{
DicConsole.ErrorWriteLine("Missing input image.");
return (int)ErrorNumber.MissingArgument;
}
inputFile = extra[0];
DicConsole.DebugWriteLine("Decode command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("Decode command", "--disk-tags={0}", diskTags);
DicConsole.DebugWriteLine("Decode command", "--input={0}", inputFile);
DicConsole.DebugWriteLine("Decode command", "--length={0}", length);
DicConsole.DebugWriteLine("Decode command", "--sector-tags={0}", sectorTags); DicConsole.DebugWriteLine("Decode command", "--sector-tags={0}", sectorTags);
DicConsole.DebugWriteLine("Decode command", "--start={0}", startSector); DicConsole.DebugWriteLine("Decode command", "--start={0}", startSector);
DicConsole.DebugWriteLine("Decode command", "--verbose={0}", MainClass.Verbose); DicConsole.DebugWriteLine("Decode command", "--verbose={0}", verbose);
FiltersList filtersList = new FiltersList(); var filtersList = new FiltersList();
IFilter inputFilter = filtersList.GetFilter(inputFile); IFilter inputFilter = filtersList.GetFilter(imagePath);
if(inputFilter == null) if(inputFilter == null)
{ {
DicConsole.ErrorWriteLine("Cannot open specified file."); DicConsole.ErrorWriteLine("Cannot open specified file.");
return (int)ErrorNumber.CannotOpenFile;
return(int)ErrorNumber.CannotOpenFile;
} }
IMediaImage inputFormat = ImageFormat.Detect(inputFilter); IMediaImage inputFormat = ImageFormat.Detect(inputFilter);
@@ -121,7 +123,8 @@ namespace DiscImageChef.Commands
if(inputFormat == null) if(inputFormat == null)
{ {
DicConsole.ErrorWriteLine("Unable to recognize image format, not decoding"); DicConsole.ErrorWriteLine("Unable to recognize image format, not decoding");
return (int)ErrorNumber.UnrecognizedFormat;
return(int)ErrorNumber.UnrecognizedFormat;
} }
inputFormat.Open(inputFilter); inputFormat.Open(inputFilter);
@@ -139,16 +142,20 @@ namespace DiscImageChef.Commands
case MediaTagType.SCSI_INQUIRY: case MediaTagType.SCSI_INQUIRY:
{ {
byte[] inquiry = inputFormat.ReadDiskTag(MediaTagType.SCSI_INQUIRY); byte[] inquiry = inputFormat.ReadDiskTag(MediaTagType.SCSI_INQUIRY);
if(inquiry == null) if(inquiry == null)
DicConsole.WriteLine("Error reading SCSI INQUIRY response from disc image"); DicConsole.WriteLine("Error reading SCSI INQUIRY response from disc image");
else else
{ {
DicConsole.WriteLine("SCSI INQUIRY command response:"); DicConsole.WriteLine("SCSI INQUIRY command response:");
DicConsole
.WriteLine("================================================================================"); DicConsole.
WriteLine("================================================================================");
DicConsole.WriteLine(Inquiry.Prettify(inquiry)); DicConsole.WriteLine(Inquiry.Prettify(inquiry));
DicConsole
.WriteLine("================================================================================"); DicConsole.
WriteLine("================================================================================");
} }
break; break;
@@ -156,16 +163,20 @@ namespace DiscImageChef.Commands
case MediaTagType.ATA_IDENTIFY: case MediaTagType.ATA_IDENTIFY:
{ {
byte[] identify = inputFormat.ReadDiskTag(MediaTagType.ATA_IDENTIFY); byte[] identify = inputFormat.ReadDiskTag(MediaTagType.ATA_IDENTIFY);
if(identify == null) if(identify == null)
DicConsole.WriteLine("Error reading ATA IDENTIFY DEVICE response from disc image"); DicConsole.WriteLine("Error reading ATA IDENTIFY DEVICE response from disc image");
else else
{ {
DicConsole.WriteLine("ATA IDENTIFY DEVICE command response:"); DicConsole.WriteLine("ATA IDENTIFY DEVICE command response:");
DicConsole
.WriteLine("================================================================================"); DicConsole.
WriteLine("================================================================================");
DicConsole.WriteLine(Identify.Prettify(identify)); DicConsole.WriteLine(Identify.Prettify(identify));
DicConsole
.WriteLine("================================================================================"); DicConsole.
WriteLine("================================================================================");
} }
break; break;
@@ -173,17 +184,21 @@ namespace DiscImageChef.Commands
case MediaTagType.ATAPI_IDENTIFY: case MediaTagType.ATAPI_IDENTIFY:
{ {
byte[] identify = inputFormat.ReadDiskTag(MediaTagType.ATAPI_IDENTIFY); byte[] identify = inputFormat.ReadDiskTag(MediaTagType.ATAPI_IDENTIFY);
if(identify == null) if(identify == null)
DicConsole DicConsole.
.WriteLine("Error reading ATA IDENTIFY PACKET DEVICE response from disc image"); WriteLine("Error reading ATA IDENTIFY PACKET DEVICE response from disc image");
else else
{ {
DicConsole.WriteLine("ATA IDENTIFY PACKET DEVICE command response:"); DicConsole.WriteLine("ATA IDENTIFY PACKET DEVICE command response:");
DicConsole
.WriteLine("================================================================================"); DicConsole.
WriteLine("================================================================================");
DicConsole.WriteLine(Identify.Prettify(identify)); DicConsole.WriteLine(Identify.Prettify(identify));
DicConsole
.WriteLine("================================================================================"); DicConsole.
WriteLine("================================================================================");
} }
break; break;
@@ -191,31 +206,41 @@ namespace DiscImageChef.Commands
case MediaTagType.CD_ATIP: case MediaTagType.CD_ATIP:
{ {
byte[] atip = inputFormat.ReadDiskTag(MediaTagType.CD_ATIP); byte[] atip = inputFormat.ReadDiskTag(MediaTagType.CD_ATIP);
if(atip == null) DicConsole.WriteLine("Error reading CD ATIP from disc image");
if(atip == null)
DicConsole.WriteLine("Error reading CD ATIP from disc image");
else else
{ {
DicConsole.WriteLine("CD ATIP:"); DicConsole.WriteLine("CD ATIP:");
DicConsole
.WriteLine("================================================================================"); DicConsole.
WriteLine("================================================================================");
DicConsole.WriteLine(ATIP.Prettify(atip)); DicConsole.WriteLine(ATIP.Prettify(atip));
DicConsole
.WriteLine("================================================================================"); DicConsole.
WriteLine("================================================================================");
} }
break; break;
} }
case MediaTagType.CD_FullTOC: case MediaTagType.CD_FullTOC:
{ {
byte[] fulltoc = inputFormat.ReadDiskTag(MediaTagType.CD_FullTOC); byte[] fullToc = inputFormat.ReadDiskTag(MediaTagType.CD_FullTOC);
if(fulltoc == null) DicConsole.WriteLine("Error reading CD full TOC from disc image");
if(fullToc == null)
DicConsole.WriteLine("Error reading CD full TOC from disc image");
else else
{ {
DicConsole.WriteLine("CD full TOC:"); DicConsole.WriteLine("CD full TOC:");
DicConsole
.WriteLine("================================================================================"); DicConsole.
DicConsole.WriteLine(FullTOC.Prettify(fulltoc)); WriteLine("================================================================================");
DicConsole
.WriteLine("================================================================================"); DicConsole.WriteLine(FullTOC.Prettify(fullToc));
DicConsole.
WriteLine("================================================================================");
} }
break; break;
@@ -223,48 +248,62 @@ namespace DiscImageChef.Commands
case MediaTagType.CD_PMA: case MediaTagType.CD_PMA:
{ {
byte[] pma = inputFormat.ReadDiskTag(MediaTagType.CD_PMA); byte[] pma = inputFormat.ReadDiskTag(MediaTagType.CD_PMA);
if(pma == null) DicConsole.WriteLine("Error reading CD PMA from disc image");
if(pma == null)
DicConsole.WriteLine("Error reading CD PMA from disc image");
else else
{ {
DicConsole.WriteLine("CD PMA:"); DicConsole.WriteLine("CD PMA:");
DicConsole
.WriteLine("================================================================================"); DicConsole.
WriteLine("================================================================================");
DicConsole.WriteLine(PMA.Prettify(pma)); DicConsole.WriteLine(PMA.Prettify(pma));
DicConsole
.WriteLine("================================================================================"); DicConsole.
WriteLine("================================================================================");
} }
break; break;
} }
case MediaTagType.CD_SessionInfo: case MediaTagType.CD_SessionInfo:
{ {
byte[] sessioninfo = inputFormat.ReadDiskTag(MediaTagType.CD_SessionInfo); byte[] sessionInfo = inputFormat.ReadDiskTag(MediaTagType.CD_SessionInfo);
if(sessioninfo == null)
if(sessionInfo == null)
DicConsole.WriteLine("Error reading CD session information from disc image"); DicConsole.WriteLine("Error reading CD session information from disc image");
else else
{ {
DicConsole.WriteLine("CD session information:"); DicConsole.WriteLine("CD session information:");
DicConsole
.WriteLine("================================================================================"); DicConsole.
DicConsole.WriteLine(Session.Prettify(sessioninfo)); WriteLine("================================================================================");
DicConsole
.WriteLine("================================================================================"); DicConsole.WriteLine(Session.Prettify(sessionInfo));
DicConsole.
WriteLine("================================================================================");
} }
break; break;
} }
case MediaTagType.CD_TEXT: case MediaTagType.CD_TEXT:
{ {
byte[] cdtext = inputFormat.ReadDiskTag(MediaTagType.CD_TEXT); byte[] cdText = inputFormat.ReadDiskTag(MediaTagType.CD_TEXT);
if(cdtext == null) DicConsole.WriteLine("Error reading CD-TEXT from disc image");
if(cdText == null)
DicConsole.WriteLine("Error reading CD-TEXT from disc image");
else else
{ {
DicConsole.WriteLine("CD-TEXT:"); DicConsole.WriteLine("CD-TEXT:");
DicConsole
.WriteLine("================================================================================"); DicConsole.
DicConsole.WriteLine(CDTextOnLeadIn.Prettify(cdtext)); WriteLine("================================================================================");
DicConsole
.WriteLine("================================================================================"); DicConsole.WriteLine(CDTextOnLeadIn.Prettify(cdText));
DicConsole.
WriteLine("================================================================================");
} }
break; break;
@@ -272,15 +311,20 @@ namespace DiscImageChef.Commands
case MediaTagType.CD_TOC: case MediaTagType.CD_TOC:
{ {
byte[] toc = inputFormat.ReadDiskTag(MediaTagType.CD_TOC); byte[] toc = inputFormat.ReadDiskTag(MediaTagType.CD_TOC);
if(toc == null) DicConsole.WriteLine("Error reading CD TOC from disc image");
if(toc == null)
DicConsole.WriteLine("Error reading CD TOC from disc image");
else else
{ {
DicConsole.WriteLine("CD TOC:"); DicConsole.WriteLine("CD TOC:");
DicConsole
.WriteLine("================================================================================"); DicConsole.
WriteLine("================================================================================");
DicConsole.WriteLine(TOC.Prettify(toc)); DicConsole.WriteLine(TOC.Prettify(toc));
DicConsole
.WriteLine("================================================================================"); DicConsole.
WriteLine("================================================================================");
} }
break; break;
@@ -288,6 +332,7 @@ namespace DiscImageChef.Commands
default: default:
DicConsole.WriteLine("Decoder for disk tag type \"{0}\" not yet implemented, sorry.", DicConsole.WriteLine("Decoder for disk tag type \"{0}\" not yet implemented, sorry.",
tag); tag);
break; break;
} }
@@ -300,6 +345,7 @@ namespace DiscImageChef.Commands
{ {
DicConsole.WriteLine("Value \"{0}\" is not a valid number for length.", length); DicConsole.WriteLine("Value \"{0}\" is not a valid number for length.", length);
DicConsole.WriteLine("Not decoding sectors tags"); DicConsole.WriteLine("Not decoding sectors tags");
return 3; return 3;
} }
} }
@@ -313,13 +359,14 @@ namespace DiscImageChef.Commands
default: default:
DicConsole.WriteLine("Decoder for disk tag type \"{0}\" not yet implemented, sorry.", DicConsole.WriteLine("Decoder for disk tag type \"{0}\" not yet implemented, sorry.",
tag); tag);
break; break;
} }
// TODO: Not implemented // TODO: Not implemented
} }
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
} }
} }

View File

@@ -31,6 +31,8 @@
// ****************************************************************************/ // ****************************************************************************/
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
@@ -40,72 +42,46 @@ using DiscImageChef.Decoders.SCSI;
using DiscImageChef.Decoders.SCSI.MMC; using DiscImageChef.Decoders.SCSI.MMC;
using DiscImageChef.Decoders.SCSI.SSC; using DiscImageChef.Decoders.SCSI.SSC;
using DiscImageChef.Devices; using DiscImageChef.Devices;
using Mono.Options;
using DeviceInfo = DiscImageChef.Core.Devices.Info.DeviceInfo; using DeviceInfo = DiscImageChef.Core.Devices.Info.DeviceInfo;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
internal class DeviceInfoCommand : Command internal class DeviceInfoCommand : Command
{ {
string devicePath; public DeviceInfoCommand() : base("device-info", "Gets information about a device.")
string outputPrefix;
bool showHelp;
public DeviceInfoCommand() : base("device-info", "Gets information about a device.") => Options = new OptionSet
{ {
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", Add(new Option(new[]
$"{MainClass.AssemblyCopyright}", "", $"usage: DiscImageChef {Name} [OPTIONS] devicepath", "", {
Help, "--output-prefix", "-w"
{ }, "Prefix for saving binary information from device.")
"output-prefix|w=", "Name of character encoding to use.", s => outputPrefix = s {
}, Argument = new Argument<string>(() => null), Required = false
{ });
"help|h|?", "Show this message and exit.", v => showHelp = v != null
}
};
public override int Invoke(IEnumerable<string> arguments) AddArgument(new Argument<string>
{
Arity = ArgumentArity.ExactlyOne, Description = "Device path", Name = "device-path"
});
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
}
static int Invoke(bool debug, bool verbose, string devicePath, string outputPrefix)
{ {
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return(int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("device-info"); Statistics.AddCommand("device-info");
if(extra.Count > 1) DicConsole.DebugWriteLine("Device-Info command", "--debug={0}", debug);
{
DicConsole.ErrorWriteLine("Too many arguments.");
return(int)ErrorNumber.UnexpectedArgumentCount;
}
if(extra.Count == 0)
{
DicConsole.ErrorWriteLine("Missing device path.");
return(int)ErrorNumber.MissingArgument;
}
devicePath = extra[0];
DicConsole.DebugWriteLine("Device-Info command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("Device-Info command", "--device={0}", devicePath); DicConsole.DebugWriteLine("Device-Info command", "--device={0}", devicePath);
DicConsole.DebugWriteLine("Device-Info command", "--output-prefix={0}", outputPrefix); DicConsole.DebugWriteLine("Device-Info command", "--output-prefix={0}", outputPrefix);
DicConsole.DebugWriteLine("Device-Info command", "--verbose={0}", MainClass.Verbose); DicConsole.DebugWriteLine("Device-Info command", "--verbose={0}", verbose);
if(devicePath.Length == 2 && if(devicePath.Length == 2 &&
devicePath[1] == ':' && devicePath[1] == ':' &&
@@ -932,7 +908,7 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("\tCan do challenge/response with Xbox discs"); DicConsole.WriteLine("\tCan do challenge/response with Xbox discs");
if(devInfo.KreonFeatures.HasFlag(KreonFeatures.DecryptSs)) if(devInfo.KreonFeatures.HasFlag(KreonFeatures.DecryptSs))
DicConsole.WriteLine("\tCan read and descrypt SS from Xbox discs"); DicConsole.WriteLine("\tCan read and decrypt SS from Xbox discs");
if(devInfo.KreonFeatures.HasFlag(KreonFeatures.XtremeUnlock)) if(devInfo.KreonFeatures.HasFlag(KreonFeatures.XtremeUnlock))
DicConsole.WriteLine("\tCan set xtreme unlock state with Xbox discs"); DicConsole.WriteLine("\tCan set xtreme unlock state with Xbox discs");
@@ -944,7 +920,7 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("\tCan do challenge/response with Xbox 360 discs"); DicConsole.WriteLine("\tCan do challenge/response with Xbox 360 discs");
if(devInfo.KreonFeatures.HasFlag(KreonFeatures.DecryptSs360)) if(devInfo.KreonFeatures.HasFlag(KreonFeatures.DecryptSs360))
DicConsole.WriteLine("\tCan read and descrypt SS from Xbox 360 discs"); DicConsole.WriteLine("\tCan read and decrypt SS from Xbox 360 discs");
if(devInfo.KreonFeatures.HasFlag(KreonFeatures.XtremeUnlock360)) if(devInfo.KreonFeatures.HasFlag(KreonFeatures.XtremeUnlock360))
DicConsole.WriteLine("\tCan set xtreme unlock state with Xbox 360 discs"); DicConsole.WriteLine("\tCan set xtreme unlock state with Xbox 360 discs");

View File

@@ -32,6 +32,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
@@ -44,9 +46,8 @@ using DiscImageChef.Database.Models;
using DiscImageChef.Decoders.ATA; using DiscImageChef.Decoders.ATA;
using DiscImageChef.Decoders.SCSI; using DiscImageChef.Decoders.SCSI;
using DiscImageChef.Devices; using DiscImageChef.Devices;
using Mono.Options;
using Newtonsoft.Json; using Newtonsoft.Json;
using Command = Mono.Options.Command; using Command = System.CommandLine.Command;
using Device = DiscImageChef.Devices.Device; using Device = DiscImageChef.Devices.Device;
using DeviceReport = DiscImageChef.Core.Devices.Report.DeviceReport; using DeviceReport = DiscImageChef.Core.Devices.Report.DeviceReport;
@@ -54,73 +55,44 @@ namespace DiscImageChef.Commands
{ {
internal class DeviceReportCommand : Command internal class DeviceReportCommand : Command
{ {
string _devicePath;
bool _showHelp;
public DeviceReportCommand() : base("device-report", public DeviceReportCommand() : base("device-report",
"Tests the device capabilities and creates an JSON report of them.") => "Tests the device capabilities and creates an JSON report of them.")
Options = new OptionSet
{
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}",
$"{MainClass.AssemblyCopyright}", "", $"usage: DiscImageChef {Name} devicepath", "",
Help,
{
"help|h|?", "Show this message and exit.", v => _showHelp = v != null
}
};
public override int Invoke(IEnumerable<string> arguments)
{ {
List<string> extra = Options.Parse(arguments); AddArgument(new Argument<string>
if(_showHelp)
{ {
Options.WriteOptionDescriptions(CommandSet.Out); Arity = ArgumentArity.ExactlyOne, Description = "Device path", Name = "device-path"
});
return(int)ErrorNumber.HelpRequested; Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
} }
static int Invoke(bool debug, bool verbose, string devicePath)
{
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("device-report"); Statistics.AddCommand("device-report");
if(extra.Count > 1) DicConsole.DebugWriteLine("Device-Report command", "--debug={0}", debug);
{ DicConsole.DebugWriteLine("Device-Report command", "--device={0}", devicePath);
DicConsole.ErrorWriteLine("Too many arguments."); DicConsole.DebugWriteLine("Device-Report command", "--verbose={0}", verbose);
return(int)ErrorNumber.UnexpectedArgumentCount; if(devicePath.Length == 2 &&
} devicePath[1] == ':' &&
devicePath[0] != '/' &&
if(extra.Count == 0) char.IsLetter(devicePath[0]))
{ devicePath = "\\\\.\\" + char.ToUpper(devicePath[0]) + ':';
DicConsole.ErrorWriteLine("Missing device path.");
return(int)ErrorNumber.MissingArgument;
}
_devicePath = extra[0];
DicConsole.DebugWriteLine("Device-Report command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("Device-Report command", "--device={0}", _devicePath);
DicConsole.DebugWriteLine("Device-Report command", "--verbose={0}", MainClass.Verbose);
if(_devicePath.Length == 2 &&
_devicePath[1] == ':' &&
_devicePath[0] != '/' &&
char.IsLetter(_devicePath[0]))
_devicePath = "\\\\.\\" + char.ToUpper(_devicePath[0]) + ':';
Device dev; Device dev;
try try
{ {
dev = new Device(_devicePath); dev = new Device(devicePath);
if(dev.IsRemote) if(dev.IsRemote)
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem, Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem,

View File

@@ -32,6 +32,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -39,173 +41,195 @@ using System.Xml.Serialization;
using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.CommonTypes.Interop;
using DiscImageChef.CommonTypes.Metadata; using DiscImageChef.CommonTypes.Metadata;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using DiscImageChef.Core.Devices.Dumping; using DiscImageChef.Core.Devices.Dumping;
using DiscImageChef.Core.Logging; using DiscImageChef.Core.Logging;
using DiscImageChef.Devices; using DiscImageChef.Devices;
using Mono.Options;
using Schemas; using Schemas;
using PlatformID = DiscImageChef.CommonTypes.Interop.PlatformID;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
// TODO: Add raw dumping // TODO: Add raw dumping
internal class DumpMediaCommand : Command internal class DumpMediaCommand : Command
{ {
string _cicmXml;
string _devicePath;
bool _doResume = true;
string _encodingName;
bool _firstTrackPregap;
bool _fixOffset = true;
bool _force;
bool _noMetadata;
bool _noTrim;
string _outputFile;
string _outputOptions;
bool _persistent;
ushort _retryPasses = 5;
bool _showHelp;
int _skip = 512;
int _speed;
bool _stopOnError;
string _wantedOutputFormat;
string _wantedSubchannel;
public DumpMediaCommand() : base("dump-media", "Dumps the media inserted on a device to a media image.") public DumpMediaCommand() : base("dump-media", "Dumps the media inserted on a device to a media image.")
{ {
Options = new OptionSet Add(new Option(new[]
{
"--cicm-xml", "-x"
}, "Take metadata from existing CICM XML sidecar.")
{
Argument = new Argument<string>(() => null), Required = false
});
Add(new Option(new[]
{
"--encoding", "-e"
}, "Name of character encoding to use.")
{
Argument = new Argument<string>(() => null), Required = false
});
Add(new Option("--first-pregap", "Try to read first track pregap. Only applicable to CD/DDCD/GD.")
{ {
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", Argument = new Argument<bool>(() => false), Required = false
$"{MainClass.AssemblyCopyright}", "", $"usage: DiscImageChef {Name} [OPTIONS] device_path output_image", });
"", Help,
Add(new Option("--fix-offset", "Fix audio tracks offset. Only applicable to CD/GD.")
{
Argument = new Argument<bool>(() => true), Required = false
});
Add(new Option(new[]
{ {
"cicm-xml|x=", "Take metadata from existing CICM XML sidecar.", s => _cicmXml = s "--force", "-f"
}, }, "Continue dump whatever happens.")
{ {
"encoding|e=", "Name of character encoding to use.", s => _encodingName = s Argument = new Argument<bool>(() => false), Required = false
} });
};
if(DetectOS.GetRealPlatformID() != PlatformID.FreeBSD) Add(new Option(new[]
Options.Add("first-pregap", "Try to read first track pregap. Only applicable to CD/DDCD/GD.", {
b => _firstTrackPregap = b != null); "--format", "-t"
},
"Format of the output image, as plugin name or plugin id. If not present, will try to detect it from output image extension.")
{
Argument = new Argument<string>(() => null), Required = false
});
Options.Add("fix-offset", "Fix audio tracks offset. Only applicable to CD/GD.", Add(new Option("--no-metadata", "Disables creating CICM XML sidecar.")
b => _fixOffset = b != null); {
Argument = new Argument<bool>(() => false), Required = false
});
Options.Add("force|f", "Continue dump whatever happens.", b => _force = b != null); Add(new Option("--no-trim", "Disables trimming errored from skipped sectors.")
{
Argument = new Argument<bool>(() => false), Required = false
});
Options.Add("format|t=", Add(new Option(new[]
"Format of the output image, as plugin name or plugin id. If not present, will try to detect it from output image extension.", {
s => _wantedOutputFormat = s); "--options", "-O"
}, "Comma separated name=value pairs of options to pass to output image plugin.")
{
Argument = new Argument<string>(() => null), Required = false
});
Options.Add("no-metadata", "Disables creating CICM XML sidecar.", b => _noMetadata = b != null); Add(new Option("--persistent", "Try to recover partial or incorrect data.")
Options.Add("no-trim", "Disables trimming errored from skipped sectors.", b => _noTrim = b != null); {
Argument = new Argument<bool>(() => false), Required = false
});
Options.Add("options|O=", "Comma separated name=value pairs of options to pass to output image plugin.", Add(new Option(new[]
s => _outputOptions = s); {
"--resume", "-r"
}, "Create/use resume mapfile.")
{
Argument = new Argument<bool>(() => true), Required = false
});
Options.Add("persistent", "Try to recover partial or incorrect data.", b => _persistent = b != null); Add(new Option(new[]
{
"--retry-passes", "-p"
}, "How many retry passes to do.")
{
Argument = new Argument<ushort>(() => 5), Required = false
});
Options.Add("resume|r", "Create/use resume mapfile.", b => _doResume = b != null); Add(new Option(new[]
{
"--skip", "-k"
}, "When an unreadable sector is found skip this many sectors.")
{
Argument = new Argument<uint>(() => 512), Required = false
});
Options.Add("retry-passes|p=", "How many retry passes to do.", (ushort us) => _retryPasses = us); Add(new Option(new[]
Options.Add("skip|k=", "When an unreadable sector is found skip this many sectors.", (int i) => _skip = i); {
"--stop-on-error", "-s"
}, "Stop media dump on first error.")
{
Argument = new Argument<bool>(() => false), Required = false
});
Options.Add("stop-on-error|s", "Stop media dump on first error.", b => _stopOnError = b != null); Add(new Option("--subchannel",
"Subchannel to dump. Only applicable to CD/GD. Values: any, rw, rw-or-pq, pq, none.")
{
Argument = new Argument<string>(() => "any"), Required = false
});
Options.Add("help|h|?", "Show this message and exit.", v => _showHelp = v != null); Add(new Option("--speed", "Speed to dump. Only applicable to optical drives, 0 for maximum.")
{
Argument = new Argument<byte>(() => 0), Required = false
});
Options.Add("subchannel", AddArgument(new Argument<string>
"Subchannel to dump. Only applicable to CD/GD. Values: any, rw, rw-or-pq, pq, none", {
s => _wantedSubchannel = s); Arity = ArgumentArity.ExactlyOne, Description = "Device path", Name = "device-path"
});
Options.Add("speed", "Speed to dump. Only applicable to optical drives, 0 for maximum", AddArgument(new Argument<string>
(int i) => _speed = i); {
Arity = ArgumentArity.ExactlyOne, Description = "Output image path", Name = "output-path"
});
/* TODO: Disabled temporarily Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
Options.Add("raw|r", "Dump sectors with tags included. For optical media, dump scrambled sectors.", (b) => raw = b != null);*/
} }
public override int Invoke(IEnumerable<string> arguments) static int Invoke(bool debug, bool verbose, string cicmXml, string devicePath, bool resume, string encoding,
bool firstTrackPregap, bool fixOffset, bool force, bool noMetadata, bool noTrim,
string outputPath, string options, bool persistent, ushort retryPasses, int skip,
int speed, bool stopOnError, string format, string subchannel)
{ {
List<string> extra = Options.Parse(arguments);
if(_showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return(int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("dump-media"); Statistics.AddCommand("dump-media");
if(extra.Count > 2) DicConsole.DebugWriteLine("Dump-Media command", "--cicm-xml={0}", cicmXml);
{ DicConsole.DebugWriteLine("Dump-Media command", "--debug={0}", debug);
DicConsole.ErrorWriteLine("Too many arguments."); DicConsole.DebugWriteLine("Dump-Media command", "--device={0}", devicePath);
DicConsole.DebugWriteLine("Dump-Media command", "--encoding={0}", encoding);
return(int)ErrorNumber.UnexpectedArgumentCount; DicConsole.DebugWriteLine("Dump-Media command", "--first-pregap={0}", firstTrackPregap);
} DicConsole.DebugWriteLine("Dump-Media command", "--force={0}", force);
DicConsole.DebugWriteLine("Dump-Media command", "--force={0}", force);
if(extra.Count <= 1) DicConsole.DebugWriteLine("Dump-Media command", "--format={0}", format);
{ DicConsole.DebugWriteLine("Dump-Media command", "--no-metadata={0}", noMetadata);
DicConsole.ErrorWriteLine("Missing paths."); DicConsole.DebugWriteLine("Dump-Media command", "--options={0}", options);
DicConsole.DebugWriteLine("Dump-Media command", "--output={0}", outputPath);
return(int)ErrorNumber.MissingArgument; DicConsole.DebugWriteLine("Dump-Media command", "--persistent={0}", persistent);
} DicConsole.DebugWriteLine("Dump-Media command", "--resume={0}", resume);
DicConsole.DebugWriteLine("Dump-Media command", "--retry-passes={0}", retryPasses);
_devicePath = extra[0]; DicConsole.DebugWriteLine("Dump-Media command", "--skip={0}", skip);
_outputFile = extra[1]; DicConsole.DebugWriteLine("Dump-Media command", "--stop-on-error={0}", stopOnError);
DicConsole.DebugWriteLine("Dump-Media command", "--verbose={0}", verbose);
DicConsole.DebugWriteLine("Dump-Media command", "--cicm-xml={0}", _cicmXml); DicConsole.DebugWriteLine("Dump-Media command", "--subchannel={0}", subchannel);
DicConsole.DebugWriteLine("Dump-Media command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("Dump-Media command", "--device={0}", _devicePath);
DicConsole.DebugWriteLine("Dump-Media command", "--encoding={0}", _encodingName);
DicConsole.DebugWriteLine("Dump-Media command", "--first-pregap={0}", _firstTrackPregap);
DicConsole.DebugWriteLine("Dump-Media command", "--force={0}", _force);
DicConsole.DebugWriteLine("Dump-Media command", "--force={0}", _force);
DicConsole.DebugWriteLine("Dump-Media command", "--format={0}", _wantedOutputFormat);
DicConsole.DebugWriteLine("Dump-Media command", "--no-metadata={0}", _noMetadata);
DicConsole.DebugWriteLine("Dump-Media command", "--options={0}", Options);
DicConsole.DebugWriteLine("Dump-Media command", "--output={0}", _outputFile);
DicConsole.DebugWriteLine("Dump-Media command", "--persistent={0}", _persistent);
DicConsole.DebugWriteLine("Dump-Media command", "--resume={0}", _doResume);
DicConsole.DebugWriteLine("Dump-Media command", "--retry-passes={0}", _retryPasses);
DicConsole.DebugWriteLine("Dump-Media command", "--skip={0}", _skip);
DicConsole.DebugWriteLine("Dump-Media command", "--stop-on-error={0}", _stopOnError);
DicConsole.DebugWriteLine("Dump-Media command", "--verbose={0}", MainClass.Verbose);
DicConsole.DebugWriteLine("Dump-Media command", "--subchannel={0}", _wantedSubchannel);
// TODO: Disabled temporarily // TODO: Disabled temporarily
//DicConsole.DebugWriteLine("Dump-Media command", "--raw={0}", raw); //DicConsole.DebugWriteLine("Dump-Media command", "--raw={0}", raw);
Dictionary<string, string> parsedOptions = Core.Options.Parse(_outputOptions); Dictionary<string, string> parsedOptions = Core.Options.Parse(options);
DicConsole.DebugWriteLine("Dump-Media command", "Parsed options:"); DicConsole.DebugWriteLine("Dump-Media command", "Parsed options:");
foreach(KeyValuePair<string, string> parsedOption in parsedOptions) foreach(KeyValuePair<string, string> parsedOption in parsedOptions)
DicConsole.DebugWriteLine("Dump-Media command", "{0} = {1}", parsedOption.Key, parsedOption.Value); DicConsole.DebugWriteLine("Dump-Media command", "{0} = {1}", parsedOption.Key, parsedOption.Value);
Encoding encoding = null; Encoding encodingClass = null;
if(_encodingName != null) if(encoding != null)
try try
{ {
encoding = Claunia.Encoding.Encoding.GetEncoding(_encodingName); encodingClass = Claunia.Encoding.Encoding.GetEncoding(encoding);
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName); DicConsole.VerboseWriteLine("Using encoding for {0}.", encodingClass.EncodingName);
} }
catch(ArgumentException) catch(ArgumentException)
{ {
@@ -214,48 +238,48 @@ namespace DiscImageChef.Commands
return(int)ErrorNumber.EncodingUnknown; return(int)ErrorNumber.EncodingUnknown;
} }
DumpSubchannel subchannel = DumpSubchannel.Any; DumpSubchannel wantedSubchannel = DumpSubchannel.Any;
switch(_wantedSubchannel?.ToLowerInvariant()) switch(subchannel?.ToLowerInvariant())
{ {
case"any": case"any":
case null: case null:
subchannel = DumpSubchannel.Any; wantedSubchannel = DumpSubchannel.Any;
break; break;
case"rw": case"rw":
subchannel = DumpSubchannel.Rw; wantedSubchannel = DumpSubchannel.Rw;
break; break;
case"rw-or-pq": case"rw-or-pq":
subchannel = DumpSubchannel.RwOrPq; wantedSubchannel = DumpSubchannel.RwOrPq;
break; break;
case"pq": case"pq":
subchannel = DumpSubchannel.Pq; wantedSubchannel = DumpSubchannel.Pq;
break; break;
case"none": case"none":
subchannel = DumpSubchannel.None; wantedSubchannel = DumpSubchannel.None;
break; break;
default: default:
DicConsole.WriteLine("Incorrect subchannel type \"{0}\" requested.", _wantedSubchannel); DicConsole.WriteLine("Incorrect subchannel type \"{0}\" requested.", subchannel);
break; break;
} }
if(_devicePath.Length == 2 && if(devicePath.Length == 2 &&
_devicePath[1] == ':' && devicePath[1] == ':' &&
_devicePath[0] != '/' && devicePath[0] != '/' &&
char.IsLetter(_devicePath[0])) char.IsLetter(devicePath[0]))
_devicePath = "\\\\.\\" + char.ToUpper(_devicePath[0]) + ':'; devicePath = "\\\\.\\" + char.ToUpper(devicePath[0]) + ':';
Device dev; Device dev;
try try
{ {
dev = new Device(_devicePath); dev = new Device(devicePath);
if(dev.IsRemote) if(dev.IsRemote)
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem, Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem,
@@ -277,17 +301,17 @@ namespace DiscImageChef.Commands
Statistics.AddDevice(dev); Statistics.AddDevice(dev);
string outputPrefix = Path.Combine(Path.GetDirectoryName(_outputFile), string outputPrefix = Path.Combine(Path.GetDirectoryName(outputPath),
Path.GetFileNameWithoutExtension(_outputFile)); Path.GetFileNameWithoutExtension(outputPath));
Resume resume = null; Resume resumeClass = null;
var xs = new XmlSerializer(typeof(Resume)); var xs = new XmlSerializer(typeof(Resume));
if(File.Exists(outputPrefix + ".resume.xml") && _doResume) if(File.Exists(outputPrefix + ".resume.xml") && resume)
try try
{ {
var sr = new StreamReader(outputPrefix + ".resume.xml"); var sr = new StreamReader(outputPrefix + ".resume.xml");
resume = (Resume)xs.Deserialize(sr); resumeClass = (Resume)xs.Deserialize(sr);
sr.Close(); sr.Close();
} }
catch catch
@@ -297,10 +321,10 @@ namespace DiscImageChef.Commands
return(int)ErrorNumber.InvalidResume; return(int)ErrorNumber.InvalidResume;
} }
if(resume != null && if(resumeClass != null &&
resume.NextBlock > resume.LastBlock && resumeClass.NextBlock > resumeClass.LastBlock &&
resume.BadBlocks.Count == 0 && resumeClass.BadBlocks.Count == 0 &&
!resume.Tape) !resumeClass.Tape)
{ {
DicConsole.WriteLine("Media already dumped correctly, not continuing..."); DicConsole.WriteLine("Media already dumped correctly, not continuing...");
@@ -310,12 +334,12 @@ namespace DiscImageChef.Commands
CICMMetadataType sidecar = null; CICMMetadataType sidecar = null;
var sidecarXs = new XmlSerializer(typeof(CICMMetadataType)); var sidecarXs = new XmlSerializer(typeof(CICMMetadataType));
if(_cicmXml != null) if(cicmXml != null)
if(File.Exists(_cicmXml)) if(File.Exists(cicmXml))
{ {
try try
{ {
var sr = new StreamReader(_cicmXml); var sr = new StreamReader(cicmXml);
sidecar = (CICMMetadataType)sidecarXs.Deserialize(sr); sidecar = (CICMMetadataType)sidecarXs.Deserialize(sr);
sr.Close(); sr.Close();
} }
@@ -337,19 +361,18 @@ namespace DiscImageChef.Commands
List<IWritableImage> candidates = new List<IWritableImage>(); List<IWritableImage> candidates = new List<IWritableImage>();
// Try extension // Try extension
if(string.IsNullOrEmpty(_wantedOutputFormat)) if(string.IsNullOrEmpty(format))
candidates.AddRange(plugins.WritableImages.Values.Where(t => candidates.AddRange(plugins.WritableImages.Values.Where(t =>
t.KnownExtensions. t.KnownExtensions.
Contains(Path. Contains(Path.GetExtension(outputPath))));
GetExtension(_outputFile))));
// Try Id // Try Id
else if(Guid.TryParse(_wantedOutputFormat, out Guid outId)) else if(Guid.TryParse(format, out Guid outId))
candidates.AddRange(plugins.WritableImages.Values.Where(t => t.Id.Equals(outId))); candidates.AddRange(plugins.WritableImages.Values.Where(t => t.Id.Equals(outId)));
// Try name // Try name
else else
candidates.AddRange(plugins.WritableImages.Values.Where(t => string.Equals(t.Name, _wantedOutputFormat, candidates.AddRange(plugins.WritableImages.Values.Where(t => string.Equals(t.Name, format,
StringComparison. StringComparison.
InvariantCultureIgnoreCase))); InvariantCultureIgnoreCase)));
@@ -371,7 +394,7 @@ namespace DiscImageChef.Commands
var dumpLog = new DumpLog(outputPrefix + ".log", dev); var dumpLog = new DumpLog(outputPrefix + ".log", dev);
if(MainClass.Verbose) if(verbose)
{ {
dumpLog.WriteLine("Output image format: {0} ({1}).", outputFormat.Name, outputFormat.Id); dumpLog.WriteLine("Output image format: {0} ({1}).", outputFormat.Name, outputFormat.Id);
DicConsole.VerboseWriteLine("Output image format: {0} ({1}).", outputFormat.Name, outputFormat.Id); DicConsole.VerboseWriteLine("Output image format: {0} ({1}).", outputFormat.Name, outputFormat.Id);
@@ -382,10 +405,10 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Output image format: {0}.", outputFormat.Name); DicConsole.WriteLine("Output image format: {0}.", outputFormat.Name);
} }
var dumper = new Dump(_doResume, dev, _devicePath, outputFormat, _retryPasses, _force, false, _persistent, var dumper = new Dump(resume, dev, devicePath, outputFormat, retryPasses, force, false, persistent,
_stopOnError, resume, dumpLog, encoding, outputPrefix, _outputFile, parsedOptions, stopOnError, resumeClass, dumpLog, encodingClass, outputPrefix, outputPath,
sidecar, (uint)_skip, _noMetadata, _noTrim, _firstTrackPregap, _fixOffset, parsedOptions, sidecar, (uint)skip, noMetadata, noTrim, firstTrackPregap, fixOffset,
MainClass.Debug, subchannel, _speed); debug, wantedSubchannel, speed);
dumper.UpdateStatus += Progress.UpdateStatus; dumper.UpdateStatus += Progress.UpdateStatus;
dumper.ErrorMessage += Progress.ErrorMessage; dumper.ErrorMessage += Progress.ErrorMessage;

View File

@@ -30,92 +30,80 @@
// Copyright © 2011-2019 Natalia Portillo // Copyright © 2011-2019 Natalia Portillo
// ****************************************************************************/ // ****************************************************************************/
using System.Collections.Generic; using System.CommandLine;
using System.CommandLine.Invocation;
using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using Mono.Options;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class EntropyCommand : Command internal class EntropyCommand : Command
{ {
bool duplicatedSectors = true;
string inputFile;
bool separatedTracks = true;
bool showHelp;
bool wholeDisc = true;
public EntropyCommand() : base("entropy", "Calculates entropy and/or duplicated sectors of an image.") public EntropyCommand() : base("entropy", "Calculates entropy and/or duplicated sectors of an image.")
{ {
Options = new OptionSet Add(new Option(new[]
{
"--duplicated-sectors", "-p"
}, "Calculates how many sectors are duplicated (have same exact data in user area).")
{
Argument = new Argument<bool>(() => true), Required = false
});
Add(new Option(new[]
{
"--separated-tracks", "-t"
}, "Calculates entropy for each track separately.")
{
Argument = new Argument<bool>(() => true), Required = false
});
Add(new Option(new[]
{
"--whole-disc", "-w"
}, "Calculates entropy for the whole disc.")
{
Argument = new Argument<bool>(() => true), Required = false
});
AddArgument(new Argument<string>
{ {
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", Arity = ArgumentArity.ExactlyOne, Description = "Media image path", Name = "image-path"
$"{MainClass.AssemblyCopyright}", });
"",
$"usage: DiscImageChef {Name} [OPTIONS] imagefile", Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
"",
Help,
{
"duplicated-sectors|p",
"Calculates how many sectors are duplicated (have same exact data in user area).",
b => duplicatedSectors = b != null
},
{
"separated-tracks|t", "Calculates entropy for each track separately.",
b => separatedTracks = b != null
},
{"whole-disc|w", "Calculates entropy for the whole disc.", b => wholeDisc = b != null},
{"help|h|?", "Show this message and exit.", v => showHelp = v != null}
};
} }
public override int Invoke(IEnumerable<string> arguments) static int Invoke(bool debug, bool verbose, bool duplicatedSectors, string imagePath, bool separatedTracks,
bool wholeDisc)
{ {
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("entropy"); Statistics.AddCommand("entropy");
if(extra.Count > 1) DicConsole.DebugWriteLine("Entropy command", "--debug={0}", debug);
{
DicConsole.ErrorWriteLine("Too many arguments.");
return (int)ErrorNumber.UnexpectedArgumentCount;
}
if(extra.Count == 0)
{
DicConsole.ErrorWriteLine("Missing input image.");
return (int)ErrorNumber.MissingArgument;
}
inputFile = extra[0];
DicConsole.DebugWriteLine("Entropy command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("Entropy command", "--duplicated-sectors={0}", duplicatedSectors); DicConsole.DebugWriteLine("Entropy command", "--duplicated-sectors={0}", duplicatedSectors);
DicConsole.DebugWriteLine("Entropy command", "--input={0}", inputFile); DicConsole.DebugWriteLine("Entropy command", "--input={0}", imagePath);
DicConsole.DebugWriteLine("Entropy command", "--separated-tracks={0}", separatedTracks); DicConsole.DebugWriteLine("Entropy command", "--separated-tracks={0}", separatedTracks);
DicConsole.DebugWriteLine("Entropy command", "--verbose={0}", MainClass.Verbose); DicConsole.DebugWriteLine("Entropy command", "--verbose={0}", verbose);
DicConsole.DebugWriteLine("Entropy command", "--whole-disc={0}", wholeDisc); DicConsole.DebugWriteLine("Entropy command", "--whole-disc={0}", wholeDisc);
FiltersList filtersList = new FiltersList(); var filtersList = new FiltersList();
IFilter inputFilter = filtersList.GetFilter(inputFile); IFilter inputFilter = filtersList.GetFilter(imagePath);
if(inputFilter == null) if(inputFilter == null)
{ {
DicConsole.ErrorWriteLine("Cannot open specified file."); DicConsole.ErrorWriteLine("Cannot open specified file.");
return (int)ErrorNumber.CannotOpenFile;
return(int)ErrorNumber.CannotOpenFile;
} }
IMediaImage inputFormat = ImageFormat.Detect(inputFilter); IMediaImage inputFormat = ImageFormat.Detect(inputFilter);
@@ -123,7 +111,8 @@ namespace DiscImageChef.Commands
if(inputFormat == null) if(inputFormat == null)
{ {
DicConsole.ErrorWriteLine("Unable to recognize image format, not checksumming"); DicConsole.ErrorWriteLine("Unable to recognize image format, not checksumming");
return (int)ErrorNumber.UnrecognizedFormat;
return(int)ErrorNumber.UnrecognizedFormat;
} }
inputFormat.Open(inputFilter); inputFormat.Open(inputFilter);
@@ -131,7 +120,7 @@ namespace DiscImageChef.Commands
Statistics.AddMedia(inputFormat.Info.MediaType, false); Statistics.AddMedia(inputFormat.Info.MediaType, false);
Statistics.AddFilter(inputFilter.Name); Statistics.AddFilter(inputFilter.Name);
Entropy entropyCalculator = new Entropy(MainClass.Debug, MainClass.Verbose, inputFormat); var entropyCalculator = new Entropy(debug, verbose, inputFormat);
entropyCalculator.InitProgressEvent += Progress.InitProgress; entropyCalculator.InitProgressEvent += Progress.InitProgress;
entropyCalculator.InitProgress2Event += Progress.InitProgress2; entropyCalculator.InitProgress2Event += Progress.InitProgress2;
entropyCalculator.UpdateProgressEvent += Progress.UpdateProgress; entropyCalculator.UpdateProgressEvent += Progress.UpdateProgress;
@@ -142,9 +131,11 @@ namespace DiscImageChef.Commands
if(separatedTracks) if(separatedTracks)
{ {
EntropyResults[] tracksEntropy = entropyCalculator.CalculateTracksEntropy(duplicatedSectors); EntropyResults[] tracksEntropy = entropyCalculator.CalculateTracksEntropy(duplicatedSectors);
foreach(EntropyResults trackEntropy in tracksEntropy) foreach(EntropyResults trackEntropy in tracksEntropy)
{ {
DicConsole.WriteLine("Entropy for track {0} is {1:F4}.", trackEntropy.Track, trackEntropy.Entropy); DicConsole.WriteLine("Entropy for track {0} is {1:F4}.", trackEntropy.Track, trackEntropy.Entropy);
if(trackEntropy.UniqueSectors != null) if(trackEntropy.UniqueSectors != null)
DicConsole.WriteLine("Track {0} has {1} unique sectors ({2:P3})", trackEntropy.Track, DicConsole.WriteLine("Track {0} has {1} unique sectors ({2:P3})", trackEntropy.Track,
trackEntropy.UniqueSectors, trackEntropy.UniqueSectors,
@@ -152,16 +143,18 @@ namespace DiscImageChef.Commands
} }
} }
if(!wholeDisc) return (int)ErrorNumber.NoError; if(!wholeDisc)
return(int)ErrorNumber.NoError;
EntropyResults entropy = entropyCalculator.CalculateMediaEntropy(duplicatedSectors); EntropyResults entropy = entropyCalculator.CalculateMediaEntropy(duplicatedSectors);
DicConsole.WriteLine("Entropy for disk is {0:F4}.", entropy.Entropy); DicConsole.WriteLine("Entropy for disk is {0:F4}.", entropy.Entropy);
if(entropy.UniqueSectors != null) if(entropy.UniqueSectors != null)
DicConsole.WriteLine("Disk has {0} unique sectors ({1:P3})", entropy.UniqueSectors, DicConsole.WriteLine("Disk has {0} unique sectors ({1:P3})", entropy.UniqueSectors,
(double)entropy.UniqueSectors / (double)entropy.Sectors); (double)entropy.UniqueSectors / (double)entropy.Sectors);
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
} }
} }

View File

@@ -32,6 +32,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.IO; using System.IO;
using System.Text; using System.Text;
using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes;
@@ -40,110 +42,115 @@ using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.CommonTypes.Structs; using DiscImageChef.CommonTypes.Structs;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using Mono.Options;
using FileAttributes = DiscImageChef.CommonTypes.Structs.FileAttributes; using FileAttributes = DiscImageChef.CommonTypes.Structs.FileAttributes;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class ExtractFilesCommand : Command internal class ExtractFilesCommand : Command
{ {
string encodingName;
bool extractXattrs;
string inputFile;
string @namespace;
string outputDir;
string pluginOptions;
bool showHelp;
public ExtractFilesCommand() : base("extract-files", "Extracts all files in disc image.") public ExtractFilesCommand() : base("extract-files", "Extracts all files in disc image.")
{ {
Options = new OptionSet Add(new Option(new[]
{
"--encoding", "-e"
}, "Name of character encoding to use.")
{
Argument = new Argument<string>(() => null), 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[]
{
"--xattrs", "-x"
}, "Extract extended attributes if present.")
{
Argument = new Argument<bool>(() => false), Required = false
});
Add(new Option(new[]
{
"--namespace", "-n"
}, "Namespace to use for filenames.")
{
Argument = new Argument<string>(() => null), Required = false
});
AddArgument(new Argument<string>
{ {
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", Arity = ArgumentArity.ExactlyOne, Description = "Disc image path", Name = "image-path"
$"{MainClass.AssemblyCopyright}", });
"",
$"usage: DiscImageChef {Name} [OPTIONS] imagefile", AddArgument(new Argument<string>
"", {
Help, Arity = ArgumentArity.ExactlyOne,
{"encoding|e=", "Name of character encoding to use.", s => encodingName = s}, Description = "Directory where extracted files will be created. Will abort if it exists",
{ Name = "output-dir"
"options|O=", "Comma separated name=value pairs of options to pass to filesystem plugin.", });
s => pluginOptions = s
}, Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
{
"output|o=", "Directory where extracted files will be created. Will abort if it exists.",
s => outputDir = s
},
{"xattrs|x", "Extract extended attributes if present.", b => extractXattrs = b != null},
{"namespace|n=", "Namespace to use for filenames.", s => @namespace = s},
{"help|h|?", "Show this message and exit.", v => showHelp = v != null}
};
} }
public override int Invoke(IEnumerable<string> arguments) static int Invoke(bool debug, bool verbose, string encoding, bool xattrs, string imagePath, string @namespace,
string outputDir, string options)
{ {
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("extract-files"); Statistics.AddCommand("extract-files");
if(extra.Count > 1) DicConsole.DebugWriteLine("Extract-Files command", "--debug={0}", debug);
{ DicConsole.DebugWriteLine("Extract-Files command", "--encoding={0}", encoding);
DicConsole.ErrorWriteLine("Too many arguments."); DicConsole.DebugWriteLine("Extract-Files command", "--input={0}", imagePath);
return (int)ErrorNumber.UnexpectedArgumentCount; DicConsole.DebugWriteLine("Extract-Files command", "--options={0}", options);
} DicConsole.DebugWriteLine("Extract-Files command", "--output={0}", outputDir);
DicConsole.DebugWriteLine("Extract-Files command", "--verbose={0}", verbose);
DicConsole.DebugWriteLine("Extract-Files command", "--xattrs={0}", xattrs);
if(extra.Count == 0) var filtersList = new FiltersList();
{ IFilter inputFilter = filtersList.GetFilter(imagePath);
DicConsole.ErrorWriteLine("Missing input image.");
return (int)ErrorNumber.MissingArgument;
}
inputFile = extra[0]; Dictionary<string, string> parsedOptions = Core.Options.Parse(options);
DicConsole.DebugWriteLine("Extract-Files command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("Extract-Files command", "--encoding={0}", encodingName);
DicConsole.DebugWriteLine("Extract-Files command", "--input={0}", inputFile);
DicConsole.DebugWriteLine("Extract-Files command", "--options={0}", pluginOptions);
DicConsole.DebugWriteLine("Extract-Files command", "--output={0}", outputDir);
DicConsole.DebugWriteLine("Extract-Files command", "--verbose={0}", MainClass.Verbose);
DicConsole.DebugWriteLine("Extract-Files command", "--xattrs={0}", extractXattrs);
FiltersList filtersList = new FiltersList();
IFilter inputFilter = filtersList.GetFilter(inputFile);
Dictionary<string, string> parsedOptions = Core.Options.Parse(pluginOptions);
DicConsole.DebugWriteLine("Extract-Files command", "Parsed options:"); DicConsole.DebugWriteLine("Extract-Files command", "Parsed options:");
foreach(KeyValuePair<string, string> parsedOption in parsedOptions) foreach(KeyValuePair<string, string> parsedOption in parsedOptions)
DicConsole.DebugWriteLine("Extract-Files command", "{0} = {1}", parsedOption.Key, parsedOption.Value); DicConsole.DebugWriteLine("Extract-Files command", "{0} = {1}", parsedOption.Key, parsedOption.Value);
parsedOptions.Add("debug", MainClass.Debug.ToString());
parsedOptions.Add("debug", debug.ToString());
if(inputFilter == null) if(inputFilter == null)
{ {
DicConsole.ErrorWriteLine("Cannot open specified file."); DicConsole.ErrorWriteLine("Cannot open specified file.");
return (int)ErrorNumber.CannotOpenFile;
return(int)ErrorNumber.CannotOpenFile;
} }
Encoding encoding = null; Encoding encodingClass = null;
if(encodingName != null) if(encoding != null)
try try
{ {
encoding = Claunia.Encoding.Encoding.GetEncoding(encodingName); encodingClass = Claunia.Encoding.Encoding.GetEncoding(encoding);
if(MainClass.Verbose) DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName);
if(verbose)
DicConsole.VerboseWriteLine("Using encoding for {0}.", encodingClass.EncodingName);
} }
catch(ArgumentException) catch(ArgumentException)
{ {
DicConsole.ErrorWriteLine("Specified encoding is not supported."); DicConsole.ErrorWriteLine("Specified encoding is not supported.");
return (int)ErrorNumber.EncodingUnknown;
return(int)ErrorNumber.EncodingUnknown;
} }
PluginBase plugins = GetPluginBase.Instance; PluginBase plugins = GetPluginBase.Instance;
@@ -155,24 +162,29 @@ namespace DiscImageChef.Commands
if(imageFormat == null) if(imageFormat == null)
{ {
DicConsole.WriteLine("Image format not identified, not proceeding with analysis."); DicConsole.WriteLine("Image format not identified, not proceeding with analysis.");
return (int)ErrorNumber.UnrecognizedFormat;
return(int)ErrorNumber.UnrecognizedFormat;
} }
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name, DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name,
imageFormat.Id); imageFormat.Id);
else DicConsole.WriteLine("Image format identified by {0}.", imageFormat.Name); else
DicConsole.WriteLine("Image format identified by {0}.", imageFormat.Name);
if (outputDir == null) if(outputDir == null)
{ {
DicConsole.WriteLine("Output directory missing."); DicConsole.WriteLine("Output directory missing.");
return (int)ErrorNumber.MissingArgument;
return(int)ErrorNumber.MissingArgument;
} }
if(Directory.Exists(outputDir) || File.Exists(outputDir)) if(Directory.Exists(outputDir) ||
File.Exists(outputDir))
{ {
DicConsole.ErrorWriteLine("Destination exists, aborting."); DicConsole.ErrorWriteLine("Destination exists, aborting.");
return (int)ErrorNumber.DestinationExists;
return(int)ErrorNumber.DestinationExists;
} }
Directory.CreateDirectory(outputDir); Directory.CreateDirectory(outputDir);
@@ -183,14 +195,18 @@ namespace DiscImageChef.Commands
{ {
DicConsole.WriteLine("Unable to open image format"); DicConsole.WriteLine("Unable to open image format");
DicConsole.WriteLine("No error given"); DicConsole.WriteLine("No error given");
return (int)ErrorNumber.CannotOpenFormat;
return(int)ErrorNumber.CannotOpenFormat;
} }
DicConsole.DebugWriteLine("Extract-Files command", "Correctly opened image file."); DicConsole.DebugWriteLine("Extract-Files command", "Correctly opened image file.");
DicConsole.DebugWriteLine("Extract-Files command", "Image without headers is {0} bytes.", DicConsole.DebugWriteLine("Extract-Files command", "Image without headers is {0} bytes.",
imageFormat.Info.ImageSize); imageFormat.Info.ImageSize);
DicConsole.DebugWriteLine("Extract-Files command", "Image has {0} sectors.", DicConsole.DebugWriteLine("Extract-Files command", "Image has {0} sectors.",
imageFormat.Info.Sectors); imageFormat.Info.Sectors);
DicConsole.DebugWriteLine("Extract-Files command", "Image identifies disk type as {0}.", DicConsole.DebugWriteLine("Extract-Files command", "Image identifies disk type as {0}.",
imageFormat.Info.MediaType); imageFormat.Info.MediaType);
@@ -202,7 +218,8 @@ namespace DiscImageChef.Commands
{ {
DicConsole.ErrorWriteLine("Unable to open image format"); DicConsole.ErrorWriteLine("Unable to open image format");
DicConsole.ErrorWriteLine("Error: {0}", ex.Message); DicConsole.ErrorWriteLine("Error: {0}", ex.Message);
return (int)ErrorNumber.CannotOpenFormat;
return(int)ErrorNumber.CannotOpenFormat;
} }
List<Partition> partitions = Core.Partitions.GetAll(imageFormat); List<Partition> partitions = Core.Partitions.GetAll(imageFormat);
@@ -211,7 +228,9 @@ namespace DiscImageChef.Commands
List<string> idPlugins; List<string> idPlugins;
IReadOnlyFilesystem plugin; IReadOnlyFilesystem plugin;
Errno error; Errno error;
if(partitions.Count == 0) DicConsole.DebugWriteLine("Extract-Files command", "No partitions found");
if(partitions.Count == 0)
DicConsole.DebugWriteLine("Extract-Files command", "No partitions found");
else else
{ {
DicConsole.WriteLine("{0} partitions found.", partitions.Count); DicConsole.WriteLine("{0} partitions found.", partitions.Count);
@@ -224,7 +243,9 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Identifying filesystem on partition"); DicConsole.WriteLine("Identifying filesystem on partition");
Core.Filesystems.Identify(imageFormat, out idPlugins, partitions[i]); Core.Filesystems.Identify(imageFormat, out idPlugins, partitions[i]);
if(idPlugins.Count == 0) DicConsole.WriteLine("Filesystem not identified");
if(idPlugins.Count == 0)
DicConsole.WriteLine("Filesystem not identified");
else if(idPlugins.Count > 1) else if(idPlugins.Count > 1)
{ {
DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins"); DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins");
@@ -233,20 +254,22 @@ namespace DiscImageChef.Commands
if(plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out plugin)) if(plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out plugin))
{ {
DicConsole.WriteLine($"As identified by {plugin.Name}."); DicConsole.WriteLine($"As identified by {plugin.Name}.");
IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin
.GetType()
.GetConstructor(Type.EmptyTypes)
?.Invoke(new object[] { });
error = fs.Mount(imageFormat, partitions[i], encoding, parsedOptions, @namespace); var fs = (IReadOnlyFilesystem)plugin.
GetType().GetConstructor(Type.EmptyTypes)?.
Invoke(new object[]
{ });
error = fs.Mount(imageFormat, partitions[i], encodingClass, parsedOptions,
@namespace);
if(error == Errno.NoError) if(error == Errno.NoError)
{ {
string volumeName = string volumeName =
string.IsNullOrEmpty(fs.XmlFsType.VolumeName) string.IsNullOrEmpty(fs.XmlFsType.VolumeName) ? "NO NAME"
? "NO NAME"
: fs.XmlFsType.VolumeName; : fs.XmlFsType.VolumeName;
ExtractFilesInDir("/", fs, volumeName); ExtractFilesInDir("/", fs, volumeName, outputDir, xattrs);
Statistics.AddFilesystem(fs.XmlFsType.Type); Statistics.AddFilesystem(fs.XmlFsType.Type);
} }
@@ -259,34 +282,38 @@ namespace DiscImageChef.Commands
{ {
plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out plugin); plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out plugin);
DicConsole.WriteLine($"Identified by {plugin.Name}."); DicConsole.WriteLine($"Identified by {plugin.Name}.");
IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin
.GetType().GetConstructor(Type.EmptyTypes) var fs = (IReadOnlyFilesystem)plugin.
?.Invoke(new object[] { }); GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[]
error = fs.Mount(imageFormat, partitions[i], encoding, parsedOptions, @namespace); { });
error = fs.Mount(imageFormat, partitions[i], encodingClass, parsedOptions, @namespace);
if(error == Errno.NoError) if(error == Errno.NoError)
{ {
string volumeName = string.IsNullOrEmpty(fs.XmlFsType.VolumeName) string volumeName = string.IsNullOrEmpty(fs.XmlFsType.VolumeName) ? "NO NAME"
? "NO NAME"
: fs.XmlFsType.VolumeName; : fs.XmlFsType.VolumeName;
ExtractFilesInDir("/", fs, volumeName); ExtractFilesInDir("/", fs, volumeName, outputDir, xattrs);
Statistics.AddFilesystem(fs.XmlFsType.Type); Statistics.AddFilesystem(fs.XmlFsType.Type);
} }
else DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); else
DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString());
} }
} }
} }
Partition wholePart = new Partition var wholePart = new Partition
{ {
Name = "Whole device", Name = "Whole device", Length = imageFormat.Info.Sectors,
Length = imageFormat.Info.Sectors, Size = imageFormat.Info.Sectors * imageFormat.Info.SectorSize
Size = imageFormat.Info.Sectors * imageFormat.Info.SectorSize
}; };
Core.Filesystems.Identify(imageFormat, out idPlugins, wholePart); Core.Filesystems.Identify(imageFormat, out idPlugins, wholePart);
if(idPlugins.Count == 0) DicConsole.WriteLine("Filesystem not identified");
if(idPlugins.Count == 0)
DicConsole.WriteLine("Filesystem not identified");
else if(idPlugins.Count > 1) else if(idPlugins.Count > 1)
{ {
DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins"); DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins");
@@ -295,67 +322,79 @@ namespace DiscImageChef.Commands
if(plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out plugin)) if(plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out plugin))
{ {
DicConsole.WriteLine($"As identified by {plugin.Name}."); DicConsole.WriteLine($"As identified by {plugin.Name}.");
IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin
.GetType().GetConstructor(Type.EmptyTypes) var fs = (IReadOnlyFilesystem)plugin.
?.Invoke(new object[] { }); GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[]
error = fs.Mount(imageFormat, wholePart, encoding, parsedOptions, @namespace); { });
error = fs.Mount(imageFormat, wholePart, encodingClass, parsedOptions, @namespace);
if(error == Errno.NoError) if(error == Errno.NoError)
{ {
string volumeName = string.IsNullOrEmpty(fs.XmlFsType.VolumeName) string volumeName = string.IsNullOrEmpty(fs.XmlFsType.VolumeName) ? "NO NAME"
? "NO NAME"
: fs.XmlFsType.VolumeName; : fs.XmlFsType.VolumeName;
ExtractFilesInDir("/", fs, volumeName); ExtractFilesInDir("/", fs, volumeName, outputDir, xattrs);
Statistics.AddFilesystem(fs.XmlFsType.Type); Statistics.AddFilesystem(fs.XmlFsType.Type);
} }
else DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); else
DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString());
} }
} }
else else
{ {
plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out plugin); plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out plugin);
DicConsole.WriteLine($"Identified by {plugin.Name}."); DicConsole.WriteLine($"Identified by {plugin.Name}.");
IReadOnlyFilesystem fs =
(IReadOnlyFilesystem)plugin.GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { }); var fs = (IReadOnlyFilesystem)plugin.GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[]
error = fs.Mount(imageFormat, wholePart, encoding, parsedOptions, @namespace); { });
error = fs.Mount(imageFormat, wholePart, encodingClass, parsedOptions, @namespace);
if(error == Errno.NoError) if(error == Errno.NoError)
{ {
string volumeName = string.IsNullOrEmpty(fs.XmlFsType.VolumeName) string volumeName = string.IsNullOrEmpty(fs.XmlFsType.VolumeName) ? "NO NAME"
? "NO NAME"
: fs.XmlFsType.VolumeName; : fs.XmlFsType.VolumeName;
ExtractFilesInDir("/", fs, volumeName); ExtractFilesInDir("/", fs, volumeName, outputDir, xattrs);
Statistics.AddFilesystem(fs.XmlFsType.Type); Statistics.AddFilesystem(fs.XmlFsType.Type);
} }
else DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); else
DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString());
} }
} }
catch(Exception ex) catch(Exception ex)
{ {
DicConsole.ErrorWriteLine($"Error reading file: {ex.Message}"); DicConsole.ErrorWriteLine($"Error reading file: {ex.Message}");
DicConsole.DebugWriteLine("Extract-Files command", ex.StackTrace); DicConsole.DebugWriteLine("Extract-Files command", ex.StackTrace);
return (int)ErrorNumber.UnexpectedException;
return(int)ErrorNumber.UnexpectedException;
} }
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
void ExtractFilesInDir(string path, IReadOnlyFilesystem fs, string volumeName) static void ExtractFilesInDir(string path, IReadOnlyFilesystem fs, string volumeName, string outputDir,
bool doXattrs)
{ {
if(path.StartsWith("/")) path = path.Substring(1); if(path.StartsWith("/"))
path = path.Substring(1);
Errno error = fs.ReadDir(path, out List<string> directory); Errno error = fs.ReadDir(path, out List<string> directory);
if(error != Errno.NoError) if(error != Errno.NoError)
{ {
DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString());
return; return;
} }
foreach(string entry in directory) foreach(string entry in directory)
{ {
error = fs.Stat(path + "/" + entry, out FileEntryInfo stat); error = fs.Stat(path + "/" + entry, out FileEntryInfo stat);
if(error == Errno.NoError) if(error == Errno.NoError)
{ {
string outputPath; string outputPath;
@@ -370,14 +409,15 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Created subdirectory at {0}", outputPath); DicConsole.WriteLine("Created subdirectory at {0}", outputPath);
ExtractFilesInDir(path + "/" + entry, fs, volumeName); ExtractFilesInDir(path + "/" + entry, fs, volumeName, outputDir, doXattrs);
DirectoryInfo di = new DirectoryInfo(outputPath); var di = new DirectoryInfo(outputPath);
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
try try
{ {
if(stat.CreationTimeUtc.HasValue) di.CreationTimeUtc = stat.CreationTimeUtc.Value; if(stat.CreationTimeUtc.HasValue)
di.CreationTimeUtc = stat.CreationTimeUtc.Value;
} }
catch catch
{ {
@@ -386,7 +426,8 @@ namespace DiscImageChef.Commands
try try
{ {
if(stat.LastWriteTimeUtc.HasValue) di.LastWriteTimeUtc = stat.LastWriteTimeUtc.Value; if(stat.LastWriteTimeUtc.HasValue)
di.LastWriteTimeUtc = stat.LastWriteTimeUtc.Value;
} }
catch catch
{ {
@@ -395,7 +436,8 @@ namespace DiscImageChef.Commands
try try
{ {
if(stat.AccessTimeUtc.HasValue) di.LastAccessTimeUtc = stat.AccessTimeUtc.Value; if(stat.AccessTimeUtc.HasValue)
di.LastAccessTimeUtc = stat.AccessTimeUtc.Value;
} }
catch catch
{ {
@@ -407,15 +449,19 @@ namespace DiscImageChef.Commands
} }
FileStream outputFile; FileStream outputFile;
if(extractXattrs)
if(doXattrs)
{ {
error = fs.ListXAttr(path + "/" + entry, out List<string> xattrs); error = fs.ListXAttr(path + "/" + entry, out List<string> xattrs);
if(error == Errno.NoError) if(error == Errno.NoError)
foreach(string xattr in xattrs) foreach(string xattr in xattrs)
{ {
byte[] xattrBuf = new byte[0]; byte[] xattrBuf = new byte[0];
error = fs.GetXattr(path + "/" + entry, xattr, ref xattrBuf); error = fs.GetXattr(path + "/" + entry, xattr, ref xattrBuf);
if(error != Errno.NoError) continue;
if(error != Errno.NoError)
continue;
Directory.CreateDirectory(Path.Combine(outputDir, fs.XmlFsType.Type, volumeName, Directory.CreateDirectory(Path.Combine(outputDir, fs.XmlFsType.Type, volumeName,
".xattrs", xattr)); ".xattrs", xattr));
@@ -427,9 +473,10 @@ namespace DiscImageChef.Commands
{ {
outputFile = new FileStream(outputPath, FileMode.CreateNew, FileAccess.ReadWrite, outputFile = new FileStream(outputPath, FileMode.CreateNew, FileAccess.ReadWrite,
FileShare.None); FileShare.None);
outputFile.Write(xattrBuf, 0, xattrBuf.Length); outputFile.Write(xattrBuf, 0, xattrBuf.Length);
outputFile.Close(); outputFile.Close();
FileInfo fi = new FileInfo(outputPath); var fi = new FileInfo(outputPath);
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
try try
{ {
@@ -453,7 +500,8 @@ namespace DiscImageChef.Commands
try try
{ {
if(stat.AccessTimeUtc.HasValue) fi.LastAccessTimeUtc = stat.AccessTimeUtc.Value; if(stat.AccessTimeUtc.HasValue)
fi.LastAccessTimeUtc = stat.AccessTimeUtc.Value;
} }
catch catch
{ {
@@ -483,13 +531,15 @@ namespace DiscImageChef.Commands
{ {
outputFile = new FileStream(outputPath, FileMode.CreateNew, FileAccess.ReadWrite, outputFile = new FileStream(outputPath, FileMode.CreateNew, FileAccess.ReadWrite,
FileShare.None); FileShare.None);
outputFile.Write(outBuf, 0, outBuf.Length); outputFile.Write(outBuf, 0, outBuf.Length);
outputFile.Close(); outputFile.Close();
FileInfo fi = new FileInfo(outputPath); var fi = new FileInfo(outputPath);
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
try try
{ {
if(stat.CreationTimeUtc.HasValue) fi.CreationTimeUtc = stat.CreationTimeUtc.Value; if(stat.CreationTimeUtc.HasValue)
fi.CreationTimeUtc = stat.CreationTimeUtc.Value;
} }
catch catch
{ {
@@ -498,7 +548,8 @@ namespace DiscImageChef.Commands
try try
{ {
if(stat.LastWriteTimeUtc.HasValue) fi.LastWriteTimeUtc = stat.LastWriteTimeUtc.Value; if(stat.LastWriteTimeUtc.HasValue)
fi.LastWriteTimeUtc = stat.LastWriteTimeUtc.Value;
} }
catch catch
{ {
@@ -507,7 +558,8 @@ namespace DiscImageChef.Commands
try try
{ {
if(stat.AccessTimeUtc.HasValue) fi.LastAccessTimeUtc = stat.AccessTimeUtc.Value; if(stat.AccessTimeUtc.HasValue)
fi.LastAccessTimeUtc = stat.AccessTimeUtc.Value;
} }
catch catch
{ {
@@ -517,12 +569,15 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Written {0} bytes of file {1} to {2}", outBuf.Length, entry, DicConsole.WriteLine("Written {0} bytes of file {1} to {2}", outBuf.Length, entry,
outputPath); outputPath);
} }
else DicConsole.ErrorWriteLine("Error {0} reading file {1}", error, entry); else
DicConsole.ErrorWriteLine("Error {0} reading file {1}", error, entry);
} }
else DicConsole.ErrorWriteLine("Cannot write file {0}, output exists", entry); else
DicConsole.ErrorWriteLine("Cannot write file {0}, output exists", entry);
} }
else DicConsole.ErrorWriteLine("Error reading file {0}", entry); else
DicConsole.ErrorWriteLine("Error reading file {0}", entry);
} }
} }
} }
} }

View File

@@ -31,6 +31,8 @@
// ****************************************************************************/ // ****************************************************************************/
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.Linq; using System.Linq;
using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
@@ -38,123 +40,121 @@ using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using DiscImageChef.Partitions; using DiscImageChef.Partitions;
using Mono.Options;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class FormatsCommand : Command internal class FormatsCommand : Command
{ {
bool showHelp;
public FormatsCommand() : base("formats", public FormatsCommand() : base("formats",
"Lists all supported disc images, partition schemes and file systems.") "Lists all supported disc images, partition schemes and file systems.") =>
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
static int Invoke(bool verbose, bool debug)
{ {
Options = new OptionSet
{
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}",
$"{MainClass.AssemblyCopyright}",
"",
$"usage: DiscImageChef {Name}",
"",
Help,
{"help|h|?", "Show this message and exit.", v => showHelp = v != null}
};
}
public override int Invoke(IEnumerable<string> arguments)
{
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("formats"); Statistics.AddCommand("formats");
if(extra.Count > 0) DicConsole.DebugWriteLine("Formats command", "--debug={0}", debug);
{ DicConsole.DebugWriteLine("Formats command", "--verbose={0}", verbose);
DicConsole.ErrorWriteLine("Too many arguments.");
return (int)ErrorNumber.UnexpectedArgumentCount;
}
DicConsole.DebugWriteLine("Formats command", "--debug={0}", MainClass.Debug); PluginBase plugins = GetPluginBase.Instance;
DicConsole.DebugWriteLine("Formats command", "--verbose={0}", MainClass.Verbose); var filtersList = new FiltersList();
PluginBase plugins = GetPluginBase.Instance;
FiltersList filtersList = new FiltersList();
DicConsole.WriteLine("Supported filters ({0}):", filtersList.Filters.Count); DicConsole.WriteLine("Supported filters ({0}):", filtersList.Filters.Count);
if(MainClass.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tFilter");
if(verbose)
DicConsole.VerboseWriteLine("GUID\t\t\t\t\tFilter");
foreach(KeyValuePair<string, IFilter> kvp in filtersList.Filters) foreach(KeyValuePair<string, IFilter> kvp in filtersList.Filters)
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name);
else else
DicConsole.WriteLine(kvp.Value.Name); DicConsole.WriteLine(kvp.Value.Name);
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Read-only media image formats ({0}):", DicConsole.WriteLine("Read-only media image formats ({0}):",
plugins.ImagePluginsList.Count(t => !t.Value.GetType().GetInterfaces() plugins.ImagePluginsList.Count(t => !t.Value.GetType().GetInterfaces().
.Contains(typeof(IWritableImage)))); Contains(typeof(IWritableImage))));
if(MainClass.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin");
foreach(KeyValuePair<string, IMediaImage> kvp in plugins.ImagePluginsList.Where(t => !t.Value.GetType() if(verbose)
.GetInterfaces() DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin");
.Contains(typeof(
foreach(KeyValuePair<string, IMediaImage> kvp in plugins.ImagePluginsList.Where(t => !t.Value.GetType().
GetInterfaces().
Contains(typeof(
IWritableImage IWritableImage
)))) ))))
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name);
else else
DicConsole.WriteLine(kvp.Value.Name); DicConsole.WriteLine(kvp.Value.Name);
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Read/write media image formats ({0}):", plugins.WritableImages.Count); DicConsole.WriteLine("Read/write media image formats ({0}):", plugins.WritableImages.Count);
if(MainClass.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin");
if(verbose)
DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin");
foreach(KeyValuePair<string, IWritableImage> kvp in plugins.WritableImages) foreach(KeyValuePair<string, IWritableImage> kvp in plugins.WritableImages)
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name);
else else
DicConsole.WriteLine(kvp.Value.Name); DicConsole.WriteLine(kvp.Value.Name);
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Supported filesystems for identification and information only ({0}):", DicConsole.WriteLine("Supported filesystems for identification and information only ({0}):",
plugins.PluginsList.Count(t => !t.Value.GetType().GetInterfaces() plugins.PluginsList.Count(t => !t.Value.GetType().GetInterfaces().
.Contains(typeof(IReadOnlyFilesystem)))); Contains(typeof(IReadOnlyFilesystem))));
if(MainClass.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin");
foreach(KeyValuePair<string, IFilesystem> kvp in plugins.PluginsList.Where(t => !t.Value.GetType() if(verbose)
.GetInterfaces() DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin");
.Contains(typeof(
foreach(KeyValuePair<string, IFilesystem> kvp in plugins.PluginsList.Where(t => !t.Value.GetType().
GetInterfaces().
Contains(typeof(
IReadOnlyFilesystem IReadOnlyFilesystem
)))) ))))
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name);
else else
DicConsole.WriteLine(kvp.Value.Name); DicConsole.WriteLine(kvp.Value.Name);
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Supported filesystems that can read their contents ({0}):", DicConsole.WriteLine("Supported filesystems that can read their contents ({0}):",
plugins.ReadOnlyFilesystems.Count); plugins.ReadOnlyFilesystems.Count);
if(MainClass.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin");
if(verbose)
DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin");
foreach(KeyValuePair<string, IReadOnlyFilesystem> kvp in plugins.ReadOnlyFilesystems) foreach(KeyValuePair<string, IReadOnlyFilesystem> kvp in plugins.ReadOnlyFilesystems)
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name);
else else
DicConsole.WriteLine(kvp.Value.Name); DicConsole.WriteLine(kvp.Value.Name);
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Supported partitioning schemes ({0}):", plugins.PartPluginsList.Count); DicConsole.WriteLine("Supported partitioning schemes ({0}):", plugins.PartPluginsList.Count);
if(MainClass.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin");
if(verbose)
DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin");
foreach(KeyValuePair<string, IPartition> kvp in plugins.PartPluginsList) foreach(KeyValuePair<string, IPartition> kvp in plugins.PartPluginsList)
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name);
else else
DicConsole.WriteLine(kvp.Value.Name); DicConsole.WriteLine(kvp.Value.Name);
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
} }
} }

View File

@@ -31,77 +31,53 @@
// ****************************************************************************/ // ****************************************************************************/
using System; using System;
using System.Collections.Generic; using System.CommandLine;
using System.CommandLine.Invocation;
using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using Mono.Options;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class ImageInfoCommand : Command internal class ImageInfoCommand : Command
{ {
string inputFile;
bool showHelp;
public ImageInfoCommand() : base("image-info", public ImageInfoCommand() : base("image-info",
"Opens a media image and shows information about the media it represents and metadata.") "Opens a media image and shows information about the media it represents and metadata.")
{ {
Options = new OptionSet AddArgument(new Argument<string>
{ {
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", Arity = ArgumentArity.ExactlyOne, Description = "Media image path", Name = "image-path"
$"{MainClass.AssemblyCopyright}", });
"",
$"usage: DiscImageChef {Name} imagefile", Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
"",
Help,
{"help|h|?", "Show this message and exit.", v => showHelp = v != null}
};
} }
public override int Invoke(IEnumerable<string> arguments) static int Invoke(bool debug, bool verbose, string imagePath)
{ {
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("image-info"); Statistics.AddCommand("image-info");
if(extra.Count > 1) DicConsole.DebugWriteLine("Analyze command", "--debug={0}", debug);
{ DicConsole.DebugWriteLine("Analyze command", "--input={0}", imagePath);
DicConsole.ErrorWriteLine("Too many arguments."); DicConsole.DebugWriteLine("Analyze command", "--verbose={0}", verbose);
return (int)ErrorNumber.UnexpectedArgumentCount;
}
if(extra.Count == 0) var filtersList = new FiltersList();
{ IFilter inputFilter = filtersList.GetFilter(imagePath);
DicConsole.ErrorWriteLine("Missing input image.");
return (int)ErrorNumber.MissingArgument;
}
inputFile = extra[0];
DicConsole.DebugWriteLine("Analyze command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("Analyze command", "--input={0}", inputFile);
DicConsole.DebugWriteLine("Analyze command", "--verbose={0}", MainClass.Verbose);
FiltersList filtersList = new FiltersList();
IFilter inputFilter = filtersList.GetFilter(inputFile);
if(inputFilter == null) if(inputFilter == null)
{ {
DicConsole.ErrorWriteLine("Cannot open specified file."); DicConsole.ErrorWriteLine("Cannot open specified file.");
return (int)ErrorNumber.CannotOpenFile;
return(int)ErrorNumber.CannotOpenFile;
} }
try try
@@ -111,7 +87,8 @@ namespace DiscImageChef.Commands
if(imageFormat == null) if(imageFormat == null)
{ {
DicConsole.WriteLine("Image format not identified."); DicConsole.WriteLine("Image format not identified.");
return (int)ErrorNumber.UnrecognizedFormat;
return(int)ErrorNumber.UnrecognizedFormat;
} }
DicConsole.WriteLine("Image format identified by {0} ({1}).", imageFormat.Name, imageFormat.Id); DicConsole.WriteLine("Image format identified by {0} ({1}).", imageFormat.Name, imageFormat.Id);
@@ -123,7 +100,8 @@ namespace DiscImageChef.Commands
{ {
DicConsole.WriteLine("Unable to open image format"); DicConsole.WriteLine("Unable to open image format");
DicConsole.WriteLine("No error given"); DicConsole.WriteLine("No error given");
return (int)ErrorNumber.CannotOpenFormat;
return(int)ErrorNumber.CannotOpenFormat;
} }
ImageInfo.PrintImageInfo(imageFormat); ImageInfo.PrintImageInfo(imageFormat);
@@ -137,17 +115,19 @@ namespace DiscImageChef.Commands
DicConsole.ErrorWriteLine("Unable to open image format"); DicConsole.ErrorWriteLine("Unable to open image format");
DicConsole.ErrorWriteLine("Error: {0}", ex.Message); DicConsole.ErrorWriteLine("Error: {0}", ex.Message);
DicConsole.DebugWriteLine("Image-info command", "Stack trace: {0}", ex.StackTrace); DicConsole.DebugWriteLine("Image-info command", "Stack trace: {0}", ex.StackTrace);
return (int)ErrorNumber.CannotOpenFormat;
return(int)ErrorNumber.CannotOpenFormat;
} }
} }
catch(Exception ex) catch(Exception ex)
{ {
DicConsole.ErrorWriteLine($"Error reading file: {ex.Message}"); DicConsole.ErrorWriteLine($"Error reading file: {ex.Message}");
DicConsole.DebugWriteLine("Image-info command", ex.StackTrace); DicConsole.DebugWriteLine("Image-info command", ex.StackTrace);
return (int)ErrorNumber.UnexpectedException;
return(int)ErrorNumber.UnexpectedException;
} }
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
} }
} }

View File

@@ -30,70 +30,47 @@
// Copyright © 2011-2019 Natalia Portillo // Copyright © 2011-2019 Natalia Portillo
// ****************************************************************************/ // ****************************************************************************/
using System.Collections.Generic; using System.CommandLine;
using System.CommandLine.Invocation;
using System.Linq; using System.Linq;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using DiscImageChef.Devices; using DiscImageChef.Devices;
using Mono.Options;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
internal class ListDevicesCommand : Command internal class ListDevicesCommand : Command
{ {
bool showHelp; public ListDevicesCommand() : base("list-devices", "Lists all connected devices.")
public ListDevicesCommand() : base("list-devices", "Lists all connected devices.") => Options = new OptionSet
{ {
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", AddArgument(new Argument<string>
$"{MainClass.AssemblyCopyright}", "", $"usage: DiscImageChef {Name} [dic-remote-host]", "",
Help,
{ {
"help|h|?", "Show this message and exit.", v => showHelp = v != null Arity = ArgumentArity.ZeroOrOne, Description = "dicremote host", Name = "dic-remote-host"
} });
};
public override int Invoke(IEnumerable<string> arguments) Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
}
static int Invoke(bool debug, bool verbose, string dicRemoteHost)
{ {
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return(int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("list-devices"); Statistics.AddCommand("list-devices");
string dicRemote = null; DicConsole.DebugWriteLine("List-Devices command", "--debug={0}", debug);
DicConsole.DebugWriteLine("List-Devices command", "--verbose={0}", verbose);
if(extra.Count > 1)
{
DicConsole.ErrorWriteLine("Too many arguments.");
return(int)ErrorNumber.UnexpectedArgumentCount;
}
if(extra.Count == 1)
dicRemote = extra[0];
DicConsole.DebugWriteLine("List-Devices command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("List-Devices command", "--verbose={0}", MainClass.Verbose);
DeviceInfo[] devices = Device.ListDevices(out bool isRemote, out string serverApplication, DeviceInfo[] devices = Device.ListDevices(out bool isRemote, out string serverApplication,
out string serverVersion, out string serverOperatingSystem, out string serverVersion, out string serverOperatingSystem,
out string serverOperatingSystemVersion, out string serverOperatingSystemVersion,
out string serverArchitecture, dicRemote); out string serverArchitecture, dicRemoteHost);
if(isRemote) if(isRemote)
{ {
@@ -110,7 +87,7 @@ namespace DiscImageChef.Commands
{ {
devices = devices.OrderBy(d => d.Path).ToArray(); devices = devices.OrderBy(d => d.Path).ToArray();
if(dicRemote is null) if(dicRemoteHost is null)
{ {
DicConsole.WriteLine("{0,-22}|{1,-16}|{2,-24}|{3,-24}|{4,-10}|{5,-10}", "Path", "Vendor", "Model", DicConsole.WriteLine("{0,-22}|{1,-16}|{2,-24}|{3,-24}|{4,-10}|{5,-10}", "Path", "Vendor", "Model",
"Serial", "Bus", "Supported?"); "Serial", "Bus", "Supported?");

View File

@@ -31,76 +31,52 @@
// ****************************************************************************/ // ****************************************************************************/
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using Mono.Options;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class ListEncodingsCommand : Command internal class ListEncodingsCommand : Command
{ {
bool showHelp; public ListEncodingsCommand() : base("list-encodings", "Lists all supported text encodings and code pages.") =>
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
public ListEncodingsCommand() : base("list-encodings", "Lists all supported text encodings and code pages.") static int Invoke(bool debug, bool verbose)
{ {
Options = new OptionSet
{
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}",
$"{MainClass.AssemblyCopyright}",
"",
$"usage: DiscImageChef {Name}",
"",
Help,
{"help|h|?", "Show this message and exit.", v => showHelp = v != null}
};
}
public override int Invoke(IEnumerable<string> arguments)
{
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("list-encodings"); Statistics.AddCommand("list-encodings");
if(extra.Count > 0) DicConsole.DebugWriteLine("List-Encodings command", "--debug={0}", debug);
DicConsole.DebugWriteLine("List-Encodings command", "--verbose={0}", verbose);
List<CommonEncodingInfo> encodings = Encoding.GetEncodings().Select(info => new CommonEncodingInfo
{ {
DicConsole.ErrorWriteLine("Too many arguments."); Name = info.Name, DisplayName = info.GetEncoding().EncodingName
return (int)ErrorNumber.UnexpectedArgumentCount; }).ToList();
}
DicConsole.DebugWriteLine("List-Encodings command", "--debug={0}", MainClass.Debug); encodings.AddRange(Claunia.Encoding.Encoding.GetEncodings().Select(info => new CommonEncodingInfo
DicConsole.DebugWriteLine("List-Encodings command", "--verbose={0}", MainClass.Verbose); {
Name = info.Name, DisplayName = info.DisplayName
List<CommonEncodingInfo> encodings = Encoding }));
.GetEncodings().Select(info => new CommonEncodingInfo
{
Name = info.Name,
DisplayName =
info.GetEncoding().EncodingName
}).ToList();
encodings.AddRange(Claunia.Encoding.Encoding.GetEncodings()
.Select(info => new CommonEncodingInfo
{
Name = info.Name, DisplayName = info.DisplayName
}));
DicConsole.WriteLine("{0,-16} {1,-8}", "Name", "Description"); DicConsole.WriteLine("{0,-16} {1,-8}", "Name", "Description");
foreach(CommonEncodingInfo info in encodings.OrderBy(t => t.DisplayName)) foreach(CommonEncodingInfo info in encodings.OrderBy(t => t.DisplayName))
DicConsole.WriteLine("{0,-16} {1,-8}", info.Name, info.DisplayName); DicConsole.WriteLine("{0,-16} {1,-8}", info.Name, info.DisplayName);
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
struct CommonEncodingInfo struct CommonEncodingInfo

View File

@@ -31,73 +31,54 @@
// ****************************************************************************/ // ****************************************************************************/
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.Linq; using System.Linq;
using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using Mono.Options;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class ListNamespacesCommand : Command internal class ListNamespacesCommand : Command
{ {
bool showHelp;
public ListNamespacesCommand() : base("list-namespaces", public ListNamespacesCommand() : base("list-namespaces",
"Lists all namespaces supported by read-only filesystems.") "Lists all namespaces supported by read-only filesystems.") =>
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
static int Invoke(bool debug, bool verbose)
{ {
Options = new OptionSet
{
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}",
$"{MainClass.AssemblyCopyright}",
"",
$"usage: DiscImageChef {Name}",
"",
Help,
{"help|h|?", "Show this message and exit.", v => showHelp = v != null}
};
}
public override int Invoke(IEnumerable<string> arguments)
{
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
if(extra.Count > 0) if(debug)
{ DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
DicConsole.ErrorWriteLine("Too many arguments.");
return (int)ErrorNumber.UnexpectedArgumentCount;
}
DicConsole.DebugWriteLine("List-Namespaces command", "--debug={0}", MainClass.Debug); if(verbose)
DicConsole.DebugWriteLine("List-Namespaces command", "--verbose={0}", MainClass.Verbose); DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
DicConsole.DebugWriteLine("List-Namespaces command", "--debug={0}", debug);
DicConsole.DebugWriteLine("List-Namespaces command", "--verbose={0}", verbose);
Statistics.AddCommand("list-namespaces"); Statistics.AddCommand("list-namespaces");
PluginBase plugins = GetPluginBase.Instance; PluginBase plugins = GetPluginBase.Instance;
foreach(KeyValuePair<string, IReadOnlyFilesystem> kvp in plugins.ReadOnlyFilesystems) foreach(KeyValuePair<string, IReadOnlyFilesystem> kvp in plugins.ReadOnlyFilesystems)
{ {
if(kvp.Value.Namespaces is null) continue; if(kvp.Value.Namespaces is null)
continue;
DicConsole.WriteLine("\tNamespaces for {0}:", kvp.Value.Name); DicConsole.WriteLine("\tNamespaces for {0}:", kvp.Value.Name);
DicConsole.WriteLine("\t\t{0,-16} {1,-16}", "Namespace", "Description"); DicConsole.WriteLine("\t\t{0,-16} {1,-16}", "Namespace", "Description");
foreach(KeyValuePair<string, string> @namespace in kvp.Value.Namespaces.OrderBy(t => t.Key)) foreach(KeyValuePair<string, string> @namespace in kvp.Value.Namespaces.OrderBy(t => t.Key))
DicConsole.WriteLine("\t\t{0,-16} {1,-16}", @namespace.Key, @namespace.Value); DicConsole.WriteLine("\t\t{0,-16} {1,-16}", @namespace.Key, @namespace.Value);
DicConsole.WriteLine(); DicConsole.WriteLine();
} }
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
} }
} }

View File

@@ -32,109 +32,107 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.Linq; using System.Linq;
using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using Mono.Options;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class ListOptionsCommand : Command internal class ListOptionsCommand : Command
{ {
bool showHelp;
public ListOptionsCommand() : base("list-options", public ListOptionsCommand() : base("list-options",
"Lists all options supported by read-only filesystems and writable media images.") "Lists all options supported by read-only filesystems and writable media images.") =>
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
static int Invoke(bool debug, bool verbose)
{ {
Options = new OptionSet
{
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}",
$"{MainClass.AssemblyCopyright}",
"",
$"usage: DiscImageChef {Name}",
"",
Help,
{"help|h|?", "Show this message and exit.", v => showHelp = v != null}
};
}
public override int Invoke(IEnumerable<string> arguments)
{
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
if(extra.Count > 0) if(debug)
{ DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
DicConsole.ErrorWriteLine("Too many arguments.");
return (int)ErrorNumber.UnexpectedArgumentCount;
}
DicConsole.DebugWriteLine("List-Options command", "--debug={0}", MainClass.Debug); if(verbose)
DicConsole.DebugWriteLine("List-Options command", "--verbose={0}", MainClass.Verbose); DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
DicConsole.DebugWriteLine("List-Options command", "--debug={0}", debug);
DicConsole.DebugWriteLine("List-Options command", "--verbose={0}", verbose);
Statistics.AddCommand("list-options"); Statistics.AddCommand("list-options");
PluginBase plugins = GetPluginBase.Instance; PluginBase plugins = GetPluginBase.Instance;
DicConsole.WriteLine("Read-only filesystems options:"); DicConsole.WriteLine("Read-only filesystems options:");
foreach(KeyValuePair<string, IReadOnlyFilesystem> kvp in plugins.ReadOnlyFilesystems) foreach(KeyValuePair<string, IReadOnlyFilesystem> kvp in plugins.ReadOnlyFilesystems)
{ {
List<(string name, Type type, string description)> options = kvp.Value.SupportedOptions.ToList(); List<(string name, Type type, string description)> options = kvp.Value.SupportedOptions.ToList();
if(options.Count == 0) continue;
DicConsole.WriteLine("\tOptions for {0}:", kvp.Value.Name); if(options.Count == 0)
continue;
DicConsole.WriteLine("\tOptions for {0}:", kvp.Value.Name);
DicConsole.WriteLine("\t\t{0,-16} {1,-16} {2,-8}", "Name", "Type", "Description"); DicConsole.WriteLine("\t\t{0,-16} {1,-16} {2,-8}", "Name", "Type", "Description");
foreach((string name, Type type, string description) option in options.OrderBy(t => t.name)) foreach((string name, Type type, string description) option in options.OrderBy(t => t.name))
DicConsole.WriteLine("\t\t{0,-16} {1,-16} {2,-8}", option.name, TypeToString(option.type), DicConsole.WriteLine("\t\t{0,-16} {1,-16} {2,-8}", option.name, TypeToString(option.type),
option.description); option.description);
DicConsole.WriteLine(); DicConsole.WriteLine();
} }
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Read/Write media images options:"); DicConsole.WriteLine("Read/Write media images options:");
foreach(KeyValuePair<string, IWritableImage> kvp in plugins.WritableImages) foreach(KeyValuePair<string, IWritableImage> kvp in plugins.WritableImages)
{ {
List<(string name, Type type, string description, object @default)> options = List<(string name, Type type, string description, object @default)> options =
kvp.Value.SupportedOptions.ToList(); kvp.Value.SupportedOptions.ToList();
if(options.Count == 0) continue;
DicConsole.WriteLine("\tOptions for {0}:", kvp.Value.Name); if(options.Count == 0)
continue;
DicConsole.WriteLine("\tOptions for {0}:", kvp.Value.Name);
DicConsole.WriteLine("\t\t{0,-20} {1,-10} {2,-12} {3,-8}", "Name", "Type", "Default", "Description"); DicConsole.WriteLine("\t\t{0,-20} {1,-10} {2,-12} {3,-8}", "Name", "Type", "Default", "Description");
foreach((string name, Type type, string description, object @default) option in foreach((string name, Type type, string description, object @default) option in
options.OrderBy(t => t.name)) options.OrderBy(t => t.name))
DicConsole.WriteLine("\t\t{0,-20} {1,-10} {2,-12} {3,-8}", option.name, TypeToString(option.type), DicConsole.WriteLine("\t\t{0,-20} {1,-10} {2,-12} {3,-8}", option.name, TypeToString(option.type),
option.@default, option.description); option.@default, option.description);
DicConsole.WriteLine(); DicConsole.WriteLine();
} }
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
static string TypeToString(Type type) static string TypeToString(Type type)
{ {
if(type == typeof(bool)) return "boolean"; if(type == typeof(bool))
return"boolean";
if(type == typeof(sbyte) || type == typeof(short) || type == typeof(int) || type == typeof(long)) if(type == typeof(sbyte) ||
return "signed number"; type == typeof(short) ||
type == typeof(int) ||
type == typeof(long))
return"signed number";
if(type == typeof(byte) || type == typeof(ushort) || type == typeof(uint) || type == typeof(ulong)) if(type == typeof(byte) ||
return "number"; type == typeof(ushort) ||
type == typeof(uint) ||
type == typeof(ulong))
return"number";
if(type == typeof(float) || type == typeof(double)) return "float number"; if(type == typeof(float) ||
type == typeof(double))
return"float number";
if(type == typeof(Guid)) return "uuid"; if(type == typeof(Guid))
return"uuid";
return type == typeof(string) ? "string" : type.ToString(); return type == typeof(string) ? "string" : type.ToString();
} }

View File

@@ -32,6 +32,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes;
@@ -40,102 +42,104 @@ using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.CommonTypes.Structs; using DiscImageChef.CommonTypes.Structs;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using Mono.Options;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class LsCommand : Command internal class LsCommand : Command
{ {
string encodingName;
string inputFile;
bool longFormat;
string @namespace;
string pluginOptions;
bool showHelp;
public LsCommand() : base("ls", "Lists files in disc image.") public LsCommand() : base("ls", "Lists files in disc image.")
{ {
Options = new OptionSet Add(new Option(new[]
{
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}",
$"{MainClass.AssemblyCopyright}",
"",
$"usage: DiscImageChef {Name} [OPTIONS] imagefile",
"",
Help,
{"encoding|e=", "Name of character encoding to use.", s => encodingName = s},
{"long|l", "Uses long format.", b => longFormat = b != null},
{ {
"options|O=", "Comma separated name=value pairs of options to pass to filesystem plugin.", "--encoding", "-e"
s => pluginOptions = s }, "Name of character encoding to use.")
}, {
{"namespace|n=", "Namespace to use for filenames.", s => @namespace = s}, Argument = new Argument<string>(() => null), Required = false
{"help|h|?", "Show this message and exit.", v => showHelp = v != null} });
};
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 override int Invoke(IEnumerable<string> arguments) static int Invoke(bool debug, bool verbose, string encoding, string imagePath, bool longFormat,
string @namespace, string options)
{ {
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
if(extra.Count > 1) if(debug)
{ DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
DicConsole.ErrorWriteLine("Too many arguments.");
return (int)ErrorNumber.UnexpectedArgumentCount;
}
if(extra.Count == 0) if(verbose)
{ DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
DicConsole.ErrorWriteLine("Missing input image.");
return (int)ErrorNumber.MissingArgument;
}
inputFile = extra[0]; DicConsole.DebugWriteLine("Ls command", "--debug={0}", debug);
DicConsole.DebugWriteLine("Ls command", "--encoding={0}", encoding);
DicConsole.DebugWriteLine("Ls command", "--debug={0}", MainClass.Debug); DicConsole.DebugWriteLine("Ls command", "--input={0}", imagePath);
DicConsole.DebugWriteLine("Ls command", "--encoding={0}", encodingName); DicConsole.DebugWriteLine("Ls command", "--options={0}", options);
DicConsole.DebugWriteLine("Ls command", "--input={0}", inputFile); DicConsole.DebugWriteLine("Ls command", "--verbose={0}", verbose);
DicConsole.DebugWriteLine("Ls command", "--options={0}", pluginOptions);
DicConsole.DebugWriteLine("Ls command", "--verbose={0}", MainClass.Verbose);
Statistics.AddCommand("ls"); Statistics.AddCommand("ls");
FiltersList filtersList = new FiltersList(); var filtersList = new FiltersList();
IFilter inputFilter = filtersList.GetFilter(inputFile); IFilter inputFilter = filtersList.GetFilter(imagePath);
Dictionary<string, string> parsedOptions = Core.Options.Parse(pluginOptions); Dictionary<string, string> parsedOptions = Core.Options.Parse(options);
DicConsole.DebugWriteLine("Ls command", "Parsed options:"); DicConsole.DebugWriteLine("Ls command", "Parsed options:");
foreach(KeyValuePair<string, string> parsedOption in parsedOptions) foreach(KeyValuePair<string, string> parsedOption in parsedOptions)
DicConsole.DebugWriteLine("Ls command", "{0} = {1}", parsedOption.Key, parsedOption.Value); DicConsole.DebugWriteLine("Ls command", "{0} = {1}", parsedOption.Key, parsedOption.Value);
parsedOptions.Add("debug", MainClass.Debug.ToString());
parsedOptions.Add("debug", debug.ToString());
if(inputFilter == null) if(inputFilter == null)
{ {
DicConsole.ErrorWriteLine("Cannot open specified file."); DicConsole.ErrorWriteLine("Cannot open specified file.");
return (int)ErrorNumber.CannotOpenFile;
return(int)ErrorNumber.CannotOpenFile;
} }
Encoding encoding = null; Encoding encodingClass = null;
if(encodingName != null) if(encoding != null)
try try
{ {
encoding = Claunia.Encoding.Encoding.GetEncoding(encodingName); encodingClass = Claunia.Encoding.Encoding.GetEncoding(encoding);
if(MainClass.Verbose) DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName);
if(verbose)
DicConsole.VerboseWriteLine("Using encoding for {0}.", encodingClass.EncodingName);
} }
catch(ArgumentException) catch(ArgumentException)
{ {
DicConsole.ErrorWriteLine("Specified encoding is not supported."); DicConsole.ErrorWriteLine("Specified encoding is not supported.");
return (int)ErrorNumber.EncodingUnknown;
return(int)ErrorNumber.EncodingUnknown;
} }
PluginBase plugins = GetPluginBase.Instance; PluginBase plugins = GetPluginBase.Instance;
@@ -147,13 +151,15 @@ namespace DiscImageChef.Commands
if(imageFormat == null) if(imageFormat == null)
{ {
DicConsole.WriteLine("Image format not identified, not proceeding with analysis."); DicConsole.WriteLine("Image format not identified, not proceeding with analysis.");
return (int)ErrorNumber.UnrecognizedFormat;
return(int)ErrorNumber.UnrecognizedFormat;
} }
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name, DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name,
imageFormat.Id); imageFormat.Id);
else DicConsole.WriteLine("Image format identified by {0}.", imageFormat.Name); else
DicConsole.WriteLine("Image format identified by {0}.", imageFormat.Name);
try try
{ {
@@ -161,13 +167,17 @@ namespace DiscImageChef.Commands
{ {
DicConsole.WriteLine("Unable to open image format"); DicConsole.WriteLine("Unable to open image format");
DicConsole.WriteLine("No error given"); DicConsole.WriteLine("No error given");
return (int)ErrorNumber.CannotOpenFormat;
return(int)ErrorNumber.CannotOpenFormat;
} }
DicConsole.DebugWriteLine("Ls command", "Correctly opened image file."); DicConsole.DebugWriteLine("Ls command", "Correctly opened image file.");
DicConsole.DebugWriteLine("Ls command", "Image without headers is {0} bytes.", DicConsole.DebugWriteLine("Ls command", "Image without headers is {0} bytes.",
imageFormat.Info.ImageSize); imageFormat.Info.ImageSize);
DicConsole.DebugWriteLine("Ls command", "Image has {0} sectors.", imageFormat.Info.Sectors); DicConsole.DebugWriteLine("Ls command", "Image has {0} sectors.", imageFormat.Info.Sectors);
DicConsole.DebugWriteLine("Ls command", "Image identifies disk type as {0}.", DicConsole.DebugWriteLine("Ls command", "Image identifies disk type as {0}.",
imageFormat.Info.MediaType); imageFormat.Info.MediaType);
@@ -179,7 +189,8 @@ namespace DiscImageChef.Commands
{ {
DicConsole.ErrorWriteLine("Unable to open image format"); DicConsole.ErrorWriteLine("Unable to open image format");
DicConsole.ErrorWriteLine("Error: {0}", ex.Message); DicConsole.ErrorWriteLine("Error: {0}", ex.Message);
return (int)ErrorNumber.CannotOpenFormat;
return(int)ErrorNumber.CannotOpenFormat;
} }
List<Partition> partitions = Core.Partitions.GetAll(imageFormat); List<Partition> partitions = Core.Partitions.GetAll(imageFormat);
@@ -188,7 +199,9 @@ namespace DiscImageChef.Commands
List<string> idPlugins; List<string> idPlugins;
IReadOnlyFilesystem plugin; IReadOnlyFilesystem plugin;
Errno error; Errno error;
if(partitions.Count == 0) DicConsole.DebugWriteLine("Ls command", "No partitions found");
if(partitions.Count == 0)
DicConsole.DebugWriteLine("Ls command", "No partitions found");
else else
{ {
DicConsole.WriteLine("{0} partitions found.", partitions.Count); DicConsole.WriteLine("{0} partitions found.", partitions.Count);
@@ -201,7 +214,9 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Identifying filesystem on partition"); DicConsole.WriteLine("Identifying filesystem on partition");
Core.Filesystems.Identify(imageFormat, out idPlugins, partitions[i]); Core.Filesystems.Identify(imageFormat, out idPlugins, partitions[i]);
if(idPlugins.Count == 0) DicConsole.WriteLine("Filesystem not identified");
if(idPlugins.Count == 0)
DicConsole.WriteLine("Filesystem not identified");
else if(idPlugins.Count > 1) else if(idPlugins.Count > 1)
{ {
DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins"); DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins");
@@ -210,17 +225,21 @@ namespace DiscImageChef.Commands
if(plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out plugin)) if(plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out plugin))
{ {
DicConsole.WriteLine($"As identified by {plugin.Name}."); DicConsole.WriteLine($"As identified by {plugin.Name}.");
IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin
.GetType()
.GetConstructor(Type.EmptyTypes)
?.Invoke(new object[] { });
if(fs == null) continue; var fs = (IReadOnlyFilesystem)plugin.
GetType().GetConstructor(Type.EmptyTypes)?.
Invoke(new object[]
{ });
if(fs == null)
continue;
error = fs.Mount(imageFormat, partitions[i], encodingClass, parsedOptions,
@namespace);
error = fs.Mount(imageFormat, partitions[i], encoding, parsedOptions, @namespace);
if(error == Errno.NoError) if(error == Errno.NoError)
{ {
ListFilesInDir("/", fs); ListFilesInDir("/", fs, longFormat);
Statistics.AddFilesystem(fs.XmlFsType.Type); Statistics.AddFilesystem(fs.XmlFsType.Type);
} }
@@ -232,35 +251,43 @@ namespace DiscImageChef.Commands
else else
{ {
plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out plugin); plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out plugin);
if(plugin == null) continue;
if(plugin == null)
continue;
DicConsole.WriteLine($"Identified by {plugin.Name}."); DicConsole.WriteLine($"Identified by {plugin.Name}.");
IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin
.GetType().GetConstructor(Type.EmptyTypes)
?.Invoke(new object[] { });
if(fs == null) continue;
error = fs.Mount(imageFormat, partitions[i], encoding, parsedOptions, @namespace); var fs = (IReadOnlyFilesystem)plugin.
GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[]
{ });
if(fs == null)
continue;
error = fs.Mount(imageFormat, partitions[i], encodingClass, parsedOptions, @namespace);
if(error == Errno.NoError) if(error == Errno.NoError)
{ {
ListFilesInDir("/", fs); ListFilesInDir("/", fs, longFormat);
Statistics.AddFilesystem(fs.XmlFsType.Type); Statistics.AddFilesystem(fs.XmlFsType.Type);
} }
else DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); else
DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString());
} }
} }
} }
Partition wholePart = new Partition var wholePart = new Partition
{ {
Name = "Whole device", Name = "Whole device", Length = imageFormat.Info.Sectors,
Length = imageFormat.Info.Sectors, Size = imageFormat.Info.Sectors * imageFormat.Info.SectorSize
Size = imageFormat.Info.Sectors * imageFormat.Info.SectorSize
}; };
Core.Filesystems.Identify(imageFormat, out idPlugins, wholePart); Core.Filesystems.Identify(imageFormat, out idPlugins, wholePart);
if(idPlugins.Count == 0) DicConsole.WriteLine("Filesystem not identified");
if(idPlugins.Count == 0)
DicConsole.WriteLine("Filesystem not identified");
else if(idPlugins.Count > 1) else if(idPlugins.Count > 1)
{ {
DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins"); DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins");
@@ -269,40 +296,50 @@ namespace DiscImageChef.Commands
if(plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out plugin)) if(plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out plugin))
{ {
DicConsole.WriteLine($"As identified by {plugin.Name}."); DicConsole.WriteLine($"As identified by {plugin.Name}.");
IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin
.GetType().GetConstructor(Type.EmptyTypes)
?.Invoke(new object[] { });
if(fs == null) continue;
error = fs.Mount(imageFormat, wholePart, encoding, parsedOptions, @namespace); var fs = (IReadOnlyFilesystem)plugin.
GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[]
{ });
if(fs == null)
continue;
error = fs.Mount(imageFormat, wholePart, encodingClass, parsedOptions, @namespace);
if(error == Errno.NoError) if(error == Errno.NoError)
{ {
ListFilesInDir("/", fs); ListFilesInDir("/", fs, longFormat);
Statistics.AddFilesystem(fs.XmlFsType.Type); Statistics.AddFilesystem(fs.XmlFsType.Type);
} }
else DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); else
DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString());
} }
} }
else else
{ {
plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out plugin); plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out plugin);
if(plugin != null) if(plugin != null)
{ {
DicConsole.WriteLine($"Identified by {plugin.Name}."); DicConsole.WriteLine($"Identified by {plugin.Name}.");
IReadOnlyFilesystem fs =
(IReadOnlyFilesystem)plugin var fs = (IReadOnlyFilesystem)plugin.
.GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { }); GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[]
{ });
if(fs != null) if(fs != null)
{ {
error = fs.Mount(imageFormat, wholePart, encoding, parsedOptions, @namespace); error = fs.Mount(imageFormat, wholePart, encodingClass, parsedOptions, @namespace);
if(error == Errno.NoError) if(error == Errno.NoError)
{ {
ListFilesInDir("/", fs); ListFilesInDir("/", fs, longFormat);
Statistics.AddFilesystem(fs.XmlFsType.Type); Statistics.AddFilesystem(fs.XmlFsType.Type);
} }
else DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); else
DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString());
} }
} }
} }
@@ -311,15 +348,17 @@ namespace DiscImageChef.Commands
{ {
DicConsole.ErrorWriteLine($"Error reading file: {ex.Message}"); DicConsole.ErrorWriteLine($"Error reading file: {ex.Message}");
DicConsole.DebugWriteLine("Ls command", ex.StackTrace); DicConsole.DebugWriteLine("Ls command", ex.StackTrace);
return (int)ErrorNumber.UnexpectedException;
return(int)ErrorNumber.UnexpectedException;
} }
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
void ListFilesInDir(string path, IReadOnlyFilesystem fs) static void ListFilesInDir(string path, IReadOnlyFilesystem fs, bool longFormat)
{ {
if(path.StartsWith("/")) path = path.Substring(1); if(path.StartsWith("/"))
path = path.Substring(1);
DicConsole.WriteLine(string.IsNullOrEmpty(path) ? "Root directory" : $"Directory: {path}"); DicConsole.WriteLine(string.IsNullOrEmpty(path) ? "Root directory" : $"Directory: {path}");
@@ -328,6 +367,7 @@ namespace DiscImageChef.Commands
if(error != Errno.NoError) if(error != Errno.NoError)
{ {
DicConsole.ErrorWriteLine("Error {0} reading root directory {1}", error.ToString(), path); DicConsole.ErrorWriteLine("Error {0} reading root directory {1}", error.ToString(), path);
return; return;
} }
@@ -335,7 +375,7 @@ namespace DiscImageChef.Commands
foreach(string entry in directory) foreach(string entry in directory)
{ {
error = fs.Stat(path + "/" + entry, out FileEntryInfo stat); fs.Stat(path + "/" + entry, out FileEntryInfo stat);
stats.Add(entry, stat); stats.Add(entry, stat);
} }
@@ -355,30 +395,36 @@ namespace DiscImageChef.Commands
entry.Key); entry.Key);
error = fs.ListXAttr(path + "/" + entry.Key, out List<string> xattrs); error = fs.ListXAttr(path + "/" + entry.Key, out List<string> xattrs);
if(error != Errno.NoError) continue;
if(error != Errno.NoError)
continue;
foreach(string xattr in xattrs) foreach(string xattr in xattrs)
{ {
byte[] xattrBuf = new byte[0]; byte[] xattrBuf = new byte[0];
error = fs.GetXattr(path + "/" + entry.Key, xattr, ref xattrBuf); error = fs.GetXattr(path + "/" + entry.Key, xattr, ref xattrBuf);
if(error == Errno.NoError) if(error == Errno.NoError)
DicConsole.WriteLine("\t\t{0}\t{1:##,#}", xattr, xattrBuf.Length); DicConsole.WriteLine("\t\t{0}\t{1:##,#}", xattr, xattrBuf.Length);
} }
} }
else DicConsole.WriteLine("{0, 47}{1}", string.Empty, entry.Key); else
DicConsole.WriteLine("{0, 47}{1}", string.Empty, entry.Key);
} }
else else
{ {
if(entry.Value != null && entry.Value.Attributes.HasFlag(FileAttributes.Directory)) if(entry.Value != null &&
entry.Value.Attributes.HasFlag(FileAttributes.Directory))
DicConsole.WriteLine("{0}/", entry.Key); DicConsole.WriteLine("{0}/", entry.Key);
else DicConsole.WriteLine("{0}", entry.Key); else
DicConsole.WriteLine("{0}", entry.Key);
} }
DicConsole.WriteLine(); DicConsole.WriteLine();
foreach(KeyValuePair<string, FileEntryInfo> subdirectory in foreach(KeyValuePair<string, FileEntryInfo> subdirectory in
stats.Where(e => e.Value?.Attributes.HasFlag(FileAttributes.Directory) == true)) stats.Where(e => e.Value?.Attributes.HasFlag(FileAttributes.Directory) == true))
ListFilesInDir(path + "/" + subdirectory.Key, fs); ListFilesInDir(path + "/" + subdirectory.Key, fs, longFormat);
} }
} }
} }

View File

@@ -32,6 +32,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
@@ -44,7 +46,6 @@ using DiscImageChef.Decoders.SCSI.MMC;
using DiscImageChef.Decoders.SCSI.SSC; using DiscImageChef.Decoders.SCSI.SSC;
using DiscImageChef.Decoders.Xbox; using DiscImageChef.Decoders.Xbox;
using DiscImageChef.Devices; using DiscImageChef.Devices;
using Mono.Options;
using BCA = DiscImageChef.Decoders.Bluray.BCA; using BCA = DiscImageChef.Decoders.Bluray.BCA;
using Cartridge = DiscImageChef.Decoders.DVD.Cartridge; using Cartridge = DiscImageChef.Decoders.DVD.Cartridge;
using DDS = DiscImageChef.Decoders.DVD.DDS; using DDS = DiscImageChef.Decoders.DVD.DDS;
@@ -55,65 +56,40 @@ namespace DiscImageChef.Commands
{ {
internal class MediaInfoCommand : Command internal class MediaInfoCommand : Command
{ {
string devicePath; public MediaInfoCommand() : base("media-info", "Gets information about the media inserted on a device.")
string outputPrefix;
bool showHelp;
public MediaInfoCommand() : base("media-info", "Gets information about the media inserted on a device.") =>
Options = new OptionSet
{
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}",
$"{MainClass.AssemblyCopyright}", "", $"usage: DiscImageChef {Name} [OPTIONS] devicepath", "",
Help,
{
"output-prefix|w=", "Write binary responses from device with that prefix.", s => outputPrefix = s
},
{
"help|h|?", "Show this message and exit.", v => showHelp = v != null
}
};
public override int Invoke(IEnumerable<string> arguments)
{ {
List<string> extra = Options.Parse(arguments); Add(new Option(new[]
{
"--output-prefix", "-w"
}, "Write binary responses from device with that prefix.")
{
Argument = new Argument<string>(() => null), Required = false
});
if(showHelp) AddArgument(new Argument<string>
{ {
Options.WriteOptionDescriptions(CommandSet.Out); Arity = ArgumentArity.ExactlyOne, Description = "Device path", Name = "device-path"
});
return(int)ErrorNumber.HelpRequested; Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
} }
static int Invoke(bool debug, bool verbose, string devicePath, string outputPrefix)
{
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("media-info"); Statistics.AddCommand("media-info");
if(extra.Count > 1) DicConsole.DebugWriteLine("Media-Info command", "--debug={0}", debug);
{
DicConsole.ErrorWriteLine("Too many arguments.");
return(int)ErrorNumber.UnexpectedArgumentCount;
}
if(extra.Count == 0)
{
DicConsole.ErrorWriteLine("Missing device path.");
return(int)ErrorNumber.MissingArgument;
}
devicePath = extra[0];
DicConsole.DebugWriteLine("Media-Info command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("Media-Info command", "--device={0}", devicePath); DicConsole.DebugWriteLine("Media-Info command", "--device={0}", devicePath);
DicConsole.DebugWriteLine("Media-Info command", "--output-prefix={0}", outputPrefix); DicConsole.DebugWriteLine("Media-Info command", "--output-prefix={0}", outputPrefix);
DicConsole.DebugWriteLine("Media-Info command", "--verbose={0}", MainClass.Verbose); DicConsole.DebugWriteLine("Media-Info command", "--verbose={0}", verbose);
if(devicePath.Length == 2 && if(devicePath.Length == 2 &&
devicePath[1] == ':' && devicePath[1] == ':' &&

View File

@@ -30,82 +30,61 @@
// Copyright © 2011-2019 Natalia Portillo // Copyright © 2011-2019 Natalia Portillo
// ****************************************************************************/ // ****************************************************************************/
using System.Collections.Generic; using System.CommandLine;
using System.CommandLine.Invocation;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using DiscImageChef.Core.Devices.Scanning; using DiscImageChef.Core.Devices.Scanning;
using DiscImageChef.Devices; using DiscImageChef.Devices;
using Mono.Options;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
internal class MediaScanCommand : Command internal class MediaScanCommand : Command
{ {
string devicePath; public MediaScanCommand() : base("media-scan", "Scans the media inserted on a device.")
string ibgLogPath;
string mhddLogPath;
bool showHelp;
public MediaScanCommand() : base("media-scan", "Scans the media inserted on a device.") =>
Options = new OptionSet
{
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}",
$"{MainClass.AssemblyCopyright}", "", $"usage: DiscImageChef {Name} [OPTIONS] devicepath", "",
Help,
{
"mhdd-log|mw=", "Write a log of the scan in the format used by MHDD.", s => mhddLogPath = s
},
{
"ibg-log|b=", "Write a log of the scan in the format used by ImgBurn.", s => ibgLogPath = s
},
{
"help|h|?", "Show this message and exit.", v => showHelp = v != null
}
};
public override int Invoke(IEnumerable<string> arguments)
{ {
List<string> extra = Options.Parse(arguments); Add(new Option(new[]
{
"--mhdd-log", "-m"
}, "Write a log of the scan in the format used by MHDD.")
{
Argument = new Argument<string>(() => null), Required = false
});
if(showHelp) Add(new Option(new[]
{
"--ibg-log", "-b"
}, "Write a log of the scan in the format used by ImgBurn.")
{
Argument = new Argument<bool>(() => true), Required = false
});
AddArgument(new Argument<string>
{ {
Options.WriteOptionDescriptions(CommandSet.Out); Arity = ArgumentArity.ExactlyOne, Description = "Device path", Name = "device-path"
});
return(int)ErrorNumber.HelpRequested; Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
} }
static int Invoke(bool debug, bool verbose, string devicePath, string ibgLog, string mhddLog)
{
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("media-scan"); Statistics.AddCommand("media-scan");
if(extra.Count > 1) DicConsole.DebugWriteLine("Media-Scan command", "--debug={0}", debug);
{
DicConsole.ErrorWriteLine("Too many arguments.");
return(int)ErrorNumber.UnexpectedArgumentCount;
}
if(extra.Count == 0)
{
DicConsole.ErrorWriteLine("Missing device path.");
return(int)ErrorNumber.MissingArgument;
}
devicePath = extra[0];
DicConsole.DebugWriteLine("Media-Scan command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("Media-Scan command", "--device={0}", devicePath); DicConsole.DebugWriteLine("Media-Scan command", "--device={0}", devicePath);
DicConsole.DebugWriteLine("Media-Scan command", "--ibg-log={0}", ibgLogPath); DicConsole.DebugWriteLine("Media-Scan command", "--ibg-log={0}", ibgLog);
DicConsole.DebugWriteLine("Media-Scan command", "--mhdd-log={0}", mhddLogPath); DicConsole.DebugWriteLine("Media-Scan command", "--mhdd-log={0}", mhddLog);
DicConsole.DebugWriteLine("Media-Scan command", "--verbose={0}", MainClass.Verbose); DicConsole.DebugWriteLine("Media-Scan command", "--verbose={0}", verbose);
if(devicePath.Length == 2 && if(devicePath.Length == 2 &&
devicePath[1] == ':' && devicePath[1] == ':' &&
@@ -139,7 +118,7 @@ namespace DiscImageChef.Commands
Statistics.AddDevice(dev); Statistics.AddDevice(dev);
var scanner = new MediaScan(mhddLogPath, ibgLogPath, devicePath, dev); var scanner = new MediaScan(mhddLog, ibgLog, devicePath, dev);
scanner.UpdateStatus += Progress.UpdateStatus; scanner.UpdateStatus += Progress.UpdateStatus;
scanner.StoppingErrorMessage += Progress.ErrorMessage; scanner.StoppingErrorMessage += Progress.ErrorMessage;
scanner.UpdateProgress += Progress.UpdateProgress; scanner.UpdateProgress += Progress.UpdateProgress;
@@ -177,9 +156,13 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine(); DicConsole.WriteLine();
#pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator #pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator
// ReSharper disable CompareOfFloatsByEqualityOperator
if(results.SeekTotal != 0 || if(results.SeekTotal != 0 ||
results.SeekMin != double.MaxValue || results.SeekMin != double.MaxValue ||
results.SeekMax != double.MinValue) results.SeekMax != double.MinValue)
// ReSharper restore CompareOfFloatsByEqualityOperator
#pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator #pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator
DicConsole.WriteLine("Testing {0} seeks, longest seek took {1:F3} ms, fastest one took {2:F3} ms. ({3:F3} ms average)", DicConsole.WriteLine("Testing {0} seeks, longest seek took {1:F3} ms, fastest one took {2:F3} ms. ({3:F3} ms average)",
results.SeekTimes, results.SeekMax, results.SeekMin, results.SeekTotal / 1000); results.SeekTimes, results.SeekMax, results.SeekMin, results.SeekTotal / 1000);

View File

@@ -30,93 +30,89 @@
// Copyright © 2011-2019 Natalia Portillo // Copyright © 2011-2019 Natalia Portillo
// ****************************************************************************/ // ****************************************************************************/
using System.Collections.Generic; using System.CommandLine;
using System.CommandLine.Invocation;
using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using Mono.Options;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class PrintHexCommand : Command internal class PrintHexCommand : Command
{ {
string inputFile;
ulong length = 1;
bool longSectors;
bool showHelp;
ulong? startSector;
ushort widthBytes = 32;
public PrintHexCommand() : base("printhex", "Prints a sector, in hexadecimal values, to the console.") public PrintHexCommand() : base("printhex", "Prints a sector, in hexadecimal values, to the console.")
{ {
Options = new OptionSet Add(new Option(new[]
{
"--length", "-l"
}, "How many sectors to print.")
{
Argument = new Argument<ulong>(() => 1), Required = false
});
Add(new Option(new[]
{
"--long-sectors", "-r"
}, "Print sectors with tags included.")
{
Argument = new Argument<bool>(() => false), Required = false
});
Add(new Option(new[]
{
"--start", "-s"
}, "Starting sector.")
{
Argument = new Argument<ulong>(), Required = true
});
Add(new Option(new[]
{
"--width", "-w"
}, "How many bytes to print per line.")
{
Argument = new Argument<ushort>(() => 32), Required = false
});
AddArgument(new Argument<string>
{ {
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", Arity = ArgumentArity.ExactlyOne, Description = "Media image path", Name = "image-path"
$"{MainClass.AssemblyCopyright}", });
"",
$"usage: DiscImageChef {Name} [OPTIONS] imagefile", Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
"",
Help,
{"length|l=", "How many sectors to print.", (ulong ul) => length = ul},
{"long-sectors|r", "Print sectors with tags included.", b => longSectors = b != null},
{"start|s=", "Name of character encoding to use.", (ulong ul) => startSector = ul},
{"width|w=", "How many bytes to print per line.", (ushort us) => widthBytes = us},
{"help|h|?", "Show this message and exit.", v => showHelp = v != null}
};
} }
public override int Invoke(IEnumerable<string> arguments) static int Invoke(bool debug, bool verbose, string imagePath, ulong length, bool longSectors, ulong startSector,
ushort widthBytes)
{ {
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("print-hex"); Statistics.AddCommand("print-hex");
if(extra.Count > 1) DicConsole.DebugWriteLine("PrintHex command", "--debug={0}", debug);
{ DicConsole.DebugWriteLine("PrintHex command", "--input={0}", imagePath);
DicConsole.ErrorWriteLine("Too many arguments."); DicConsole.DebugWriteLine("PrintHex command", "--length={0}", length);
return (int)ErrorNumber.UnexpectedArgumentCount;
}
if(extra.Count == 0)
{
DicConsole.ErrorWriteLine("Missing input image.");
return (int)ErrorNumber.MissingArgument;
}
if(startSector is null)
{
DicConsole.ErrorWriteLine("Missing starting sector.");
return (int)ErrorNumber.MissingArgument;
}
inputFile = extra[0];
DicConsole.DebugWriteLine("PrintHex command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("PrintHex command", "--input={0}", inputFile);
DicConsole.DebugWriteLine("PrintHex command", "--length={0}", length);
DicConsole.DebugWriteLine("PrintHex command", "--long-sectors={0}", longSectors); DicConsole.DebugWriteLine("PrintHex command", "--long-sectors={0}", longSectors);
DicConsole.DebugWriteLine("PrintHex command", "--start={0}", startSector); DicConsole.DebugWriteLine("PrintHex command", "--start={0}", startSector);
DicConsole.DebugWriteLine("PrintHex command", "--verbose={0}", MainClass.Verbose); DicConsole.DebugWriteLine("PrintHex command", "--verbose={0}", verbose);
DicConsole.DebugWriteLine("PrintHex command", "--WidthBytes={0}", widthBytes); DicConsole.DebugWriteLine("PrintHex command", "--WidthBytes={0}", widthBytes);
FiltersList filtersList = new FiltersList(); var filtersList = new FiltersList();
IFilter inputFilter = filtersList.GetFilter(inputFile); IFilter inputFilter = filtersList.GetFilter(imagePath);
if(inputFilter == null) if(inputFilter == null)
{ {
DicConsole.ErrorWriteLine("Cannot open specified file."); DicConsole.ErrorWriteLine("Cannot open specified file.");
return (int)ErrorNumber.CannotOpenFile;
return(int)ErrorNumber.CannotOpenFile;
} }
IMediaImage inputFormat = ImageFormat.Detect(inputFilter); IMediaImage inputFormat = ImageFormat.Detect(inputFilter);
@@ -124,7 +120,8 @@ namespace DiscImageChef.Commands
if(inputFormat == null) if(inputFormat == null)
{ {
DicConsole.ErrorWriteLine("Unable to recognize image format, not verifying"); DicConsole.ErrorWriteLine("Unable to recognize image format, not verifying");
return (int)ErrorNumber.UnrecognizedFormat;
return(int)ErrorNumber.UnrecognizedFormat;
} }
inputFormat.Open(inputFilter); inputFormat.Open(inputFilter);
@@ -135,28 +132,29 @@ namespace DiscImageChef.Commands
if(inputFormat.Info.ReadableSectorTags == null) if(inputFormat.Info.ReadableSectorTags == null)
{ {
DicConsole DicConsole.
.WriteLine("Requested sectors with tags, unsupported by underlying image format, printing only user data."); WriteLine("Requested sectors with tags, unsupported by underlying image format, printing only user data.");
longSectors = false; longSectors = false;
} }
else else
{ {
if(inputFormat.Info.ReadableSectorTags.Count == 0) if(inputFormat.Info.ReadableSectorTags.Count == 0)
{ {
DicConsole DicConsole.
.WriteLine("Requested sectors with tags, unsupported by underlying image format, printing only user data."); WriteLine("Requested sectors with tags, unsupported by underlying image format, printing only user data.");
longSectors = false; longSectors = false;
} }
} }
byte[] sector = longSectors byte[] sector = longSectors ? inputFormat.ReadSectorLong(startSector + i)
? inputFormat.ReadSectorLong(startSector.Value + i) : inputFormat.ReadSector(startSector + i);
: inputFormat.ReadSector(startSector.Value + i);
PrintHex.PrintHexArray(sector, widthBytes); PrintHex.PrintHexArray(sector, widthBytes);
} }
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
} }
} }

View File

@@ -33,71 +33,42 @@
// TODO: Fix errors returned // TODO: Fix errors returned
using System; using System;
using System.Collections.Generic; using System.CommandLine;
using System.CommandLine.Invocation;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using Mono.Options;
using Remote = DiscImageChef.Devices.Remote.Remote; using Remote = DiscImageChef.Devices.Remote.Remote;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
internal class RemoteCommand : Command internal class RemoteCommand : Command
{ {
string host; public RemoteCommand() : base("remote", "Tests connection to a DiscImageChef Remote Server.")
bool showHelp;
public RemoteCommand() : base("remote", "Tests connection to a DiscImageChef Remote Server.") =>
Options = new OptionSet
{
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}",
$"{MainClass.AssemblyCopyright}", "", $"usage: DiscImageChef {Name} [OPTIONS] host", "",
Help,
{
"help|h|?", "Show this message and exit.", v => showHelp = v != null
}
};
public override int Invoke(IEnumerable<string> arguments)
{ {
List<string> extra = Options.Parse(arguments); AddArgument(new Argument<string>
if(showHelp)
{ {
Options.WriteOptionDescriptions(CommandSet.Out); Arity = ArgumentArity.ExactlyOne, Description = "dicremote host", Name = "host"
});
return(int)ErrorNumber.HelpRequested; Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
} }
static int Invoke(bool debug, bool verbose, string host)
{
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
// Statistics.AddCommand("remote"); Statistics.AddCommand("remote");
if(extra.Count > 1) DicConsole.DebugWriteLine("Remote command", "--debug={0}", debug);
{
DicConsole.ErrorWriteLine("Too many arguments.");
return(int)ErrorNumber.UnexpectedArgumentCount;
}
if(extra.Count == 0)
{
DicConsole.ErrorWriteLine("Missing input image.");
return(int)ErrorNumber.MissingArgument;
}
host = extra[0];
DicConsole.DebugWriteLine("Remote command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("Remote command", "--host={0}", host); DicConsole.DebugWriteLine("Remote command", "--host={0}", host);
DicConsole.DebugWriteLine("Remote command", "--verbose={0}", MainClass.Verbose); DicConsole.DebugWriteLine("Remote command", "--verbose={0}", verbose);
try try
{ {

View File

@@ -30,62 +30,44 @@
// Copyright © 2011-2019 Natalia Portillo // Copyright © 2011-2019 Natalia Portillo
// ****************************************************************************/ // ****************************************************************************/
using System.Collections.Generic; using System.CommandLine.Invocation;
using System.Linq; using System.Linq;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Database; using DiscImageChef.Database;
using DiscImageChef.Database.Models; using DiscImageChef.Database.Models;
using Mono.Options; using Command = System.CommandLine.Command;
using Command = Mono.Options.Command;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class StatisticsCommand : Command internal class StatisticsCommand : Command
{ {
bool showHelp; public StatisticsCommand() : base("stats", "Shows statistics.") =>
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
public StatisticsCommand() : base("stats", "Shows statistics.") static int Invoke(bool debug, bool verbose)
{ {
Options = new OptionSet
{
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}",
$"{MainClass.AssemblyCopyright}",
"",
$"usage: DiscImageChef {Name}",
"",
Help,
{"help|h|?", "Show this message and exit.", v => showHelp = v != null}
};
}
public override int Invoke(IEnumerable<string> arguments)
{
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
if(extra.Count > 0) if(debug)
{ DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
DicConsole.ErrorWriteLine("Too many arguments.");
return (int)ErrorNumber.UnexpectedArgumentCount;
}
DicContext ctx = DicContext.Create(Settings.Settings.LocalDbPath); if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
if(!ctx.Commands.Any() && !ctx.Filesystems.Any() && !ctx.Filters.Any() && !ctx.MediaFormats.Any() && var ctx = DicContext.Create(Settings.Settings.LocalDbPath);
!ctx.Medias.Any() && !ctx.Partitions.Any() && !ctx.SeenDevices.Any())
if(!ctx.Commands.Any() &&
!ctx.Filesystems.Any() &&
!ctx.Filters.Any() &&
!ctx.MediaFormats.Any() &&
!ctx.Medias.Any() &&
!ctx.Partitions.Any() &&
!ctx.SeenDevices.Any())
{ {
DicConsole.WriteLine("There are no statistics."); DicConsole.WriteLine("There are no statistics.");
return (int)ErrorNumber.NothingFound;
return(int)ErrorNumber.NothingFound;
} }
bool thereAreStats = false; bool thereAreStats = false;
@@ -97,11 +79,13 @@ namespace DiscImageChef.Commands
foreach(string command in ctx.Commands.OrderBy(c => c.Name).Select(c => c.Name).Distinct()) foreach(string command in ctx.Commands.OrderBy(c => c.Name).Select(c => c.Name).Distinct())
{ {
ulong count = ctx.Commands.Where(c => c.Name == command && c.Synchronized).Select(c => c.Count) ulong count = ctx.Commands.Where(c => c.Name == command && c.Synchronized).Select(c => c.Count).
.FirstOrDefault(); FirstOrDefault();
count += (ulong)ctx.Commands.LongCount(c => c.Name == command && !c.Synchronized); count += (ulong)ctx.Commands.LongCount(c => c.Name == command && !c.Synchronized);
if(count == 0) continue; if(count == 0)
continue;
DicConsole.WriteLine("You have called the {0} command {1} times.", command, count); DicConsole.WriteLine("You have called the {0} command {1} times.", command, count);
thereAreStats = true; thereAreStats = true;
@@ -117,11 +101,13 @@ namespace DiscImageChef.Commands
foreach(string filter in ctx.Filters.OrderBy(c => c.Name).Select(c => c.Name).Distinct()) foreach(string filter in ctx.Filters.OrderBy(c => c.Name).Select(c => c.Name).Distinct())
{ {
ulong count = ctx.Filters.Where(c => c.Name == filter && c.Synchronized).Select(c => c.Count) ulong count = ctx.Filters.Where(c => c.Name == filter && c.Synchronized).Select(c => c.Count).
.FirstOrDefault(); FirstOrDefault();
count += (ulong)ctx.Filters.LongCount(c => c.Name == filter && !c.Synchronized); count += (ulong)ctx.Filters.LongCount(c => c.Name == filter && !c.Synchronized);
if(count == 0) continue; if(count == 0)
continue;
DicConsole.WriteLine("Filter {0} has been found {1} times.", filter, count); DicConsole.WriteLine("Filter {0} has been found {1} times.", filter, count);
thereAreStats = true; thereAreStats = true;
@@ -137,11 +123,13 @@ namespace DiscImageChef.Commands
foreach(string format in ctx.MediaFormats.OrderBy(c => c.Name).Select(c => c.Name).Distinct()) foreach(string format in ctx.MediaFormats.OrderBy(c => c.Name).Select(c => c.Name).Distinct())
{ {
ulong count = ctx.MediaFormats.Where(c => c.Name == format && c.Synchronized).Select(c => c.Count) ulong count = ctx.MediaFormats.Where(c => c.Name == format && c.Synchronized).Select(c => c.Count).
.FirstOrDefault(); FirstOrDefault();
count += (ulong)ctx.MediaFormats.LongCount(c => c.Name == format && !c.Synchronized); count += (ulong)ctx.MediaFormats.LongCount(c => c.Name == format && !c.Synchronized);
if(count == 0) continue; if(count == 0)
continue;
DicConsole.WriteLine("Format {0} has been found {1} times.", format, count); DicConsole.WriteLine("Format {0} has been found {1} times.", format, count);
thereAreStats = true; thereAreStats = true;
@@ -157,11 +145,13 @@ namespace DiscImageChef.Commands
foreach(string partition in ctx.Partitions.OrderBy(c => c.Name).Select(c => c.Name).Distinct()) foreach(string partition in ctx.Partitions.OrderBy(c => c.Name).Select(c => c.Name).Distinct())
{ {
ulong count = ctx.Partitions.Where(c => c.Name == partition && c.Synchronized).Select(c => c.Count) ulong count = ctx.Partitions.Where(c => c.Name == partition && c.Synchronized).Select(c => c.Count).
.FirstOrDefault(); FirstOrDefault();
count += (ulong)ctx.Partitions.LongCount(c => c.Name == partition && !c.Synchronized); count += (ulong)ctx.Partitions.LongCount(c => c.Name == partition && !c.Synchronized);
if(count == 0) continue; if(count == 0)
continue;
DicConsole.WriteLine("Partitioning scheme {0} has been found {1} times.", partition, count); DicConsole.WriteLine("Partitioning scheme {0} has been found {1} times.", partition, count);
thereAreStats = true; thereAreStats = true;
@@ -177,11 +167,13 @@ namespace DiscImageChef.Commands
foreach(string filesystem in ctx.Filesystems.OrderBy(c => c.Name).Select(c => c.Name).Distinct()) foreach(string filesystem in ctx.Filesystems.OrderBy(c => c.Name).Select(c => c.Name).Distinct())
{ {
ulong count = ctx.Filesystems.Where(c => c.Name == filesystem && c.Synchronized) ulong count = ctx.Filesystems.Where(c => c.Name == filesystem && c.Synchronized).
.Select(c => c.Count).FirstOrDefault(); Select(c => c.Count).FirstOrDefault();
count += (ulong)ctx.Filesystems.LongCount(c => c.Name == filesystem && !c.Synchronized); count += (ulong)ctx.Filesystems.LongCount(c => c.Name == filesystem && !c.Synchronized);
if(count == 0) continue; if(count == 0)
continue;
DicConsole.WriteLine("Filesystem {0} has been found {1} times.", filesystem, count); DicConsole.WriteLine("Filesystem {0} has been found {1} times.", filesystem, count);
thereAreStats = true; thereAreStats = true;
@@ -195,10 +187,10 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Device statistics"); DicConsole.WriteLine("Device statistics");
DicConsole.WriteLine("================="); DicConsole.WriteLine("=================");
foreach(DeviceStat ds in ctx.SeenDevices.OrderBy(ds => ds.Manufacturer).ThenBy(ds => ds.Model) foreach(DeviceStat ds in ctx.SeenDevices.OrderBy(ds => ds.Manufacturer).ThenBy(ds => ds.Model).
.ThenBy(ds => ds.Revision).ThenBy(ds => ds.Bus)) ThenBy(ds => ds.Revision).ThenBy(ds => ds.Bus))
DicConsole DicConsole.
.WriteLine("Device model {0}, manufactured by {1}, with revision {2} and attached via {3}.", WriteLine("Device model {0}, manufactured by {1}, with revision {2} and attached via {3}.",
ds.Model, ds.Manufacturer, ds.Revision, ds.Bus); ds.Model, ds.Manufacturer, ds.Revision, ds.Bus);
DicConsole.WriteLine(); DicConsole.WriteLine();
@@ -212,8 +204,9 @@ namespace DiscImageChef.Commands
foreach(string media in ctx.Medias.OrderBy(ms => ms.Type).Select(ms => ms.Type).Distinct()) foreach(string media in ctx.Medias.OrderBy(ms => ms.Type).Select(ms => ms.Type).Distinct())
{ {
ulong count = ctx.Medias.Where(c => c.Type == media && c.Synchronized && c.Real) ulong count = ctx.Medias.Where(c => c.Type == media && c.Synchronized && c.Real).
.Select(c => c.Count).FirstOrDefault(); Select(c => c.Count).FirstOrDefault();
count += (ulong)ctx.Medias.LongCount(c => c.Type == media && !c.Synchronized && c.Real); count += (ulong)ctx.Medias.LongCount(c => c.Type == media && !c.Synchronized && c.Real);
if(count > 0) if(count > 0)
@@ -222,11 +215,13 @@ namespace DiscImageChef.Commands
thereAreStats = true; thereAreStats = true;
} }
count = ctx.Medias.Where(c => c.Type == media && c.Synchronized && !c.Real).Select(c => c.Count) count = ctx.Medias.Where(c => c.Type == media && c.Synchronized && !c.Real).Select(c => c.Count).
.FirstOrDefault(); FirstOrDefault();
count += (ulong)ctx.Medias.LongCount(c => c.Type == media && !c.Synchronized && !c.Real); count += (ulong)ctx.Medias.LongCount(c => c.Type == media && !c.Synchronized && !c.Real);
if(count == 0) continue; if(count == 0)
continue;
DicConsole.WriteLine("Media type {0} has been found {1} times in a media image.", media, count); DicConsole.WriteLine("Media type {0} has been found {1} times in a media image.", media, count);
thereAreStats = true; thereAreStats = true;
@@ -235,8 +230,10 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine(); DicConsole.WriteLine();
} }
if(!thereAreStats) DicConsole.WriteLine("There are no statistics."); if(!thereAreStats)
return (int)ErrorNumber.NoError; DicConsole.WriteLine("There are no statistics.");
return(int)ErrorNumber.NoError;
} }
} }
} }

View File

@@ -30,62 +30,44 @@
// Copyright © 2011-2019 Natalia Portillo // Copyright © 2011-2019 Natalia Portillo
// ****************************************************************************/ // ****************************************************************************/
using System.Collections.Generic; using System.CommandLine;
using System.CommandLine.Invocation;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using Mono.Options;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class UpdateCommand : Command internal class UpdateCommand : Command
{ {
readonly bool masterDbUpdate; readonly bool _masterDbUpdate;
bool showHelp;
public UpdateCommand(bool masterDbUpdate) : base("update", "Updates the database.") public UpdateCommand(bool masterDbUpdate) : base("update", "Updates the database.")
{ {
this.masterDbUpdate = masterDbUpdate; _masterDbUpdate = masterDbUpdate;
Options = new OptionSet
{ Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}",
$"{MainClass.AssemblyCopyright}",
"",
$"usage: DiscImageChef {Name}",
"",
Help,
{"help|h|?", "Show this message and exit.", v => showHelp = v != null}
};
} }
public override int Invoke(IEnumerable<string> arguments) int Invoke(bool debug, bool verbose)
{ {
if(masterDbUpdate) return (int)ErrorNumber.NoError; if(_masterDbUpdate)
return(int)ErrorNumber.NoError;
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
if(extra.Count > 0) if(debug)
{ DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
DicConsole.ErrorWriteLine("Too many arguments.");
return (int)ErrorNumber.UnexpectedArgumentCount;
}
DicConsole.DebugWriteLine("Update command", "--debug={0}", MainClass.Debug); if(verbose)
DicConsole.DebugWriteLine("Update command", "--verbose={0}", MainClass.Verbose); DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
DicConsole.DebugWriteLine("Update command", "--debug={0}", debug);
DicConsole.DebugWriteLine("Update command", "--verbose={0}", verbose);
DoUpdate(false); DoUpdate(false);
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
internal static void DoUpdate(bool create) internal static void DoUpdate(bool create)

View File

@@ -32,81 +32,71 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.CommonTypes.Structs; using DiscImageChef.CommonTypes.Structs;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using Mono.Options;
namespace DiscImageChef.Commands namespace DiscImageChef.Commands
{ {
class VerifyCommand : Command internal class VerifyCommand : Command
{ {
string inputFile;
bool showHelp;
bool verifyDisc = true;
bool verifySectors = true;
public VerifyCommand() : base("verify", "Verifies a disc image integrity, and if supported, sector integrity.") public VerifyCommand() : base("verify", "Verifies a disc image integrity, and if supported, sector integrity.")
{ {
Options = new OptionSet Add(new Option(new[]
{
"--verify-disc", "-w"
}, "Verify disc image if supported.")
{
Argument = new Argument<bool>(() => true), Required = false
});
Add(new Option(new[]
{
"--verify-sectors", "-s"
}, "Verify all sectors if supported.")
{
Argument = new Argument<bool>(() => true), Required = false
});
AddArgument(new Argument<string>
{ {
$"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", Arity = ArgumentArity.ExactlyOne, Description = "Disc image path", Name = "image-path"
$"{MainClass.AssemblyCopyright}", });
"",
$"usage: DiscImageChef {Name} [OPTIONS] imagefile", Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
"",
Help,
{"verify-disc|w", "Verify disc image if supported.", b => verifyDisc = b != null},
{"verify-sectors|s", "Verify all sectors if supported.", b => verifySectors = b != null},
{"help|h|?", "Show this message and exit.", v => showHelp = v != null}
};
} }
public override int Invoke(IEnumerable<string> arguments) static int Invoke(bool debug, bool verbose, string imagePath, bool verifyDisc = true, bool verifySectors = true)
{ {
List<string> extra = Options.Parse(arguments);
if(showHelp)
{
Options.WriteOptionDescriptions(CommandSet.Out);
return (int)ErrorNumber.HelpRequested;
}
MainClass.PrintCopyright(); MainClass.PrintCopyright();
if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; if(debug)
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
if(verbose)
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
Statistics.AddCommand("verify"); Statistics.AddCommand("verify");
if(extra.Count > 1) DicConsole.DebugWriteLine("Verify command", "--debug={0}", debug);
{ DicConsole.DebugWriteLine("Verify command", "--input={0}", imagePath);
DicConsole.ErrorWriteLine("Too many arguments."); DicConsole.DebugWriteLine("Verify command", "--verbose={0}", verbose);
return (int)ErrorNumber.UnexpectedArgumentCount; DicConsole.DebugWriteLine("Verify command", "--verify-disc={0}", verifyDisc);
}
if(extra.Count == 0)
{
DicConsole.ErrorWriteLine("Missing input image.");
return (int)ErrorNumber.MissingArgument;
}
inputFile = extra[0];
DicConsole.DebugWriteLine("Verify command", "--debug={0}", MainClass.Debug);
DicConsole.DebugWriteLine("Verify command", "--input={0}", inputFile);
DicConsole.DebugWriteLine("Verify command", "--verbose={0}", MainClass.Verbose);
DicConsole.DebugWriteLine("Verify command", "--verify-disc={0}", verifyDisc);
DicConsole.DebugWriteLine("Verify command", "--verify-sectors={0}", verifySectors); DicConsole.DebugWriteLine("Verify command", "--verify-sectors={0}", verifySectors);
FiltersList filtersList = new FiltersList(); var filtersList = new FiltersList();
IFilter inputFilter = filtersList.GetFilter(inputFile); IFilter inputFilter = filtersList.GetFilter(imagePath);
if(inputFilter == null) if(inputFilter == null)
{ {
DicConsole.ErrorWriteLine("Cannot open specified file."); DicConsole.ErrorWriteLine("Cannot open specified file.");
return (int)ErrorNumber.CannotOpenFile;
return(int)ErrorNumber.CannotOpenFile;
} }
IMediaImage inputFormat = ImageFormat.Detect(inputFilter); IMediaImage inputFormat = ImageFormat.Detect(inputFilter);
@@ -114,7 +104,8 @@ namespace DiscImageChef.Commands
if(inputFormat == null) if(inputFormat == null)
{ {
DicConsole.ErrorWriteLine("Unable to recognize image format, not verifying"); DicConsole.ErrorWriteLine("Unable to recognize image format, not verifying");
return (int)ErrorNumber.FormatNotFound;
return(int)ErrorNumber.FormatNotFound;
} }
inputFormat.Open(inputFilter); inputFormat.Open(inputFilter);
@@ -123,18 +114,19 @@ namespace DiscImageChef.Commands
Statistics.AddFilter(inputFilter.Name); Statistics.AddFilter(inputFilter.Name);
bool? correctImage = null; bool? correctImage = null;
long totalSectors = 0;
long errorSectors = 0; long errorSectors = 0;
bool? correctSectors = null; bool? correctSectors = null;
long unknownSectors = 0; long unknownSectors = 0;
IVerifiableImage verifiableImage = inputFormat as IVerifiableImage; var verifiableImage = inputFormat as IVerifiableImage;
IVerifiableSectorsImage verifiableSectorsImage = inputFormat as IVerifiableSectorsImage; var verifiableSectorsImage = inputFormat as IVerifiableSectorsImage;
if(verifiableImage is null && verifiableSectorsImage is null) if(verifiableImage is null &&
verifiableSectorsImage is null)
{ {
DicConsole.ErrorWriteLine("The specified image does not support any kind of verification"); DicConsole.ErrorWriteLine("The specified image does not support any kind of verification");
return (int)ErrorNumber.NotVerificable;
return(int)ErrorNumber.NotVerificable;
} }
if(verifyDisc && verifiableImage != null) if(verifyDisc && verifiableImage != null)
@@ -149,12 +141,15 @@ namespace DiscImageChef.Commands
{ {
case true: case true:
DicConsole.WriteLine("Disc image checksums are correct"); DicConsole.WriteLine("Disc image checksums are correct");
break; break;
case false: case false:
DicConsole.WriteLine("Disc image checksums are incorrect"); DicConsole.WriteLine("Disc image checksums are incorrect");
break; break;
case null: case null:
DicConsole.WriteLine("Disc image does not contain checksums"); DicConsole.WriteLine("Disc image does not contain checksums");
break; break;
} }
@@ -175,6 +170,7 @@ namespace DiscImageChef.Commands
ulong currentSectorAll = 0; ulong currentSectorAll = 0;
startCheck = DateTime.UtcNow; startCheck = DateTime.UtcNow;
foreach(Track currentTrack in inputTracks) foreach(Track currentTrack in inputTracks)
{ {
ulong remainingSectors = currentTrack.TrackEndSector - currentTrack.TrackStartSector; ulong remainingSectors = currentTrack.TrackEndSector - currentTrack.TrackStartSector;
@@ -185,20 +181,20 @@ namespace DiscImageChef.Commands
DicConsole.Write("\rChecking sector {0} of {1}, on track {2}", currentSectorAll, DicConsole.Write("\rChecking sector {0} of {1}, on track {2}", currentSectorAll,
inputFormat.Info.Sectors, currentTrack.TrackSequence); inputFormat.Info.Sectors, currentTrack.TrackSequence);
List<ulong> tempfailingLbas; List<ulong> tempFailingLbas;
List<ulong> tempunknownLbas; List<ulong> tempUnknownLbas;
if(remainingSectors < 512) if(remainingSectors < 512)
opticalMediaImage.VerifySectors(currentSector, (uint)remainingSectors, opticalMediaImage.VerifySectors(currentSector, (uint)remainingSectors,
currentTrack.TrackSequence, out tempfailingLbas, currentTrack.TrackSequence, out tempFailingLbas,
out tempunknownLbas); out tempUnknownLbas);
else else
opticalMediaImage.VerifySectors(currentSector, 512, currentTrack.TrackSequence, opticalMediaImage.VerifySectors(currentSector, 512, currentTrack.TrackSequence,
out tempfailingLbas, out tempunknownLbas); out tempFailingLbas, out tempUnknownLbas);
failingLbas.AddRange(tempfailingLbas); failingLbas.AddRange(tempFailingLbas);
unknownLbas.AddRange(tempunknownLbas); unknownLbas.AddRange(tempUnknownLbas);
if(remainingSectors < 512) if(remainingSectors < 512)
{ {
@@ -223,23 +219,24 @@ namespace DiscImageChef.Commands
ulong currentSector = 0; ulong currentSector = 0;
startCheck = DateTime.UtcNow; startCheck = DateTime.UtcNow;
while(remainingSectors > 0) while(remainingSectors > 0)
{ {
DicConsole.Write("\rChecking sector {0} of {1}", currentSector, inputFormat.Info.Sectors); DicConsole.Write("\rChecking sector {0} of {1}", currentSector, inputFormat.Info.Sectors);
List<ulong> tempfailingLbas; List<ulong> tempFailingLbas;
List<ulong> tempunknownLbas; List<ulong> tempUnknownLbas;
if(remainingSectors < 512) if(remainingSectors < 512)
verifiableSectorsImage.VerifySectors(currentSector, (uint)remainingSectors, verifiableSectorsImage.VerifySectors(currentSector, (uint)remainingSectors,
out tempfailingLbas, out tempunknownLbas); out tempFailingLbas, out tempUnknownLbas);
else else
verifiableSectorsImage.VerifySectors(currentSector, 512, out tempfailingLbas, verifiableSectorsImage.VerifySectors(currentSector, 512, out tempFailingLbas,
out tempunknownLbas); out tempUnknownLbas);
failingLbas.AddRange(tempfailingLbas); failingLbas.AddRange(tempFailingLbas);
unknownLbas.AddRange(tempunknownLbas); unknownLbas.AddRange(tempUnknownLbas);
if(remainingSectors < 512) if(remainingSectors < 512)
{ {
@@ -262,15 +259,20 @@ namespace DiscImageChef.Commands
if(unknownSectors > 0) if(unknownSectors > 0)
DicConsole.WriteLine("There is at least one sector that does not contain a checksum"); DicConsole.WriteLine("There is at least one sector that does not contain a checksum");
if(errorSectors > 0) if(errorSectors > 0)
DicConsole.WriteLine("There is at least one sector with incorrect checksum or errors"); DicConsole.WriteLine("There is at least one sector with incorrect checksum or errors");
if(unknownSectors == 0 && errorSectors == 0) DicConsole.WriteLine("All sector checksums are correct");
if(unknownSectors == 0 &&
errorSectors == 0)
DicConsole.WriteLine("All sector checksums are correct");
DicConsole.VerboseWriteLine("Checking sector checksums took {0} seconds", checkTime.TotalSeconds); DicConsole.VerboseWriteLine("Checking sector checksums took {0} seconds", checkTime.TotalSeconds);
if(MainClass.Verbose) if(verbose)
{ {
DicConsole.VerboseWriteLine("LBAs with error:"); DicConsole.VerboseWriteLine("LBAs with error:");
if(failingLbas.Count == (int)inputFormat.Info.Sectors) if(failingLbas.Count == (int)inputFormat.Info.Sectors)
DicConsole.VerboseWriteLine("\tall sectors."); DicConsole.VerboseWriteLine("\tall sectors.");
else else
@@ -278,6 +280,7 @@ namespace DiscImageChef.Commands
DicConsole.VerboseWriteLine("\t{0}", t); DicConsole.VerboseWriteLine("\t{0}", t);
DicConsole.WriteLine("LBAs without checksum:"); DicConsole.WriteLine("LBAs without checksum:");
if(unknownLbas.Count == (int)inputFormat.Info.Sectors) if(unknownLbas.Count == (int)inputFormat.Info.Sectors)
DicConsole.VerboseWriteLine("\tall sectors."); DicConsole.VerboseWriteLine("\tall sectors.");
else else
@@ -290,27 +293,26 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Total unknowns.......... {0}", unknownLbas.Count); DicConsole.WriteLine("Total unknowns.......... {0}", unknownLbas.Count);
DicConsole.WriteLine("Total errors+unknowns... {0}", failingLbas.Count + unknownLbas.Count); DicConsole.WriteLine("Total errors+unknowns... {0}", failingLbas.Count + unknownLbas.Count);
totalSectors = (long)inputFormat.Info.Sectors; if(failingLbas.Count > 0)
errorSectors = failingLbas.Count; correctSectors = false;
unknownSectors = unknownLbas.Count; else if((ulong)unknownLbas.Count < inputFormat.Info.Sectors)
if(failingLbas.Count > 0) correctSectors = false; correctSectors = true;
else if((ulong)unknownLbas.Count < inputFormat.Info.Sectors) correctSectors = true;
} }
switch(correctImage) switch(correctImage)
{ {
case null when correctSectors is null: return (int)ErrorNumber.NotVerificable; case null when correctSectors is null: return(int)ErrorNumber.NotVerificable;
case null when correctSectors == false: return (int)ErrorNumber.BadSectorsImageNotVerified; case null when correctSectors == false: return(int)ErrorNumber.BadSectorsImageNotVerified;
case null when correctSectors == true: return (int)ErrorNumber.CorrectSectorsImageNotVerified; case null when correctSectors == true: return(int)ErrorNumber.CorrectSectorsImageNotVerified;
case false when correctSectors is null: return (int)ErrorNumber.BadImageSectorsNotVerified; case false when correctSectors is null: return(int)ErrorNumber.BadImageSectorsNotVerified;
case false when correctSectors == false: return (int)ErrorNumber.BadImageBadSectors; case false when correctSectors == false: return(int)ErrorNumber.BadImageBadSectors;
case false when correctSectors == true: return (int)ErrorNumber.CorrectSectorsBadImage; case false when correctSectors == true: return(int)ErrorNumber.CorrectSectorsBadImage;
case true when correctSectors is null: return (int)ErrorNumber.CorrectImageSectorsNotVerified; case true when correctSectors is null: return(int)ErrorNumber.CorrectImageSectorsNotVerified;
case true when correctSectors == false: return (int)ErrorNumber.CorrectImageBadSectors; case true when correctSectors == false: return(int)ErrorNumber.CorrectImageBadSectors;
case true when correctSectors == true: return (int)ErrorNumber.NoError; case true when correctSectors == true: return(int)ErrorNumber.NoError;
} }
return (int)ErrorNumber.NoError; return(int)ErrorNumber.NoError;
} }
} }
} }

View File

@@ -264,8 +264,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Mono.Options" Version="5.3.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="System.CommandLine.Experimental" Version="0.3.0-alpha.19577.1" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.1" /> <PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.1" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.3.0" /> <PackageReference Include="Unclassified.NetRevisionTask" Version="0.3.0" />

View File

@@ -31,44 +31,43 @@
// ****************************************************************************/ // ****************************************************************************/
using System; using System;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscImageChef.Commands; using DiscImageChef.Commands;
using DiscImageChef.CommonTypes.Interop;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Core; using DiscImageChef.Core;
using DiscImageChef.Database; using DiscImageChef.Database;
using DiscImageChef.Settings; using DiscImageChef.Settings;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Mono.Options;
using PlatformID = DiscImageChef.CommonTypes.Interop.PlatformID;
namespace DiscImageChef namespace DiscImageChef
{ {
internal class MainClass internal class MainClass
{ {
internal static bool Verbose; static string _assemblyCopyright;
internal static bool Debug; static string _assemblyTitle;
internal static string AssemblyCopyright; static AssemblyInformationalVersionAttribute _assemblyVersion;
internal static string AssemblyTitle;
internal static AssemblyInformationalVersionAttribute AssemblyVersion;
[STAThread] [STAThread]
public static int Main(string[] args) public static int Main(string[] args)
{ {
var attributes = typeof(MainClass).Assembly.GetCustomAttributes(typeof(AssemblyTitleAttribute), false); object[] attributes = typeof(MainClass).Assembly.GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
AssemblyTitle = ((AssemblyTitleAttribute) attributes[0]).Title; _assemblyTitle = ((AssemblyTitleAttribute)attributes[0]).Title;
attributes = typeof(MainClass).Assembly.GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); attributes = typeof(MainClass).Assembly.GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false);
AssemblyVersion =
_assemblyVersion =
Attribute.GetCustomAttribute(typeof(MainClass).Assembly, typeof(AssemblyInformationalVersionAttribute)) Attribute.GetCustomAttribute(typeof(MainClass).Assembly, typeof(AssemblyInformationalVersionAttribute))
as AssemblyInformationalVersionAttribute; as AssemblyInformationalVersionAttribute;
AssemblyCopyright = ((AssemblyCopyrightAttribute) attributes[0]).Copyright;
DicConsole.WriteLineEvent += System.Console.WriteLine; _assemblyCopyright = ((AssemblyCopyrightAttribute)attributes[0]).Copyright;
DicConsole.WriteEvent += System.Console.Write;
DicConsole.WriteLineEvent += System.Console.WriteLine;
DicConsole.WriteEvent += System.Console.Write;
DicConsole.ErrorWriteLineEvent += System.Console.Error.WriteLine; DicConsole.ErrorWriteLineEvent += System.Console.Error.WriteLine;
Settings.Settings.LoadSettings(); Settings.Settings.LoadSettings();
@@ -77,16 +76,17 @@ namespace DiscImageChef
ctx.Database.Migrate(); ctx.Database.Migrate();
ctx.SaveChanges(); ctx.SaveChanges();
var masterDbUpdate = false; bool masterDbUpdate = false;
if (!File.Exists(Settings.Settings.MasterDbPath))
if(!File.Exists(Settings.Settings.MasterDbPath))
{ {
masterDbUpdate = true; masterDbUpdate = true;
UpdateCommand.DoUpdate(true); UpdateCommand.DoUpdate(true);
} }
var mctx = DicContext.Create(Settings.Settings.MasterDbPath); var masterContext = DicContext.Create(Settings.Settings.MasterDbPath);
if(mctx.Database.GetPendingMigrations().Any()) if(masterContext.Database.GetPendingMigrations().Any())
{ {
DicConsole.WriteLine("New database version, updating..."); DicConsole.WriteLine("New database version, updating...");
@@ -103,84 +103,76 @@ namespace DiscImageChef
UpdateCommand.DoUpdate(true); UpdateCommand.DoUpdate(true);
} }
if ((args.Length < 1 || args[0].ToLowerInvariant() != "gui") && if((args.Length < 1 || args[0].ToLowerInvariant() != "gui") &&
Settings.Settings.Current.GdprCompliance < DicSettings.GdprLevel) Settings.Settings.Current.GdprCompliance < DicSettings.GdprLevel)
new ConfigureCommand(true, true).Invoke(args); new ConfigureCommand(true, true).Invoke(args);
Statistics.LoadStats();
if (Settings.Settings.Current.Stats != null && Settings.Settings.Current.Stats.ShareStats)
Task.Run(() => { Statistics.SubmitStats(); });
var currentPlatform = DetectOS.GetRealPlatformID(); Statistics.LoadStats();
if(Settings.Settings.Current.Stats != null &&
Settings.Settings.Current.Stats.ShareStats)
Task.Run(Statistics.SubmitStats);
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
var commands = new CommandSet("DiscImageChef")
{
$"{AssemblyTitle} {AssemblyVersion?.InformationalVersion}",
$"{AssemblyCopyright}",
"",
"usage: DiscImageChef COMMAND [OPTIONS]",
"",
"Global options:",
{"verbose|v", "Shows verbose output.", b => Verbose = b != null},
{"debug|d", "Shows debug output from plugins.", b => Debug = b != null},
"",
"Available commands:",
new AnalyzeCommand(),
new BenchmarkCommand(),
new ChecksumCommand(),
new CompareCommand(),
new ConfigureCommand(false, false),
new ConvertImageCommand(),
new CreateSidecarCommand(),
new DecodeCommand()
};
if (currentPlatform == PlatformID.FreeBSD || currentPlatform == PlatformID.Linux ||
currentPlatform == PlatformID.Win32NT)
{
commands.Add(new DeviceInfoCommand());
commands.Add(new DeviceReportCommand());
commands.Add(new DumpMediaCommand());
}
commands.Add(new EntropyCommand());
commands.Add(new ExtractFilesCommand());
commands.Add(new FormatsCommand());
commands.Add(new ImageInfoCommand());
if (currentPlatform == PlatformID.FreeBSD || currentPlatform == PlatformID.Linux ||
currentPlatform == PlatformID.Win32NT) commands.Add(new ListDevicesCommand());
commands.Add(new ListEncodingsCommand());
commands.Add(new ListNamespacesCommand());
commands.Add(new ListOptionsCommand());
commands.Add(new LsCommand());
if (currentPlatform == PlatformID.FreeBSD || currentPlatform == PlatformID.Linux ||
currentPlatform == PlatformID.Win32NT)
{
commands.Add(new MediaInfoCommand());
commands.Add(new MediaScanCommand());
}
commands.Add(new PrintHexCommand());
commands.Add(new StatisticsCommand());
commands.Add(new UpdateCommand(masterDbUpdate));
commands.Add(new VerifyCommand());
commands.Add(new RemoteCommand());
var ret = commands.Run(args);
Statistics.SaveStats(); Statistics.SaveStats();
return ret; var rootCommand = new RootCommand
{
new Option(new[]
{
"--verbose", "-v"
}, "Shows verbose output.")
{
Argument = new Argument<bool>(() => false)
},
new Option(new[]
{
"--debug", "-d"
}, "Shows debug output from plugins.")
{
Argument = new Argument<bool>(() => false)
}
};
rootCommand.Description =
$"{_assemblyTitle} {_assemblyVersion?.InformationalVersion}\n{_assemblyCopyright}";
rootCommand.AddCommand(new AnalyzeCommand());
rootCommand.AddCommand(new BenchmarkCommand());
rootCommand.AddCommand(new ChecksumCommand());
rootCommand.AddCommand(new CompareCommand());
rootCommand.AddCommand(new ConfigureCommand(false, false));
rootCommand.AddCommand(new ConvertImageCommand());
rootCommand.AddCommand(new CreateSidecarCommand());
rootCommand.AddCommand(new DecodeCommand());
rootCommand.AddCommand(new DeviceInfoCommand());
rootCommand.AddCommand(new DeviceReportCommand());
rootCommand.AddCommand(new DumpMediaCommand());
rootCommand.AddCommand(new EntropyCommand());
rootCommand.AddCommand(new ExtractFilesCommand());
rootCommand.AddCommand(new FormatsCommand());
rootCommand.AddCommand(new ImageInfoCommand());
rootCommand.AddCommand(new ListDevicesCommand());
rootCommand.AddCommand(new ListEncodingsCommand());
rootCommand.AddCommand(new ListNamespacesCommand());
rootCommand.AddCommand(new ListOptionsCommand());
rootCommand.AddCommand(new LsCommand());
rootCommand.AddCommand(new MediaInfoCommand());
rootCommand.AddCommand(new MediaScanCommand());
rootCommand.AddCommand(new PrintHexCommand());
rootCommand.AddCommand(new StatisticsCommand());
rootCommand.AddCommand(new UpdateCommand(masterDbUpdate));
rootCommand.AddCommand(new VerifyCommand());
rootCommand.AddCommand(new RemoteCommand());
return rootCommand.Invoke(args);
} }
internal static void PrintCopyright() internal static void PrintCopyright()
{ {
DicConsole.WriteLine("{0} {1}", AssemblyTitle, AssemblyVersion?.InformationalVersion); DicConsole.WriteLine("{0} {1}", _assemblyTitle, _assemblyVersion?.InformationalVersion);
DicConsole.WriteLine("{0}", AssemblyCopyright); DicConsole.WriteLine("{0}", _assemblyCopyright);
DicConsole.WriteLine(); DicConsole.WriteLine();
} }
} }