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