From d8151a3af90f84e35d177aee7bc7fa95cab1dfbd Mon Sep 17 00:00:00 2001 From: Surenthar Pitchai Date: Wed, 5 Jan 2022 13:30:15 +0530 Subject: [PATCH] changed the traget framework to 4.8 and included all exception handling for the FileInfo in the MainForm of OnCompute method --- src/.vs/ChecksumValidator/project-colors.json | 11 + src/Backup/ChecksumValidator.sln | 20 + .../CRC32.cs | 145 ++++++ .../Checksum.cs | 184 +++++++ .../ChecksumMethod.cs | 17 + .../ColorPulser.cs | 146 ++++++ ...Gardian.Utilities.ChecksumValidator.csproj | 73 +++ .../MainForm.Designer.cs | 351 +++++++++++++ .../MainForm.cs | 354 +++++++++++++ .../MainForm.resx | 135 +++++ .../Program.cs | 32 ++ .../Properties/AssemblyInfo.cs | 28 + .../Properties/Resources.Designer.cs | 107 ++++ .../Properties/Resources.resx | 139 +++++ .../Resources/App.ico | Bin 0 -> 14846 bytes .../Resources/OpenHS.png | Bin 0 -> 743 bytes .../Resources/PasteHS.png | Bin 0 -> 730 bytes .../Resources/RunHS.png | Bin 0 -> 373 bytes .../Resources/StopHS.png | Bin 0 -> 429 bytes .../TraceUtilities.cs | 489 ++++++++++++++++++ src/ChecksumValidator.sln | 9 +- ...Gardian.Utilities.ChecksumValidator.csproj | 13 +- .../MainForm.cs | 29 +- .../Properties/Resources.Designer.cs | 19 +- .../app.config | 3 + src/UpgradeLog.htm | Bin 0 -> 53900 bytes 26 files changed, 2296 insertions(+), 8 deletions(-) create mode 100644 src/.vs/ChecksumValidator/project-colors.json create mode 100644 src/Backup/ChecksumValidator.sln create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/CRC32.cs create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/Checksum.cs create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/ChecksumMethod.cs create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/ColorPulser.cs create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/Gardian.Utilities.ChecksumValidator.csproj create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.Designer.cs create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.cs create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.resx create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/Program.cs create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/Properties/AssemblyInfo.cs create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/Properties/Resources.Designer.cs create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/Properties/Resources.resx create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/Resources/App.ico create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/Resources/OpenHS.png create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/Resources/PasteHS.png create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/Resources/RunHS.png create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/Resources/StopHS.png create mode 100644 src/Backup/Gardian.Utilities.ChecksumValidator/TraceUtilities.cs create mode 100644 src/Gardian.Utilities.ChecksumValidator/app.config create mode 100644 src/UpgradeLog.htm diff --git a/src/.vs/ChecksumValidator/project-colors.json b/src/.vs/ChecksumValidator/project-colors.json new file mode 100644 index 0000000..509e419 --- /dev/null +++ b/src/.vs/ChecksumValidator/project-colors.json @@ -0,0 +1,11 @@ +{ + "Version": 1, + "ProjectMap": { + "67aa0267-46db-4857-bfc1-87c9ab535542": { + "ProjectGuid": "67aa0267-46db-4857-bfc1-87c9ab535542", + "DisplayName": "Gardian.Utilities.ChecksumValidator", + "ColorIndex": 0 + } + }, + "NextColorIndex": 1 +} \ No newline at end of file diff --git a/src/Backup/ChecksumValidator.sln b/src/Backup/ChecksumValidator.sln new file mode 100644 index 0000000..f613ea8 --- /dev/null +++ b/src/Backup/ChecksumValidator.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gardian.Utilities.ChecksumValidator", "Gardian.Utilities.ChecksumValidator\Gardian.Utilities.ChecksumValidator.csproj", "{67AA0267-46DB-4857-BFC1-87C9AB535542}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {67AA0267-46DB-4857-BFC1-87C9AB535542}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {67AA0267-46DB-4857-BFC1-87C9AB535542}.Debug|Any CPU.Build.0 = Debug|Any CPU + {67AA0267-46DB-4857-BFC1-87C9AB535542}.Release|Any CPU.ActiveCfg = Release|Any CPU + {67AA0267-46DB-4857-BFC1-87C9AB535542}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/CRC32.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/CRC32.cs new file mode 100644 index 0000000..004a7d6 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/CRC32.cs @@ -0,0 +1,145 @@ +// Author: Damien Guard, (c) 2006 +// (http://damieng.com/blog/2006/08/08/Calculating_CRC32_in_C_and_NET) + +using System; +using System.Security.Cryptography; + +/// +/// +public sealed class CRC32 : HashAlgorithm +{ + + /// + /// Default polynomial used for CRC32 computation. + /// + [CLSCompliant(false)] + public const UInt32 DefaultPolynomial = 0xedb88320; + + /// + /// Default CRC32 computation seed. + /// + [CLSCompliant(false)] + public const UInt32 DefaultSeed = 0xffffffff; + + private UInt32 _hash; + private readonly UInt32 _seed; + private readonly UInt32[] _table; + private static UInt32[] DefaultTable; + + /// + /// + public CRC32() + { + this._table = InitializeTable(DefaultPolynomial); + this._seed = DefaultSeed; + Initialize(); + } + + /// + /// + [CLSCompliant(false)] + public CRC32(UInt32 polynomial, UInt32 seed) + { + this._table = InitializeTable(polynomial); + this._seed = seed; + Initialize(); + } + + /// + /// + public override void Initialize() + { + this._hash = this._seed; + } + + /// + /// + protected override void HashCore(byte[] buffer, int start, int length) + { + this._hash = CalculateHash(this._table, this._hash, buffer, start, length); + } + + /// + /// + protected override byte[] HashFinal() + { + byte[] hashBuffer = UInt32ToBigEndianBytes(~this._hash); + this.HashValue = hashBuffer; + return hashBuffer; + } + + /// + /// + public override int HashSize + { + get { return 32; } + } + + /// + /// + [CLSCompliant(false)] + public static UInt32 Compute(byte[] buffer) + { + return ~CalculateHash(InitializeTable(DefaultPolynomial), DefaultSeed, buffer, 0, buffer.Length); + } + + /// + /// + [CLSCompliant(false)] + public static UInt32 Compute(UInt32 seed, byte[] buffer) + { + return ~CalculateHash(InitializeTable(DefaultPolynomial), seed, buffer, 0, buffer.Length); + } + + /// + /// + [CLSCompliant(false)] + public static UInt32 Compute(UInt32 polynomial, UInt32 seed, byte[] buffer) + { + return ~CalculateHash(InitializeTable(polynomial), seed, buffer, 0, buffer.Length); + } + + private static UInt32[] InitializeTable(UInt32 polynomial) + { + if (polynomial == DefaultPolynomial && DefaultTable != null) + return DefaultTable; + + var createTable = new UInt32[256]; + for (int i = 0; i < 256; i++) + { + var entry = (UInt32)i; + for (int j = 0; j < 8; j++) + if ((entry & 1) == 1) + entry = (entry >> 1) ^ polynomial; + else + entry = entry >> 1; + createTable[i] = entry; + } + + if (polynomial == DefaultPolynomial) + DefaultTable = createTable; + + return createTable; + } + + private static UInt32 CalculateHash(UInt32[] table, UInt32 seed, byte[] buffer, int start, int size) + { + UInt32 crc = seed; + for (int i = start; i < size; i++) + unchecked + { + crc = (crc >> 8) ^ table[buffer[i] ^ crc & 0xff]; + } + return crc; + } + + private static byte[] UInt32ToBigEndianBytes(UInt32 x) + { + return new[] { + (byte)((x >> 24) & 0xff), + (byte)((x >> 16) & 0xff), + (byte)((x >> 8) & 0xff), + (byte)(x & 0xff) + }; + } +} \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Checksum.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/Checksum.cs new file mode 100644 index 0000000..991ea77 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/Checksum.cs @@ -0,0 +1,184 @@ +using System; +using System.Globalization; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using System.Threading; + +namespace Gardian.Utilities.ChecksumValidator +{ + + /// + /// Checksum computation implementation. + /// + internal static class Checksum + { + + //************************************************** + //* Public interface + //************************************************** + + //------------------------------------------------- + /// + /// Compute checksum for the specified source file, + /// return it as hex string ("F3BA87..."). + /// + /// + /// This method will be run on a worker thread + /// (from thread pool) via async invocation. + /// + public static string ComputeChecksum(string sourceFile, ChecksumMethod method, Action progressNotifier) + { + System.Threading.Thread.Sleep(100); + using (var hashAlgorithm = CreateHashAlgorithm(method)) + using (var source = new TrackingStream(File.OpenRead(sourceFile), progressNotifier)) + { + var hash = hashAlgorithm.ComputeHash(source); + + var msg = new StringBuilder(128); + foreach (var byteValue in hash) + { + msg.AppendFormat(byteValue.ToString("X2", CultureInfo.InvariantCulture)); + } + return msg.ToString(); + } + } + + + //------------------------------------------------- + /// + /// Flag that requests cancellation of the current computation + /// (if set to true and a computation is ongoing). + /// + /// + /// Field marked as volatile because it will be accessed + /// by multiple threads (UI thread to set it, worker + /// thread to check it). + /// + public static volatile bool Cancel; + + + + + //************************************************** + //* Private + //************************************************** + + //------------------------------------------------- + /// + /// Find hash algorithm that corresponds to the + /// requested method + /// + /// Thrown + /// when requested method is not recognized. + private static HashAlgorithm CreateHashAlgorithm(ChecksumMethod method) + { + switch (method) + { + case ChecksumMethod.SHA1: return new SHA1CryptoServiceProvider(); + case ChecksumMethod.MD5: return new MD5CryptoServiceProvider(); + case ChecksumMethod.CRC32: return new CRC32(); + default: throw new NotSupportedException(string.Concat("Requested checksum method ", method, " is not supported")); + } + } + + + //------------------------------------------------- + /// + /// Custom stream for hash algorithm that only implements + /// Read & Dispose methods (every other method will + /// throw NotSupportedException). This class implements + /// a bridge pattern (both Read and Dispose are forwarded + /// to the underlying "tracked" stream). The only extra + /// functionality is that if Read operation read another + /// megabyte of data since last progress notifier invocation, + /// progress percentage is recomputed and progress notifier + /// is called with this value. This allows us to track + /// progress of hash computation even though HashAlgorithm + /// does not support this. + /// + private sealed class TrackingStream : Stream + { + public TrackingStream(Stream trackedStream, Action progressNotifier) + { + if (trackedStream == null) { throw new ArgumentNullException("trackedStream"); } + this._trackedStream = trackedStream; + this._progressNotifier = progressNotifier; + } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + { + this._trackedStream.Dispose(); + } + } + public override void Flush() + { + throw new NotImplementedException(); + } + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + public override int Read(byte[] buffer, int offset, int count) + { + var ret = this._trackedStream.Read(buffer, offset, count); + + if (Checksum.Cancel) + { + throw new ThreadInterruptedException(); + } + if (this._progressNotifier != null) + { + var position = this._trackedStream.Position; + const long mb = 2L << 19; + var megabyte = position / mb; + if (megabyte > this._lastMegabyte) + { + this._lastMegabyte = megabyte; + var percentage = ((decimal)position / this._trackedStream.Length); + this._progressNotifier(percentage); + } + } + return ret; + } + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } + public override bool CanRead + { + get { throw new NotImplementedException(); } + } + public override bool CanSeek + { + get { throw new NotImplementedException(); } + } + public override bool CanWrite + { + get { throw new NotImplementedException(); } + } + public override long Length + { + get { throw new NotImplementedException(); } + } + public override long Position + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + private long _lastMegabyte; + private readonly Action _progressNotifier; + private readonly Stream _trackedStream; + + } + + } + +} \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/ChecksumMethod.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/ChecksumMethod.cs new file mode 100644 index 0000000..53f5e8f --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/ChecksumMethod.cs @@ -0,0 +1,17 @@ +namespace Gardian.Utilities.ChecksumValidator +{ + + /// + /// Define supported checksum (hash) methods. + /// + internal enum ChecksumMethod + { + // ReSharper disable InconsistentNaming + None = 0, + SHA1, + MD5, + CRC32, + // ReSharper restore InconsistentNaming + } + +} diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/ColorPulser.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/ColorPulser.cs new file mode 100644 index 0000000..c8b72d7 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/ColorPulser.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; + +namespace Gardian.Utilities.ChecksumValidator +{ + + /// + /// + internal sealed class ColorPulser + { + + //************************************************** + //* Construction & destruction + //************************************************** + + //------------------------------------------------- + /// + /// Create new instance of color pulser, initializing + /// the color-transitions table. + /// + public ColorPulser(Timer timer, List ongoingPulses, Color startColor, Color endColor, TimeSpan pulseDuration) + { + if (timer == null) { throw new ArgumentNullException("timer"); } + this._timer = timer; + if (ongoingPulses == null) { throw new ArgumentNullException("ongoingPulses"); } + this._pulses = ongoingPulses; + + var change = timer.Interval; + if (change < 10) { throw new ArgumentException("Timer interval should be longer than 10 milliseconds", "timer");} + + var pulse = (int)pulseDuration.TotalMilliseconds; + if (pulse <= change) { throw new ArgumentException("Pulse duration should be longer than change period", "pulseDuration");} + + var count = pulse / change; + this._colors = new List(count * 2); + var redStep = (decimal)(endColor.R - startColor.R) / count; + var greenStep = (decimal)(endColor.G - startColor.G) / count; + var blueStep = (decimal)(endColor.B - startColor.B) / count; + /* + var currentRed = (decimal)startColor.R; + var currentGreen = (decimal)startColor.G; + var currentBlue = (decimal)startColor.B; + for (var i = 0; i < count - 1; ++i) + { + currentRed += redStep; + currentGreen += greenStep; + currentBlue += blueStep; + this._colors.Add(Color.FromArgb((int)currentRed, (int)currentGreen, (int)currentBlue)); + } + */ + this._colors.Add(endColor); + decimal currentRed = endColor.R; + decimal currentGreen = endColor.G; + decimal currentBlue = endColor.B; + for (var i = 0; i < count - 1; ++i) + { + currentRed -= redStep; + currentGreen -= greenStep; + currentBlue -= blueStep; + this._colors.Add(Color.FromArgb((int)currentRed, (int)currentGreen, (int)currentBlue)); + } + this._colors.Add(startColor); + + this._timer.Tick += this.OnTimer; + } + + + + + //************************************************** + //* Public interface + //************************************************** + + //------------------------------------------------- + /// + /// + public void Pulse(Control control) + { + if (control != null) + { + this._pulses.RemoveAll(p => object.ReferenceEquals(((PulseProgress)p).Control, control)); + this._pulses.Add(new PulseProgress { Pulser = this, Control = control, NextColorIndex = 0 }); + this.OnTimer(null, null); // immediately set color[0] + } + } + + + + + //************************************************** + //* Private + //************************************************** + + //------------------------------------------------- + /// + /// + /// + /// + private void OnTimer(object sender, EventArgs e) + { + if (this._pulses.Count > 0) + { + if (!this._timer.Enabled) + { + this._timer.Enabled = true; + } + + var i = 0; + while (i < this._pulses.Count) + { + var pulseProgress = (PulseProgress)this._pulses[i]; + if (object.ReferenceEquals(this, pulseProgress.Pulser)) + { + pulseProgress.Control.BackColor = this._colors[pulseProgress.NextColorIndex++]; + if (pulseProgress.NextColorIndex >= this._colors.Count) + { + this._pulses.RemoveAt(i--); + } + } + ++i; + } + } + else + { + this._timer.Enabled = false; + } + } + + + private sealed class PulseProgress + { + public ColorPulser Pulser; + public Control Control; + public int NextColorIndex; + } + + + private readonly List _colors; + private readonly List _pulses; + private readonly Timer _timer; + + } + +} \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Gardian.Utilities.ChecksumValidator.csproj b/src/Backup/Gardian.Utilities.ChecksumValidator/Gardian.Utilities.ChecksumValidator.csproj new file mode 100644 index 0000000..8dbb484 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/Gardian.Utilities.ChecksumValidator.csproj @@ -0,0 +1,73 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {67AA0267-46DB-4857-BFC1-87C9AB535542} + WinExe + Properties + Gardian.Utilities.ChecksumValidator + ChecksumValidator + v2.0 + 512 + ..\..\build\$(Configuration)\ + ..\..\build\$(Configuration)\$(AssemblyName).xml + prompt + 4 + Resources\App.ico + + + true + full + false + DEBUG;TRACE + + + pdbonly + true + TRACE + + + + + + + + + + + + + + + Form + + + MainForm.cs + + + + + MainForm.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + + + + + + + + \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.Designer.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.Designer.cs new file mode 100644 index 0000000..7b78a2d --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.Designer.cs @@ -0,0 +1,351 @@ +namespace Gardian.Utilities.ChecksumValidator +{ + partial class MainForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.Windows.Forms.TableLayoutPanel layout; + System.Windows.Forms.Button cancel; + System.Windows.Forms.ToolTip tooltop; + this._methodsContainer = new System.Windows.Forms.FlowLayoutPanel(); + this._methodLabel = new System.Windows.Forms.Label(); + this._methodSha1 = new System.Windows.Forms.RadioButton(); + this._methodMd5 = new System.Windows.Forms.RadioButton(); + this._methodCrc32 = new System.Windows.Forms.RadioButton(); + this._fileLabel = new System.Windows.Forms.Label(); + this._file = new System.Windows.Forms.TextBox(); + this._filePaste = new System.Windows.Forms.Button(); + this._fileBrowse = new System.Windows.Forms.Button(); + this._checksumLabel = new System.Windows.Forms.Label(); + this._checksum = new System.Windows.Forms.TextBox(); + this._checksumPaste = new System.Windows.Forms.Button(); + this._resultLabel = new System.Windows.Forms.Label(); + this._result = new System.Windows.Forms.TextBox(); + this._resultCompute = new System.Windows.Forms.Button(); + this._timer = new System.Windows.Forms.Timer(this.components); + layout = new System.Windows.Forms.TableLayoutPanel(); + cancel = new System.Windows.Forms.Button(); + tooltop = new System.Windows.Forms.ToolTip(this.components); + layout.SuspendLayout(); + this._methodsContainer.SuspendLayout(); + this.SuspendLayout(); + // + // layout + // + layout.AutoSize = true; + layout.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + layout.ColumnCount = 3; + layout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + layout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + layout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + layout.Controls.Add(this._methodsContainer, 0, 0); + layout.Controls.Add(this._fileLabel, 0, 1); + layout.Controls.Add(this._file, 0, 2); + layout.Controls.Add(this._filePaste, 1, 2); + layout.Controls.Add(this._fileBrowse, 2, 2); + layout.Controls.Add(this._checksumLabel, 0, 3); + layout.Controls.Add(this._checksum, 0, 4); + layout.Controls.Add(this._checksumPaste, 1, 4); + layout.Controls.Add(this._resultLabel, 0, 5); + layout.Controls.Add(this._result, 0, 6); + layout.Controls.Add(this._resultCompute, 1, 6); + layout.Location = new System.Drawing.Point(0, 0); + layout.Margin = new System.Windows.Forms.Padding(0); + layout.Name = "layout"; + layout.Padding = new System.Windows.Forms.Padding(6, 9, 6, 9); + layout.RowCount = 7; + layout.RowStyles.Add(new System.Windows.Forms.RowStyle()); + layout.RowStyles.Add(new System.Windows.Forms.RowStyle()); + layout.RowStyles.Add(new System.Windows.Forms.RowStyle()); + layout.RowStyles.Add(new System.Windows.Forms.RowStyle()); + layout.RowStyles.Add(new System.Windows.Forms.RowStyle()); + layout.RowStyles.Add(new System.Windows.Forms.RowStyle()); + layout.RowStyles.Add(new System.Windows.Forms.RowStyle()); + layout.Size = new System.Drawing.Size(478, 200); + layout.TabIndex = 0; + // + // _methodsContainer + // + this._methodsContainer.Anchor = System.Windows.Forms.AnchorStyles.Left; + this._methodsContainer.AutoSize = true; + this._methodsContainer.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + layout.SetColumnSpan(this._methodsContainer, 2); + this._methodsContainer.Controls.Add(this._methodLabel); + this._methodsContainer.Controls.Add(this._methodSha1); + this._methodsContainer.Controls.Add(this._methodMd5); + this._methodsContainer.Controls.Add(this._methodCrc32); + this._methodsContainer.Location = new System.Drawing.Point(6, 9); + this._methodsContainer.Margin = new System.Windows.Forms.Padding(0); + this._methodsContainer.Name = "_methodsContainer"; + this._methodsContainer.Size = new System.Drawing.Size(279, 23); + this._methodsContainer.TabIndex = 0; + // + // _methodLabel + // + this._methodLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this._methodLabel.AutoSize = true; + this._methodLabel.Location = new System.Drawing.Point(0, 5); + this._methodLabel.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0); + this._methodLabel.Name = "_methodLabel"; + this._methodLabel.Size = new System.Drawing.Size(98, 13); + this._methodLabel.TabIndex = 0; + this._methodLabel.Text = "Checksum method:"; + // + // _methodSha1 + // + this._methodSha1.AutoSize = true; + this._methodSha1.Checked = true; + this._methodSha1.Location = new System.Drawing.Point(104, 3); + this._methodSha1.Name = "_methodSha1"; + this._methodSha1.Size = new System.Drawing.Size(53, 17); + this._methodSha1.TabIndex = 0; + this._methodSha1.TabStop = true; + this._methodSha1.Text = "SHA1"; + this._methodSha1.UseVisualStyleBackColor = true; + // + // _methodMd5 + // + this._methodMd5.AutoSize = true; + this._methodMd5.Location = new System.Drawing.Point(163, 3); + this._methodMd5.Name = "_methodMd5"; + this._methodMd5.Size = new System.Drawing.Size(48, 17); + this._methodMd5.TabIndex = 0; + this._methodMd5.Text = "MD5"; + this._methodMd5.UseVisualStyleBackColor = true; + // + // _methodCrc32 + // + this._methodCrc32.AutoSize = true; + this._methodCrc32.Location = new System.Drawing.Point(217, 3); + this._methodCrc32.Name = "_methodCrc32"; + this._methodCrc32.Size = new System.Drawing.Size(59, 17); + this._methodCrc32.TabIndex = 0; + this._methodCrc32.Text = "CRC32"; + this._methodCrc32.UseVisualStyleBackColor = true; + // + // _fileLabel + // + this._fileLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this._fileLabel.AutoSize = true; + this._fileLabel.Location = new System.Drawing.Point(6, 41); + this._fileLabel.Margin = new System.Windows.Forms.Padding(0, 9, 3, 0); + this._fileLabel.Name = "_fileLabel"; + this._fileLabel.Size = new System.Drawing.Size(66, 13); + this._fileLabel.TabIndex = 0; + this._fileLabel.Text = "File to verify:"; + // + // _file + // + this._file.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this._file.Location = new System.Drawing.Point(9, 59); + this._file.Name = "_file"; + this._file.Size = new System.Drawing.Size(340, 20); + this._file.TabIndex = 0; + this._file.TextChanged += new System.EventHandler(this.CheckComputationAvailability); + // + // _filePaste + // + this._filePaste.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this._filePaste.AutoSize = true; + this._filePaste.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this._filePaste.Image = global::Gardian.Utilities.ChecksumValidator.Properties.Resources.Paste; + this._filePaste.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this._filePaste.Location = new System.Drawing.Point(355, 57); + this._filePaste.Name = "_filePaste"; + this._filePaste.Padding = new System.Windows.Forms.Padding(3, 1, 3, 1); + this._filePaste.Size = new System.Drawing.Size(28, 25); + this._filePaste.TabIndex = 0; + tooltop.SetToolTip(this._filePaste, "Paste clipboard as \"File to verify\""); + this._filePaste.UseVisualStyleBackColor = true; + this._filePaste.Click += new System.EventHandler(this.OnFilePaste); + // + // _fileBrowse + // + this._fileBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this._fileBrowse.AutoSize = true; + this._fileBrowse.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this._fileBrowse.Image = global::Gardian.Utilities.ChecksumValidator.Properties.Resources.Open; + this._fileBrowse.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this._fileBrowse.Location = new System.Drawing.Point(386, 57); + this._fileBrowse.Margin = new System.Windows.Forms.Padding(0, 3, 3, 3); + this._fileBrowse.Name = "_fileBrowse"; + this._fileBrowse.Padding = new System.Windows.Forms.Padding(3, 1, 3, 1); + this._fileBrowse.Size = new System.Drawing.Size(83, 25); + this._fileBrowse.TabIndex = 0; + this._fileBrowse.Text = " Browse"; + this._fileBrowse.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + tooltop.SetToolTip(this._fileBrowse, "Browse for \"File to verify\""); + this._fileBrowse.UseVisualStyleBackColor = true; + this._fileBrowse.Click += new System.EventHandler(this.OnBrowse); + // + // _checksumLabel + // + this._checksumLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this._checksumLabel.AutoSize = true; + this._checksumLabel.Location = new System.Drawing.Point(6, 94); + this._checksumLabel.Margin = new System.Windows.Forms.Padding(0, 9, 3, 0); + this._checksumLabel.Name = "_checksumLabel"; + this._checksumLabel.Size = new System.Drawing.Size(107, 13); + this._checksumLabel.TabIndex = 0; + this._checksumLabel.Text = "Expected checksum:"; + // + // _checksum + // + this._checksum.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this._checksum.Location = new System.Drawing.Point(9, 112); + this._checksum.Name = "_checksum"; + this._checksum.Size = new System.Drawing.Size(340, 20); + this._checksum.TabIndex = 0; + // + // _checksumPaste + // + this._checksumPaste.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this._checksumPaste.AutoSize = true; + this._checksumPaste.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + layout.SetColumnSpan(this._checksumPaste, 2); + this._checksumPaste.Image = global::Gardian.Utilities.ChecksumValidator.Properties.Resources.Paste; + this._checksumPaste.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this._checksumPaste.Location = new System.Drawing.Point(355, 110); + this._checksumPaste.Name = "_checksumPaste"; + this._checksumPaste.Padding = new System.Windows.Forms.Padding(3, 1, 3, 1); + this._checksumPaste.Size = new System.Drawing.Size(114, 25); + this._checksumPaste.TabIndex = 0; + this._checksumPaste.Text = "Paste"; + this._checksumPaste.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + tooltop.SetToolTip(this._checksumPaste, "Paste clipboard as \"Expected checksum\""); + this._checksumPaste.UseVisualStyleBackColor = true; + this._checksumPaste.Click += new System.EventHandler(this.OnChecksumPaste); + // + // _resultLabel + // + this._resultLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this._resultLabel.AutoSize = true; + this._resultLabel.Enabled = false; + this._resultLabel.Location = new System.Drawing.Point(6, 147); + this._resultLabel.Margin = new System.Windows.Forms.Padding(0, 9, 3, 0); + this._resultLabel.Name = "_resultLabel"; + this._resultLabel.Size = new System.Drawing.Size(110, 13); + this._resultLabel.TabIndex = 0; + this._resultLabel.Text = "Computed checksum:"; + // + // _result + // + this._result.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this._result.BackColor = System.Drawing.SystemColors.Window; + this._result.Enabled = false; + this._result.Location = new System.Drawing.Point(9, 165); + this._result.Name = "_result"; + this._result.ReadOnly = true; + this._result.Size = new System.Drawing.Size(340, 20); + this._result.TabIndex = 0; + // + // _resultCompute + // + this._resultCompute.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this._resultCompute.AutoSize = true; + layout.SetColumnSpan(this._resultCompute, 2); + this._resultCompute.Enabled = false; + this._resultCompute.Image = global::Gardian.Utilities.ChecksumValidator.Properties.Resources.Run; + this._resultCompute.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this._resultCompute.Location = new System.Drawing.Point(355, 163); + this._resultCompute.Name = "_resultCompute"; + this._resultCompute.Padding = new System.Windows.Forms.Padding(6, 1, 3, 1); + this._resultCompute.Size = new System.Drawing.Size(114, 25); + this._resultCompute.TabIndex = 0; + this._resultCompute.Text = "Compute"; + this._resultCompute.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + tooltop.SetToolTip(this._resultCompute, "Compute checksum and verify it against the specified expected value"); + this._resultCompute.UseVisualStyleBackColor = true; + this._resultCompute.Click += new System.EventHandler(this.OnCompute); + // + // cancel + // + cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + cancel.Location = new System.Drawing.Point(0, 0); + cancel.Name = "cancel"; + cancel.Size = new System.Drawing.Size(75, 23); + cancel.TabIndex = 0; + cancel.TabStop = false; + cancel.Text = "Cancel"; + cancel.UseVisualStyleBackColor = true; + cancel.Click += new System.EventHandler(this.OnCancel); + // + // _timer + // + this._timer.Interval = 20; + // + // MainForm + // + this.AcceptButton = this._resultCompute; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoSize = true; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.CancelButton = cancel; + this.ClientSize = new System.Drawing.Size(594, 274); + this.Controls.Add(layout); + this.Controls.Add(cancel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.Name = "MainForm"; + this.Text = "Main dialog"; + layout.ResumeLayout(false); + layout.PerformLayout(); + this._methodsContainer.ResumeLayout(false); + this._methodsContainer.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox _file; + private System.Windows.Forms.Label _checksumLabel; + private System.Windows.Forms.TextBox _checksum; + private System.Windows.Forms.Button _fileBrowse; + private System.Windows.Forms.Button _checksumPaste; + private System.Windows.Forms.Label _resultLabel; + private System.Windows.Forms.Button _resultCompute; + private System.Windows.Forms.TextBox _result; + private System.Windows.Forms.Timer _timer; + private System.Windows.Forms.Label _fileLabel; + private System.Windows.Forms.RadioButton _methodSha1; + private System.Windows.Forms.RadioButton _methodMd5; + private System.Windows.Forms.FlowLayoutPanel _methodsContainer; + private System.Windows.Forms.Label _methodLabel; + private System.Windows.Forms.RadioButton _methodCrc32; + private System.Windows.Forms.Button _filePaste; + } +} \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.cs new file mode 100644 index 0000000..45999d7 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.cs @@ -0,0 +1,354 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Threading; +using System.Windows.Forms; + +namespace Gardian.Utilities.ChecksumValidator +{ + + /// + /// + public sealed partial class MainForm : Form + { + + //************************************************** + //* Construction & destruction + //************************************************** + + //------------------------------------------------- + /// + /// Create new instance of main form, initializing + /// controls (designer), fonts, icon and color pulsers + /// (pulsers are used to temporarily highlight input + /// controls when something interesting happens). + /// + public MainForm() + { + this.InitializeComponent(); + this.Font = SystemFonts.MessageBoxFont; + this.Icon = Properties.Resources.App; + this.Text = Properties.Resources.Title; + var boldFont = new Font(this.Font, FontStyle.Bold); + this._methodLabel.Font = this._fileLabel.Font = this._checksumLabel.Font = this._resultLabel.Font = boldFont; + + var ongoingPulses = new List(); + this._greenPulser = new ColorPulser( + this._timer, + ongoingPulses, + SystemColors.Window, + Color.PaleGreen, //SystemColors.Info, + TimeSpan.FromMilliseconds(250)); + this._redPulser = new ColorPulser( + this._timer, + ongoingPulses, + SystemColors.Window, + Color.MistyRose, + TimeSpan.FromMilliseconds(250)); + this._result.MouseClick += this.OnErrorDetails; + this.HelpRequested += this.OnErrorDetails; + } + + + //------------------------------------------------- + /// + /// Set initial form focus. + /// + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + this._file.Focus(); + } + + + + + //************************************************** + //* Private + //************************************************** + + //------------------------------------------------- + /// + /// + private void CheckComputationAvailability(object sender, EventArgs e) + { + this._resultCompute.Enabled = !string.IsNullOrEmpty(this._file.Text); + } + + + //------------------------------------------------- + /// + /// + private void OnBrowse(object sender, EventArgs e) + { + using (var dlg = new OpenFileDialog + { + CheckFileExists = false, + CheckPathExists = false, + DereferenceLinks = true, + Multiselect = false, + Title = "Select file to compute checksum for", + Filter = "Executable files (*.exe;*.msi;*.msu;*.iso)|*.exe;*.msi;*.msu;*.iso|All files (*.*)|*.*", + }) + { + if (!string.IsNullOrEmpty(this._file.Text)) + { + try + { + dlg.InitialDirectory = Path.GetDirectoryName(this._file.Text); + } + catch (ArgumentException) {} + } + if (dlg.ShowDialog(this) == DialogResult.OK) + { + this._file.Text = dlg.FileName; + this._greenPulser.Pulse(this._file); + this.CheckComputationAvailability(null, null); + this._checksum.Focus(); + } + } + } + + + //------------------------------------------------- + /// + /// + private void OnCancel(object sender, EventArgs e) + { + this.Close(); + } + + + //------------------------------------------------- + /// + /// + private void OnChecksumPaste(object sender, EventArgs e) + { + if (Clipboard.ContainsText()) + { + this._checksum.Text = Clipboard.GetText(); + this._checksum.Select(this._checksum.Text.Length, 0); + this._greenPulser.Pulse(this._checksum); + if (this._resultCompute.Enabled) + { + this._resultCompute.Focus(); + } + } + } + + + //------------------------------------------------- + /// + /// + private void OnCompute(object sender, EventArgs e) + { + if (this._resultCompute.Tag != null) + { + Checksum.Cancel = true; + this._resultCompute.Text = "Cancelling"; + } + else + { + this._result.Enabled = true; + + FileInfo fileInfo = null; + try { fileInfo = new FileInfo(this._file.Text); } catch (ArgumentException) {} + if (fileInfo == null || !fileInfo.Exists) + { + this._file.Focus(); + this._result.ForeColor = Color.Red; + this._result.Text = "Specified file does not exist or is not readable"; + this._result.Select(this._result.Text.Length, 0); + + this._redPulser.Pulse(this._file); + this._redPulser.Pulse(this._result); + return; + } + + this._methodsContainer.Enabled = false; + this._checksumLabel.Enabled = false; + this._checksum.Enabled = false; + this._checksumPaste.Enabled = false; + this._fileLabel.Enabled = false; + this._file.Enabled = false; + this._filePaste.Enabled = false; + this._fileBrowse.Enabled = false; + this._resultLabel.Enabled = true; + this._result.ForeColor = SystemColors.ControlText; + this.OnComputeProgress(0m); + //this._greenPulser.Pulse(this._result); + this._resultCompute.Text = "Cancel"; + this._resultCompute.Image = Properties.Resources.Stop; + this._resultCompute.Tag = string.Empty; // make Tag non-null + this._resultCompute.Focus(); + + Checksum.Cancel = false; + this._error = null; + Func, string> computeFunction = Checksum.ComputeChecksum; + computeFunction.BeginInvoke( + fileInfo.FullName, + this._methodMd5.Checked + ? ChecksumMethod.MD5 + : this._methodCrc32.Checked + ? ChecksumMethod.CRC32 + : ChecksumMethod.SHA1, + this.OnComputeProgress, + this.OnComputeDone, + computeFunction); + } + } + + + //------------------------------------------------- + /// + /// + private void OnComputeDone(IAsyncResult result) + { + string checksum = null; + string error = null; + try + { + var test = (Func, string>)result.AsyncState; + checksum = test.EndInvoke(result); + } + catch (Exception ex) + { + error = (ex is ThreadInterruptedException + ? string.Empty + : TraceUtilities.BuildExceptionReport( + "Checksum computation failed", + string.Empty, null, ex, null).ToString()); + if (error.Length > 0) + { + TraceUtilities.TraceMultilineText(error, "Checksum Error"); + } + } + + this.BeginInvoke(new Action(this.OnComputeReportResults), checksum, error); // marshall to the UI thread + } + + + //------------------------------------------------- + /// + /// Computation is still going on, + /// + private void OnComputeProgress(decimal percentage) + { + if (this.InvokeRequired) + { + this.Invoke(new Action(this.OnComputeProgress), percentage); // marshall to the UI thread + } + else + { + var percentageStr = percentage.ToString("0.0%"); + var currentTicks = DateTime.Now.Ticks; + if (currentTicks > this._nextTitleUpdateTicks) + { + const long delay = 150 * TimeSpan.TicksPerMillisecond; + this._nextTitleUpdateTicks = currentTicks + delay; + this.Text = string.Concat(percentageStr, " - ", Properties.Resources.Title); + } + this._result.Text = string.Concat("Please wait... (", percentageStr, " complete)"); + } + } + + + //------------------------------------------------- + /// + /// + private void OnComputeReportResults(string checksum, string error) + { + this.Text = Properties.Resources.Title; + this._methodsContainer.Enabled = true; + this._checksumLabel.Enabled = true; + this._checksum.Enabled = true; + this._checksumPaste.Enabled = true; + this._fileLabel.Enabled = true; + this._file.Enabled = true; + this._filePaste.Enabled = true; + this._fileBrowse.Enabled = true; + this._resultCompute.Text = "Compute"; + this._resultCompute.Image = Properties.Resources.Run; + this._resultCompute.Tag = null; + + if (error != null) + { + if (error.Length == 0) + { + this._result.Text = "Cancelled"; + } + else + { + this._error = error; + this._result.Text = "Failed (click here or press F1 for error details)"; + } + this._redPulser.Pulse(this._result); + this._result.ForeColor = Color.Red; + } + else + { + var identical = StringComparer.OrdinalIgnoreCase.Equals(checksum, this._checksum.Text.Trim()); + this._result.Text = string.Concat( + checksum ?? "(no results)", + " - ", + identical ? "OK" : "INVALID"); + this._result.ForeColor = identical ? Color.Green : Color.Red; + if (identical) + { + this._greenPulser.Pulse(this._checksum); + this._greenPulser.Pulse(this._result); + } + else + { + this._checksum.Focus(); + this._redPulser.Pulse(this._checksum); + this._redPulser.Pulse(this._result); + } + } + + this._result.Select(this._result.Text.Length, 0); + } + + + //------------------------------------------------- + /// + /// + private void OnErrorDetails(object sender, EventArgs e) + { + if (this._error != null) + { + MessageBox.Show( + this, + this._error, + "SHA1 Computation Error", + MessageBoxButtons.OK, + MessageBoxIcon.Information); + } + } + + + //------------------------------------------------- + /// + /// + private void OnFilePaste(object sender, EventArgs e) + { + if (Clipboard.ContainsText()) + { + this._file.Text = Clipboard.GetText(); + this._file.Select(this._file.Text.Length, 0); + this._greenPulser.Pulse(this._file); + this.CheckComputationAvailability(null, null); + this._checksum.Focus(); + } + } + + + private string _error; + private readonly ColorPulser _greenPulser; + private long _nextTitleUpdateTicks; // earliest time when titlebar can be updated again (DateTime ticks); for discussion on reason behind this see http://stackoverflow.com/questions/380380/how-to-force-a-redraw-of-my-applications-entry-in-the-taskbar + private readonly ColorPulser _redPulser; + + } + +} \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.resx b/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.resx new file mode 100644 index 0000000..b78cb16 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.resx @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + + False + + + 102, 17 + + + False + + + 17, 17 + + \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Program.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/Program.cs new file mode 100644 index 0000000..660ddf5 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/Program.cs @@ -0,0 +1,32 @@ +using System; +using System.Windows.Forms; + +namespace Gardian.Utilities.ChecksumValidator +{ + + // .NET 3.5 - style delegates + internal delegate void Action(T value); + internal delegate void Action(T1 value1, T2 value2); + internal delegate T4 Func(T1 value1, T2 value2, T3 value3); + + + /// + /// + public static class Program + { + + /// + /// The main entry point for the application. + /// + [STAThread] + public static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Control.CheckForIllegalCrossThreadCalls = true; + Application.Run(new MainForm()); + } + + } + +} \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/AssemblyInfo.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7d7a364 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/AssemblyInfo.cs @@ -0,0 +1,28 @@ +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("ChecksumValidator")] +[assembly: AssemblyDescription("ChecksumValidator: GUI application to compute checksum of a specified file and validate it against expected checksum")] +[assembly: AssemblyCulture("")] +[assembly: AssemblyCopyright("Copyright (C) 2009 Milan Gardian. All rights reserved.")] +[assembly: ComVisible(false)] +[assembly: Guid("10ABE120-00E5-43FB-8101-16ACA2A31A04")] +[assembly: CLSCompliant(true)] + +[assembly: AssemblyVersion("1.2")] +[assembly: AssemblyFileVersion("1.2.2009.05130")] +[assembly: AssemblyProduct("ChecksumValidator v1.2 " +#if DEBUG + + "(debug)" +#else + + "(release)" +#endif +)] +[assembly: AssemblyConfiguration( +#if DEBUG + "DEBUG" +#else + "RELEASE" +#endif +)] \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/Resources.Designer.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/Resources.Designer.cs new file mode 100644 index 0000000..1690113 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/Resources.Designer.cs @@ -0,0 +1,107 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.3074 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Gardian.Utilities.ChecksumValidator.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Gardian.Utilities.ChecksumValidator.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + internal static System.Drawing.Icon App { + get { + object obj = ResourceManager.GetObject("App", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + internal static System.Drawing.Bitmap Open { + get { + object obj = ResourceManager.GetObject("Open", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Paste { + get { + object obj = ResourceManager.GetObject("Paste", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Run { + get { + object obj = ResourceManager.GetObject("Run", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Stop { + get { + object obj = ResourceManager.GetObject("Stop", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Checksum validator. + /// + internal static string Title { + get { + return ResourceManager.GetString("Title", resourceCulture); + } + } + } +} diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/Resources.resx b/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/Resources.resx new file mode 100644 index 0000000..7460970 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/Resources.resx @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\App.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\openHS.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\PasteHS.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\RunHS.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\StopHS.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Checksum validator + + \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/App.ico b/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/App.ico new file mode 100644 index 0000000000000000000000000000000000000000..b2ec9176c6243a10b96b42fa807dc564dce3dd3c GIT binary patch literal 14846 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 literal 0 HcmV?d00001 diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/OpenHS.png b/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/OpenHS.png new file mode 100644 index 0000000000000000000000000000000000000000..0bc670e2c0dfd658b8e064e6ec5e5ace236bd8aa GIT binary patch literal 743 zcmV?P)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ;T}ebiRCwB?lTAxiQ51%sbM8^IEWeO4D2PT)geLg| z8bwL73?ljgMFWF^zD61~(McH?pwNHcK z+SfpEjo16EwceNIWm(2*Dp*O=g)6{lt;>6$3^m^FzfbK0MIf z)^q&yt%in8YvxXN+#Z=*itc#>JzcFp|KFmuWl86r1E)^>4|w$KwU)W1XwbME0np#n zRLhpF>j3bb!Iy*wPk*#M?Cps5A3AgXZ@{-jHE3OcWIo>gJDu6yeT{g2P!ju+;1)(0 zc(n;@1ZynDTEtqc6^@;{=#@+qCtwr&Aj6l0oFsUKDSQ+McYXS2{mYMQ{!BrvAU37U z%g9N>^A|;+7UycP)?vkAtYD497{}U5;dm0xHXCSZF5>&S z-{yFb0nUO+z-ivSpXcVY_-y8isZ#X4)O`Q)`c~ib`452=L5$_~ zL>=3<3ZBUW0;wi55jKu7u_DnCCXSdHpXK9J9i!9f)sl&`3uSm@?A#nd@dsFiNi-&o zFj`@>CRK{Xg+(4s)$?H@e)4uWKk^G8!tiu8J8CC+^QgOYb}9kd2B@@xC@n{saz@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ;P)S5VRCwB?lTAoeVHAd+JL(uNB`Hg2RYYPDSX7G& z35m=Sgci9fQi{lkh@cjc5J4#Y5VTW>j21}}LNOsF2(~bapoLMQiKdP^dgspfd+&TL z)X2(OcvgqQ;o+PY9?v<)N-Fnn!``l&&X|z2FL~YbvHVV3*SqBa-qT07F9OYrgY-l{ zHFbx`LohQv$NjqriZ_%I&&wyY7ND~6%B@$6`!S%o>Tn6w)$6IMT0>63TH?7OP1m|U z1+!Dc<8daw^iaEdl)CL53=Rw=e!U-RWv;;MVzcEg(on2<>N#DXCZ z-*IXJJ(oo3`IFn8^#WjxVNZD}QfbcBALn50N%yj&)yp;35=ns?0v z(btiIVPjv-@4(4GzCyA`kS_y6l_~>6Lo)-z&;LOBB?CjL0RzLU1O^7H84L{K`IF+0 zx&hU`_H=O!skpV|(ptY}Ly==2|8w-E@H8G)5LDUC%v0v9D5&vfhtRv!JKSw4oJ@_4 z2Y!`3f2?~{;l!nV*@q^}T>kQN=}Aq?^nd4449`tITCuG*Zno{INV&W6=Q2D5ckG>Q zro2_$MA=oLHvLM~y8LrxO0Eu9ZgvPC-Lc0?)}_lqL_McRptn?HnfUS0B^)Imx8IRe z)KJt=f6mTu`t9!DstI>Bllr2Z&IbDLvE@9lhqt3Eqd&60>iqA`%xCQ7?Br)RT;P1h z`Sr+ktNcTY6Mr28 PdYi%1)z4*}Q$iB}e9e%5 literal 0 HcmV?d00001 diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/StopHS.png b/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/StopHS.png new file mode 100644 index 0000000000000000000000000000000000000000..a75db7757e2ad8fcc442014fe574b5e61438a83a GIT binary patch literal 429 zcmV;e0aE^nP)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ-BS}O-RCwCtld(&~Kp4eeT2ZT^O$Li~EgjoUa1hB- zvbs2AFRuPC{s&GOTy)GL85|03g+hmp(MFGOflHISv$=CGLINEeeB;OC2k$*TLu-v) z)WDAVd%)gr$LVD30Pp~~N^6u#2c^=!^Y9XGdyVZ9r<1XBcyxTc*y18_cOn8I|moSbb69LVo|GZj-wE+L@7k&l+ XH*cBHD2Q%R00000NkvXXu0mjfqKT@= literal 0 HcmV?d00001 diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/TraceUtilities.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/TraceUtilities.cs new file mode 100644 index 0000000..efb7e45 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/TraceUtilities.cs @@ -0,0 +1,489 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; + +namespace Gardian.Utilities.ChecksumValidator +{ + + /// + /// Collection of tracing methods. + /// + public static class TraceUtilities + { + + ///------------------------------------------------ + /// + /// Build string that contains all available information + /// about the specified exception (all nested exceptions, + /// type of exception, mesage, stack). + /// + public static StringBuilder BuildExceptionReport(Exception ex) + { + return BuildExceptionReport(null, null, null, ex, null); + } + + + ///------------------------------------------------ + /// + /// Build string that contains all available information + /// about the specified exception (all nested exceptions, + /// type of exception, mesage, stack). + /// + public static StringBuilder BuildExceptionReport(Exception ex, StringBuilder builder) + { + return BuildExceptionReport(null, null, null, ex, builder); + } + + + ///------------------------------------------------ + /// + /// Build string that contains all available information + /// about the specified exception (all nested exceptions, + /// type of exception, mesage, stack). + /// + public static StringBuilder BuildExceptionReport(string header, string footer, string separator, Exception ex, StringBuilder builder) + { + //validate arguments + if (null == builder) + { + builder = new StringBuilder(512); + } + if (null == header) + { + header = "~~~~~~~~~" + Environment.NewLine + "Exception report"; + } + if (null == footer) + { + footer = "~~~~~~~~~"; + } + if (null == separator) + { + separator = "---------"; + } + + //header + LinePrinter linePrinter = new LinePrinter(' ', 0, builder); + if (header.Length > 0) + { + TraverseStringLines(header, linePrinter.Print); + linePrinter.Print(separator); + } + + //body + TraverseExceptionTree( + ex, + 0, //starting level + true, //first exception in list + delegate(KeyValuePair, string> info) //section header printer + { + //print section header + linePrinter.UpdateIndent(info.Key.Key); + if (info.Key.Value) //first section + { + linePrinter.Print(string.Empty); + linePrinter.Print("List of embedded exceptions:"); + linePrinter.Print(string.Empty); + } + else + { + linePrinter.Print(separator); + } + + //user-friendly message (if present) + if (string.IsNullOrEmpty(info.Value)) + { + linePrinter.Print(""); + } + else + { + linePrinter.PrintPrefix(); + builder.Append("User-friendly message: "); + linePrinter.StartWithoutPrefix(); + TraverseStringLines(info.Value, linePrinter.Print); + } + }, + delegate(KeyValuePair, Exception> info) //exception detail printer + { + //make sure indent is up-to-date + linePrinter.UpdateIndent(info.Key.Key); + + //separator between exceptions (if needed) + if (info.Key.Value) + { + if (info.Key.Key > 0) + { + linePrinter.UpdateIndent(info.Key.Key - 1); + linePrinter.Print("Exception details:"); + linePrinter.UpdateIndent(info.Key.Key); + } + } + else + { + linePrinter.Print(separator); + } + + //exception details + if (null == info.Value) + { + linePrinter.Print(""); + } + else + { + linePrinter.PrintPrefix(); + builder.Append(info.Value.GetType().FullName); + builder.Append(" - "); + linePrinter.StartWithoutPrefix(); + TraverseStringLines(string.IsNullOrEmpty(info.Value.Message) ? "" : info.Value.Message, linePrinter.Print); + + FileNotFoundException tex = info.Value as FileNotFoundException; + if (null != tex) + { + if (!string.IsNullOrEmpty(tex.FileName)) + { + linePrinter.PrintPrefix(); + builder.Append("FileNotFoundException.FileName: "); + linePrinter.StartWithoutPrefix(); + TraverseStringLines(tex.FileName, linePrinter.Print); + } + if (!string.IsNullOrEmpty(tex.FusionLog)) + { + linePrinter.PrintPrefix(); + builder.Append("FileNotFoundException.FusionLog: "); + linePrinter.StartWithoutPrefix(); + TraverseStringLines(tex.FusionLog, linePrinter.Print); + } + } + else + { + SqlException sex = info.Value as SqlException; + if (null != sex) + { + linePrinter.PrintPrefix(); + builder.Append("SqlException.ErrorCode: "); + builder.Append(sex.ErrorCode); + builder.Append(" (0x"); + builder.Append(sex.ErrorCode.ToString("X8", CultureInfo.InvariantCulture)); + builder.AppendLine(")"); + + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors.Count: "); + builder.AppendLine(sex.Errors.Count.ToString(CultureInfo.InvariantCulture)); + builder.AppendLine(); + + int index = 0; + foreach (SqlError sqlError in sex.Errors) + { + string indexStr = (index++).ToString(CultureInfo.InvariantCulture); + + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors["); + builder.Append(indexStr); + builder.Append("].Class: "); + builder.AppendLine(sqlError.Class.ToString(CultureInfo.InvariantCulture)); + + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors["); + builder.Append(indexStr); + builder.Append("].LineNumber: "); + builder.AppendLine(sqlError.LineNumber.ToString(CultureInfo.InvariantCulture)); + + if (!string.IsNullOrEmpty(sqlError.Message)) + { + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors["); + builder.Append(indexStr); + builder.Append("].Message: "); + linePrinter.StartWithoutPrefix(); + TraverseStringLines(sqlError.Message, linePrinter.Print); + } + + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors["); + builder.Append(indexStr); + builder.Append("].Number: "); + builder.Append(sqlError.Number.ToString(CultureInfo.InvariantCulture)); + builder.Append(" (0x"); + builder.Append(sqlError.Number.ToString("X8", CultureInfo.InvariantCulture)); + builder.AppendLine(")"); + + if (!string.IsNullOrEmpty(sqlError.Procedure)) + { + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors["); + builder.Append(indexStr); + builder.Append("].Procedure: "); + linePrinter.StartWithoutPrefix(); + TraverseStringLines(sqlError.Procedure, linePrinter.Print); + } + + if (!string.IsNullOrEmpty(sqlError.Server)) + { + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors["); + builder.Append(indexStr); + builder.Append("].Server: "); + linePrinter.StartWithoutPrefix(); + TraverseStringLines(sqlError.Server, linePrinter.Print); + } + + if (!string.IsNullOrEmpty(sqlError.Source)) + { + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors["); + builder.Append(indexStr); + builder.Append("].Source: "); + linePrinter.StartWithoutPrefix(); + TraverseStringLines(sqlError.Source, linePrinter.Print); + } + + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors["); + builder.Append(indexStr); + builder.Append("].State: "); + builder.AppendLine(sqlError.State.ToString(CultureInfo.InvariantCulture)); + + builder.AppendLine(); + } + } + else + { + ExternalException eex = info.Value as ExternalException; + if (null != eex) + { + linePrinter.PrintPrefix(); + builder.Append("ExternalException.ErrorCode: "); + builder.Append(eex.ErrorCode); + builder.Append(" (0x"); + builder.Append(eex.ErrorCode.ToString("X8", CultureInfo.InvariantCulture)); + builder.AppendLine(")"); + } + } + } + + TraverseStringLines(string.IsNullOrEmpty(info.Value.StackTrace) ? "" : info.Value.StackTrace, linePrinter.Print); + } + }); + + //footer + if (footer.Length > 0) + { + linePrinter.UpdateIndent(0); + TraverseStringLines(footer, linePrinter.Print); + } + + return builder; + } + + + //------------------------------------------------- + /// + /// Output exception report (from BuildExceptionReport) + /// to .NET's diagnostic trace using the specified category + /// to mark each output line. + /// + public static void TraceExceptionReport(string category, Exception ex) + { + TraceExceptionReport(null, null, null, category, ex); + } + + + //------------------------------------------------- + /// + /// Output exception report (from BuildExceptionReport) + /// to .NET's diagnostic trace using the specified category + /// to mark each output line. + /// + public static void TraceExceptionReport(string header, string footer, string separator, string category, Exception ex) + { + StringBuilder b = BuildExceptionReport(header, footer, separator, ex, null); + TraceMultilineText(b.ToString(), category); + } + + + //------------------------------------------------- + /// + /// + public static void TraceMultilineText(string text, string category) + { + TraverseStringLines(text, delegate(string s) + { + Trace.WriteLine(s, category); + }); + } + + + //------------------------------------------------- + /// + /// Traverse all exceptions that are hanging off the + /// specified root exception, calling the action handler + /// for each exception encountered (including the root + /// exception). Callback receives level + /// + /// + /// + /// + /// + /// + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Method signature was designed so that only standard .NET types are used (helpful when this class is included in PRun project directly for compile)")] + [SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow", Justification = "We don't expect levels to rise beyond int boundaries :)")] + public static void TraverseExceptionTree(Exception ex, int level, bool first, System.Action, string>> sectionStartHandler, System.Action, Exception>> exceptionHandler) + { + while (null != ex) + { + if (null != exceptionHandler) { exceptionHandler(new KeyValuePair, Exception>(new KeyValuePair(level, first), ex)); } + if (null != ex.Data) + { + int sectionLevel = level + 1; + int exceptionLevel = level + 2; + bool firstInSection = true; + ReflectionTypeLoadException loadException = ex as ReflectionTypeLoadException; + if (null != loadException) + { + foreach (Exception subex in loadException.LoaderExceptions) + { + if (null != sectionStartHandler) { sectionStartHandler(new KeyValuePair, string>(new KeyValuePair(sectionLevel, firstInSection), null)); } + TraverseExceptionTree(subex, exceptionLevel, true, sectionStartHandler, exceptionHandler); + firstInSection = false; + } + } + foreach (DictionaryEntry dictionaryEntry in ex.Data) + { + IEnumerable subexCollection = dictionaryEntry.Value as IEnumerable; + if (null != subexCollection) + { + foreach (Exception subex in subexCollection) + { + if (null != sectionStartHandler) { sectionStartHandler(new KeyValuePair, string>(new KeyValuePair(sectionLevel, firstInSection), null)); } + TraverseExceptionTree(subex, exceptionLevel, true, sectionStartHandler, exceptionHandler); + firstInSection = false; + } + } + else + { + IEnumerable> subexCollection2 = dictionaryEntry.Value as IEnumerable>; + if (null != subexCollection2) + { + foreach (KeyValuePair pair in subexCollection2) + { + if (null != sectionStartHandler) { sectionStartHandler(new KeyValuePair, string>(new KeyValuePair(sectionLevel, firstInSection), pair.Key)); } + TraverseExceptionTree(pair.Value, exceptionLevel, true, sectionStartHandler, exceptionHandler); + firstInSection = false; + } + } + } + } + } + ex = ex.InnerException; + first = false; + } + } + + + //------------------------------------------------- + /// + /// Invoke the specified delegate for each line that's + /// contained in the provided value. E.g. value + /// "hello(newline)world(newline)" would cause action + /// to be called twice, once with "hello" and once + /// with "world". + /// + public static void TraverseStringLines(string value, System.Action action) + { + if (null != action && null != value) + { + int start = 0; + while (true) + { + int end = value.IndexOf(Environment.NewLine, start, StringComparison.Ordinal); + if (end >= 0) + { + action(value.Substring(start, end - start)); + start = end + Environment.NewLine.Length; + } + else + { + if (0 == start) + { + action(value); + } + else + { + int finalSegmentLength = value.Length - start; + if (finalSegmentLength > 0) + { + action(value.Substring(start, finalSegmentLength)); + } + } + break; + } + } + } + } + + + + + /************************************************** + /* Private + /**************************************************/ + + //------------------------------------------------- + /// + /// + private sealed class LinePrinter + { + public LinePrinter(char prefix, int indent, StringBuilder stringBuilder) + { + this._prefix = prefix; + this._repeatCount = indent; + this._stringBuilder = stringBuilder; + } + + public void Print(string s) + { + if (this._noPrefix) + { + this._noPrefix = false; + } + else + { + this._stringBuilder.Append(this._prefix, this._repeatCount); + } + this._stringBuilder.AppendLine(s); + } + + public void PrintPrefix() + { + if (this._repeatCount > 0) + { + this._stringBuilder.Append(this._prefix, this._repeatCount); + } + } + + public void StartWithoutPrefix() + { + this._noPrefix = true; + } + + public void UpdateIndent(int indent) + { + this._repeatCount = 4 * indent; + } + + private readonly char _prefix; + private int _repeatCount; + private bool _noPrefix; //initialized to false by CLR + private readonly StringBuilder _stringBuilder; + } + + } + +} \ No newline at end of file diff --git a/src/ChecksumValidator.sln b/src/ChecksumValidator.sln index f613ea8..0e19e80 100644 --- a/src/ChecksumValidator.sln +++ b/src/ChecksumValidator.sln @@ -1,6 +1,8 @@  -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32014.148 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gardian.Utilities.ChecksumValidator", "Gardian.Utilities.ChecksumValidator\Gardian.Utilities.ChecksumValidator.csproj", "{67AA0267-46DB-4857-BFC1-87C9AB535542}" EndProject Global @@ -17,4 +19,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E2831EED-D6CE-4816-A557-D19454FC5CB4} + EndGlobalSection EndGlobal diff --git a/src/Gardian.Utilities.ChecksumValidator/Gardian.Utilities.ChecksumValidator.csproj b/src/Gardian.Utilities.ChecksumValidator/Gardian.Utilities.ChecksumValidator.csproj index 8dbb484..d570d3f 100644 --- a/src/Gardian.Utilities.ChecksumValidator/Gardian.Utilities.ChecksumValidator.csproj +++ b/src/Gardian.Utilities.ChecksumValidator/Gardian.Utilities.ChecksumValidator.csproj @@ -1,5 +1,5 @@  - + Debug AnyCPU @@ -10,24 +10,32 @@ Properties Gardian.Utilities.ChecksumValidator ChecksumValidator - v2.0 + v4.8 512 ..\..\build\$(Configuration)\ ..\..\build\$(Configuration)\$(AssemblyName).xml prompt 4 Resources\App.ico + + + + + 3.5 + true full false DEBUG;TRACE + false pdbonly true TRACE + false @@ -63,6 +71,7 @@ True + diff --git a/src/Gardian.Utilities.ChecksumValidator/MainForm.cs b/src/Gardian.Utilities.ChecksumValidator/MainForm.cs index 45999d7..9fa0663 100644 --- a/src/Gardian.Utilities.ChecksumValidator/MainForm.cs +++ b/src/Gardian.Utilities.ChecksumValidator/MainForm.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Drawing; using System.IO; +using System.Security; using System.Threading; using System.Windows.Forms; @@ -98,7 +99,7 @@ private void OnBrowse(object sender, EventArgs e) { dlg.InitialDirectory = Path.GetDirectoryName(this._file.Text); } - catch (ArgumentException) {} + catch (ArgumentException) { } } if (dlg.ShowDialog(this) == DialogResult.OK) { @@ -152,8 +153,32 @@ private void OnCompute(object sender, EventArgs e) { this._result.Enabled = true; + //Included all possible exceptions catching for FileInfo FileInfo fileInfo = null; - try { fileInfo = new FileInfo(this._file.Text); } catch (ArgumentException) {} + try + { + fileInfo = new FileInfo(this._file.Text); + } + catch (ArgumentNullException) + { + MessageBox.Show("ArgumentNullException Occured: The file name might be null"); + } + catch (SecurityException) + { + MessageBox.Show("SecurityException Occured: The caller does not have the required permission"); + } + catch (ArgumentException) + { + MessageBox.Show("ArgumentException Occured: The file name might be empty, might contains only white spaces, or might contain invalid characters"); + } + catch (UnauthorizedAccessException) + { + MessageBox.Show("UnauthorizedAccessException Occured: The access for the file might be restricted"); + } + catch (NotSupportedException) + { + MessageBox.Show("NotSupportedException Occured: The file name might contain : in the middle of its string"); + } if (fileInfo == null || !fileInfo.Exists) { this._file.Focus(); diff --git a/src/Gardian.Utilities.ChecksumValidator/Properties/Resources.Designer.cs b/src/Gardian.Utilities.ChecksumValidator/Properties/Resources.Designer.cs index 1690113..6a5add4 100644 --- a/src/Gardian.Utilities.ChecksumValidator/Properties/Resources.Designer.cs +++ b/src/Gardian.Utilities.ChecksumValidator/Properties/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.3074 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -19,7 +19,7 @@ namespace Gardian.Utilities.ChecksumValidator.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -60,6 +60,9 @@ internal Resources() { } } + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// internal static System.Drawing.Icon App { get { object obj = ResourceManager.GetObject("App", resourceCulture); @@ -67,6 +70,9 @@ internal static System.Drawing.Icon App { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// internal static System.Drawing.Bitmap Open { get { object obj = ResourceManager.GetObject("Open", resourceCulture); @@ -74,6 +80,9 @@ internal static System.Drawing.Bitmap Open { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// internal static System.Drawing.Bitmap Paste { get { object obj = ResourceManager.GetObject("Paste", resourceCulture); @@ -81,6 +90,9 @@ internal static System.Drawing.Bitmap Paste { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// internal static System.Drawing.Bitmap Run { get { object obj = ResourceManager.GetObject("Run", resourceCulture); @@ -88,6 +100,9 @@ internal static System.Drawing.Bitmap Run { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// internal static System.Drawing.Bitmap Stop { get { object obj = ResourceManager.GetObject("Stop", resourceCulture); diff --git a/src/Gardian.Utilities.ChecksumValidator/app.config b/src/Gardian.Utilities.ChecksumValidator/app.config new file mode 100644 index 0000000..3e0e37c --- /dev/null +++ b/src/Gardian.Utilities.ChecksumValidator/app.config @@ -0,0 +1,3 @@ + + + diff --git a/src/UpgradeLog.htm b/src/UpgradeLog.htm new file mode 100644 index 0000000000000000000000000000000000000000..6e9e5e38a96477d9f1056446a34daae60fa0a79b GIT binary patch literal 53900 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 literal 0 HcmV?d00001