//
// 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();
}
}
}