/Utilities/Compression/Checksums/Adler32.cs
C# | 221 lines | 103 code | 25 blank | 93 comment | 6 complexity | 053790727166bf2ad9dca8fbbb3bdaf8 MD5 | raw file
Possible License(s): Apache-2.0
- using System;
-
- namespace Delta.Utilities.Compression.Checksums
- {
-
- #region Summary
- /// <summary>
- /// Computes Adler32 checksum for a stream of data. An Adler32
- /// checksum is not as reliable as a CRC32 checksum, but a lot faster to
- /// compute.
- /// </summary>
- /// <remarks>
- /// The specification for Adler32 may be found in RFC 1950.
- /// ZLIB Compressed Data Format Specification version 3.3)
- ///
- /// From that document:
- ///
- /// "ADLER32 (Adler-32 checksum)
- /// This contains a checksum value of the uncompressed data
- /// (excluding any dictionary data) computed according to Adler-32
- /// algorithm. This algorithm is a 32-bit extension and improvement
- /// of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073
- /// standard.
- ///
- /// Adler-32 is composed of two sums accumulated per byte: s1 is
- /// the sum of all bytes, s2 is the sum of all s1 values. Both sums
- /// are done modulo 65521. s1 is initialized to 1, s2 to zero. The
- /// Adler-32 checksum is stored as s2*65536 + s1 in most-
- /// significant-byte first (network) order."
- ///
- /// "8.2. The Adler-32 algorithm
- ///
- /// The Adler-32 algorithm is much faster than the CRC32 algorithm yet
- /// still provides an extremely low probability of undetected errors.
- ///
- /// The modulo on unsigned long accumulators can be delayed for 5552
- /// bytes, so the modulo operation time is negligible. If the bytes
- /// are a, b, c, the second sum is 3a + 2b + c + 3, and so is position
- /// and order sensitive, unlike the first sum, which is just a
- /// checksum. That 65521 is prime is important to avoid a possible
- /// large class of two-byte errors that leave the check unchanged.
- /// (The Fletcher checksum uses 255, which is not prime and which also
- /// makes the Fletcher check insensitive to single byte changes 0 -
- /// 255.)
- ///
- /// The sum s1 is initialized to 1 instead of zero to make the length
- /// of the sequence part of s2, so that the length does not have to be
- /// checked separately. (Any sequence of zeroes has a Fletcher
- /// checksum of zero.)"
- /// </remarks>
- /// <see cref="Delta.Utilities.Compression.Streams.InflaterInputStream"/>
- /// <see cref="Delta.Utilities.Compression.Streams.DeflaterOutputStream"/>
- #endregion
-
- public sealed class Adler32
- {
- #region Constants
- /// <summary>
- /// largest prime smaller than 65536
- /// </summary>
- private const uint Base = 65521;
- #endregion
-
- #region Value (Public)
- /// <summary>
- /// Returns the Adler32 data checksum computed so far.
- /// </summary>
- public long Value
- {
- get
- {
- return checksum;
- } // get
- }
- #endregion
-
- #region Private
-
- #region checksum (Private)
- /// <summary>
- /// Checksum
- /// </summary>
- private uint checksum;
- #endregion
-
- #endregion
-
- #region Constructors
- /// <summary>
- /// Creates a new instance of the <code>Adler32</code> class.
- /// The checksum starts off with a value of 1.
- /// </summary>
- public Adler32()
- {
- Reset();
- }
- #endregion
-
- #region Reset (Public)
- /// <summary>
- /// Resets the Adler32 checksum to the initial value.
- /// </summary>
- public void Reset()
- {
- checksum = 1; //Initialize to 1
- }
- #endregion
-
- #region Update (Public)
- /// <summary>
- /// Updates the checksum with the byte b.
- /// </summary>
- /// <param name="value">Data value to add.
- /// The high byte of the int is ignored.</param>
- public void Update(int value)
- {
- // We could make a length 1 byte array and call update again,
- // but I would rather not have that overhead.
- uint s1 = checksum & 0xFFFF;
- uint s2 = checksum >> 16;
-
- s1 = (s1 + ((uint)value & 0xFF)) % Base;
- s2 = (s1 + s2) % Base;
-
- checksum = (s2 << 16) + s1;
- }
-
- // Update(value)
-
- /// <summary>
- /// Updates the checksum with the bytes taken from the array.
- /// </summary>
- /// <param name="buffer">An array of bytes</param>
- public void Update(byte[] buffer)
- {
- Update(buffer, 0, buffer.Length);
- }
-
- // Update(buffer)
-
- /// <summary>
- /// Updates the checksum with the bytes taken from the array.
- /// </summary>
- /// <param name="buffer">An array of bytes</param>
- /// <param name="offset">Start of the data used for this update</param>
- /// <param name="count">Number of bytes to use for this update</param>
- public void Update(byte[] buffer, int offset, int count)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException("buffer");
- } // if (buf)
-
- if (offset < 0 ||
- count < 0 ||
- offset + count > buffer.Length)
- {
- throw new ArgumentOutOfRangeException();
- } // if (off)
-
- //(By Per Bothner)
- uint s1 = checksum & 0xFFFF;
- uint s2 = checksum >> 16;
-
- while (count > 0)
- {
- // We can defer the modulo operation:
- // s1 maximally grows from 65521 to 65521 + 255 * 3800
- // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31
- int n = 3800;
- if (n > count)
- {
- n = count;
- } // if (n)
- count -= n;
- while (--n >= 0)
- {
- s1 = s1 + (uint)(buffer[offset++] & 0xFF);
- s2 = s2 + s1;
- } // while (--n)
- s1 %= Base;
- s2 %= Base;
- } // while (count)
-
- checksum = (s2 << 16) | s1;
- }
- #endregion
-
- /// <summary>
- /// Adler 32 tests
- /// </summary>
- public class Adler32Tests
- {
- #region Helpers
-
- #region TestAdler32
- /// <summary>
- /// Test adler 32
- /// </summary>
- public void TestAdler32()
- {
- Adler32 testAdler32 = new Adler32();
-
- // Test clearing (sets value to 1 here)
- testAdler32.Reset();
- Assert.Equal(1, testAdler32.Value);
-
- // Throw in a byte array
- byte[] someData = new byte[]
- {
- 59, 49, 193, 98, 4, 199, 254, 9, 42
- };
- testAdler32.Update(someData);
- Assert.Equal(295502732, testAdler32.Value);
- }
- #endregion
-
- #endregion
- }
- }
- }