Enable comparing byte addressable images.

This commit is contained in:
2021-11-13 19:15:53 +00:00
parent 5d1bc1a907
commit b015101bda

View File

@@ -45,353 +45,373 @@ using Aaru.Helpers;
using Spectre.Console;
using ImageInfo = Aaru.CommonTypes.Structs.ImageInfo;
namespace Aaru.Commands.Image
namespace Aaru.Commands.Image;
internal sealed class CompareCommand : Command
{
internal sealed class CompareCommand : Command
public CompareCommand() : base("compare", "Compares two disc images.")
{
public CompareCommand() : base("compare", "Compares two disc images.")
AddAlias("cmp");
AddArgument(new Argument<string>
{
AddAlias("cmp");
Arity = ArgumentArity.ExactlyOne,
Description = "First media image path",
Name = "image-path1"
});
AddArgument(new Argument<string>
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)
{
IAnsiConsole stderrConsole = AnsiConsole.Create(new AnsiConsoleSettings
{
Arity = ArgumentArity.ExactlyOne,
Description = "First media image path",
Name = "image-path1"
Out = new AnsiConsoleOutput(System.Console.Error)
});
AddArgument(new Argument<string>
AaruConsole.DebugWriteLineEvent += (format, objects) =>
{
Arity = ArgumentArity.ExactlyOne,
Description = "Second media image path",
Name = "image-path2"
});
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
if(objects is null)
stderrConsole.MarkupLine(format);
else
stderrConsole.MarkupLine(format, objects);
};
}
public static int Invoke(bool debug, bool verbose, string imagePath1, string imagePath2)
if(verbose)
AaruConsole.WriteEvent += (format, objects) =>
{
if(objects is null)
AnsiConsole.Markup(format);
else
AnsiConsole.Markup(format, objects);
};
Statistics.AddCommand("compare");
AaruConsole.DebugWriteLine("Compare command", "--debug={0}", debug);
AaruConsole.DebugWriteLine("Compare command", "--input1={0}", imagePath1);
AaruConsole.DebugWriteLine("Compare command", "--input2={0}", imagePath2);
AaruConsole.DebugWriteLine("Compare command", "--verbose={0}", verbose);
var filtersList = new FiltersList();
IFilter inputFilter1 = null;
IFilter inputFilter2 = null;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
MainClass.PrintCopyright();
ctx.AddTask("Identifying file 1 filter...").IsIndeterminate();
inputFilter1 = filtersList.GetFilter(imagePath1);
});
if(debug)
{
IAnsiConsole stderrConsole = AnsiConsole.Create(new AnsiConsoleSettings
{
Out = new AnsiConsoleOutput(System.Console.Error)
});
filtersList = new FiltersList();
AaruConsole.DebugWriteLineEvent += (format, objects) =>
{
if(objects is null)
stderrConsole.MarkupLine(format);
else
stderrConsole.MarkupLine(format, objects);
};
}
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying file 2 filter...").IsIndeterminate();
inputFilter2 = filtersList.GetFilter(imagePath2);
});
if(verbose)
AaruConsole.WriteEvent += (format, objects) =>
{
if(objects is null)
AnsiConsole.Markup(format);
else
AnsiConsole.Markup(format, objects);
};
if(inputFilter1 == null)
{
AaruConsole.ErrorWriteLine("Cannot open input file 1");
Statistics.AddCommand("compare");
return (int)ErrorNumber.CannotOpenFile;
}
AaruConsole.DebugWriteLine("Compare command", "--debug={0}", debug);
AaruConsole.DebugWriteLine("Compare command", "--input1={0}", imagePath1);
AaruConsole.DebugWriteLine("Compare command", "--input2={0}", imagePath2);
AaruConsole.DebugWriteLine("Compare command", "--verbose={0}", verbose);
if(inputFilter2 == null)
{
AaruConsole.ErrorWriteLine("Cannot open input file 2");
var filtersList = new FiltersList();
IFilter inputFilter1 = null;
IFilter inputFilter2 = null;
return (int)ErrorNumber.CannotOpenFile;
}
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying file 1 filter...").IsIndeterminate();
inputFilter1 = filtersList.GetFilter(imagePath1);
});
IBaseImage input1Format = null;
IBaseImage input2Format = null;
filtersList = new FiltersList();
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying image 1 format...").IsIndeterminate();
input1Format = ImageFormat.Detect(inputFilter1);
});
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying file 2 filter...").IsIndeterminate();
inputFilter2 = filtersList.GetFilter(imagePath2);
});
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying image 1 format...").IsIndeterminate();
input2Format = ImageFormat.Detect(inputFilter2);
});
if(inputFilter1 == null)
{
AaruConsole.ErrorWriteLine("Cannot open input file 1");
if(input1Format == null)
{
AaruConsole.ErrorWriteLine("Input file 1 format not identified, not proceeding with comparison.");
return (int)ErrorNumber.CannotOpenFile;
}
return (int)ErrorNumber.UnrecognizedFormat;
}
if(inputFilter2 == null)
{
AaruConsole.ErrorWriteLine("Cannot open input file 2");
if(verbose)
AaruConsole.VerboseWriteLine("Input file 1 format identified by {0} ({1}).", input1Format.Name,
input1Format.Id);
else
AaruConsole.WriteLine("Input file 1 format identified by {0}.", input1Format.Name);
return (int)ErrorNumber.CannotOpenFile;
}
if(input2Format == null)
{
AaruConsole.ErrorWriteLine("Input file 2 format not identified, not proceeding with comparison.");
IMediaImage input1Format = null;
IMediaImage input2Format = null;
return (int)ErrorNumber.UnrecognizedFormat;
}
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying image 1 format...").IsIndeterminate();
input1Format = ImageFormat.Detect(inputFilter1);
});
if(verbose)
AaruConsole.VerboseWriteLine("Input file 2 format identified by {0} ({1}).", input2Format.Name,
input2Format.Id);
else
AaruConsole.WriteLine("Input file 2 format identified by {0}.", input2Format.Name);
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Identifying image 1 format...").IsIndeterminate();
input2Format = ImageFormat.Detect(inputFilter2);
});
ErrorNumber opened1 = ErrorNumber.NoData;
ErrorNumber opened2 = ErrorNumber.NoData;
if(input1Format == null)
{
AaruConsole.ErrorWriteLine("Input file 1 format not identified, not proceeding with comparison.");
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Opening image 1 file...").IsIndeterminate();
opened1 = input1Format.Open(inputFilter1);
});
return (int)ErrorNumber.UnrecognizedFormat;
}
if(opened1 != ErrorNumber.NoError)
{
AaruConsole.WriteLine("Unable to open image 1 format");
AaruConsole.WriteLine("Error {0}", opened1);
if(verbose)
AaruConsole.VerboseWriteLine("Input file 1 format identified by {0} ({1}).", input1Format.Name,
input1Format.Id);
else
AaruConsole.WriteLine("Input file 1 format identified by {0}.", input1Format.Name);
return (int)opened1;
}
if(input2Format == null)
{
AaruConsole.ErrorWriteLine("Input file 2 format not identified, not proceeding with comparison.");
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Opening image 2 file...").IsIndeterminate();
opened2 = input2Format.Open(inputFilter2);
});
return (int)ErrorNumber.UnrecognizedFormat;
}
if(opened2 != ErrorNumber.NoError)
{
AaruConsole.WriteLine("Unable to open image 2 format");
AaruConsole.WriteLine("Error {0}", opened2);
if(verbose)
AaruConsole.VerboseWriteLine("Input file 2 format identified by {0} ({1}).", input2Format.Name,
input2Format.Id);
else
AaruConsole.WriteLine("Input file 2 format identified by {0}.", input2Format.Name);
return (int)opened2;
}
ErrorNumber opened1 = ErrorNumber.NoData;
ErrorNumber opened2 = ErrorNumber.NoData;
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);
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Opening image 1 file...").IsIndeterminate();
opened1 = input1Format.Open(inputFilter1);
});
var sb = new StringBuilder();
Table table = new();
table.AddColumn("");
table.AddColumn("Media image 1");
table.AddColumn("Media image 2");
table.Columns[0].RightAligned();
if(opened1 != ErrorNumber.NoError)
{
AaruConsole.WriteLine("Unable to open image 1 format");
AaruConsole.WriteLine("Error {0}", opened1);
if(verbose)
{
table.AddRow("File", Markup.Escape(imagePath1), Markup.Escape(imagePath2));
table.AddRow("Media image format", input1Format.Name, input2Format.Name);
}
else
{
sb.AppendFormat("[bold]Media image 1:[/] {0}", imagePath1).AppendLine();
sb.AppendFormat("[bold]Media image 2:[/] {0}", imagePath2).AppendLine();
}
return (int)opened1;
}
bool imagesDiffer = false;
ErrorNumber errno;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Opening image 2 file...").IsIndeterminate();
opened2 = input2Format.Open(inputFilter2);
});
if(opened2 != ErrorNumber.NoError)
{
AaruConsole.WriteLine("Unable to open image 2 format");
AaruConsole.WriteLine("Error {0}", opened2);
return (int)opened2;
}
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();
Table table = new();
table.AddColumn("");
table.AddColumn("Disc image 1");
table.AddColumn("Disc image 2");
table.Columns[0].RightAligned();
if(verbose)
{
table.AddRow("File", Markup.Escape(imagePath1), Markup.Escape(imagePath2));
table.AddRow("Disc image format", input1Format.Name, input2Format.Name);
}
else
{
sb.AppendFormat("[bold]Disc image 1:[/] {0}", imagePath1).AppendLine();
sb.AppendFormat("[bold]Disc image 2:[/] {0}", imagePath2).AppendLine();
}
bool imagesDiffer = false;
ErrorNumber errno;
ImageInfo image1Info = input1Format.Info;
ImageInfo image2Info = input2Format.Info;
Dictionary<MediaTagType, byte[]> image1DiskTags = new();
Dictionary<MediaTagType, byte[]> image2DiskTags = new();
ImageInfo image1Info = input1Format.Info;
ImageInfo image2Info = input2Format.Info;
Dictionary<MediaTagType, byte[]> image1DiskTags = new();
Dictionary<MediaTagType, byte[]> image2DiskTags = new();
var input1MediaImage = input1Format as IMediaImage;
var input2MediaImage = input2Format as IMediaImage;
if(input1MediaImage != null)
foreach(MediaTagType diskTag in Enum.GetValues(typeof(MediaTagType)))
{
errno = input1Format.ReadMediaTag(diskTag, out byte[] tempArray);
errno = input1MediaImage.ReadMediaTag(diskTag, out byte[] tempArray);
if(errno == ErrorNumber.NoError)
image1DiskTags.Add(diskTag, tempArray);
}
if(input2MediaImage != null)
foreach(MediaTagType diskTag in Enum.GetValues(typeof(MediaTagType)))
{
errno = input2Format.ReadMediaTag(diskTag, out byte[] tempArray);
errno = input2MediaImage.ReadMediaTag(diskTag, out byte[] tempArray);
if(errno == ErrorNumber.NoError)
image2DiskTags.Add(diskTag, tempArray);
}
if(verbose)
{
table.AddRow("Has partitions?", image1Info.HasPartitions.ToString(),
image2Info.HasPartitions.ToString());
if(verbose)
{
table.AddRow("Has partitions?", image1Info.HasPartitions.ToString(), image2Info.HasPartitions.ToString());
table.AddRow("Has sessions?", image1Info.HasSessions.ToString(), image2Info.HasSessions.ToString());
table.AddRow("Has sessions?", image1Info.HasSessions.ToString(), image2Info.HasSessions.ToString());
table.AddRow("Image size", image1Info.ImageSize.ToString(), image2Info.ImageSize.ToString());
table.AddRow("Image size", image1Info.ImageSize.ToString(), image2Info.ImageSize.ToString());
table.AddRow("Sectors", image1Info.Sectors.ToString(), image2Info.Sectors.ToString());
table.AddRow("Sectors", image1Info.Sectors.ToString(), image2Info.Sectors.ToString());
table.AddRow("Sector size", image1Info.SectorSize.ToString(), image2Info.SectorSize.ToString());
table.AddRow("Sector size", image1Info.SectorSize.ToString(), image2Info.SectorSize.ToString());
table.AddRow("Creation time", image1Info.CreationTime.ToString(), image2Info.CreationTime.ToString());
table.AddRow("Creation time", image1Info.CreationTime.ToString(), image2Info.CreationTime.ToString());
table.AddRow("Last modification time", image1Info.LastModificationTime.ToString(),
image2Info.LastModificationTime.ToString());
table.AddRow("Last modification time", image1Info.LastModificationTime.ToString(),
image2Info.LastModificationTime.ToString());
table.AddRow("Disk type", image1Info.MediaType.ToString(), image2Info.MediaType.ToString());
table.AddRow("Disk type", image1Info.MediaType.ToString(), image2Info.MediaType.ToString());
table.AddRow("Image version", image1Info.Version ?? "", image2Info.Version ?? "");
table.AddRow("Image version", image1Info.Version ?? "", image2Info.Version ?? "");
table.AddRow("Image application", image1Info.Application ?? "", image2Info.Application ?? "");
table.AddRow("Image application", image1Info.Application ?? "", image2Info.Application ?? "");
table.AddRow("Image application version", image1Info.ApplicationVersion ?? "",
image2Info.ApplicationVersion ?? "");
table.AddRow("Image application version", image1Info.ApplicationVersion ?? "",
image2Info.ApplicationVersion ?? "");
table.AddRow("Image creator", image1Info.Creator ?? "", image2Info.Creator ?? "");
table.AddRow("Image creator", image1Info.Creator ?? "", image2Info.Creator ?? "");
table.AddRow("Image name", image1Info.MediaTitle ?? "", image2Info.MediaTitle ?? "");
table.AddRow("Image name", image1Info.MediaTitle ?? "", image2Info.MediaTitle ?? "");
table.AddRow("Image comments", image1Info.Comments ?? "", image2Info.Comments ?? "");
table.AddRow("Image comments", image1Info.Comments ?? "", image2Info.Comments ?? "");
table.AddRow("Disk manufacturer", image1Info.MediaManufacturer ?? "",
image2Info.MediaManufacturer ?? "");
table.AddRow("Disk manufacturer", image1Info.MediaManufacturer ?? "", image2Info.MediaManufacturer ?? "");
table.AddRow("Disk model", image1Info.MediaModel ?? "", image2Info.MediaModel ?? "");
table.AddRow("Disk model", image1Info.MediaModel ?? "", image2Info.MediaModel ?? "");
table.AddRow("Disk serial number", image1Info.MediaSerialNumber ?? "",
image2Info.MediaSerialNumber ?? "");
table.AddRow("Disk serial number", image1Info.MediaSerialNumber ?? "", image2Info.MediaSerialNumber ?? "");
table.AddRow("Disk barcode", image1Info.MediaBarcode ?? "", image2Info.MediaBarcode ?? "");
table.AddRow("Disk barcode", image1Info.MediaBarcode ?? "", image2Info.MediaBarcode ?? "");
table.AddRow("Disk part no.", image1Info.MediaPartNumber ?? "", image2Info.MediaPartNumber ?? "");
table.AddRow("Disk part no.", image1Info.MediaPartNumber ?? "", image2Info.MediaPartNumber ?? "");
table.AddRow("Disk sequence", image1Info.MediaSequence.ToString(), image2Info.MediaSequence.ToString());
table.AddRow("Disk sequence", image1Info.MediaSequence.ToString(), image2Info.MediaSequence.ToString());
table.AddRow("Last disk on sequence", image1Info.LastMediaSequence.ToString(),
image2Info.LastMediaSequence.ToString());
table.AddRow("Last disk on sequence", image1Info.LastMediaSequence.ToString(),
image2Info.LastMediaSequence.ToString());
table.AddRow("Drive manufacturer", image1Info.DriveManufacturer ?? "",
image2Info.DriveManufacturer ?? "");
table.AddRow("Drive manufacturer", image1Info.DriveManufacturer ?? "", image2Info.DriveManufacturer ?? "");
table.AddRow("Drive firmware revision", image1Info.DriveFirmwareRevision ?? "",
image2Info.DriveFirmwareRevision ?? "");
table.AddRow("Drive firmware revision", image1Info.DriveFirmwareRevision ?? "",
image2Info.DriveFirmwareRevision ?? "");
table.AddRow("Drive model", image1Info.DriveModel ?? "", image2Info.DriveModel ?? "");
table.AddRow("Drive model", image1Info.DriveModel ?? "", image2Info.DriveModel ?? "");
table.AddRow("Drive serial number", image1Info.DriveSerialNumber ?? "",
image2Info.DriveSerialNumber ?? "");
table.AddRow("Drive serial number", image1Info.DriveSerialNumber ?? "", image2Info.DriveSerialNumber ?? "");
foreach(MediaTagType diskTag in
foreach(MediaTagType diskTag in
(Enum.GetValues(typeof(MediaTagType)) as MediaTagType[]).OrderBy(e => e.ToString()))
table.AddRow($"Has {diskTag}?", image1DiskTags.ContainsKey(diskTag).ToString(),
image2DiskTags.ContainsKey(diskTag).ToString());
table.AddRow($"Has {diskTag}?", image1DiskTags.ContainsKey(diskTag).ToString(),
image2DiskTags.ContainsKey(diskTag).ToString());
}
ulong leastSectors = 0;
Core.Spectre.ProgressSingleSpinner(ctx =>
{
ctx.AddTask("Comparing disk image characteristics").IsIndeterminate();
if(image1Info.HasPartitions != image2Info.HasPartitions)
{
imagesDiffer = true;
if(!verbose)
sb.AppendLine("Image partitioned status differ");
}
ulong leastSectors = 0;
Core.Spectre.ProgressSingleSpinner(ctx =>
if(image1Info.HasSessions != image2Info.HasSessions)
{
ctx.AddTask("Comparing disk image characteristics").IsIndeterminate();
imagesDiffer = true;
if(image1Info.HasPartitions != image2Info.HasPartitions)
{
imagesDiffer = true;
if(!verbose)
sb.AppendLine("Image session status differ");
}
if(!verbose)
sb.AppendLine("Image partitioned status differ");
}
if(image1Info.Sectors != image2Info.Sectors)
{
imagesDiffer = true;
if(image1Info.HasSessions != image2Info.HasSessions)
{
imagesDiffer = true;
if(!verbose)
sb.AppendLine("Image sectors differ");
}
if(!verbose)
sb.AppendLine("Image session status differ");
}
if(image1Info.SectorSize != image2Info.SectorSize)
{
imagesDiffer = true;
if(image1Info.Sectors != image2Info.Sectors)
{
imagesDiffer = true;
if(!verbose)
sb.AppendLine("Image sector size differ");
}
if(!verbose)
sb.AppendLine("Image sectors differ");
}
if(image1Info.MediaType != image2Info.MediaType)
{
imagesDiffer = true;
if(image1Info.SectorSize != image2Info.SectorSize)
{
imagesDiffer = true;
if(!verbose)
sb.AppendLine("Disk type differ");
}
if(!verbose)
sb.AppendLine("Image sector size differ");
}
if(image1Info.Sectors < image2Info.Sectors)
{
imagesDiffer = true;
leastSectors = image1Info.Sectors;
if(image1Info.MediaType != image2Info.MediaType)
{
imagesDiffer = true;
if(!verbose)
sb.AppendLine("Image 2 has more sectors");
}
else if(image1Info.Sectors > image2Info.Sectors)
{
imagesDiffer = true;
leastSectors = image2Info.Sectors;
if(!verbose)
sb.AppendLine("Disk type differ");
}
if(!verbose)
sb.AppendLine("Image 1 has more sectors");
}
else
leastSectors = image1Info.Sectors;
});
if(image1Info.Sectors < image2Info.Sectors)
{
imagesDiffer = true;
leastSectors = image1Info.Sectors;
var input1ByteAddressable = input1Format as IByteAddressableImage;
var input2ByteAddressable = input2Format as IByteAddressableImage;
if(!verbose)
sb.AppendLine("Image 2 has more sectors");
}
else if(image1Info.Sectors > image2Info.Sectors)
{
imagesDiffer = true;
leastSectors = image2Info.Sectors;
if(input1ByteAddressable is null &&
input2ByteAddressable is not null)
imagesDiffer = true;
if(!verbose)
sb.AppendLine("Image 1 has more sectors");
}
else
leastSectors = image1Info.Sectors;
});
if(input1ByteAddressable is not null &&
input2ByteAddressable is null)
imagesDiffer = true;
if(input1MediaImage is null &&
input2MediaImage is not null)
imagesDiffer = true;
if(input1MediaImage is not null &&
input2MediaImage is null)
imagesDiffer = true;
if(input1MediaImage is not null &&
input2MediaImage is not null)
AnsiConsole.Progress().AutoClear(true).HideCompleted(true).
Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()).
Start(ctx =>
@@ -406,13 +426,13 @@ namespace Aaru.Commands.Image
try
{
errno = input1Format.ReadSector(sector, out byte[] image1Sector);
errno = input1MediaImage.ReadSector(sector, out byte[] image1Sector);
if(errno != ErrorNumber.NoError)
AaruConsole.
ErrorWriteLine($"Error {errno} reading sector {sector} from image 1.");
errno = input2Format.ReadSector(sector, out byte[] image2Sector);
errno = input1MediaImage.ReadSector(sector, out byte[] image2Sector);
if(errno != ErrorNumber.NoError)
AaruConsole.
@@ -445,16 +465,54 @@ namespace Aaru.Commands.Image
}
});
AaruConsole.WriteLine();
if(input1ByteAddressable is not null &&
input2ByteAddressable is not null)
AnsiConsole.Progress().AutoClear(true).HideCompleted(true).
Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()).
Start(ctx =>
{
ProgressTask task = ctx.AddTask("Comparing images...");
task.IsIndeterminate = true;
sb.AppendLine(imagesDiffer ? "Images differ" : "Images do not differ");
byte[] data1 = new byte[input1ByteAddressable.Info.Sectors];
byte[] data2 = new byte[input2ByteAddressable.Info.Sectors];
byte[] tmp;
if(verbose)
AnsiConsole.Render(table);
else
AaruConsole.WriteLine(sb.ToString());
input1ByteAddressable.ReadBytes(data1, 0, data1.Length, out int bytesRead);
return (int)ErrorNumber.NoError;
}
if(bytesRead != data1.Length)
{
tmp = new byte[bytesRead];
Array.Copy(data1, 0, tmp, 0, bytesRead);
data1 = tmp;
}
input2ByteAddressable.ReadBytes(data2, 0, data2.Length, out bytesRead);
if(bytesRead != data2.Length)
{
tmp = new byte[bytesRead];
Array.Copy(data2, 0, tmp, 0, bytesRead);
data2 = tmp;
}
ArrayHelpers.CompareBytes(out bool different, out bool sameSize, data1, data2);
if(different)
imagesDiffer = true;
else if(!sameSize)
imagesDiffer = true;
});
AaruConsole.WriteLine();
sb.AppendLine(imagesDiffer ? "Images differ" : "Images do not differ");
if(verbose)
AnsiConsole.Render(table);
else
AaruConsole.WriteLine(sb.ToString());
return (int)ErrorNumber.NoError;
}
}