diff --git a/.idea/.idea.DiscImageChef/.idea/contentModel.xml b/.idea/.idea.DiscImageChef/.idea/contentModel.xml index 499afadd8..dd6544bf1 100644 --- a/.idea/.idea.DiscImageChef/.idea/contentModel.xml +++ b/.idea/.idea.DiscImageChef/.idea/contentModel.xml @@ -33,6 +33,7 @@ + @@ -49,7 +50,6 @@ - diff --git a/DiscImageChef/Commands/Analyze.cs b/DiscImageChef/Commands/Analyze.cs index b700dc384..2e9a8a557 100644 --- a/DiscImageChef/Commands/Analyze.cs +++ b/DiscImageChef/Commands/Analyze.cs @@ -37,41 +37,92 @@ using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.Console; using DiscImageChef.Core; +using Mono.Options; namespace DiscImageChef.Commands { - static class Analyze + class AnalyzeCommand : Command { - internal static void DoAnalyze(AnalyzeOptions options) + string encodingName; + string inputFile; + bool searchForFilesystems = true; + bool searchForPartitions = true; + bool showHelp; + + public AnalyzeCommand() : base("analyze", + "Analyzes a disc image and searches for partitions and/or filesystems.") { - DicConsole.DebugWriteLine("Analyze command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Analyze command", "--verbose={0}", options.Verbose); - DicConsole.DebugWriteLine("Analyze command", "--input={0}", options.InputFile); - DicConsole.DebugWriteLine("Analyze command", "--filesystems={0}", options.SearchForFilesystems); - DicConsole.DebugWriteLine("Analyze command", "--partitions={0}", options.SearchForPartitions); - DicConsole.DebugWriteLine("Analyze command", "--encoding={0}", options.EncodingName); + Options = new OptionSet + { + $"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", + $"{MainClass.AssemblyCopyright}", + "", + $"usage: DiscImageChef {Name} [OPTIONS] imagefile", + "", + 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 arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 1) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count == 0) + { + DicConsole.ErrorWriteLine("Missing input image."); + return 1; + } + + 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(options.InputFile); + IFilter inputFilter = filtersList.GetFilter(inputFile); if(inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); - return; + return 2; } Encoding encoding = null; - if(options.EncodingName != null) + if(encodingName != null) try { - encoding = Claunia.Encoding.Encoding.GetEncoding(options.EncodingName); - if(options.Verbose) DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName); + encoding = Claunia.Encoding.Encoding.GetEncoding(encodingName); + if(MainClass.Verbose) DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName); } catch(ArgumentException) { DicConsole.ErrorWriteLine("Specified encoding is not supported."); - return; + return 5; } PluginBase plugins = GetPluginBase.Instance; @@ -85,10 +136,10 @@ namespace DiscImageChef.Commands if(imageFormat == null) { DicConsole.WriteLine("Image format not identified, not proceeding with analysis."); - return; + return 3; } - if(options.Verbose) + if(MainClass.Verbose) DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name, imageFormat.Id); else DicConsole.WriteLine("Image format identified by {0}.", imageFormat.Name); @@ -100,31 +151,31 @@ namespace DiscImageChef.Commands { DicConsole.WriteLine("Unable to open image format"); DicConsole.WriteLine("No error given"); - return; + return 4; } - if(options.Verbose) + if(MainClass.Verbose) { - Core.ImageInfo.PrintImageInfo(imageFormat); + ImageInfo.PrintImageInfo(imageFormat); DicConsole.WriteLine(); } - Core.Statistics.AddMediaFormat(imageFormat.Format); - Core.Statistics.AddMedia(imageFormat.Info.MediaType, false); - Core.Statistics.AddFilter(inputFilter.Name); + Statistics.AddMediaFormat(imageFormat.Format); + Statistics.AddMedia(imageFormat.Info.MediaType, false); + Statistics.AddFilter(inputFilter.Name); } catch(Exception ex) { DicConsole.ErrorWriteLine("Unable to open image format"); DicConsole.ErrorWriteLine("Error: {0}", ex.Message); DicConsole.DebugWriteLine("Analyze command", "Stack trace: {0}", ex.StackTrace); - return; + return -1; } List idPlugins; IFilesystem plugin; string information; - if(options.SearchForPartitions) + if(searchForPartitions) { List partitions = Core.Partitions.GetAll(imageFormat); Core.Partitions.AddSchemesToStats(partitions); @@ -132,10 +183,10 @@ namespace DiscImageChef.Commands if(partitions.Count == 0) { DicConsole.DebugWriteLine("Analyze command", "No partitions found"); - if(!options.SearchForFilesystems) + if(!searchForFilesystems) { DicConsole.WriteLine("No partitions founds, not searching for filesystems"); - return; + return -2; } checkraw = true; @@ -158,7 +209,7 @@ namespace DiscImageChef.Commands DicConsole.WriteLine("Partition description:"); DicConsole.WriteLine(partitions[i].Description); - if(!options.SearchForFilesystems) continue; + if(!searchForFilesystems) continue; DicConsole.WriteLine("Identifying filesystem on partition"); @@ -174,7 +225,7 @@ namespace DiscImageChef.Commands DicConsole.WriteLine($"As identified by {plugin.Name}."); plugin.GetInformation(imageFormat, partitions[i], out information, encoding); DicConsole.Write(information); - Core.Statistics.AddFilesystem(plugin.XmlFsType.Type); + Statistics.AddFilesystem(plugin.XmlFsType.Type); } } else @@ -185,7 +236,7 @@ namespace DiscImageChef.Commands DicConsole.WriteLine($"Identified by {plugin.Name}."); plugin.GetInformation(imageFormat, partitions[i], out information, encoding); DicConsole.Write("{0}", information); - Core.Statistics.AddFilesystem(plugin.XmlFsType.Type); + Statistics.AddFilesystem(plugin.XmlFsType.Type); } } } @@ -212,7 +263,7 @@ namespace DiscImageChef.Commands DicConsole.WriteLine($"As identified by {plugin.Name}."); plugin.GetInformation(imageFormat, wholePart, out information, encoding); DicConsole.Write(information); - Core.Statistics.AddFilesystem(plugin.XmlFsType.Type); + Statistics.AddFilesystem(plugin.XmlFsType.Type); } } else @@ -223,7 +274,7 @@ namespace DiscImageChef.Commands DicConsole.WriteLine($"Identified by {plugin.Name}."); plugin.GetInformation(imageFormat, wholePart, out information, encoding); DicConsole.Write(information); - Core.Statistics.AddFilesystem(plugin.XmlFsType.Type); + Statistics.AddFilesystem(plugin.XmlFsType.Type); } } } @@ -234,7 +285,8 @@ namespace DiscImageChef.Commands DicConsole.DebugWriteLine("Analyze command", ex.StackTrace); } - Core.Statistics.AddCommand("analyze"); + Statistics.AddCommand("analyze"); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/Benchmark.cs b/DiscImageChef/Commands/Benchmark.cs index 1d3a0762e..fd2363dc0 100644 --- a/DiscImageChef/Commands/Benchmark.cs +++ b/DiscImageChef/Commands/Benchmark.cs @@ -33,19 +33,60 @@ using System.Collections.Generic; using DiscImageChef.Console; using DiscImageChef.Core; +using Mono.Options; namespace DiscImageChef.Commands { - static class Benchmark + class BenchmarkCommand : Command { - internal static void DoBenchmark(BenchmarkOptions options) - { - Dictionary checksumTimes = new Dictionary(); - Core.Benchmark.InitProgressEvent += Progress.InitProgress; - Core.Benchmark.UpdateProgressEvent += Progress.UpdateProgress; - Core.Benchmark.EndProgressEvent += Progress.EndProgress; + int blockSize = 512; + int bufferSize = 128; + bool showHelp; - BenchmarkResults results = Core.Benchmark.Do(options.BufferSize * 1024 * 1024, options.BlockSize); + public BenchmarkCommand() : base("benchmark", "Benchmarks hashing and entropy calculation.") + { + Options = new OptionSet + { + $"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", + $"{MainClass.AssemblyCopyright}", + "", + $"usage: DiscImageChef {Name} [OPTIONS]", + "", + 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 arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count != 0) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + DicConsole.DebugWriteLine("Benchmark command", "--debug={0}", MainClass.Debug); + DicConsole.DebugWriteLine("Benchmark command", "--verbose={0}", MainClass.Verbose); + + Benchmark.InitProgressEvent += Progress.InitProgress; + Benchmark.UpdateProgressEvent += Progress.UpdateProgress; + Benchmark.EndProgressEvent += Progress.EndProgress; + + BenchmarkResults results = Benchmark.Do(bufferSize * 1024 * 1024, blockSize); DicConsole.WriteLine("Took {0} seconds to fill buffer, {1:F3} MiB/sec.", results.FillTime, results.FillSpeed); @@ -55,11 +96,8 @@ namespace DiscImageChef.Commands results.EntropySpeed); foreach(KeyValuePair entry in results.Entries) - { - checksumTimes.Add(entry.Key, entry.Value.TimeSpan); DicConsole.WriteLine("Took {0} seconds to {1} buffer, {2:F3} MiB/sec.", entry.Value.TimeSpan, entry.Key, entry.Value.Speed); - } DicConsole.WriteLine("Took {0} seconds to do all algorithms at the same time, {1:F3} MiB/sec.", results.TotalTime, results.TotalSpeed); @@ -70,7 +108,8 @@ namespace DiscImageChef.Commands DicConsole.WriteLine("Max memory used is {0} bytes", results.MaxMemory); DicConsole.WriteLine("Min memory used is {0} bytes", results.MinMemory); - Core.Statistics.AddCommand("benchmark"); + Statistics.AddCommand("benchmark"); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/Checksum.cs b/DiscImageChef/Commands/Checksum.cs index 1631c231d..c60301a0c 100644 --- a/DiscImageChef/Commands/Checksum.cs +++ b/DiscImageChef/Commands/Checksum.cs @@ -37,43 +37,117 @@ using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.CommonTypes.Structs; using DiscImageChef.Console; using DiscImageChef.Core; +using Mono.Options; using Schemas; namespace DiscImageChef.Commands { - static class Checksum + class ChecksumCommand : Command { // How many sectors to read at once const uint SECTORS_TO_READ = 256; - internal static void DoChecksum(ChecksumOptions options) + bool doAdler32 = true; + bool doCrc16 = true; + bool doCrc32 = true; + bool doCrc64; + bool doFletcher16; + bool doFletcher32; + bool doMd5 = true; + bool doRipemd160; + 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.") { - DicConsole.DebugWriteLine("Checksum command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Checksum command", "--verbose={0}", options.Verbose); - DicConsole.DebugWriteLine("Checksum command", "--separated-tracks={0}", options.SeparatedTracks); - DicConsole.DebugWriteLine("Checksum command", "--whole-disc={0}", options.WholeDisc); - DicConsole.DebugWriteLine("Checksum command", "--input={0}", options.InputFile); - DicConsole.DebugWriteLine("Checksum command", "--adler32={0}", options.DoAdler32); - DicConsole.DebugWriteLine("Checksum command", "--crc16={0}", options.DoCrc16); - DicConsole.DebugWriteLine("Checksum command", "--crc32={0}", options.DoCrc32); - DicConsole.DebugWriteLine("Checksum command", "--crc64={0}", options.DoCrc64); - DicConsole.DebugWriteLine("Checksum command", "--md5={0}", options.DoMd5); - DicConsole.DebugWriteLine("Checksum command", "--ripemd160={0}", options.DoRipemd160); - DicConsole.DebugWriteLine("Checksum command", "--sha1={0}", options.DoSha1); - DicConsole.DebugWriteLine("Checksum command", "--sha256={0}", options.DoSha256); - DicConsole.DebugWriteLine("Checksum command", "--sha384={0}", options.DoSha384); - DicConsole.DebugWriteLine("Checksum command", "--sha512={0}", options.DoSha512); - DicConsole.DebugWriteLine("Checksum command", "--spamsum={0}", options.DoSpamSum); - DicConsole.DebugWriteLine("Checksum command", "--fletcher16={0}", options.DoFletcher16); - DicConsole.DebugWriteLine("Checksum command", "--fletcher32={0}", options.DoFletcher32); + Options = new OptionSet + { + $"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", + $"{MainClass.AssemblyCopyright}", + "", + $"usage: DiscImageChef {Name} [OPTIONS] imagefile", + "", + Help, + {"adler32|a", "Calculates Adler-32.", b => doAdler32 = b != null}, + {"crc16", "Calculates CRC16.", b => doCrc16 = b != null}, + {"crc32|c", "Calculates CRC32.", b => doCrc32 = b != null}, + {"crc64", "Calculates CRC64 (ECMA).", b => doCrc64 = b != null}, + {"fletcher16", "Calculates Fletcher-16.", b => doFletcher16 = b != null}, + {"fletcher32", "Calculates Fletcher-32.", b => doFletcher32 = b != null}, + {"md5|m", "Calculates MD5.", b => doMd5 = b != null}, + {"ripemd160", "Calculates RIPEMD160.", b => doRipemd160 = b != null}, + {"separated-tracks|t", "Checksums each track separately.", b => separatedTracks = b != null}, + {"sha1|s", "Calculates SHA1.", b => doSha1 = b != null}, + {"sha256", "Calculates SHA256.", b => doSha256 = b != null}, + {"sha384", "Calculates SHA384.", b => doSha384 = b != null}, + {"sha512", "Calculates SHA512.", b => doSha512 = b != null}, + {"spamsum|f", "Calculates SpamSum fuzzy hash.", b => doSpamSum = b != null}, + {"whole-disc|w", "Checksums the whole disc.", b => wholeDisc = b != null}, + {"help|h|?", "Show this message and exit.", v => showHelp = v != null} + }; + } + + public override int Invoke(IEnumerable arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 1) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count == 0) + { + DicConsole.ErrorWriteLine("Missing input image."); + return 1; + } + + 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", "--ripemd160={0}", doRipemd160); + DicConsole.DebugWriteLine("Checksum command", "--separated-tracks={0}", separatedTracks); + DicConsole.DebugWriteLine("Checksum command", "--sha1={0}", doSha1); + DicConsole.DebugWriteLine("Checksum command", "--sha256={0}", doSha256); + DicConsole.DebugWriteLine("Checksum command", "--sha384={0}", doSha384); + DicConsole.DebugWriteLine("Checksum command", "--sha512={0}", doSha512); + DicConsole.DebugWriteLine("Checksum command", "--spamsum={0}", doSpamSum); + DicConsole.DebugWriteLine("Checksum command", "--verbose={0}", MainClass.Verbose); + DicConsole.DebugWriteLine("Checksum command", "--whole-disc={0}", wholeDisc); FiltersList filtersList = new FiltersList(); - IFilter inputFilter = filtersList.GetFilter(options.InputFile); + IFilter inputFilter = filtersList.GetFilter(inputFile); if(inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); - return; + return 1; } IMediaImage inputFormat = ImageFormat.Detect(inputFilter); @@ -81,44 +155,44 @@ namespace DiscImageChef.Commands if(inputFormat == null) { DicConsole.ErrorWriteLine("Unable to recognize image format, not checksumming"); - return; + return 2; } inputFormat.Open(inputFilter); - Core.Statistics.AddMediaFormat(inputFormat.Format); - Core.Statistics.AddMedia(inputFormat.Info.MediaType, false); - Core.Statistics.AddFilter(inputFilter.Name); + Statistics.AddMediaFormat(inputFormat.Format); + Statistics.AddMedia(inputFormat.Info.MediaType, false); + Statistics.AddFilter(inputFilter.Name); EnableChecksum enabledChecksums = new EnableChecksum(); - if(options.DoAdler32) enabledChecksums |= EnableChecksum.Adler32; - if(options.DoCrc16) enabledChecksums |= EnableChecksum.Crc16; - if(options.DoCrc32) enabledChecksums |= EnableChecksum.Crc32; - if(options.DoCrc64) enabledChecksums |= EnableChecksum.Crc64; - if(options.DoMd5) enabledChecksums |= EnableChecksum.Md5; - if(options.DoRipemd160) enabledChecksums |= EnableChecksum.Ripemd160; - if(options.DoSha1) enabledChecksums |= EnableChecksum.Sha1; - if(options.DoSha256) enabledChecksums |= EnableChecksum.Sha256; - if(options.DoSha384) enabledChecksums |= EnableChecksum.Sha384; - if(options.DoSha512) enabledChecksums |= EnableChecksum.Sha512; - if(options.DoSpamSum) enabledChecksums |= EnableChecksum.SpamSum; - if(options.DoFletcher16) enabledChecksums |= EnableChecksum.Fletcher16; - if(options.DoFletcher32) enabledChecksums |= EnableChecksum.Fletcher32; + if(doAdler32) enabledChecksums |= EnableChecksum.Adler32; + if(doCrc16) enabledChecksums |= EnableChecksum.Crc16; + if(doCrc32) enabledChecksums |= EnableChecksum.Crc32; + if(doCrc64) enabledChecksums |= EnableChecksum.Crc64; + if(doMd5) enabledChecksums |= EnableChecksum.Md5; + if(doRipemd160) enabledChecksums |= EnableChecksum.Ripemd160; + if(doSha1) enabledChecksums |= EnableChecksum.Sha1; + if(doSha256) enabledChecksums |= EnableChecksum.Sha256; + if(doSha384) enabledChecksums |= EnableChecksum.Sha384; + if(doSha512) enabledChecksums |= EnableChecksum.Sha512; + if(doSpamSum) enabledChecksums |= EnableChecksum.SpamSum; + if(doFletcher16) enabledChecksums |= EnableChecksum.Fletcher16; + if(doFletcher32) enabledChecksums |= EnableChecksum.Fletcher32; - Core.Checksum mediaChecksum = null; + Checksum mediaChecksum = null; if(inputFormat.Info.HasPartitions) try { - Core.Checksum trackChecksum = null; + Checksum trackChecksum = null; - if(options.WholeDisc) mediaChecksum = new Core.Checksum(enabledChecksums); + if(wholeDisc) mediaChecksum = new Checksum(enabledChecksums); ulong previousTrackEnd = 0; List inputTracks = inputFormat.Tracks; foreach(Track currentTrack in inputTracks) { - if(currentTrack.TrackStartSector - previousTrackEnd != 0 && options.WholeDisc) + if(currentTrack.TrackStartSector - previousTrackEnd != 0 && wholeDisc) for(ulong i = previousTrackEnd + 1; i < currentTrack.TrackStartSector; i++) { DicConsole.Write("\rHashing track-less sector {0}", i); @@ -133,7 +207,7 @@ namespace DiscImageChef.Commands currentTrack.TrackSequence, currentTrack.TrackStartSector, currentTrack.TrackEndSector); - if(options.SeparatedTracks) trackChecksum = new Core.Checksum(enabledChecksums); + if(separatedTracks) trackChecksum = new Checksum(enabledChecksums); ulong sectors = currentTrack.TrackEndSector - currentTrack.TrackStartSector + 1; ulong doneSectors = 0; @@ -160,14 +234,14 @@ namespace DiscImageChef.Commands doneSectors += sectors - doneSectors; } - if(options.WholeDisc) mediaChecksum?.Update(sector); + if(wholeDisc) mediaChecksum?.Update(sector); - if(options.SeparatedTracks) trackChecksum?.Update(sector); + if(separatedTracks) trackChecksum?.Update(sector); } DicConsole.WriteLine(); - if(options.SeparatedTracks) + if(separatedTracks) if(trackChecksum != null) foreach(ChecksumType chk in trackChecksum.End()) DicConsole.WriteLine("Track {0}'s {1}: {2}", currentTrack.TrackSequence, chk.type, @@ -176,7 +250,7 @@ namespace DiscImageChef.Commands previousTrackEnd = currentTrack.TrackEndSector; } - if(inputFormat.Info.Sectors - previousTrackEnd != 0 && options.WholeDisc) + if(inputFormat.Info.Sectors - previousTrackEnd != 0 && wholeDisc) for(ulong i = previousTrackEnd + 1; i < inputFormat.Info.Sectors; i++) { DicConsole.Write("\rHashing track-less sector {0}", i); @@ -185,19 +259,19 @@ namespace DiscImageChef.Commands mediaChecksum?.Update(hiddenSector); } - if(options.WholeDisc) + if(wholeDisc) if(mediaChecksum != null) foreach(ChecksumType chk in mediaChecksum.End()) DicConsole.WriteLine("Disk's {0}: {1}", chk.type, chk.Value); } catch(Exception ex) { - if(options.Debug) DicConsole.DebugWriteLine("Could not get tracks because {0}", ex.Message); + if(MainClass.Debug) DicConsole.DebugWriteLine("Could not get tracks because {0}", ex.Message); else DicConsole.WriteLine("Unable to get separate tracks, not checksumming them"); } else { - mediaChecksum = new Core.Checksum(enabledChecksums); + mediaChecksum = new Checksum(enabledChecksums); ulong sectors = inputFormat.Info.Sectors; DicConsole.WriteLine("Sectors {0}", sectors); @@ -230,7 +304,8 @@ namespace DiscImageChef.Commands DicConsole.WriteLine("Disk's {0}: {1}", chk.type, chk.Value); } - Core.Statistics.AddCommand("checksum"); + Statistics.AddCommand("checksum"); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/Compare.cs b/DiscImageChef/Commands/Compare.cs index ad864c432..1a9a61de4 100644 --- a/DiscImageChef/Commands/Compare.cs +++ b/DiscImageChef/Commands/Compare.cs @@ -39,33 +39,80 @@ using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.CommonTypes.Structs; using DiscImageChef.Console; using DiscImageChef.Core; +using Mono.Options; +using ImageInfo = DiscImageChef.CommonTypes.Structs.ImageInfo; namespace DiscImageChef.Commands { - static class Compare + class CompareCommand : Command { - internal static void DoCompare(CompareOptions options) + string InputFile1; + string InputFile2; + bool ShowHelp; + + public CompareCommand() : base("compare", "Compares two disc images.") { - DicConsole.DebugWriteLine("Compare command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Compare command", "--verbose={0}", options.Verbose); - DicConsole.DebugWriteLine("Compare command", "--input1={0}", options.InputFile1); - DicConsole.DebugWriteLine("Compare command", "--input2={0}", options.InputFile2); + Options = new OptionSet + { + $"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", + $"{MainClass.AssemblyCopyright}", + "", + $"usage: DiscImageChef {Name} imagefile1 imagefile2", + "", + Help, + {"help|h|?", "Show this message and exit.", v => ShowHelp = v != null} + }; + } + + public override int Invoke(IEnumerable arguments) + { + List extra = Options.Parse(arguments); + + if(ShowHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 2) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count <= 1) + { + DicConsole.ErrorWriteLine("Missing input image."); + return 1; + } + + InputFile1 = extra[0]; + InputFile1 = 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(options.InputFile1); + IFilter inputFilter1 = filtersList.GetFilter(InputFile1); filtersList = new FiltersList(); - IFilter inputFilter2 = filtersList.GetFilter(options.InputFile2); + IFilter inputFilter2 = filtersList.GetFilter(InputFile2); if(inputFilter1 == null) { DicConsole.ErrorWriteLine("Cannot open input file 1"); - return; + return 1; } if(inputFilter2 == null) { DicConsole.ErrorWriteLine("Cannot open input file 2"); - return; + return 2; } IMediaImage input1Format = ImageFormat.Detect(inputFilter1); @@ -74,10 +121,10 @@ namespace DiscImageChef.Commands if(input1Format == null) { DicConsole.ErrorWriteLine("Input file 1 format not identified, not proceeding with comparison."); - return; + return 3; } - if(options.Verbose) + if(MainClass.Verbose) DicConsole.VerboseWriteLine("Input file 1 format identified by {0} ({1}).", input1Format.Name, input1Format.Id); else DicConsole.WriteLine("Input file 1 format identified by {0}.", input1Format.Name); @@ -85,10 +132,10 @@ namespace DiscImageChef.Commands if(input2Format == null) { DicConsole.ErrorWriteLine("Input file 2 format not identified, not proceeding with comparison."); - return; + return 4; } - if(options.Verbose) + if(MainClass.Verbose) DicConsole.VerboseWriteLine("Input file 2 format identified by {0} ({1}).", input2Format.Name, input2Format.Id); else DicConsole.WriteLine("Input file 2 format identified by {0}.", input2Format.Name); @@ -96,32 +143,32 @@ namespace DiscImageChef.Commands input1Format.Open(inputFilter1); input2Format.Open(inputFilter2); - Core.Statistics.AddMediaFormat(input1Format.Format); - Core.Statistics.AddMediaFormat(input2Format.Format); - Core.Statistics.AddMedia(input1Format.Info.MediaType, false); - Core.Statistics.AddMedia(input2Format.Info.MediaType, false); - Core.Statistics.AddFilter(inputFilter1.Name); - Core.Statistics.AddFilter(inputFilter2.Name); + Statistics.AddMediaFormat(input1Format.Format); + Statistics.AddMediaFormat(input2Format.Format); + Statistics.AddMedia(input1Format.Info.MediaType, false); + Statistics.AddMedia(input2Format.Info.MediaType, false); + Statistics.AddFilter(inputFilter1.Name); + Statistics.AddFilter(inputFilter2.Name); StringBuilder sb = new StringBuilder(); - if(options.Verbose) + if(MainClass.Verbose) { sb.AppendLine("\tDisc image 1\tDisc image 2"); sb.AppendLine("================================"); - sb.AppendFormat("File\t{0}\t{1}", options.InputFile1, options.InputFile2).AppendLine(); + sb.AppendFormat("File\t{0}\t{1}", InputFile1, InputFile2).AppendLine(); sb.AppendFormat("Disc image format\t{0}\t{1}", input1Format.Name, input2Format.Name).AppendLine(); } else { - sb.AppendFormat("Disc image 1: {0}", options.InputFile1).AppendLine(); - sb.AppendFormat("Disc image 2: {0}", options.InputFile2).AppendLine(); + sb.AppendFormat("Disc image 1: {0}", InputFile1).AppendLine(); + sb.AppendFormat("Disc image 2: {0}", InputFile2).AppendLine(); } bool imagesDiffer = false; - CommonTypes.Structs.ImageInfo image1Info = new CommonTypes.Structs.ImageInfo(); - CommonTypes.Structs.ImageInfo image2Info = new CommonTypes.Structs.ImageInfo(); + ImageInfo image1Info = new ImageInfo(); + ImageInfo image2Info = new ImageInfo(); List image1Sessions = new List(); List image2Sessions = new List(); Dictionary image1DiskTags = new Dictionary(); @@ -221,7 +268,7 @@ namespace DiscImageChef.Commands #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body } - if(options.Verbose) + if(MainClass.Verbose) { sb.AppendFormat("Has partitions?\t{0}\t{1}", image1Info.HasPartitions, image2Info.HasPartitions) .AppendLine(); @@ -272,31 +319,31 @@ namespace DiscImageChef.Commands if(image1Info.HasPartitions != image2Info.HasPartitions) { imagesDiffer = true; - if(!options.Verbose) sb.AppendLine("Image partitioned status differ"); + if(!MainClass.Verbose) sb.AppendLine("Image partitioned status differ"); } if(image1Info.HasSessions != image2Info.HasSessions) { imagesDiffer = true; - if(!options.Verbose) sb.AppendLine("Image session status differ"); + if(!MainClass.Verbose) sb.AppendLine("Image session status differ"); } if(image1Info.Sectors != image2Info.Sectors) { imagesDiffer = true; - if(!options.Verbose) sb.AppendLine("Image sectors differ"); + if(!MainClass.Verbose) sb.AppendLine("Image sectors differ"); } if(image1Info.SectorSize != image2Info.SectorSize) { imagesDiffer = true; - if(!options.Verbose) sb.AppendLine("Image sector size differ"); + if(!MainClass.Verbose) sb.AppendLine("Image sector size differ"); } if(image1Info.MediaType != image2Info.MediaType) { imagesDiffer = true; - if(!options.Verbose) sb.AppendLine("Disk type differ"); + if(!MainClass.Verbose) sb.AppendLine("Disk type differ"); } ulong leastSectors; @@ -304,13 +351,13 @@ namespace DiscImageChef.Commands { imagesDiffer = true; leastSectors = image1Info.Sectors; - if(!options.Verbose) sb.AppendLine("Image 2 has more sectors"); + if(!MainClass.Verbose) sb.AppendLine("Image 2 has more sectors"); } else if(image1Info.Sectors > image2Info.Sectors) { imagesDiffer = true; leastSectors = image2Info.Sectors; - if(!options.Verbose) sb.AppendLine("Image 1 has more sectors"); + if(!MainClass.Verbose) sb.AppendLine("Image 1 has more sectors"); } else leastSectors = image1Info.Sectors; @@ -351,7 +398,8 @@ namespace DiscImageChef.Commands DicConsole.WriteLine(sb.ToString()); - Core.Statistics.AddCommand("compare"); + Statistics.AddCommand("compare"); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/Configure.cs b/DiscImageChef/Commands/Configure.cs index 44c073266..79a36b910 100644 --- a/DiscImageChef/Commands/Configure.cs +++ b/DiscImageChef/Commands/Configure.cs @@ -31,15 +31,59 @@ // ****************************************************************************/ using System; +using System.Collections.Generic; using DiscImageChef.Console; using DiscImageChef.Settings; +using Mono.Options; namespace DiscImageChef.Commands { - static class Configure + class ConfigureCommand : Command { - internal static void DoConfigure(bool gdprChange) + readonly bool gdprChange; + bool showHelp; + + public ConfigureCommand(bool gdprChange) : base("configure", "Configures user settings and statistics.") { + this.gdprChange = gdprChange; + 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 arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count != 0) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count == 0) + { + DicConsole.ErrorWriteLine("Missing input image."); + return 1; + } + if(gdprChange) { DicConsole.WriteLine("In compliance with the European Union General Data Protection Regulation 2016/679 (GDPR),\n" + @@ -228,6 +272,7 @@ namespace DiscImageChef.Commands Settings.Settings.Current.GdprCompliance = DicSettings.GdprLevel; Settings.Settings.SaveSettings(); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/ConvertImage.cs b/DiscImageChef/Commands/ConvertImage.cs index b24a4c243..585b54f6f 100644 --- a/DiscImageChef/Commands/ConvertImage.cs +++ b/DiscImageChef/Commands/ConvertImage.cs @@ -42,107 +42,234 @@ using DiscImageChef.CommonTypes.Metadata; using DiscImageChef.CommonTypes.Structs; using DiscImageChef.Console; using DiscImageChef.Core; +using Mono.Options; using Schemas; +using ImageInfo = DiscImageChef.CommonTypes.Structs.ImageInfo; using Version = DiscImageChef.CommonTypes.Interop.Version; namespace DiscImageChef.Commands { - public static class ConvertImage + class ConvertImageCommand : Command { - public static void DoConvert(ConvertImageOptions options) - { - DicConsole.DebugWriteLine("Analyze command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Analyze command", "--verbose={0}", options.Verbose); - DicConsole.DebugWriteLine("Analyze command", "--input={0}", options.InputFile); - DicConsole.DebugWriteLine("Analyze command", "--output={0}", options.OutputFile); - DicConsole.DebugWriteLine("Analyze command", "--format={0}", options.OutputFormat); - DicConsole.DebugWriteLine("Analyze command", "--count={0}", options.Count); - DicConsole.DebugWriteLine("Analyze command", "--force={0}", options.Force); - DicConsole.DebugWriteLine("Analyze command", "--creator={0}", options.Creator); - DicConsole.DebugWriteLine("Analyze command", "--media-title={0}", options.MediaTitle); - DicConsole.DebugWriteLine("Analyze command", "--comments={0}", options.Comments); - DicConsole.DebugWriteLine("Analyze command", "--media-manufacturer={0}", options.MediaManufacturer); - DicConsole.DebugWriteLine("Analyze command", "--media-model={0}", options.MediaModel); - DicConsole.DebugWriteLine("Analyze command", "--media-serial={0}", options.MediaSerialNumber); - DicConsole.DebugWriteLine("Analyze command", "--media-barcode={0}", options.MediaBarcode); - DicConsole.DebugWriteLine("Analyze command", "--media-partnumber={0}", options.MediaPartNumber); - DicConsole.DebugWriteLine("Analyze command", "--media-sequence={0}", options.MediaSequence); - DicConsole.DebugWriteLine("Analyze command", "--media-lastsequence={0}", options.LastMediaSequence); - DicConsole.DebugWriteLine("Analyze command", "--drive-manufacturer={0}", options.DriveManufacturer); - DicConsole.DebugWriteLine("Analyze command", "--drive-model={0}", options.DriveModel); - DicConsole.DebugWriteLine("Analyze command", "--drive-serial={0}", options.DriveSerialNumber); - DicConsole.DebugWriteLine("Analyze command", "--drive-revision={0}", options.DriveFirmwareRevision); - DicConsole.DebugWriteLine("Analyze command", "--cicm-xml={0}", options.CicmXml); - DicConsole.DebugWriteLine("Analyze command", "--resume-file={0}", options.ResumeFile); - DicConsole.DebugWriteLine("Analyze command", "--options={0}", options.Options); + 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; - Dictionary parsedOptions = Options.Parse(options.Options); + public ConvertImageCommand() : base("convert-image", "Converts one image to another format.") + { + Options = new OptionSet + { + $"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", + $"{MainClass.AssemblyCopyright}", + "", + $"usage: DiscImageChef {Name} [OPTIONS] inputimage outputimage", + "", + 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=", + "Manufacturer of the drive used to read the media represented by the image.", + s => driveManufacturer = s + }, + { + "drive-model=", "Model of the drive used to read the media represented by the image.", + s => driveModel = s + }, + { + "drive-revision=", + "Firmware revision of the drive used to read the media represented by the image.", + s => driveFirmwareRevision = s + }, + { + "drive-serial=", "Serial number of the drive used to read the media represented by the image.", + s => driveSerialNumber = s + }, + { + "force|f", "Continue conversion even if sector or media tags will be lost in the process.", + b => force = b != null + }, + { + "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.", + s => wantedOutputFormat = s + }, + {"media-barcode=", "Barcode of the media represented by the image.", s => mediaBarcode = s}, + { + "media-lastsequence=", + "Last media of the sequence the media represented by the image corresponds to.", + (int i) => lastMediaSequence = i + }, + { + "media-manufacturer=", "Manufacturer of the media represented by the image.", + s => mediaManufacturer = s + }, + {"media-model=", "Model of the media represented by the image.", s => mediaModel = s}, + { + "media-partnumber=", "Part number of the media represented by the image.", + s => mediaPartNumber = s + }, + { + "media-sequence=", "Number in sequence for the media represented by the image.", + (int i) => mediaSequence = i + }, + { + "media-serial=", "Serial number of the media represented by the image.", + 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 arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 2) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count <= 1) + { + DicConsole.ErrorWriteLine("Missing input image."); + return 1; + } + + 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-model={0}", driveModel); + DicConsole.DebugWriteLine("Analyze command", "--drive-revision={0}", driveFirmwareRevision); + DicConsole.DebugWriteLine("Analyze command", "--drive-serial={0}", driveSerialNumber); + DicConsole.DebugWriteLine("Analyze command", "--force={0}", force); + DicConsole.DebugWriteLine("Analyze command", "--format={0}", wantedOutputFormat); + DicConsole.DebugWriteLine("Analyze command", "--input={0}", inputFile); + DicConsole.DebugWriteLine("Analyze command", "--media-barcode={0}", mediaBarcode); + DicConsole.DebugWriteLine("Analyze command", "--media-lastsequence={0}", lastMediaSequence); + DicConsole.DebugWriteLine("Analyze command", "--media-manufacturer={0}", mediaManufacturer); + DicConsole.DebugWriteLine("Analyze command", "--media-model={0}", mediaModel); + DicConsole.DebugWriteLine("Analyze command", "--media-partnumber={0}", mediaPartNumber); + DicConsole.DebugWriteLine("Analyze command", "--media-sequence={0}", mediaSequence); + DicConsole.DebugWriteLine("Analyze command", "--media-serial={0}", mediaSerialNumber); + DicConsole.DebugWriteLine("Analyze command", "--media-title={0}", mediaTitle); + DicConsole.DebugWriteLine("Analyze command", "--options={0}", outputOptions); + DicConsole.DebugWriteLine("Analyze command", "--output={0}", outputFile); + DicConsole.DebugWriteLine("Analyze command", "--resume-file={0}", resumeFile); + DicConsole.DebugWriteLine("Analyze command", "--verbose={0}", MainClass.Verbose); + + Dictionary parsedOptions = Core.Options.Parse(outputOptions); DicConsole.DebugWriteLine("Analyze command", "Parsed options:"); foreach(KeyValuePair parsedOption in parsedOptions) DicConsole.DebugWriteLine("Analyze command", "{0} = {1}", parsedOption.Key, parsedOption.Value); - if(options.Count == 0) + if(count == 0) { DicConsole.ErrorWriteLine("Need to specify more than 0 sectors to copy at once"); - return; + return 1; } Resume resume = null; CICMMetadataType sidecar = null; XmlSerializer xs = new XmlSerializer(typeof(CICMMetadataType)); - if(options.CicmXml != null) - if(File.Exists(options.CicmXml)) + if(cicmXml != null) + if(File.Exists(cicmXml)) try { - StreamReader sr = new StreamReader(options.CicmXml); + StreamReader sr = new StreamReader(cicmXml); sidecar = (CICMMetadataType)xs.Deserialize(sr); sr.Close(); } catch { DicConsole.ErrorWriteLine("Incorrect metadata sidecar file, not continuing..."); - return; + return 2; } else { DicConsole.ErrorWriteLine("Could not find metadata sidecar, not continuing..."); - return; + return 3; } xs = new XmlSerializer(typeof(Resume)); - if(options.ResumeFile != null) - if(File.Exists(options.ResumeFile)) + if(resumeFile != null) + if(File.Exists(resumeFile)) try { - StreamReader sr = new StreamReader(options.ResumeFile); + StreamReader sr = new StreamReader(resumeFile); resume = (Resume)xs.Deserialize(sr); sr.Close(); } catch { DicConsole.ErrorWriteLine("Incorrect resume file, not continuing..."); - return; + return 4; } else { DicConsole.ErrorWriteLine("Could not find resume file, not continuing..."); - return; + return 5; } FiltersList filtersList = new FiltersList(); - IFilter inputFilter = filtersList.GetFilter(options.InputFile); + IFilter inputFilter = filtersList.GetFilter(inputFile); if(inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); - return; + return 6; } - if(File.Exists(options.OutputFile)) + if(File.Exists(outputFile)) { DicConsole.ErrorWriteLine("Output file already exists, not continuing."); - return; + return 8; } PluginBase plugins = GetPluginBase.Instance; @@ -151,10 +278,10 @@ namespace DiscImageChef.Commands if(inputFormat == null) { DicConsole.WriteLine("Input image format not identified, not proceeding with conversion."); - return; + return 7; } - if(options.Verbose) + if(MainClass.Verbose) DicConsole.VerboseWriteLine("Input image format identified by {0} ({1}).", inputFormat.Name, inputFormat.Id); else DicConsole.WriteLine("Input image format identified by {0}.", inputFormat.Name); @@ -165,7 +292,7 @@ namespace DiscImageChef.Commands { DicConsole.WriteLine("Unable to open image format"); DicConsole.WriteLine("No error given"); - return; + return 9; } DicConsole.DebugWriteLine("Convert-image command", "Correctly opened image file."); @@ -175,66 +302,65 @@ namespace DiscImageChef.Commands DicConsole.DebugWriteLine("Convert-image command", "Image identifies media type as {0}.", inputFormat.Info.MediaType); - Core.Statistics.AddMediaFormat(inputFormat.Format); - Core.Statistics.AddMedia(inputFormat.Info.MediaType, false); - Core.Statistics.AddFilter(inputFilter.Name); + Statistics.AddMediaFormat(inputFormat.Format); + Statistics.AddMedia(inputFormat.Info.MediaType, false); + Statistics.AddFilter(inputFilter.Name); } catch(Exception ex) { DicConsole.ErrorWriteLine("Unable to open image format"); DicConsole.ErrorWriteLine("Error: {0}", ex.Message); DicConsole.DebugWriteLine("Convert-image command", "Stack trace: {0}", ex.StackTrace); - return; + return 10; } List candidates = new List(); // Try extension - if(string.IsNullOrEmpty(options.OutputFormat)) + if(string.IsNullOrEmpty(wantedOutputFormat)) candidates.AddRange(plugins.WritableImages.Values.Where(t => t.KnownExtensions - .Contains(Path.GetExtension(options - .OutputFile)))); + .Contains(Path.GetExtension(outputFile)))); // Try Id - else if(Guid.TryParse(options.OutputFormat, out Guid outId)) + else if(Guid.TryParse(wantedOutputFormat, out Guid outId)) candidates.AddRange(plugins.WritableImages.Values.Where(t => t.Id.Equals(outId))); // Try name else - candidates.AddRange(plugins.WritableImages.Values.Where(t => string.Equals(t.Name, options.OutputFormat, + candidates.AddRange(plugins.WritableImages.Values.Where(t => string.Equals(t.Name, wantedOutputFormat, StringComparison .InvariantCultureIgnoreCase))); if(candidates.Count == 0) { DicConsole.WriteLine("No plugin supports requested extension."); - return; + return 11; } if(candidates.Count > 1) { DicConsole.WriteLine("More than one plugin supports requested extension."); - return; + return 12; } IWritableImage outputFormat = candidates[0]; - if(options.Verbose) + if(MainClass.Verbose) DicConsole.VerboseWriteLine("Output image format: {0} ({1}).", outputFormat.Name, outputFormat.Id); else DicConsole.WriteLine("Output image format: {0}.", outputFormat.Name); if(!outputFormat.SupportedMediaTypes.Contains(inputFormat.Info.MediaType)) { DicConsole.ErrorWriteLine("Output format does not support media type, cannot continue..."); - return; + return 13; } foreach(MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags) { - if(outputFormat.SupportedMediaTags.Contains(mediaTag) || options.Force) continue; + if(outputFormat.SupportedMediaTags.Contains(mediaTag) || force) continue; DicConsole.ErrorWriteLine("Converting image will lose media tag {0}, not continuing...", mediaTag); DicConsole.ErrorWriteLine("If you don't care, use force option."); - return; + return 14; } bool useLong = inputFormat.Info.ReadableSectorTags.Count != 0; @@ -243,7 +369,7 @@ namespace DiscImageChef.Commands { if(outputFormat.SupportedSectorTags.Contains(sectorTag)) continue; - if(options.Force) + if(force) { if(sectorTag != SectorTagType.CdTrackFlags && sectorTag != SectorTagType.CdTrackIsrc && sectorTag != SectorTagType.CdSectorSubchannel) useLong = false; @@ -253,44 +379,43 @@ namespace DiscImageChef.Commands 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."); - return; + return 15; } - if(!outputFormat.Create(options.OutputFile, inputFormat.Info.MediaType, parsedOptions, - inputFormat.Info.Sectors, inputFormat.Info.SectorSize)) + if(!outputFormat.Create(outputFile, inputFormat.Info.MediaType, parsedOptions, inputFormat.Info.Sectors, + inputFormat.Info.SectorSize)) { DicConsole.ErrorWriteLine("Error {0} creating output image.", outputFormat.ErrorMessage); - return; + return 16; } - CommonTypes.Structs.ImageInfo metadata = new CommonTypes.Structs.ImageInfo + ImageInfo metadata = new ImageInfo { Application = "DiscImageChef", ApplicationVersion = Version.GetVersion(), - Comments = options.Comments ?? inputFormat.Info.Comments, - Creator = options.Creator ?? inputFormat.Info.Creator, - DriveFirmwareRevision = options.DriveFirmwareRevision ?? inputFormat.Info.DriveFirmwareRevision, - DriveManufacturer = options.DriveManufacturer ?? inputFormat.Info.DriveManufacturer, - DriveModel = options.DriveModel ?? inputFormat.Info.DriveModel, - DriveSerialNumber = options.DriveSerialNumber ?? inputFormat.Info.DriveSerialNumber, - LastMediaSequence = - options.LastMediaSequence != 0 ? options.LastMediaSequence : inputFormat.Info.LastMediaSequence, - MediaBarcode = options.MediaBarcode ?? inputFormat.Info.MediaBarcode, - MediaManufacturer = options.MediaManufacturer ?? inputFormat.Info.MediaManufacturer, - MediaModel = options.MediaModel ?? inputFormat.Info.MediaModel, - MediaPartNumber = options.MediaPartNumber ?? inputFormat.Info.MediaPartNumber, - MediaSequence = options.MediaSequence != 0 ? options.MediaSequence : inputFormat.Info.MediaSequence, - MediaSerialNumber = options.MediaSerialNumber ?? inputFormat.Info.MediaSerialNumber, - MediaTitle = options.MediaTitle ?? inputFormat.Info.MediaTitle + Comments = comments ?? inputFormat.Info.Comments, + Creator = creator ?? inputFormat.Info.Creator, + DriveFirmwareRevision = driveFirmwareRevision ?? inputFormat.Info.DriveFirmwareRevision, + DriveManufacturer = driveManufacturer ?? inputFormat.Info.DriveManufacturer, + DriveModel = driveModel ?? inputFormat.Info.DriveModel, + DriveSerialNumber = driveSerialNumber ?? inputFormat.Info.DriveSerialNumber, + LastMediaSequence = lastMediaSequence != 0 ? lastMediaSequence : inputFormat.Info.LastMediaSequence, + MediaBarcode = mediaBarcode ?? inputFormat.Info.MediaBarcode, + MediaManufacturer = mediaManufacturer ?? inputFormat.Info.MediaManufacturer, + MediaModel = mediaModel ?? inputFormat.Info.MediaModel, + MediaPartNumber = mediaPartNumber ?? inputFormat.Info.MediaPartNumber, + MediaSequence = mediaSequence != 0 ? mediaSequence : inputFormat.Info.MediaSequence, + MediaSerialNumber = mediaSerialNumber ?? inputFormat.Info.MediaSerialNumber, + MediaTitle = mediaTitle ?? inputFormat.Info.MediaTitle }; if(!outputFormat.SetMetadata(metadata)) { DicConsole.ErrorWrite("Error {0} setting metadata, ", outputFormat.ErrorMessage); - if(!options.Force) + if(!force) { DicConsole.ErrorWriteLine("not continuing..."); - return; + return 17; } DicConsole.ErrorWriteLine("continuing..."); @@ -309,24 +434,24 @@ namespace DiscImageChef.Commands { DicConsole.ErrorWriteLine("Error {0} sending tracks list to output image.", outputFormat.ErrorMessage); - return; + return 18; } foreach(MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags) { - if(options.Force && !outputFormat.SupportedMediaTags.Contains(mediaTag)) continue; + if(force && !outputFormat.SupportedMediaTags.Contains(mediaTag)) continue; DicConsole.WriteLine("Converting media tag {0}", mediaTag); byte[] tag = inputFormat.ReadDiskTag(mediaTag); if(outputFormat.WriteMediaTag(tag, mediaTag)) continue; - if(options.Force) + if(force) DicConsole.ErrorWriteLine("Error {0} writing media tag, continuing...", outputFormat.ErrorMessage); else { DicConsole.ErrorWriteLine("Error {0} writing media tag, not continuing...", outputFormat.ErrorMessage); - return; + return 19; } } @@ -348,9 +473,10 @@ namespace DiscImageChef.Commands byte[] sector; uint sectorsToDo; - if(inputFormat.Info.Sectors - doneSectors >= (ulong)options.Count) - sectorsToDo = (uint)options.Count; - else sectorsToDo = (uint)(inputFormat.Info.Sectors - doneSectors); + if(inputFormat.Info.Sectors - doneSectors >= (ulong)count) sectorsToDo = (uint)count; + else + sectorsToDo = + (uint)(inputFormat.Info.Sectors - doneSectors); DicConsole.Write("\rConverting sectors {0} to {1} ({2:P2} done)", doneSectors, doneSectors + sectorsToDo, doneSectors / (double)inputFormat.Info.Sectors); @@ -382,14 +508,14 @@ namespace DiscImageChef.Commands } if(!result) - if(options.Force) + if(force) DicConsole.ErrorWriteLine("Error {0} writing sector {1}, continuing...", outputFormat.ErrorMessage, doneSectors); else { DicConsole.ErrorWriteLine("Error {0} writing sector {1}, not continuing...", outputFormat.ErrorMessage, doneSectors); - return; + return 20; } doneSectors += sectorsToDo; @@ -417,7 +543,7 @@ namespace DiscImageChef.Commands continue; } - if(options.Force && !outputFormat.SupportedSectorTags.Contains(tag)) continue; + if(force && !outputFormat.SupportedSectorTags.Contains(tag)) continue; doneSectors = 0; while(doneSectors < inputFormat.Info.Sectors) @@ -425,9 +551,10 @@ namespace DiscImageChef.Commands byte[] sector; uint sectorsToDo; - if(inputFormat.Info.Sectors - doneSectors >= (ulong)options.Count) - sectorsToDo = (uint)options.Count; - else sectorsToDo = (uint)(inputFormat.Info.Sectors - doneSectors); + if(inputFormat.Info.Sectors - doneSectors >= (ulong)count) sectorsToDo = (uint)count; + else + sectorsToDo = + (uint)(inputFormat.Info.Sectors - doneSectors); DicConsole.Write("\rConverting tag {2} for sectors {0} to {1} ({2:P2} done)", doneSectors, doneSectors + sectorsToDo, doneSectors / (double)inputFormat.Info.Sectors, @@ -446,14 +573,14 @@ namespace DiscImageChef.Commands } if(!result) - if(options.Force) + if(force) DicConsole.ErrorWriteLine("Error {0} writing sector {1}, continuing...", outputFormat.ErrorMessage, doneSectors); else { DicConsole.ErrorWriteLine("Error {0} writing sector {1}, not continuing...", outputFormat.ErrorMessage, doneSectors); - return; + return 21; } doneSectors += sectorsToDo; @@ -476,10 +603,8 @@ namespace DiscImageChef.Commands byte[] sector; uint sectorsToDo; - if(trackSectors - doneSectors >= (ulong)options.Count) sectorsToDo = (uint)options.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)", doneSectors + track.TrackStartSector, @@ -516,14 +641,14 @@ namespace DiscImageChef.Commands } if(!result) - if(options.Force) + if(force) DicConsole.ErrorWriteLine("Error {0} writing sector {1}, continuing...", outputFormat.ErrorMessage, doneSectors); else { DicConsole.ErrorWriteLine("Error {0} writing sector {1}, not continuing...", outputFormat.ErrorMessage, doneSectors); - return; + return 22; } doneSectors += sectorsToDo; @@ -552,7 +677,7 @@ namespace DiscImageChef.Commands continue; } - if(options.Force && !outputFormat.SupportedSectorTags.Contains(tag)) continue; + if(force && !outputFormat.SupportedSectorTags.Contains(tag)) continue; foreach(Track track in tracks) { @@ -570,14 +695,14 @@ namespace DiscImageChef.Commands sector = inputFormat.ReadSectorTag(track.TrackStartSector, tag); result = outputFormat.WriteSectorTag(sector, track.TrackStartSector, tag); if(!result) - if(options.Force) + if(force) DicConsole.ErrorWriteLine("Error {0} writing tag, continuing...", outputFormat.ErrorMessage); else { DicConsole.ErrorWriteLine("Error {0} writing tag, not continuing...", outputFormat.ErrorMessage); - return; + return 23; } continue; @@ -586,7 +711,7 @@ namespace DiscImageChef.Commands while(doneSectors < trackSectors) { uint sectorsToDo; - if(trackSectors - doneSectors >= (ulong)options.Count) sectorsToDo = (uint)options.Count; + if(trackSectors - doneSectors >= (ulong)count) sectorsToDo = (uint)count; else sectorsToDo = (uint)(trackSectors - doneSectors); @@ -611,14 +736,14 @@ namespace DiscImageChef.Commands } if(!result) - if(options.Force) + if(force) DicConsole.ErrorWriteLine("Error {0} writing tag for sector {1}, continuing...", outputFormat.ErrorMessage, doneSectors); else { DicConsole.ErrorWriteLine("Error {0} writing tag for sector {1}, not continuing...", outputFormat.ErrorMessage, doneSectors); - return; + return 24; } doneSectors += sectorsToDo; @@ -668,7 +793,8 @@ namespace DiscImageChef.Commands DicConsole.WriteLine(); DicConsole.WriteLine("Conversion done."); - Core.Statistics.AddCommand("convert-image"); + Statistics.AddCommand("convert-image"); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/CreateSidecar.cs b/DiscImageChef/Commands/CreateSidecar.cs index 5b51a599d..cdb84bcd5 100644 --- a/DiscImageChef/Commands/CreateSidecar.cs +++ b/DiscImageChef/Commands/CreateSidecar.cs @@ -40,14 +40,79 @@ using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.Console; using DiscImageChef.Core; +using Mono.Options; using Schemas; namespace DiscImageChef.Commands { - static class CreateSidecar + class CreateSidecarCommand : Command { - internal static void DoSidecar(CreateSidecarOptions options) + int blockSize; + string encodingName; + string inputFile; + bool showHelp; + bool tape; + + public CreateSidecarCommand() : base("create-sidecar", "Creates CICM Metadata XML sidecar.") { + Options = new OptionSet + { + $"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", + $"{MainClass.AssemblyCopyright}", + "", + $"usage: DiscImageChef {Name} [OPTIONS] input", + "", + Help, + { + "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.", + (int i) => blockSize = i + }, + {"encoding|e=", "Name of character encoding to use.", s => encodingName = s}, + { + "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).", + b => tape = b != null + }, + {"help|h|?", "Show this message and exit.", v => showHelp = v != null} + }; + } + + public override int Invoke(IEnumerable arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 1) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count == 0) + { + DicConsole.ErrorWriteLine("Missing input image."); + return 1; + } + + inputFile = extra[0]; + + DicConsole.DebugWriteLine("Create sidecar command", "--block-size={0}", blockSize); + DicConsole.DebugWriteLine("Create sidecar command", "--debug={0}", MainClass.Debug); + DicConsole.DebugWriteLine("Create sidecar command", "--encoding={0}", encodingName); + DicConsole.DebugWriteLine("Create sidecar command", "--input={0}", inputFile); + DicConsole.DebugWriteLine("Create sidecar command", "--tape={0}", tape); + DicConsole.DebugWriteLine("Create sidecar command", "--verbose={0}", MainClass.Verbose); + Sidecar.InitProgressEvent += Progress.InitProgress; Sidecar.UpdateProgressEvent += Progress.UpdateProgress; Sidecar.EndProgressEvent += Progress.EndProgress; @@ -58,33 +123,33 @@ namespace DiscImageChef.Commands Encoding encoding = null; - if(options.EncodingName != null) + if(encodingName != null) try { - encoding = Claunia.Encoding.Encoding.GetEncoding(options.EncodingName); - if(options.Verbose) DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName); + encoding = Claunia.Encoding.Encoding.GetEncoding(encodingName); + if(MainClass.Verbose) DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName); } catch(ArgumentException) { DicConsole.ErrorWriteLine("Specified encoding is not supported."); - return; + return 1; } - if(File.Exists(options.InputFile)) + if(File.Exists(inputFile)) { - if(options.Tape) + if(tape) { DicConsole.ErrorWriteLine("You cannot use --tape option when input is a file."); - return; + return 2; } FiltersList filtersList = new FiltersList(); - IFilter inputFilter = filtersList.GetFilter(options.InputFile); + IFilter inputFilter = filtersList.GetFilter(inputFile); if(inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); - return; + return 3; } try @@ -94,10 +159,10 @@ namespace DiscImageChef.Commands if(imageFormat == null) { DicConsole.WriteLine("Image format not identified, not proceeding with analysis."); - return; + return 4; } - if(options.Verbose) + if(MainClass.Verbose) DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name, imageFormat.Id); else DicConsole.WriteLine("Image format identified by {0}.", imageFormat.Name); @@ -108,7 +173,7 @@ namespace DiscImageChef.Commands { DicConsole.WriteLine("Unable to open image format"); DicConsole.WriteLine("No error given"); - return; + return 5; } DicConsole.DebugWriteLine("Analyze command", "Correctly opened image file."); @@ -117,26 +182,26 @@ namespace DiscImageChef.Commands { DicConsole.ErrorWriteLine("Unable to open image format"); DicConsole.ErrorWriteLine("Error: {0}", ex.Message); - return; + return 6; } - Core.Statistics.AddMediaFormat(imageFormat.Format); - Core.Statistics.AddFilter(inputFilter.Name); + Statistics.AddMediaFormat(imageFormat.Format); + Statistics.AddFilter(inputFilter.Name); - CICMMetadataType sidecar = Sidecar.Create(imageFormat, options.InputFile, inputFilter.Id, encoding); + CICMMetadataType sidecar = Sidecar.Create(imageFormat, inputFile, inputFilter.Id, encoding); DicConsole.WriteLine("Writing metadata sidecar"); FileStream xmlFs = new - FileStream(Path.Combine(Path.GetDirectoryName(options.InputFile) ?? throw new InvalidOperationException(), Path.GetFileNameWithoutExtension(options.InputFile) + ".cicm.xml"), + FileStream(Path.Combine(Path.GetDirectoryName(inputFile) ?? throw new InvalidOperationException(), Path.GetFileNameWithoutExtension(inputFile) + ".cicm.xml"), FileMode.CreateNew); XmlSerializer xmlSer = new XmlSerializer(typeof(CICMMetadataType)); xmlSer.Serialize(xmlFs, sidecar); xmlFs.Close(); - Core.Statistics.AddCommand("create-sidecar"); + Statistics.AddCommand("create-sidecar"); } catch(Exception ex) { @@ -144,37 +209,37 @@ namespace DiscImageChef.Commands DicConsole.DebugWriteLine("Analyze command", ex.StackTrace); } } - else if(Directory.Exists(options.InputFile)) + else if(Directory.Exists(inputFile)) { - if(!options.Tape) + if(!tape) { DicConsole.ErrorWriteLine("Cannot create a sidecar from a directory."); - return; + return 7; } - string[] contents = Directory.GetFiles(options.InputFile, "*", SearchOption.TopDirectoryOnly); - List files = contents.Where(file => new FileInfo(file).Length % options.BlockSize == 0) - .ToList(); + string[] contents = Directory.GetFiles(inputFile, "*", SearchOption.TopDirectoryOnly); + List files = contents.Where(file => new FileInfo(file).Length % blockSize == 0).ToList(); files.Sort(StringComparer.CurrentCultureIgnoreCase); - CICMMetadataType sidecar = - Sidecar.Create(Path.GetFileName(options.InputFile), files, options.BlockSize); + CICMMetadataType sidecar = Sidecar.Create(Path.GetFileName(inputFile), files, blockSize); DicConsole.WriteLine("Writing metadata sidecar"); FileStream xmlFs = new - FileStream(Path.Combine(Path.GetDirectoryName(options.InputFile) ?? throw new InvalidOperationException(), Path.GetFileNameWithoutExtension(options.InputFile) + ".cicm.xml"), + FileStream(Path.Combine(Path.GetDirectoryName(inputFile) ?? throw new InvalidOperationException(), Path.GetFileNameWithoutExtension(inputFile) + ".cicm.xml"), FileMode.CreateNew); XmlSerializer xmlSer = new XmlSerializer(typeof(CICMMetadataType)); xmlSer.Serialize(xmlFs, sidecar); xmlFs.Close(); - Core.Statistics.AddCommand("create-sidecar"); + Statistics.AddCommand("create-sidecar"); } else DicConsole.ErrorWriteLine("The specified input file cannot be found."); + + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/Decode.cs b/DiscImageChef/Commands/Decode.cs index c819063d1..79e432755 100644 --- a/DiscImageChef/Commands/Decode.cs +++ b/DiscImageChef/Commands/Decode.cs @@ -30,6 +30,7 @@ // Copyright © 2011-2019 Natalia Portillo // ****************************************************************************/ +using System.Collections.Generic; using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Interfaces; @@ -38,28 +39,80 @@ using DiscImageChef.Core; using DiscImageChef.Decoders.ATA; using DiscImageChef.Decoders.CD; using DiscImageChef.Decoders.SCSI; +using Mono.Options; namespace DiscImageChef.Commands { - static class Decode + class DecodeCommand : Command { - internal static void DoDecode(DecodeOptions options) + 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.") { - DicConsole.DebugWriteLine("Decode command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Decode command", "--verbose={0}", options.Verbose); - DicConsole.DebugWriteLine("Decode command", "--input={0}", options.InputFile); - DicConsole.DebugWriteLine("Decode command", "--start={0}", options.StartSector); - DicConsole.DebugWriteLine("Decode command", "--length={0}", options.Length); - DicConsole.DebugWriteLine("Decode command", "--disk-tags={0}", options.DiskTags); - DicConsole.DebugWriteLine("Decode command", "--sector-tags={0}", options.SectorTags); + Options = new OptionSet + { + $"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", + $"{MainClass.AssemblyCopyright}", + "", + $"usage: DiscImageChef {Name} [OPTIONS] imagefile", + "", + 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 arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 1) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count == 0) + { + DicConsole.ErrorWriteLine("Missing input image."); + return 1; + } + + 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", "--start={0}", startSector); + DicConsole.DebugWriteLine("Decode command", "--verbose={0}", MainClass.Verbose); FiltersList filtersList = new FiltersList(); - IFilter inputFilter = filtersList.GetFilter(options.InputFile); + IFilter inputFilter = filtersList.GetFilter(inputFile); if(inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); - return; + return 1; } IMediaImage inputFormat = ImageFormat.Detect(inputFilter); @@ -67,15 +120,15 @@ namespace DiscImageChef.Commands if(inputFormat == null) { DicConsole.ErrorWriteLine("Unable to recognize image format, not decoding"); - return; + return 2; } inputFormat.Open(inputFilter); - Core.Statistics.AddMediaFormat(inputFormat.Format); - Core.Statistics.AddMedia(inputFormat.Info.MediaType, false); - Core.Statistics.AddFilter(inputFilter.Name); + Statistics.AddMediaFormat(inputFormat.Format); + Statistics.AddMedia(inputFormat.Info.MediaType, false); + Statistics.AddFilter(inputFilter.Name); - if(options.DiskTags) + if(diskTags) if(inputFormat.Info.ReadableMediaTags.Count == 0) DicConsole.WriteLine("There are no disk tags in chosen disc image."); else @@ -237,16 +290,16 @@ namespace DiscImageChef.Commands break; } - if(options.SectorTags) + if(sectorTags) { - if(options.Length.ToLowerInvariant() == "all") { } + if(length.ToLowerInvariant() == "all") { } else { - if(!ulong.TryParse(options.Length, out ulong _)) + if(!ulong.TryParse(length, out ulong _)) { - DicConsole.WriteLine("Value \"{0}\" is not a valid number for length.", options.Length); + DicConsole.WriteLine("Value \"{0}\" is not a valid number for length.", length); DicConsole.WriteLine("Not decoding sectors tags"); - return; + return 3; } } @@ -265,7 +318,8 @@ namespace DiscImageChef.Commands // TODO: Not implemented } - Core.Statistics.AddCommand("decode"); + Statistics.AddCommand("decode"); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/DeviceInfo.cs b/DiscImageChef/Commands/DeviceInfo.cs index b7d570e1e..c16fd63da 100644 --- a/DiscImageChef/Commands/DeviceInfo.cs +++ b/DiscImageChef/Commands/DeviceInfo.cs @@ -40,31 +40,78 @@ using DiscImageChef.Decoders.SCSI; using DiscImageChef.Decoders.SCSI.MMC; using DiscImageChef.Decoders.SCSI.SSC; using DiscImageChef.Devices; +using Mono.Options; +using DeviceInfo = DiscImageChef.Core.Devices.Info.DeviceInfo; namespace DiscImageChef.Commands { - static class DeviceInfo + class DeviceInfoCommand : Command { - internal static void DoDeviceInfo(DeviceInfoOptions options) + string devicePath; + string outputPrefix; + + bool showHelp; + + public DeviceInfoCommand() : base("device-info", "Gets information about a device.") { - DicConsole.DebugWriteLine("Device-Info command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Device-Info command", "--verbose={0}", options.Verbose); - DicConsole.DebugWriteLine("Device-Info command", "--device={0}", options.DevicePath); - DicConsole.DebugWriteLine("Device-Info command", "--output-prefix={0}", options.OutputPrefix); + Options = new OptionSet + { + $"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", + $"{MainClass.AssemblyCopyright}", + "", + $"usage: DiscImageChef {Name} [OPTIONS] devicepath", + "", + Help, + {"output-prefix|w=", "Name of character encoding to use.", s => outputPrefix = s}, + {"help|h|?", "Show this message and exit.", v => showHelp = v != null} + }; + } - if(options.DevicePath.Length == 2 && options.DevicePath[1] == ':' && options.DevicePath[0] != '/' && - char.IsLetter(options.DevicePath[0])) - options.DevicePath = "\\\\.\\" + char.ToUpper(options.DevicePath[0]) + ':'; + public override int Invoke(IEnumerable arguments) + { + List extra = Options.Parse(arguments); - Device dev = new Device(options.DevicePath); + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 1) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count == 0) + { + DicConsole.ErrorWriteLine("Missing device path."); + return 1; + } + + 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", "--output-prefix={0}", outputPrefix); + DicConsole.DebugWriteLine("Device-Info command", "--verbose={0}", MainClass.Verbose); + + if(devicePath.Length == 2 && devicePath[1] == ':' && devicePath[0] != '/' && char.IsLetter(devicePath[0])) + devicePath = "\\\\.\\" + char.ToUpper(devicePath[0]) + ':'; + + Device dev = new Device(devicePath); if(dev.Error) { DicConsole.ErrorWriteLine("Error {0} opening device.", dev.LastError); - return; + return 1; } - Core.Statistics.AddDevice(dev); + Statistics.AddDevice(dev); if(dev.IsUsb) { @@ -156,11 +203,11 @@ namespace DiscImageChef.Commands else DicConsole.DebugWriteLine("Device-Info command", "Could not get tuples"); } - Core.Devices.Info.DeviceInfo devInfo = new Core.Devices.Info.DeviceInfo(dev); + DeviceInfo devInfo = new DeviceInfo(dev); if(devInfo.AtaIdentify != null) { - DataFile.WriteTo("Device-Info command", options.OutputPrefix, "_ata_identify.bin", "ATA IDENTIFY", + DataFile.WriteTo("Device-Info command", outputPrefix, "_ata_identify.bin", "ATA IDENTIFY", devInfo.AtaIdentify); DicConsole.WriteLine(Identify.Prettify(devInfo.AtaIdentify)); @@ -202,7 +249,7 @@ namespace DiscImageChef.Commands if(devInfo.AtapiIdentify != null) { - DataFile.WriteTo("Device-Info command", options.OutputPrefix, "_atapi_identify.bin", "ATAPI IDENTIFY", + DataFile.WriteTo("Device-Info command", outputPrefix, "_atapi_identify.bin", "ATAPI IDENTIFY", devInfo.AtapiIdentify); DicConsole.WriteLine(Identify.Prettify(devInfo.AtapiIdentify)); @@ -212,7 +259,7 @@ namespace DiscImageChef.Commands { if(dev.Type != DeviceType.ATAPI) DicConsole.WriteLine("SCSI device"); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, "_scsi_inquiry.bin", "SCSI INQUIRY", + DataFile.WriteTo("Device-Info command", outputPrefix, "_scsi_inquiry.bin", "SCSI INQUIRY", devInfo.ScsiInquiryData); DicConsole.WriteLine(Inquiry.Prettify(devInfo.ScsiInquiry)); @@ -223,147 +270,129 @@ namespace DiscImageChef.Commands { DicConsole.WriteLine("ASCII Page {0:X2}h: {1}", page.Key, EVPD.DecodeASCIIPage(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, page.Value); } else if(page.Key == 0x80) { DicConsole.WriteLine("Unit Serial Number: {0}", EVPD.DecodePage80(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if(page.Key == 0x81) { DicConsole.WriteLine("{0}", EVPD.PrettifyPage_81(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if(page.Key == 0x82) { DicConsole.WriteLine("ASCII implemented operating definitions: {0}", EVPD.DecodePage82(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if(page.Key == 0x83) { DicConsole.WriteLine("{0}", EVPD.PrettifyPage_83(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if(page.Key == 0x84) { DicConsole.WriteLine("{0}", EVPD.PrettifyPage_84(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if(page.Key == 0x85) { DicConsole.WriteLine("{0}", EVPD.PrettifyPage_85(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if(page.Key == 0x86) { DicConsole.WriteLine("{0}", EVPD.PrettifyPage_86(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if(page.Key == 0x89) { DicConsole.WriteLine("{0}", EVPD.PrettifyPage_89(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if(page.Key == 0xB0) { DicConsole.WriteLine("{0}", EVPD.PrettifyPage_B0(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if(page.Key == 0xB1) { DicConsole.WriteLine("Manufacturer-assigned Serial Number: {0}", EVPD.DecodePageB1(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if(page.Key == 0xB2) { DicConsole.WriteLine("TapeAlert Supported Flags Bitmap: 0x{0:X16}", EVPD.DecodePageB2(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if(page.Key == 0xB3) { DicConsole.WriteLine("Automation Device Serial Number: {0}", EVPD.DecodePageB3(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if(page.Key == 0xB4) { DicConsole.WriteLine("Data Transfer Device Element Address: 0x{0}", EVPD.DecodePageB4(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if(page.Key == 0xC0 && StringHandlers.CToString(devInfo.ScsiInquiry.Value.VendorIdentification) .ToLowerInvariant().Trim() == "quantum") { DicConsole.WriteLine("{0}", EVPD.PrettifyPage_C0_Quantum(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if(page.Key == 0xC0 && StringHandlers.CToString(devInfo.ScsiInquiry.Value.VendorIdentification) .ToLowerInvariant().Trim() == "seagate") { DicConsole.WriteLine("{0}", EVPD.PrettifyPage_C0_Seagate(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if(page.Key == 0xC0 && StringHandlers.CToString(devInfo.ScsiInquiry.Value.VendorIdentification) .ToLowerInvariant().Trim() == "ibm") { DicConsole.WriteLine("{0}", EVPD.PrettifyPage_C0_IBM(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if(page.Key == 0xC1 && StringHandlers.CToString(devInfo.ScsiInquiry.Value.VendorIdentification) .ToLowerInvariant().Trim() == "ibm") { DicConsole.WriteLine("{0}", EVPD.PrettifyPage_C1_IBM(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if((page.Key == 0xC0 || page.Key == 0xC1) && StringHandlers.CToString(devInfo.ScsiInquiry.Value.VendorIdentification) .ToLowerInvariant().Trim() == "certance") { DicConsole.WriteLine("{0}", EVPD.PrettifyPage_C0_C1_Certance(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if((page.Key == 0xC2 || page.Key == 0xC3 || page.Key == 0xC4 || page.Key == 0xC5 || page.Key == 0xC6) && @@ -371,9 +400,8 @@ namespace DiscImageChef.Commands .ToLowerInvariant().Trim() == "certance") { DicConsole.WriteLine("{0}", EVPD.PrettifyPage_C2_C3_C4_C5_C6_Certance(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if((page.Key == 0xC0 || page.Key == 0xC1 || page.Key == 0xC2 || page.Key == 0xC3 || page.Key == 0xC4 || page.Key == 0xC5) && StringHandlers @@ -382,18 +410,16 @@ namespace DiscImageChef.Commands .ToLowerInvariant().Trim() == "hp") { DicConsole.WriteLine("{0}", EVPD.PrettifyPage_C0_to_C5_HP(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else if(page.Key == 0xDF && StringHandlers.CToString(devInfo.ScsiInquiry.Value.VendorIdentification) .ToLowerInvariant().Trim() == "certance") { DicConsole.WriteLine("{0}", EVPD.PrettifyPage_DF_Certance(page.Value)); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } else { @@ -402,18 +428,17 @@ namespace DiscImageChef.Commands DicConsole.DebugWriteLine("Device-Info command", "Found undecoded SCSI VPD page 0x{0:X2}", page.Key); - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - $"_scsi_evpd_{page.Key:X2}h.bin", $"SCSI INQUIRY EVPD {page.Key:X2}h", - page.Value); + DataFile.WriteTo("Device-Info command", outputPrefix, $"_scsi_evpd_{page.Key:X2}h.bin", + $"SCSI INQUIRY EVPD {page.Key:X2}h", page.Value); } if(devInfo.ScsiModeSense6 != null) - DataFile.WriteTo("Device-Info command", options.OutputPrefix, "_scsi_modesense6.bin", - "SCSI MODE SENSE", devInfo.ScsiModeSense6); + DataFile.WriteTo("Device-Info command", outputPrefix, "_scsi_modesense6.bin", "SCSI MODE SENSE", + devInfo.ScsiModeSense6); if(devInfo.ScsiModeSense10 != null) - DataFile.WriteTo("Device-Info command", options.OutputPrefix, "_scsi_modesense10.bin", - "SCSI MODE SENSE", devInfo.ScsiModeSense10); + DataFile.WriteTo("Device-Info command", outputPrefix, "_scsi_modesense10.bin", "SCSI MODE SENSE", + devInfo.ScsiModeSense10); if(devInfo.ScsiMode.HasValue) PrintScsiModePages.Print(devInfo.ScsiMode.Value, @@ -422,7 +447,7 @@ namespace DiscImageChef.Commands if(devInfo.MmcConfiguration != null) { - DataFile.WriteTo("Device-Info command", options.OutputPrefix, "_mmc_getconfiguration.bin", + DataFile.WriteTo("Device-Info command", outputPrefix, "_mmc_getconfiguration.bin", "MMC GET CONFIGURATION", devInfo.MmcConfiguration); Features.SeparatedFeatures ftr = Features.Separate(devInfo.MmcConfiguration); @@ -629,7 +654,7 @@ namespace DiscImageChef.Commands { if(devInfo.PlextorFeatures.Eeprom != null) { - DataFile.WriteTo("Device-Info command", options.OutputPrefix, "_plextor_eeprom.bin", + DataFile.WriteTo("Device-Info command", outputPrefix, "_plextor_eeprom.bin", "PLEXTOR READ EEPROM", devInfo.PlextorFeatures.Eeprom); DicConsole.WriteLine("Drive has loaded a total of {0} discs", devInfo.PlextorFeatures.Discs); @@ -772,7 +797,7 @@ namespace DiscImageChef.Commands if(devInfo.BlockLimits != null) { - DataFile.WriteTo("Device-Info command", options.OutputPrefix, "_ssc_readblocklimits.bin", + DataFile.WriteTo("Device-Info command", outputPrefix, "_ssc_readblocklimits.bin", "SSC READ BLOCK LIMITS", devInfo.BlockLimits); DicConsole.WriteLine("Block limits for device:"); DicConsole.WriteLine(BlockLimits.Prettify(devInfo.BlockLimits)); @@ -780,7 +805,7 @@ namespace DiscImageChef.Commands if(devInfo.DensitySupport != null) { - DataFile.WriteTo("Device-Info command", options.OutputPrefix, "_ssc_reportdensitysupport.bin", + DataFile.WriteTo("Device-Info command", outputPrefix, "_ssc_reportdensitysupport.bin", "SSC REPORT DENSITY SUPPORT", devInfo.DensitySupport); if(devInfo.DensitySupportHeader.HasValue) { @@ -791,9 +816,8 @@ namespace DiscImageChef.Commands if(devInfo.MediumDensitySupport != null) { - DataFile.WriteTo("Device-Info command", options.OutputPrefix, - "_ssc_reportdensitysupport_medium.bin", "SSC REPORT DENSITY SUPPORT (MEDIUM)", - devInfo.MediumDensitySupport); + DataFile.WriteTo("Device-Info command", outputPrefix, "_ssc_reportdensitysupport_medium.bin", + "SSC REPORT DENSITY SUPPORT (MEDIUM)", devInfo.MediumDensitySupport); if(devInfo.MediaTypeSupportHeader.HasValue) { DicConsole.WriteLine("Medium types supported by device:"); @@ -813,32 +837,29 @@ namespace DiscImageChef.Commands if(devInfo.CID != null) { noInfo = false; - DataFile.WriteTo("Device-Info command", options.OutputPrefix, "_mmc_cid.bin", "MMC CID", - devInfo.CID); + DataFile.WriteTo("Device-Info command", outputPrefix, "_mmc_cid.bin", "MMC CID", devInfo.CID); DicConsole.WriteLine("{0}", Decoders.MMC.Decoders.PrettifyCID(devInfo.CID)); } if(devInfo.CSD != null) { noInfo = false; - DataFile.WriteTo("Device-Info command", options.OutputPrefix, "_mmc_csd.bin", "MMC CSD", - devInfo.CSD); + DataFile.WriteTo("Device-Info command", outputPrefix, "_mmc_csd.bin", "MMC CSD", devInfo.CSD); DicConsole.WriteLine("{0}", Decoders.MMC.Decoders.PrettifyCSD(devInfo.CSD)); } if(devInfo.OCR != null) { noInfo = false; - DataFile.WriteTo("Device-Info command", options.OutputPrefix, "_mmc_ocr.bin", "MMC OCR", - devInfo.OCR); + DataFile.WriteTo("Device-Info command", outputPrefix, "_mmc_ocr.bin", "MMC OCR", devInfo.OCR); DicConsole.WriteLine("{0}", Decoders.MMC.Decoders.PrettifyOCR(devInfo.OCR)); } if(devInfo.ExtendedCSD != null) { noInfo = false; - DataFile.WriteTo("Device-Info command", options.OutputPrefix, "_mmc_ecsd.bin", - "MMC Extended CSD", devInfo.ExtendedCSD); + DataFile.WriteTo("Device-Info command", outputPrefix, "_mmc_ecsd.bin", "MMC Extended CSD", + devInfo.ExtendedCSD); DicConsole.WriteLine("{0}", Decoders.MMC.Decoders.PrettifyExtendedCSD(devInfo.ExtendedCSD)); } @@ -852,32 +873,32 @@ namespace DiscImageChef.Commands if(devInfo.CID != null) { noInfo = false; - DataFile.WriteTo("Device-Info command", options.OutputPrefix, "_sd_cid.bin", - "SecureDigital CID", devInfo.CID); + DataFile.WriteTo("Device-Info command", outputPrefix, "_sd_cid.bin", "SecureDigital CID", + devInfo.CID); DicConsole.WriteLine("{0}", Decoders.SecureDigital.Decoders.PrettifyCID(devInfo.CID)); } if(devInfo.CSD != null) { noInfo = false; - DataFile.WriteTo("Device-Info command", options.OutputPrefix, "_sd_csd.bin", - "SecureDigital CSD", devInfo.CSD); + DataFile.WriteTo("Device-Info command", outputPrefix, "_sd_csd.bin", "SecureDigital CSD", + devInfo.CSD); DicConsole.WriteLine("{0}", Decoders.SecureDigital.Decoders.PrettifyCSD(devInfo.CSD)); } if(devInfo.OCR != null) { noInfo = false; - DataFile.WriteTo("Device-Info command", options.OutputPrefix, "_sd_ocr.bin", - "SecureDigital OCR", devInfo.OCR); + DataFile.WriteTo("Device-Info command", outputPrefix, "_sd_ocr.bin", "SecureDigital OCR", + devInfo.OCR); DicConsole.WriteLine("{0}", Decoders.SecureDigital.Decoders.PrettifyOCR(devInfo.OCR)); } if(devInfo.SCR != null) { noInfo = false; - DataFile.WriteTo("Device-Info command", options.OutputPrefix, "_sd_scr.bin", - "SecureDigital SCR", devInfo.SCR); + DataFile.WriteTo("Device-Info command", outputPrefix, "_sd_scr.bin", "SecureDigital SCR", + devInfo.SCR); DicConsole.WriteLine("{0}", Decoders.SecureDigital.Decoders.PrettifySCR(devInfo.SCR)); } @@ -886,9 +907,11 @@ namespace DiscImageChef.Commands break; } - Core.Statistics.AddCommand("device-info"); + Statistics.AddCommand("device-info"); dev.Close(); + + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/DeviceReport.cs b/DiscImageChef/Commands/DeviceReport.cs index 202fefa3f..5ca26cc28 100644 --- a/DiscImageChef/Commands/DeviceReport.cs +++ b/DiscImageChef/Commands/DeviceReport.cs @@ -43,40 +43,87 @@ using DiscImageChef.Database; using DiscImageChef.Database.Models; using DiscImageChef.Decoders.ATA; using DiscImageChef.Decoders.SCSI; +using Mono.Options; using Newtonsoft.Json; +using Command = Mono.Options.Command; using Device = DiscImageChef.Devices.Device; +using DeviceReport = DiscImageChef.Core.Devices.Report.DeviceReport; namespace DiscImageChef.Commands { - static class DeviceReport + class DeviceReportCommand : Command { - internal static void DoDeviceReport(DeviceReportOptions options) + string devicePath; + + bool showHelp; + + public DeviceReportCommand() : base("device-report", + "Tests the device capabilities and creates an JSON report of them.") { - DicConsole.DebugWriteLine("Device-Report command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Device-Report command", "--verbose={0}", options.Verbose); - DicConsole.DebugWriteLine("Device-Report command", "--device={0}", options.DevicePath); + 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 arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 1) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count == 0) + { + DicConsole.ErrorWriteLine("Missing device path."); + return 1; + } + + 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(!DetectOS.IsAdmin) { DicConsole .ErrorWriteLine("Because of the commands sent to a device, device report must be run with administrative privileges."); DicConsole.ErrorWriteLine("Not continuing."); - return; + return 1; } - if(options.DevicePath.Length == 2 && options.DevicePath[1] == ':' && options.DevicePath[0] != '/' && - char.IsLetter(options.DevicePath[0])) - options.DevicePath = "\\\\.\\" + char.ToUpper(options.DevicePath[0]) + ':'; + if(devicePath.Length == 2 && devicePath[1] == ':' && devicePath[0] != '/' && char.IsLetter(devicePath[0])) + devicePath = "\\\\.\\" + char.ToUpper(devicePath[0]) + ':'; - Device dev = new Device(options.DevicePath); + Device dev = new Device(devicePath); if(dev.Error) { DicConsole.ErrorWriteLine("Error {0} opening device.", dev.LastError); - return; + return 2; } - Core.Statistics.AddDevice(dev); + Statistics.AddDevice(dev); DeviceReportV2 report = new DeviceReportV2 { @@ -94,7 +141,7 @@ namespace DiscImageChef.Commands jsonFile = jsonFile.Replace('\\', '_').Replace('/', '_').Replace('?', '_'); - Core.Devices.Report.DeviceReport reporter = new Core.Devices.Report.DeviceReport(dev, options.Debug); + DeviceReport reporter = new DeviceReport(dev, MainClass.Debug); ConsoleKeyInfo pressedKey; @@ -248,7 +295,7 @@ namespace DiscImageChef.Commands dev.AtapiIdentify(out buffer, out _, dev.Timeout, out _); - if(!Identify.Decode(buffer).HasValue) return; + if(!Identify.Decode(buffer).HasValue) return 3; report.ATAPI = new Ata {Identify = buffer}; @@ -448,7 +495,7 @@ namespace DiscImageChef.Commands tryPioneer |= dev.Manufacturer.ToLowerInvariant() == "pioneer"; tryNec |= dev.Manufacturer.ToLowerInvariant() == "nec"; - if(options.Debug) + if(MainClass.Debug) { if(!tryPlextor) { @@ -614,7 +661,7 @@ namespace DiscImageChef.Commands dev.Timeout, out _); if(!sense) { - if(options.Debug) mediaTest.ReadLong10Data = buffer; + if(MainClass.Debug) mediaTest.ReadLong10Data = buffer; mediaTest.LongBlockSize = i; break; @@ -627,8 +674,8 @@ namespace DiscImageChef.Commands } } - if(options.Debug && mediaTest.SupportsReadLong == true && - mediaTest.LongBlockSize != mediaTest.BlockSize) + if(MainClass.Debug && mediaTest.SupportsReadLong == true && + mediaTest.LongBlockSize != mediaTest.BlockSize) { sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, (ushort)mediaTest.LongBlockSize, dev.Timeout, out _); @@ -844,8 +891,8 @@ namespace DiscImageChef.Commands } } - if(options.Debug && mediaTest.SupportsReadLong == true && - mediaTest.LongBlockSize != mediaTest.BlockSize) + if(MainClass.Debug && mediaTest.SupportsReadLong == true && + mediaTest.LongBlockSize != mediaTest.BlockSize) { sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, (ushort)mediaTest.LongBlockSize, dev.Timeout, out _); @@ -889,7 +936,8 @@ namespace DiscImageChef.Commands dev.Timeout, out _); if(!sense) { - if(options.Debug) report.SCSI.ReadCapabilities.ReadLong10Data = buffer; + if(MainClass.Debug) + report.SCSI.ReadCapabilities.ReadLong10Data = buffer; report.SCSI.ReadCapabilities.LongBlockSize = i; break; @@ -902,7 +950,7 @@ namespace DiscImageChef.Commands } } - if(options.Debug && report.SCSI.ReadCapabilities.SupportsReadLong == true && + if(MainClass.Debug && report.SCSI.ReadCapabilities.SupportsReadLong == true && report.SCSI.ReadCapabilities.LongBlockSize != report.SCSI.ReadCapabilities.BlockSize) { @@ -931,7 +979,7 @@ namespace DiscImageChef.Commands jsonSw.Close(); jsonFs.Close(); - Core.Statistics.AddCommand("device-report"); + Statistics.AddCommand("device-report"); using(DicContext ctx = DicContext.Create(Settings.Settings.LocalDbPath)) { @@ -941,6 +989,7 @@ namespace DiscImageChef.Commands // TODO: if(Settings.Settings.Current.ShareReports) Remote.SubmitReport(report); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/DumpMedia.cs b/DiscImageChef/Commands/DumpMedia.cs index 808e5f340..6d8efb1b9 100644 --- a/DiscImageChef/Commands/DumpMedia.cs +++ b/DiscImageChef/Commands/DumpMedia.cs @@ -45,16 +45,111 @@ using DiscImageChef.Core; using DiscImageChef.Core.Devices.Dumping; using DiscImageChef.Core.Logging; using DiscImageChef.Devices; +using Mono.Options; using Schemas; using Ata = DiscImageChef.Core.Devices.Dumping.Ata; using Scsi = DiscImageChef.Core.Devices.Dumping.Scsi; namespace DiscImageChef.Commands { - static class DumpMedia + class DumpMediaCommand : Command { - internal static void DoDumpMedia(DumpMediaOptions options) + string cicmXml; + string devicePath; + bool doResume = true; + string encodingName; + bool firstTrackPregap; + bool force; + bool noMetadata; + bool noTrim; + string outputFile; + string outputOptions; + bool persistent; + // TODO: Disabled temporarily + bool raw = false; + ushort retryPasses = 5; + bool showHelp; + int skip = 512; + bool stopOnError; + string wanteOutputFormat; + + public DumpMediaCommand() : base("dump-media", "Dumps the media inserted on a device to a media image.") { + Options = new OptionSet + { + $"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", + $"{MainClass.AssemblyCopyright}", + "", + $"usage: DiscImageChef {Name} [OPTIONS] devicepath outputimage", + "", + Help, + {"cicm-xml|x=", "Take metadata from existing CICM XML sidecar.", s => cicmXml = s}, + {"encoding|e=", "Name of character encoding to use.", s => encodingName = s}, + { + "first-pregap", "Try to read first track pregap. Only applicable to CD/DDCD/GD.", + b => firstTrackPregap = b != null + }, + {"force|f", "Continue dump whatever happens.", b => force = 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.", + s => wanteOutputFormat = s + }, + {"no-metadata", "Disables creating CICM XML sidecar.", b => noMetadata = b != null}, + {"no-trim", "Disables trimming errored from skipped sectors.", b => noTrim = b != null}, + { + "options|O=", "Comma separated name=value pairs of options to pass to output image plugin.", + s => outputOptions = s + }, + {"persistent", "Try to recover partial or incorrect data.", b => persistent = b != null}, + /* TODO: Disabled temporarily + { "raw|r", "Dump sectors with tags included. For optical media, dump scrambled sectors.", (b) => Raw = b != null}, */ + { + "resume|r", "Create/use resume mapfile.", + b => doResume = b != null + }, + {"retry-passes|p=", "How many retry passes to do.", (ushort us) => retryPasses = us}, + {"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.", + b => stopOnError = b != null + }, + { + "help|h|?", "Show this message and exit.", + v => showHelp = v != null + } + }; + } + + public override int Invoke(IEnumerable arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 2) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count <= 1) + { + DicConsole.ErrorWriteLine("Missing paths."); + return 1; + } + + devicePath = extra[0]; + outputFile = extra[1]; + // TODO: Be able to cancel hashing Sidecar.InitProgressEvent += Progress.InitProgress; Sidecar.UpdateProgressEvent += Progress.UpdateProgress; @@ -64,65 +159,64 @@ namespace DiscImageChef.Commands Sidecar.EndProgressEvent2 += Progress.EndProgress2; Sidecar.UpdateStatusEvent += Progress.UpdateStatus; - DicConsole.DebugWriteLine("Dump-Media command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Dump-Media command", "--verbose={0}", options.Verbose); - DicConsole.DebugWriteLine("Dump-Media command", "--device={0}", options.DevicePath); + DicConsole.DebugWriteLine("Dump-Media command", "--cicm-xml={0}", cicmXml); + 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}", wanteOutputFormat); + 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); // TODO: Disabled temporarily - //DicConsole.DebugWriteLine("Dump-Media command", "--raw={0}", options.Raw); - DicConsole.DebugWriteLine("Dump-Media command", "--stop-on-error={0}", options.StopOnError); - DicConsole.DebugWriteLine("Dump-Media command", "--force={0}", options.Force); - DicConsole.DebugWriteLine("Dump-Media command", "--retry-passes={0}", options.RetryPasses); - DicConsole.DebugWriteLine("Dump-Media command", "--persistent={0}", options.Persistent); - DicConsole.DebugWriteLine("Dump-Media command", "--resume={0}", options.Resume); - DicConsole.DebugWriteLine("Dump-Media command", "--first-pregap={0}", options.FirstTrackPregap); - DicConsole.DebugWriteLine("Dump-Media command", "--encoding={0}", options.EncodingName); - DicConsole.DebugWriteLine("Dump-Media command", "--output={0}", options.OutputFile); - DicConsole.DebugWriteLine("Dump-Media command", "--format={0}", options.OutputFormat); - DicConsole.DebugWriteLine("Dump-Media command", "--force={0}", options.Force); - DicConsole.DebugWriteLine("Dump-Media command", "--options={0}", options.Options); - DicConsole.DebugWriteLine("Dump-Media command", "--cicm-xml={0}", options.CicmXml); - DicConsole.DebugWriteLine("Dump-Media command", "--skip={0}", options.Skip); - DicConsole.DebugWriteLine("Dump-Media command", "--no-metadata={0}", options.NoMetadata); + //DicConsole.DebugWriteLine("Dump-Media command", "--raw={0}", raw); + 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); - Dictionary parsedOptions = Options.Parse(options.Options); + Dictionary parsedOptions = Core.Options.Parse(outputOptions); DicConsole.DebugWriteLine("Dump-Media command", "Parsed options:"); foreach(KeyValuePair parsedOption in parsedOptions) DicConsole.DebugWriteLine("Dump-Media command", "{0} = {1}", parsedOption.Key, parsedOption.Value); Encoding encoding = null; - if(options.EncodingName != null) + if(encodingName != null) try { - encoding = Claunia.Encoding.Encoding.GetEncoding(options.EncodingName); - if(options.Verbose) DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName); + encoding = Claunia.Encoding.Encoding.GetEncoding(encodingName); + if(MainClass.Verbose) DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName); } catch(ArgumentException) { DicConsole.ErrorWriteLine("Specified encoding is not supported."); - return; + return 1; } - if(options.DevicePath.Length == 2 && options.DevicePath[1] == ':' && options.DevicePath[0] != '/' && - char.IsLetter(options.DevicePath[0])) - options.DevicePath = "\\\\.\\" + char.ToUpper(options.DevicePath[0]) + ':'; + if(devicePath.Length == 2 && devicePath[1] == ':' && devicePath[0] != '/' && char.IsLetter(devicePath[0])) + devicePath = "\\\\.\\" + char.ToUpper(devicePath[0]) + ':'; - Device dev = new Device(options.DevicePath); + Device dev = new Device(devicePath); if(dev.Error) { DicConsole.ErrorWriteLine("Error {0} opening device.", dev.LastError); - return; + return 2; } - Core.Statistics.AddDevice(dev); + Statistics.AddDevice(dev); - string outputPrefix = Path.Combine(Path.GetDirectoryName(options.OutputFile), - Path.GetFileNameWithoutExtension(options.OutputFile)); + string outputPrefix = Path.Combine(Path.GetDirectoryName(outputFile), + Path.GetFileNameWithoutExtension(outputFile)); Resume resume = null; XmlSerializer xs = new XmlSerializer(typeof(Resume)); - if(File.Exists(outputPrefix + ".resume.xml") && options.Resume) + if(File.Exists(outputPrefix + ".resume.xml") && doResume) try { StreamReader sr = new StreamReader(outputPrefix + ".resume.xml"); @@ -132,71 +226,70 @@ namespace DiscImageChef.Commands catch { DicConsole.ErrorWriteLine("Incorrect resume file, not continuing..."); - return; + return 3; } if(resume != null && resume.NextBlock > resume.LastBlock && resume.BadBlocks.Count == 0) { DicConsole.WriteLine("Media already dumped correctly, not continuing..."); - return; + return 4; } CICMMetadataType sidecar = null; XmlSerializer sidecarXs = new XmlSerializer(typeof(CICMMetadataType)); - if(options.CicmXml != null) - if(File.Exists(options.CicmXml)) + if(cicmXml != null) + if(File.Exists(cicmXml)) try { - StreamReader sr = new StreamReader(options.CicmXml); + StreamReader sr = new StreamReader(cicmXml); sidecar = (CICMMetadataType)sidecarXs.Deserialize(sr); sr.Close(); } catch { DicConsole.ErrorWriteLine("Incorrect metadata sidecar file, not continuing..."); - return; + return 5; } else { DicConsole.ErrorWriteLine("Could not find metadata sidecar, not continuing..."); - return; + return 6; } PluginBase plugins = GetPluginBase.Instance; List candidates = new List(); // Try extension - if(string.IsNullOrEmpty(options.OutputFormat)) + if(string.IsNullOrEmpty(wanteOutputFormat)) candidates.AddRange(plugins.WritableImages.Values.Where(t => t.KnownExtensions - .Contains(Path.GetExtension(options - .OutputFile)))); + .Contains(Path.GetExtension(outputFile)))); // Try Id - else if(Guid.TryParse(options.OutputFormat, out Guid outId)) + else if(Guid.TryParse(wanteOutputFormat, out Guid outId)) candidates.AddRange(plugins.WritableImages.Values.Where(t => t.Id.Equals(outId))); // Try name else - candidates.AddRange(plugins.WritableImages.Values.Where(t => string.Equals(t.Name, options.OutputFormat, + candidates.AddRange(plugins.WritableImages.Values.Where(t => string.Equals(t.Name, wanteOutputFormat, StringComparison .InvariantCultureIgnoreCase))); if(candidates.Count == 0) { DicConsole.WriteLine("No plugin supports requested extension."); - return; + return 7; } if(candidates.Count > 1) { DicConsole.WriteLine("More than one plugin supports requested extension."); - return; + return 8; } IWritableImage outputFormat = candidates[0]; DumpLog dumpLog = new DumpLog(outputPrefix + ".log", dev); - if(options.Verbose) + if(MainClass.Verbose) { dumpLog.WriteLine("Output image format: {0} ({1}).", outputFormat.Name, outputFormat.Id); DicConsole.VerboseWriteLine("Output image format: {0} ({1}).", outputFormat.Name, outputFormat.Id); @@ -209,41 +302,33 @@ namespace DiscImageChef.Commands if(dev.IsUsb && dev.UsbVendorId == 0x054C && (dev.UsbProductId == 0x01C8 || dev.UsbProductId == 0x01C9 || dev.UsbProductId == 0x02D2)) - PlayStationPortable.Dump(dev, options.DevicePath, outputFormat, options.RetryPasses, options.Force, - options.Persistent, options.StopOnError, ref resume, ref dumpLog, encoding, - outputPrefix, options.OutputFile, parsedOptions, sidecar, (uint)options.Skip, - options.NoMetadata, options.NoTrim); + PlayStationPortable.Dump(dev, devicePath, outputFormat, retryPasses, force, persistent, stopOnError, + ref resume, ref dumpLog, encoding, outputPrefix, outputFile, parsedOptions, + sidecar, (uint)skip, noMetadata, noTrim); else switch(dev.Type) { case DeviceType.ATA: - Ata.Dump(dev, options.DevicePath, outputFormat, options.RetryPasses, options.Force, - false, /*options.Raw,*/ - options.Persistent, options.StopOnError, ref resume, ref dumpLog, encoding, - outputPrefix, options.OutputFile, parsedOptions, sidecar, (uint)options.Skip, - options.NoMetadata, options.NoTrim); + Ata.Dump(dev, devicePath, outputFormat, retryPasses, force, false, /*raw,*/ + persistent, stopOnError, ref resume, ref dumpLog, encoding, outputPrefix, outputFile, + parsedOptions, sidecar, (uint)skip, noMetadata, noTrim); break; case DeviceType.MMC: case DeviceType.SecureDigital: - SecureDigital.Dump(dev, options.DevicePath, outputFormat, options.RetryPasses, options.Force, - false, /*options.Raw,*/ options.Persistent, options.StopOnError, ref resume, - ref dumpLog, encoding, outputPrefix, options.OutputFile, parsedOptions, - sidecar, (uint)options.Skip, options.NoMetadata, options.NoTrim); + SecureDigital.Dump(dev, devicePath, outputFormat, retryPasses, force, false, /*raw,*/ + persistent, stopOnError, ref resume, ref dumpLog, encoding, outputPrefix, + outputFile, parsedOptions, sidecar, (uint)skip, noMetadata, noTrim); break; case DeviceType.NVMe: - NvMe.Dump(dev, options.DevicePath, outputFormat, options.RetryPasses, options.Force, - false, /*options.Raw,*/ - options.Persistent, options.StopOnError, ref resume, ref dumpLog, encoding, - outputPrefix, options.OutputFile, parsedOptions, sidecar, (uint)options.Skip, - options.NoMetadata, options.NoTrim); + NvMe.Dump(dev, devicePath, outputFormat, retryPasses, force, false, /*raw,*/ + persistent, stopOnError, ref resume, ref dumpLog, encoding, outputPrefix, outputFile, + parsedOptions, sidecar, (uint)skip, noMetadata, noTrim); break; case DeviceType.ATAPI: case DeviceType.SCSI: - Scsi.Dump(dev, options.DevicePath, outputFormat, options.RetryPasses, options.Force, - false, /*options.Raw,*/ - options.Persistent, options.StopOnError, ref resume, ref dumpLog, - options.FirstTrackPregap, encoding, outputPrefix, options.OutputFile, parsedOptions, - sidecar, (uint)options.Skip, options.NoMetadata, options.NoTrim); + Scsi.Dump(dev, devicePath, outputFormat, retryPasses, force, false, /*raw,*/ + persistent, stopOnError, ref resume, ref dumpLog, firstTrackPregap, encoding, + outputPrefix, outputFile, parsedOptions, sidecar, (uint)skip, noMetadata, noTrim); break; default: dumpLog.WriteLine("Unknown device type."); @@ -251,7 +336,7 @@ namespace DiscImageChef.Commands throw new NotSupportedException("Unknown device type."); } - if(resume != null && options.Resume) + if(resume != null && doResume) { resume.LastWriteDate = DateTime.UtcNow; resume.BadBlocks.Sort(); @@ -266,9 +351,10 @@ namespace DiscImageChef.Commands dumpLog.Close(); - Core.Statistics.AddCommand("dump-media"); + Statistics.AddCommand("dump-media"); dev.Close(); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/Entropy.cs b/DiscImageChef/Commands/Entropy.cs index d22af10b4..df2199cc4 100644 --- a/DiscImageChef/Commands/Entropy.cs +++ b/DiscImageChef/Commands/Entropy.cs @@ -30,31 +30,90 @@ // Copyright © 2011-2019 Natalia Portillo // ****************************************************************************/ +using System.Collections.Generic; using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.Console; using DiscImageChef.Core; +using Mono.Options; namespace DiscImageChef.Commands { - static class Entropy + class EntropyCommand : Command { - internal static void DoEntropy(EntropyOptions options) + 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.") { - DicConsole.DebugWriteLine("Entropy command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Entropy command", "--verbose={0}", options.Verbose); - DicConsole.DebugWriteLine("Entropy command", "--separated-tracks={0}", options.SeparatedTracks); - DicConsole.DebugWriteLine("Entropy command", "--whole-disc={0}", options.WholeDisc); - DicConsole.DebugWriteLine("Entropy command", "--input={0}", options.InputFile); - DicConsole.DebugWriteLine("Entropy command", "--duplicated-sectors={0}", options.DuplicatedSectors); + Options = new OptionSet + { + $"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", + $"{MainClass.AssemblyCopyright}", + "", + $"usage: DiscImageChef {Name} [OPTIONS] imagefile", + "", + 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 arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 1) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count == 0) + { + DicConsole.ErrorWriteLine("Missing input image."); + return 1; + } + + inputFile = extra[0]; + + DicConsole.DebugWriteLine("Entropy command", "--debug={0}", MainClass.Debug); + DicConsole.DebugWriteLine("Entropy command", "--duplicated-sectors={0}", duplicatedSectors); + DicConsole.DebugWriteLine("Entropy command", "--input={0}", inputFile); + DicConsole.DebugWriteLine("Entropy command", "--separated-tracks={0}", separatedTracks); + DicConsole.DebugWriteLine("Entropy command", "--verbose={0}", MainClass.Verbose); + DicConsole.DebugWriteLine("Entropy command", "--whole-disc={0}", wholeDisc); FiltersList filtersList = new FiltersList(); - IFilter inputFilter = filtersList.GetFilter(options.InputFile); + IFilter inputFilter = filtersList.GetFilter(inputFile); if(inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); - return; + return 1; } IMediaImage inputFormat = ImageFormat.Detect(inputFilter); @@ -62,15 +121,15 @@ namespace DiscImageChef.Commands if(inputFormat == null) { DicConsole.ErrorWriteLine("Unable to recognize image format, not checksumming"); - return; + return 2; } inputFormat.Open(inputFilter); - Core.Statistics.AddMediaFormat(inputFormat.Format); - Core.Statistics.AddMedia(inputFormat.Info.MediaType, false); - Core.Statistics.AddFilter(inputFilter.Name); + Statistics.AddMediaFormat(inputFormat.Format); + Statistics.AddMedia(inputFormat.Info.MediaType, false); + Statistics.AddFilter(inputFilter.Name); - Core.Entropy entropyCalculator = new Core.Entropy(options.Debug, options.Verbose, inputFormat); + Entropy entropyCalculator = new Entropy(MainClass.Debug, MainClass.Verbose, inputFormat); entropyCalculator.InitProgressEvent += Progress.InitProgress; entropyCalculator.InitProgress2Event += Progress.InitProgress2; entropyCalculator.UpdateProgressEvent += Progress.UpdateProgress; @@ -78,9 +137,9 @@ namespace DiscImageChef.Commands entropyCalculator.EndProgressEvent += Progress.EndProgress; entropyCalculator.EndProgress2Event += Progress.EndProgress2; - if(options.SeparatedTracks) + if(separatedTracks) { - EntropyResults[] tracksEntropy = entropyCalculator.CalculateTracksEntropy(options.DuplicatedSectors); + EntropyResults[] tracksEntropy = entropyCalculator.CalculateTracksEntropy(duplicatedSectors); foreach(EntropyResults trackEntropy in tracksEntropy) { DicConsole.WriteLine("Entropy for track {0} is {1:F4}.", trackEntropy.Track, trackEntropy.Entropy); @@ -91,20 +150,21 @@ namespace DiscImageChef.Commands } } - if(!options.WholeDisc) + if(!wholeDisc) { - Core.Statistics.AddCommand("entropy"); - return; + Statistics.AddCommand("entropy"); + return 0; } - EntropyResults entropy = entropyCalculator.CalculateMediaEntropy(options.DuplicatedSectors); + EntropyResults entropy = entropyCalculator.CalculateMediaEntropy(duplicatedSectors); DicConsole.WriteLine("Entropy for disk is {0:F4}.", entropy.Entropy); if(entropy.UniqueSectors != null) DicConsole.WriteLine("Disk has {0} unique sectors ({1:P3})", entropy.UniqueSectors, (double)entropy.UniqueSectors / (double)entropy.Sectors); - Core.Statistics.AddCommand("entropy"); + Statistics.AddCommand("entropy"); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/ExtractFiles.cs b/DiscImageChef/Commands/ExtractFiles.cs index 6e81a16f7..ebe454e3d 100644 --- a/DiscImageChef/Commands/ExtractFiles.cs +++ b/DiscImageChef/Commands/ExtractFiles.cs @@ -39,47 +39,106 @@ using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.CommonTypes.Structs; using DiscImageChef.Console; using DiscImageChef.Core; +using Mono.Options; namespace DiscImageChef.Commands { - // TODO: Rewrite this, has an insane amount of repeating code ;) - static class ExtractFiles + class ExtractFilesCommand : Command { - internal static void DoExtractFiles(ExtractFilesOptions options) + string encodingName; + bool extractXattrs; + string inputFile; + string outputDir; + string pluginOptions; + bool showHelp; + + public ExtractFilesCommand() : base("extract-files", "Extracts all files in disc image.") { - DicConsole.DebugWriteLine("Extract-Files command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Extract-Files command", "--verbose={0}", options.Verbose); - DicConsole.DebugWriteLine("Extract-Files command", "--input={0}", options.InputFile); - DicConsole.DebugWriteLine("Extract-Files command", "--xattrs={0}", options.Xattrs); - DicConsole.DebugWriteLine("Extract-Files command", "--output={0}", options.OutputDir); + Options = new OptionSet + { + $"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", + $"{MainClass.AssemblyCopyright}", + "", + $"usage: DiscImageChef {Name} [OPTIONS] imagefile", + "", + Help, + {"encoding|e=", "Name of character encoding to use.", s => encodingName = s}, + { + "options|O=", "Comma separated name=value pairs of options to pass to filesystem plugin.", + s => pluginOptions = s + }, + { + "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}, + {"help|h|?", "Show this message and exit.", v => showHelp = v != null} + }; + } + + public override int Invoke(IEnumerable arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 1) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count == 0) + { + DicConsole.ErrorWriteLine("Missing input image."); + return 1; + } + + inputFile = extra[0]; + + 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(options.InputFile); + IFilter inputFilter = filtersList.GetFilter(inputFile); - Dictionary parsedOptions = Options.Parse(options.Options); + Dictionary parsedOptions = Core.Options.Parse(pluginOptions); DicConsole.DebugWriteLine("Extract-Files command", "Parsed options:"); foreach(KeyValuePair parsedOption in parsedOptions) DicConsole.DebugWriteLine("Extract-Files command", "{0} = {1}", parsedOption.Key, parsedOption.Value); - parsedOptions.Add("debug", options.Debug.ToString()); + parsedOptions.Add("debug", MainClass.Debug.ToString()); if(inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); - return; + return 0; } Encoding encoding = null; - if(options.EncodingName != null) + if(encodingName != null) try { - encoding = Claunia.Encoding.Encoding.GetEncoding(options.EncodingName); - if(options.Verbose) DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName); + encoding = Claunia.Encoding.Encoding.GetEncoding(encodingName); + if(MainClass.Verbose) DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName); } catch(ArgumentException) { DicConsole.ErrorWriteLine("Specified encoding is not supported."); - return; + return 1; } PluginBase plugins = GetPluginBase.Instance; @@ -91,21 +150,21 @@ namespace DiscImageChef.Commands if(imageFormat == null) { DicConsole.WriteLine("Image format not identified, not proceeding with analysis."); - return; + return 2; } - if(options.Verbose) + if(MainClass.Verbose) DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name, imageFormat.Id); else DicConsole.WriteLine("Image format identified by {0}.", imageFormat.Name); - if(Directory.Exists(options.OutputDir) || File.Exists(options.OutputDir)) + if(Directory.Exists(outputDir) || File.Exists(outputDir)) { DicConsole.ErrorWriteLine("Destination exists, aborting."); - return; + return 3; } - Directory.CreateDirectory(options.OutputDir); + Directory.CreateDirectory(outputDir); try { @@ -113,7 +172,7 @@ namespace DiscImageChef.Commands { DicConsole.WriteLine("Unable to open image format"); DicConsole.WriteLine("No error given"); - return; + return 4; } DicConsole.DebugWriteLine("Extract-Files command", "Correctly opened image file."); @@ -124,15 +183,15 @@ namespace DiscImageChef.Commands DicConsole.DebugWriteLine("Extract-Files command", "Image identifies disk type as {0}.", imageFormat.Info.MediaType); - Core.Statistics.AddMediaFormat(imageFormat.Format); - Core.Statistics.AddMedia(imageFormat.Info.MediaType, false); - Core.Statistics.AddFilter(inputFilter.Name); + Statistics.AddMediaFormat(imageFormat.Format); + Statistics.AddMedia(imageFormat.Info.MediaType, false); + Statistics.AddFilter(inputFilter.Name); } catch(Exception ex) { DicConsole.ErrorWriteLine("Unable to open image format"); DicConsole.ErrorWriteLine("Error: {0}", ex.Message); - return; + return 5; } List partitions = Core.Partitions.GetAll(imageFormat); @@ -185,7 +244,7 @@ namespace DiscImageChef.Commands { string outputPath; FileStream outputFile; - if(options.Xattrs) + if(extractXattrs) { error = fs.ListXAttr(entry, out List xattrs); if(error == Errno.NoError) @@ -195,14 +254,15 @@ namespace DiscImageChef.Commands error = fs.GetXattr(entry, xattr, ref xattrBuf); if(error != Errno.NoError) continue; - Directory - .CreateDirectory(Path.Combine(options.OutputDir, - fs.XmlFsType.Type, - volumeName, ".xattrs", - xattr)); + Directory.CreateDirectory(Path.Combine(outputDir, + fs.XmlFsType + .Type, + volumeName, + ".xattrs", + xattr)); outputPath = - Path.Combine(options.OutputDir, fs.XmlFsType.Type, + Path.Combine(outputDir, fs.XmlFsType.Type, volumeName, ".xattrs", xattr, entry); if(!File.Exists(outputPath)) @@ -245,13 +305,11 @@ namespace DiscImageChef.Commands } } - Directory.CreateDirectory(Path.Combine(options.OutputDir, - fs.XmlFsType.Type, + Directory.CreateDirectory(Path.Combine(outputDir, fs.XmlFsType.Type, volumeName)); outputPath = - Path.Combine(options.OutputDir, fs.XmlFsType.Type, volumeName, - entry); + Path.Combine(outputDir, fs.XmlFsType.Type, volumeName, entry); if(!File.Exists(outputPath)) { @@ -304,7 +362,7 @@ namespace DiscImageChef.Commands DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); - Core.Statistics.AddFilesystem(fs.XmlFsType.Type); + Statistics.AddFilesystem(fs.XmlFsType.Type); } else DicConsole.ErrorWriteLine("Unable to mount device, error {0}", @@ -335,7 +393,7 @@ namespace DiscImageChef.Commands { FileStream outputFile; string outputPath; - if(options.Xattrs) + if(extractXattrs) { error = fs.ListXAttr(entry, out List xattrs); if(error == Errno.NoError) @@ -345,14 +403,14 @@ namespace DiscImageChef.Commands error = fs.GetXattr(entry, xattr, ref xattrBuf); if(error != Errno.NoError) continue; - Directory.CreateDirectory(Path.Combine(options.OutputDir, + Directory.CreateDirectory(Path.Combine(outputDir, fs.XmlFsType.Type, volumeName, ".xattrs", xattr)); outputPath = - Path.Combine(options.OutputDir, fs.XmlFsType.Type, - volumeName, ".xattrs", xattr, entry); + Path.Combine(outputDir, fs.XmlFsType.Type, volumeName, + ".xattrs", xattr, entry); if(!File.Exists(outputPath)) { @@ -392,11 +450,10 @@ namespace DiscImageChef.Commands } } - Directory.CreateDirectory(Path.Combine(options.OutputDir, fs.XmlFsType.Type, + Directory.CreateDirectory(Path.Combine(outputDir, fs.XmlFsType.Type, volumeName)); - outputPath = - Path.Combine(options.OutputDir, fs.XmlFsType.Type, volumeName, entry); + outputPath = Path.Combine(outputDir, fs.XmlFsType.Type, volumeName, entry); if(!File.Exists(outputPath)) { @@ -447,7 +504,7 @@ namespace DiscImageChef.Commands else DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); - Core.Statistics.AddFilesystem(fs.XmlFsType.Type); + Statistics.AddFilesystem(fs.XmlFsType.Type); } else DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); } @@ -491,7 +548,7 @@ namespace DiscImageChef.Commands { FileStream outputFile; string outputPath; - if(options.Xattrs) + if(extractXattrs) { error = fs.ListXAttr(entry, out List xattrs); if(error == Errno.NoError) @@ -501,14 +558,14 @@ namespace DiscImageChef.Commands error = fs.GetXattr(entry, xattr, ref xattrBuf); if(error != Errno.NoError) continue; - Directory.CreateDirectory(Path.Combine(options.OutputDir, + Directory.CreateDirectory(Path.Combine(outputDir, fs.XmlFsType.Type, volumeName, ".xattrs", xattr)); outputPath = - Path.Combine(options.OutputDir, fs.XmlFsType.Type, - volumeName, ".xattrs", xattr, entry); + Path.Combine(outputDir, fs.XmlFsType.Type, volumeName, + ".xattrs", xattr, entry); if(!File.Exists(outputPath)) { @@ -548,11 +605,10 @@ namespace DiscImageChef.Commands } } - Directory.CreateDirectory(Path.Combine(options.OutputDir, fs.XmlFsType.Type, + Directory.CreateDirectory(Path.Combine(outputDir, fs.XmlFsType.Type, volumeName)); - outputPath = - Path.Combine(options.OutputDir, fs.XmlFsType.Type, volumeName, entry); + outputPath = Path.Combine(outputDir, fs.XmlFsType.Type, volumeName, entry); if(!File.Exists(outputPath)) { @@ -603,7 +659,7 @@ namespace DiscImageChef.Commands else DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); - Core.Statistics.AddFilesystem(fs.XmlFsType.Type); + Statistics.AddFilesystem(fs.XmlFsType.Type); } else DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); } @@ -630,7 +686,7 @@ namespace DiscImageChef.Commands { string outputPath; FileStream outputFile; - if(options.Xattrs) + if(extractXattrs) { error = fs.ListXAttr(entry, out List xattrs); if(error == Errno.NoError) @@ -640,13 +696,12 @@ namespace DiscImageChef.Commands error = fs.GetXattr(entry, xattr, ref xattrBuf); if(error != Errno.NoError) continue; - Directory.CreateDirectory(Path.Combine(options.OutputDir, - fs.XmlFsType.Type, volumeName, - ".xattrs", xattr)); + Directory.CreateDirectory(Path.Combine(outputDir, fs.XmlFsType.Type, + volumeName, ".xattrs", xattr)); outputPath = - Path.Combine(options.OutputDir, fs.XmlFsType.Type, volumeName, - ".xattrs", xattr, entry); + Path.Combine(outputDir, fs.XmlFsType.Type, volumeName, ".xattrs", + xattr, entry); if(!File.Exists(outputPath)) { @@ -686,10 +741,9 @@ namespace DiscImageChef.Commands } } - Directory.CreateDirectory(Path.Combine(options.OutputDir, fs.XmlFsType.Type, - volumeName)); + Directory.CreateDirectory(Path.Combine(outputDir, fs.XmlFsType.Type, volumeName)); - outputPath = Path.Combine(options.OutputDir, fs.XmlFsType.Type, volumeName, entry); + outputPath = Path.Combine(outputDir, fs.XmlFsType.Type, volumeName, entry); if(!File.Exists(outputPath)) { @@ -734,7 +788,7 @@ namespace DiscImageChef.Commands } else DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); - Core.Statistics.AddFilesystem(fs.XmlFsType.Type); + Statistics.AddFilesystem(fs.XmlFsType.Type); } else DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); } @@ -745,7 +799,8 @@ namespace DiscImageChef.Commands DicConsole.DebugWriteLine("Extract-Files command", ex.StackTrace); } - Core.Statistics.AddCommand("extract-files"); + Statistics.AddCommand("extract-files"); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/Formats.cs b/DiscImageChef/Commands/Formats.cs index 155708837..c23e2e2f9 100644 --- a/DiscImageChef/Commands/Formats.cs +++ b/DiscImageChef/Commands/Formats.cs @@ -37,20 +37,59 @@ using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.Console; using DiscImageChef.Core; using DiscImageChef.Partitions; +using Mono.Options; namespace DiscImageChef.Commands { - static class Formats + class FormatsCommand : Command { - internal static void ListFormats(FormatsOptions formatsOptions) + bool showHelp; + + public FormatsCommand() : base("formats", + "Lists all supported disc images, partition schemes and file systems.") { + 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 arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 0) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + DicConsole.DebugWriteLine("Formats command", "--debug={0}", MainClass.Debug); + DicConsole.DebugWriteLine("Formats command", "--verbose={0}", MainClass.Verbose); + PluginBase plugins = GetPluginBase.Instance; FiltersList filtersList = new FiltersList(); DicConsole.WriteLine("Supported filters ({0}):", filtersList.Filters.Count); - if(formatsOptions.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tFilter"); + if(MainClass.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tFilter"); foreach(KeyValuePair kvp in filtersList.Filters) - if(formatsOptions.Verbose) + if(MainClass.Verbose) DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); else DicConsole.WriteLine(kvp.Value.Name); @@ -59,22 +98,22 @@ namespace DiscImageChef.Commands DicConsole.WriteLine("Read-only media image formats ({0}):", plugins.ImagePluginsList.Count(t => !t.Value.GetType().GetInterfaces() .Contains(typeof(IWritableImage)))); - if(formatsOptions.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin"); + if(MainClass.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin"); foreach(KeyValuePair kvp in plugins.ImagePluginsList.Where(t => !t.Value.GetType() .GetInterfaces() .Contains(typeof( IWritableImage )))) - if(formatsOptions.Verbose) + if(MainClass.Verbose) DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); else DicConsole.WriteLine(kvp.Value.Name); DicConsole.WriteLine(); DicConsole.WriteLine("Read/write media image formats ({0}):", plugins.WritableImages.Count); - if(formatsOptions.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin"); + if(MainClass.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin"); foreach(KeyValuePair kvp in plugins.WritableImages) - if(formatsOptions.Verbose) + if(MainClass.Verbose) DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); else DicConsole.WriteLine(kvp.Value.Name); @@ -83,13 +122,13 @@ namespace DiscImageChef.Commands DicConsole.WriteLine("Supported filesystems for identification and information only ({0}):", plugins.PluginsList.Count(t => !t.Value.GetType().GetInterfaces() .Contains(typeof(IReadOnlyFilesystem)))); - if(formatsOptions.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin"); + if(MainClass.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin"); foreach(KeyValuePair kvp in plugins.PluginsList.Where(t => !t.Value.GetType() .GetInterfaces() .Contains(typeof( IReadOnlyFilesystem )))) - if(formatsOptions.Verbose) + if(MainClass.Verbose) DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); else DicConsole.WriteLine(kvp.Value.Name); @@ -97,23 +136,24 @@ namespace DiscImageChef.Commands DicConsole.WriteLine(); DicConsole.WriteLine("Supported filesystems that can read their contents ({0}):", plugins.ReadOnlyFilesystems.Count); - if(formatsOptions.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin"); + if(MainClass.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin"); foreach(KeyValuePair kvp in plugins.ReadOnlyFilesystems) - if(formatsOptions.Verbose) + if(MainClass.Verbose) DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); else DicConsole.WriteLine(kvp.Value.Name); DicConsole.WriteLine(); DicConsole.WriteLine("Supported partitioning schemes ({0}):", plugins.PartPluginsList.Count); - if(formatsOptions.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin"); + if(MainClass.Verbose) DicConsole.VerboseWriteLine("GUID\t\t\t\t\tPlugin"); foreach(KeyValuePair kvp in plugins.PartPluginsList) - if(formatsOptions.Verbose) + if(MainClass.Verbose) DicConsole.VerboseWriteLine("{0}\t{1}", kvp.Value.Id, kvp.Value.Name); else DicConsole.WriteLine(kvp.Value.Name); - Core.Statistics.AddCommand("formats"); + Statistics.AddCommand("formats"); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/Gui.cs b/DiscImageChef/Commands/Gui.cs new file mode 100644 index 000000000..d22b99646 --- /dev/null +++ b/DiscImageChef/Commands/Gui.cs @@ -0,0 +1,83 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : Gui.cs +// Author(s) : Natalia Portillo +// +// Component : Verbs. +// +// --[ Description ] ---------------------------------------------------------- +// +// Implements the 'gui' verb. +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2019 Natalia Portillo +// ****************************************************************************/ + +using System.Collections.Generic; +using DiscImageChef.Console; +using DiscImageChef.Gui.Forms; +using Eto; +using Eto.Forms; +using Mono.Options; +using Command = Mono.Options.Command; + +namespace DiscImageChef.Commands +{ + class GuiCommand : Command + { + bool showHelp; + + public GuiCommand() : base("gui", "Opens the in-progress GUI.") + { + 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 arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + if(extra.Count > 0) + { + MainClass.PrintCopyright(); + + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + new Application(Platform.Detect).Run(new frmMain(MainClass.Debug, MainClass.Verbose)); + return 0; + } + } +} \ No newline at end of file diff --git a/DiscImageChef/Commands/ImageInfo.cs b/DiscImageChef/Commands/ImageInfo.cs index 722cfa7dc..649704954 100644 --- a/DiscImageChef/Commands/ImageInfo.cs +++ b/DiscImageChef/Commands/ImageInfo.cs @@ -31,28 +31,75 @@ // ****************************************************************************/ using System; +using System.Collections.Generic; using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.Console; using DiscImageChef.Core; +using Mono.Options; namespace DiscImageChef.Commands { - static class ImageInfo + class ImageInfoCommand : Command { - internal static void GetImageInfo(ImageInfoOptions options) + string inputFile; + + bool showHelp; + + public ImageInfoCommand() : base("image-info", + "Opens a media image and shows information about the media it represents and metadata.") { - DicConsole.DebugWriteLine("Analyze command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Analyze command", "--verbose={0}", options.Verbose); - DicConsole.DebugWriteLine("Analyze command", "--input={0}", options.InputFile); + Options = new OptionSet + { + $"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", + $"{MainClass.AssemblyCopyright}", + "", + $"usage: DiscImageChef {Name} imagefile", + "", + Help, + {"help|h|?", "Show this message and exit.", v => showHelp = v != null} + }; + } + + public override int Invoke(IEnumerable arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 1) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count == 0) + { + DicConsole.ErrorWriteLine("Missing input image."); + return 1; + } + + 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(options.InputFile); + IFilter inputFilter = filtersList.GetFilter(inputFile); if(inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); - return; + return 1; } try @@ -62,7 +109,7 @@ namespace DiscImageChef.Commands if(imageFormat == null) { DicConsole.WriteLine("Image format not identified."); - return; + return 2; } DicConsole.WriteLine("Image format identified by {0} ({1}).", imageFormat.Name, imageFormat.Id); @@ -74,14 +121,14 @@ namespace DiscImageChef.Commands { DicConsole.WriteLine("Unable to open image format"); DicConsole.WriteLine("No error given"); - return; + return 3; } - Core.ImageInfo.PrintImageInfo(imageFormat); + ImageInfo.PrintImageInfo(imageFormat); - Core.Statistics.AddMediaFormat(imageFormat.Format); - Core.Statistics.AddMedia(imageFormat.Info.MediaType, false); - Core.Statistics.AddFilter(inputFilter.Name); + Statistics.AddMediaFormat(imageFormat.Format); + Statistics.AddMedia(imageFormat.Info.MediaType, false); + Statistics.AddFilter(inputFilter.Name); } catch(Exception ex) { @@ -96,7 +143,8 @@ namespace DiscImageChef.Commands DicConsole.DebugWriteLine("Image-info command", ex.StackTrace); } - Core.Statistics.AddCommand("image-info"); + Statistics.AddCommand("image-info"); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/ListDevices.cs b/DiscImageChef/Commands/ListDevices.cs index 380c14844..3bfa29dda 100644 --- a/DiscImageChef/Commands/ListDevices.cs +++ b/DiscImageChef/Commands/ListDevices.cs @@ -30,20 +30,57 @@ // Copyright © 2011-2019 Natalia Portillo // ****************************************************************************/ +using System.Collections.Generic; using System.Linq; using DiscImageChef.Console; +using DiscImageChef.Core; using DiscImageChef.Devices; +using Mono.Options; namespace DiscImageChef.Commands { - static class ListDevices + class ListDevicesCommand : Command { - internal static void DoListDevices(ListDevicesOptions options) - { - DicConsole.DebugWriteLine("Media-Info command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Media-Info command", "--verbose={0}", options.Verbose); + bool showHelp; - Devices.DeviceInfo[] devices = Device.ListDevices(); + public ListDevicesCommand() : base("list-devices", "Lists all connected devices.") + { + 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 arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 0) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + DicConsole.DebugWriteLine("List-Devices command", "--debug={0}", MainClass.Debug); + DicConsole.DebugWriteLine("List-Devices command", "--verbose={0}", MainClass.Verbose); + + DeviceInfo[] devices = Device.ListDevices(); if(devices == null || devices.Length == 0) DicConsole.WriteLine("No known devices attached."); else @@ -55,12 +92,13 @@ namespace DiscImageChef.Commands DicConsole.WriteLine("{0,-22}+{1,-16}+{2,-24}+{3,-24}+{4,-10}+{5,-10}", "----------------------", "----------------", "------------------------", "------------------------", "----------", "----------"); - foreach(Devices.DeviceInfo dev in devices) + foreach(DeviceInfo dev in devices) DicConsole.WriteLine("{0,-22}|{1,-16}|{2,-24}|{3,-24}|{4,-10}|{5,-10}", dev.Path, dev.Vendor, dev.Model, dev.Serial, dev.Bus, dev.Supported); } - Core.Statistics.AddCommand("list-devices"); + Statistics.AddCommand("list-devices"); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/ListEncodings.cs b/DiscImageChef/Commands/ListEncodings.cs index 55dc7f7ab..deb205bd5 100644 --- a/DiscImageChef/Commands/ListEncodings.cs +++ b/DiscImageChef/Commands/ListEncodings.cs @@ -34,13 +34,52 @@ using System.Collections.Generic; using System.Linq; using System.Text; using DiscImageChef.Console; +using DiscImageChef.Core; +using Mono.Options; namespace DiscImageChef.Commands { - static class ListEncodings + class ListEncodingsCommand : Command { - internal static void DoList() + bool showHelp; + + public ListEncodingsCommand() : base("list-encodings", "Lists all supported text encodings and code pages.") { + 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 arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 0) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + DicConsole.DebugWriteLine("List-Encodings command", "--debug={0}", MainClass.Debug); + DicConsole.DebugWriteLine("List-Encodings command", "--verbose={0}", MainClass.Verbose); + List encodings = Encoding .GetEncodings().Select(info => new CommonEncodingInfo { @@ -59,7 +98,8 @@ namespace DiscImageChef.Commands foreach(CommonEncodingInfo info in encodings.OrderBy(t => t.DisplayName)) DicConsole.WriteLine("{0,-16} {1,-8}", info.Name, info.DisplayName); - Core.Statistics.AddCommand("list-encodings"); + Statistics.AddCommand("list-encodings"); + return 0; } struct CommonEncodingInfo diff --git a/DiscImageChef/Commands/ListOptions.cs b/DiscImageChef/Commands/ListOptions.cs index b8d427041..9c1c8ed25 100644 --- a/DiscImageChef/Commands/ListOptions.cs +++ b/DiscImageChef/Commands/ListOptions.cs @@ -37,13 +37,52 @@ using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.Console; using DiscImageChef.Core; +using Mono.Options; namespace DiscImageChef.Commands { - static class ListOptions + class ListOptionsCommand : Command { - internal static void DoList() + bool showHelp; + + public ListOptionsCommand() : base("list-options", + "Lists all options supported by read-only filesystems and writable media images.") { + 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 arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 0) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + DicConsole.DebugWriteLine("List-Options command", "--debug={0}", MainClass.Debug); + DicConsole.DebugWriteLine("List-Options command", "--verbose={0}", MainClass.Verbose); + PluginBase plugins = GetPluginBase.Instance; DicConsole.WriteLine("Read-only filesystems options:"); @@ -77,6 +116,8 @@ namespace DiscImageChef.Commands option.@default, option.description); DicConsole.WriteLine(); } + + return 0; } static string TypeToString(Type type) diff --git a/DiscImageChef/Commands/Ls.cs b/DiscImageChef/Commands/Ls.cs index 2d414dc2e..931034931 100644 --- a/DiscImageChef/Commands/Ls.cs +++ b/DiscImageChef/Commands/Ls.cs @@ -38,44 +38,99 @@ using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.CommonTypes.Structs; using DiscImageChef.Console; using DiscImageChef.Core; +using Mono.Options; namespace DiscImageChef.Commands { - static class Ls + class LsCommand : Command { - internal static void DoLs(LsOptions options) + string encodingName; + string inputFile; + bool longFormat; + string pluginOptions; + bool showHelp; + + public LsCommand() : base("ls", "Lists files in disc image.") { - DicConsole.DebugWriteLine("Ls command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Ls command", "--verbose={0}", options.Verbose); - DicConsole.DebugWriteLine("Ls command", "--input={0}", options.InputFile); + Options = new OptionSet + { + $"{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.", + s => pluginOptions = s + }, + {"help|h|?", "Show this message and exit.", v => showHelp = v != null} + }; + } + + public override int Invoke(IEnumerable arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 1) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count == 0) + { + DicConsole.ErrorWriteLine("Missing input image."); + return 1; + } + + inputFile = extra[0]; + + DicConsole.DebugWriteLine("Ls command", "--debug={0}", MainClass.Debug); + DicConsole.DebugWriteLine("Ls command", "--encoding={0}", encodingName); + DicConsole.DebugWriteLine("Ls command", "--input={0}", inputFile); + DicConsole.DebugWriteLine("Ls command", "--options={0}", pluginOptions); + DicConsole.DebugWriteLine("Ls command", "--verbose={0}", MainClass.Verbose); FiltersList filtersList = new FiltersList(); - IFilter inputFilter = filtersList.GetFilter(options.InputFile); + IFilter inputFilter = filtersList.GetFilter(inputFile); - Dictionary parsedOptions = Options.Parse(options.Options); + Dictionary parsedOptions = Core.Options.Parse(pluginOptions); DicConsole.DebugWriteLine("Ls command", "Parsed options:"); foreach(KeyValuePair parsedOption in parsedOptions) DicConsole.DebugWriteLine("Ls command", "{0} = {1}", parsedOption.Key, parsedOption.Value); - parsedOptions.Add("debug", options.Debug.ToString()); + parsedOptions.Add("debug", MainClass.Debug.ToString()); if(inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); - return; + return 1; } Encoding encoding = null; - if(options.EncodingName != null) + if(encodingName != null) try { - encoding = Claunia.Encoding.Encoding.GetEncoding(options.EncodingName); - if(options.Verbose) DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName); + encoding = Claunia.Encoding.Encoding.GetEncoding(encodingName); + if(MainClass.Verbose) DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName); } catch(ArgumentException) { DicConsole.ErrorWriteLine("Specified encoding is not supported."); - return; + return 2; } PluginBase plugins = GetPluginBase.Instance; @@ -87,10 +142,10 @@ namespace DiscImageChef.Commands if(imageFormat == null) { DicConsole.WriteLine("Image format not identified, not proceeding with analysis."); - return; + return 3; } - if(options.Verbose) + if(MainClass.Verbose) DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name, imageFormat.Id); else DicConsole.WriteLine("Image format identified by {0}.", imageFormat.Name); @@ -101,7 +156,7 @@ namespace DiscImageChef.Commands { DicConsole.WriteLine("Unable to open image format"); DicConsole.WriteLine("No error given"); - return; + return 4; } DicConsole.DebugWriteLine("Ls command", "Correctly opened image file."); @@ -111,15 +166,15 @@ namespace DiscImageChef.Commands DicConsole.DebugWriteLine("Ls command", "Image identifies disk type as {0}.", imageFormat.Info.MediaType); - Core.Statistics.AddMediaFormat(imageFormat.Format); - Core.Statistics.AddMedia(imageFormat.Info.MediaType, false); - Core.Statistics.AddFilter(inputFilter.Name); + Statistics.AddMediaFormat(imageFormat.Format); + Statistics.AddMedia(imageFormat.Info.MediaType, false); + Statistics.AddFilter(inputFilter.Name); } catch(Exception ex) { DicConsole.ErrorWriteLine("Unable to open image format"); DicConsole.ErrorWriteLine("Error: {0}", ex.Message); - return; + return 3; } List partitions = Core.Partitions.GetAll(imageFormat); @@ -168,7 +223,7 @@ namespace DiscImageChef.Commands DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); - Core.Statistics.AddFilesystem(fs.XmlFsType.Type); + Statistics.AddFilesystem(fs.XmlFsType.Type); } else DicConsole.ErrorWriteLine("Unable to mount device, error {0}", @@ -196,7 +251,7 @@ namespace DiscImageChef.Commands else DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); - Core.Statistics.AddFilesystem(fs.XmlFsType.Type); + Statistics.AddFilesystem(fs.XmlFsType.Type); } else DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); } @@ -235,7 +290,7 @@ namespace DiscImageChef.Commands else DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); - Core.Statistics.AddFilesystem(fs.XmlFsType.Type); + Statistics.AddFilesystem(fs.XmlFsType.Type); } else DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); } @@ -257,7 +312,7 @@ namespace DiscImageChef.Commands error = fs.ReadDir("/", out List rootDir); if(error == Errno.NoError) foreach(string entry in rootDir) - if(options.Long) + if(longFormat) { error = fs.Stat(entry, out FileEntryInfo stat); if(error == Errno.NoError) @@ -284,7 +339,7 @@ namespace DiscImageChef.Commands else DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); - Core.Statistics.AddFilesystem(fs.XmlFsType.Type); + Statistics.AddFilesystem(fs.XmlFsType.Type); } else DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); } @@ -297,7 +352,8 @@ namespace DiscImageChef.Commands DicConsole.DebugWriteLine("Ls command", ex.StackTrace); } - Core.Statistics.AddCommand("ls"); + Statistics.AddCommand("ls"); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/MediaInfo.cs b/DiscImageChef/Commands/MediaInfo.cs index 6c3f53c5e..9de055a29 100644 --- a/DiscImageChef/Commands/MediaInfo.cs +++ b/DiscImageChef/Commands/MediaInfo.cs @@ -44,6 +44,7 @@ using DiscImageChef.Decoders.SCSI.MMC; using DiscImageChef.Decoders.SCSI.SSC; using DiscImageChef.Decoders.Xbox; using DiscImageChef.Devices; +using Mono.Options; using BCA = DiscImageChef.Decoders.Bluray.BCA; using Cartridge = DiscImageChef.Decoders.DVD.Cartridge; using DDS = DiscImageChef.Decoders.DVD.DDS; @@ -52,28 +53,75 @@ using Spare = DiscImageChef.Decoders.DVD.Spare; namespace DiscImageChef.Commands { - static class MediaInfo + class MediaInfoCommand : Command { - internal static void DoMediaInfo(MediaInfoOptions options) + string devicePath; + string outputPrefix; + bool showHelp; + + public MediaInfoCommand() : base("media-info", "Gets information about the media inserted on a device.") { - DicConsole.DebugWriteLine("Media-Info command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Media-Info command", "--verbose={0}", options.Verbose); - DicConsole.DebugWriteLine("Media-Info command", "--device={0}", options.DevicePath); - DicConsole.DebugWriteLine("Media-Info command", "--output-prefix={0}", options.OutputPrefix); + 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 + } + }; + } - if(options.DevicePath.Length == 2 && options.DevicePath[1] == ':' && options.DevicePath[0] != '/' && - char.IsLetter(options.DevicePath[0])) - options.DevicePath = "\\\\.\\" + char.ToUpper(options.DevicePath[0]) + ':'; + public override int Invoke(IEnumerable arguments) + { + List extra = Options.Parse(arguments); - Device dev = new Device(options.DevicePath); + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 1) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count == 0) + { + DicConsole.ErrorWriteLine("Missing device path."); + return 1; + } + + 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", "--output-prefix={0}", outputPrefix); + DicConsole.DebugWriteLine("Media-Info command", "--verbose={0}", MainClass.Verbose); + + if(devicePath.Length == 2 && devicePath[1] == ':' && devicePath[0] != '/' && char.IsLetter(devicePath[0])) + devicePath = "\\\\.\\" + char.ToUpper(devicePath[0]) + ':'; + + Device dev = new Device(devicePath); if(dev.Error) { DicConsole.ErrorWriteLine("Error {0} opening device.", dev.LastError); - return; + return 1; } - Core.Statistics.AddDevice(dev); + Statistics.AddDevice(dev); switch(dev.Type) { @@ -85,16 +133,18 @@ namespace DiscImageChef.Commands DoSdMediaInfo(); break; case DeviceType.NVMe: - DoNvmeMediaInfo(options.OutputPrefix, dev); + DoNvmeMediaInfo(outputPrefix, dev); break; case DeviceType.ATAPI: case DeviceType.SCSI: - DoScsiMediaInfo(options.OutputPrefix, dev); + DoScsiMediaInfo(outputPrefix, dev); break; default: throw new NotSupportedException("Unknown device type."); } - Core.Statistics.AddCommand("media-info"); + Statistics.AddCommand("media-info"); + + return 0; } static void DoAtaMediaInfo() @@ -451,7 +501,7 @@ namespace DiscImageChef.Commands } DicConsole.WriteLine("Media identified as {0}", scsiInfo.MediaType); - Core.Statistics.AddMedia(scsiInfo.MediaType, true); + Statistics.AddMedia(scsiInfo.MediaType, true); dev.Close(); } diff --git a/DiscImageChef/Commands/MediaScan.cs b/DiscImageChef/Commands/MediaScan.cs index 36937cf60..4bcdff841 100644 --- a/DiscImageChef/Commands/MediaScan.cs +++ b/DiscImageChef/Commands/MediaScan.cs @@ -31,54 +31,103 @@ // ****************************************************************************/ using System; +using System.Collections.Generic; using DiscImageChef.CommonTypes.Enums; using DiscImageChef.Console; +using DiscImageChef.Core; using DiscImageChef.Core.Devices.Scanning; using DiscImageChef.Devices; +using Mono.Options; namespace DiscImageChef.Commands { - static class MediaScan + class MediaScanCommand : Command { - internal static void DoMediaScan(MediaScanOptions options) + string devicePath; + string ibgLogPath; + string mhddLogPath; + bool showHelp; + + public MediaScanCommand() : base("media-scan", "Scans the media inserted on a device.") { - DicConsole.DebugWriteLine("Media-Scan command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Media-Scan command", "--verbose={0}", options.Verbose); - DicConsole.DebugWriteLine("Media-Scan command", "--device={0}", options.DevicePath); - DicConsole.DebugWriteLine("Media-Scan command", "--mhdd-log={0}", options.MhddLogPath); - DicConsole.DebugWriteLine("Media-Scan command", "--ibg-log={0}", options.IbgLogPath); + 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} + }; + } - if(options.DevicePath.Length == 2 && options.DevicePath[1] == ':' && options.DevicePath[0] != '/' && - char.IsLetter(options.DevicePath[0])) - options.DevicePath = "\\\\.\\" + char.ToUpper(options.DevicePath[0]) + ':'; + public override int Invoke(IEnumerable arguments) + { + List extra = Options.Parse(arguments); - Device dev = new Device(options.DevicePath); + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 1) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count == 0) + { + DicConsole.ErrorWriteLine("Missing device path."); + return 1; + } + + 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", "--ibg-log={0}", ibgLogPath); + DicConsole.DebugWriteLine("Media-Scan command", "--mhdd-log={0}", mhddLogPath); + DicConsole.DebugWriteLine("Media-Scan command", "--verbose={0}", MainClass.Verbose); + + if(devicePath.Length == 2 && devicePath[1] == ':' && devicePath[0] != '/' && char.IsLetter(devicePath[0])) + devicePath = "\\\\.\\" + char.ToUpper(devicePath[0]) + ':'; + + Device dev = new Device(devicePath); if(dev.Error) { DicConsole.ErrorWriteLine("Error {0} opening device.", dev.LastError); - return; + return 1; } - Core.Statistics.AddDevice(dev); + Statistics.AddDevice(dev); ScanResults results; switch(dev.Type) { case DeviceType.ATA: - results = Ata.Scan(options.MhddLogPath, options.IbgLogPath, options.DevicePath, dev); + results = Ata.Scan(mhddLogPath, ibgLogPath, devicePath, dev); break; case DeviceType.MMC: case DeviceType.SecureDigital: - results = SecureDigital.Scan(options.MhddLogPath, options.IbgLogPath, options.DevicePath, dev); + results = SecureDigital.Scan(mhddLogPath, ibgLogPath, devicePath, dev); break; case DeviceType.NVMe: - results = Nvme.Scan(options.MhddLogPath, options.IbgLogPath, options.DevicePath, dev); + results = Nvme.Scan(mhddLogPath, ibgLogPath, devicePath, dev); break; case DeviceType.ATAPI: case DeviceType.SCSI: - results = Scsi.Scan(options.MhddLogPath, options.IbgLogPath, options.DevicePath, dev); + results = Scsi.Scan(mhddLogPath, ibgLogPath, devicePath, dev); break; default: throw new NotSupportedException("Unknown device type."); } @@ -109,9 +158,10 @@ namespace DiscImageChef.Commands 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); - Core.Statistics.AddCommand("media-scan"); + Statistics.AddCommand("media-scan"); dev.Close(); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/PrintHex.cs b/DiscImageChef/Commands/PrintHex.cs index 231dbfe31..5a636b6bc 100644 --- a/DiscImageChef/Commands/PrintHex.cs +++ b/DiscImageChef/Commands/PrintHex.cs @@ -30,32 +30,91 @@ // Copyright © 2011-2019 Natalia Portillo // ****************************************************************************/ +using System.Collections.Generic; using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.Console; using DiscImageChef.Core; +using Mono.Options; namespace DiscImageChef.Commands { - static class PrintHex + class PrintHexCommand : Command { - internal static void DoPrintHex(PrintHexOptions options) + 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.") { - DicConsole.DebugWriteLine("PrintHex command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("PrintHex command", "--verbose={0}", options.Verbose); - DicConsole.DebugWriteLine("PrintHex command", "--input={0}", options.InputFile); - DicConsole.DebugWriteLine("PrintHex command", "--start={0}", options.StartSector); - DicConsole.DebugWriteLine("PrintHex command", "--length={0}", options.Length); - DicConsole.DebugWriteLine("PrintHex command", "--long-sectors={0}", options.LongSectors); - DicConsole.DebugWriteLine("PrintHex command", "--WidthBytes={0}", options.WidthBytes); + Options = new OptionSet + { + $"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", + $"{MainClass.AssemblyCopyright}", + "", + $"usage: DiscImageChef {Name} [OPTIONS] imagefile", + "", + 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 arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 1) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count == 0) + { + DicConsole.ErrorWriteLine("Missing input image."); + return 1; + } + + if(startSector is null) + { + DicConsole.ErrorWriteLine("Missing starting sector."); + return 1; + } + + 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", "--start={0}", startSector); + DicConsole.DebugWriteLine("PrintHex command", "--verbose={0}", MainClass.Verbose); + DicConsole.DebugWriteLine("PrintHex command", "--WidthBytes={0}", widthBytes); FiltersList filtersList = new FiltersList(); - IFilter inputFilter = filtersList.GetFilter(options.InputFile); + IFilter inputFilter = filtersList.GetFilter(inputFile); if(inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); - return; + return 1; } IMediaImage inputFormat = ImageFormat.Detect(inputFilter); @@ -63,20 +122,20 @@ namespace DiscImageChef.Commands if(inputFormat == null) { DicConsole.ErrorWriteLine("Unable to recognize image format, not verifying"); - return; + return 2; } inputFormat.Open(inputFilter); - for(ulong i = 0; i < options.Length; i++) + for(ulong i = 0; i < length; i++) { - DicConsole.WriteLine("Sector {0}", options.StartSector + i); + DicConsole.WriteLine("Sector {0}", startSector + i); if(inputFormat.Info.ReadableSectorTags == null) { DicConsole .WriteLine("Requested sectors with tags, unsupported by underlying image format, printing only user data."); - options.LongSectors = false; + longSectors = false; } else { @@ -84,18 +143,19 @@ namespace DiscImageChef.Commands { DicConsole .WriteLine("Requested sectors with tags, unsupported by underlying image format, printing only user data."); - options.LongSectors = false; + longSectors = false; } } - byte[] sector = options.LongSectors - ? inputFormat.ReadSectorLong(options.StartSector + i) - : inputFormat.ReadSector(options.StartSector + i); + byte[] sector = longSectors + ? inputFormat.ReadSectorLong(startSector.Value + i) + : inputFormat.ReadSector(startSector.Value + i); - DiscImageChef.PrintHex.PrintHexArray(sector, options.WidthBytes); + PrintHex.PrintHexArray(sector, widthBytes); } - Core.Statistics.AddCommand("print-hex"); + Statistics.AddCommand("print-hex"); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/Statistics.cs b/DiscImageChef/Commands/Statistics.cs index c19309df0..4a1166614 100644 --- a/DiscImageChef/Commands/Statistics.cs +++ b/DiscImageChef/Commands/Statistics.cs @@ -30,24 +30,61 @@ // Copyright © 2011-2019 Natalia Portillo // ****************************************************************************/ +using System.Collections.Generic; using System.Linq; using DiscImageChef.Console; using DiscImageChef.Database; using DiscImageChef.Database.Models; +using Mono.Options; +using Command = Mono.Options.Command; namespace DiscImageChef.Commands { - static class Statistics + class StatisticsCommand : Command { - internal static void ShowStats() + bool showHelp; + + public StatisticsCommand() : base("stats", "Shows statistics.") { + 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 arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 0) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + DicContext ctx = DicContext.Create(Settings.Settings.LocalDbPath); 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."); - return; + return 1; } bool thereAreStats = false; @@ -198,6 +235,7 @@ namespace DiscImageChef.Commands } if(!thereAreStats) DicConsole.WriteLine("There are no statistics."); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/Update.cs b/DiscImageChef/Commands/Update.cs index 7cf529b57..64189251f 100644 --- a/DiscImageChef/Commands/Update.cs +++ b/DiscImageChef/Commands/Update.cs @@ -30,25 +30,67 @@ // Copyright © 2011-2019 Natalia Portillo // ****************************************************************************/ +using System.Collections.Generic; using DiscImageChef.Console; using DiscImageChef.Core; +using Mono.Options; namespace DiscImageChef.Commands { - static class Update + class UpdateCommand : Command { - internal static void DoUpdate(UpdateOptions options) + readonly bool masterDbUpdate; + bool showHelp; + + public UpdateCommand(bool masterDbUpdate) : base("update", "Updates the database.") { - DicConsole.DebugWriteLine("Media-Info command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Media-Info command", "--verbose={0}", options.Verbose); + this.masterDbUpdate = masterDbUpdate; + 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 arguments) + { + if(masterDbUpdate) return 0; + + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 0) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + DicConsole.DebugWriteLine("Update command", "--debug={0}", MainClass.Debug); + DicConsole.DebugWriteLine("Update command", "--verbose={0}", MainClass.Verbose); DoUpdate(false); + + return 0; } internal static void DoUpdate(bool create) { Remote.UpdateMasterDatabase(create); - Core.Statistics.AddCommand("update"); + Statistics.AddCommand("update"); } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/Verify.cs b/DiscImageChef/Commands/Verify.cs index e3353e218..b97dc4785 100644 --- a/DiscImageChef/Commands/Verify.cs +++ b/DiscImageChef/Commands/Verify.cs @@ -37,26 +37,74 @@ using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.CommonTypes.Structs; using DiscImageChef.Console; using DiscImageChef.Core; +using Mono.Options; namespace DiscImageChef.Commands { - static class Verify + class VerifyCommand : Command { - internal static void DoVerify(VerifyOptions options) + string inputFile; + bool showHelp; + bool verifyDisc = true; + bool verifySectors = true; + + public VerifyCommand() : base("verify", "Verifies a disc image integrity, and if supported, sector integrity.") { - DicConsole.DebugWriteLine("Verify command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Verify command", "--verbose={0}", options.Verbose); - DicConsole.DebugWriteLine("Verify command", "--input={0}", options.InputFile); - DicConsole.DebugWriteLine("Verify command", "--verify-disc={0}", options.VerifyDisc); - DicConsole.DebugWriteLine("Verify command", "--verify-sectors={0}", options.VerifySectors); + Options = new OptionSet + { + $"{MainClass.AssemblyTitle} {MainClass.AssemblyVersion?.InformationalVersion}", + $"{MainClass.AssemblyCopyright}", + "", + $"usage: DiscImageChef {Name} [OPTIONS] imagefile", + "", + 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 arguments) + { + List extra = Options.Parse(arguments); + + if(showHelp) + { + Options.WriteOptionDescriptions(CommandSet.Out); + return 0; + } + + MainClass.PrintCopyright(); + if(MainClass.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if(MainClass.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + + if(extra.Count > 1) + { + DicConsole.ErrorWriteLine("Too many arguments."); + return 1; + } + + if(extra.Count == 0) + { + DicConsole.ErrorWriteLine("Missing input image."); + return 1; + } + + 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); FiltersList filtersList = new FiltersList(); - IFilter inputFilter = filtersList.GetFilter(options.InputFile); + IFilter inputFilter = filtersList.GetFilter(inputFile); if(inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); - return; + return 1; } IMediaImage inputFormat = ImageFormat.Detect(inputFilter); @@ -64,13 +112,13 @@ namespace DiscImageChef.Commands if(inputFormat == null) { DicConsole.ErrorWriteLine("Unable to recognize image format, not verifying"); - return; + return 2; } inputFormat.Open(inputFilter); - Core.Statistics.AddMediaFormat(inputFormat.Format); - Core.Statistics.AddMedia(inputFormat.Info.MediaType, false); - Core.Statistics.AddFilter(inputFilter.Name); + Statistics.AddMediaFormat(inputFormat.Format); + Statistics.AddMedia(inputFormat.Info.MediaType, false); + Statistics.AddFilter(inputFilter.Name); bool? correctDisc = null; long totalSectors = 0; @@ -78,7 +126,7 @@ namespace DiscImageChef.Commands long correctSectors = 0; long unknownSectors = 0; - if(options.VerifyDisc) + if(verifyDisc) { DateTime startCheck = DateTime.UtcNow; bool? discCheckStatus = inputFormat.VerifyMediaImage(); @@ -103,7 +151,7 @@ namespace DiscImageChef.Commands DicConsole.VerboseWriteLine("Checking disc image checksums took {0} seconds", checkTime.TotalSeconds); } - if(options.VerifySectors) + if(verifySectors) { bool formatHasTracks; try @@ -215,7 +263,7 @@ namespace DiscImageChef.Commands DicConsole.VerboseWriteLine("Checking sector checksums took {0} seconds", checkTime.TotalSeconds); - if(options.Verbose) + if(MainClass.Verbose) { DicConsole.VerboseWriteLine("LBAs with error:"); if(failingLbas.Count == (int)inputFormat.Info.Sectors) @@ -243,7 +291,8 @@ namespace DiscImageChef.Commands correctSectors = totalSectors - errorSectors - unknownSectors; } - Core.Statistics.AddCommand("verify"); + Statistics.AddCommand("verify"); + return 0; } } } \ No newline at end of file diff --git a/DiscImageChef/DiscImageChef.csproj b/DiscImageChef/DiscImageChef.csproj index d54114a6c..2d310c493 100644 --- a/DiscImageChef/DiscImageChef.csproj +++ b/DiscImageChef/DiscImageChef.csproj @@ -53,11 +53,11 @@ + - @@ -262,11 +262,12 @@ - + + diff --git a/DiscImageChef/Main.cs b/DiscImageChef/Main.cs index eb2d2092f..5c44beb70 100644 --- a/DiscImageChef/Main.cs +++ b/DiscImageChef/Main.cs @@ -34,24 +34,35 @@ using System; using System.IO; using System.Reflection; using System.Threading.Tasks; -using CommandLine; using DiscImageChef.Commands; using DiscImageChef.Console; +using DiscImageChef.Core; using DiscImageChef.Database; -using DiscImageChef.Gui.Forms; using DiscImageChef.Settings; -using Eto; -using Eto.Forms; using Microsoft.EntityFrameworkCore; -using Statistics = DiscImageChef.Core.Statistics; +using Mono.Options; namespace DiscImageChef { class MainClass { + internal static bool Verbose; + internal static bool Debug; + internal static string AssemblyCopyright; + internal static string AssemblyTitle; + internal static AssemblyInformationalVersionAttribute AssemblyVersion; + [STAThread] - public static void Main(string[] args) + public static int Main(string[] args) { + object[] attributes = typeof(MainClass).Assembly.GetCustomAttributes(typeof(AssemblyTitleAttribute), false); + AssemblyTitle = ((AssemblyTitleAttribute)attributes[0]).Title; + attributes = typeof(MainClass).Assembly.GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); + AssemblyVersion = + Attribute.GetCustomAttribute(typeof(MainClass).Assembly, typeof(AssemblyInformationalVersionAttribute)) + as AssemblyInformationalVersionAttribute; + AssemblyCopyright = ((AssemblyCopyrightAttribute)attributes[0]).Copyright; + DicConsole.WriteLineEvent += System.Console.WriteLine; DicConsole.WriteEvent += System.Console.Write; DicConsole.ErrorWriteLineEvent += System.Console.Error.WriteLine; @@ -66,7 +77,7 @@ namespace DiscImageChef if(!File.Exists(Settings.Settings.MasterDbPath)) { masterDbUpdate = true; - Update.DoUpdate(masterDbUpdate); + UpdateCommand.DoUpdate(masterDbUpdate); } DicContext mctx = DicContext.Create(Settings.Settings.MasterDbPath); @@ -74,193 +85,63 @@ namespace DiscImageChef mctx.SaveChanges(); if((args.Length < 1 || args[0].ToLowerInvariant() != "gui") && - Settings.Settings.Current.GdprCompliance < DicSettings.GdprLevel) Configure.DoConfigure(true); + Settings.Settings.Current.GdprCompliance < DicSettings.GdprLevel) + new ConfigureCommand(true).Invoke(args); Statistics.LoadStats(); if(Settings.Settings.Current.Stats != null && Settings.Settings.Current.Stats.ShareStats) Task.Run(() => { Statistics.SubmitStats(); }); - Parser.Default.ParseArguments(args, typeof(AnalyzeOptions), typeof(BenchmarkOptions), - typeof(ChecksumOptions), typeof(CompareOptions), typeof(ConfigureOptions), - typeof(ConvertImageOptions), typeof(CreateSidecarOptions), - typeof(DecodeOptions), typeof(DeviceInfoOptions), typeof(DeviceReportOptions), - typeof(DumpMediaOptions), typeof(EntropyOptions), typeof(ExtractFilesOptions), - typeof(FormatsOptions), typeof(ImageInfoOptions), typeof(ListDevicesOptions), - typeof(ListEncodingsOptions), typeof(ListOptionsOptions), typeof(LsOptions), - typeof(MediaInfoOptions), typeof(MediaScanOptions), typeof(PrintHexOptions), - typeof(StatsOptions), typeof(VerifyOptions), typeof(GuiOptions), - typeof(UpdateOptions)).WithParsed(opts => + CommandSet commands = new CommandSet("DiscImageChef") { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - Analyze.DoAnalyze(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - Compare.DoCompare(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - Checksum.DoChecksum(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - Entropy.DoEntropy(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - Verify.DoVerify(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - Commands.PrintHex.DoPrintHex(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - Decode.DoDecode(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - DeviceInfo.DoDeviceInfo(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - MediaInfo.DoMediaInfo(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - MediaScan.DoMediaScan(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - Formats.ListFormats(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - Benchmark.DoBenchmark(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - CreateSidecar.DoSidecar(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - DumpMedia.DoDumpMedia(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - DeviceReport.DoDeviceReport(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - Ls.DoLs(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - ExtractFiles.DoExtractFiles(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - ListDevices.DoListDevices(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - ListEncodings.DoList(); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - ListOptions.DoList(); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - ConvertImage.DoConvert(opts); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - PrintCopyright(); - ImageInfo.GetImageInfo(opts); - }).WithParsed(opts => - { - PrintCopyright(); - Configure.DoConfigure(false); - }).WithParsed(opts => - { - PrintCopyright(); - Commands.Statistics.ShowStats(); - }).WithParsed(opts => - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + $"{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), + new ConvertImageCommand(), + new CreateSidecarCommand(), + new DecodeCommand(), + new DeviceInfoCommand(), + new DeviceReportCommand(), + new DumpMediaCommand(), + new EntropyCommand(), + new ExtractFilesCommand(), + new FormatsCommand(), + new GuiCommand(), + new ImageInfoCommand(), + new ListDevicesCommand(), + new ListEncodingsCommand(), + new ListOptionsCommand(), + new LsCommand(), + new MediaInfoCommand(), + new MediaScanCommand(), + new PrintHexCommand(), + new StatisticsCommand(), + new UpdateCommand(masterDbUpdate), + new VerifyCommand() + }; - new Application(Platform.Detect).Run(new frmMain(opts.Debug, opts.Verbose)); - }).WithParsed(opts => - { - if(!masterDbUpdate) - { - if(opts.Debug) DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; - if(opts.Verbose) DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; - - Update.DoUpdate(opts); - } - }).WithNotParsed(errs => Environment.Exit(1)); + int ret = commands.Run(args); Statistics.SaveStats(); + + return ret; } - static void PrintCopyright() + internal static void PrintCopyright() { - object[] attributes = - typeof(MainClass).Assembly.GetCustomAttributes(typeof(AssemblyTitleAttribute), false); - string assemblyTitle = ((AssemblyTitleAttribute)attributes[0]).Title; - attributes = typeof(MainClass).Assembly.GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); - AssemblyInformationalVersionAttribute assemblyVersion = - Attribute.GetCustomAttribute(typeof(MainClass).Assembly, typeof(AssemblyInformationalVersionAttribute)) - as AssemblyInformationalVersionAttribute; - string assemblyCopyright = ((AssemblyCopyrightAttribute)attributes[0]).Copyright; - - DicConsole.WriteLine("{0} {1}", assemblyTitle, assemblyVersion?.InformationalVersion); - DicConsole.WriteLine("{0}", assemblyCopyright); + DicConsole.WriteLine("{0} {1}", AssemblyTitle, AssemblyVersion?.InformationalVersion); + DicConsole.WriteLine("{0}", AssemblyCopyright); DicConsole.WriteLine(); } } diff --git a/DiscImageChef/Options.cs b/DiscImageChef/Options.cs deleted file mode 100644 index 31c4bea18..000000000 --- a/DiscImageChef/Options.cs +++ /dev/null @@ -1,465 +0,0 @@ -// /*************************************************************************** -// The Disc Image Chef -// ---------------------------------------------------------------------------- -// -// Filename : Options.cs -// Author(s) : Natalia Portillo -// -// Component : Main program loop. -// -// --[ Description ] ---------------------------------------------------------- -// -// Defines verbs and options. -// -// --[ License ] -------------------------------------------------------------- -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General public License for more details. -// -// You should have received a copy of the GNU General public License -// along with this program. If not, see . -// -// ---------------------------------------------------------------------------- -// Copyright © 2011-2019 Natalia Portillo -// ****************************************************************************/ - -using CommandLine; - -// ReSharper disable MemberCanBeInternal -// ReSharper disable UnusedAutoPropertyAccessor.Global - -namespace DiscImageChef -{ - public abstract class CommonOptions - { - [Option('v', "verbose", Default = false, HelpText = "Shows verbose output")] - public bool Verbose { get; set; } - - [Option('d', "debug", Default = false, HelpText = "Shows debug output from plugins")] - public bool Debug { get; set; } - } - - [Verb("analyze", HelpText = "Analyzes a disc image and searches for partitions and/or filesystems.")] - public class AnalyzeOptions : CommonOptions - { - [Option('p', "partitions", Default = true, HelpText = "Searches and interprets partitions.")] - public bool SearchForPartitions { get; set; } - - [Option('f', "filesystems", Default = true, HelpText = "Searches and interprets partitions.")] - public bool SearchForFilesystems { get; set; } - - [Option('i', "input", Required = true, HelpText = "Disc image.")] - public string InputFile { get; set; } - - [Option('e', "encoding", Default = null, HelpText = "Name of character encoding to use.")] - public string EncodingName { get; set; } - } - - [Verb("compare", HelpText = "Compares two disc images.")] - public class CompareOptions : CommonOptions - { - [Option("input1", Required = true, HelpText = "First disc image.")] - public string InputFile1 { get; set; } - - [Option("input2", Required = true, HelpText = "Second disc image.")] - public string InputFile2 { get; set; } - } - - [Verb("checksum", HelpText = "Checksums an image.")] - public class ChecksumOptions : CommonOptions - { - [Option('t', "separated-tracks", Default = true, HelpText = "Checksums each track separately.")] - public bool SeparatedTracks { get; set; } - - [Option('w', "whole-disc", Default = true, HelpText = "Checksums the whole disc.")] - public bool WholeDisc { get; set; } - - [Option('a', "adler32", Default = true, HelpText = "Calculates Adler-32.")] - public bool DoAdler32 { get; set; } - - [Option("crc16", Default = true, HelpText = "Calculates CRC16.")] - public bool DoCrc16 { get; set; } - - [Option('c', "crc32", Default = true, HelpText = "Calculates CRC32.")] - public bool DoCrc32 { get; set; } - - [Option("crc64", Default = false, HelpText = "Calculates CRC64 (ECMA).")] - public bool DoCrc64 { get; set; } - - [Option("fletcher16", Default = false, HelpText = "Calculates Fletcher-16.")] - public bool DoFletcher16 { get; set; } - - [Option("fletcher32", Default = false, HelpText = "Calculates Fletcher-32.")] - public bool DoFletcher32 { get; set; } - - [Option('m', "md5", Default = true, HelpText = "Calculates MD5.")] - public bool DoMd5 { get; set; } - - [Option("ripemd160", Default = false, HelpText = "Calculates RIPEMD160.")] - public bool DoRipemd160 { get; set; } - - [Option('s', "sha1", Default = true, HelpText = "Calculates SHA1.")] - public bool DoSha1 { get; set; } - - [Option("sha256", Default = false, HelpText = "Calculates SHA256.")] - public bool DoSha256 { get; set; } - - [Option("sha384", Default = false, HelpText = "Calculates SHA384.")] - public bool DoSha384 { get; set; } - - [Option("sha512", Default = false, HelpText = "Calculates SHA512.")] - public bool DoSha512 { get; set; } - - [Option('f', "spamsum", Default = true, HelpText = "Calculates SpamSum fuzzy hash.")] - public bool DoSpamSum { get; set; } - - [Option('i', "input", Required = true, HelpText = "Disc image.")] - public string InputFile { get; set; } - } - - [Verb("entropy", HelpText = "Calculates entropy and/or duplicated sectors of an image.")] - public class EntropyOptions : CommonOptions - { - [Option('p', "duplicated-sectors", Default = true, - HelpText = - "Calculates how many sectors are duplicated (have same exact data in user area).")] - public bool DuplicatedSectors { get; set; } - - [Option('t', "separated-tracks", Default = true, HelpText = "Calculates entropy for each track separately.")] - public bool SeparatedTracks { get; set; } - - [Option('w', "whole-disc", Default = true, HelpText = "Calculates entropy for the whole disc.")] - public bool WholeDisc { get; set; } - - [Option('i', "input", Required = true, HelpText = "Disc image.")] - public string InputFile { get; set; } - } - - [Verb("verify", HelpText = "Verifies a disc image integrity, and if supported, sector integrity.")] - public class VerifyOptions : CommonOptions - { - [Option('w', "verify-disc", Default = true, HelpText = "Verify disc image if supported.")] - public bool VerifyDisc { get; set; } - - [Option('s', "verify-sectors", Default = true, HelpText = "Verify all sectors if supported.")] - public bool VerifySectors { get; set; } - - [Option('i', "input", Required = true, HelpText = "Disc image.")] - public string InputFile { get; set; } - } - - [Verb("printhex", HelpText = "Prints a sector, in hexadecimal values, to the console.")] - public class PrintHexOptions : CommonOptions - { - [Option('s', "start", Required = true, HelpText = "Start sector.")] - public ulong StartSector { get; set; } - - [Option('l', "length", Default = (ulong)1, HelpText = "How many sectors to print.")] - public ulong Length { get; set; } - - [Option('r', "long-sectors", Default = false, HelpText = "Print sectors with tags included.")] - public bool LongSectors { get; set; } - - [Option('w', "width", Default = (ushort)32, HelpText = "How many bytes to print per line.")] - public ushort WidthBytes { get; set; } - - [Option('i', "input", Required = true, HelpText = "Disc image.")] - public string InputFile { get; set; } - } - - [Verb("decode", HelpText = "Decodes and pretty prints disk and/or sector tags.")] - public class DecodeOptions : CommonOptions - { - [Option('s', "start", Default = (ulong)0, HelpText = "Start sector.")] - public ulong StartSector { get; set; } - - [Option('l', "length", Default = "all", HelpText = "How many sectors to decode, or \"all\".")] - public string Length { get; set; } - - [Option('k', "disk-tags", Default = true, HelpText = "Decode disk tags.")] - public bool DiskTags { get; set; } - - [Option('t', "sector-tags", Default = true, HelpText = "Decode sector tags.")] - public bool SectorTags { get; set; } - - [Option('i', "input", Required = true, HelpText = "Disc image.")] - public string InputFile { get; set; } - } - - [Verb("device-info", HelpText = "Gets information about a device.")] - public class DeviceInfoOptions : CommonOptions - { - [Option('i', "device", Required = true, HelpText = "Device path.")] - public string DevicePath { get; set; } - - [Option('w', "output-prefix", Required = false, Default = "", - HelpText = "Write binary responses from device with that prefix.")] - public string OutputPrefix { get; set; } - } - - [Verb("media-info", HelpText = "Gets information about the media inserted on a device.")] - public class MediaInfoOptions : CommonOptions - { - [Option('i', "device", Required = true, HelpText = "Device path.")] - public string DevicePath { get; set; } - - [Option('w', "output-prefix", Required = false, Default = "", - HelpText = "Write binary responses from device with that prefix.")] - public string OutputPrefix { get; set; } - } - - [Verb("media-scan", HelpText = "Scans the media inserted on a device.")] - public class MediaScanOptions : CommonOptions - { - [Option('i', "device", Required = true, HelpText = "Device path.")] - public string DevicePath { get; set; } - - [Option('m', "mhdd-log", Required = false, Default = "", - HelpText = "Write a log of the scan in the format used by MHDD.")] - public string MhddLogPath { get; set; } - - [Option('b', "ibg-log", Required = false, Default = "", - HelpText = "Write a log of the scan in the format used by ImgBurn.")] - public string IbgLogPath { get; set; } - } - - [Verb("formats", HelpText = "Lists all supported disc images, partition schemes and file systems.")] - public class FormatsOptions : CommonOptions { } - - [Verb("benchmark", HelpText = "Benchmarks hashing and entropy calculation.")] - public class BenchmarkOptions : CommonOptions - { - [Option('b', "block-size", Required = false, Default = 512, HelpText = "Block size.")] - public int BlockSize { get; set; } - - [Option('s', "buffer-size", Required = false, Default = 128, HelpText = "Buffer size in mebibytes.")] - public int BufferSize { get; set; } - } - - [Verb("create-sidecar", HelpText = "Creates CICM Metadata XML sidecar.")] - public class CreateSidecarOptions : CommonOptions - { - [Option('i', "input", Required = true, HelpText = "Disc image.")] - public string InputFile { get; set; } - [Option('t', "tape", Required = false, Default = false, - HelpText = - "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).")] - public bool Tape { get; set; } - [Option('b', "block-size", Required = false, Default = 512, - HelpText = - "Only used for tapes, indicates block size. Files in the folder whose size is not a multiple of this value will simply be ignored.")] - public int BlockSize { get; set; } - - [Option('e', "encoding", Default = null, HelpText = "Name of character encoding to use.")] - public string EncodingName { get; set; } - } - - [Verb("dump-media", HelpText = "Dumps the media inserted on a device to a media image.")] - public class DumpMediaOptions : CommonOptions - { - [Option('i', "device", Required = true, HelpText = "Device path.")] - public string DevicePath { get; set; } - - // TODO: Disabled temporarily - /* [Option('r', "raw", Default = false, - HelpText = "Dump sectors with tags included. For optical media, dump scrambled sectors")] - public bool Raw { get; set; }*/ - - [Option('s', "stop-on-error", Default = false, HelpText = "Stop media dump on first error.")] - public bool StopOnError { get; set; } - - [Option('f', "force", Default = false, HelpText = "Continue dump whatever happens.")] - public bool Force { get; set; } - - [Option('p', "retry-passes", Default = (ushort)5, HelpText = "How many retry passes to do.")] - public ushort RetryPasses { get; set; } - - [Option("persistent", Default = false, HelpText = "Try to recover partial or incorrect data.")] - public bool Persistent { get; set; } - - [Option('m', "resume", Default = true, HelpText = "Create/use resume mapfile.")] - public bool Resume { get; set; } - - [Option("first-pregap", Default = false, - HelpText = "Try to read first track pregap. Only applicable to CD/DDCD/GD.")] - public bool FirstTrackPregap { get; set; } - - [Option('e', "encoding", Default = null, HelpText = "Name of character encoding to use.")] - public string EncodingName { get; set; } - - [Option('o', "output", Required = true, HelpText = "Output image.")] - public string OutputFile { get; set; } - - [Option('t', "format", Default = null, - HelpText = - "Format of the output image, as plugin name or plugin id. If not present, will try to detect it from output image extension.")] - public string OutputFormat { get; set; } - - [Option('O', "options", Default = null, - HelpText = "Comma separated name=value pairs of options to pass to output image plugin")] - public string Options { get; set; } - - [Option('x', "cicm-xml", Default = null, HelpText = "Take metadata from existing CICM XML sidecar.")] - public string CicmXml { get; set; } - - [Option('k', "skip", Default = 512, HelpText = "When an unreadable sector is found skip this many sectors.")] - public int Skip { get; set; } - - [Option("no-metadata", Default = false, HelpText = "Disables creating CICM XML sidecar.")] - public bool NoMetadata { get; set; } - - [Option("no-trim", Default = false, HelpText = "Disables trimming errored from skipped sectors.")] - public bool NoTrim { get; set; } - } - - [Verb("device-report", HelpText = "Tests the device capabilities and creates an XML report of them.")] - public class DeviceReportOptions : CommonOptions - { - [Option('i', "device", Required = true, HelpText = "Device path.")] - public string DevicePath { get; set; } - } - - [Verb("configure", HelpText = "Configures user settings and statistics.")] - public class ConfigureOptions { } - - [Verb("stats", HelpText = "Shows statistics.")] - public class StatsOptions { } - - [Verb("ls", HelpText = "Lists files in disc image.")] - public class LsOptions : CommonOptions - { - [Option('i', "input", Required = true, HelpText = "Disc image.")] - public string InputFile { get; set; } - - [Option('l', "long", Default = false, HelpText = "Uses long format.")] - public bool Long { get; set; } - - [Option('e', "encoding", Default = null, HelpText = "Name of character encoding to use.")] - public string EncodingName { get; set; } - - [Option('O', "options", Default = null, - HelpText = "Comma separated name=value pairs of options to pass to filesystem plugin")] - public string Options { get; set; } - } - - [Verb("extract-files", HelpText = "Extracts all files in disc image.")] - public class ExtractFilesOptions : CommonOptions - { - [Option('i', "input", Required = true, HelpText = "Disc image.")] - public string InputFile { get; set; } - - [Option('o', "output", Required = true, - HelpText = "Directory where extracted files will be created. Will abort if it exists.")] - public string OutputDir { get; set; } - - [Option('x', "xattrs", Default = false, HelpText = "Extract extended attributes if present.")] - public bool Xattrs { get; set; } - - [Option('e', "encoding", Default = null, HelpText = "Name of character encoding to use.")] - public string EncodingName { get; set; } - - [Option('O', "options", Default = null, - HelpText = "Comma separated name=value pairs of options to pass to filesystem plugin")] - public string Options { get; set; } - } - - [Verb("list-devices", HelpText = "Lists all connected devices.")] - public class ListDevicesOptions : CommonOptions { } - - [Verb("list-encodings", HelpText = "Lists all supported text encodings and code pages.")] - public class ListEncodingsOptions : CommonOptions { } - - [Verb("list-options", HelpText = "Lists all options supported by read-only filesystems and writable media images.")] - public class ListOptionsOptions : CommonOptions { } - - [Verb("convert-image", HelpText = "Converts one image to another format.")] - public class ConvertImageOptions : CommonOptions - { - [Option('i', "input", Required = true, HelpText = "Input image.")] - public string InputFile { get; set; } - - [Option('o', "output", Required = true, HelpText = "Output image.")] - public string OutputFile { get; set; } - - [Option('p', "format", Default = null, - HelpText = - "Format of the output image, as plugin name or plugin id. If not present, will try to detect it from output image extension.")] - public string OutputFormat { get; set; } - - [Option('c', "count", Default = 64, HelpText = "How many sectors to convert at once.")] - public int Count { get; set; } - - [Option('f', "force", Default = false, - HelpText = - "Continue conversion even if sector or media tags will be lost in the process.")] - public bool Force { get; set; } - - [Option("creator", Default = null, HelpText = "Who (person) created the image?")] - public string Creator { get; set; } - [Option("media-title", Default = null, HelpText = "Title of the media represented by the image")] - public string MediaTitle { get; set; } - [Option("comments", Default = null, HelpText = "Image comments")] - public string Comments { get; set; } - [Option("media-manufacturer", Default = null, HelpText = "Manufacturer of the media represented by the image")] - public string MediaManufacturer { get; set; } - [Option("media-model", Default = null, HelpText = "Model of the media represented by the image")] - public string MediaModel { get; set; } - [Option("media-serial", Default = null, HelpText = "Serial number of the media represented by the image")] - public string MediaSerialNumber { get; set; } - [Option("media-barcode", Default = null, HelpText = "Barcode of the media represented by the image")] - public string MediaBarcode { get; set; } - [Option("media-partnumber", Default = null, HelpText = "Part number of the media represented by the image")] - public string MediaPartNumber { get; set; } - [Option("media-sequence", Default = 0, HelpText = "Number in sequence for the media represented by the image")] - public int MediaSequence { get; set; } - [Option("media-lastsequence", Default = 0, - HelpText = - "Last media of the sequence the media represented by the image corresponds to")] - public int LastMediaSequence { get; set; } - [Option("drive-manufacturer", Default = null, - HelpText = - "Manufacturer of the drive used to read the media represented by the image")] - public string DriveManufacturer { get; set; } - [Option("drive-model", Default = null, - HelpText = "Model of the drive used to read the media represented by the image")] - public string DriveModel { get; set; } - [Option("drive-serial", Default = null, - HelpText = "Serial number of the drive used to read the media represented by the image")] - public string DriveSerialNumber { get; set; } - [Option("drive-revision", Default = null, - HelpText = - "Firmware revision of the drive used to read the media represented by the image")] - public string DriveFirmwareRevision { get; set; } - - [Option('O', "options", Default = null, - HelpText = "Comma separated name=value pairs of options to pass to output image plugin")] - public string Options { get; set; } - - [Option('x', "cicm-xml", Default = null, HelpText = "Take metadata from existing CICM XML sidecar.")] - public string CicmXml { get; set; } - - [Option('r', "resume-file", Default = null, HelpText = "Take list of dump hardware from existing resume file.")] - public string ResumeFile { get; set; } - } - - [Verb("image-info", HelpText = - "Opens a media image and shows information about the media it represents and metadata.")] - public class ImageInfoOptions : CommonOptions - { - [Option('i', "input", Required = true, HelpText = "Media image.")] - public string InputFile { get; set; } - } - - [Verb("gui", HelpText = "Opens the in-progress GUI.")] - public class GuiOptions : CommonOptions { } - - [Verb("update", HelpText = "Updates the database.")] - public class UpdateOptions : CommonOptions { } -} \ No newline at end of file