PageRenderTime 30ms CodeModel.GetById 19ms app.highlight 7ms RepoModel.GetById 1ms app.codeStats 0ms

/Utilities/Compression/Checksums/Adler32.cs

#
C# | 221 lines | 103 code | 25 blank | 93 comment | 6 complexity | 053790727166bf2ad9dca8fbbb3bdaf8 MD5 | raw file
  1using System;
  2
  3namespace Delta.Utilities.Compression.Checksums
  4{
  5
  6	#region Summary
  7	/// <summary>
  8	/// Computes Adler32 checksum for a stream of data. An Adler32
  9	/// checksum is not as reliable as a CRC32 checksum, but a lot faster to
 10	/// compute.
 11	/// </summary>
 12	/// <remarks>
 13	/// The specification for Adler32 may be found in RFC 1950.
 14	/// ZLIB Compressed Data Format Specification version 3.3)
 15	/// 
 16	/// From that document:
 17	/// 
 18	///      "ADLER32 (Adler-32 checksum)
 19	///       This contains a checksum value of the uncompressed data
 20	///       (excluding any dictionary data) computed according to Adler-32
 21	///       algorithm. This algorithm is a 32-bit extension and improvement
 22	///       of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073
 23	///       standard.
 24	/// 
 25	///       Adler-32 is composed of two sums accumulated per byte: s1 is
 26	///       the sum of all bytes, s2 is the sum of all s1 values. Both sums
 27	///       are done modulo 65521. s1 is initialized to 1, s2 to zero.  The
 28	///       Adler-32 checksum is stored as s2*65536 + s1 in most-
 29	///       significant-byte first (network) order."
 30	/// 
 31	///  "8.2. The Adler-32 algorithm
 32	/// 
 33	///    The Adler-32 algorithm is much faster than the CRC32 algorithm yet
 34	///    still provides an extremely low probability of undetected errors.
 35	/// 
 36	///    The modulo on unsigned long accumulators can be delayed for 5552
 37	///    bytes, so the modulo operation time is negligible.  If the bytes
 38	///    are a, b, c, the second sum is 3a + 2b + c + 3, and so is position
 39	///    and order sensitive, unlike the first sum, which is just a
 40	///    checksum.  That 65521 is prime is important to avoid a possible
 41	///    large class of two-byte errors that leave the check unchanged.
 42	///    (The Fletcher checksum uses 255, which is not prime and which also
 43	///    makes the Fletcher check insensitive to single byte changes 0 -
 44	///    255.)
 45	/// 
 46	///    The sum s1 is initialized to 1 instead of zero to make the length
 47	///    of the sequence part of s2, so that the length does not have to be
 48	///    checked separately. (Any sequence of zeroes has a Fletcher
 49	///    checksum of zero.)"
 50	/// </remarks>
 51	/// <see cref="Delta.Utilities.Compression.Streams.InflaterInputStream"/>
 52	/// <see cref="Delta.Utilities.Compression.Streams.DeflaterOutputStream"/>
 53	#endregion
 54
 55	public sealed class Adler32
 56	{
 57		#region Constants
 58		/// <summary>
 59		/// largest prime smaller than 65536
 60		/// </summary>
 61		private const uint Base = 65521;
 62		#endregion
 63
 64		#region Value (Public)
 65		/// <summary>
 66		/// Returns the Adler32 data checksum computed so far.
 67		/// </summary>
 68		public long Value
 69		{
 70			get
 71			{
 72				return checksum;
 73			} // get
 74		}
 75		#endregion
 76
 77		#region Private
 78
 79		#region checksum (Private)
 80		/// <summary>
 81		/// Checksum
 82		/// </summary>
 83		private uint checksum;
 84		#endregion
 85
 86		#endregion
 87
 88		#region Constructors
 89		/// <summary>
 90		/// Creates a new instance of the <code>Adler32</code> class.
 91		/// The checksum starts off with a value of 1.
 92		/// </summary>
 93		public Adler32()
 94		{
 95			Reset();
 96		}
 97		#endregion
 98
 99		#region Reset (Public)
100		/// <summary>
101		/// Resets the Adler32 checksum to the initial value.
102		/// </summary>
103		public void Reset()
104		{
105			checksum = 1; //Initialize to 1
106		}
107		#endregion
108
109		#region Update (Public)
110		/// <summary>
111		/// Updates the checksum with the byte b.
112		/// </summary>
113		/// <param name="value">Data value to add.
114		/// The high byte of the int is ignored.</param>
115		public void Update(int value)
116		{
117			// We could make a length 1 byte array and call update again,
118			// but I would rather not have that overhead.
119			uint s1 = checksum & 0xFFFF;
120			uint s2 = checksum >> 16;
121
122			s1 = (s1 + ((uint)value & 0xFF)) % Base;
123			s2 = (s1 + s2) % Base;
124
125			checksum = (s2 << 16) + s1;
126		}
127
128		// Update(value)
129
130		/// <summary>
131		/// Updates the checksum with the bytes taken from the array.
132		/// </summary>
133		/// <param name="buffer">An array of bytes</param>
134		public void Update(byte[] buffer)
135		{
136			Update(buffer, 0, buffer.Length);
137		}
138
139		// Update(buffer)
140
141		/// <summary>
142		/// Updates the checksum with the bytes taken from the array.
143		/// </summary>
144		/// <param name="buffer">An array of bytes</param>
145		/// <param name="offset">Start of the data used for this update</param>
146		/// <param name="count">Number of bytes to use for this update</param>
147		public void Update(byte[] buffer, int offset, int count)
148		{
149			if (buffer == null)
150			{
151				throw new ArgumentNullException("buffer");
152			} // if (buf)
153
154			if (offset < 0 ||
155			    count < 0 ||
156			    offset + count > buffer.Length)
157			{
158				throw new ArgumentOutOfRangeException();
159			} // if (off)
160
161			//(By Per Bothner)
162			uint s1 = checksum & 0xFFFF;
163			uint s2 = checksum >> 16;
164
165			while (count > 0)
166			{
167				// We can defer the modulo operation:
168				// s1 maximally grows from 65521 to 65521 + 255 * 3800
169				// s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31
170				int n = 3800;
171				if (n > count)
172				{
173					n = count;
174				} // if (n)
175				count -= n;
176				while (--n >= 0)
177				{
178					s1 = s1 + (uint)(buffer[offset++] & 0xFF);
179					s2 = s2 + s1;
180				} // while (--n)
181				s1 %= Base;
182				s2 %= Base;
183			} // while (count)
184
185			checksum = (s2 << 16) | s1;
186		}
187		#endregion
188
189		/// <summary>
190		/// Adler 32 tests
191		/// </summary>
192		public class Adler32Tests
193		{
194			#region Helpers
195
196			#region TestAdler32
197			/// <summary>
198			/// Test adler 32
199			/// </summary>
200			public void TestAdler32()
201			{
202				Adler32 testAdler32 = new Adler32();
203
204				// Test clearing (sets value to 1 here)
205				testAdler32.Reset();
206				Assert.Equal(1, testAdler32.Value);
207
208				// Throw in a byte array
209				byte[] someData = new byte[]
210				{
211					59, 49, 193, 98, 4, 199, 254, 9, 42
212				};
213				testAdler32.Update(someData);
214				Assert.Equal(295502732, testAdler32.Value);
215			}
216			#endregion
217
218			#endregion
219		}
220	}
221}