diff --git a/DiscImageChef/ChangeLog b/DiscImageChef/ChangeLog index 8ee91b572..08f7372b7 100644 --- a/DiscImageChef/ChangeLog +++ b/DiscImageChef/ChangeLog @@ -1,3 +1,11 @@ +2015-04-19 Natalia Portillo + + * Options.cs: + * Commands/Checksum.cs: + * DiscImageChef.csproj: + * Checksums/Adler32Context.cs: + Added Adler-32 checksum + 2015-03-22 Natalia Portillo * Plugins/ProDOS.cs: diff --git a/DiscImageChef/Checksums/Adler32Context.cs b/DiscImageChef/Checksums/Adler32Context.cs new file mode 100644 index 000000000..b12323457 --- /dev/null +++ b/DiscImageChef/Checksums/Adler32Context.cs @@ -0,0 +1,193 @@ +/*************************************************************************** +The Disc Image Chef +---------------------------------------------------------------------------- + +Filename : Adler32Context.cs +Version : 1.0 +Author(s) : Natalia Portillo + +Component : Checksums. + +Revision : $Revision$ +Last change by : $Author$ +Date : $Date$ + +--[ Description ] ---------------------------------------------------------- + +Implements an Adler-32 algorithm. + +--[ License ] -------------------------------------------------------------- + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +---------------------------------------------------------------------------- +Copyright (C) 2011-2015 Claunia.com +****************************************************************************/ +//$Id$ +using System; +using System.Text; +using System.IO; + +namespace DiscImageChef.Checksums +{ + public class Adler32Context + { + UInt16 sum1, sum2; + const UInt16 AdlerModule = 65521; + + /// + /// Initializes the Adler-32 sums + /// + public void Init() + { + sum1 = 1; + sum2 = 0; + } + + /// + /// Updates the hash with data. + /// + /// Data buffer. + /// Length of buffer to hash. + public void Update(byte[] data, uint len) + { + for (int i = 0; i < len; i++) + { + sum1 = (ushort)((sum1 + data[i]) % AdlerModule); + sum2 = (ushort)((sum2 + sum1) % AdlerModule); + } + } + + /// + /// Updates the hash with data. + /// + /// Data buffer. + public void Update(byte[] data) + { + Update(data, (uint)data.Length); + } + + /// + /// Returns a byte array of the hash value. + /// + public byte[] Final() + { + UInt32 finalSum = (uint)((sum2 << 16) | sum1); + return BigEndianBitConverter.GetBytes(finalSum); + } + + /// + /// Returns a hexadecimal representation of the hash value. + /// + public string End() + { + UInt32 finalSum = (uint)((sum2 << 16) | sum1); + StringBuilder adlerOutput = new StringBuilder(); + + for (int i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++) + { + adlerOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2")); + } + + return adlerOutput.ToString(); + } + + /// + /// Gets the hash of a file + /// + /// File path. + public static byte[] File(string filename) + { + byte[] hash; + File(filename, out hash); + return hash; + } + + /// + /// Gets the hash of a file in hexadecimal and as a byte array. + /// + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash) + { + FileStream fileStream = new FileStream(filename, FileMode.Open); + UInt16 localSum1, localSum2; + UInt32 finalSum; + + localSum1 = 1; + localSum2 = 0; + + localSum1 = (ushort)((localSum1 + fileStream.ReadByte()) % AdlerModule); + localSum2 = (ushort)((localSum2 + localSum1) % AdlerModule); + + finalSum = (uint)((localSum2 << 16) | localSum1); + + hash = BitConverter.GetBytes(finalSum); + + StringBuilder adlerOutput = new StringBuilder(); + + for (int i = 0; i < hash.Length; i++) + { + adlerOutput.Append(hash[i].ToString("x2")); + } + + return adlerOutput.ToString(); + } + + /// + /// Gets the hash of the specified data buffer. + /// + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + public static string Data(byte[] data, uint len, out byte[] hash) + { + UInt16 localSum1, localSum2; + UInt32 finalSum; + + localSum1 = 1; + localSum2 = 0; + + for (int i = 0; i < len; i++) + { + localSum1 = (ushort)((localSum1 + data[i]) % AdlerModule); + localSum2 = (ushort)((localSum2 + localSum1) % AdlerModule); + } + + finalSum = (uint)((localSum2 << 16) | localSum1); + + hash = BitConverter.GetBytes(finalSum); + + StringBuilder adlerOutput = new StringBuilder(); + + for (int i = 0; i < hash.Length; i++) + { + adlerOutput.Append(hash[i].ToString("x2")); + } + + return adlerOutput.ToString(); + } + + /// + /// Gets the hash of the specified data buffer. + /// + /// Data buffer. + /// Byte array of the hash value. + public static string Data(byte[] data, out byte[] hash) + { + return Data(data, (uint)data.Length, out hash); + } + } +} + diff --git a/DiscImageChef/Commands/Checksum.cs b/DiscImageChef/Commands/Checksum.cs index 7eec40f4a..24f7d5f8f 100644 --- a/DiscImageChef/Commands/Checksum.cs +++ b/DiscImageChef/Commands/Checksum.cs @@ -53,6 +53,7 @@ namespace DiscImageChef.Commands Console.WriteLine("--separated-tracks={0}", options.SeparatedTracks); Console.WriteLine("--whole-disc={0}", options.WholeDisc); Console.WriteLine("--input={0}", options.InputFile); + Console.WriteLine("--adler32={0}", options.DoAdler32); Console.WriteLine("--crc32={0}", options.DoCRC32); Console.WriteLine("--crc64={0}", options.DoCRC64); Console.WriteLine("--md5={0}", options.DoMD5); @@ -81,6 +82,7 @@ namespace DiscImageChef.Commands List inputTracks = inputFormat.GetTracks(); foreach (Track currentTrack in inputTracks) { + Adler32Context adler32ctxTrack = new Adler32Context(); CRC32Context crc32ctxTrack = new CRC32Context(); CRC64Context crc64ctxTrack = new CRC64Context(); MD5Context md5ctxTrack = new MD5Context(); @@ -90,6 +92,8 @@ namespace DiscImageChef.Commands SHA384Context sha384ctxTrack = new SHA384Context(); SHA512Context sha512ctxTrack = new SHA512Context(); + if (options.DoAdler32) + adler32ctxTrack.Init(); if (options.DoCRC32) crc32ctxTrack.Init(); if (options.DoCRC64) @@ -114,6 +118,8 @@ namespace DiscImageChef.Commands { Console.Write("\rHashing sector {0} of track {1}", i + 1, currentTrack.TrackSequence); byte[] sector = inputFormat.ReadSector(i, currentTrack.TrackSequence); + if (options.DoAdler32) + adler32ctxTrack.Update(sector); if (options.DoCRC32) crc32ctxTrack.Update(sector); if (options.DoCRC64) @@ -134,6 +140,8 @@ namespace DiscImageChef.Commands Console.WriteLine(); + if (options.DoAdler32) + Console.WriteLine("Track {0}'s Adler-32: 0x{1}", currentTrack.TrackSequence, adler32ctxTrack.End()); if (options.DoCRC32) Console.WriteLine("Track {0}'s CRC32: 0x{1}", currentTrack.TrackSequence, crc32ctxTrack.End()); if (options.DoCRC64) @@ -164,6 +172,7 @@ namespace DiscImageChef.Commands if (options.WholeDisc) { + Adler32Context adler32ctx = new Adler32Context(); CRC32Context crc32ctx = new CRC32Context(); CRC64Context crc64ctx = new CRC64Context(); MD5Context md5ctx = new MD5Context(); @@ -173,6 +182,8 @@ namespace DiscImageChef.Commands SHA384Context sha384ctx = new SHA384Context(); SHA512Context sha512ctx = new SHA512Context(); + if (options.DoAdler32) + adler32ctx.Init(); if (options.DoCRC32) crc32ctx.Init(); if (options.DoCRC64) @@ -197,6 +208,8 @@ namespace DiscImageChef.Commands { Console.Write("\rHashing sector {0}", i + 1); byte[] sector = inputFormat.ReadSector(i); + if (options.DoAdler32) + adler32ctx.Update(sector); if (options.DoCRC32) crc32ctx.Update(sector); if (options.DoCRC64) @@ -217,6 +230,8 @@ namespace DiscImageChef.Commands Console.WriteLine(); + if (options.DoAdler32) + Console.WriteLine("Disk's Adler-32: 0x{0}", adler32ctx.End()); if (options.DoCRC32) Console.WriteLine("Disk's CRC32: 0x{0}", crc32ctx.End()); if (options.DoCRC64) diff --git a/DiscImageChef/DiscImageChef.csproj b/DiscImageChef/DiscImageChef.csproj index 68f7dd6f8..7a7338e29 100644 --- a/DiscImageChef/DiscImageChef.csproj +++ b/DiscImageChef/DiscImageChef.csproj @@ -106,6 +106,7 @@ + diff --git a/DiscImageChef/Options.cs b/DiscImageChef/Options.cs index ddd0467aa..2e43d5391 100644 --- a/DiscImageChef/Options.cs +++ b/DiscImageChef/Options.cs @@ -82,6 +82,10 @@ namespace DiscImageChef HelpText = "Checksums the whole disc.")] public bool WholeDisc { get; set; } + [Option('a', "adler32", DefaultValue = true, + HelpText = "Calculates Adler-32.")] + public bool DoAdler32 { get; set; } + [Option('c', "crc32", DefaultValue = true, HelpText = "Calculates CRC32.")] public bool DoCRC32 { get; set; } diff --git a/README.md b/README.md index d29117fbc..79e66a79c 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ Supported file systems Supported checksums =================== +* Adler-32 * CRC-16 * CRC-32 * CRC-64