diff --git a/.idea/.idea.DiscImageChef/.idea/contentModel.xml b/.idea/.idea.DiscImageChef/.idea/contentModel.xml
index b77ee138a..3cd0d2e3e 100644
--- a/.idea/.idea.DiscImageChef/.idea/contentModel.xml
+++ b/.idea/.idea.DiscImageChef/.idea/contentModel.xml
@@ -1621,6 +1621,8 @@
+
+
diff --git a/DiscImageChef.Gui/Forms/frmImageChecksum.xeto b/DiscImageChef.Gui/Forms/frmImageChecksum.xeto
new file mode 100644
index 000000000..e4bf331b3
--- /dev/null
+++ b/DiscImageChef.Gui/Forms/frmImageChecksum.xeto
@@ -0,0 +1,99 @@
+
+
\ No newline at end of file
diff --git a/DiscImageChef.Gui/Forms/frmImageChecksum.xeto.cs b/DiscImageChef.Gui/Forms/frmImageChecksum.xeto.cs
new file mode 100644
index 000000000..c4a8647c3
--- /dev/null
+++ b/DiscImageChef.Gui/Forms/frmImageChecksum.xeto.cs
@@ -0,0 +1,425 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : frmImageVerify.xeto.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Image entropy calculation window.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Implements verifying media image.
+//
+// --[ 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-2018 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.Threading;
+using DiscImageChef.CommonTypes.Interfaces;
+using DiscImageChef.CommonTypes.Structs;
+using DiscImageChef.Console;
+using DiscImageChef.Core;
+using Eto.Forms;
+using Eto.Serialization.Xaml;
+using Schemas;
+
+namespace DiscImageChef.Gui.Forms
+{
+ public class frmImageChecksum : Form
+ {
+ // How many sectors to read at once
+ const uint SECTORS_TO_READ = 256;
+ bool cancel;
+ IMediaImage inputFormat;
+
+ public frmImageChecksum(IMediaImage inputFormat)
+ {
+ this.inputFormat = inputFormat;
+ XamlReader.Load(this);
+ cancel = false;
+ try { chkChecksumTracks.Visible = inputFormat.Tracks?.Count > 0; }
+ catch { chkChecksumTracks.Visible = false; }
+
+ chkChecksumTracks.Checked = chkChecksumTracks.Visible;
+ chkChecksumMedia.Visible = chkChecksumTracks.Visible;
+ #if NETSTANDARD2_0
+ chkRipemd160.Visible = false;
+ #endif
+ }
+
+ protected void OnBtnStart(object sender, EventArgs e)
+ {
+ chkAdler32.Enabled = false;
+ chkChecksumMedia.Enabled = false;
+ chkChecksumTracks.Enabled = false;
+ chkCrc16.Enabled = false;
+ chkCrc32.Enabled = false;
+ chkCrc64.Enabled = false;
+ chkFletcher16.Enabled = false;
+ chkFletcher32.Enabled = false;
+ chkMd5.Enabled = false;
+ chkRipemd160.Enabled = false;
+ chkSha1.Enabled = false;
+ chkSha256.Enabled = false;
+ chkSha384.Enabled = false;
+ chkSha512.Enabled = false;
+ chkSpamsum.Enabled = false;
+ btnClose.Visible = false;
+ btnStart.Visible = false;
+ btnStop.Visible = true;
+ stkProgress.Visible = true;
+ lblProgress2.Visible = false;
+
+ new Thread(DoWork).Start();
+ }
+
+ void DoWork()
+ {
+ bool formatHasTracks;
+
+ try { formatHasTracks = inputFormat.Tracks?.Count > 0; }
+ catch { formatHasTracks = false; }
+
+ // Setup progress bars
+ Application.Instance.Invoke(() =>
+ {
+ stkProgress.Visible = true;
+ prgProgress.MaxValue = 1;
+ prgProgress2.MaxValue = (int)(inputFormat.Info.Sectors / SECTORS_TO_READ);
+
+ if(formatHasTracks && chkChecksumTracks.Checked == true)
+ prgProgress.MaxValue += inputFormat.Tracks.Count;
+ else
+ {
+ prgProgress.MaxValue = 2;
+ prgProgress2.Visible = false;
+ lblProgress2.Visible = false;
+ }
+ });
+
+ EnableChecksum enabledChecksums = new EnableChecksum();
+
+ if(chkAdler32.Checked == true) enabledChecksums |= EnableChecksum.Adler32;
+ if(chkCrc16.Checked == true) enabledChecksums |= EnableChecksum.Crc16;
+ if(chkCrc32.Checked == true) enabledChecksums |= EnableChecksum.Crc32;
+ if(chkCrc64.Checked == true) enabledChecksums |= EnableChecksum.Crc64;
+ if(chkMd5.Checked == true) enabledChecksums |= EnableChecksum.Md5;
+ #if !NETSTANDARD2_0
+ if(chkRipemd160.Checked == true) enabledChecksums |= EnableChecksum.Ripemd160;
+ #endif
+ if(chkSha1.Checked == true) enabledChecksums |= EnableChecksum.Sha1;
+ if(chkSha256.Checked == true) enabledChecksums |= EnableChecksum.Sha256;
+ if(chkSha384.Checked == true) enabledChecksums |= EnableChecksum.Sha384;
+ if(chkSha512.Checked == true) enabledChecksums |= EnableChecksum.Sha512;
+ if(chkSpamsum.Checked == true) enabledChecksums |= EnableChecksum.SpamSum;
+ if(chkFletcher16.Checked == true) enabledChecksums |= EnableChecksum.Fletcher16;
+ if(chkFletcher32.Checked == true) enabledChecksums |= EnableChecksum.Fletcher32;
+
+ Checksum mediaChecksum = null;
+
+ TreeGridItemCollection trackHashes = new TreeGridItemCollection();
+ TreeGridItemCollection mediaHashes = new TreeGridItemCollection();
+
+ if(formatHasTracks)
+ try
+ {
+ Checksum trackChecksum = null;
+
+ if(chkChecksumMedia.Checked == true) mediaChecksum = new Checksum(enabledChecksums);
+
+ ulong previousTrackEnd = 0;
+
+ foreach(Track currentTrack in inputFormat.Tracks)
+ {
+ Application.Instance.Invoke(() =>
+ {
+ lblProgress.Text =
+ $"Hashing track {currentTrack.TrackSequence} of {inputFormat.Tracks.Count}";
+ prgProgress.Value++;
+ });
+
+ if(currentTrack.TrackStartSector - previousTrackEnd != 0 && chkChecksumMedia.Checked == true)
+ for(ulong i = previousTrackEnd + 1; i < currentTrack.TrackStartSector; i++)
+ {
+ ulong sector = i;
+ Application.Instance.Invoke(() =>
+ {
+ prgProgress2.Value = (int)(sector / SECTORS_TO_READ);
+ lblProgress2.Text = $"Hashing track-less sector {sector}";
+ });
+
+ 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(chkChecksumTracks.Checked == true) trackChecksum = new Checksum(enabledChecksums);
+
+ ulong sectors = currentTrack.TrackEndSector - currentTrack.TrackStartSector + 1;
+ ulong doneSectors = 0;
+
+ while(doneSectors < sectors)
+ {
+ if(cancel)
+ {
+ Application.Instance.Invoke(() =>
+ {
+ btnClose.Visible = true;
+ btnStart.Visible = false;
+ btnStop.Visible = false;
+ });
+ return;
+ }
+
+ byte[] sector;
+
+ if(sectors - doneSectors >= SECTORS_TO_READ)
+ {
+ sector = inputFormat.ReadSectors(doneSectors, SECTORS_TO_READ,
+ currentTrack.TrackSequence);
+
+ ulong doneSectorsToInvoke = doneSectors;
+ Application.Instance.Invoke(() =>
+ {
+ prgProgress2.Value = (int)(doneSectorsToInvoke / SECTORS_TO_READ);
+ lblProgress2.Text =
+ $"Hashings sectors {doneSectorsToInvoke} to {doneSectorsToInvoke + SECTORS_TO_READ} of track {currentTrack.TrackSequence}";
+ });
+
+ doneSectors += SECTORS_TO_READ;
+ }
+ else
+ {
+ sector = inputFormat.ReadSectors(doneSectors, (uint)(sectors - doneSectors),
+ currentTrack.TrackSequence);
+
+ ulong doneSectorsToInvoke = doneSectors;
+ Application.Instance.Invoke(() =>
+ {
+ prgProgress2.Value = (int)(doneSectorsToInvoke / SECTORS_TO_READ);
+ lblProgress2.Text =
+ $"Hashings sectors {doneSectorsToInvoke} to {doneSectorsToInvoke + (sectors - doneSectorsToInvoke)} of track {currentTrack.TrackSequence}";
+ });
+
+ doneSectors += sectors - doneSectors;
+ }
+
+ if(chkChecksumMedia.Checked == true) mediaChecksum?.Update(sector);
+
+ if(chkChecksumTracks.Checked == true) trackChecksum?.Update(sector);
+ }
+
+ if(chkChecksumTracks.Checked == true)
+ if(trackChecksum != null)
+ foreach(ChecksumType chk in trackChecksum.End())
+ trackHashes.Add(new TreeGridItem
+ {
+ Values = new object[]
+ {
+ currentTrack.TrackSequence, chk.type, chk.Value
+ }
+ });
+
+ previousTrackEnd = currentTrack.TrackEndSector;
+ }
+
+ if(inputFormat.Info.Sectors - previousTrackEnd != 0 && chkChecksumMedia.Checked == true)
+ for(ulong i = previousTrackEnd + 1; i < inputFormat.Info.Sectors; i++)
+ {
+ ulong sector = i;
+ Application.Instance.Invoke(() =>
+ {
+ prgProgress2.Value = (int)(sector / SECTORS_TO_READ);
+ lblProgress2.Text = $"Hashing track-less sector {sector}";
+ });
+
+ byte[] hiddenSector = inputFormat.ReadSector(i);
+ mediaChecksum?.Update(hiddenSector);
+ }
+
+ if(chkChecksumMedia.Checked == true)
+ if(mediaChecksum != null)
+ foreach(ChecksumType chk in mediaChecksum.End())
+ mediaHashes.Add(new TreeGridItem {Values = new object[] {chk.type, chk.Value}});
+ }
+ catch(Exception ex)
+ {
+ DicConsole.DebugWriteLine("Could not get tracks because {0}", ex.Message);
+ DicConsole.WriteLine("Unable to get separate tracks, not checksumming them");
+ }
+ else
+ {
+ Application.Instance.Invoke(() => { stkProgress1.Visible = false; });
+ mediaChecksum = new Checksum(enabledChecksums);
+
+ ulong doneSectors = 0;
+
+ while(doneSectors < inputFormat.Info.Sectors)
+ {
+ if(cancel)
+ {
+ Application.Instance.Invoke(() =>
+ {
+ btnClose.Visible = true;
+ btnStart.Visible = false;
+ btnStop.Visible = false;
+ });
+ return;
+ }
+
+ byte[] sector;
+
+ if(inputFormat.Info.Sectors - doneSectors >= SECTORS_TO_READ)
+ {
+ sector = inputFormat.ReadSectors(doneSectors, SECTORS_TO_READ);
+
+ ulong doneSectorsToInvoke = doneSectors;
+ Application.Instance.Invoke(() =>
+ {
+ prgProgress2.Value = (int)(doneSectorsToInvoke / SECTORS_TO_READ);
+ lblProgress2.Text =
+ $"Hashings sectors {doneSectorsToInvoke} to {doneSectorsToInvoke + SECTORS_TO_READ}";
+ });
+ doneSectors += SECTORS_TO_READ;
+ }
+ else
+ {
+ sector = inputFormat.ReadSectors(doneSectors, (uint)(inputFormat.Info.Sectors - doneSectors));
+ ulong doneSectorsToInvoke = doneSectors;
+ Application.Instance.Invoke(() =>
+ {
+ prgProgress2.Value = (int)(doneSectorsToInvoke / SECTORS_TO_READ);
+ lblProgress2.Text =
+ $"Hashings sectors {doneSectorsToInvoke} to {doneSectorsToInvoke + (inputFormat.Info.Sectors - doneSectorsToInvoke)}";
+ });
+ doneSectors += inputFormat.Info.Sectors - doneSectors;
+ }
+
+ mediaChecksum.Update(sector);
+ }
+
+ foreach(ChecksumType chk in mediaChecksum.End())
+ mediaHashes.Add(new TreeGridItem {Values = new object[] {chk.type, chk.Value}});
+ }
+
+ if(chkChecksumTracks.Checked == true)
+ Application.Instance.Invoke(() =>
+ {
+ grpTrackChecksums.Text = "Track checksums:";
+ stkTrackChecksums.Visible = true;
+
+ treeTrackChecksums.Columns.Add(new GridColumn
+ {
+ HeaderText = "Track", DataCell = new TextBoxCell(0)
+ });
+ treeTrackChecksums.Columns.Add(new GridColumn
+ {
+ HeaderText = "Algorithm", DataCell = new TextBoxCell(1)
+ });
+ treeTrackChecksums.Columns.Add(new GridColumn {HeaderText = "Hash", DataCell = new TextBoxCell(2)});
+
+ treeTrackChecksums.AllowMultipleSelection = false;
+ treeTrackChecksums.ShowHeader = true;
+ treeTrackChecksums.DataStore = trackHashes;
+ });
+
+ if(chkChecksumMedia.Checked == true)
+ Application.Instance.Invoke(() =>
+ {
+ grpMediaChecksums.Text = "Media checksums:";
+ stkMediaChecksums.Visible = true;
+
+ treeMediaChecksums.Columns.Add(new GridColumn
+ {
+ HeaderText = "Algorithm", DataCell = new TextBoxCell(0)
+ });
+ treeMediaChecksums.Columns.Add(new GridColumn {HeaderText = "Hash", DataCell = new TextBoxCell(1)});
+
+ treeMediaChecksums.AllowMultipleSelection = false;
+ treeMediaChecksums.ShowHeader = true;
+ treeMediaChecksums.DataStore = mediaHashes;
+ });
+
+ Statistics.AddCommand("checksum");
+
+ Application.Instance.Invoke(() =>
+ {
+ stkOptions.Visible = false;
+ stkResults.Visible = true;
+ stkProgress.Visible = false;
+ btnStart.Visible = false;
+ btnStop.Visible = false;
+ btnClose.Visible = true;
+ });
+ }
+
+ protected void OnBtnClose(object sender, EventArgs e)
+ {
+ Close();
+ }
+
+ protected void OnBtnStop(object sender, EventArgs e)
+ {
+ cancel = true;
+ btnStop.Enabled = false;
+ }
+
+ #region XAML IDs
+ StackLayout stkOptions;
+ CheckBox chkChecksumMedia;
+ CheckBox chkChecksumTracks;
+ CheckBox chkAdler32;
+ CheckBox chkCrc16;
+ CheckBox chkCrc32;
+ CheckBox chkCrc64;
+ CheckBox chkFletcher16;
+ CheckBox chkFletcher32;
+ CheckBox chkMd5;
+ CheckBox chkRipemd160;
+ CheckBox chkSha1;
+ CheckBox chkSha256;
+ CheckBox chkSha384;
+ CheckBox chkSha512;
+ CheckBox chkSpamsum;
+ StackLayout stkResults;
+ StackLayout stkTrackChecksums;
+ GroupBox grpTrackChecksums;
+ TreeGridView treeTrackChecksums;
+ StackLayout stkMediaChecksums;
+ GroupBox grpMediaChecksums;
+ TreeGridView treeMediaChecksums;
+ StackLayout stkProgress;
+ StackLayout stkProgress1;
+ Label lblProgress;
+ ProgressBar prgProgress;
+ StackLayout stkProgress2;
+ Label lblProgress2;
+ ProgressBar prgProgress2;
+ Button btnStart;
+ Button btnClose;
+ Button btnStop;
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/DiscImageChef.Gui/Panels/pnlImageInfo.xeto b/DiscImageChef.Gui/Panels/pnlImageInfo.xeto
index 648469254..e2bc2ff6d 100644
--- a/DiscImageChef.Gui/Panels/pnlImageInfo.xeto
+++ b/DiscImageChef.Gui/Panels/pnlImageInfo.xeto
@@ -115,6 +115,7 @@
+
diff --git a/DiscImageChef.Gui/Panels/pnlImageInfo.xeto.cs b/DiscImageChef.Gui/Panels/pnlImageInfo.xeto.cs
index f024b7f71..e94cab051 100644
--- a/DiscImageChef.Gui/Panels/pnlImageInfo.xeto.cs
+++ b/DiscImageChef.Gui/Panels/pnlImageInfo.xeto.cs
@@ -55,9 +55,10 @@ namespace DiscImageChef.Gui.Panels
{
public class pnlImageInfo : Panel
{
- frmImageEntropy frmImageEntropy;
- frmImageVerify frmImageVerify;
- IMediaImage imageFormat;
+ frmImageChecksum frmImageChecksum;
+ frmImageEntropy frmImageEntropy;
+ frmImageVerify frmImageVerify;
+ IMediaImage imageFormat;
public pnlImageInfo(string imagePath, IFilter filter, IMediaImage imageFormat)
{
@@ -812,6 +813,19 @@ namespace DiscImageChef.Gui.Panels
frmImageVerify.Show();
}
+ protected void OnBtnChecksum(object sender, EventArgs e)
+ {
+ if(frmImageChecksum != null)
+ {
+ frmImageChecksum.Show();
+ return;
+ }
+
+ frmImageChecksum = new frmImageChecksum(imageFormat);
+ frmImageChecksum.Closed += (s, ea) => { frmImageChecksum = null; };
+ frmImageChecksum.Show();
+ }
+
#region XAML controls
#pragma warning disable 169
#pragma warning disable 649
@@ -858,6 +872,8 @@ namespace DiscImageChef.Gui.Panels
ImageView imgMediaLogo;
SvgImageView svgMediaLogo;
Button btnEntropy;
+ Button btnVerify;
+ Button btnChecksum;
#pragma warning restore 169
#pragma warning restore 649
#endregion