Adler32.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // Adler32.cs - Computes Adler32 data checksum of a data stream
  2. // Copyright (C) 2001 Mike Krueger
  3. //
  4. // This file was translated from java, it was part of the GNU Classpath
  5. // Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
  6. //
  7. // This program is free software; you can redistribute it and/or
  8. // modify it under the terms of the GNU General Public License
  9. // as published by the Free Software Foundation; either version 2
  10. // of the License, or (at your option) any later version.
  11. //
  12. // This program is distributed in the hope that it will be useful,
  13. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. // GNU General Public License for more details.
  16. //
  17. // You should have received a copy of the GNU General Public License
  18. // along with this program; if not, write to the Free Software
  19. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20. //
  21. // Linking this library statically or dynamically with other modules is
  22. // making a combined work based on this library. Thus, the terms and
  23. // conditions of the GNU General Public License cover the whole
  24. // combination.
  25. //
  26. // As a special exception, the copyright holders of this library give you
  27. // permission to link this library with independent modules to produce an
  28. // executable, regardless of the license terms of these independent
  29. // modules, and to copy and distribute the resulting executable under
  30. // terms of your choice, provided that you also meet, for each linked
  31. // independent module, the terms and conditions of the license of that
  32. // module. An independent module is a module which is not derived from
  33. // or based on this library. If you modify this library, you may extend
  34. // this exception to your version of the library, but you are not
  35. // obligated to do so. If you do not wish to do so, delete this
  36. // exception statement from your version.
  37. using System;
  38. namespace CommonMPQ.SharpZipLib.Checksums
  39. {
  40. /// <summary>
  41. /// Computes Adler32 checksum for a stream of data. An Adler32
  42. /// checksum is not as reliable as a CRC32 checksum, but a lot faster to
  43. /// compute.
  44. ///
  45. /// The specification for Adler32 may be found in RFC 1950.
  46. /// ZLIB Compressed Data Format Specification version 3.3)
  47. ///
  48. ///
  49. /// From that document:
  50. ///
  51. /// "ADLER32 (Adler-32 checksum)
  52. /// This contains a checksum value of the uncompressed data
  53. /// (excluding any dictionary data) computed according to Adler-32
  54. /// algorithm. This algorithm is a 32-bit extension and improvement
  55. /// of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073
  56. /// standard.
  57. ///
  58. /// Adler-32 is composed of two sums accumulated per byte: s1 is
  59. /// the sum of all bytes, s2 is the sum of all s1 values. Both sums
  60. /// are done modulo 65521. s1 is initialized to 1, s2 to zero. The
  61. /// Adler-32 checksum is stored as s2*65536 + s1 in most-
  62. /// significant-byte first (network) order."
  63. ///
  64. /// "8.2. The Adler-32 algorithm
  65. ///
  66. /// The Adler-32 algorithm is much faster than the CRC32 algorithm yet
  67. /// still provides an extremely low probability of undetected errors.
  68. ///
  69. /// The modulo on unsigned long accumulators can be delayed for 5552
  70. /// bytes, so the modulo operation time is negligible. If the bytes
  71. /// are a, b, c, the second sum is 3a + 2b + c + 3, and so is position
  72. /// and order sensitive, unlike the first sum, which is just a
  73. /// checksum. That 65521 is prime is important to avoid a possible
  74. /// large class of two-byte errors that leave the check unchanged.
  75. /// (The Fletcher checksum uses 255, which is not prime and which also
  76. /// makes the Fletcher check insensitive to single byte changes 0 -
  77. /// 255.)
  78. ///
  79. /// The sum s1 is initialized to 1 instead of zero to make the length
  80. /// of the sequence part of s2, so that the length does not have to be
  81. /// checked separately. (Any sequence of zeroes has a Fletcher
  82. /// checksum of zero.)"
  83. /// </summary>
  84. /// <see cref="CommonMPQ.SharpZipLib.Zip.Compression.Streams.InflaterInputStream"/>
  85. /// <see cref="CommonMPQ.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream"/>
  86. public sealed class Adler32 : IChecksum
  87. {
  88. /// <summary>
  89. /// largest prime smaller than 65536
  90. /// </summary>
  91. const uint BASE = 65521;
  92. /// <summary>
  93. /// Returns the Adler32 data checksum computed so far.
  94. /// </summary>
  95. public long Value {
  96. get {
  97. return checksum;
  98. }
  99. }
  100. /// <summary>
  101. /// Creates a new instance of the Adler32 class.
  102. /// The checksum starts off with a value of 1.
  103. /// </summary>
  104. public Adler32()
  105. {
  106. Reset();
  107. }
  108. /// <summary>
  109. /// Resets the Adler32 checksum to the initial value.
  110. /// </summary>
  111. public void Reset()
  112. {
  113. checksum = 1;
  114. }
  115. /// <summary>
  116. /// Updates the checksum with a byte value.
  117. /// </summary>
  118. /// <param name="value">
  119. /// The data value to add. The high byte of the int is ignored.
  120. /// </param>
  121. public void Update(int value)
  122. {
  123. // We could make a length 1 byte array and call update again, but I
  124. // would rather not have that overhead
  125. uint s1 = checksum & 0xFFFF;
  126. uint s2 = checksum >> 16;
  127. s1 = (s1 + ((uint)value & 0xFF)) % BASE;
  128. s2 = (s1 + s2) % BASE;
  129. checksum = (s2 << 16) + s1;
  130. }
  131. /// <summary>
  132. /// Updates the checksum with an array of bytes.
  133. /// </summary>
  134. /// <param name="buffer">
  135. /// The source of the data to update with.
  136. /// </param>
  137. public void Update(byte[] buffer)
  138. {
  139. if ( buffer == null ) {
  140. throw new ArgumentNullException("buffer");
  141. }
  142. Update(buffer, 0, buffer.Length);
  143. }
  144. /// <summary>
  145. /// Updates the checksum with the bytes taken from the array.
  146. /// </summary>
  147. /// <param name="buffer">
  148. /// an array of bytes
  149. /// </param>
  150. /// <param name="offset">
  151. /// the start of the data used for this update
  152. /// </param>
  153. /// <param name="count">
  154. /// the number of bytes to use for this update
  155. /// </param>
  156. public void Update(byte[] buffer, int offset, int count)
  157. {
  158. if (buffer == null) {
  159. throw new ArgumentNullException("buffer");
  160. }
  161. if (offset < 0) {
  162. #if NETCF_1_0
  163. throw new ArgumentOutOfRangeException("offset");
  164. #else
  165. throw new ArgumentOutOfRangeException("offset", "cannot be negative");
  166. #endif
  167. }
  168. if ( count < 0 )
  169. {
  170. #if NETCF_1_0
  171. throw new ArgumentOutOfRangeException("count");
  172. #else
  173. throw new ArgumentOutOfRangeException("count", "cannot be negative");
  174. #endif
  175. }
  176. if (offset >= buffer.Length)
  177. {
  178. #if NETCF_1_0
  179. throw new ArgumentOutOfRangeException("offset");
  180. #else
  181. throw new ArgumentOutOfRangeException("offset", "not a valid index into buffer");
  182. #endif
  183. }
  184. if (offset + count > buffer.Length)
  185. {
  186. #if NETCF_1_0
  187. throw new ArgumentOutOfRangeException("count");
  188. #else
  189. throw new ArgumentOutOfRangeException("count", "exceeds buffer size");
  190. #endif
  191. }
  192. //(By Per Bothner)
  193. uint s1 = checksum & 0xFFFF;
  194. uint s2 = checksum >> 16;
  195. while (count > 0) {
  196. // We can defer the modulo operation:
  197. // s1 maximally grows from 65521 to 65521 + 255 * 3800
  198. // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31
  199. int n = 3800;
  200. if (n > count) {
  201. n = count;
  202. }
  203. count -= n;
  204. while (--n >= 0) {
  205. s1 = s1 + (uint)(buffer[offset++] & 0xff);
  206. s2 = s2 + s1;
  207. }
  208. s1 %= BASE;
  209. s2 %= BASE;
  210. }
  211. checksum = (s2 << 16) | s1;
  212. }
  213. #region Instance Fields
  214. uint checksum;
  215. #endregion
  216. }
  217. }