| | 1 | | using System; |
| | 2 | |
|
| | 3 | | namespace ICSharpCode.SharpZipLib.Checksum |
| | 4 | | { |
| | 5 | | /// <summary> |
| | 6 | | /// CRC-32 with unreversed data and reversed output |
| | 7 | | /// </summary> |
| | 8 | | /// <remarks> |
| | 9 | | /// Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: |
| | 10 | | /// x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0. |
| | 11 | | /// |
| | 12 | | /// Polynomials over GF(2) are represented in binary, one bit per coefficient, |
| | 13 | | /// with the lowest powers in the most significant bit. Then adding polynomials |
| | 14 | | /// is just exclusive-or, and multiplying a polynomial by x is a right shift by |
| | 15 | | /// one. If we call the above polynomial p, and represent a byte as the |
| | 16 | | /// polynomial q, also with the lowest power in the most significant bit (so the |
| | 17 | | /// byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, |
| | 18 | | /// where a mod b means the remainder after dividing a by b. |
| | 19 | | /// |
| | 20 | | /// This calculation is done using the shift-register method of multiplying and |
| | 21 | | /// taking the remainder. The register is initialized to zero, and for each |
| | 22 | | /// incoming bit, x^32 is added mod p to the register if the bit is a one (where |
| | 23 | | /// x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by |
| | 24 | | /// x (which is shifting right by one and adding x^32 mod p if the bit shifted |
| | 25 | | /// out is a one). We start with the highest power (least significant bit) of |
| | 26 | | /// q and repeat for all eight bits of q. |
| | 27 | | /// |
| | 28 | | /// The table is simply the CRC of all possible eight bit values. This is all |
| | 29 | | /// the information needed to generate CRC's on data a byte at a time for all |
| | 30 | | /// combinations of CRC register values and incoming bytes. |
| | 31 | | /// </remarks> |
| | 32 | | public sealed class BZip2Crc : IChecksum |
| | 33 | | { |
| | 34 | | #region Instance Fields |
| 1 | 35 | | readonly static uint crcInit = 0xFFFFFFFF; |
| 1 | 36 | | readonly static uint crcXor = 0x00000000; |
| | 37 | |
|
| 1 | 38 | | readonly static uint[] crcTable = { |
| 1 | 39 | | 0X00000000, 0X04C11DB7, 0X09823B6E, 0X0D4326D9, |
| 1 | 40 | | 0X130476DC, 0X17C56B6B, 0X1A864DB2, 0X1E475005, |
| 1 | 41 | | 0X2608EDB8, 0X22C9F00F, 0X2F8AD6D6, 0X2B4BCB61, |
| 1 | 42 | | 0X350C9B64, 0X31CD86D3, 0X3C8EA00A, 0X384FBDBD, |
| 1 | 43 | | 0X4C11DB70, 0X48D0C6C7, 0X4593E01E, 0X4152FDA9, |
| 1 | 44 | | 0X5F15ADAC, 0X5BD4B01B, 0X569796C2, 0X52568B75, |
| 1 | 45 | | 0X6A1936C8, 0X6ED82B7F, 0X639B0DA6, 0X675A1011, |
| 1 | 46 | | 0X791D4014, 0X7DDC5DA3, 0X709F7B7A, 0X745E66CD, |
| 1 | 47 | | 0X9823B6E0, 0X9CE2AB57, 0X91A18D8E, 0X95609039, |
| 1 | 48 | | 0X8B27C03C, 0X8FE6DD8B, 0X82A5FB52, 0X8664E6E5, |
| 1 | 49 | | 0XBE2B5B58, 0XBAEA46EF, 0XB7A96036, 0XB3687D81, |
| 1 | 50 | | 0XAD2F2D84, 0XA9EE3033, 0XA4AD16EA, 0XA06C0B5D, |
| 1 | 51 | | 0XD4326D90, 0XD0F37027, 0XDDB056FE, 0XD9714B49, |
| 1 | 52 | | 0XC7361B4C, 0XC3F706FB, 0XCEB42022, 0XCA753D95, |
| 1 | 53 | | 0XF23A8028, 0XF6FB9D9F, 0XFBB8BB46, 0XFF79A6F1, |
| 1 | 54 | | 0XE13EF6F4, 0XE5FFEB43, 0XE8BCCD9A, 0XEC7DD02D, |
| 1 | 55 | | 0X34867077, 0X30476DC0, 0X3D044B19, 0X39C556AE, |
| 1 | 56 | | 0X278206AB, 0X23431B1C, 0X2E003DC5, 0X2AC12072, |
| 1 | 57 | | 0X128E9DCF, 0X164F8078, 0X1B0CA6A1, 0X1FCDBB16, |
| 1 | 58 | | 0X018AEB13, 0X054BF6A4, 0X0808D07D, 0X0CC9CDCA, |
| 1 | 59 | | 0X7897AB07, 0X7C56B6B0, 0X71159069, 0X75D48DDE, |
| 1 | 60 | | 0X6B93DDDB, 0X6F52C06C, 0X6211E6B5, 0X66D0FB02, |
| 1 | 61 | | 0X5E9F46BF, 0X5A5E5B08, 0X571D7DD1, 0X53DC6066, |
| 1 | 62 | | 0X4D9B3063, 0X495A2DD4, 0X44190B0D, 0X40D816BA, |
| 1 | 63 | | 0XACA5C697, 0XA864DB20, 0XA527FDF9, 0XA1E6E04E, |
| 1 | 64 | | 0XBFA1B04B, 0XBB60ADFC, 0XB6238B25, 0XB2E29692, |
| 1 | 65 | | 0X8AAD2B2F, 0X8E6C3698, 0X832F1041, 0X87EE0DF6, |
| 1 | 66 | | 0X99A95DF3, 0X9D684044, 0X902B669D, 0X94EA7B2A, |
| 1 | 67 | | 0XE0B41DE7, 0XE4750050, 0XE9362689, 0XEDF73B3E, |
| 1 | 68 | | 0XF3B06B3B, 0XF771768C, 0XFA325055, 0XFEF34DE2, |
| 1 | 69 | | 0XC6BCF05F, 0XC27DEDE8, 0XCF3ECB31, 0XCBFFD686, |
| 1 | 70 | | 0XD5B88683, 0XD1799B34, 0XDC3ABDED, 0XD8FBA05A, |
| 1 | 71 | | 0X690CE0EE, 0X6DCDFD59, 0X608EDB80, 0X644FC637, |
| 1 | 72 | | 0X7A089632, 0X7EC98B85, 0X738AAD5C, 0X774BB0EB, |
| 1 | 73 | | 0X4F040D56, 0X4BC510E1, 0X46863638, 0X42472B8F, |
| 1 | 74 | | 0X5C007B8A, 0X58C1663D, 0X558240E4, 0X51435D53, |
| 1 | 75 | | 0X251D3B9E, 0X21DC2629, 0X2C9F00F0, 0X285E1D47, |
| 1 | 76 | | 0X36194D42, 0X32D850F5, 0X3F9B762C, 0X3B5A6B9B, |
| 1 | 77 | | 0X0315D626, 0X07D4CB91, 0X0A97ED48, 0X0E56F0FF, |
| 1 | 78 | | 0X1011A0FA, 0X14D0BD4D, 0X19939B94, 0X1D528623, |
| 1 | 79 | | 0XF12F560E, 0XF5EE4BB9, 0XF8AD6D60, 0XFC6C70D7, |
| 1 | 80 | | 0XE22B20D2, 0XE6EA3D65, 0XEBA91BBC, 0XEF68060B, |
| 1 | 81 | | 0XD727BBB6, 0XD3E6A601, 0XDEA580D8, 0XDA649D6F, |
| 1 | 82 | | 0XC423CD6A, 0XC0E2D0DD, 0XCDA1F604, 0XC960EBB3, |
| 1 | 83 | | 0XBD3E8D7E, 0XB9FF90C9, 0XB4BCB610, 0XB07DABA7, |
| 1 | 84 | | 0XAE3AFBA2, 0XAAFBE615, 0XA7B8C0CC, 0XA379DD7B, |
| 1 | 85 | | 0X9B3660C6, 0X9FF77D71, 0X92B45BA8, 0X9675461F, |
| 1 | 86 | | 0X8832161A, 0X8CF30BAD, 0X81B02D74, 0X857130C3, |
| 1 | 87 | | 0X5D8A9099, 0X594B8D2E, 0X5408ABF7, 0X50C9B640, |
| 1 | 88 | | 0X4E8EE645, 0X4A4FFBF2, 0X470CDD2B, 0X43CDC09C, |
| 1 | 89 | | 0X7B827D21, 0X7F436096, 0X7200464F, 0X76C15BF8, |
| 1 | 90 | | 0X68860BFD, 0X6C47164A, 0X61043093, 0X65C52D24, |
| 1 | 91 | | 0X119B4BE9, 0X155A565E, 0X18197087, 0X1CD86D30, |
| 1 | 92 | | 0X029F3D35, 0X065E2082, 0X0B1D065B, 0X0FDC1BEC, |
| 1 | 93 | | 0X3793A651, 0X3352BBE6, 0X3E119D3F, 0X3AD08088, |
| 1 | 94 | | 0X2497D08D, 0X2056CD3A, 0X2D15EBE3, 0X29D4F654, |
| 1 | 95 | | 0XC5A92679, 0XC1683BCE, 0XCC2B1D17, 0XC8EA00A0, |
| 1 | 96 | | 0XD6AD50A5, 0XD26C4D12, 0XDF2F6BCB, 0XDBEE767C, |
| 1 | 97 | | 0XE3A1CBC1, 0XE760D676, 0XEA23F0AF, 0XEEE2ED18, |
| 1 | 98 | | 0XF0A5BD1D, 0XF464A0AA, 0XF9278673, 0XFDE69BC4, |
| 1 | 99 | | 0X89B8FD09, 0X8D79E0BE, 0X803AC667, 0X84FBDBD0, |
| 1 | 100 | | 0X9ABC8BD5, 0X9E7D9662, 0X933EB0BB, 0X97FFAD0C, |
| 1 | 101 | | 0XAFB010B1, 0XAB710D06, 0XA6322BDF, 0XA2F33668, |
| 1 | 102 | | 0XBCB4666D, 0XB8757BDA, 0XB5365D03, 0XB1F740B4 |
| 1 | 103 | | }; |
| | 104 | |
|
| | 105 | | /// <summary> |
| | 106 | | /// The CRC data checksum so far. |
| | 107 | | /// </summary> |
| | 108 | | uint checkValue; |
| | 109 | | #endregion |
| | 110 | |
|
| | 111 | | /// <summary> |
| | 112 | | /// Initialise a default instance of <see cref="BZip2Crc"></see> |
| | 113 | | /// </summary> |
| 3 | 114 | | public BZip2Crc() |
| | 115 | | { |
| 3 | 116 | | Reset(); |
| 3 | 117 | | } |
| | 118 | |
|
| | 119 | | /// <summary> |
| | 120 | | /// Resets the CRC data checksum as if no update was ever called. |
| | 121 | | /// </summary> |
| | 122 | | public void Reset() |
| | 123 | | { |
| 5 | 124 | | checkValue = crcInit; |
| 5 | 125 | | } |
| | 126 | |
|
| | 127 | | /// <summary> |
| | 128 | | /// Returns the CRC data checksum computed so far. |
| | 129 | | /// </summary> |
| | 130 | | /// <remarks>Reversed Out = true</remarks> |
| | 131 | | public long Value { |
| | 132 | | get { |
| | 133 | | // Tehcnically, the output should be: |
| | 134 | | //return (long)(~checkValue ^ crcXor); |
| | 135 | | // but x ^ 0 = x, so there is no point in adding |
| | 136 | | // the XOR operation |
| 3 | 137 | | return (long)(~checkValue); |
| | 138 | | } |
| | 139 | | } |
| | 140 | |
|
| | 141 | | /// <summary> |
| | 142 | | /// Updates the checksum with the int bval. |
| | 143 | | /// </summary> |
| | 144 | | /// <param name = "bval"> |
| | 145 | | /// the byte is taken as the lower 8 bits of bval |
| | 146 | | /// </param> |
| | 147 | | /// <remarks>Reversed Data = false</remarks> |
| | 148 | | public void Update(int bval) |
| | 149 | | { |
| 10 | 150 | | checkValue = unchecked(crcTable[(byte)(((checkValue >> 24) & 0xFF) ^ bval)] ^ (checkValue << 8)); |
| 10 | 151 | | } |
| | 152 | |
|
| | 153 | | /// <summary> |
| | 154 | | /// Updates the CRC data checksum with the bytes taken from |
| | 155 | | /// a block of data. |
| | 156 | | /// </summary> |
| | 157 | | /// <param name="buffer">Contains the data to update the CRC with.</param> |
| | 158 | | public void Update(byte[] buffer) |
| | 159 | | { |
| 2 | 160 | | if (buffer == null) { |
| 1 | 161 | | throw new ArgumentNullException(nameof(buffer)); |
| | 162 | | } |
| | 163 | |
|
| 1 | 164 | | Update(buffer, 0, buffer.Length); |
| 1 | 165 | | } |
| | 166 | |
|
| | 167 | | /// <summary> |
| | 168 | | /// Update CRC data checksum based on a portion of a block of data |
| | 169 | | /// </summary> |
| | 170 | | /// <param name = "buffer">Contains the data to update the CRC with.</param> |
| | 171 | | /// <param name = "offset">The offset into the buffer where the data starts</param> |
| | 172 | | /// <param name = "count">The number of data bytes to update the CRC with.</param> |
| | 173 | | public void Update(byte[] buffer, int offset, int count) |
| | 174 | | { |
| 6 | 175 | | if (buffer == null) { |
| 1 | 176 | | throw new ArgumentNullException(nameof(buffer)); |
| | 177 | | } |
| | 178 | |
|
| 5 | 179 | | if (offset < 0) { |
| 1 | 180 | | throw new ArgumentOutOfRangeException(nameof(offset), "cannot be less than zero"); |
| | 181 | | } |
| | 182 | |
|
| 4 | 183 | | if (offset >= buffer.Length) { |
| 1 | 184 | | throw new ArgumentOutOfRangeException(nameof(offset), "not a valid index into buffer"); |
| | 185 | | } |
| | 186 | |
|
| 3 | 187 | | if (count < 0) { |
| 1 | 188 | | throw new ArgumentOutOfRangeException(nameof(count), "cannot be less than zero"); |
| | 189 | | } |
| | 190 | |
|
| 2 | 191 | | if (offset + count > buffer.Length) { |
| 1 | 192 | | throw new ArgumentOutOfRangeException(nameof(count), "exceeds buffer size"); |
| | 193 | | } |
| | 194 | |
|
| 20 | 195 | | for (int i = 0; i < count; ++i) { |
| 9 | 196 | | Update(buffer[offset++]); |
| | 197 | | } |
| 1 | 198 | | } |
| | 199 | | } |
| | 200 | | } |