// // Copyright (c) 2006-2009 Microsoft Corporation. All rights reserved. // // // Implements the CRC algorithm, which is used in zip files. The zip format calls for // the zipfile to contain a CRC for the unencrypted byte stream of each file. // // It is based on example source code published at // http://www.vbaccelerator.com/home/net/code/libraries/CRC32/Crc32_zip_CRC32_CRC32_cs.asp // // This implementation adds a tweak of that code for use within zip creation. While // computing the CRC we also compress the byte stream, in the same read loop. This // avoids the need to read through the uncompressed stream twice - once to compute CRC // and another time to compress. // // Thu, 30 Mar 2006 13:58 // using System; namespace ThirdParty.Ionic.Zlib { /// /// Calculates a 32bit Cyclic Redundancy Checksum (CRC) using the /// same polynomial used by Zip. This type is used internally by DotNetZip; it is generally not used directly /// by applications wishing to create, read, or manipulate zip archive files. /// internal class CRC32 { /// /// indicates the total number of bytes read on the CRC stream. /// This is used when writing the ZipDirEntry when compressing files. /// public Int64 TotalBytesRead { get { return _TotalBytesRead; } } /// /// Indicates the current CRC for all blocks slurped in. /// public Int32 Crc32Result { get { // return one's complement of the running result return unchecked((Int32)(~_RunningCrc32Result)); } } /// /// Returns the CRC32 for the specified stream. /// /// The stream over which to calculate the CRC32 /// the CRC32 calculation public Int32 GetCrc32(System.IO.Stream input) { return GetCrc32AndCopy(input, null); } /// /// Returns the CRC32 for the specified stream, and writes the input into the output stream. /// /// The stream over which to calculate the CRC32 /// The stream into which to deflate the input /// the CRC32 calculation public Int32 GetCrc32AndCopy(System.IO.Stream input, System.IO.Stream output) { unchecked { //UInt32 crc32Result; //crc32Result = 0xFFFFFFFF; byte[] buffer = new byte[BUFFER_SIZE]; int readSize = BUFFER_SIZE; _TotalBytesRead = 0; int count = input.Read(buffer, 0, readSize); if (output != null) output.Write(buffer, 0, count); _TotalBytesRead += count; while (count > 0) { //for (int i = 0; i < count; i++) //{ // _RunningCrc32Result = ((_RunningCrc32Result) >> 8) ^ crc32Table[(buffer[i]) ^ ((_RunningCrc32Result) & 0x000000FF)]; //} SlurpBlock(buffer, 0, count); count = input.Read(buffer, 0, readSize); if (output != null) output.Write(buffer, 0, count); _TotalBytesRead += count; } return (Int32)(~_RunningCrc32Result); } } /// /// Get the CRC32 for the given (word,byte) combo. /// This is a computation defined by PKzip. /// /// The word to start with. /// The byte to combine it with. /// The CRC-ized result. public Int32 ComputeCrc32(Int32 W, byte B) { return _InternalComputeCrc32((UInt32)W, B); } internal Int32 _InternalComputeCrc32(UInt32 W, byte B) { return (Int32)(crc32Table[(W ^ B) & 0xFF] ^ (W >> 8)); } /// /// Update the value for the running CRC32 using the given block of bytes. /// This is useful when using the CRC32() class in a Stream. /// /// block of bytes to slurp /// starting point in the block /// how many bytes within the block to slurp public void SlurpBlock(byte[] block, int offset, int count) { for (int i = 0; i < count; i++) { int x = offset + i; _RunningCrc32Result = ((_RunningCrc32Result) >> 8) ^ crc32Table[(block[x]) ^ ((_RunningCrc32Result) & 0x000000FF)]; } _TotalBytesRead += count; } // pre-initialize the crc table for speed of lookup. static CRC32() { unchecked { // This is the official polynomial used by CRC32 in PKZip. // Often the polynomial is shown reversed as 0x04C11DB7. UInt32 dwPolynomial = 0xEDB88320; UInt32 i, j; crc32Table = new UInt32[256]; UInt32 dwCrc; for (i = 0; i < 256; i++) { dwCrc = i; for (j = 8; j > 0; j--) { if ((dwCrc & 1) == 1) { dwCrc = (dwCrc >> 1) ^ dwPolynomial; } else { dwCrc >>= 1; } } crc32Table[i] = dwCrc; } } } // private member vars private Int64 _TotalBytesRead; private static UInt32[] crc32Table; private const int BUFFER_SIZE = 8192; private UInt32 _RunningCrc32Result = 0xFFFFFFFF; } /// /// A Stream that calculates a CRC32 (a checksum) on all bytes read, /// or on all bytes written. /// /// /// /// /// This class can be used to verify the CRC of a ZipEntry when reading from a stream, /// or to calculate a CRC when writing to a stream. The stream should be used to either /// read, or write, but not both. If you intermix reads and writes, the results are /// not defined. /// /// This class is intended primarily for use internally by the DotNetZip library. /// public class CrcCalculatorStream : System.IO.Stream { private System.IO.Stream _InnerStream; private CRC32 _Crc32; private Int64 _length = 0; /// /// Gets the total number of bytes run through the CRC32 calculator. /// /// /// /// This is either the total number of bytes read, or the total number /// of bytes written, depending on the direction of this stream. /// public Int64 TotalBytesSlurped { get { return _Crc32.TotalBytesRead; } } /// /// The constructor. /// /// The underlying stream public CrcCalculatorStream(System.IO.Stream stream) : base() { _InnerStream = stream; _Crc32 = new CRC32(); } /// /// The constructor. /// /// The underlying stream /// The length of the stream to slurp public CrcCalculatorStream(System.IO.Stream stream, Int64 length) : base() { _InnerStream = stream; _Crc32 = new CRC32(); _length = length; } /// /// Provides the current CRC for all blocks slurped in. /// public Int32 Crc32 { get { return _Crc32.Crc32Result; } } /// /// Read from the stream /// /// the buffer to read /// the offset at which to start /// the number of bytes to read /// the number of bytes actually read public override int Read(byte[] buffer, int offset, int count) { int bytesToRead = count; // Need to limit the # of bytes returned, if the stream is intended to have a definite length. // This is especially useful when returning a stream for the uncompressed data directly to the // application. The app won't necessarily read only the UncompressedSize number of bytes. // For example wrapping the stream returned from OpenReader() into a StreadReader() and // calling ReadToEnd() on it, We can "over-read" the zip data and get a corrupt string. // The length limits that, prevents that problem. if (_length != 0) { if (_Crc32.TotalBytesRead >= _length) return 0; // EOF Int64 bytesRemaining = _length - _Crc32.TotalBytesRead; if (bytesRemaining < count) bytesToRead = (int)bytesRemaining; } int n = _InnerStream.Read(buffer, offset, bytesToRead); if (n > 0) _Crc32.SlurpBlock(buffer, offset, n); return n; } /// /// Write to the stream. /// /// the buffer from which to write /// the offset at which to start writing /// the number of bytes to write public override void Write(byte[] buffer, int offset, int count) { if (count > 0) _Crc32.SlurpBlock(buffer, offset, count); _InnerStream.Write(buffer, offset, count); } /// /// Indicates whether the stream supports reading. /// public override bool CanRead { get { return _InnerStream.CanRead; } } /// /// Indicates whether the stream supports seeking. /// public override bool CanSeek { get { return _InnerStream.CanSeek; } } /// /// Indicates whether the stream supports writing. /// public override bool CanWrite { get { return _InnerStream.CanWrite; } } /// /// Flush the stream. /// public override void Flush() { _InnerStream.Flush(); } /// /// Not implemented. /// public override long Length { get { if (_length == 0) throw new NotImplementedException(); else return _length; } } /// /// Not implemented. /// public override long Position { get { return _Crc32.TotalBytesRead; } set { throw new NotImplementedException(); } } /// /// Not implemented. /// /// N/A /// N/A /// N/A public override long Seek(long offset, System.IO.SeekOrigin origin) { throw new NotImplementedException(); } /// /// Not implemented. /// /// N/A public override void SetLength(long value) { throw new NotImplementedException(); } } }