mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Move commands to families.
This commit is contained in:
316
DiscImageChef/Commands/Image/Analyze.cs
Normal file
316
DiscImageChef/Commands/Image/Analyze.cs
Normal file
@@ -0,0 +1,316 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Analyze.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Verbs.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements the 'analyze' 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2019 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.Text;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.Console;
|
||||
using DiscImageChef.Core;
|
||||
|
||||
namespace DiscImageChef.Commands.Image
|
||||
{
|
||||
internal class AnalyzeCommand : Command
|
||||
{
|
||||
public AnalyzeCommand() : base("analyze",
|
||||
"Analyzes a disc image and searches for partitions and/or filesystems.")
|
||||
{
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--encoding", "-e"
|
||||
}, "Name of character encoding to use.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--filesystems", "-f"
|
||||
}, "Searches and analyzes filesystems.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--partitions", "-p"
|
||||
}, "Searches and interprets partitions.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
AddArgument(new Argument<string>
|
||||
{
|
||||
Arity = ArgumentArity.ExactlyOne, Description = "Disc image path", Name = "image-path"
|
||||
});
|
||||
|
||||
Handler = CommandHandler.Create(typeof(AnalyzeCommand).GetMethod(nameof(Invoke)));
|
||||
}
|
||||
|
||||
public static int Invoke(bool verbose, bool debug, string encoding, bool filesystems, bool partitions,
|
||||
string imagePath)
|
||||
{
|
||||
MainClass.PrintCopyright();
|
||||
|
||||
if(debug)
|
||||
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
|
||||
|
||||
if(verbose)
|
||||
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
|
||||
|
||||
Statistics.AddCommand("analyze");
|
||||
|
||||
DicConsole.DebugWriteLine("Analyze command", "--debug={0}", debug);
|
||||
DicConsole.DebugWriteLine("Analyze command", "--encoding={0}", encoding);
|
||||
DicConsole.DebugWriteLine("Analyze command", "--filesystems={0}", filesystems);
|
||||
DicConsole.DebugWriteLine("Analyze command", "--input={0}", imagePath);
|
||||
DicConsole.DebugWriteLine("Analyze command", "--partitions={0}", partitions);
|
||||
DicConsole.DebugWriteLine("Analyze command", "--verbose={0}", verbose);
|
||||
|
||||
var filtersList = new FiltersList();
|
||||
IFilter inputFilter = filtersList.GetFilter(imagePath);
|
||||
|
||||
if(inputFilter == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Cannot open specified file.");
|
||||
|
||||
return(int)ErrorNumber.CannotOpenFile;
|
||||
}
|
||||
|
||||
Encoding encodingClass = null;
|
||||
|
||||
if(encoding != null)
|
||||
try
|
||||
{
|
||||
encodingClass = Claunia.Encoding.Encoding.GetEncoding(encoding);
|
||||
|
||||
if(verbose)
|
||||
DicConsole.VerboseWriteLine("Using encoding for {0}.", encodingClass.EncodingName);
|
||||
}
|
||||
catch(ArgumentException)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Specified encoding is not supported.");
|
||||
|
||||
return(int)ErrorNumber.EncodingUnknown;
|
||||
}
|
||||
|
||||
PluginBase plugins = GetPluginBase.Instance;
|
||||
|
||||
bool checkRaw = false;
|
||||
|
||||
try
|
||||
{
|
||||
IMediaImage imageFormat = ImageFormat.Detect(inputFilter);
|
||||
|
||||
if(imageFormat == null)
|
||||
{
|
||||
DicConsole.WriteLine("Image format not identified, not proceeding with analysis.");
|
||||
|
||||
return(int)ErrorNumber.UnrecognizedFormat;
|
||||
}
|
||||
|
||||
if(verbose)
|
||||
DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name,
|
||||
imageFormat.Id);
|
||||
else
|
||||
DicConsole.WriteLine("Image format identified by {0}.", imageFormat.Name);
|
||||
|
||||
DicConsole.WriteLine();
|
||||
|
||||
try
|
||||
{
|
||||
if(!imageFormat.Open(inputFilter))
|
||||
{
|
||||
DicConsole.WriteLine("Unable to open image format");
|
||||
DicConsole.WriteLine("No error given");
|
||||
|
||||
return(int)ErrorNumber.CannotOpenFormat;
|
||||
}
|
||||
|
||||
if(verbose)
|
||||
{
|
||||
ImageInfo.PrintImageInfo(imageFormat);
|
||||
DicConsole.WriteLine();
|
||||
}
|
||||
|
||||
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(int)ErrorNumber.CannotOpenFormat;
|
||||
}
|
||||
|
||||
List<string> idPlugins;
|
||||
IFilesystem plugin;
|
||||
string information;
|
||||
|
||||
if(partitions)
|
||||
{
|
||||
List<Partition> partitionsList = Core.Partitions.GetAll(imageFormat);
|
||||
Core.Partitions.AddSchemesToStats(partitionsList);
|
||||
|
||||
if(partitionsList.Count == 0)
|
||||
{
|
||||
DicConsole.DebugWriteLine("Analyze command", "No partitions found");
|
||||
|
||||
if(!filesystems)
|
||||
{
|
||||
DicConsole.WriteLine("No partitions founds, not searching for filesystems");
|
||||
|
||||
return(int)ErrorNumber.NothingFound;
|
||||
}
|
||||
|
||||
checkRaw = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DicConsole.WriteLine("{0} partitions found.", partitionsList.Count);
|
||||
|
||||
for(int i = 0; i < partitionsList.Count; i++)
|
||||
{
|
||||
DicConsole.WriteLine();
|
||||
DicConsole.WriteLine("Partition {0}:", partitionsList[i].Sequence);
|
||||
DicConsole.WriteLine("Partition name: {0}", partitionsList[i].Name);
|
||||
DicConsole.WriteLine("Partition type: {0}", partitionsList[i].Type);
|
||||
|
||||
DicConsole.WriteLine("Partition start: sector {0}, byte {1}", partitionsList[i].Start,
|
||||
partitionsList[i].Offset);
|
||||
|
||||
DicConsole.WriteLine("Partition length: {0} sectors, {1} bytes", partitionsList[i].Length,
|
||||
partitionsList[i].Size);
|
||||
|
||||
DicConsole.WriteLine("Partition scheme: {0}", partitionsList[i].Scheme);
|
||||
DicConsole.WriteLine("Partition description:");
|
||||
DicConsole.WriteLine(partitionsList[i].Description);
|
||||
|
||||
if(!filesystems)
|
||||
continue;
|
||||
|
||||
DicConsole.WriteLine("Identifying filesystem on partition");
|
||||
|
||||
Core.Filesystems.Identify(imageFormat, out idPlugins, partitionsList[i]);
|
||||
|
||||
if(idPlugins.Count == 0)
|
||||
DicConsole.WriteLine("Filesystem not identified");
|
||||
else if(idPlugins.Count > 1)
|
||||
{
|
||||
DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins");
|
||||
|
||||
foreach(string pluginName in idPlugins)
|
||||
if(plugins.PluginsList.TryGetValue(pluginName, out plugin))
|
||||
{
|
||||
DicConsole.WriteLine($"As identified by {plugin.Name}.");
|
||||
|
||||
plugin.GetInformation(imageFormat, partitionsList[i], out information,
|
||||
encodingClass);
|
||||
|
||||
DicConsole.Write(information);
|
||||
Statistics.AddFilesystem(plugin.XmlFsType.Type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
plugins.PluginsList.TryGetValue(idPlugins[0], out plugin);
|
||||
|
||||
if(plugin == null)
|
||||
continue;
|
||||
|
||||
DicConsole.WriteLine($"Identified by {plugin.Name}.");
|
||||
plugin.GetInformation(imageFormat, partitionsList[i], out information, encodingClass);
|
||||
DicConsole.Write("{0}", information);
|
||||
Statistics.AddFilesystem(plugin.XmlFsType.Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(checkRaw)
|
||||
{
|
||||
var wholePart = new Partition
|
||||
{
|
||||
Name = "Whole device", Length = imageFormat.Info.Sectors,
|
||||
Size = imageFormat.Info.Sectors * imageFormat.Info.SectorSize
|
||||
};
|
||||
|
||||
Core.Filesystems.Identify(imageFormat, out idPlugins, wholePart);
|
||||
|
||||
if(idPlugins.Count == 0)
|
||||
DicConsole.WriteLine("Filesystem not identified");
|
||||
else if(idPlugins.Count > 1)
|
||||
{
|
||||
DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins");
|
||||
|
||||
foreach(string pluginName in idPlugins)
|
||||
if(plugins.PluginsList.TryGetValue(pluginName, out plugin))
|
||||
{
|
||||
DicConsole.WriteLine($"As identified by {plugin.Name}.");
|
||||
plugin.GetInformation(imageFormat, wholePart, out information, encodingClass);
|
||||
DicConsole.Write(information);
|
||||
Statistics.AddFilesystem(plugin.XmlFsType.Type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
plugins.PluginsList.TryGetValue(idPlugins[0], out plugin);
|
||||
|
||||
if(plugin != null)
|
||||
{
|
||||
DicConsole.WriteLine($"Identified by {plugin.Name}.");
|
||||
plugin.GetInformation(imageFormat, wholePart, out information, encodingClass);
|
||||
DicConsole.Write(information);
|
||||
Statistics.AddFilesystem(plugin.XmlFsType.Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
DicConsole.ErrorWriteLine($"Error reading file: {ex.Message}");
|
||||
DicConsole.DebugWriteLine("Analyze command", ex.StackTrace);
|
||||
|
||||
return(int)ErrorNumber.UnexpectedException;
|
||||
}
|
||||
|
||||
return(int)ErrorNumber.NoError;
|
||||
}
|
||||
}
|
||||
}
|
||||
489
DiscImageChef/Commands/Image/Checksum.cs
Normal file
489
DiscImageChef/Commands/Image/Checksum.cs
Normal file
@@ -0,0 +1,489 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Checksum.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Verbs.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements the 'checksum' 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2019 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using DiscImageChef.Console;
|
||||
using DiscImageChef.Core;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.Commands.Image
|
||||
{
|
||||
internal class ChecksumCommand : Command
|
||||
{
|
||||
// How many sectors to read at once
|
||||
const uint SECTORS_TO_READ = 256;
|
||||
|
||||
public ChecksumCommand() : base("checksum", "Checksums an image.")
|
||||
{
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--adler32", "-a"
|
||||
}, "Calculates Adler32.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--crc16", "Calculates CRC16.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--crc32", "-c"
|
||||
}, "Calculates CRC32.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--crc64", "Calculates CRC64.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--fletcher16", "Calculates Fletcher-16.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--fletcher32", "Calculates Fletcher-32.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--md5", "-m"
|
||||
}, "Calculates MD5.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--separated-tracks", "-t"
|
||||
}, "Checksums each track separately.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--sha1", "-s"
|
||||
}, "Calculates SHA1.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--sha256", "Calculates SHA256.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--sha384", "Calculates SHA384.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--sha512", "Calculates SHA512.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--spamsum", "-f"
|
||||
}, "Calculates SpamSum fuzzy hash.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--whole-disc", "-w"
|
||||
}, "Checksums the whole disc.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
AddArgument(new Argument<string>
|
||||
{
|
||||
Arity = ArgumentArity.ExactlyOne, Description = "Media image path", Name = "image-path"
|
||||
});
|
||||
|
||||
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
|
||||
}
|
||||
|
||||
public static int Invoke(bool debug, bool verbose, bool adler32, bool crc16, bool crc32, bool crc64,
|
||||
bool fletcher16, bool fletcher32, bool md5, bool sha1, bool sha256, bool sha384,
|
||||
bool sha512, bool spamSum, string imagePath, bool separatedTracks, bool wholeDisc)
|
||||
{
|
||||
MainClass.PrintCopyright();
|
||||
|
||||
if(debug)
|
||||
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
|
||||
|
||||
if(verbose)
|
||||
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
|
||||
|
||||
Statistics.AddCommand("checksum");
|
||||
|
||||
DicConsole.DebugWriteLine("Checksum command", "--adler32={0}", adler32);
|
||||
DicConsole.DebugWriteLine("Checksum command", "--crc16={0}", crc16);
|
||||
DicConsole.DebugWriteLine("Checksum command", "--crc32={0}", crc32);
|
||||
DicConsole.DebugWriteLine("Checksum command", "--crc64={0}", crc64);
|
||||
DicConsole.DebugWriteLine("Checksum command", "--debug={0}", debug);
|
||||
DicConsole.DebugWriteLine("Checksum command", "--fletcher16={0}", fletcher16);
|
||||
DicConsole.DebugWriteLine("Checksum command", "--fletcher32={0}", fletcher32);
|
||||
DicConsole.DebugWriteLine("Checksum command", "--input={0}", imagePath);
|
||||
DicConsole.DebugWriteLine("Checksum command", "--md5={0}", md5);
|
||||
DicConsole.DebugWriteLine("Checksum command", "--separated-tracks={0}", separatedTracks);
|
||||
DicConsole.DebugWriteLine("Checksum command", "--sha1={0}", sha1);
|
||||
DicConsole.DebugWriteLine("Checksum command", "--sha256={0}", sha256);
|
||||
DicConsole.DebugWriteLine("Checksum command", "--sha384={0}", sha384);
|
||||
DicConsole.DebugWriteLine("Checksum command", "--sha512={0}", sha512);
|
||||
DicConsole.DebugWriteLine("Checksum command", "--spamsum={0}", spamSum);
|
||||
DicConsole.DebugWriteLine("Checksum command", "--verbose={0}", verbose);
|
||||
DicConsole.DebugWriteLine("Checksum command", "--whole-disc={0}", wholeDisc);
|
||||
|
||||
var filtersList = new FiltersList();
|
||||
IFilter inputFilter = filtersList.GetFilter(imagePath);
|
||||
|
||||
if(inputFilter == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Cannot open specified file.");
|
||||
|
||||
return(int)ErrorNumber.CannotOpenFile;
|
||||
}
|
||||
|
||||
IMediaImage inputFormat = ImageFormat.Detect(inputFilter);
|
||||
|
||||
if(inputFormat == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Unable to recognize image format, not checksumming");
|
||||
|
||||
return(int)ErrorNumber.UnrecognizedFormat;
|
||||
}
|
||||
|
||||
inputFormat.Open(inputFilter);
|
||||
Statistics.AddMediaFormat(inputFormat.Format);
|
||||
Statistics.AddMedia(inputFormat.Info.MediaType, false);
|
||||
Statistics.AddFilter(inputFilter.Name);
|
||||
var enabledChecksums = new EnableChecksum();
|
||||
|
||||
if(adler32)
|
||||
enabledChecksums |= EnableChecksum.Adler32;
|
||||
|
||||
if(crc16)
|
||||
enabledChecksums |= EnableChecksum.Crc16;
|
||||
|
||||
if(crc32)
|
||||
enabledChecksums |= EnableChecksum.Crc32;
|
||||
|
||||
if(crc64)
|
||||
enabledChecksums |= EnableChecksum.Crc64;
|
||||
|
||||
if(md5)
|
||||
enabledChecksums |= EnableChecksum.Md5;
|
||||
|
||||
if(sha1)
|
||||
enabledChecksums |= EnableChecksum.Sha1;
|
||||
|
||||
if(sha256)
|
||||
enabledChecksums |= EnableChecksum.Sha256;
|
||||
|
||||
if(sha384)
|
||||
enabledChecksums |= EnableChecksum.Sha384;
|
||||
|
||||
if(sha512)
|
||||
enabledChecksums |= EnableChecksum.Sha512;
|
||||
|
||||
if(spamSum)
|
||||
enabledChecksums |= EnableChecksum.SpamSum;
|
||||
|
||||
if(fletcher16)
|
||||
enabledChecksums |= EnableChecksum.Fletcher16;
|
||||
|
||||
if(fletcher32)
|
||||
enabledChecksums |= EnableChecksum.Fletcher32;
|
||||
|
||||
Checksum mediaChecksum = null;
|
||||
|
||||
switch(inputFormat)
|
||||
{
|
||||
case IOpticalMediaImage opticalInput when opticalInput.Tracks != null:
|
||||
try
|
||||
{
|
||||
Checksum trackChecksum = null;
|
||||
|
||||
if(wholeDisc)
|
||||
mediaChecksum = new Checksum(enabledChecksums);
|
||||
|
||||
ulong previousTrackEnd = 0;
|
||||
|
||||
List<Track> inputTracks = opticalInput.Tracks;
|
||||
|
||||
foreach(Track currentTrack in inputTracks)
|
||||
{
|
||||
if(currentTrack.TrackStartSector - previousTrackEnd != 0 && wholeDisc)
|
||||
for(ulong i = previousTrackEnd + 1; i < currentTrack.TrackStartSector; i++)
|
||||
{
|
||||
DicConsole.Write("\rHashing track-less sector {0}", i);
|
||||
|
||||
byte[] hiddenSector = inputFormat.ReadSector(i);
|
||||
|
||||
mediaChecksum?.Update(hiddenSector);
|
||||
}
|
||||
|
||||
DicConsole.DebugWriteLine("Checksum command",
|
||||
"Track {0} starts at sector {1} and ends at sector {2}",
|
||||
currentTrack.TrackSequence, currentTrack.TrackStartSector,
|
||||
currentTrack.TrackEndSector);
|
||||
|
||||
if(separatedTracks)
|
||||
trackChecksum = new Checksum(enabledChecksums);
|
||||
|
||||
ulong sectors = (currentTrack.TrackEndSector - currentTrack.TrackStartSector) + 1;
|
||||
ulong doneSectors = 0;
|
||||
DicConsole.WriteLine("Track {0} has {1} sectors", currentTrack.TrackSequence, sectors);
|
||||
|
||||
while(doneSectors < sectors)
|
||||
{
|
||||
byte[] sector;
|
||||
|
||||
if(sectors - doneSectors >= SECTORS_TO_READ)
|
||||
{
|
||||
sector = opticalInput.ReadSectors(doneSectors, SECTORS_TO_READ,
|
||||
currentTrack.TrackSequence);
|
||||
|
||||
DicConsole.Write("\rHashing sectors {0} to {2} of track {1}", doneSectors,
|
||||
currentTrack.TrackSequence, doneSectors + SECTORS_TO_READ);
|
||||
|
||||
doneSectors += SECTORS_TO_READ;
|
||||
}
|
||||
else
|
||||
{
|
||||
sector = opticalInput.ReadSectors(doneSectors, (uint)(sectors - doneSectors),
|
||||
currentTrack.TrackSequence);
|
||||
|
||||
DicConsole.Write("\rHashing sectors {0} to {2} of track {1}", doneSectors,
|
||||
currentTrack.TrackSequence, doneSectors + (sectors - doneSectors));
|
||||
|
||||
doneSectors += sectors - doneSectors;
|
||||
}
|
||||
|
||||
if(wholeDisc)
|
||||
mediaChecksum?.Update(sector);
|
||||
|
||||
if(separatedTracks)
|
||||
trackChecksum?.Update(sector);
|
||||
}
|
||||
|
||||
DicConsole.WriteLine();
|
||||
|
||||
if(separatedTracks)
|
||||
if(trackChecksum != null)
|
||||
foreach(ChecksumType chk in trackChecksum.End())
|
||||
DicConsole.WriteLine("Track {0}'s {1}: {2}", currentTrack.TrackSequence,
|
||||
chk.type, chk.Value);
|
||||
|
||||
previousTrackEnd = currentTrack.TrackEndSector;
|
||||
}
|
||||
|
||||
if(opticalInput.Info.Sectors - previousTrackEnd != 0 && wholeDisc)
|
||||
for(ulong i = previousTrackEnd + 1; i < opticalInput.Info.Sectors; i++)
|
||||
{
|
||||
DicConsole.Write("\rHashing track-less sector {0}", i);
|
||||
|
||||
byte[] hiddenSector = inputFormat.ReadSector(i);
|
||||
mediaChecksum?.Update(hiddenSector);
|
||||
}
|
||||
|
||||
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(debug)
|
||||
DicConsole.DebugWriteLine("Could not get tracks because {0}", ex.Message);
|
||||
else
|
||||
DicConsole.WriteLine("Unable to get separate tracks, not checksumming them");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ITapeImage tapeImage when tapeImage.IsTape && tapeImage.Files?.Count > 0:
|
||||
{
|
||||
Checksum trackChecksum = null;
|
||||
|
||||
if(wholeDisc)
|
||||
mediaChecksum = new Checksum(enabledChecksums);
|
||||
|
||||
ulong previousTrackEnd = 0;
|
||||
|
||||
foreach(TapeFile currentFile in tapeImage.Files)
|
||||
{
|
||||
if(currentFile.FirstBlock - previousTrackEnd != 0 && wholeDisc)
|
||||
for(ulong i = previousTrackEnd + 1; i < currentFile.FirstBlock; i++)
|
||||
{
|
||||
DicConsole.Write("\rHashing file-less block {0}", i);
|
||||
|
||||
byte[] hiddenSector = inputFormat.ReadSector(i);
|
||||
|
||||
mediaChecksum?.Update(hiddenSector);
|
||||
}
|
||||
|
||||
DicConsole.DebugWriteLine("Checksum command",
|
||||
"Track {0} starts at sector {1} and ends at block {2}",
|
||||
currentFile.File, currentFile.FirstBlock, currentFile.LastBlock);
|
||||
|
||||
if(separatedTracks)
|
||||
trackChecksum = new Checksum(enabledChecksums);
|
||||
|
||||
ulong sectors = (currentFile.LastBlock - currentFile.FirstBlock) + 1;
|
||||
ulong doneSectors = 0;
|
||||
DicConsole.WriteLine("File {0} has {1} sectors", currentFile.File, sectors);
|
||||
|
||||
while(doneSectors < sectors)
|
||||
{
|
||||
byte[] sector;
|
||||
|
||||
if(sectors - doneSectors >= SECTORS_TO_READ)
|
||||
{
|
||||
sector = tapeImage.ReadSectors(doneSectors + currentFile.FirstBlock, SECTORS_TO_READ);
|
||||
|
||||
DicConsole.Write("\rHashing blocks {0} to {2} of file {1}", doneSectors,
|
||||
currentFile.File, doneSectors + SECTORS_TO_READ);
|
||||
|
||||
doneSectors += SECTORS_TO_READ;
|
||||
}
|
||||
else
|
||||
{
|
||||
sector = tapeImage.ReadSectors(doneSectors + currentFile.FirstBlock,
|
||||
(uint)(sectors - doneSectors));
|
||||
|
||||
DicConsole.Write("\rHashing blocks {0} to {2} of file {1}", doneSectors,
|
||||
currentFile.File, doneSectors + (sectors - doneSectors));
|
||||
|
||||
doneSectors += sectors - doneSectors;
|
||||
}
|
||||
|
||||
if(wholeDisc)
|
||||
mediaChecksum?.Update(sector);
|
||||
|
||||
if(separatedTracks)
|
||||
trackChecksum?.Update(sector);
|
||||
}
|
||||
|
||||
DicConsole.WriteLine();
|
||||
|
||||
if(separatedTracks)
|
||||
if(trackChecksum != null)
|
||||
foreach(ChecksumType chk in trackChecksum.End())
|
||||
DicConsole.WriteLine("File {0}'s {1}: {2}", currentFile.File, chk.type, chk.Value);
|
||||
|
||||
previousTrackEnd = currentFile.LastBlock;
|
||||
}
|
||||
|
||||
if(tapeImage.Info.Sectors - previousTrackEnd != 0 && wholeDisc)
|
||||
for(ulong i = previousTrackEnd + 1; i < tapeImage.Info.Sectors; i++)
|
||||
{
|
||||
DicConsole.Write("\rHashing file-less sector {0}", i);
|
||||
|
||||
byte[] hiddenSector = inputFormat.ReadSector(i);
|
||||
mediaChecksum?.Update(hiddenSector);
|
||||
}
|
||||
|
||||
if(wholeDisc)
|
||||
if(mediaChecksum != null)
|
||||
foreach(ChecksumType chk in mediaChecksum.End())
|
||||
DicConsole.WriteLine("Tape's {0}: {1}", chk.type, chk.Value);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
mediaChecksum = new Checksum(enabledChecksums);
|
||||
|
||||
ulong sectors = inputFormat.Info.Sectors;
|
||||
DicConsole.WriteLine("Sectors {0}", sectors);
|
||||
ulong doneSectors = 0;
|
||||
|
||||
while(doneSectors < sectors)
|
||||
{
|
||||
byte[] sector;
|
||||
|
||||
if(sectors - doneSectors >= SECTORS_TO_READ)
|
||||
{
|
||||
sector = inputFormat.ReadSectors(doneSectors, SECTORS_TO_READ);
|
||||
|
||||
DicConsole.Write("\rHashing sectors {0} to {1}", doneSectors,
|
||||
doneSectors + SECTORS_TO_READ);
|
||||
|
||||
doneSectors += SECTORS_TO_READ;
|
||||
}
|
||||
else
|
||||
{
|
||||
sector = inputFormat.ReadSectors(doneSectors, (uint)(sectors - doneSectors));
|
||||
|
||||
DicConsole.Write("\rHashing sectors {0} to {1}", doneSectors,
|
||||
doneSectors + (sectors - doneSectors));
|
||||
|
||||
doneSectors += sectors - doneSectors;
|
||||
}
|
||||
|
||||
mediaChecksum.Update(sector);
|
||||
}
|
||||
|
||||
DicConsole.WriteLine();
|
||||
|
||||
foreach(ChecksumType chk in mediaChecksum.End())
|
||||
DicConsole.WriteLine("Disk's {0}: {1}", chk.type, chk.Value);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(int)ErrorNumber.NoError;
|
||||
}
|
||||
}
|
||||
}
|
||||
365
DiscImageChef/Commands/Image/Compare.cs
Normal file
365
DiscImageChef/Commands/Image/Compare.cs
Normal file
@@ -0,0 +1,365 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Compare.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Verbs.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements the 'compare' 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2019 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.Text;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using DiscImageChef.Console;
|
||||
using DiscImageChef.Core;
|
||||
using ImageInfo = DiscImageChef.CommonTypes.Structs.ImageInfo;
|
||||
|
||||
namespace DiscImageChef.Commands.Image
|
||||
{
|
||||
internal class CompareCommand : Command
|
||||
{
|
||||
public CompareCommand() : base("compare", "Compares two disc images.")
|
||||
{
|
||||
AddArgument(new Argument<string>
|
||||
{
|
||||
Arity = ArgumentArity.ExactlyOne, Description = "First media image path", Name = "image-path1"
|
||||
});
|
||||
|
||||
AddArgument(new Argument<string>
|
||||
{
|
||||
Arity = ArgumentArity.ExactlyOne, Description = "Second media image path", Name = "image-path2"
|
||||
});
|
||||
|
||||
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
|
||||
}
|
||||
|
||||
public static int Invoke(bool debug, bool verbose, string imagePath1, string imagePath2)
|
||||
{
|
||||
MainClass.PrintCopyright();
|
||||
|
||||
if(debug)
|
||||
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
|
||||
|
||||
if(verbose)
|
||||
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
|
||||
|
||||
Statistics.AddCommand("compare");
|
||||
|
||||
DicConsole.DebugWriteLine("Compare command", "--debug={0}", debug);
|
||||
DicConsole.DebugWriteLine("Compare command", "--input1={0}", imagePath1);
|
||||
DicConsole.DebugWriteLine("Compare command", "--input2={0}", imagePath2);
|
||||
DicConsole.DebugWriteLine("Compare command", "--verbose={0}", verbose);
|
||||
|
||||
var filtersList = new FiltersList();
|
||||
IFilter inputFilter1 = filtersList.GetFilter(imagePath1);
|
||||
filtersList = new FiltersList();
|
||||
IFilter inputFilter2 = filtersList.GetFilter(imagePath2);
|
||||
|
||||
if(inputFilter1 == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Cannot open input file 1");
|
||||
|
||||
return(int)ErrorNumber.CannotOpenFile;
|
||||
}
|
||||
|
||||
if(inputFilter2 == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Cannot open input file 2");
|
||||
|
||||
return(int)ErrorNumber.CannotOpenFile;
|
||||
}
|
||||
|
||||
IMediaImage input1Format = ImageFormat.Detect(inputFilter1);
|
||||
IMediaImage input2Format = ImageFormat.Detect(inputFilter2);
|
||||
|
||||
if(input1Format == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Input file 1 format not identified, not proceeding with comparison.");
|
||||
|
||||
return(int)ErrorNumber.UnrecognizedFormat;
|
||||
}
|
||||
|
||||
if(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);
|
||||
|
||||
if(input2Format == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Input file 2 format not identified, not proceeding with comparison.");
|
||||
|
||||
return(int)ErrorNumber.UnrecognizedFormat;
|
||||
}
|
||||
|
||||
if(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);
|
||||
|
||||
input1Format.Open(inputFilter1);
|
||||
input2Format.Open(inputFilter2);
|
||||
|
||||
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);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
if(verbose)
|
||||
{
|
||||
sb.AppendLine("\tDisc image 1\tDisc image 2");
|
||||
sb.AppendLine("================================");
|
||||
sb.AppendFormat("File\t{0}\t{1}", imagePath1, imagePath2).AppendLine();
|
||||
sb.AppendFormat("Disc image format\t{0}\t{1}", input1Format.Name, input2Format.Name).AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendFormat("Disc image 1: {0}", imagePath1).AppendLine();
|
||||
sb.AppendFormat("Disc image 2: {0}", imagePath2).AppendLine();
|
||||
}
|
||||
|
||||
bool imagesDiffer = false;
|
||||
|
||||
ImageInfo image1Info = input1Format.Info;
|
||||
ImageInfo image2Info = input2Format.Info;
|
||||
List<Session> image1Sessions = new List<Session>();
|
||||
List<Session> image2Sessions = new List<Session>();
|
||||
Dictionary<MediaTagType, byte[]> image1DiskTags = new Dictionary<MediaTagType, byte[]>();
|
||||
Dictionary<MediaTagType, byte[]> image2DiskTags = new Dictionary<MediaTagType, byte[]>();
|
||||
|
||||
foreach(MediaTagType disktag in Enum.GetValues(typeof(MediaTagType)))
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] temparray = input1Format.ReadDiskTag(disktag);
|
||||
image1DiskTags.Add(disktag, temparray);
|
||||
}
|
||||
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
|
||||
}
|
||||
|
||||
foreach(MediaTagType disktag in Enum.GetValues(typeof(MediaTagType)))
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] temparray = input2Format.ReadDiskTag(disktag);
|
||||
image2DiskTags.Add(disktag, temparray);
|
||||
}
|
||||
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
|
||||
}
|
||||
|
||||
if(verbose)
|
||||
{
|
||||
sb.AppendFormat("Has partitions?\t{0}\t{1}", image1Info.HasPartitions, image2Info.HasPartitions).
|
||||
AppendLine();
|
||||
|
||||
sb.AppendFormat("Has sessions?\t{0}\t{1}", image1Info.HasSessions, image2Info.HasSessions).AppendLine();
|
||||
sb.AppendFormat("Image size\t{0}\t{1}", image1Info.ImageSize, image2Info.ImageSize).AppendLine();
|
||||
sb.AppendFormat("Sectors\t{0}\t{1}", image1Info.Sectors, image2Info.Sectors).AppendLine();
|
||||
sb.AppendFormat("Sector size\t{0}\t{1}", image1Info.SectorSize, image2Info.SectorSize).AppendLine();
|
||||
|
||||
sb.AppendFormat("Creation time\t{0}\t{1}", image1Info.CreationTime, image2Info.CreationTime).
|
||||
AppendLine();
|
||||
|
||||
sb.AppendFormat("Last modification time\t{0}\t{1}", image1Info.LastModificationTime,
|
||||
image2Info.LastModificationTime).AppendLine();
|
||||
|
||||
sb.AppendFormat("Disk type\t{0}\t{1}", image1Info.MediaType, image2Info.MediaType).AppendLine();
|
||||
sb.AppendFormat("Image version\t{0}\t{1}", image1Info.Version, image2Info.Version).AppendLine();
|
||||
|
||||
sb.AppendFormat("Image application\t{0}\t{1}", image1Info.Application, image2Info.Application).
|
||||
AppendLine();
|
||||
|
||||
sb.AppendFormat("Image application version\t{0}\t{1}", image1Info.ApplicationVersion,
|
||||
image2Info.ApplicationVersion).AppendLine();
|
||||
|
||||
sb.AppendFormat("Image creator\t{0}\t{1}", image1Info.Creator, image2Info.Creator).AppendLine();
|
||||
sb.AppendFormat("Image name\t{0}\t{1}", image1Info.MediaTitle, image2Info.MediaTitle).AppendLine();
|
||||
sb.AppendFormat("Image comments\t{0}\t{1}", image1Info.Comments, image2Info.Comments).AppendLine();
|
||||
|
||||
sb.AppendFormat("Disk manufacturer\t{0}\t{1}", image1Info.MediaManufacturer,
|
||||
image2Info.MediaManufacturer).AppendLine();
|
||||
|
||||
sb.AppendFormat("Disk model\t{0}\t{1}", image1Info.MediaModel, image2Info.MediaModel).AppendLine();
|
||||
|
||||
sb.AppendFormat("Disk serial number\t{0}\t{1}", image1Info.MediaSerialNumber,
|
||||
image2Info.MediaSerialNumber).AppendLine();
|
||||
|
||||
sb.AppendFormat("Disk barcode\t{0}\t{1}", image1Info.MediaBarcode, image2Info.MediaBarcode).
|
||||
AppendLine();
|
||||
|
||||
sb.AppendFormat("Disk part no.\t{0}\t{1}", image1Info.MediaPartNumber, image2Info.MediaPartNumber).
|
||||
AppendLine();
|
||||
|
||||
sb.AppendFormat("Disk sequence\t{0}\t{1}", image1Info.MediaSequence, image2Info.MediaSequence).
|
||||
AppendLine();
|
||||
|
||||
sb.AppendFormat("Last disk on sequence\t{0}\t{1}", image1Info.LastMediaSequence,
|
||||
image2Info.LastMediaSequence).AppendLine();
|
||||
|
||||
sb.AppendFormat("Drive manufacturer\t{0}\t{1}", image1Info.DriveManufacturer,
|
||||
image2Info.DriveManufacturer).AppendLine();
|
||||
|
||||
sb.AppendFormat("Drive firmware revision\t{0}\t{1}", image1Info.DriveFirmwareRevision,
|
||||
image2Info.DriveFirmwareRevision).AppendLine();
|
||||
|
||||
sb.AppendFormat("Drive model\t{0}\t{1}", image1Info.DriveModel, image2Info.DriveModel).AppendLine();
|
||||
|
||||
sb.AppendFormat("Drive serial number\t{0}\t{1}", image1Info.DriveSerialNumber,
|
||||
image2Info.DriveSerialNumber).AppendLine();
|
||||
|
||||
foreach(MediaTagType disktag in Enum.GetValues(typeof(MediaTagType)))
|
||||
sb.AppendFormat("Has {0}?\t{1}\t{2}", disktag, image1DiskTags.ContainsKey(disktag),
|
||||
image2DiskTags.ContainsKey(disktag)).AppendLine();
|
||||
}
|
||||
|
||||
DicConsole.WriteLine("Comparing disk image characteristics");
|
||||
|
||||
if(image1Info.HasPartitions != image2Info.HasPartitions)
|
||||
{
|
||||
imagesDiffer = true;
|
||||
|
||||
if(!verbose)
|
||||
sb.AppendLine("Image partitioned status differ");
|
||||
}
|
||||
|
||||
if(image1Info.HasSessions != image2Info.HasSessions)
|
||||
{
|
||||
imagesDiffer = true;
|
||||
|
||||
if(!verbose)
|
||||
sb.AppendLine("Image session status differ");
|
||||
}
|
||||
|
||||
if(image1Info.Sectors != image2Info.Sectors)
|
||||
{
|
||||
imagesDiffer = true;
|
||||
|
||||
if(!verbose)
|
||||
sb.AppendLine("Image sectors differ");
|
||||
}
|
||||
|
||||
if(image1Info.SectorSize != image2Info.SectorSize)
|
||||
{
|
||||
imagesDiffer = true;
|
||||
|
||||
if(!verbose)
|
||||
sb.AppendLine("Image sector size differ");
|
||||
}
|
||||
|
||||
if(image1Info.MediaType != image2Info.MediaType)
|
||||
{
|
||||
imagesDiffer = true;
|
||||
|
||||
if(!verbose)
|
||||
sb.AppendLine("Disk type differ");
|
||||
}
|
||||
|
||||
ulong leastSectors;
|
||||
|
||||
if(image1Info.Sectors < image2Info.Sectors)
|
||||
{
|
||||
imagesDiffer = true;
|
||||
leastSectors = image1Info.Sectors;
|
||||
|
||||
if(!verbose)
|
||||
sb.AppendLine("Image 2 has more sectors");
|
||||
}
|
||||
else if(image1Info.Sectors > image2Info.Sectors)
|
||||
{
|
||||
imagesDiffer = true;
|
||||
leastSectors = image2Info.Sectors;
|
||||
|
||||
if(!verbose)
|
||||
sb.AppendLine("Image 1 has more sectors");
|
||||
}
|
||||
else
|
||||
leastSectors = image1Info.Sectors;
|
||||
|
||||
DicConsole.WriteLine("Comparing sectors...");
|
||||
|
||||
for(ulong sector = 0; sector < leastSectors; sector++)
|
||||
{
|
||||
DicConsole.Write("\rComparing sector {0} of {1}...", sector + 1, leastSectors);
|
||||
|
||||
try
|
||||
{
|
||||
byte[] image1Sector = input1Format.ReadSector(sector);
|
||||
byte[] image2Sector = input2Format.ReadSector(sector);
|
||||
ArrayHelpers.CompareBytes(out bool different, out bool sameSize, image1Sector, image2Sector);
|
||||
|
||||
if(different)
|
||||
{
|
||||
imagesDiffer = true;
|
||||
sb.AppendFormat("Sector {0} is different", sector).AppendLine();
|
||||
}
|
||||
else if(!sameSize)
|
||||
{
|
||||
imagesDiffer = true;
|
||||
|
||||
sb.
|
||||
AppendFormat("Sector {0} has different sizes ({1} bytes in image 1, {2} in image 2) but are otherwise identical",
|
||||
sector, image1Sector.LongLength, image2Sector.LongLength).AppendLine();
|
||||
}
|
||||
}
|
||||
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
|
||||
}
|
||||
|
||||
DicConsole.WriteLine();
|
||||
|
||||
sb.AppendLine(imagesDiffer ? "Images differ" : "Images do not differ");
|
||||
|
||||
DicConsole.WriteLine(sb.ToString());
|
||||
|
||||
return(int)ErrorNumber.NoError;
|
||||
}
|
||||
}
|
||||
}
|
||||
906
DiscImageChef/Commands/Image/ConvertImage.cs
Normal file
906
DiscImageChef/Commands/Image/ConvertImage.cs
Normal file
@@ -0,0 +1,906 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : ConvertImage.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Verbs.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Converts from one media image to another.
|
||||
//
|
||||
// --[ 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2019 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Serialization;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Metadata;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using DiscImageChef.Console;
|
||||
using DiscImageChef.Core;
|
||||
using Schemas;
|
||||
using ImageInfo = DiscImageChef.CommonTypes.Structs.ImageInfo;
|
||||
using Version = DiscImageChef.CommonTypes.Interop.Version;
|
||||
|
||||
namespace DiscImageChef.Commands.Image
|
||||
{
|
||||
internal class ConvertImageCommand : Command
|
||||
{
|
||||
public ConvertImageCommand() : base("convert-image", "Converts one image to another format.")
|
||||
{
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--cicm-xml", "-x"
|
||||
}, "Take metadata from existing CICM XML sidecar.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--comments", "Image comments.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--count", "-c"
|
||||
}, "How many sectors to convert at once.")
|
||||
{
|
||||
Argument = new Argument<int>(() => 64), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--creator", "Who (person) created the image?.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--drive-manufacturer",
|
||||
"Manufacturer of the drive used to read the media represented by the image.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--drive-model", "Model of the drive used to read the media represented by the image.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--drive-revision",
|
||||
"Firmware revision of the drive used to read the media represented by the image.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--drive-serial",
|
||||
"Serial number of the drive used to read the media represented by the image.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--force", "-f"
|
||||
}, "Continue conversion even if sector or media tags will be lost in the process.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => false), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--format", "-p"
|
||||
},
|
||||
"Format of the output image, as plugin name or plugin id. If not present, will try to detect it from output image extension.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--media-barcode", "Barcode of the media represented by the image.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--media-lastsequence",
|
||||
"Last media of the sequence the media represented by the image corresponds to.")
|
||||
{
|
||||
Argument = new Argument<int>(() => 0), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--media-manufacturer", "Manufacturer of the media represented by the image.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--media-model", "Model of the media represented by the image.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--media-partnumber", "Part number of the media represented by the image.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--media-sequence", "Number in sequence for the media represented by the image.")
|
||||
{
|
||||
Argument = new Argument<int>(() => 0), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--media-serial", "Serial number of the media represented by the image.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
Add(new Option("--media-title", "Title of the media represented by the image.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--options", "-O"
|
||||
}, "Comma separated name=value pairs of options to pass to output image plugin.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--resume-file", "-r"
|
||||
}, "Take list of dump hardware from existing resume file.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
AddArgument(new Argument<string>
|
||||
{
|
||||
Arity = ArgumentArity.ExactlyOne, Description = "Input image path", Name = "input-path"
|
||||
});
|
||||
|
||||
AddArgument(new Argument<string>
|
||||
{
|
||||
Arity = ArgumentArity.ExactlyOne, Description = "Output image path", Name = "output-path"
|
||||
});
|
||||
|
||||
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
|
||||
}
|
||||
|
||||
public static int Invoke(bool verbose, bool debug, string cicmXml, string comments, int count, string creator,
|
||||
string driveFirmwareRevision, string driveManufacturer, string driveModel,
|
||||
string driveSerialNumber, bool force, string inputPath, int lastMediaSequence,
|
||||
string mediaBarcode, string mediaManufacturer, string mediaModel,
|
||||
string mediaPartNumber, int mediaSequence, string mediaSerialNumber, string mediaTitle,
|
||||
string outputPath, string outputOptions, string resumeFile, string format)
|
||||
{
|
||||
MainClass.PrintCopyright();
|
||||
|
||||
if(debug)
|
||||
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
|
||||
|
||||
if(verbose)
|
||||
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
|
||||
|
||||
Statistics.AddCommand("convert-image");
|
||||
|
||||
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}", 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}", format);
|
||||
DicConsole.DebugWriteLine("Analyze command", "--input={0}", inputPath);
|
||||
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}", outputPath);
|
||||
DicConsole.DebugWriteLine("Analyze command", "--resume-file={0}", resumeFile);
|
||||
DicConsole.DebugWriteLine("Analyze command", "--verbose={0}", verbose);
|
||||
|
||||
Dictionary<string, string> parsedOptions = Core.Options.Parse(outputOptions);
|
||||
DicConsole.DebugWriteLine("Analyze command", "Parsed options:");
|
||||
|
||||
foreach(KeyValuePair<string, string> parsedOption in parsedOptions)
|
||||
DicConsole.DebugWriteLine("Analyze command", "{0} = {1}", parsedOption.Key, parsedOption.Value);
|
||||
|
||||
if(count == 0)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Need to specify more than 0 sectors to copy at once");
|
||||
|
||||
return(int)ErrorNumber.InvalidArgument;
|
||||
}
|
||||
|
||||
Resume resume = null;
|
||||
CICMMetadataType sidecar = null;
|
||||
|
||||
var xs = new XmlSerializer(typeof(CICMMetadataType));
|
||||
|
||||
if(cicmXml != null)
|
||||
if(File.Exists(cicmXml))
|
||||
try
|
||||
{
|
||||
var sr = new StreamReader(cicmXml);
|
||||
sidecar = (CICMMetadataType)xs.Deserialize(sr);
|
||||
sr.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Incorrect metadata sidecar file, not continuing...");
|
||||
|
||||
return(int)ErrorNumber.InvalidSidecar;
|
||||
}
|
||||
else
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Could not find metadata sidecar, not continuing...");
|
||||
|
||||
return(int)ErrorNumber.FileNotFound;
|
||||
}
|
||||
|
||||
xs = new XmlSerializer(typeof(Resume));
|
||||
|
||||
if(resumeFile != null)
|
||||
if(File.Exists(resumeFile))
|
||||
try
|
||||
{
|
||||
var sr = new StreamReader(resumeFile);
|
||||
resume = (Resume)xs.Deserialize(sr);
|
||||
sr.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Incorrect resume file, not continuing...");
|
||||
|
||||
return(int)ErrorNumber.InvalidResume;
|
||||
}
|
||||
else
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Could not find resume file, not continuing...");
|
||||
|
||||
return(int)ErrorNumber.FileNotFound;
|
||||
}
|
||||
|
||||
var filtersList = new FiltersList();
|
||||
IFilter inputFilter = filtersList.GetFilter(inputPath);
|
||||
|
||||
if(inputFilter == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Cannot open specified file.");
|
||||
|
||||
return(int)ErrorNumber.CannotOpenFile;
|
||||
}
|
||||
|
||||
if(File.Exists(outputPath))
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Output file already exists, not continuing.");
|
||||
|
||||
return(int)ErrorNumber.DestinationExists;
|
||||
}
|
||||
|
||||
PluginBase plugins = GetPluginBase.Instance;
|
||||
IMediaImage inputFormat = ImageFormat.Detect(inputFilter);
|
||||
|
||||
if(inputFormat == null)
|
||||
{
|
||||
DicConsole.WriteLine("Input image format not identified, not proceeding with conversion.");
|
||||
|
||||
return(int)ErrorNumber.UnrecognizedFormat;
|
||||
}
|
||||
|
||||
if(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);
|
||||
|
||||
try
|
||||
{
|
||||
if(!inputFormat.Open(inputFilter))
|
||||
{
|
||||
DicConsole.WriteLine("Unable to open image format");
|
||||
DicConsole.WriteLine("No error given");
|
||||
|
||||
return(int)ErrorNumber.CannotOpenFormat;
|
||||
}
|
||||
|
||||
DicConsole.DebugWriteLine("Convert-image command", "Correctly opened image file.");
|
||||
|
||||
DicConsole.DebugWriteLine("Convert-image command", "Image without headers is {0} bytes.",
|
||||
inputFormat.Info.ImageSize);
|
||||
|
||||
DicConsole.DebugWriteLine("Convert-image command", "Image has {0} sectors.", inputFormat.Info.Sectors);
|
||||
|
||||
DicConsole.DebugWriteLine("Convert-image command", "Image identifies media type as {0}.",
|
||||
inputFormat.Info.MediaType);
|
||||
|
||||
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(int)ErrorNumber.CannotOpenFormat;
|
||||
}
|
||||
|
||||
List<IWritableImage> candidates = new List<IWritableImage>();
|
||||
|
||||
// Try extension
|
||||
if(string.IsNullOrEmpty(format))
|
||||
candidates.AddRange(plugins.WritableImages.Values.Where(t =>
|
||||
t.KnownExtensions.
|
||||
Contains(Path.GetExtension(outputPath))));
|
||||
|
||||
// Try Id
|
||||
else if(Guid.TryParse(format, 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, format,
|
||||
StringComparison.
|
||||
InvariantCultureIgnoreCase)));
|
||||
|
||||
if(candidates.Count == 0)
|
||||
{
|
||||
DicConsole.WriteLine("No plugin supports requested extension.");
|
||||
|
||||
return(int)ErrorNumber.FormatNotFound;
|
||||
}
|
||||
|
||||
if(candidates.Count > 1)
|
||||
{
|
||||
DicConsole.WriteLine("More than one plugin supports requested extension.");
|
||||
|
||||
return(int)ErrorNumber.TooManyFormats;
|
||||
}
|
||||
|
||||
IWritableImage outputFormat = candidates[0];
|
||||
|
||||
if(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(int)ErrorNumber.UnsupportedMedia;
|
||||
}
|
||||
|
||||
foreach(MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags)
|
||||
{
|
||||
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(int)ErrorNumber.DataWillBeLost;
|
||||
}
|
||||
|
||||
bool useLong = inputFormat.Info.ReadableSectorTags.Count != 0;
|
||||
|
||||
foreach(SectorTagType sectorTag in inputFormat.Info.ReadableSectorTags)
|
||||
{
|
||||
if(outputFormat.SupportedSectorTags.Contains(sectorTag))
|
||||
continue;
|
||||
|
||||
if(force)
|
||||
{
|
||||
if(sectorTag != SectorTagType.CdTrackFlags &&
|
||||
sectorTag != SectorTagType.CdTrackIsrc &&
|
||||
sectorTag != SectorTagType.CdSectorSubchannel)
|
||||
useLong = false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
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(int)ErrorNumber.DataWillBeLost;
|
||||
}
|
||||
|
||||
if(!outputFormat.Create(outputPath, inputFormat.Info.MediaType, parsedOptions, inputFormat.Info.Sectors,
|
||||
inputFormat.Info.SectorSize))
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Error {0} creating output image.", outputFormat.ErrorMessage);
|
||||
|
||||
return(int)ErrorNumber.CannotCreateFormat;
|
||||
}
|
||||
|
||||
var metadata = new ImageInfo
|
||||
{
|
||||
Application = "DiscImageChef",
|
||||
ApplicationVersion = Version.GetVersion(),
|
||||
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(!force)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("not continuing...");
|
||||
|
||||
return(int)ErrorNumber.WriteError;
|
||||
}
|
||||
|
||||
DicConsole.ErrorWriteLine("continuing...");
|
||||
}
|
||||
|
||||
CICMMetadataType cicmMetadata = inputFormat.CicmMetadata;
|
||||
List<DumpHardwareType> dumpHardware = inputFormat.DumpHardware;
|
||||
|
||||
foreach(MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags)
|
||||
{
|
||||
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(force)
|
||||
DicConsole.ErrorWriteLine("Error {0} writing media tag, continuing...", outputFormat.ErrorMessage);
|
||||
else
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Error {0} writing media tag, not continuing...",
|
||||
outputFormat.ErrorMessage);
|
||||
|
||||
return(int)ErrorNumber.WriteError;
|
||||
}
|
||||
}
|
||||
|
||||
DicConsole.WriteLine("{0} sectors to convert", inputFormat.Info.Sectors);
|
||||
ulong doneSectors = 0;
|
||||
|
||||
if(inputFormat is IOpticalMediaImage inputOptical &&
|
||||
outputFormat is IWritableOpticalImage outputOptical &&
|
||||
inputOptical.Tracks != null)
|
||||
{
|
||||
if(!outputOptical.SetTracks(inputOptical.Tracks))
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Error {0} sending tracks list to output image.",
|
||||
outputFormat.ErrorMessage);
|
||||
|
||||
return(int)ErrorNumber.WriteError;
|
||||
}
|
||||
|
||||
foreach(Track track in inputOptical.Tracks)
|
||||
{
|
||||
doneSectors = 0;
|
||||
ulong trackSectors = (track.TrackEndSector - track.TrackStartSector) + 1;
|
||||
|
||||
while(doneSectors < trackSectors)
|
||||
{
|
||||
byte[] sector;
|
||||
|
||||
uint sectorsToDo;
|
||||
|
||||
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,
|
||||
doneSectors + sectorsToDo + track.TrackStartSector,
|
||||
(doneSectors + track.TrackStartSector) / (double)inputFormat.Info.Sectors,
|
||||
track.TrackSequence);
|
||||
|
||||
bool result;
|
||||
|
||||
if(useLong)
|
||||
if(sectorsToDo == 1)
|
||||
{
|
||||
sector = inputFormat.ReadSectorLong(doneSectors + track.TrackStartSector);
|
||||
result = outputFormat.WriteSectorLong(sector, doneSectors + track.TrackStartSector);
|
||||
}
|
||||
else
|
||||
{
|
||||
sector = inputFormat.ReadSectorsLong(doneSectors + track.TrackStartSector, sectorsToDo);
|
||||
|
||||
result = outputFormat.WriteSectorsLong(sector, doneSectors + track.TrackStartSector,
|
||||
sectorsToDo);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sectorsToDo == 1)
|
||||
{
|
||||
sector = inputFormat.ReadSector(doneSectors + track.TrackStartSector);
|
||||
result = outputFormat.WriteSector(sector, doneSectors + track.TrackStartSector);
|
||||
}
|
||||
else
|
||||
{
|
||||
sector = inputFormat.ReadSectors(doneSectors + track.TrackStartSector, sectorsToDo);
|
||||
|
||||
result = outputFormat.WriteSectors(sector, doneSectors + track.TrackStartSector,
|
||||
sectorsToDo);
|
||||
}
|
||||
}
|
||||
|
||||
if(!result)
|
||||
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(int)ErrorNumber.WriteError;
|
||||
}
|
||||
|
||||
doneSectors += sectorsToDo;
|
||||
}
|
||||
}
|
||||
|
||||
DicConsole.Write("\rConverting sectors {0} to {1} in track {3} ({2:P2} done)", inputFormat.Info.Sectors,
|
||||
inputFormat.Info.Sectors, 1.0, inputOptical.Tracks.Count);
|
||||
|
||||
DicConsole.WriteLine();
|
||||
|
||||
foreach(SectorTagType tag in inputFormat.Info.ReadableSectorTags.OrderBy(t => t))
|
||||
{
|
||||
if(!useLong)
|
||||
break;
|
||||
|
||||
switch(tag)
|
||||
{
|
||||
case SectorTagType.AppleSectorTag:
|
||||
case SectorTagType.CdSectorSync:
|
||||
case SectorTagType.CdSectorHeader:
|
||||
case SectorTagType.CdSectorSubHeader:
|
||||
case SectorTagType.CdSectorEdc:
|
||||
case SectorTagType.CdSectorEccP:
|
||||
case SectorTagType.CdSectorEccQ:
|
||||
case SectorTagType.CdSectorEcc:
|
||||
// This tags are inline in long sector
|
||||
continue;
|
||||
}
|
||||
|
||||
if(force && !outputFormat.SupportedSectorTags.Contains(tag))
|
||||
continue;
|
||||
|
||||
foreach(Track track in inputOptical.Tracks)
|
||||
{
|
||||
doneSectors = 0;
|
||||
ulong trackSectors = (track.TrackEndSector - track.TrackStartSector) + 1;
|
||||
byte[] sector;
|
||||
bool result;
|
||||
|
||||
switch(tag)
|
||||
{
|
||||
case SectorTagType.CdTrackFlags:
|
||||
case SectorTagType.CdTrackIsrc:
|
||||
DicConsole.Write("\rConverting tag {0} in track {1} ({2:P2} done).", tag,
|
||||
track.TrackSequence,
|
||||
track.TrackSequence / (double)inputOptical.Tracks.Count);
|
||||
|
||||
sector = inputFormat.ReadSectorTag(track.TrackStartSector, tag);
|
||||
result = outputFormat.WriteSectorTag(sector, track.TrackStartSector, tag);
|
||||
|
||||
if(!result)
|
||||
if(force)
|
||||
DicConsole.ErrorWriteLine("Error {0} writing tag, continuing...",
|
||||
outputFormat.ErrorMessage);
|
||||
else
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Error {0} writing tag, not continuing...",
|
||||
outputFormat.ErrorMessage);
|
||||
|
||||
return(int)ErrorNumber.WriteError;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
while(doneSectors < trackSectors)
|
||||
{
|
||||
uint sectorsToDo;
|
||||
|
||||
if(trackSectors - doneSectors >= (ulong)count)
|
||||
sectorsToDo = (uint)count;
|
||||
else
|
||||
sectorsToDo = (uint)(trackSectors - doneSectors);
|
||||
|
||||
DicConsole.Write("\rConverting tag {4} for sectors {0} to {1} in track {3} ({2:P2} done)",
|
||||
doneSectors + track.TrackStartSector,
|
||||
doneSectors + sectorsToDo + track.TrackStartSector,
|
||||
(doneSectors + track.TrackStartSector) / (double)inputFormat.Info.Sectors,
|
||||
track.TrackSequence, tag);
|
||||
|
||||
if(sectorsToDo == 1)
|
||||
{
|
||||
sector = inputFormat.ReadSectorTag(doneSectors + track.TrackStartSector, tag);
|
||||
result = outputFormat.WriteSectorTag(sector, doneSectors + track.TrackStartSector, tag);
|
||||
}
|
||||
else
|
||||
{
|
||||
sector = inputFormat.ReadSectorsTag(doneSectors + track.TrackStartSector, sectorsToDo,
|
||||
tag);
|
||||
|
||||
result = outputFormat.WriteSectorsTag(sector, doneSectors + track.TrackStartSector,
|
||||
sectorsToDo, tag);
|
||||
}
|
||||
|
||||
if(!result)
|
||||
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(int)ErrorNumber.WriteError;
|
||||
}
|
||||
|
||||
doneSectors += sectorsToDo;
|
||||
}
|
||||
}
|
||||
|
||||
switch(tag)
|
||||
{
|
||||
case SectorTagType.CdTrackFlags:
|
||||
case SectorTagType.CdTrackIsrc:
|
||||
DicConsole.Write("\rConverting tag {0} in track {1} ({2:P2} done).", tag,
|
||||
inputOptical.Tracks.Count, 1.0);
|
||||
|
||||
break;
|
||||
default:
|
||||
DicConsole.Write("\rConverting tag {4} for sectors {0} to {1} in track {3} ({2:P2} done)",
|
||||
inputFormat.Info.Sectors, inputFormat.Info.Sectors, 1.0,
|
||||
inputOptical.Tracks.Count, tag);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
DicConsole.WriteLine();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DicConsole.WriteLine("Setting geometry to {0} cylinders, {1} heads and {2} sectors per track",
|
||||
inputFormat.Info.Cylinders, inputFormat.Info.Heads,
|
||||
inputFormat.Info.SectorsPerTrack);
|
||||
|
||||
if(!outputFormat.SetGeometry(inputFormat.Info.Cylinders, inputFormat.Info.Heads,
|
||||
inputFormat.Info.SectorsPerTrack))
|
||||
DicConsole.ErrorWriteLine("Error {0} setting geometry, image may be incorrect, continuing...",
|
||||
outputFormat.ErrorMessage);
|
||||
|
||||
while(doneSectors < inputFormat.Info.Sectors)
|
||||
{
|
||||
byte[] sector;
|
||||
|
||||
uint sectorsToDo;
|
||||
|
||||
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);
|
||||
|
||||
bool result;
|
||||
|
||||
if(useLong)
|
||||
if(sectorsToDo == 1)
|
||||
{
|
||||
sector = inputFormat.ReadSectorLong(doneSectors);
|
||||
result = outputFormat.WriteSectorLong(sector, doneSectors);
|
||||
}
|
||||
else
|
||||
{
|
||||
sector = inputFormat.ReadSectorsLong(doneSectors, sectorsToDo);
|
||||
result = outputFormat.WriteSectorsLong(sector, doneSectors, sectorsToDo);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sectorsToDo == 1)
|
||||
{
|
||||
sector = inputFormat.ReadSector(doneSectors);
|
||||
result = outputFormat.WriteSector(sector, doneSectors);
|
||||
}
|
||||
else
|
||||
{
|
||||
sector = inputFormat.ReadSectors(doneSectors, sectorsToDo);
|
||||
result = outputFormat.WriteSectors(sector, doneSectors, sectorsToDo);
|
||||
}
|
||||
}
|
||||
|
||||
if(!result)
|
||||
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(int)ErrorNumber.WriteError;
|
||||
}
|
||||
|
||||
doneSectors += sectorsToDo;
|
||||
}
|
||||
|
||||
DicConsole.Write("\rConverting sectors {0} to {1} ({2:P2} done)", inputFormat.Info.Sectors,
|
||||
inputFormat.Info.Sectors, 1.0);
|
||||
|
||||
DicConsole.WriteLine();
|
||||
|
||||
foreach(SectorTagType tag in inputFormat.Info.ReadableSectorTags)
|
||||
{
|
||||
if(!useLong)
|
||||
break;
|
||||
|
||||
switch(tag)
|
||||
{
|
||||
case SectorTagType.AppleSectorTag:
|
||||
case SectorTagType.CdSectorSync:
|
||||
case SectorTagType.CdSectorHeader:
|
||||
case SectorTagType.CdSectorSubHeader:
|
||||
case SectorTagType.CdSectorEdc:
|
||||
case SectorTagType.CdSectorEccP:
|
||||
case SectorTagType.CdSectorEccQ:
|
||||
case SectorTagType.CdSectorEcc:
|
||||
// This tags are inline in long sector
|
||||
continue;
|
||||
}
|
||||
|
||||
if(force && !outputFormat.SupportedSectorTags.Contains(tag))
|
||||
continue;
|
||||
|
||||
doneSectors = 0;
|
||||
|
||||
while(doneSectors < inputFormat.Info.Sectors)
|
||||
{
|
||||
byte[] sector;
|
||||
|
||||
uint sectorsToDo;
|
||||
|
||||
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,
|
||||
tag);
|
||||
|
||||
bool result;
|
||||
|
||||
if(sectorsToDo == 1)
|
||||
{
|
||||
sector = inputFormat.ReadSectorTag(doneSectors, tag);
|
||||
result = outputFormat.WriteSectorTag(sector, doneSectors, tag);
|
||||
}
|
||||
else
|
||||
{
|
||||
sector = inputFormat.ReadSectorsTag(doneSectors, sectorsToDo, tag);
|
||||
result = outputFormat.WriteSectorsTag(sector, doneSectors, sectorsToDo, tag);
|
||||
}
|
||||
|
||||
if(!result)
|
||||
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(int)ErrorNumber.WriteError;
|
||||
}
|
||||
|
||||
doneSectors += sectorsToDo;
|
||||
}
|
||||
|
||||
DicConsole.Write("\rConverting tag {2} for sectors {0} to {1} ({2:P2} done)",
|
||||
inputFormat.Info.Sectors, inputFormat.Info.Sectors, 1.0, tag);
|
||||
|
||||
DicConsole.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
|
||||
if(resume != null ||
|
||||
dumpHardware != null)
|
||||
{
|
||||
if(resume != null)
|
||||
ret = outputFormat.SetDumpHardware(resume.Tries);
|
||||
else if(dumpHardware != null)
|
||||
ret = outputFormat.SetDumpHardware(dumpHardware);
|
||||
|
||||
if(ret)
|
||||
DicConsole.WriteLine("Written dump hardware list to output image.");
|
||||
}
|
||||
|
||||
ret = false;
|
||||
|
||||
if(sidecar != null ||
|
||||
cicmMetadata != null)
|
||||
{
|
||||
if(sidecar != null)
|
||||
ret = outputFormat.SetCicmMetadata(sidecar);
|
||||
else if(cicmMetadata != null)
|
||||
ret = outputFormat.SetCicmMetadata(cicmMetadata);
|
||||
|
||||
if(ret)
|
||||
DicConsole.WriteLine("Written CICM XML metadata to output image.");
|
||||
}
|
||||
|
||||
DicConsole.WriteLine("Closing output image.");
|
||||
|
||||
if(!outputFormat.Close())
|
||||
DicConsole.ErrorWriteLine("Error {0} closing output image... Contents are not correct.",
|
||||
outputFormat.ErrorMessage);
|
||||
|
||||
DicConsole.WriteLine();
|
||||
DicConsole.WriteLine("Conversion done.");
|
||||
|
||||
return(int)ErrorNumber.NoError;
|
||||
}
|
||||
}
|
||||
}
|
||||
261
DiscImageChef/Commands/Image/CreateSidecar.cs
Normal file
261
DiscImageChef/Commands/Image/CreateSidecar.cs
Normal file
@@ -0,0 +1,261 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : CreateSidecar.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Verbs.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements the 'create-sidecar' 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2019 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.Console;
|
||||
using DiscImageChef.Core;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.Commands.Image
|
||||
{
|
||||
internal class CreateSidecarCommand : Command
|
||||
{
|
||||
public CreateSidecarCommand() : base("create-sidecar", "Creates CICM Metadata XML sidecar.")
|
||||
{
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--block-size", "-b"
|
||||
},
|
||||
"Only used for tapes, indicates block size. Files in the folder whose size is not a multiple of this value will simply be ignored.")
|
||||
{
|
||||
Argument = new Argument<int>(() => 512), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--encoding", "-e"
|
||||
}, "Name of character encoding to use.")
|
||||
{
|
||||
Argument = new Argument<string>(() => null), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--tape", "-t"
|
||||
},
|
||||
"When used indicates that input is a folder containing alphabetically sorted files extracted from a linear block-based tape with fixed block size (e.g. a SCSI tape device).")
|
||||
{
|
||||
Argument = new Argument<bool>(() => false), Required = false
|
||||
});
|
||||
|
||||
AddArgument(new Argument<string>
|
||||
{
|
||||
Arity = ArgumentArity.ExactlyOne, Description = "Media image path", Name = "image-path"
|
||||
});
|
||||
|
||||
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
|
||||
}
|
||||
|
||||
public static int Invoke(bool debug, bool verbose, uint blockSize, string encodingName, string imagePath,
|
||||
bool tape)
|
||||
{
|
||||
MainClass.PrintCopyright();
|
||||
|
||||
if(debug)
|
||||
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
|
||||
|
||||
if(verbose)
|
||||
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
|
||||
|
||||
Statistics.AddCommand("create-sidecar");
|
||||
|
||||
DicConsole.DebugWriteLine("Create sidecar command", "--block-size={0}", blockSize);
|
||||
DicConsole.DebugWriteLine("Create sidecar command", "--debug={0}", debug);
|
||||
DicConsole.DebugWriteLine("Create sidecar command", "--encoding={0}", encodingName);
|
||||
DicConsole.DebugWriteLine("Create sidecar command", "--input={0}", imagePath);
|
||||
DicConsole.DebugWriteLine("Create sidecar command", "--tape={0}", tape);
|
||||
DicConsole.DebugWriteLine("Create sidecar command", "--verbose={0}", verbose);
|
||||
|
||||
Encoding encodingClass = null;
|
||||
|
||||
if(encodingName != null)
|
||||
try
|
||||
{
|
||||
encodingClass = Claunia.Encoding.Encoding.GetEncoding(encodingName);
|
||||
|
||||
if(verbose)
|
||||
DicConsole.VerboseWriteLine("Using encoding for {0}.", encodingClass.EncodingName);
|
||||
}
|
||||
catch(ArgumentException)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Specified encoding is not supported.");
|
||||
|
||||
return(int)ErrorNumber.EncodingUnknown;
|
||||
}
|
||||
|
||||
if(File.Exists(imagePath))
|
||||
{
|
||||
if(tape)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("You cannot use --tape option when input is a file.");
|
||||
|
||||
return(int)ErrorNumber.ExpectedDirectory;
|
||||
}
|
||||
|
||||
var filtersList = new FiltersList();
|
||||
IFilter inputFilter = filtersList.GetFilter(imagePath);
|
||||
|
||||
if(inputFilter == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Cannot open specified file.");
|
||||
|
||||
return(int)ErrorNumber.CannotOpenFile;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
IMediaImage imageFormat = ImageFormat.Detect(inputFilter);
|
||||
|
||||
if(imageFormat == null)
|
||||
{
|
||||
DicConsole.WriteLine("Image format not identified, not proceeding with analysis.");
|
||||
|
||||
return(int)ErrorNumber.UnrecognizedFormat;
|
||||
}
|
||||
|
||||
if(verbose)
|
||||
DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name,
|
||||
imageFormat.Id);
|
||||
else
|
||||
DicConsole.WriteLine("Image format identified by {0}.", imageFormat.Name);
|
||||
|
||||
try
|
||||
{
|
||||
if(!imageFormat.Open(inputFilter))
|
||||
{
|
||||
DicConsole.WriteLine("Unable to open image format");
|
||||
DicConsole.WriteLine("No error given");
|
||||
|
||||
return(int)ErrorNumber.CannotOpenFormat;
|
||||
}
|
||||
|
||||
DicConsole.DebugWriteLine("Analyze command", "Correctly opened image file.");
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Unable to open image format");
|
||||
DicConsole.ErrorWriteLine("Error: {0}", ex.Message);
|
||||
|
||||
return(int)ErrorNumber.CannotOpenFormat;
|
||||
}
|
||||
|
||||
Statistics.AddMediaFormat(imageFormat.Format);
|
||||
Statistics.AddFilter(inputFilter.Name);
|
||||
|
||||
var sidecarClass = new Sidecar(imageFormat, imagePath, inputFilter.Id, encodingClass);
|
||||
sidecarClass.InitProgressEvent += Progress.InitProgress;
|
||||
sidecarClass.UpdateProgressEvent += Progress.UpdateProgress;
|
||||
sidecarClass.EndProgressEvent += Progress.EndProgress;
|
||||
sidecarClass.InitProgressEvent2 += Progress.InitProgress2;
|
||||
sidecarClass.UpdateProgressEvent2 += Progress.UpdateProgress2;
|
||||
sidecarClass.EndProgressEvent2 += Progress.EndProgress2;
|
||||
sidecarClass.UpdateStatusEvent += Progress.UpdateStatus;
|
||||
|
||||
System.Console.CancelKeyPress += (sender, e) =>
|
||||
{
|
||||
e.Cancel = true;
|
||||
sidecarClass.Abort();
|
||||
};
|
||||
|
||||
CICMMetadataType sidecar = sidecarClass.Create();
|
||||
|
||||
DicConsole.WriteLine("Writing metadata sidecar");
|
||||
|
||||
var xmlFs =
|
||||
new
|
||||
FileStream(Path.Combine(Path.GetDirectoryName(imagePath) ?? throw new InvalidOperationException(), Path.GetFileNameWithoutExtension(imagePath) + ".cicm.xml"),
|
||||
FileMode.CreateNew);
|
||||
|
||||
var xmlSer = new XmlSerializer(typeof(CICMMetadataType));
|
||||
xmlSer.Serialize(xmlFs, sidecar);
|
||||
xmlFs.Close();
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
DicConsole.ErrorWriteLine($"Error reading file: {ex.Message}");
|
||||
DicConsole.DebugWriteLine("Analyze command", ex.StackTrace);
|
||||
|
||||
return(int)ErrorNumber.UnexpectedException;
|
||||
}
|
||||
}
|
||||
else if(Directory.Exists(imagePath))
|
||||
{
|
||||
if(!tape)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Cannot create a sidecar from a directory.");
|
||||
|
||||
return(int)ErrorNumber.ExpectedFile;
|
||||
}
|
||||
|
||||
string[] contents = Directory.GetFiles(imagePath, "*", SearchOption.TopDirectoryOnly);
|
||||
List<string> files = contents.Where(file => new FileInfo(file).Length % blockSize == 0).ToList();
|
||||
|
||||
files.Sort(StringComparer.CurrentCultureIgnoreCase);
|
||||
|
||||
var sidecarClass = new Sidecar();
|
||||
sidecarClass.InitProgressEvent += Progress.InitProgress;
|
||||
sidecarClass.UpdateProgressEvent += Progress.UpdateProgress;
|
||||
sidecarClass.EndProgressEvent += Progress.EndProgress;
|
||||
sidecarClass.InitProgressEvent2 += Progress.InitProgress2;
|
||||
sidecarClass.UpdateProgressEvent2 += Progress.UpdateProgress2;
|
||||
sidecarClass.EndProgressEvent2 += Progress.EndProgress2;
|
||||
sidecarClass.UpdateStatusEvent += Progress.UpdateStatus;
|
||||
CICMMetadataType sidecar = sidecarClass.BlockTape(Path.GetFileName(imagePath), files, blockSize);
|
||||
|
||||
DicConsole.WriteLine("Writing metadata sidecar");
|
||||
|
||||
var xmlFs =
|
||||
new
|
||||
FileStream(Path.Combine(Path.GetDirectoryName(imagePath) ?? throw new InvalidOperationException(), Path.GetFileNameWithoutExtension(imagePath) + ".cicm.xml"),
|
||||
FileMode.CreateNew);
|
||||
|
||||
var xmlSer = new XmlSerializer(typeof(CICMMetadataType));
|
||||
xmlSer.Serialize(xmlFs, sidecar);
|
||||
xmlFs.Close();
|
||||
}
|
||||
else
|
||||
DicConsole.ErrorWriteLine("The specified input file cannot be found.");
|
||||
|
||||
return(int)ErrorNumber.NoError;
|
||||
}
|
||||
}
|
||||
}
|
||||
372
DiscImageChef/Commands/Image/Decode.cs
Normal file
372
DiscImageChef/Commands/Image/Decode.cs
Normal file
@@ -0,0 +1,372 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Decode.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Verbs.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements the 'decode' 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2019 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.Console;
|
||||
using DiscImageChef.Core;
|
||||
using DiscImageChef.Decoders.ATA;
|
||||
using DiscImageChef.Decoders.CD;
|
||||
using DiscImageChef.Decoders.SCSI;
|
||||
|
||||
namespace DiscImageChef.Commands.Image
|
||||
{
|
||||
internal class DecodeCommand : Command
|
||||
{
|
||||
public DecodeCommand() : base("decode", "Decodes and pretty prints disk and/or sector tags.")
|
||||
{
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--disk-tags", "-f"
|
||||
}, "Decode disk tags.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--length", "-l"
|
||||
}, "How many sectors to decode, or \"all\".")
|
||||
{
|
||||
Argument = new Argument<string>(() => "all"), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--sector-tags", "-p"
|
||||
}, "Decode sector tags.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--start", "-s"
|
||||
}, "Sector to start decoding from.")
|
||||
{
|
||||
Argument = new Argument<ulong>(() => 0), Required = false
|
||||
});
|
||||
|
||||
AddArgument(new Argument<string>
|
||||
{
|
||||
Arity = ArgumentArity.ExactlyOne, Description = "Media image path", Name = "image-path"
|
||||
});
|
||||
|
||||
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
|
||||
}
|
||||
|
||||
public static int Invoke(bool verbose, bool debug, bool diskTags, string imagePath, string length,
|
||||
bool sectorTags, ulong startSector)
|
||||
{
|
||||
MainClass.PrintCopyright();
|
||||
|
||||
if(debug)
|
||||
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
|
||||
|
||||
if(verbose)
|
||||
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
|
||||
|
||||
Statistics.AddCommand("decode");
|
||||
|
||||
DicConsole.DebugWriteLine("Decode command", "--debug={0}", debug);
|
||||
DicConsole.DebugWriteLine("Decode command", "--disk-tags={0}", diskTags);
|
||||
DicConsole.DebugWriteLine("Decode command", "--input={0}", imagePath);
|
||||
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}", verbose);
|
||||
|
||||
var filtersList = new FiltersList();
|
||||
IFilter inputFilter = filtersList.GetFilter(imagePath);
|
||||
|
||||
if(inputFilter == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Cannot open specified file.");
|
||||
|
||||
return(int)ErrorNumber.CannotOpenFile;
|
||||
}
|
||||
|
||||
IMediaImage inputFormat = ImageFormat.Detect(inputFilter);
|
||||
|
||||
if(inputFormat == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Unable to recognize image format, not decoding");
|
||||
|
||||
return(int)ErrorNumber.UnrecognizedFormat;
|
||||
}
|
||||
|
||||
inputFormat.Open(inputFilter);
|
||||
Statistics.AddMediaFormat(inputFormat.Format);
|
||||
Statistics.AddMedia(inputFormat.Info.MediaType, false);
|
||||
Statistics.AddFilter(inputFilter.Name);
|
||||
|
||||
if(diskTags)
|
||||
if(inputFormat.Info.ReadableMediaTags.Count == 0)
|
||||
DicConsole.WriteLine("There are no disk tags in chosen disc image.");
|
||||
else
|
||||
foreach(MediaTagType tag in inputFormat.Info.ReadableMediaTags)
|
||||
switch(tag)
|
||||
{
|
||||
case MediaTagType.SCSI_INQUIRY:
|
||||
{
|
||||
byte[] inquiry = inputFormat.ReadDiskTag(MediaTagType.SCSI_INQUIRY);
|
||||
|
||||
if(inquiry == null)
|
||||
DicConsole.WriteLine("Error reading SCSI INQUIRY response from disc image");
|
||||
else
|
||||
{
|
||||
DicConsole.WriteLine("SCSI INQUIRY command response:");
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
|
||||
DicConsole.WriteLine(Inquiry.Prettify(inquiry));
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MediaTagType.ATA_IDENTIFY:
|
||||
{
|
||||
byte[] identify = inputFormat.ReadDiskTag(MediaTagType.ATA_IDENTIFY);
|
||||
|
||||
if(identify == null)
|
||||
DicConsole.WriteLine("Error reading ATA IDENTIFY DEVICE response from disc image");
|
||||
else
|
||||
{
|
||||
DicConsole.WriteLine("ATA IDENTIFY DEVICE command response:");
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
|
||||
DicConsole.WriteLine(Identify.Prettify(identify));
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MediaTagType.ATAPI_IDENTIFY:
|
||||
{
|
||||
byte[] identify = inputFormat.ReadDiskTag(MediaTagType.ATAPI_IDENTIFY);
|
||||
|
||||
if(identify == null)
|
||||
DicConsole.
|
||||
WriteLine("Error reading ATA IDENTIFY PACKET DEVICE response from disc image");
|
||||
else
|
||||
{
|
||||
DicConsole.WriteLine("ATA IDENTIFY PACKET DEVICE command response:");
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
|
||||
DicConsole.WriteLine(Identify.Prettify(identify));
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MediaTagType.CD_ATIP:
|
||||
{
|
||||
byte[] atip = inputFormat.ReadDiskTag(MediaTagType.CD_ATIP);
|
||||
|
||||
if(atip == null)
|
||||
DicConsole.WriteLine("Error reading CD ATIP from disc image");
|
||||
else
|
||||
{
|
||||
DicConsole.WriteLine("CD ATIP:");
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
|
||||
DicConsole.WriteLine(ATIP.Prettify(atip));
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MediaTagType.CD_FullTOC:
|
||||
{
|
||||
byte[] fullToc = inputFormat.ReadDiskTag(MediaTagType.CD_FullTOC);
|
||||
|
||||
if(fullToc == null)
|
||||
DicConsole.WriteLine("Error reading CD full TOC from disc image");
|
||||
else
|
||||
{
|
||||
DicConsole.WriteLine("CD full TOC:");
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
|
||||
DicConsole.WriteLine(FullTOC.Prettify(fullToc));
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MediaTagType.CD_PMA:
|
||||
{
|
||||
byte[] pma = inputFormat.ReadDiskTag(MediaTagType.CD_PMA);
|
||||
|
||||
if(pma == null)
|
||||
DicConsole.WriteLine("Error reading CD PMA from disc image");
|
||||
else
|
||||
{
|
||||
DicConsole.WriteLine("CD PMA:");
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
|
||||
DicConsole.WriteLine(PMA.Prettify(pma));
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MediaTagType.CD_SessionInfo:
|
||||
{
|
||||
byte[] sessionInfo = inputFormat.ReadDiskTag(MediaTagType.CD_SessionInfo);
|
||||
|
||||
if(sessionInfo == null)
|
||||
DicConsole.WriteLine("Error reading CD session information from disc image");
|
||||
else
|
||||
{
|
||||
DicConsole.WriteLine("CD session information:");
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
|
||||
DicConsole.WriteLine(Session.Prettify(sessionInfo));
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MediaTagType.CD_TEXT:
|
||||
{
|
||||
byte[] cdText = inputFormat.ReadDiskTag(MediaTagType.CD_TEXT);
|
||||
|
||||
if(cdText == null)
|
||||
DicConsole.WriteLine("Error reading CD-TEXT from disc image");
|
||||
else
|
||||
{
|
||||
DicConsole.WriteLine("CD-TEXT:");
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
|
||||
DicConsole.WriteLine(CDTextOnLeadIn.Prettify(cdText));
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MediaTagType.CD_TOC:
|
||||
{
|
||||
byte[] toc = inputFormat.ReadDiskTag(MediaTagType.CD_TOC);
|
||||
|
||||
if(toc == null)
|
||||
DicConsole.WriteLine("Error reading CD TOC from disc image");
|
||||
else
|
||||
{
|
||||
DicConsole.WriteLine("CD TOC:");
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
|
||||
DicConsole.WriteLine(TOC.Prettify(toc));
|
||||
|
||||
DicConsole.
|
||||
WriteLine("================================================================================");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DicConsole.WriteLine("Decoder for disk tag type \"{0}\" not yet implemented, sorry.",
|
||||
tag);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(sectorTags)
|
||||
{
|
||||
if(length.ToLowerInvariant() == "all") { }
|
||||
else
|
||||
{
|
||||
if(!ulong.TryParse(length, out ulong _))
|
||||
{
|
||||
DicConsole.WriteLine("Value \"{0}\" is not a valid number for length.", length);
|
||||
DicConsole.WriteLine("Not decoding sectors tags");
|
||||
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
if(inputFormat.Info.ReadableSectorTags.Count == 0)
|
||||
DicConsole.WriteLine("There are no sector tags in chosen disc image.");
|
||||
else
|
||||
foreach(SectorTagType tag in inputFormat.Info.ReadableSectorTags)
|
||||
switch(tag)
|
||||
{
|
||||
default:
|
||||
DicConsole.WriteLine("Decoder for disk tag type \"{0}\" not yet implemented, sorry.",
|
||||
tag);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Not implemented
|
||||
}
|
||||
|
||||
return(int)ErrorNumber.NoError;
|
||||
}
|
||||
}
|
||||
}
|
||||
160
DiscImageChef/Commands/Image/Entropy.cs
Normal file
160
DiscImageChef/Commands/Image/Entropy.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Entropy.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Verbs.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements the 'entropy' 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2019 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.Console;
|
||||
using DiscImageChef.Core;
|
||||
|
||||
namespace DiscImageChef.Commands.Image
|
||||
{
|
||||
internal class EntropyCommand : Command
|
||||
{
|
||||
public EntropyCommand() : base("entropy", "Calculates entropy and/or duplicated sectors of an image.")
|
||||
{
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--duplicated-sectors", "-p"
|
||||
}, "Calculates how many sectors are duplicated (have same exact data in user area).")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--separated-tracks", "-t"
|
||||
}, "Calculates entropy for each track separately.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--whole-disc", "-w"
|
||||
}, "Calculates entropy for the whole disc.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
AddArgument(new Argument<string>
|
||||
{
|
||||
Arity = ArgumentArity.ExactlyOne, Description = "Media image path", Name = "image-path"
|
||||
});
|
||||
|
||||
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
|
||||
}
|
||||
|
||||
public static int Invoke(bool debug, bool verbose, bool duplicatedSectors, string imagePath,
|
||||
bool separatedTracks, bool wholeDisc)
|
||||
{
|
||||
MainClass.PrintCopyright();
|
||||
|
||||
if(debug)
|
||||
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
|
||||
|
||||
if(verbose)
|
||||
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
|
||||
|
||||
Statistics.AddCommand("entropy");
|
||||
|
||||
DicConsole.DebugWriteLine("Entropy command", "--debug={0}", debug);
|
||||
DicConsole.DebugWriteLine("Entropy command", "--duplicated-sectors={0}", duplicatedSectors);
|
||||
DicConsole.DebugWriteLine("Entropy command", "--input={0}", imagePath);
|
||||
DicConsole.DebugWriteLine("Entropy command", "--separated-tracks={0}", separatedTracks);
|
||||
DicConsole.DebugWriteLine("Entropy command", "--verbose={0}", verbose);
|
||||
DicConsole.DebugWriteLine("Entropy command", "--whole-disc={0}", wholeDisc);
|
||||
|
||||
var filtersList = new FiltersList();
|
||||
IFilter inputFilter = filtersList.GetFilter(imagePath);
|
||||
|
||||
if(inputFilter == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Cannot open specified file.");
|
||||
|
||||
return(int)ErrorNumber.CannotOpenFile;
|
||||
}
|
||||
|
||||
IMediaImage inputFormat = ImageFormat.Detect(inputFilter);
|
||||
|
||||
if(inputFormat == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Unable to recognize image format, not checksumming");
|
||||
|
||||
return(int)ErrorNumber.UnrecognizedFormat;
|
||||
}
|
||||
|
||||
inputFormat.Open(inputFilter);
|
||||
Statistics.AddMediaFormat(inputFormat.Format);
|
||||
Statistics.AddMedia(inputFormat.Info.MediaType, false);
|
||||
Statistics.AddFilter(inputFilter.Name);
|
||||
|
||||
var entropyCalculator = new Entropy(debug, verbose, inputFormat);
|
||||
entropyCalculator.InitProgressEvent += Progress.InitProgress;
|
||||
entropyCalculator.InitProgress2Event += Progress.InitProgress2;
|
||||
entropyCalculator.UpdateProgressEvent += Progress.UpdateProgress;
|
||||
entropyCalculator.UpdateProgress2Event += Progress.UpdateProgress2;
|
||||
entropyCalculator.EndProgressEvent += Progress.EndProgress;
|
||||
entropyCalculator.EndProgress2Event += Progress.EndProgress2;
|
||||
|
||||
if(separatedTracks)
|
||||
{
|
||||
EntropyResults[] tracksEntropy = entropyCalculator.CalculateTracksEntropy(duplicatedSectors);
|
||||
|
||||
foreach(EntropyResults trackEntropy in tracksEntropy)
|
||||
{
|
||||
DicConsole.WriteLine("Entropy for track {0} is {1:F4}.", trackEntropy.Track, trackEntropy.Entropy);
|
||||
|
||||
if(trackEntropy.UniqueSectors != null)
|
||||
DicConsole.WriteLine("Track {0} has {1} unique sectors ({2:P3})", trackEntropy.Track,
|
||||
trackEntropy.UniqueSectors,
|
||||
(double)trackEntropy.UniqueSectors / (double)trackEntropy.Sectors);
|
||||
}
|
||||
}
|
||||
|
||||
if(!wholeDisc)
|
||||
return(int)ErrorNumber.NoError;
|
||||
|
||||
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);
|
||||
|
||||
return(int)ErrorNumber.NoError;
|
||||
}
|
||||
}
|
||||
}
|
||||
55
DiscImageChef/Commands/Image/ImageFamily.cs
Normal file
55
DiscImageChef/Commands/Image/ImageFamily.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : ImageFamily.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Verbs.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements the 'image' 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2019 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.CommandLine;
|
||||
|
||||
namespace DiscImageChef.Commands.Image
|
||||
{
|
||||
public class ImageFamily : Command
|
||||
{
|
||||
public ImageFamily() : base("image", "Commands to manage images")
|
||||
{
|
||||
AddAlias("i");
|
||||
|
||||
AddCommand(new AnalyzeCommand());
|
||||
AddCommand(new ChecksumCommand());
|
||||
AddCommand(new CompareCommand());
|
||||
AddCommand(new ConvertImageCommand());
|
||||
AddCommand(new CreateSidecarCommand());
|
||||
AddCommand(new DecodeCommand());
|
||||
AddCommand(new EntropyCommand());
|
||||
AddCommand(new ImageInfoCommand());
|
||||
AddCommand(new PrintHexCommand());
|
||||
AddCommand(new VerifyCommand());
|
||||
}
|
||||
}
|
||||
}
|
||||
133
DiscImageChef/Commands/Image/ImageInfo.cs
Normal file
133
DiscImageChef/Commands/Image/ImageInfo.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : ImageInfo.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Verbs.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements the 'image-info' 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2019 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.Console;
|
||||
using DiscImageChef.Core;
|
||||
|
||||
namespace DiscImageChef.Commands.Image
|
||||
{
|
||||
internal class ImageInfoCommand : Command
|
||||
{
|
||||
public ImageInfoCommand() : base("image-info",
|
||||
"Opens a media image and shows information about the media it represents and metadata.")
|
||||
{
|
||||
AddArgument(new Argument<string>
|
||||
{
|
||||
Arity = ArgumentArity.ExactlyOne, Description = "Media image path", Name = "image-path"
|
||||
});
|
||||
|
||||
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
|
||||
}
|
||||
|
||||
public static int Invoke(bool debug, bool verbose, string imagePath)
|
||||
{
|
||||
MainClass.PrintCopyright();
|
||||
|
||||
if(debug)
|
||||
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
|
||||
|
||||
if(verbose)
|
||||
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
|
||||
|
||||
Statistics.AddCommand("image-info");
|
||||
|
||||
DicConsole.DebugWriteLine("Analyze command", "--debug={0}", debug);
|
||||
DicConsole.DebugWriteLine("Analyze command", "--input={0}", imagePath);
|
||||
DicConsole.DebugWriteLine("Analyze command", "--verbose={0}", verbose);
|
||||
|
||||
var filtersList = new FiltersList();
|
||||
IFilter inputFilter = filtersList.GetFilter(imagePath);
|
||||
|
||||
if(inputFilter == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Cannot open specified file.");
|
||||
|
||||
return(int)ErrorNumber.CannotOpenFile;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
IMediaImage imageFormat = ImageFormat.Detect(inputFilter);
|
||||
|
||||
if(imageFormat == null)
|
||||
{
|
||||
DicConsole.WriteLine("Image format not identified.");
|
||||
|
||||
return(int)ErrorNumber.UnrecognizedFormat;
|
||||
}
|
||||
|
||||
DicConsole.WriteLine("Image format identified by {0} ({1}).", imageFormat.Name, imageFormat.Id);
|
||||
DicConsole.WriteLine();
|
||||
|
||||
try
|
||||
{
|
||||
if(!imageFormat.Open(inputFilter))
|
||||
{
|
||||
DicConsole.WriteLine("Unable to open image format");
|
||||
DicConsole.WriteLine("No error given");
|
||||
|
||||
return(int)ErrorNumber.CannotOpenFormat;
|
||||
}
|
||||
|
||||
ImageInfo.PrintImageInfo(imageFormat);
|
||||
|
||||
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("Image-info command", "Stack trace: {0}", ex.StackTrace);
|
||||
|
||||
return(int)ErrorNumber.CannotOpenFormat;
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
DicConsole.ErrorWriteLine($"Error reading file: {ex.Message}");
|
||||
DicConsole.DebugWriteLine("Image-info command", ex.StackTrace);
|
||||
|
||||
return(int)ErrorNumber.UnexpectedException;
|
||||
}
|
||||
|
||||
return(int)ErrorNumber.NoError;
|
||||
}
|
||||
}
|
||||
}
|
||||
160
DiscImageChef/Commands/Image/PrintHex.cs
Normal file
160
DiscImageChef/Commands/Image/PrintHex.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : PrintHex.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Verbs.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements the 'printhex' 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2019 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.Console;
|
||||
using DiscImageChef.Core;
|
||||
|
||||
namespace DiscImageChef.Commands.Image
|
||||
{
|
||||
internal class PrintHexCommand : Command
|
||||
{
|
||||
public PrintHexCommand() : base("printhex", "Prints a sector, in hexadecimal values, to the console.")
|
||||
{
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--length", "-l"
|
||||
}, "How many sectors to print.")
|
||||
{
|
||||
Argument = new Argument<ulong>(() => 1), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--long-sectors", "-r"
|
||||
}, "Print sectors with tags included.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => false), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--start", "-s"
|
||||
}, "Starting sector.")
|
||||
{
|
||||
Argument = new Argument<ulong>(), Required = true
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--width", "-w"
|
||||
}, "How many bytes to print per line.")
|
||||
{
|
||||
Argument = new Argument<ushort>(() => 32), Required = false
|
||||
});
|
||||
|
||||
AddArgument(new Argument<string>
|
||||
{
|
||||
Arity = ArgumentArity.ExactlyOne, Description = "Media image path", Name = "image-path"
|
||||
});
|
||||
|
||||
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
|
||||
}
|
||||
|
||||
public static int Invoke(bool debug, bool verbose, string imagePath, ulong length, bool longSectors,
|
||||
ulong startSector, ushort widthBytes)
|
||||
{
|
||||
MainClass.PrintCopyright();
|
||||
|
||||
if(debug)
|
||||
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
|
||||
|
||||
if(verbose)
|
||||
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
|
||||
|
||||
Statistics.AddCommand("print-hex");
|
||||
|
||||
DicConsole.DebugWriteLine("PrintHex command", "--debug={0}", debug);
|
||||
DicConsole.DebugWriteLine("PrintHex command", "--input={0}", imagePath);
|
||||
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}", verbose);
|
||||
DicConsole.DebugWriteLine("PrintHex command", "--WidthBytes={0}", widthBytes);
|
||||
|
||||
var filtersList = new FiltersList();
|
||||
IFilter inputFilter = filtersList.GetFilter(imagePath);
|
||||
|
||||
if(inputFilter == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Cannot open specified file.");
|
||||
|
||||
return(int)ErrorNumber.CannotOpenFile;
|
||||
}
|
||||
|
||||
IMediaImage inputFormat = ImageFormat.Detect(inputFilter);
|
||||
|
||||
if(inputFormat == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Unable to recognize image format, not verifying");
|
||||
|
||||
return(int)ErrorNumber.UnrecognizedFormat;
|
||||
}
|
||||
|
||||
inputFormat.Open(inputFilter);
|
||||
|
||||
for(ulong i = 0; i < length; 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.");
|
||||
|
||||
longSectors = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(inputFormat.Info.ReadableSectorTags.Count == 0)
|
||||
{
|
||||
DicConsole.
|
||||
WriteLine("Requested sectors with tags, unsupported by underlying image format, printing only user data.");
|
||||
|
||||
longSectors = false;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] sector = longSectors ? inputFormat.ReadSectorLong(startSector + i)
|
||||
: inputFormat.ReadSector(startSector + i);
|
||||
|
||||
PrintHex.PrintHexArray(sector, widthBytes);
|
||||
}
|
||||
|
||||
return(int)ErrorNumber.NoError;
|
||||
}
|
||||
}
|
||||
}
|
||||
319
DiscImageChef/Commands/Image/Verify.cs
Normal file
319
DiscImageChef/Commands/Image/Verify.cs
Normal file
@@ -0,0 +1,319 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Verify.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Verbs.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements the 'verify' 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2019 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using DiscImageChef.Console;
|
||||
using DiscImageChef.Core;
|
||||
|
||||
namespace DiscImageChef.Commands.Image
|
||||
{
|
||||
internal class VerifyCommand : Command
|
||||
{
|
||||
public VerifyCommand() : base("verify", "Verifies a disc image integrity, and if supported, sector integrity.")
|
||||
{
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--verify-disc", "-w"
|
||||
}, "Verify disc image if supported.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
Add(new Option(new[]
|
||||
{
|
||||
"--verify-sectors", "-s"
|
||||
}, "Verify all sectors if supported.")
|
||||
{
|
||||
Argument = new Argument<bool>(() => true), Required = false
|
||||
});
|
||||
|
||||
AddArgument(new Argument<string>
|
||||
{
|
||||
Arity = ArgumentArity.ExactlyOne, Description = "Disc image path", Name = "image-path"
|
||||
});
|
||||
|
||||
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
|
||||
}
|
||||
|
||||
public static int Invoke(bool debug, bool verbose, string imagePath, bool verifyDisc = true,
|
||||
bool verifySectors = true)
|
||||
{
|
||||
MainClass.PrintCopyright();
|
||||
|
||||
if(debug)
|
||||
DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
|
||||
|
||||
if(verbose)
|
||||
DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
|
||||
|
||||
Statistics.AddCommand("verify");
|
||||
|
||||
DicConsole.DebugWriteLine("Verify command", "--debug={0}", debug);
|
||||
DicConsole.DebugWriteLine("Verify command", "--input={0}", imagePath);
|
||||
DicConsole.DebugWriteLine("Verify command", "--verbose={0}", verbose);
|
||||
DicConsole.DebugWriteLine("Verify command", "--verify-disc={0}", verifyDisc);
|
||||
DicConsole.DebugWriteLine("Verify command", "--verify-sectors={0}", verifySectors);
|
||||
|
||||
var filtersList = new FiltersList();
|
||||
IFilter inputFilter = filtersList.GetFilter(imagePath);
|
||||
|
||||
if(inputFilter == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Cannot open specified file.");
|
||||
|
||||
return(int)ErrorNumber.CannotOpenFile;
|
||||
}
|
||||
|
||||
IMediaImage inputFormat = ImageFormat.Detect(inputFilter);
|
||||
|
||||
if(inputFormat == null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Unable to recognize image format, not verifying");
|
||||
|
||||
return(int)ErrorNumber.FormatNotFound;
|
||||
}
|
||||
|
||||
inputFormat.Open(inputFilter);
|
||||
Statistics.AddMediaFormat(inputFormat.Format);
|
||||
Statistics.AddMedia(inputFormat.Info.MediaType, false);
|
||||
Statistics.AddFilter(inputFilter.Name);
|
||||
|
||||
bool? correctImage = null;
|
||||
long errorSectors = 0;
|
||||
bool? correctSectors = null;
|
||||
long unknownSectors = 0;
|
||||
|
||||
var verifiableImage = inputFormat as IVerifiableImage;
|
||||
var verifiableSectorsImage = inputFormat as IVerifiableSectorsImage;
|
||||
|
||||
if(verifiableImage is null &&
|
||||
verifiableSectorsImage is null)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("The specified image does not support any kind of verification");
|
||||
|
||||
return(int)ErrorNumber.NotVerificable;
|
||||
}
|
||||
|
||||
if(verifyDisc && verifiableImage != null)
|
||||
{
|
||||
DateTime startCheck = DateTime.UtcNow;
|
||||
bool? discCheckStatus = verifiableImage.VerifyMediaImage();
|
||||
DateTime endCheck = DateTime.UtcNow;
|
||||
|
||||
TimeSpan checkTime = endCheck - startCheck;
|
||||
|
||||
switch(discCheckStatus)
|
||||
{
|
||||
case true:
|
||||
DicConsole.WriteLine("Disc image checksums are correct");
|
||||
|
||||
break;
|
||||
case false:
|
||||
DicConsole.WriteLine("Disc image checksums are incorrect");
|
||||
|
||||
break;
|
||||
case null:
|
||||
DicConsole.WriteLine("Disc image does not contain checksums");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
correctImage = discCheckStatus;
|
||||
DicConsole.VerboseWriteLine("Checking disc image checksums took {0} seconds", checkTime.TotalSeconds);
|
||||
}
|
||||
|
||||
if(verifySectors)
|
||||
{
|
||||
DateTime startCheck = DateTime.Now;
|
||||
DateTime endCheck = startCheck;
|
||||
List<ulong> failingLbas = new List<ulong>();
|
||||
List<ulong> unknownLbas = new List<ulong>();
|
||||
|
||||
if(verifiableSectorsImage is IOpticalMediaImage opticalMediaImage)
|
||||
{
|
||||
List<Track> inputTracks = opticalMediaImage.Tracks;
|
||||
ulong currentSectorAll = 0;
|
||||
|
||||
startCheck = DateTime.UtcNow;
|
||||
|
||||
foreach(Track currentTrack in inputTracks)
|
||||
{
|
||||
ulong remainingSectors = currentTrack.TrackEndSector - currentTrack.TrackStartSector;
|
||||
ulong currentSector = 0;
|
||||
|
||||
while(remainingSectors > 0)
|
||||
{
|
||||
DicConsole.Write("\rChecking sector {0} of {1}, on track {2}", currentSectorAll,
|
||||
inputFormat.Info.Sectors, currentTrack.TrackSequence);
|
||||
|
||||
List<ulong> tempFailingLbas;
|
||||
List<ulong> tempUnknownLbas;
|
||||
|
||||
if(remainingSectors < 512)
|
||||
opticalMediaImage.VerifySectors(currentSector, (uint)remainingSectors,
|
||||
currentTrack.TrackSequence, out tempFailingLbas,
|
||||
out tempUnknownLbas);
|
||||
else
|
||||
opticalMediaImage.VerifySectors(currentSector, 512, currentTrack.TrackSequence,
|
||||
out tempFailingLbas, out tempUnknownLbas);
|
||||
|
||||
failingLbas.AddRange(tempFailingLbas);
|
||||
|
||||
unknownLbas.AddRange(tempUnknownLbas);
|
||||
|
||||
if(remainingSectors < 512)
|
||||
{
|
||||
currentSector += remainingSectors;
|
||||
currentSectorAll += remainingSectors;
|
||||
remainingSectors = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentSector += 512;
|
||||
currentSectorAll += 512;
|
||||
remainingSectors -= 512;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
endCheck = DateTime.UtcNow;
|
||||
}
|
||||
else if(verifiableSectorsImage != null)
|
||||
{
|
||||
ulong remainingSectors = inputFormat.Info.Sectors;
|
||||
ulong currentSector = 0;
|
||||
|
||||
startCheck = DateTime.UtcNow;
|
||||
|
||||
while(remainingSectors > 0)
|
||||
{
|
||||
DicConsole.Write("\rChecking sector {0} of {1}", currentSector, inputFormat.Info.Sectors);
|
||||
|
||||
List<ulong> tempFailingLbas;
|
||||
List<ulong> tempUnknownLbas;
|
||||
|
||||
if(remainingSectors < 512)
|
||||
verifiableSectorsImage.VerifySectors(currentSector, (uint)remainingSectors,
|
||||
out tempFailingLbas, out tempUnknownLbas);
|
||||
else
|
||||
verifiableSectorsImage.VerifySectors(currentSector, 512, out tempFailingLbas,
|
||||
out tempUnknownLbas);
|
||||
|
||||
failingLbas.AddRange(tempFailingLbas);
|
||||
|
||||
unknownLbas.AddRange(tempUnknownLbas);
|
||||
|
||||
if(remainingSectors < 512)
|
||||
{
|
||||
currentSector += remainingSectors;
|
||||
remainingSectors = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentSector += 512;
|
||||
remainingSectors -= 512;
|
||||
}
|
||||
}
|
||||
|
||||
endCheck = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
TimeSpan checkTime = endCheck - startCheck;
|
||||
|
||||
DicConsole.Write("\r" + new string(' ', System.Console.WindowWidth - 1) + "\r");
|
||||
|
||||
if(unknownSectors > 0)
|
||||
DicConsole.WriteLine("There is at least one sector that does not contain a checksum");
|
||||
|
||||
if(errorSectors > 0)
|
||||
DicConsole.WriteLine("There is at least one sector with incorrect checksum or errors");
|
||||
|
||||
if(unknownSectors == 0 &&
|
||||
errorSectors == 0)
|
||||
DicConsole.WriteLine("All sector checksums are correct");
|
||||
|
||||
DicConsole.VerboseWriteLine("Checking sector checksums took {0} seconds", checkTime.TotalSeconds);
|
||||
|
||||
if(verbose)
|
||||
{
|
||||
DicConsole.VerboseWriteLine("LBAs with error:");
|
||||
|
||||
if(failingLbas.Count == (int)inputFormat.Info.Sectors)
|
||||
DicConsole.VerboseWriteLine("\tall sectors.");
|
||||
else
|
||||
foreach(ulong t in failingLbas)
|
||||
DicConsole.VerboseWriteLine("\t{0}", t);
|
||||
|
||||
DicConsole.WriteLine("LBAs without checksum:");
|
||||
|
||||
if(unknownLbas.Count == (int)inputFormat.Info.Sectors)
|
||||
DicConsole.VerboseWriteLine("\tall sectors.");
|
||||
else
|
||||
foreach(ulong t in unknownLbas)
|
||||
DicConsole.VerboseWriteLine("\t{0}", t);
|
||||
}
|
||||
|
||||
DicConsole.WriteLine("Total sectors........... {0}", inputFormat.Info.Sectors);
|
||||
DicConsole.WriteLine("Total errors............ {0}", failingLbas.Count);
|
||||
DicConsole.WriteLine("Total unknowns.......... {0}", unknownLbas.Count);
|
||||
DicConsole.WriteLine("Total errors+unknowns... {0}", failingLbas.Count + unknownLbas.Count);
|
||||
|
||||
if(failingLbas.Count > 0)
|
||||
correctSectors = false;
|
||||
else if((ulong)unknownLbas.Count < inputFormat.Info.Sectors)
|
||||
correctSectors = true;
|
||||
}
|
||||
|
||||
switch(correctImage)
|
||||
{
|
||||
case null when correctSectors is null: return(int)ErrorNumber.NotVerificable;
|
||||
case null when correctSectors == false: return(int)ErrorNumber.BadSectorsImageNotVerified;
|
||||
case null when correctSectors == true: return(int)ErrorNumber.CorrectSectorsImageNotVerified;
|
||||
case false when correctSectors is null: return(int)ErrorNumber.BadImageSectorsNotVerified;
|
||||
case false when correctSectors == false: return(int)ErrorNumber.BadImageBadSectors;
|
||||
case false when correctSectors == true: return(int)ErrorNumber.CorrectSectorsBadImage;
|
||||
case true when correctSectors is null: return(int)ErrorNumber.CorrectImageSectorsNotVerified;
|
||||
case true when correctSectors == false: return(int)ErrorNumber.CorrectImageBadSectors;
|
||||
case true when correctSectors == true: return(int)ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
return(int)ErrorNumber.NoError;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user