Fix all warnings & Trim (#2226)

* Fix AutoFishing crash
* Fix all warnings
* Remove DotNetZip.
* Fix the usage of HttpClient.
This commit is contained in:
BruceChen 2022-10-02 18:31:08 +08:00 committed by GitHub
parent 4aa6c1c99f
commit 1d52d1eadd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
227 changed files with 2201 additions and 43564 deletions

View file

@ -1,814 +0,0 @@
// CRC32.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2011 Dino Chiesa.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// Last Saved: <2011-August-02 18:25:54>
//
// ------------------------------------------------------------------
//
// This module defines the CRC32 class, which can do the CRC32 algorithm, using
// arbitrary starting polynomials, and bit reversal. The bit reversal is what
// distinguishes this CRC-32 used in BZip2 from the CRC-32 that is used in PKZIP
// files, or GZIP files. This class does both.
//
// ------------------------------------------------------------------
using System;
using Interop = System.Runtime.InteropServices;
namespace Ionic.Crc
{
/// <summary>
/// Computes a CRC-32. The CRC-32 algorithm is parameterized - you
/// can set the polynomial and enable or disable bit
/// reversal. This can be used for GZIP, BZip2, or ZIP.
/// </summary>
/// <remarks>
/// This type is used internally by DotNetZip; it is generally not used
/// directly by applications wishing to create, read, or manipulate zip
/// archive files.
/// </remarks>
[Interop.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000C")]
[Interop.ComVisible(true)]
#if !NETCF
[Interop.ClassInterface(Interop.ClassInterfaceType.AutoDispatch)]
#endif
public class CRC32
{
/// <summary>
/// Indicates the total number of bytes applied to the CRC.
/// </summary>
public Int64 TotalBytesRead
{
get
{
return _TotalBytesRead;
}
}
/// <summary>
/// Indicates the current CRC for all blocks slurped in.
/// </summary>
public Int32 Crc32Result
{
get
{
return unchecked((Int32)(~_register));
}
}
/// <summary>
/// Returns the CRC32 for the specified stream.
/// </summary>
/// <param name="input">The stream over which to calculate the CRC32</param>
/// <returns>the CRC32 calculation</returns>
public Int32 GetCrc32(System.IO.Stream input)
{
return GetCrc32AndCopy(input, null);
}
/// <summary>
/// Returns the CRC32 for the specified stream, and writes the input into the
/// output stream.
/// </summary>
/// <param name="input">The stream over which to calculate the CRC32</param>
/// <param name="output">The stream into which to deflate the input</param>
/// <returns>the CRC32 calculation</returns>
public Int32 GetCrc32AndCopy(System.IO.Stream input, System.IO.Stream output)
{
if (input == null)
throw new Exception("The input stream must not be null.");
unchecked
{
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)
{
SlurpBlock(buffer, 0, count);
count = input.Read(buffer, 0, readSize);
if (output != null) output.Write(buffer, 0, count);
_TotalBytesRead += count;
}
return (Int32)(~_register);
}
}
/// <summary>
/// Get the CRC32 for the given (word,byte) combo. This is a
/// computation defined by PKzip for PKZIP 2.0 (weak) encryption.
/// </summary>
/// <param name="W">The word to start with.</param>
/// <param name="B">The byte to combine it with.</param>
/// <returns>The CRC-ized result.</returns>
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));
}
/// <summary>
/// Update the value for the running CRC32 using the given block of bytes.
/// This is useful when using the CRC32() class in a Stream.
/// </summary>
/// <param name="block">block of bytes to slurp</param>
/// <param name="offset">starting point in the block</param>
/// <param name="count">how many bytes within the block to slurp</param>
public void SlurpBlock(byte[] block, int offset, int count)
{
if (block == null)
throw new Exception("The data buffer must not be null.");
// bzip algorithm
for (int i = 0; i < count; i++)
{
int x = offset + i;
byte b = block[x];
if (this.reverseBits)
{
UInt32 temp = (_register >> 24) ^ b;
_register = (_register << 8) ^ crc32Table[temp];
}
else
{
UInt32 temp = (_register & 0x000000FF) ^ b;
_register = (_register >> 8) ^ crc32Table[temp];
}
}
_TotalBytesRead += count;
}
/// <summary>
/// Process one byte in the CRC.
/// </summary>
/// <param name = "b">the byte to include into the CRC . </param>
public void UpdateCRC(byte b)
{
if (this.reverseBits)
{
UInt32 temp = (_register >> 24) ^ b;
_register = (_register << 8) ^ crc32Table[temp];
}
else
{
UInt32 temp = (_register & 0x000000FF) ^ b;
_register = (_register >> 8) ^ crc32Table[temp];
}
}
/// <summary>
/// Process a run of N identical bytes into the CRC.
/// </summary>
/// <remarks>
/// <para>
/// This method serves as an optimization for updating the CRC when a
/// run of identical bytes is found. Rather than passing in a buffer of
/// length n, containing all identical bytes b, this method accepts the
/// byte value and the length of the (virtual) buffer - the length of
/// the run.
/// </para>
/// </remarks>
/// <param name = "b">the byte to include into the CRC. </param>
/// <param name = "n">the number of times that byte should be repeated. </param>
public void UpdateCRC(byte b, int n)
{
while (n-- > 0)
{
if (this.reverseBits)
{
uint temp = (_register >> 24) ^ b;
_register = (_register << 8) ^ crc32Table[(temp >= 0)
? temp
: (temp + 256)];
}
else
{
UInt32 temp = (_register & 0x000000FF) ^ b;
_register = (_register >> 8) ^ crc32Table[(temp >= 0)
? temp
: (temp + 256)];
}
}
}
private static uint ReverseBits(uint data)
{
unchecked
{
uint ret = data;
ret = (ret & 0x55555555) << 1 | (ret >> 1) & 0x55555555;
ret = (ret & 0x33333333) << 2 | (ret >> 2) & 0x33333333;
ret = (ret & 0x0F0F0F0F) << 4 | (ret >> 4) & 0x0F0F0F0F;
ret = (ret << 24) | ((ret & 0xFF00) << 8) | ((ret >> 8) & 0xFF00) | (ret >> 24);
return ret;
}
}
private static byte ReverseBits(byte data)
{
unchecked
{
uint u = (uint)data * 0x00020202;
uint m = 0x01044010;
uint s = u & m;
uint t = (u << 2) & (m << 1);
return (byte)((0x01001001 * (s + t)) >> 24);
}
}
private void GenerateLookupTable()
{
crc32Table = new UInt32[256];
unchecked
{
UInt32 dwCrc;
byte i = 0;
do
{
dwCrc = i;
for (byte j = 8; j > 0; j--)
{
if ((dwCrc & 1) == 1)
{
dwCrc = (dwCrc >> 1) ^ dwPolynomial;
}
else
{
dwCrc >>= 1;
}
}
if (reverseBits)
{
crc32Table[ReverseBits(i)] = ReverseBits(dwCrc);
}
else
{
crc32Table[i] = dwCrc;
}
i++;
} while (i!=0);
}
#if VERBOSE
Console.WriteLine();
Console.WriteLine("private static readonly UInt32[] crc32Table = {");
for (int i = 0; i < crc32Table.Length; i+=4)
{
Console.Write(" ");
for (int j=0; j < 4; j++)
{
Console.Write(" 0x{0:X8}U,", crc32Table[i+j]);
}
Console.WriteLine();
}
Console.WriteLine("};");
Console.WriteLine();
#endif
}
private uint gf2_matrix_times(uint[] matrix, uint vec)
{
uint sum = 0;
int i=0;
while (vec != 0)
{
if ((vec & 0x01)== 0x01)
sum ^= matrix[i];
vec >>= 1;
i++;
}
return sum;
}
private void gf2_matrix_square(uint[] square, uint[] mat)
{
for (int i = 0; i < 32; i++)
square[i] = gf2_matrix_times(mat, mat[i]);
}
/// <summary>
/// Combines the given CRC32 value with the current running total.
/// </summary>
/// <remarks>
/// This is useful when using a divide-and-conquer approach to
/// calculating a CRC. Multiple threads can each calculate a
/// CRC32 on a segment of the data, and then combine the
/// individual CRC32 values at the end.
/// </remarks>
/// <param name="crc">the crc value to be combined with this one</param>
/// <param name="length">the length of data the CRC value was calculated on</param>
public void Combine(int crc, int length)
{
uint[] even = new uint[32]; // even-power-of-two zeros operator
uint[] odd = new uint[32]; // odd-power-of-two zeros operator
if (length == 0)
return;
uint crc1= ~_register;
uint crc2= (uint) crc;
// put operator for one zero bit in odd
odd[0] = this.dwPolynomial; // the CRC-32 polynomial
uint row = 1;
for (int i = 1; i < 32; i++)
{
odd[i] = row;
row <<= 1;
}
// put operator for two zero bits in even
gf2_matrix_square(even, odd);
// put operator for four zero bits in odd
gf2_matrix_square(odd, even);
uint len2 = (uint) length;
// apply len2 zeros to crc1 (first square will put the operator for one
// zero byte, eight zero bits, in even)
do {
// apply zeros operator for this bit of len2
gf2_matrix_square(even, odd);
if ((len2 & 1)== 1)
crc1 = gf2_matrix_times(even, crc1);
len2 >>= 1;
if (len2 == 0)
break;
// another iteration of the loop with odd and even swapped
gf2_matrix_square(odd, even);
if ((len2 & 1)==1)
crc1 = gf2_matrix_times(odd, crc1);
len2 >>= 1;
} while (len2 != 0);
crc1 ^= crc2;
_register= ~crc1;
//return (int) crc1;
return;
}
/// <summary>
/// Create an instance of the CRC32 class using the default settings: no
/// bit reversal, and a polynomial of 0xEDB88320.
/// </summary>
public CRC32() : this(false)
{
}
/// <summary>
/// Create an instance of the CRC32 class, specifying whether to reverse
/// data bits or not.
/// </summary>
/// <param name='reverseBits'>
/// specify true if the instance should reverse data bits.
/// </param>
/// <remarks>
/// <para>
/// In the CRC-32 used by BZip2, the bits are reversed. Therefore if you
/// want a CRC32 with compatibility with BZip2, you should pass true
/// here. In the CRC-32 used by GZIP and PKZIP, the bits are not
/// reversed; Therefore if you want a CRC32 with compatibility with
/// those, you should pass false.
/// </para>
/// </remarks>
public CRC32(bool reverseBits) :
this( unchecked((int)0xEDB88320), reverseBits)
{
}
/// <summary>
/// Create an instance of the CRC32 class, specifying the polynomial and
/// whether to reverse data bits or not.
/// </summary>
/// <param name='polynomial'>
/// The polynomial to use for the CRC, expressed in the reversed (LSB)
/// format: the highest ordered bit in the polynomial value is the
/// coefficient of the 0th power; the second-highest order bit is the
/// coefficient of the 1 power, and so on. Expressed this way, the
/// polynomial for the CRC-32C used in IEEE 802.3, is 0xEDB88320.
/// </param>
/// <param name='reverseBits'>
/// specify true if the instance should reverse data bits.
/// </param>
///
/// <remarks>
/// <para>
/// In the CRC-32 used by BZip2, the bits are reversed. Therefore if you
/// want a CRC32 with compatibility with BZip2, you should pass true
/// here for the <c>reverseBits</c> parameter. In the CRC-32 used by
/// GZIP and PKZIP, the bits are not reversed; Therefore if you want a
/// CRC32 with compatibility with those, you should pass false for the
/// <c>reverseBits</c> parameter.
/// </para>
/// </remarks>
public CRC32(int polynomial, bool reverseBits)
{
this.reverseBits = reverseBits;
this.dwPolynomial = (uint) polynomial;
this.GenerateLookupTable();
}
/// <summary>
/// Reset the CRC-32 class - clear the CRC "remainder register."
/// </summary>
/// <remarks>
/// <para>
/// Use this when employing a single instance of this class to compute
/// multiple, distinct CRCs on multiple, distinct data blocks.
/// </para>
/// </remarks>
public void Reset()
{
_register = 0xFFFFFFFFU;
}
// private member vars
private UInt32 dwPolynomial;
private Int64 _TotalBytesRead;
private bool reverseBits;
private UInt32[] crc32Table;
private const int BUFFER_SIZE = 8192;
private UInt32 _register = 0xFFFFFFFFU;
}
/// <summary>
/// A Stream that calculates a CRC32 (a checksum) on all bytes read,
/// or on all bytes written.
/// </summary>
///
/// <remarks>
/// <para>
/// 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.
/// </para>
///
/// <para>
/// This class is intended primarily for use internally by the
/// DotNetZip library.
/// </para>
/// </remarks>
public class CrcCalculatorStream : System.IO.Stream, System.IDisposable
{
private static readonly Int64 UnsetLengthLimit = -99;
internal System.IO.Stream _innerStream;
private CRC32 _Crc32;
private Int64 _lengthLimit = -99;
private bool _leaveOpen;
/// <summary>
/// The default constructor.
/// </summary>
/// <remarks>
/// <para>
/// Instances returned from this constructor will leave the underlying
/// stream open upon Close(). The stream uses the default CRC32
/// algorithm, which implies a polynomial of 0xEDB88320.
/// </para>
/// </remarks>
/// <param name="stream">The underlying stream</param>
public CrcCalculatorStream(System.IO.Stream stream)
: this(true, CrcCalculatorStream.UnsetLengthLimit, stream, null)
{
}
/// <summary>
/// The constructor allows the caller to specify how to handle the
/// underlying stream at close.
/// </summary>
/// <remarks>
/// <para>
/// The stream uses the default CRC32 algorithm, which implies a
/// polynomial of 0xEDB88320.
/// </para>
/// </remarks>
/// <param name="stream">The underlying stream</param>
/// <param name="leaveOpen">true to leave the underlying stream
/// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
public CrcCalculatorStream(System.IO.Stream stream, bool leaveOpen)
: this(leaveOpen, CrcCalculatorStream.UnsetLengthLimit, stream, null)
{
}
/// <summary>
/// A constructor allowing the specification of the length of the stream
/// to read.
/// </summary>
/// <remarks>
/// <para>
/// The stream uses the default CRC32 algorithm, which implies a
/// polynomial of 0xEDB88320.
/// </para>
/// <para>
/// Instances returned from this constructor will leave the underlying
/// stream open upon Close().
/// </para>
/// </remarks>
/// <param name="stream">The underlying stream</param>
/// <param name="length">The length of the stream to slurp</param>
public CrcCalculatorStream(System.IO.Stream stream, Int64 length)
: this(true, length, stream, null)
{
if (length < 0)
throw new ArgumentException("length");
}
/// <summary>
/// A constructor allowing the specification of the length of the stream
/// to read, as well as whether to keep the underlying stream open upon
/// Close().
/// </summary>
/// <remarks>
/// <para>
/// The stream uses the default CRC32 algorithm, which implies a
/// polynomial of 0xEDB88320.
/// </para>
/// </remarks>
/// <param name="stream">The underlying stream</param>
/// <param name="length">The length of the stream to slurp</param>
/// <param name="leaveOpen">true to leave the underlying stream
/// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
public CrcCalculatorStream(System.IO.Stream stream, Int64 length, bool leaveOpen)
: this(leaveOpen, length, stream, null)
{
if (length < 0)
throw new ArgumentException("length");
}
/// <summary>
/// A constructor allowing the specification of the length of the stream
/// to read, as well as whether to keep the underlying stream open upon
/// Close(), and the CRC32 instance to use.
/// </summary>
/// <remarks>
/// <para>
/// The stream uses the specified CRC32 instance, which allows the
/// application to specify how the CRC gets calculated.
/// </para>
/// </remarks>
/// <param name="stream">The underlying stream</param>
/// <param name="length">The length of the stream to slurp</param>
/// <param name="leaveOpen">true to leave the underlying stream
/// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
/// <param name="crc32">the CRC32 instance to use to calculate the CRC32</param>
public CrcCalculatorStream(System.IO.Stream stream, Int64 length, bool leaveOpen,
CRC32 crc32)
: this(leaveOpen, length, stream, crc32)
{
if (length < 0)
throw new ArgumentException("length");
}
// This ctor is private - no validation is done here. This is to allow the use
// of a (specific) negative value for the _lengthLimit, to indicate that there
// is no length set. So we validate the length limit in those ctors that use an
// explicit param, otherwise we don't validate, because it could be our special
// value.
private CrcCalculatorStream
(bool leaveOpen, Int64 length, System.IO.Stream stream, CRC32 crc32)
: base()
{
_innerStream = stream;
_Crc32 = crc32 ?? new CRC32();
_lengthLimit = length;
_leaveOpen = leaveOpen;
}
/// <summary>
/// Gets the total number of bytes run through the CRC32 calculator.
/// </summary>
///
/// <remarks>
/// This is either the total number of bytes read, or the total number of
/// bytes written, depending on the direction of this stream.
/// </remarks>
public Int64 TotalBytesSlurped
{
get { return _Crc32.TotalBytesRead; }
}
/// <summary>
/// Provides the current CRC for all blocks slurped in.
/// </summary>
/// <remarks>
/// <para>
/// The running total of the CRC is kept as data is written or read
/// through the stream. read this property after all reads or writes to
/// get an accurate CRC for the entire stream.
/// </para>
/// </remarks>
public Int32 Crc
{
get { return _Crc32.Crc32Result; }
}
/// <summary>
/// Indicates whether the underlying stream will be left open when the
/// <c>CrcCalculatorStream</c> is Closed.
/// </summary>
/// <remarks>
/// <para>
/// Set this at any point before calling <see cref="Close()"/>.
/// </para>
/// </remarks>
public bool LeaveOpen
{
get { return _leaveOpen; }
set { _leaveOpen = value; }
}
/// <summary>
/// Read from the stream
/// </summary>
/// <param name="buffer">the buffer to read</param>
/// <param name="offset">the offset at which to start</param>
/// <param name="count">the number of bytes to read</param>
/// <returns>the number of bytes actually read</returns>
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 (_lengthLimit != CrcCalculatorStream.UnsetLengthLimit)
{
if (_Crc32.TotalBytesRead >= _lengthLimit) return 0; // EOF
Int64 bytesRemaining = _lengthLimit - _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;
}
/// <summary>
/// Write to the stream.
/// </summary>
/// <param name="buffer">the buffer from which to write</param>
/// <param name="offset">the offset at which to start writing</param>
/// <param name="count">the number of bytes to write</param>
public override void Write(byte[] buffer, int offset, int count)
{
if (count > 0) _Crc32.SlurpBlock(buffer, offset, count);
_innerStream.Write(buffer, offset, count);
}
/// <summary>
/// Indicates whether the stream supports reading.
/// </summary>
public override bool CanRead
{
get { return _innerStream.CanRead; }
}
/// <summary>
/// Indicates whether the stream supports seeking.
/// </summary>
/// <remarks>
/// <para>
/// Always returns false.
/// </para>
/// </remarks>
public override bool CanSeek
{
get { return false; }
}
/// <summary>
/// Indicates whether the stream supports writing.
/// </summary>
public override bool CanWrite
{
get { return _innerStream.CanWrite; }
}
/// <summary>
/// Flush the stream.
/// </summary>
public override void Flush()
{
_innerStream.Flush();
}
/// <summary>
/// Returns the length of the underlying stream.
/// </summary>
public override long Length
{
get
{
if (_lengthLimit == CrcCalculatorStream.UnsetLengthLimit)
return _innerStream.Length;
else return _lengthLimit;
}
}
/// <summary>
/// The getter for this property returns the total bytes read.
/// If you use the setter, it will throw
/// <see cref="NotSupportedException"/>.
/// </summary>
public override long Position
{
get { return _Crc32.TotalBytesRead; }
set { throw new NotSupportedException(); }
}
/// <summary>
/// Seeking is not supported on this stream. This method always throws
/// <see cref="NotSupportedException"/>
/// </summary>
/// <param name="offset">N/A</param>
/// <param name="origin">N/A</param>
/// <returns>N/A</returns>
public override long Seek(long offset, System.IO.SeekOrigin origin)
{
throw new NotSupportedException();
}
/// <summary>
/// This method always throws
/// <see cref="NotSupportedException"/>
/// </summary>
/// <param name="value">N/A</param>
public override void SetLength(long value)
{
throw new NotSupportedException();
}
void IDisposable.Dispose()
{
Close();
}
/// <summary>
/// Closes the stream.
/// </summary>
public override void Close()
{
base.Close();
if (!_leaveOpen)
_innerStream.Close();
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,740 +0,0 @@
// DeflateStream.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009-2010 Dino Chiesa.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2011-July-31 14:48:11>
//
// ------------------------------------------------------------------
//
// This module defines the DeflateStream class, which can be used as a replacement for
// the System.IO.Compression.DeflateStream class in the .NET BCL.
//
// ------------------------------------------------------------------
using System;
namespace Ionic.Zlib
{
/// <summary>
/// A class for compressing and decompressing streams using the Deflate algorithm.
/// </summary>
///
/// <remarks>
///
/// <para>
/// The DeflateStream is a <see
/// href="http://en.wikipedia.org/wiki/Decorator_pattern">Decorator</see> on a <see
/// cref="System.IO.Stream"/>. It adds DEFLATE compression or decompression to any
/// stream.
/// </para>
///
/// <para>
/// Using this stream, applications can compress or decompress data via stream
/// <c>Read</c> and <c>Write</c> operations. Either compresssion or decompression
/// can occur through either reading or writing. The compression format used is
/// DEFLATE, which is documented in <see
/// href="http://www.ietf.org/rfc/rfc1951.txt">IETF RFC 1951</see>, "DEFLATE
/// Compressed Data Format Specification version 1.3.".
/// </para>
///
/// <para>
/// This class is similar to <see cref="ZlibStream"/>, except that
/// <c>ZlibStream</c> adds the <see href="http://www.ietf.org/rfc/rfc1950.txt">RFC
/// 1950 - ZLIB</see> framing bytes to a compressed stream when compressing, or
/// expects the RFC1950 framing bytes when decompressing. The <c>DeflateStream</c>
/// does not.
/// </para>
///
/// </remarks>
///
/// <seealso cref="ZlibStream" />
/// <seealso cref="GZipStream" />
public class DeflateStream : System.IO.Stream
{
internal ZlibBaseStream _baseStream;
internal System.IO.Stream _innerStream;
bool _disposed;
/// <summary>
/// Create a DeflateStream using the specified CompressionMode.
/// </summary>
///
/// <remarks>
/// When mode is <c>CompressionMode.Compress</c>, the DeflateStream will use
/// the default compression level. The "captive" stream will be closed when
/// the DeflateStream is closed.
/// </remarks>
///
/// <example>
/// This example uses a DeflateStream to compress data from a file, and writes
/// the compressed data to another file.
/// <code>
/// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
/// {
/// using (var raw = System.IO.File.Create(fileToCompress + ".deflated"))
/// {
/// using (Stream compressor = new DeflateStream(raw, CompressionMode.Compress))
/// {
/// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
/// int n;
/// while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
/// {
/// compressor.Write(buffer, 0, n);
/// }
/// }
/// }
/// }
/// </code>
///
/// <code lang="VB">
/// Using input As Stream = File.OpenRead(fileToCompress)
/// Using raw As FileStream = File.Create(fileToCompress &amp; ".deflated")
/// Using compressor As Stream = New DeflateStream(raw, CompressionMode.Compress)
/// Dim buffer As Byte() = New Byte(4096) {}
/// Dim n As Integer = -1
/// Do While (n &lt;&gt; 0)
/// If (n &gt; 0) Then
/// compressor.Write(buffer, 0, n)
/// End If
/// n = input.Read(buffer, 0, buffer.Length)
/// Loop
/// End Using
/// End Using
/// End Using
/// </code>
/// </example>
/// <param name="stream">The stream which will be read or written.</param>
/// <param name="mode">Indicates whether the DeflateStream will compress or decompress.</param>
public DeflateStream(System.IO.Stream stream, CompressionMode mode)
: this(stream, mode, CompressionLevel.Default, false)
{
}
/// <summary>
/// Create a DeflateStream using the specified CompressionMode and the specified CompressionLevel.
/// </summary>
///
/// <remarks>
///
/// <para>
/// When mode is <c>CompressionMode.Decompress</c>, the level parameter is
/// ignored. The "captive" stream will be closed when the DeflateStream is
/// closed.
/// </para>
///
/// </remarks>
///
/// <example>
///
/// This example uses a DeflateStream to compress data from a file, and writes
/// the compressed data to another file.
///
/// <code>
/// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
/// {
/// using (var raw = System.IO.File.Create(fileToCompress + ".deflated"))
/// {
/// using (Stream compressor = new DeflateStream(raw,
/// CompressionMode.Compress,
/// CompressionLevel.BestCompression))
/// {
/// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
/// int n= -1;
/// while (n != 0)
/// {
/// if (n &gt; 0)
/// compressor.Write(buffer, 0, n);
/// n= input.Read(buffer, 0, buffer.Length);
/// }
/// }
/// }
/// }
/// </code>
///
/// <code lang="VB">
/// Using input As Stream = File.OpenRead(fileToCompress)
/// Using raw As FileStream = File.Create(fileToCompress &amp; ".deflated")
/// Using compressor As Stream = New DeflateStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression)
/// Dim buffer As Byte() = New Byte(4096) {}
/// Dim n As Integer = -1
/// Do While (n &lt;&gt; 0)
/// If (n &gt; 0) Then
/// compressor.Write(buffer, 0, n)
/// End If
/// n = input.Read(buffer, 0, buffer.Length)
/// Loop
/// End Using
/// End Using
/// End Using
/// </code>
/// </example>
/// <param name="stream">The stream to be read or written while deflating or inflating.</param>
/// <param name="mode">Indicates whether the <c>DeflateStream</c> will compress or decompress.</param>
/// <param name="level">A tuning knob to trade speed for effectiveness.</param>
public DeflateStream(System.IO.Stream stream, CompressionMode mode, CompressionLevel level)
: this(stream, mode, level, false)
{
}
/// <summary>
/// Create a <c>DeflateStream</c> using the specified
/// <c>CompressionMode</c>, and explicitly specify whether the
/// stream should be left open after Deflation or Inflation.
/// </summary>
///
/// <remarks>
///
/// <para>
/// This constructor allows the application to request that the captive stream
/// remain open after the deflation or inflation occurs. By default, after
/// <c>Close()</c> is called on the stream, the captive stream is also
/// closed. In some cases this is not desired, for example if the stream is a
/// memory stream that will be re-read after compression. Specify true for
/// the <paramref name="leaveOpen"/> parameter to leave the stream open.
/// </para>
///
/// <para>
/// The <c>DeflateStream</c> will use the default compression level.
/// </para>
///
/// <para>
/// See the other overloads of this constructor for example code.
/// </para>
/// </remarks>
///
/// <param name="stream">
/// The stream which will be read or written. This is called the
/// "captive" stream in other places in this documentation.
/// </param>
///
/// <param name="mode">
/// Indicates whether the <c>DeflateStream</c> will compress or decompress.
/// </param>
///
/// <param name="leaveOpen">true if the application would like the stream to
/// remain open after inflation/deflation.</param>
public DeflateStream(System.IO.Stream stream, CompressionMode mode, bool leaveOpen)
: this(stream, mode, CompressionLevel.Default, leaveOpen)
{
}
/// <summary>
/// Create a <c>DeflateStream</c> using the specified <c>CompressionMode</c>
/// and the specified <c>CompressionLevel</c>, and explicitly specify whether
/// the stream should be left open after Deflation or Inflation.
/// </summary>
///
/// <remarks>
///
/// <para>
/// When mode is <c>CompressionMode.Decompress</c>, the level parameter is ignored.
/// </para>
///
/// <para>
/// This constructor allows the application to request that the captive stream
/// remain open after the deflation or inflation occurs. By default, after
/// <c>Close()</c> is called on the stream, the captive stream is also
/// closed. In some cases this is not desired, for example if the stream is a
/// <see cref="System.IO.MemoryStream"/> that will be re-read after
/// compression. Specify true for the <paramref name="leaveOpen"/> parameter
/// to leave the stream open.
/// </para>
///
/// </remarks>
///
/// <example>
///
/// This example shows how to use a <c>DeflateStream</c> to compress data from
/// a file, and store the compressed data into another file.
///
/// <code>
/// using (var output = System.IO.File.Create(fileToCompress + ".deflated"))
/// {
/// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
/// {
/// using (Stream compressor = new DeflateStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, true))
/// {
/// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
/// int n= -1;
/// while (n != 0)
/// {
/// if (n &gt; 0)
/// compressor.Write(buffer, 0, n);
/// n= input.Read(buffer, 0, buffer.Length);
/// }
/// }
/// }
/// // can write additional data to the output stream here
/// }
/// </code>
///
/// <code lang="VB">
/// Using output As FileStream = File.Create(fileToCompress &amp; ".deflated")
/// Using input As Stream = File.OpenRead(fileToCompress)
/// Using compressor As Stream = New DeflateStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, True)
/// Dim buffer As Byte() = New Byte(4096) {}
/// Dim n As Integer = -1
/// Do While (n &lt;&gt; 0)
/// If (n &gt; 0) Then
/// compressor.Write(buffer, 0, n)
/// End If
/// n = input.Read(buffer, 0, buffer.Length)
/// Loop
/// End Using
/// End Using
/// ' can write additional data to the output stream here.
/// End Using
/// </code>
/// </example>
/// <param name="stream">The stream which will be read or written.</param>
/// <param name="mode">Indicates whether the DeflateStream will compress or decompress.</param>
/// <param name="leaveOpen">true if the application would like the stream to remain open after inflation/deflation.</param>
/// <param name="level">A tuning knob to trade speed for effectiveness.</param>
public DeflateStream(System.IO.Stream stream, CompressionMode mode, CompressionLevel level, bool leaveOpen)
{
_innerStream = stream;
_baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.DEFLATE, leaveOpen);
}
#region Zlib properties
/// <summary>
/// This property sets the flush behavior on the stream.
/// </summary>
/// <remarks> See the ZLIB documentation for the meaning of the flush behavior.
/// </remarks>
virtual public FlushType FlushMode
{
get { return (this._baseStream._flushMode); }
set
{
if (_disposed) throw new ObjectDisposedException("DeflateStream");
this._baseStream._flushMode = value;
}
}
/// <summary>
/// The size of the working buffer for the compression codec.
/// </summary>
///
/// <remarks>
/// <para>
/// The working buffer is used for all stream operations. The default size is
/// 1024 bytes. The minimum size is 128 bytes. You may get better performance
/// with a larger buffer. Then again, you might not. You would have to test
/// it.
/// </para>
///
/// <para>
/// Set this before the first call to <c>Read()</c> or <c>Write()</c> on the
/// stream. If you try to set it afterwards, it will throw.
/// </para>
/// </remarks>
public int BufferSize
{
get
{
return this._baseStream._bufferSize;
}
set
{
if (_disposed) throw new ObjectDisposedException("DeflateStream");
if (this._baseStream._workingBuffer != null)
throw new ZlibException("The working buffer is already set.");
if (value < ZlibConstants.WorkingBufferSizeMin)
throw new ZlibException(String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value, ZlibConstants.WorkingBufferSizeMin));
this._baseStream._bufferSize = value;
}
}
/// <summary>
/// The ZLIB strategy to be used during compression.
/// </summary>
///
/// <remarks>
/// By tweaking this parameter, you may be able to optimize the compression for
/// data with particular characteristics.
/// </remarks>
public CompressionStrategy Strategy
{
get
{
return this._baseStream.Strategy;
}
set
{
if (_disposed) throw new ObjectDisposedException("DeflateStream");
this._baseStream.Strategy = value;
}
}
/// <summary> Returns the total number of bytes input so far.</summary>
virtual public long TotalIn
{
get
{
return this._baseStream._z.TotalBytesIn;
}
}
/// <summary> Returns the total number of bytes output so far.</summary>
virtual public long TotalOut
{
get
{
return this._baseStream._z.TotalBytesOut;
}
}
#endregion
#region System.IO.Stream methods
/// <summary>
/// Dispose the stream.
/// </summary>
/// <remarks>
/// <para>
/// This may or may not result in a <c>Close()</c> call on the captive
/// stream. See the constructors that have a <c>leaveOpen</c> parameter
/// for more information.
/// </para>
/// <para>
/// Application code won't call this code directly. This method may be
/// invoked in two distinct scenarios. If disposing == true, the method
/// has been called directly or indirectly by a user's code, for example
/// via the public Dispose() method. In this case, both managed and
/// unmanaged resources can be referenced and disposed. If disposing ==
/// false, the method has been called by the runtime from inside the
/// object finalizer and this method should not reference other objects;
/// in that case only unmanaged resources must be referenced or
/// disposed.
/// </para>
/// </remarks>
/// <param name="disposing">
/// true if the Dispose method was invoked by user code.
/// </param>
protected override void Dispose(bool disposing)
{
try
{
if (!_disposed)
{
if (disposing && (this._baseStream != null))
this._baseStream.Close();
_disposed = true;
}
}
finally
{
base.Dispose(disposing);
}
}
/// <summary>
/// Indicates whether the stream can be read.
/// </summary>
/// <remarks>
/// The return value depends on whether the captive stream supports reading.
/// </remarks>
public override bool CanRead
{
get
{
if (_disposed) throw new ObjectDisposedException("DeflateStream");
return _baseStream._stream.CanRead;
}
}
/// <summary>
/// Indicates whether the stream supports Seek operations.
/// </summary>
/// <remarks>
/// Always returns false.
/// </remarks>
public override bool CanSeek
{
get { return false; }
}
/// <summary>
/// Indicates whether the stream can be written.
/// </summary>
/// <remarks>
/// The return value depends on whether the captive stream supports writing.
/// </remarks>
public override bool CanWrite
{
get
{
if (_disposed) throw new ObjectDisposedException("DeflateStream");
return _baseStream._stream.CanWrite;
}
}
/// <summary>
/// Flush the stream.
/// </summary>
public override void Flush()
{
if (_disposed) throw new ObjectDisposedException("DeflateStream");
_baseStream.Flush();
}
/// <summary>
/// Reading this property always throws a <see cref="NotImplementedException"/>.
/// </summary>
public override long Length
{
get { throw new NotImplementedException(); }
}
/// <summary>
/// The position of the stream pointer.
/// </summary>
///
/// <remarks>
/// Setting this property always throws a <see
/// cref="NotImplementedException"/>. Reading will return the total bytes
/// written out, if used in writing, or the total bytes read in, if used in
/// reading. The count may refer to compressed bytes or uncompressed bytes,
/// depending on how you've used the stream.
/// </remarks>
public override long Position
{
get
{
if (this._baseStream._streamMode == Ionic.Zlib.ZlibBaseStream.StreamMode.Writer)
return this._baseStream._z.TotalBytesOut;
if (this._baseStream._streamMode == Ionic.Zlib.ZlibBaseStream.StreamMode.Reader)
return this._baseStream._z.TotalBytesIn;
return 0;
}
set { throw new NotImplementedException(); }
}
/// <summary>
/// Read data from the stream.
/// </summary>
/// <remarks>
///
/// <para>
/// If you wish to use the <c>DeflateStream</c> to compress data while
/// reading, you can create a <c>DeflateStream</c> with
/// <c>CompressionMode.Compress</c>, providing an uncompressed data stream.
/// Then call Read() on that <c>DeflateStream</c>, and the data read will be
/// compressed as you read. If you wish to use the <c>DeflateStream</c> to
/// decompress data while reading, you can create a <c>DeflateStream</c> with
/// <c>CompressionMode.Decompress</c>, providing a readable compressed data
/// stream. Then call Read() on that <c>DeflateStream</c>, and the data read
/// will be decompressed as you read.
/// </para>
///
/// <para>
/// A <c>DeflateStream</c> can be used for <c>Read()</c> or <c>Write()</c>, but not both.
/// </para>
///
/// </remarks>
/// <param name="buffer">The buffer into which the read data should be placed.</param>
/// <param name="offset">the offset within that data array to put the first byte read.</param>
/// <param name="count">the number of bytes to read.</param>
/// <returns>the number of bytes actually read</returns>
public override int Read(byte[] buffer, int offset, int count)
{
if (_disposed) throw new ObjectDisposedException("DeflateStream");
return _baseStream.Read(buffer, offset, count);
}
/// <summary>
/// Calling this method always throws a <see cref="NotImplementedException"/>.
/// </summary>
/// <param name="offset">this is irrelevant, since it will always throw!</param>
/// <param name="origin">this is irrelevant, since it will always throw!</param>
/// <returns>irrelevant!</returns>
public override long Seek(long offset, System.IO.SeekOrigin origin)
{
throw new NotImplementedException();
}
/// <summary>
/// Calling this method always throws a <see cref="NotImplementedException"/>.
/// </summary>
/// <param name="value">this is irrelevant, since it will always throw!</param>
public override void SetLength(long value)
{
throw new NotImplementedException();
}
/// <summary>
/// Write data to the stream.
/// </summary>
/// <remarks>
///
/// <para>
/// If you wish to use the <c>DeflateStream</c> to compress data while
/// writing, you can create a <c>DeflateStream</c> with
/// <c>CompressionMode.Compress</c>, and a writable output stream. Then call
/// <c>Write()</c> on that <c>DeflateStream</c>, providing uncompressed data
/// as input. The data sent to the output stream will be the compressed form
/// of the data written. If you wish to use the <c>DeflateStream</c> to
/// decompress data while writing, you can create a <c>DeflateStream</c> with
/// <c>CompressionMode.Decompress</c>, and a writable output stream. Then
/// call <c>Write()</c> on that stream, providing previously compressed
/// data. The data sent to the output stream will be the decompressed form of
/// the data written.
/// </para>
///
/// <para>
/// A <c>DeflateStream</c> can be used for <c>Read()</c> or <c>Write()</c>,
/// but not both.
/// </para>
///
/// </remarks>
///
/// <param name="buffer">The buffer holding data to write to the stream.</param>
/// <param name="offset">the offset within that data array to find the first byte to write.</param>
/// <param name="count">the number of bytes to write.</param>
public override void Write(byte[] buffer, int offset, int count)
{
if (_disposed) throw new ObjectDisposedException("DeflateStream");
_baseStream.Write(buffer, offset, count);
}
#endregion
/// <summary>
/// Compress a string into a byte array using DEFLATE (RFC 1951).
/// </summary>
///
/// <remarks>
/// Uncompress it with <see cref="DeflateStream.UncompressString(byte[])"/>.
/// </remarks>
///
/// <seealso cref="DeflateStream.UncompressString(byte[])">DeflateStream.UncompressString(byte[])</seealso>
/// <seealso cref="DeflateStream.CompressBuffer(byte[])">DeflateStream.CompressBuffer(byte[])</seealso>
/// <seealso cref="GZipStream.CompressString(string)">GZipStream.CompressString(string)</seealso>
/// <seealso cref="ZlibStream.CompressString(string)">ZlibStream.CompressString(string)</seealso>
///
/// <param name="s">
/// A string to compress. The string will first be encoded
/// using UTF8, then compressed.
/// </param>
///
/// <returns>The string in compressed form</returns>
public static byte[] CompressString(String s)
{
using (var ms = new System.IO.MemoryStream())
{
System.IO.Stream compressor =
new DeflateStream(ms, CompressionMode.Compress, CompressionLevel.BestCompression);
ZlibBaseStream.CompressString(s, compressor);
return ms.ToArray();
}
}
/// <summary>
/// Compress a byte array into a new byte array using DEFLATE.
/// </summary>
///
/// <remarks>
/// Uncompress it with <see cref="DeflateStream.UncompressBuffer(byte[])"/>.
/// </remarks>
///
/// <seealso cref="DeflateStream.CompressString(string)">DeflateStream.CompressString(string)</seealso>
/// <seealso cref="DeflateStream.UncompressBuffer(byte[])">DeflateStream.UncompressBuffer(byte[])</seealso>
/// <seealso cref="GZipStream.CompressBuffer(byte[])">GZipStream.CompressBuffer(byte[])</seealso>
/// <seealso cref="ZlibStream.CompressBuffer(byte[])">ZlibStream.CompressBuffer(byte[])</seealso>
///
/// <param name="b">
/// A buffer to compress.
/// </param>
///
/// <returns>The data in compressed form</returns>
public static byte[] CompressBuffer(byte[] b)
{
using (var ms = new System.IO.MemoryStream())
{
System.IO.Stream compressor =
new DeflateStream( ms, CompressionMode.Compress, CompressionLevel.BestCompression );
ZlibBaseStream.CompressBuffer(b, compressor);
return ms.ToArray();
}
}
/// <summary>
/// Uncompress a DEFLATE'd byte array into a single string.
/// </summary>
///
/// <seealso cref="DeflateStream.CompressString(String)">DeflateStream.CompressString(String)</seealso>
/// <seealso cref="DeflateStream.UncompressBuffer(byte[])">DeflateStream.UncompressBuffer(byte[])</seealso>
/// <seealso cref="GZipStream.UncompressString(byte[])">GZipStream.UncompressString(byte[])</seealso>
/// <seealso cref="ZlibStream.UncompressString(byte[])">ZlibStream.UncompressString(byte[])</seealso>
///
/// <param name="compressed">
/// A buffer containing DEFLATE-compressed data.
/// </param>
///
/// <returns>The uncompressed string</returns>
public static String UncompressString(byte[] compressed)
{
using (var input = new System.IO.MemoryStream(compressed))
{
System.IO.Stream decompressor =
new DeflateStream(input, CompressionMode.Decompress);
return ZlibBaseStream.UncompressString(compressed, decompressor);
}
}
/// <summary>
/// Uncompress a DEFLATE'd byte array into a byte array.
/// </summary>
///
/// <seealso cref="DeflateStream.CompressBuffer(byte[])">DeflateStream.CompressBuffer(byte[])</seealso>
/// <seealso cref="DeflateStream.UncompressString(byte[])">DeflateStream.UncompressString(byte[])</seealso>
/// <seealso cref="GZipStream.UncompressBuffer(byte[])">GZipStream.UncompressBuffer(byte[])</seealso>
/// <seealso cref="ZlibStream.UncompressBuffer(byte[])">ZlibStream.UncompressBuffer(byte[])</seealso>
///
/// <param name="compressed">
/// A buffer containing data that has been compressed with DEFLATE.
/// </param>
///
/// <returns>The data in uncompressed form</returns>
public static byte[] UncompressBuffer(byte[] compressed)
{
using (var input = new System.IO.MemoryStream(compressed))
{
System.IO.Stream decompressor =
new DeflateStream( input, CompressionMode.Decompress );
return ZlibBaseStream.UncompressBuffer(compressed, decompressor);
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,436 +0,0 @@
// Inftree.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2009-October-28 12:43:54>
//
// ------------------------------------------------------------------
//
// This module defines classes used in decompression. This code is derived
// from the jzlib implementation of zlib. In keeping with the license for jzlib,
// the copyright to that code is below.
//
// ------------------------------------------------------------------
//
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the distribution.
//
// 3. The names of the authors may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------
//
// This program is based on zlib-1.1.3; credit to authors
// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
// and contributors of zlib.
//
// -----------------------------------------------------------------------
using System;
namespace Ionic.Zlib
{
sealed class InfTree
{
private const int MANY = 1440;
private const int Z_OK = 0;
private const int Z_STREAM_END = 1;
private const int Z_NEED_DICT = 2;
private const int Z_ERRNO = - 1;
private const int Z_STREAM_ERROR = - 2;
private const int Z_DATA_ERROR = - 3;
private const int Z_MEM_ERROR = - 4;
private const int Z_BUF_ERROR = - 5;
private const int Z_VERSION_ERROR = - 6;
internal const int fixed_bl = 9;
internal const int fixed_bd = 5;
//UPGRADE_NOTE: Final was removed from the declaration of 'fixed_tl'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
internal static readonly int[] fixed_tl = new int[]{96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 192, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 160, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 224, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 144, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 208, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 176, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 240, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 200, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 168, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 232, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 152, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 216, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 184, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 248, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 196, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 164, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 228, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 148, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 212, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 180, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 244, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 204, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 172, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 236, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 156, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 220, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 188, 0, 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 252, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 194, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 162, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 226, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 146, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 210, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 178, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 242, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 202, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 170, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 234, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 154, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 218, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 186,
0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 250, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 198, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 166, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 230, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 150, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 214, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 182, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 246, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 206, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 174, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 238, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 158, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 222, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 190, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 254, 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 193, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 161, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 225, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 145, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 209, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 177, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 241, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 201, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 169, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 233, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 153, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 217, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 185, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 249, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 197, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 165, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 229, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 149, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 213, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 181, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 245, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 205, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 173, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 237, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 157, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 221, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 189, 0, 8,
14, 0, 8, 142, 0, 8, 78, 0, 9, 253, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 195, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 163, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 227, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 147, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 211, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 179, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 243, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 203, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 171, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 235, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 155, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 219, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 187, 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 251, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 199, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 167, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 231, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 151, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 215, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 183, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 247, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 207, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 175, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 239, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 159, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 223, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 191, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 255};
//UPGRADE_NOTE: Final was removed from the declaration of 'fixed_td'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
internal static readonly int[] fixed_td = new int[]{80, 5, 1, 87, 5, 257, 83, 5, 17, 91, 5, 4097, 81, 5, 5, 89, 5, 1025, 85, 5, 65, 93, 5, 16385, 80, 5, 3, 88, 5, 513, 84, 5, 33, 92, 5, 8193, 82, 5, 9, 90, 5, 2049, 86, 5, 129, 192, 5, 24577, 80, 5, 2, 87, 5, 385, 83, 5, 25, 91, 5, 6145, 81, 5, 7, 89, 5, 1537, 85, 5, 97, 93, 5, 24577, 80, 5, 4, 88, 5, 769, 84, 5, 49, 92, 5, 12289, 82, 5, 13, 90, 5, 3073, 86, 5, 193, 192, 5, 24577};
// Tables for deflate from PKZIP's appnote.txt.
//UPGRADE_NOTE: Final was removed from the declaration of 'cplens'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
internal static readonly int[] cplens = new int[]{3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
// see note #13 above about 258
//UPGRADE_NOTE: Final was removed from the declaration of 'cplext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
internal static readonly int[] cplext = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112};
//UPGRADE_NOTE: Final was removed from the declaration of 'cpdist'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
internal static readonly int[] cpdist = new int[]{1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577};
//UPGRADE_NOTE: Final was removed from the declaration of 'cpdext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
internal static readonly int[] cpdext = new int[]{0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
// If BMAX needs to be larger than 16, then h and x[] should be uLong.
internal const int BMAX = 15; // maximum bit length of any code
internal int[] hn = null; // hufts used in space
internal int[] v = null; // work area for huft_build
internal int[] c = null; // bit length count table
internal int[] r = null; // table entry for structure assignment
internal int[] u = null; // table stack
internal int[] x = null; // bit offsets, then code stack
private int huft_build(int[] b, int bindex, int n, int s, int[] d, int[] e, int[] t, int[] m, int[] hp, int[] hn, int[] v)
{
// Given a list of code lengths and a maximum table size, make a set of
// tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
// if the given code set is incomplete (the tables are still built in this
// case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
// lengths), or Z_MEM_ERROR if not enough memory.
int a; // counter for codes of length k
int f; // i repeats in table every f entries
int g; // maximum code length
int h; // table level
int i; // counter, current code
int j; // counter
int k; // number of bits in current code
int l; // bits per table (returned in m)
int mask; // (1 << w) - 1, to avoid cc -O bug on HP
int p; // pointer into c[], b[], or v[]
int q; // points to current table
int w; // bits before this table == (l * h)
int xp; // pointer into x
int y; // number of dummy codes added
int z; // number of entries in current table
// Generate counts for each bit length
p = 0; i = n;
do
{
c[b[bindex + p]]++; p++; i--; // assume all entries <= BMAX
}
while (i != 0);
if (c[0] == n)
{
// null input--all zero length codes
t[0] = - 1;
m[0] = 0;
return Z_OK;
}
// Find minimum and maximum length, bound *m by those
l = m[0];
for (j = 1; j <= BMAX; j++)
if (c[j] != 0)
break;
k = j; // minimum code length
if (l < j)
{
l = j;
}
for (i = BMAX; i != 0; i--)
{
if (c[i] != 0)
break;
}
g = i; // maximum code length
if (l > i)
{
l = i;
}
m[0] = l;
// Adjust last length count to fill out codes, if needed
for (y = 1 << j; j < i; j++, y <<= 1)
{
if ((y -= c[j]) < 0)
{
return Z_DATA_ERROR;
}
}
if ((y -= c[i]) < 0)
{
return Z_DATA_ERROR;
}
c[i] += y;
// Generate starting offsets into the value table for each length
x[1] = j = 0;
p = 1; xp = 2;
while (--i != 0)
{
// note that i == g from above
x[xp] = (j += c[p]);
xp++;
p++;
}
// Make a table of values in order of bit lengths
i = 0; p = 0;
do
{
if ((j = b[bindex + p]) != 0)
{
v[x[j]++] = i;
}
p++;
}
while (++i < n);
n = x[g]; // set n to length of v
// Generate the Huffman codes and for each, make the table entries
x[0] = i = 0; // first Huffman code is zero
p = 0; // grab values in bit order
h = - 1; // no tables yet--level -1
w = - l; // bits decoded == (l * h)
u[0] = 0; // just to keep compilers happy
q = 0; // ditto
z = 0; // ditto
// go through the bit lengths (k already is bits in shortest code)
for (; k <= g; k++)
{
a = c[k];
while (a-- != 0)
{
// here i is the Huffman code of length k bits for value *p
// make tables up to required level
while (k > w + l)
{
h++;
w += l; // previous table always l bits
// compute minimum size table less than or equal to l bits
z = g - w;
z = (z > l)?l:z; // table size upper limit
if ((f = 1 << (j = k - w)) > a + 1)
{
// try a k-w bit table
// too few codes for k-w bit table
f -= (a + 1); // deduct codes from patterns left
xp = k;
if (j < z)
{
while (++j < z)
{
// try smaller tables up to z bits
if ((f <<= 1) <= c[++xp])
break; // enough codes to use up j bits
f -= c[xp]; // else deduct codes from patterns
}
}
}
z = 1 << j; // table entries for j-bit table
// allocate new table
if (hn[0] + z > MANY)
{
// (note: doesn't matter for fixed)
return Z_DATA_ERROR; // overflow of MANY
}
u[h] = q = hn[0]; // DEBUG
hn[0] += z;
// connect to last table, if there is one
if (h != 0)
{
x[h] = i; // save pattern for backing up
r[0] = (sbyte) j; // bits in this table
r[1] = (sbyte) l; // bits to dump before this table
j = SharedUtils.URShift(i, (w - l));
r[2] = (int) (q - u[h - 1] - j); // offset to this table
Array.Copy(r, 0, hp, (u[h - 1] + j) * 3, 3); // connect to last table
}
else
{
t[0] = q; // first table is returned result
}
}
// set up table entry in r
r[1] = (sbyte) (k - w);
if (p >= n)
{
r[0] = 128 + 64; // out of values--invalid code
}
else if (v[p] < s)
{
r[0] = (sbyte) (v[p] < 256?0:32 + 64); // 256 is end-of-block
r[2] = v[p++]; // simple code is just the value
}
else
{
r[0] = (sbyte) (e[v[p] - s] + 16 + 64); // non-simple--look up in lists
r[2] = d[v[p++] - s];
}
// fill code-like entries with r
f = 1 << (k - w);
for (j = SharedUtils.URShift(i, w); j < z; j += f)
{
Array.Copy(r, 0, hp, (q + j) * 3, 3);
}
// backwards increment the k-bit code i
for (j = 1 << (k - 1); (i & j) != 0; j = SharedUtils.URShift(j, 1))
{
i ^= j;
}
i ^= j;
// backup over finished tables
mask = (1 << w) - 1; // needed on HP, cc -O bug
while ((i & mask) != x[h])
{
h--; // don't need to update q
w -= l;
mask = (1 << w) - 1;
}
}
}
// Return Z_BUF_ERROR if we were given an incomplete table
return y != 0 && g != 1?Z_BUF_ERROR:Z_OK;
}
internal int inflate_trees_bits(int[] c, int[] bb, int[] tb, int[] hp, ZlibCodec z)
{
int result;
initWorkArea(19);
hn[0] = 0;
result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v);
if (result == Z_DATA_ERROR)
{
z.Message = "oversubscribed dynamic bit lengths tree";
}
else if (result == Z_BUF_ERROR || bb[0] == 0)
{
z.Message = "incomplete dynamic bit lengths tree";
result = Z_DATA_ERROR;
}
return result;
}
internal int inflate_trees_dynamic(int nl, int nd, int[] c, int[] bl, int[] bd, int[] tl, int[] td, int[] hp, ZlibCodec z)
{
int result;
// build literal/length tree
initWorkArea(288);
hn[0] = 0;
result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v);
if (result != Z_OK || bl[0] == 0)
{
if (result == Z_DATA_ERROR)
{
z.Message = "oversubscribed literal/length tree";
}
else if (result != Z_MEM_ERROR)
{
z.Message = "incomplete literal/length tree";
result = Z_DATA_ERROR;
}
return result;
}
// build distance tree
initWorkArea(288);
result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v);
if (result != Z_OK || (bd[0] == 0 && nl > 257))
{
if (result == Z_DATA_ERROR)
{
z.Message = "oversubscribed distance tree";
}
else if (result == Z_BUF_ERROR)
{
z.Message = "incomplete distance tree";
result = Z_DATA_ERROR;
}
else if (result != Z_MEM_ERROR)
{
z.Message = "empty distance tree with lengths";
result = Z_DATA_ERROR;
}
return result;
}
return Z_OK;
}
internal static int inflate_trees_fixed(int[] bl, int[] bd, int[][] tl, int[][] td, ZlibCodec z)
{
bl[0] = fixed_bl;
bd[0] = fixed_bd;
tl[0] = fixed_tl;
td[0] = fixed_td;
return Z_OK;
}
private void initWorkArea(int vsize)
{
if (hn == null)
{
hn = new int[1];
v = new int[vsize];
c = new int[BMAX + 1];
r = new int[3];
u = new int[BMAX];
x = new int[BMAX + 1];
}
else
{
if (v.Length < vsize)
{
v = new int[vsize];
}
Array.Clear(v,0,vsize);
Array.Clear(c,0,BMAX+1);
r[0]=0; r[1]=0; r[2]=0;
// for(int i=0; i<BMAX; i++){u[i]=0;}
//Array.Copy(c, 0, u, 0, BMAX);
Array.Clear(u,0,BMAX);
// for(int i=0; i<BMAX+1; i++){x[i]=0;}
//Array.Copy(c, 0, x, 0, BMAX + 1);
Array.Clear(x,0,BMAX+1);
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,423 +0,0 @@
// Tree.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2009-October-28 13:29:50>
//
// ------------------------------------------------------------------
//
// This module defines classes for zlib compression and
// decompression. This code is derived from the jzlib implementation of
// zlib. In keeping with the license for jzlib, the copyright to that
// code is below.
//
// ------------------------------------------------------------------
//
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the distribution.
//
// 3. The names of the authors may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------
//
// This program is based on zlib-1.1.3; credit to authors
// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
// and contributors of zlib.
//
// -----------------------------------------------------------------------
using System;
namespace Ionic.Zlib
{
sealed class Tree
{
private static readonly int HEAP_SIZE = (2 * InternalConstants.L_CODES + 1);
// extra bits for each length code
internal static readonly int[] ExtraLengthBits = new int[]
{
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
};
// extra bits for each distance code
internal static readonly int[] ExtraDistanceBits = new int[]
{
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13
};
// extra bits for each bit length code
internal static readonly int[] extra_blbits = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7};
internal static readonly sbyte[] bl_order = new sbyte[]{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
// The lengths of the bit length codes are sent in order of decreasing
// probability, to avoid transmitting the lengths for unused bit
// length codes.
internal const int Buf_size = 8 * 2;
// see definition of array dist_code below
//internal const int DIST_CODE_LEN = 512;
private static readonly sbyte[] _dist_code = new sbyte[]
{
0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21,
22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
};
internal static readonly sbyte[] LengthCode = new sbyte[]
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11,
12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17,
18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
};
internal static readonly int[] LengthBase = new int[]
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28,
32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0
};
internal static readonly int[] DistanceBase = new int[]
{
0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192,
256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
};
/// <summary>
/// Map from a distance to a distance code.
/// </summary>
/// <remarks>
/// No side effects. _dist_code[256] and _dist_code[257] are never used.
/// </remarks>
internal static int DistanceCode(int dist)
{
return (dist < 256)
? _dist_code[dist]
: _dist_code[256 + SharedUtils.URShift(dist, 7)];
}
internal short[] dyn_tree; // the dynamic tree
internal int max_code; // largest code with non zero frequency
internal StaticTree staticTree; // the corresponding static tree
// Compute the optimal bit lengths for a tree and update the total bit length
// for the current block.
// IN assertion: the fields freq and dad are set, heap[heap_max] and
// above are the tree nodes sorted by increasing frequency.
// OUT assertions: the field len is set to the optimal bit length, the
// array bl_count contains the frequencies for each bit length.
// The length opt_len is updated; static_len is also updated if stree is
// not null.
internal void gen_bitlen(DeflateManager s)
{
short[] tree = dyn_tree;
short[] stree = staticTree.treeCodes;
int[] extra = staticTree.extraBits;
int base_Renamed = staticTree.extraBase;
int max_length = staticTree.maxLength;
int h; // heap index
int n, m; // iterate over the tree elements
int bits; // bit length
int xbits; // extra bits
short f; // frequency
int overflow = 0; // number of elements with bit length too large
for (bits = 0; bits <= InternalConstants.MAX_BITS; bits++)
s.bl_count[bits] = 0;
// In a first pass, compute the optimal bit lengths (which may
// overflow in the case of the bit length tree).
tree[s.heap[s.heap_max] * 2 + 1] = 0; // root of the heap
for (h = s.heap_max + 1; h < HEAP_SIZE; h++)
{
n = s.heap[h];
bits = tree[tree[n * 2 + 1] * 2 + 1] + 1;
if (bits > max_length)
{
bits = max_length; overflow++;
}
tree[n * 2 + 1] = (short) bits;
// We overwrite tree[n*2+1] which is no longer needed
if (n > max_code)
continue; // not a leaf node
s.bl_count[bits]++;
xbits = 0;
if (n >= base_Renamed)
xbits = extra[n - base_Renamed];
f = tree[n * 2];
s.opt_len += f * (bits + xbits);
if (stree != null)
s.static_len += f * (stree[n * 2 + 1] + xbits);
}
if (overflow == 0)
return ;
// This happens for example on obj2 and pic of the Calgary corpus
// Find the first bit length which could increase:
do
{
bits = max_length - 1;
while (s.bl_count[bits] == 0)
bits--;
s.bl_count[bits]--; // move one leaf down the tree
s.bl_count[bits + 1] = (short) (s.bl_count[bits + 1] + 2); // move one overflow item as its brother
s.bl_count[max_length]--;
// The brother of the overflow item also moves one step up,
// but this does not affect bl_count[max_length]
overflow -= 2;
}
while (overflow > 0);
for (bits = max_length; bits != 0; bits--)
{
n = s.bl_count[bits];
while (n != 0)
{
m = s.heap[--h];
if (m > max_code)
continue;
if (tree[m * 2 + 1] != bits)
{
s.opt_len = (int) (s.opt_len + ((long) bits - (long) tree[m * 2 + 1]) * (long) tree[m * 2]);
tree[m * 2 + 1] = (short) bits;
}
n--;
}
}
}
// Construct one Huffman tree and assigns the code bit strings and lengths.
// Update the total bit length for the current block.
// IN assertion: the field freq is set for all tree elements.
// OUT assertions: the fields len and code are set to the optimal bit length
// and corresponding code. The length opt_len is updated; static_len is
// also updated if stree is not null. The field max_code is set.
internal void build_tree(DeflateManager s)
{
short[] tree = dyn_tree;
short[] stree = staticTree.treeCodes;
int elems = staticTree.elems;
int n, m; // iterate over heap elements
int max_code = -1; // largest code with non zero frequency
int node; // new node being created
// Construct the initial heap, with least frequent element in
// heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
// heap[0] is not used.
s.heap_len = 0;
s.heap_max = HEAP_SIZE;
for (n = 0; n < elems; n++)
{
if (tree[n * 2] != 0)
{
s.heap[++s.heap_len] = max_code = n;
s.depth[n] = 0;
}
else
{
tree[n * 2 + 1] = 0;
}
}
// The pkzip format requires that at least one distance code exists,
// and that at least one bit should be sent even if there is only one
// possible code. So to avoid special checks later on we force at least
// two codes of non zero frequency.
while (s.heap_len < 2)
{
node = s.heap[++s.heap_len] = (max_code < 2?++max_code:0);
tree[node * 2] = 1;
s.depth[node] = 0;
s.opt_len--;
if (stree != null)
s.static_len -= stree[node * 2 + 1];
// node is 0 or 1 so it does not have extra bits
}
this.max_code = max_code;
// The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
// establish sub-heaps of increasing lengths:
for (n = s.heap_len / 2; n >= 1; n--)
s.pqdownheap(tree, n);
// Construct the Huffman tree by repeatedly combining the least two
// frequent nodes.
node = elems; // next internal node of the tree
do
{
// n = node of least frequency
n = s.heap[1];
s.heap[1] = s.heap[s.heap_len--];
s.pqdownheap(tree, 1);
m = s.heap[1]; // m = node of next least frequency
s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency
s.heap[--s.heap_max] = m;
// Create a new node father of n and m
tree[node * 2] = unchecked((short) (tree[n * 2] + tree[m * 2]));
s.depth[node] = (sbyte) (System.Math.Max((byte) s.depth[n], (byte) s.depth[m]) + 1);
tree[n * 2 + 1] = tree[m * 2 + 1] = (short) node;
// and insert the new node in the heap
s.heap[1] = node++;
s.pqdownheap(tree, 1);
}
while (s.heap_len >= 2);
s.heap[--s.heap_max] = s.heap[1];
// At this point, the fields freq and dad are set. We can now
// generate the bit lengths.
gen_bitlen(s);
// The field len is now set, we can generate the bit codes
gen_codes(tree, max_code, s.bl_count);
}
// Generate the codes for a given tree and bit counts (which need not be
// optimal).
// IN assertion: the array bl_count contains the bit length statistics for
// the given tree and the field len is set for all tree elements.
// OUT assertion: the field code is set for all tree elements of non
// zero code length.
internal static void gen_codes(short[] tree, int max_code, short[] bl_count)
{
short[] next_code = new short[InternalConstants.MAX_BITS + 1]; // next code value for each bit length
short code = 0; // running code value
int bits; // bit index
int n; // code index
// The distribution counts are first used to generate the code values
// without bit reversal.
for (bits = 1; bits <= InternalConstants.MAX_BITS; bits++)
unchecked {
next_code[bits] = code = (short) ((code + bl_count[bits - 1]) << 1);
}
// Check that the bit counts in bl_count are consistent. The last code
// must be all ones.
//Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
// "inconsistent bit counts");
//Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
for (n = 0; n <= max_code; n++)
{
int len = tree[n * 2 + 1];
if (len == 0)
continue;
// Now reverse the bits
tree[n * 2] = unchecked((short) (bi_reverse(next_code[len]++, len)));
}
}
// Reverse the first len bits of a code, using straightforward code (a faster
// method would use a table)
// IN assertion: 1 <= len <= 15
internal static int bi_reverse(int code, int len)
{
int res = 0;
do
{
res |= code & 1;
code >>= 1; //SharedUtils.URShift(code, 1);
res <<= 1;
}
while (--len > 0);
return res >> 1;
}
}
}

View file

@ -1,116 +0,0 @@
// ComHelper.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009 Dino Chiesa.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2011-June-13 17:04:06>
//
// ------------------------------------------------------------------
//
// This module defines a COM Helper class.
//
// Created: Tue, 08 Sep 2009 22:03
//
using Interop=System.Runtime.InteropServices;
namespace Ionic.Zip
{
/// <summary>
/// This class exposes a set of COM-accessible wrappers for static
/// methods available on the ZipFile class. You don't need this
/// class unless you are using DotNetZip from a COM environment.
/// </summary>
[System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000F")]
[System.Runtime.InteropServices.ComVisible(true)]
#if !NETCF
[System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.AutoDispatch)]
#endif
public class ComHelper
{
/// <summary>
/// A wrapper for <see cref="ZipFile.IsZipFile(string)">ZipFile.IsZipFile(string)</see>
/// </summary>
/// <param name="filename">The filename to of the zip file to check.</param>
/// <returns>true if the file contains a valid zip file.</returns>
public bool IsZipFile(string filename)
{
return ZipFile.IsZipFile(filename);
}
/// <summary>
/// A wrapper for <see cref="ZipFile.IsZipFile(string, bool)">ZipFile.IsZipFile(string, bool)</see>
/// </summary>
/// <remarks>
/// We cannot use "overloaded" Method names in COM interop.
/// So, here, we use a unique name.
/// </remarks>
/// <param name="filename">The filename to of the zip file to check.</param>
/// <returns>true if the file contains a valid zip file.</returns>
public bool IsZipFileWithExtract(string filename)
{
return ZipFile.IsZipFile(filename, true);
}
#if !NETCF
/// <summary>
/// A wrapper for <see cref="ZipFile.CheckZip(string)">ZipFile.CheckZip(string)</see>
/// </summary>
/// <param name="filename">The filename to of the zip file to check.</param>
///
/// <returns>true if the named zip file checks OK. Otherwise, false. </returns>
public bool CheckZip(string filename)
{
return ZipFile.CheckZip(filename);
}
/// <summary>
/// A COM-friendly wrapper for the static method <see cref="ZipFile.CheckZipPassword(string,string)"/>.
/// </summary>
///
/// <param name="filename">The filename to of the zip file to check.</param>
///
/// <param name="password">The password to check.</param>
///
/// <returns>true if the named zip file checks OK. Otherwise, false. </returns>
public bool CheckZipPassword(string filename, string password)
{
return ZipFile.CheckZipPassword(filename, password);
}
/// <summary>
/// A wrapper for <see cref="ZipFile.FixZipDirectory(string)">ZipFile.FixZipDirectory(string)</see>
/// </summary>
/// <param name="filename">The filename to of the zip file to fix.</param>
public void FixZipDirectory(string filename)
{
ZipFile.FixZipDirectory(filename);
}
#endif
/// <summary>
/// A wrapper for <see cref="ZipFile.LibraryVersion">ZipFile.LibraryVersion</see>
/// </summary>
/// <returns>
/// the version number on the DotNetZip assembly, formatted as a string.
/// </returns>
public string GetZipLibraryVersion()
{
return ZipFile.LibraryVersion.ToString();
}
}
}

View file

@ -1,135 +0,0 @@
// EncryptionAlgorithm.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009 Dino Chiesa
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2009-October-21 17:24:45>
//
// ------------------------------------------------------------------
//
// This module defines the EncryptionAgorithm enum
//
//
// ------------------------------------------------------------------
namespace Ionic.Zip
{
/// <summary>
/// An enum that provides the various encryption algorithms supported by this
/// library.
/// </summary>
///
/// <remarks>
///
/// <para>
/// <c>PkzipWeak</c> implies the use of Zip 2.0 encryption, which is known to be
/// weak and subvertible.
/// </para>
///
/// <para>
/// A note on interoperability: Values of <c>PkzipWeak</c> and <c>None</c> are
/// specified in <see
/// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE's zip
/// specification</see>, and are considered to be "standard". Zip archives
/// produced using these options will be interoperable with many other zip tools
/// and libraries, including Windows Explorer.
/// </para>
///
/// <para>
/// Values of <c>WinZipAes128</c> and <c>WinZipAes256</c> are not part of the Zip
/// specification, but rather imply the use of a vendor-specific extension from
/// WinZip. If you want to produce interoperable Zip archives, do not use these
/// values. For example, if you produce a zip archive using WinZipAes256, you
/// will be able to open it in Windows Explorer on Windows XP and Vista, but you
/// will not be able to extract entries; trying this will lead to an "unspecified
/// error". For this reason, some people have said that a zip archive that uses
/// WinZip's AES encryption is not actually a zip archive at all. A zip archive
/// produced this way will be readable with the WinZip tool (Version 11 and
/// beyond).
/// </para>
///
/// <para>
/// There are other third-party tools and libraries, both commercial and
/// otherwise, that support WinZip's AES encryption. These will be able to read
/// AES-encrypted zip archives produced by DotNetZip, and conversely applications
/// that use DotNetZip to read zip archives will be able to read AES-encrypted
/// archives produced by those tools or libraries. Consult the documentation for
/// those other tools and libraries to find out if WinZip's AES encryption is
/// supported.
/// </para>
///
/// <para>
/// In case you care: According to <see
/// href="http://www.winzip.com/aes_info.htm">the WinZip specification</see>, the
/// actual AES key used is derived from the <see cref="ZipEntry.Password"/> via an
/// algorithm that complies with <see
/// href="http://www.ietf.org/rfc/rfc2898.txt">RFC 2898</see>, using an iteration
/// count of 1000. The algorithm is sometimes referred to as PBKDF2, which stands
/// for "Password Based Key Derivation Function #2".
/// </para>
///
/// <para>
/// A word about password strength and length: The AES encryption technology is
/// very good, but any system is only as secure as the weakest link. If you want
/// to secure your data, be sure to use a password that is hard to guess. To make
/// it harder to guess (increase its "entropy"), you should make it longer. If
/// you use normal characters from an ASCII keyboard, a password of length 20 will
/// be strong enough that it will be impossible to guess. For more information on
/// that, I'd encourage you to read <see
/// href="http://www.redkestrel.co.uk/Articles/RandomPasswordStrength.html">this
/// article.</see>
/// </para>
///
/// <para>
/// The WinZip AES algorithms are not supported with the version of DotNetZip that
/// runs on the .NET Compact Framework. This is because .NET CF lacks the
/// HMACSHA1 class that is required for producing the archive.
/// </para>
/// </remarks>
public enum EncryptionAlgorithm
{
/// <summary>
/// No encryption at all.
/// </summary>
None = 0,
/// <summary>
/// Traditional or Classic pkzip encryption.
/// </summary>
PkzipWeak,
#if AESCRYPTO
/// <summary>
/// WinZip AES encryption (128 key bits).
/// </summary>
WinZipAes128,
/// <summary>
/// WinZip AES encryption (256 key bits).
/// </summary>
WinZipAes256,
#endif
/// <summary>
/// An encryption algorithm that is not supported by DotNetZip.
/// </summary>
Unsupported = 4,
// others... not implemented (yet?)
}
}

View file

@ -1,684 +0,0 @@
// Events.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2006, 2007, 2008, 2009 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2011-August-06 12:26:24>
//
// ------------------------------------------------------------------
//
// This module defines events used by the ZipFile class.
//
//
using System;
using System.Collections.Generic;
using System.Text;
namespace Ionic.Zip
{
/// <summary>
/// Delegate in which the application writes the <c>ZipEntry</c> content for the named entry.
/// </summary>
///
/// <param name="entryName">The name of the entry that must be written.</param>
/// <param name="stream">The stream to which the entry data should be written.</param>
///
/// <remarks>
/// When you add an entry and specify a <c>WriteDelegate</c>, via <see
/// cref="Ionic.Zip.ZipFile.AddEntry(string, WriteDelegate)"/>, the application
/// code provides the logic that writes the entry data directly into the zip file.
/// </remarks>
///
/// <example>
///
/// This example shows how to define a WriteDelegate that obtains a DataSet, and then
/// writes the XML for the DataSet into the zip archive. There's no need to
/// save the XML to a disk file first.
///
/// <code lang="C#">
/// private void WriteEntry (String filename, Stream output)
/// {
/// DataSet ds1 = ObtainDataSet();
/// ds1.WriteXml(output);
/// }
///
/// private void Run()
/// {
/// using (var zip = new ZipFile())
/// {
/// zip.AddEntry(zipEntryName, WriteEntry);
/// zip.Save(zipFileName);
/// }
/// }
/// </code>
///
/// <code lang="vb">
/// Private Sub WriteEntry (ByVal filename As String, ByVal output As Stream)
/// DataSet ds1 = ObtainDataSet()
/// ds1.WriteXml(stream)
/// End Sub
///
/// Public Sub Run()
/// Using zip = New ZipFile
/// zip.AddEntry(zipEntryName, New WriteDelegate(AddressOf WriteEntry))
/// zip.Save(zipFileName)
/// End Using
/// End Sub
/// </code>
/// </example>
/// <seealso cref="Ionic.Zip.ZipFile.AddEntry(string, WriteDelegate)"/>
public delegate void WriteDelegate(string entryName, System.IO.Stream stream);
/// <summary>
/// Delegate in which the application opens the stream, just-in-time, for the named entry.
/// </summary>
///
/// <param name="entryName">
/// The name of the ZipEntry that the application should open the stream for.
/// </param>
///
/// <remarks>
/// When you add an entry via <see cref="Ionic.Zip.ZipFile.AddEntry(string,
/// OpenDelegate, CloseDelegate)"/>, the application code provides the logic that
/// opens and closes the stream for the given ZipEntry.
/// </remarks>
///
/// <seealso cref="Ionic.Zip.ZipFile.AddEntry(string, OpenDelegate, CloseDelegate)"/>
public delegate System.IO.Stream OpenDelegate(string entryName);
/// <summary>
/// Delegate in which the application closes the stream, just-in-time, for the named entry.
/// </summary>
///
/// <param name="entryName">
/// The name of the ZipEntry that the application should close the stream for.
/// </param>
///
/// <param name="stream">The stream to be closed.</param>
///
/// <remarks>
/// When you add an entry via <see cref="Ionic.Zip.ZipFile.AddEntry(string,
/// OpenDelegate, CloseDelegate)"/>, the application code provides the logic that
/// opens and closes the stream for the given ZipEntry.
/// </remarks>
///
/// <seealso cref="Ionic.Zip.ZipFile.AddEntry(string, OpenDelegate, CloseDelegate)"/>
public delegate void CloseDelegate(string entryName, System.IO.Stream stream);
/// <summary>
/// Delegate for the callback by which the application tells the
/// library the CompressionLevel to use for a file.
/// </summary>
///
/// <remarks>
/// <para>
/// Using this callback, the application can, for example, specify that
/// previously-compressed files (.mp3, .png, .docx, etc) should use a
/// <c>CompressionLevel</c> of <c>None</c>, or can set the compression level based
/// on any other factor.
/// </para>
/// </remarks>
/// <seealso cref="Ionic.Zip.ZipFile.SetCompression"/>
public delegate Ionic.Zlib.CompressionLevel SetCompressionCallback(string localFileName, string fileNameInArchive);
/// <summary>
/// In an EventArgs type, indicates which sort of progress event is being
/// reported.
/// </summary>
/// <remarks>
/// There are events for reading, events for saving, and events for
/// extracting. This enumeration allows a single EventArgs type to be sued to
/// describe one of multiple subevents. For example, a SaveProgress event is
/// invoked before, after, and during the saving of a single entry. The value
/// of an enum with this type, specifies which event is being triggered. The
/// same applies to Extraction, Reading and Adding events.
/// </remarks>
public enum ZipProgressEventType
{
/// <summary>
/// Indicates that a Add() operation has started.
/// </summary>
Adding_Started,
/// <summary>
/// Indicates that an individual entry in the archive has been added.
/// </summary>
Adding_AfterAddEntry,
/// <summary>
/// Indicates that a Add() operation has completed.
/// </summary>
Adding_Completed,
/// <summary>
/// Indicates that a Read() operation has started.
/// </summary>
Reading_Started,
/// <summary>
/// Indicates that an individual entry in the archive is about to be read.
/// </summary>
Reading_BeforeReadEntry,
/// <summary>
/// Indicates that an individual entry in the archive has just been read.
/// </summary>
Reading_AfterReadEntry,
/// <summary>
/// Indicates that a Read() operation has completed.
/// </summary>
Reading_Completed,
/// <summary>
/// The given event reports the number of bytes read so far
/// during a Read() operation.
/// </summary>
Reading_ArchiveBytesRead,
/// <summary>
/// Indicates that a Save() operation has started.
/// </summary>
Saving_Started,
/// <summary>
/// Indicates that an individual entry in the archive is about to be written.
/// </summary>
Saving_BeforeWriteEntry,
/// <summary>
/// Indicates that an individual entry in the archive has just been saved.
/// </summary>
Saving_AfterWriteEntry,
/// <summary>
/// Indicates that a Save() operation has completed.
/// </summary>
Saving_Completed,
/// <summary>
/// Indicates that the zip archive has been created in a
/// temporary location during a Save() operation.
/// </summary>
Saving_AfterSaveTempArchive,
/// <summary>
/// Indicates that the temporary file is about to be renamed to the final archive
/// name during a Save() operation.
/// </summary>
Saving_BeforeRenameTempArchive,
/// <summary>
/// Indicates that the temporary file is has just been renamed to the final archive
/// name during a Save() operation.
/// </summary>
Saving_AfterRenameTempArchive,
/// <summary>
/// Indicates that the self-extracting archive has been compiled
/// during a Save() operation.
/// </summary>
Saving_AfterCompileSelfExtractor,
/// <summary>
/// The given event is reporting the number of source bytes that have run through the compressor so far
/// during a Save() operation.
/// </summary>
Saving_EntryBytesRead,
/// <summary>
/// Indicates that an entry is about to be extracted.
/// </summary>
Extracting_BeforeExtractEntry,
/// <summary>
/// Indicates that an entry has just been extracted.
/// </summary>
Extracting_AfterExtractEntry,
/// <summary>
/// Indicates that extraction of an entry would overwrite an existing
/// filesystem file. You must use
/// <see cref="ExtractExistingFileAction.InvokeExtractProgressEvent">
/// ExtractExistingFileAction.InvokeExtractProgressEvent</see> in the call
/// to <c>ZipEntry.Extract()</c> in order to receive this event.
/// </summary>
Extracting_ExtractEntryWouldOverwrite,
/// <summary>
/// The given event is reporting the number of bytes written so far for
/// the current entry during an Extract() operation.
/// </summary>
Extracting_EntryBytesWritten,
/// <summary>
/// Indicates that an ExtractAll operation is about to begin.
/// </summary>
Extracting_BeforeExtractAll,
/// <summary>
/// Indicates that an ExtractAll operation has completed.
/// </summary>
Extracting_AfterExtractAll,
/// <summary>
/// Indicates that an error has occurred while saving a zip file.
/// This generally means the file cannot be opened, because it has been
/// removed, or because it is locked by another process. It can also
/// mean that the file cannot be Read, because of a range lock conflict.
/// </summary>
Error_Saving,
}
/// <summary>
/// Provides information about the progress of a save, read, or extract operation.
/// This is a base class; you will probably use one of the classes derived from this one.
/// </summary>
public class ZipProgressEventArgs : EventArgs
{
private int _entriesTotal;
private bool _cancel;
private ZipEntry _latestEntry;
private ZipProgressEventType _flavor;
private String _archiveName;
private Int64 _bytesTransferred;
private Int64 _totalBytesToTransfer;
internal ZipProgressEventArgs() { }
internal ZipProgressEventArgs(string archiveName, ZipProgressEventType flavor)
{
this._archiveName = archiveName;
this._flavor = flavor;
}
/// <summary>
/// The total number of entries to be saved or extracted.
/// </summary>
public int EntriesTotal
{
get { return _entriesTotal; }
set { _entriesTotal = value; }
}
/// <summary>
/// The name of the last entry saved or extracted.
/// </summary>
public ZipEntry CurrentEntry
{
get { return _latestEntry; }
set { _latestEntry = value; }
}
/// <summary>
/// In an event handler, set this to cancel the save or extract
/// operation that is in progress.
/// </summary>
public bool Cancel
{
get { return _cancel; }
set { _cancel = _cancel || value; }
}
/// <summary>
/// The type of event being reported.
/// </summary>
public ZipProgressEventType EventType
{
get { return _flavor; }
set { _flavor = value; }
}
/// <summary>
/// Returns the archive name associated to this event.
/// </summary>
public String ArchiveName
{
get { return _archiveName; }
set { _archiveName = value; }
}
/// <summary>
/// The number of bytes read or written so far for this entry.
/// </summary>
public Int64 BytesTransferred
{
get { return _bytesTransferred; }
set { _bytesTransferred = value; }
}
/// <summary>
/// Total number of bytes that will be read or written for this entry.
/// This number will be -1 if the value cannot be determined.
/// </summary>
public Int64 TotalBytesToTransfer
{
get { return _totalBytesToTransfer; }
set { _totalBytesToTransfer = value; }
}
}
/// <summary>
/// Provides information about the progress of a Read operation.
/// </summary>
public class ReadProgressEventArgs : ZipProgressEventArgs
{
internal ReadProgressEventArgs() { }
private ReadProgressEventArgs(string archiveName, ZipProgressEventType flavor)
: base(archiveName, flavor)
{ }
internal static ReadProgressEventArgs Before(string archiveName, int entriesTotal)
{
var x = new ReadProgressEventArgs(archiveName, ZipProgressEventType.Reading_BeforeReadEntry);
x.EntriesTotal = entriesTotal;
return x;
}
internal static ReadProgressEventArgs After(string archiveName, ZipEntry entry, int entriesTotal)
{
var x = new ReadProgressEventArgs(archiveName, ZipProgressEventType.Reading_AfterReadEntry);
x.EntriesTotal = entriesTotal;
x.CurrentEntry = entry;
return x;
}
internal static ReadProgressEventArgs Started(string archiveName)
{
var x = new ReadProgressEventArgs(archiveName, ZipProgressEventType.Reading_Started);
return x;
}
internal static ReadProgressEventArgs ByteUpdate(string archiveName, ZipEntry entry, Int64 bytesXferred, Int64 totalBytes)
{
var x = new ReadProgressEventArgs(archiveName, ZipProgressEventType.Reading_ArchiveBytesRead);
x.CurrentEntry = entry;
x.BytesTransferred = bytesXferred;
x.TotalBytesToTransfer = totalBytes;
return x;
}
internal static ReadProgressEventArgs Completed(string archiveName)
{
var x = new ReadProgressEventArgs(archiveName, ZipProgressEventType.Reading_Completed);
return x;
}
}
/// <summary>
/// Provides information about the progress of a Add operation.
/// </summary>
public class AddProgressEventArgs : ZipProgressEventArgs
{
internal AddProgressEventArgs() { }
private AddProgressEventArgs(string archiveName, ZipProgressEventType flavor)
: base(archiveName, flavor)
{ }
internal static AddProgressEventArgs AfterEntry(string archiveName, ZipEntry entry, int entriesTotal)
{
var x = new AddProgressEventArgs(archiveName, ZipProgressEventType.Adding_AfterAddEntry);
x.EntriesTotal = entriesTotal;
x.CurrentEntry = entry;
return x;
}
internal static AddProgressEventArgs Started(string archiveName)
{
var x = new AddProgressEventArgs(archiveName, ZipProgressEventType.Adding_Started);
return x;
}
internal static AddProgressEventArgs Completed(string archiveName)
{
var x = new AddProgressEventArgs(archiveName, ZipProgressEventType.Adding_Completed);
return x;
}
}
/// <summary>
/// Provides information about the progress of a save operation.
/// </summary>
public class SaveProgressEventArgs : ZipProgressEventArgs
{
private int _entriesSaved;
/// <summary>
/// Constructor for the SaveProgressEventArgs.
/// </summary>
/// <param name="archiveName">the name of the zip archive.</param>
/// <param name="before">whether this is before saving the entry, or after</param>
/// <param name="entriesTotal">The total number of entries in the zip archive.</param>
/// <param name="entriesSaved">Number of entries that have been saved.</param>
/// <param name="entry">The entry involved in the event.</param>
internal SaveProgressEventArgs(string archiveName, bool before, int entriesTotal, int entriesSaved, ZipEntry entry)
: base(archiveName, (before) ? ZipProgressEventType.Saving_BeforeWriteEntry : ZipProgressEventType.Saving_AfterWriteEntry)
{
this.EntriesTotal = entriesTotal;
this.CurrentEntry = entry;
this._entriesSaved = entriesSaved;
}
internal SaveProgressEventArgs() { }
internal SaveProgressEventArgs(string archiveName, ZipProgressEventType flavor)
: base(archiveName, flavor)
{ }
internal static SaveProgressEventArgs ByteUpdate(string archiveName, ZipEntry entry, Int64 bytesXferred, Int64 totalBytes)
{
var x = new SaveProgressEventArgs(archiveName, ZipProgressEventType.Saving_EntryBytesRead);
x.ArchiveName = archiveName;
x.CurrentEntry = entry;
x.BytesTransferred = bytesXferred;
x.TotalBytesToTransfer = totalBytes;
return x;
}
internal static SaveProgressEventArgs Started(string archiveName)
{
var x = new SaveProgressEventArgs(archiveName, ZipProgressEventType.Saving_Started);
return x;
}
internal static SaveProgressEventArgs Completed(string archiveName)
{
var x = new SaveProgressEventArgs(archiveName, ZipProgressEventType.Saving_Completed);
return x;
}
/// <summary>
/// Number of entries saved so far.
/// </summary>
public int EntriesSaved
{
get { return _entriesSaved; }
}
}
/// <summary>
/// Provides information about the progress of the extract operation.
/// </summary>
public class ExtractProgressEventArgs : ZipProgressEventArgs
{
private int _entriesExtracted;
private string _target;
/// <summary>
/// Constructor for the ExtractProgressEventArgs.
/// </summary>
/// <param name="archiveName">the name of the zip archive.</param>
/// <param name="before">whether this is before saving the entry, or after</param>
/// <param name="entriesTotal">The total number of entries in the zip archive.</param>
/// <param name="entriesExtracted">Number of entries that have been extracted.</param>
/// <param name="entry">The entry involved in the event.</param>
/// <param name="extractLocation">The location to which entries are extracted.</param>
internal ExtractProgressEventArgs(string archiveName, bool before, int entriesTotal, int entriesExtracted, ZipEntry entry, string extractLocation)
: base(archiveName, (before) ? ZipProgressEventType.Extracting_BeforeExtractEntry : ZipProgressEventType.Extracting_AfterExtractEntry)
{
this.EntriesTotal = entriesTotal;
this.CurrentEntry = entry;
this._entriesExtracted = entriesExtracted;
this._target = extractLocation;
}
internal ExtractProgressEventArgs(string archiveName, ZipProgressEventType flavor)
: base(archiveName, flavor)
{ }
internal ExtractProgressEventArgs()
{ }
internal static ExtractProgressEventArgs BeforeExtractEntry(string archiveName, ZipEntry entry, string extractLocation)
{
var x = new ExtractProgressEventArgs
{
ArchiveName = archiveName,
EventType = ZipProgressEventType.Extracting_BeforeExtractEntry,
CurrentEntry = entry,
_target = extractLocation,
};
return x;
}
internal static ExtractProgressEventArgs ExtractExisting(string archiveName, ZipEntry entry, string extractLocation)
{
var x = new ExtractProgressEventArgs
{
ArchiveName = archiveName,
EventType = ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite,
CurrentEntry = entry,
_target = extractLocation,
};
return x;
}
internal static ExtractProgressEventArgs AfterExtractEntry(string archiveName, ZipEntry entry, string extractLocation)
{
var x = new ExtractProgressEventArgs
{
ArchiveName = archiveName,
EventType = ZipProgressEventType.Extracting_AfterExtractEntry,
CurrentEntry = entry,
_target = extractLocation,
};
return x;
}
internal static ExtractProgressEventArgs ExtractAllStarted(string archiveName, string extractLocation)
{
var x = new ExtractProgressEventArgs(archiveName, ZipProgressEventType.Extracting_BeforeExtractAll);
x._target = extractLocation;
return x;
}
internal static ExtractProgressEventArgs ExtractAllCompleted(string archiveName, string extractLocation)
{
var x = new ExtractProgressEventArgs(archiveName, ZipProgressEventType.Extracting_AfterExtractAll);
x._target = extractLocation;
return x;
}
internal static ExtractProgressEventArgs ByteUpdate(string archiveName, ZipEntry entry, Int64 bytesWritten, Int64 totalBytes)
{
var x = new ExtractProgressEventArgs(archiveName, ZipProgressEventType.Extracting_EntryBytesWritten);
x.ArchiveName = archiveName;
x.CurrentEntry = entry;
x.BytesTransferred = bytesWritten;
x.TotalBytesToTransfer = totalBytes;
return x;
}
/// <summary>
/// Number of entries extracted so far. This is set only if the
/// EventType is Extracting_BeforeExtractEntry or Extracting_AfterExtractEntry, and
/// the Extract() is occurring witin the scope of a call to ExtractAll().
/// </summary>
public int EntriesExtracted
{
get { return _entriesExtracted; }
}
/// <summary>
/// Returns the extraction target location, a filesystem path.
/// </summary>
public String ExtractLocation
{
get { return _target; }
}
}
/// <summary>
/// Provides information about the an error that occurred while zipping.
/// </summary>
public class ZipErrorEventArgs : ZipProgressEventArgs
{
private Exception _exc;
private ZipErrorEventArgs() { }
internal static ZipErrorEventArgs Saving(string archiveName, ZipEntry entry, Exception exception)
{
var x = new ZipErrorEventArgs
{
EventType = ZipProgressEventType.Error_Saving,
ArchiveName = archiveName,
CurrentEntry = entry,
_exc = exception
};
return x;
}
/// <summary>
/// Returns the exception that occurred, if any.
/// </summary>
public Exception @Exception
{
get { return _exc; }
}
/// <summary>
/// Returns the name of the file that caused the exception, if any.
/// </summary>
public String FileName
{
get { return CurrentEntry.LocalFileName; }
}
}
}

View file

@ -1,300 +0,0 @@
// Exceptions.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2008, 2009 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2011-July-12 12:19:10>
//
// ------------------------------------------------------------------
//
// This module defines exceptions used in the class library.
//
using System;
using System.Collections.Generic;
using System.Text;
#if !NETCF
using System.Runtime.Serialization;
#endif
namespace Ionic.Zip
{
///// <summary>
///// Base exception type for all custom exceptions in the Zip library. It acts as a marker class.
///// </summary>
//[AttributeUsage(AttributeTargets.Class)]
//public class ZipExceptionAttribute : Attribute { }
/// <summary>
/// Issued when an <c>ZipEntry.ExtractWithPassword()</c> method is invoked
/// with an incorrect password.
/// </summary>
#if !SILVERLIGHT
[Serializable]
#endif
[System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000B")]
public class BadPasswordException : ZipException
{
/// <summary>
/// Default ctor.
/// </summary>
public BadPasswordException() { }
/// <summary>
/// Come on, you know how exceptions work. Why are you looking at this documentation?
/// </summary>
/// <param name="message">The message in the exception.</param>
public BadPasswordException(String message)
: base(message)
{ }
/// <summary>
/// Come on, you know how exceptions work. Why are you looking at this documentation?
/// </summary>
/// <param name="message">The message in the exception.</param>
/// <param name="innerException">The innerException for this exception.</param>
public BadPasswordException(String message, Exception innerException)
: base(message, innerException)
{
}
#if ! (NETCF || SILVERLIGHT)
/// <summary>
/// Come on, you know how exceptions work. Why are you looking at this documentation?
/// </summary>
/// <param name="info">The serialization info for the exception.</param>
/// <param name="context">The streaming context from which to deserialize.</param>
protected BadPasswordException(SerializationInfo info, StreamingContext context)
: base(info, context)
{ }
#endif
}
/// <summary>
/// Indicates that a read was attempted on a stream, and bad or incomplete data was
/// received.
/// </summary>
#if !SILVERLIGHT
[Serializable]
#endif
[System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000A")]
public class BadReadException : ZipException
{
/// <summary>
/// Default ctor.
/// </summary>
public BadReadException() { }
/// <summary>
/// Come on, you know how exceptions work. Why are you looking at this documentation?
/// </summary>
/// <param name="message">The message in the exception.</param>
public BadReadException(String message)
: base(message)
{ }
/// <summary>
/// Come on, you know how exceptions work. Why are you looking at this documentation?
/// </summary>
/// <param name="message">The message in the exception.</param>
/// <param name="innerException">The innerException for this exception.</param>
public BadReadException(String message, Exception innerException)
: base(message, innerException)
{
}
#if ! (NETCF || SILVERLIGHT)
/// <summary>
/// Come on, you know how exceptions work. Why are you looking at this documentation?
/// </summary>
/// <param name="info">The serialization info for the exception.</param>
/// <param name="context">The streaming context from which to deserialize.</param>
protected BadReadException(SerializationInfo info, StreamingContext context)
: base(info, context)
{ }
#endif
}
/// <summary>
/// Issued when an CRC check fails upon extracting an entry from a zip archive.
/// </summary>
#if !SILVERLIGHT
[Serializable]
#endif
[System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d00009")]
public class BadCrcException : ZipException
{
/// <summary>
/// Default ctor.
/// </summary>
public BadCrcException() { }
/// <summary>
/// Come on, you know how exceptions work. Why are you looking at this documentation?
/// </summary>
/// <param name="message">The message in the exception.</param>
public BadCrcException(String message)
: base(message)
{ }
#if ! (NETCF || SILVERLIGHT)
/// <summary>
/// Come on, you know how exceptions work. Why are you looking at this documentation?
/// </summary>
/// <param name="info">The serialization info for the exception.</param>
/// <param name="context">The streaming context from which to deserialize.</param>
protected BadCrcException(SerializationInfo info, StreamingContext context)
: base(info, context)
{ }
#endif
}
/// <summary>
/// Issued when errors occur saving a self-extracting archive.
/// </summary>
#if !SILVERLIGHT
[Serializable]
#endif
[System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d00008")]
public class SfxGenerationException : ZipException
{
/// <summary>
/// Default ctor.
/// </summary>
public SfxGenerationException() { }
/// <summary>
/// Come on, you know how exceptions work. Why are you looking at this documentation?
/// </summary>
/// <param name="message">The message in the exception.</param>
public SfxGenerationException(String message)
: base(message)
{ }
#if ! (NETCF || SILVERLIGHT)
/// <summary>
/// Come on, you know how exceptions work. Why are you looking at this documentation?
/// </summary>
/// <param name="info">The serialization info for the exception.</param>
/// <param name="context">The streaming context from which to deserialize.</param>
protected SfxGenerationException(SerializationInfo info, StreamingContext context)
: base(info, context)
{ }
#endif
}
/// <summary>
/// Indicates that an operation was attempted on a ZipFile which was not possible
/// given the state of the instance. For example, if you call <c>Save()</c> on a ZipFile
/// which has no filename set, you can get this exception.
/// </summary>
#if !SILVERLIGHT
[Serializable]
#endif
[System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d00007")]
public class BadStateException : ZipException
{
/// <summary>
/// Default ctor.
/// </summary>
public BadStateException() { }
/// <summary>
/// Come on, you know how exceptions work. Why are you looking at this documentation?
/// </summary>
/// <param name="message">The message in the exception.</param>
public BadStateException(String message)
: base(message)
{ }
/// <summary>
/// Come on, you know how exceptions work. Why are you looking at this documentation?
/// </summary>
/// <param name="message">The message in the exception.</param>
/// <param name="innerException">The innerException for this exception.</param>
public BadStateException(String message, Exception innerException)
: base(message, innerException)
{}
#if ! (NETCF || SILVERLIGHT)
/// <summary>
/// Come on, you know how exceptions work. Why are you looking at this documentation?
/// </summary>
/// <param name="info">The serialization info for the exception.</param>
/// <param name="context">The streaming context from which to deserialize.</param>
protected BadStateException(SerializationInfo info, StreamingContext context)
: base(info, context)
{ }
#endif
}
/// <summary>
/// Base class for all exceptions defined by and throw by the Zip library.
/// </summary>
#if !SILVERLIGHT
[Serializable]
#endif
[System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d00006")]
public class ZipException : Exception
{
/// <summary>
/// Default ctor.
/// </summary>
public ZipException() { }
/// <summary>
/// Come on, you know how exceptions work. Why are you looking at this documentation?
/// </summary>
/// <param name="message">The message in the exception.</param>
public ZipException(String message) : base(message) { }
/// <summary>
/// Come on, you know how exceptions work. Why are you looking at this documentation?
/// </summary>
/// <param name="message">The message in the exception.</param>
/// <param name="innerException">The innerException for this exception.</param>
public ZipException(String message, Exception innerException)
: base(message, innerException)
{ }
#if ! (NETCF || SILVERLIGHT)
/// <summary>
/// Come on, you know how exceptions work. Why are you looking at this documentation?
/// </summary>
/// <param name="info">The serialization info for the exception.</param>
/// <param name="context">The streaming context from which to deserialize.</param>
protected ZipException(SerializationInfo info, StreamingContext context)
: base(info, context)
{ }
#endif
}
}

View file

@ -1,85 +0,0 @@
// ExtractExistingFileAction.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009 Dino Chiesa
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2009-August-25 08:44:37>
//
// ------------------------------------------------------------------
//
// This module defines the ExtractExistingFileAction enum
//
//
// ------------------------------------------------------------------
namespace Ionic.Zip
{
/// <summary>
/// An enum for the options when extracting an entry would overwrite an existing file.
/// </summary>
///
/// <remarks>
/// <para>
/// This enum describes the actions that the library can take when an
/// <c>Extract()</c> or <c>ExtractWithPassword()</c> method is called to extract an
/// entry to a filesystem, and the extraction would overwrite an existing filesystem
/// file.
/// </para>
/// </remarks>
///
public enum ExtractExistingFileAction
{
/// <summary>
/// Throw an exception when extraction would overwrite an existing file. (For
/// COM clients, this is a 0 (zero).)
/// </summary>
Throw,
/// <summary>
/// When extraction would overwrite an existing file, overwrite the file silently.
/// The overwrite will happen even if the target file is marked as read-only.
/// (For COM clients, this is a 1.)
/// </summary>
OverwriteSilently,
/// <summary>
/// When extraction would overwrite an existing file, don't overwrite the file, silently.
/// (For COM clients, this is a 2.)
/// </summary>
DoNotOverwrite,
/// <summary>
/// When extraction would overwrite an existing file, invoke the ExtractProgress
/// event, using an event type of <see
/// cref="ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite"/>. In
/// this way, the application can decide, just-in-time, whether to overwrite the
/// file. For example, a GUI application may wish to pop up a dialog to allow
/// the user to choose. You may want to examine the <see
/// cref="ExtractProgressEventArgs.ExtractLocation"/> property before making
/// the decision. If, after your processing in the Extract progress event, you
/// want to NOT extract the file, set <see cref="ZipEntry.ExtractExistingFile"/>
/// on the <c>ZipProgressEventArgs.CurrentEntry</c> to <c>DoNotOverwrite</c>.
/// If you do want to extract the file, set <c>ZipEntry.ExtractExistingFile</c>
/// to <c>OverwriteSilently</c>. If you want to cancel the Extraction, set
/// <c>ZipProgressEventArgs.Cancel</c> to true. Cancelling differs from using
/// DoNotOverwrite in that a cancel will not extract any further entries, if
/// there are any. (For COM clients, the value of this enum is a 3.)
/// </summary>
InvokeExtractProgressEvent,
}
}

View file

@ -1,114 +0,0 @@
// OffsetStream.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009 Dino Chiesa
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2009-August-27 12:50:35>
//
// ------------------------------------------------------------------
//
// This module defines logic for handling reading of zip archives embedded
// into larger streams. The initial position of the stream serves as
// the base offset for all future Seek() operations.
//
// ------------------------------------------------------------------
using System;
using System.IO;
namespace Ionic.Zip
{
internal class OffsetStream : System.IO.Stream, System.IDisposable
{
private Int64 _originalPosition;
private Stream _innerStream;
public OffsetStream(Stream s)
: base()
{
_originalPosition = s.Position;
_innerStream = s;
}
public override int Read(byte[] buffer, int offset, int count)
{
return _innerStream.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
public override bool CanRead
{
get { return _innerStream.CanRead; }
}
public override bool CanSeek
{
get { return _innerStream.CanSeek; }
}
public override bool CanWrite
{
get { return false; }
}
public override void Flush()
{
_innerStream.Flush();
}
public override long Length
{
get
{
return _innerStream.Length;
}
}
public override long Position
{
get { return _innerStream.Position - _originalPosition; }
set { _innerStream.Position = _originalPosition + value; }
}
public override long Seek(long offset, System.IO.SeekOrigin origin)
{
return _innerStream.Seek(_originalPosition + offset, origin) - _originalPosition;
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
void IDisposable.Dispose()
{
Close();
}
public override void Close()
{
base.Close();
}
}
}

View file

@ -1,901 +0,0 @@
// Shared.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2006-2011 Dino Chiesa.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// Last Saved: <2011-August-02 19:41:01>
//
// ------------------------------------------------------------------
//
// This module defines some shared utility classes and methods.
//
// Created: Tue, 27 Mar 2007 15:30
//
using System;
using System.IO;
using System.Security.Permissions;
namespace Ionic.Zip
{
/// <summary>
/// Collects general purpose utility methods.
/// </summary>
internal static class SharedUtilities
{
/// private null constructor
//private SharedUtilities() { }
// workitem 8423
public static Int64 GetFileLength(string fileName)
{
if (!File.Exists(fileName))
throw new System.IO.FileNotFoundException(fileName);
long fileLength = 0L;
FileShare fs = FileShare.ReadWrite;
#if !NETCF
// FileShare.Delete is not defined for the Compact Framework
fs |= FileShare.Delete;
#endif
using (var s = File.Open(fileName, FileMode.Open, FileAccess.Read, fs))
{
fileLength = s.Length;
}
return fileLength;
}
[System.Diagnostics.Conditional("NETCF")]
public static void Workaround_Ladybug318918(Stream s)
{
// This is a workaround for this issue:
// https://connect.microsoft.com/VisualStudio/feedback/details/318918
// It's required only on NETCF.
s.Flush();
}
#if LEGACY
/// <summary>
/// Round the given DateTime value to an even second value.
/// </summary>
///
/// <remarks>
/// <para>
/// Round up in the case of an odd second value. The rounding does not consider
/// fractional seconds.
/// </para>
/// <para>
/// This is useful because the Zip spec allows storage of time only to the nearest
/// even second. So if you want to compare the time of an entry in the archive with
/// it's actual time in the filesystem, you need to round the actual filesystem
/// time, or use a 2-second threshold for the comparison.
/// </para>
/// <para>
/// This is most nautrally an extension method for the DateTime class but this
/// library is built for .NET 2.0, not for .NET 3.5; This means extension methods
/// are a no-no.
/// </para>
/// </remarks>
/// <param name="source">The DateTime value to round</param>
/// <returns>The ruonded DateTime value</returns>
public static DateTime RoundToEvenSecond(DateTime source)
{
// round to nearest second:
if ((source.Second % 2) == 1)
source += new TimeSpan(0, 0, 1);
DateTime dtRounded = new DateTime(source.Year, source.Month, source.Day, source.Hour, source.Minute, source.Second);
//if (source.Millisecond >= 500) dtRounded = dtRounded.AddSeconds(1);
return dtRounded;
}
#endif
#if YOU_LIKE_REDUNDANT_CODE
internal static string NormalizePath(string path)
{
// remove leading single dot slash
if (path.StartsWith(".\\")) path = path.Substring(2);
// remove intervening dot-slash
path = path.Replace("\\.\\", "\\");
// remove double dot when preceded by a directory name
var re = new System.Text.RegularExpressions.Regex(@"^(.*\\)?([^\\\.]+\\\.\.\\)(.+)$");
path = re.Replace(path, "$1$3");
return path;
}
#endif
private static System.Text.RegularExpressions.Regex doubleDotRegex1 =
new System.Text.RegularExpressions.Regex(@"^(.*/)?([^/\\.]+/\\.\\./)(.+)$");
private static string SimplifyFwdSlashPath(string path)
{
if (path.StartsWith("./")) path = path.Substring(2);
path = path.Replace("/./", "/");
// Replace foo/anything/../bar with foo/bar
path = doubleDotRegex1.Replace(path, "$1$3");
return path;
}
/// <summary>
/// Utility routine for transforming path names from filesystem format (on Windows that means backslashes) to
/// a format suitable for use within zipfiles. This means trimming the volume letter and colon (if any) And
/// swapping backslashes for forward slashes.
/// </summary>
/// <param name="pathName">source path.</param>
/// <returns>transformed path</returns>
public static string NormalizePathForUseInZipFile(string pathName)
{
// boundary case
if (String.IsNullOrEmpty(pathName)) return pathName;
// trim volume if necessary
if ((pathName.Length >= 2) && ((pathName[1] == ':') && (pathName[2] == '\\')))
pathName = pathName.Substring(3);
// swap slashes
pathName = pathName.Replace('\\', '/');
// trim all leading slashes
while (pathName.StartsWith("/")) pathName = pathName.Substring(1);
return SimplifyFwdSlashPath(pathName);
}
static System.Text.Encoding ibm437 = System.Text.Encoding.GetEncoding("IBM437");
static System.Text.Encoding utf8 = System.Text.Encoding.GetEncoding("UTF-8");
internal static byte[] StringToByteArray(string value, System.Text.Encoding encoding)
{
byte[] a = encoding.GetBytes(value);
return a;
}
internal static byte[] StringToByteArray(string value)
{
return StringToByteArray(value, ibm437);
}
//internal static byte[] Utf8StringToByteArray(string value)
//{
// return StringToByteArray(value, utf8);
//}
//internal static string StringFromBuffer(byte[] buf, int maxlength)
//{
// return StringFromBuffer(buf, maxlength, ibm437);
//}
internal static string Utf8StringFromBuffer(byte[] buf)
{
return StringFromBuffer(buf, utf8);
}
internal static string StringFromBuffer(byte[] buf, System.Text.Encoding encoding)
{
// this form of the GetString() method is required for .NET CF compatibility
string s = encoding.GetString(buf, 0, buf.Length);
return s;
}
internal static int ReadSignature(System.IO.Stream s)
{
int x = 0;
try { x = _ReadFourBytes(s, "n/a"); }
catch (BadReadException) { }
return x;
}
internal static int ReadEntrySignature(System.IO.Stream s)
{
// handle the case of ill-formatted zip archives - includes a data descriptor
// when none is expected.
int x = 0;
try
{
x = _ReadFourBytes(s, "n/a");
if (x == ZipConstants.ZipEntryDataDescriptorSignature)
{
// advance past data descriptor - 12 bytes if not zip64
s.Seek(12, SeekOrigin.Current);
// workitem 10178
Workaround_Ladybug318918(s);
x = _ReadFourBytes(s, "n/a");
if (x != ZipConstants.ZipEntrySignature)
{
// Maybe zip64 was in use for the prior entry.
// Therefore, skip another 8 bytes.
s.Seek(8, SeekOrigin.Current);
// workitem 10178
Workaround_Ladybug318918(s);
x = _ReadFourBytes(s, "n/a");
if (x != ZipConstants.ZipEntrySignature)
{
// seek back to the first spot
s.Seek(-24, SeekOrigin.Current);
// workitem 10178
Workaround_Ladybug318918(s);
x = _ReadFourBytes(s, "n/a");
}
}
}
}
catch (BadReadException) { }
return x;
}
internal static int ReadInt(System.IO.Stream s)
{
return _ReadFourBytes(s, "Could not read block - no data! (position 0x{0:X8})");
}
private static int _ReadFourBytes(System.IO.Stream s, string message)
{
int n = 0;
byte[] block = new byte[4];
#if NETCF
// workitem 9181
// Reading here in NETCF sometimes reads "backwards". Seems to happen for
// larger files. Not sure why. Maybe an error in caching. If the data is:
//
// 00100210: 9efa 0f00 7072 6f6a 6563 742e 6963 7750 ....project.icwP
// 00100220: 4b05 0600 0000 0006 0006 0091 0100 008e K...............
// 00100230: 0010 0000 00 .....
//
// ...and the stream Position is 10021F, then a Read of 4 bytes is returning
// 50776369, instead of 06054b50. This seems to happen the 2nd time Read()
// is called from that Position..
//
// submitted to connect.microsoft.com
// https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=318918#tabs
//
for (int i = 0; i < block.Length; i++)
{
n+= s.Read(block, i, 1);
}
#else
n = s.Read(block, 0, block.Length);
#endif
if (n != block.Length) throw new BadReadException(String.Format(message, s.Position));
int data = unchecked((((block[3] * 256 + block[2]) * 256) + block[1]) * 256 + block[0]);
return data;
}
/// <summary>
/// Finds a signature in the zip stream. This is useful for finding
/// the end of a zip entry, for example, or the beginning of the next ZipEntry.
/// </summary>
///
/// <remarks>
/// <para>
/// Scans through 64k at a time.
/// </para>
///
/// <para>
/// If the method fails to find the requested signature, the stream Position
/// after completion of this method is unchanged. If the method succeeds in
/// finding the requested signature, the stream position after completion is
/// direct AFTER the signature found in the stream.
/// </para>
/// </remarks>
///
/// <param name="stream">The stream to search</param>
/// <param name="SignatureToFind">The 4-byte signature to find</param>
/// <returns>The number of bytes read</returns>
internal static long FindSignature(System.IO.Stream stream, int SignatureToFind)
{
long startingPosition = stream.Position;
int BATCH_SIZE = 65536; // 8192;
byte[] targetBytes = new byte[4];
targetBytes[0] = (byte)(SignatureToFind >> 24);
targetBytes[1] = (byte)((SignatureToFind & 0x00FF0000) >> 16);
targetBytes[2] = (byte)((SignatureToFind & 0x0000FF00) >> 8);
targetBytes[3] = (byte)(SignatureToFind & 0x000000FF);
byte[] batch = new byte[BATCH_SIZE];
int n = 0;
bool success = false;
do
{
n = stream.Read(batch, 0, batch.Length);
if (n != 0)
{
for (int i = 0; i < n; i++)
{
if (batch[i] == targetBytes[3])
{
long curPosition = stream.Position;
stream.Seek(i - n, System.IO.SeekOrigin.Current);
// workitem 10178
Workaround_Ladybug318918(stream);
// workitem 7711
int sig = ReadSignature(stream);
success = (sig == SignatureToFind);
if (!success)
{
stream.Seek(curPosition, System.IO.SeekOrigin.Begin);
// workitem 10178
Workaround_Ladybug318918(stream);
}
else
break; // out of for loop
}
}
}
else break;
if (success) break;
} while (true);
if (!success)
{
stream.Seek(startingPosition, System.IO.SeekOrigin.Begin);
// workitem 10178
Workaround_Ladybug318918(stream);
return -1; // or throw?
}
// subtract 4 for the signature.
long bytesRead = (stream.Position - startingPosition) - 4;
return bytesRead;
}
// If I have a time in the .NET environment, and I want to use it for
// SetWastWriteTime() etc, then I need to adjust it for Win32.
internal static DateTime AdjustTime_Reverse(DateTime time)
{
if (time.Kind == DateTimeKind.Utc) return time;
DateTime adjusted = time;
if (DateTime.Now.IsDaylightSavingTime() && !time.IsDaylightSavingTime())
adjusted = time - new System.TimeSpan(1, 0, 0);
else if (!DateTime.Now.IsDaylightSavingTime() && time.IsDaylightSavingTime())
adjusted = time + new System.TimeSpan(1, 0, 0);
return adjusted;
}
#if NECESSARY
// If I read a time from a file with GetLastWriteTime() (etc), I need
// to adjust it for display in the .NET environment.
internal static DateTime AdjustTime_Forward(DateTime time)
{
if (time.Kind == DateTimeKind.Utc) return time;
DateTime adjusted = time;
if (DateTime.Now.IsDaylightSavingTime() && !time.IsDaylightSavingTime())
adjusted = time + new System.TimeSpan(1, 0, 0);
else if (!DateTime.Now.IsDaylightSavingTime() && time.IsDaylightSavingTime())
adjusted = time - new System.TimeSpan(1, 0, 0);
return adjusted;
}
#endif
internal static DateTime PackedToDateTime(Int32 packedDateTime)
{
// workitem 7074 & workitem 7170
if (packedDateTime == 0xFFFF || packedDateTime == 0)
return new System.DateTime(1995, 1, 1, 0, 0, 0, 0); // return a fixed date when none is supplied.
Int16 packedTime = unchecked((Int16)(packedDateTime & 0x0000ffff));
Int16 packedDate = unchecked((Int16)((packedDateTime & 0xffff0000) >> 16));
int year = 1980 + ((packedDate & 0xFE00) >> 9);
int month = (packedDate & 0x01E0) >> 5;
int day = packedDate & 0x001F;
int hour = (packedTime & 0xF800) >> 11;
int minute = (packedTime & 0x07E0) >> 5;
//int second = packedTime & 0x001F;
int second = (packedTime & 0x001F) * 2;
// validation and error checking.
// this is not foolproof but will catch most errors.
if (second >= 60) { minute++; second = 0; }
if (minute >= 60) { hour++; minute = 0; }
if (hour >= 24) { day++; hour = 0; }
DateTime d = System.DateTime.Now;
bool success= false;
try
{
d = new System.DateTime(year, month, day, hour, minute, second, 0);
success= true;
}
catch (System.ArgumentOutOfRangeException)
{
if (year == 1980 && (month == 0 || day == 0))
{
try
{
d = new System.DateTime(1980, 1, 1, hour, minute, second, 0);
success= true;
}
catch (System.ArgumentOutOfRangeException)
{
try
{
d = new System.DateTime(1980, 1, 1, 0, 0, 0, 0);
success= true;
}
catch (System.ArgumentOutOfRangeException) { }
}
}
// workitem 8814
// my god, I can't believe how many different ways applications
// can mess up a simple date format.
else
{
try
{
while (year < 1980) year++;
while (year > 2030) year--;
while (month < 1) month++;
while (month > 12) month--;
while (day < 1) day++;
while (day > 28) day--;
while (minute < 0) minute++;
while (minute > 59) minute--;
while (second < 0) second++;
while (second > 59) second--;
d = new System.DateTime(year, month, day, hour, minute, second, 0);
success= true;
}
catch (System.ArgumentOutOfRangeException) { }
}
}
if (!success)
{
string msg = String.Format("y({0}) m({1}) d({2}) h({3}) m({4}) s({5})", year, month, day, hour, minute, second);
throw new ZipException(String.Format("Bad date/time format in the zip file. ({0})", msg));
}
// workitem 6191
//d = AdjustTime_Reverse(d);
d = DateTime.SpecifyKind(d, DateTimeKind.Local);
return d;
}
internal
static Int32 DateTimeToPacked(DateTime time)
{
// The time is passed in here only for purposes of writing LastModified to the
// zip archive. It should always be LocalTime, but we convert anyway. And,
// since the time is being written out, it needs to be adjusted.
time = time.ToLocalTime();
// workitem 7966
//time = AdjustTime_Forward(time);
// see http://www.vsft.com/hal/dostime.htm for the format
UInt16 packedDate = (UInt16)((time.Day & 0x0000001F) | ((time.Month << 5) & 0x000001E0) | (((time.Year - 1980) << 9) & 0x0000FE00));
UInt16 packedTime = (UInt16)((time.Second / 2 & 0x0000001F) | ((time.Minute << 5) & 0x000007E0) | ((time.Hour << 11) & 0x0000F800));
Int32 result = (Int32)(((UInt32)(packedDate << 16)) | packedTime);
return result;
}
/// <summary>
/// Create a pseudo-random filename, suitable for use as a temporary
/// file, and open it.
/// </summary>
/// <remarks>
/// <para>
/// The System.IO.Path.GetRandomFileName() method is not available on
/// the Compact Framework, so this library provides its own substitute
/// on NETCF.
/// </para>
/// <para>
/// This method produces a filename of the form
/// DotNetZip-xxxxxxxx.tmp, where xxxxxxxx is replaced by randomly
/// chosen characters, and creates that file.
/// </para>
/// </remarks>
public static void CreateAndOpenUniqueTempFile(string dir,
out Stream fs,
out string filename)
{
// workitem 9763
// http://dotnet.org.za/markn/archive/2006/04/15/51594.aspx
// try 3 times:
for (int i = 0; i < 3; i++)
{
try
{
filename = Path.Combine(dir, InternalGetTempFileName());
fs = new FileStream(filename, FileMode.CreateNew);
return;
}
catch (IOException)
{
if (i == 2) throw;
}
}
throw new IOException();
}
#if NETCF || SILVERLIGHT
public static string InternalGetTempFileName()
{
return "DotNetZip-" + GenerateRandomStringImpl(8,0) + ".tmp";
}
internal static string GenerateRandomStringImpl(int length, int delta)
{
bool WantMixedCase = (delta == 0);
System.Random rnd = new System.Random();
string result = "";
char[] a = new char[length];
for (int i = 0; i < length; i++)
{
// delta == 65 means uppercase
// delta == 97 means lowercase
if (WantMixedCase)
delta = (rnd.Next(2) == 0) ? 65 : 97;
a[i] = (char)(rnd.Next(26) + delta);
}
result = new System.String(a);
return result;
}
#else
public static string InternalGetTempFileName()
{
return "DotNetZip-" + Path.GetRandomFileName().Substring(0, 8) + ".tmp";
}
#endif
/// <summary>
/// Workitem 7889: handle ERROR_LOCK_VIOLATION during read
/// </summary>
/// <remarks>
/// This could be gracefully handled with an extension attribute, but
/// This assembly is built for .NET 2.0, so I cannot use them.
/// </remarks>
internal static int ReadWithRetry(System.IO.Stream s, byte[] buffer, int offset, int count, string FileName)
{
int n = 0;
bool done = false;
#if !NETCF && !SILVERLIGHT
int retries = 0;
#endif
do
{
try
{
n = s.Read(buffer, offset, count);
done = true;
}
#if NETCF || SILVERLIGHT
catch (System.IO.IOException)
{
throw;
}
#else
catch (System.IO.IOException ioexc1)
{
// Check if we can call GetHRForException,
// which makes unmanaged code calls.
var p = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
if (p.IsUnrestricted())
{
uint hresult = _HRForException(ioexc1);
if (hresult != 0x80070021) // ERROR_LOCK_VIOLATION
throw new System.IO.IOException(String.Format("Cannot read file {0}", FileName), ioexc1);
retries++;
if (retries > 10)
throw new System.IO.IOException(String.Format("Cannot read file {0}, at offset 0x{1:X8} after 10 retries", FileName, offset), ioexc1);
// max time waited on last retry = 250 + 10*550 = 5.75s
// aggregate time waited after 10 retries: 250 + 55*550 = 30.5s
System.Threading.Thread.Sleep(250 + retries * 550);
}
else
{
// The permission.Demand() failed. Therefore, we cannot call
// GetHRForException, and cannot do the subtle handling of
// ERROR_LOCK_VIOLATION. Just bail.
throw;
}
}
#endif
}
while (!done);
return n;
}
#if !NETCF
// workitem 8009
//
// This method must remain separate.
//
// Marshal.GetHRForException() is needed to do special exception handling for
// the read. But, that method requires UnmanagedCode permissions, and is marked
// with LinkDemand for UnmanagedCode. In an ASP.NET medium trust environment,
// where UnmanagedCode is restricted, will generate a SecurityException at the
// time of JIT of the method that calls a method that is marked with LinkDemand
// for UnmanagedCode. The SecurityException, if it is restricted, will occur
// when this method is JITed.
//
// The Marshal.GetHRForException() is factored out of ReadWithRetry in order to
// avoid the SecurityException at JIT compile time. Because _HRForException is
// called only when the UnmanagedCode is allowed. This means .NET never
// JIT-compiles this method when UnmanagedCode is disallowed, and thus never
// generates the JIT-compile time exception.
//
#endif
private static uint _HRForException(System.Exception ex1)
{
return unchecked((uint)System.Runtime.InteropServices.Marshal.GetHRForException(ex1));
}
}
/// <summary>
/// A decorator stream. It wraps another stream, and performs bookkeeping
/// to keep track of the stream Position.
/// </summary>
/// <remarks>
/// <para>
/// In some cases, it is not possible to get the Position of a stream, let's
/// say, on a write-only output stream like ASP.NET's
/// <c>Response.OutputStream</c>, or on a different write-only stream
/// provided as the destination for the zip by the application. In this
/// case, programmers can use this counting stream to count the bytes read
/// or written.
/// </para>
/// <para>
/// Consider the scenario of an application that saves a self-extracting
/// archive (SFX), that uses a custom SFX stub.
/// </para>
/// <para>
/// Saving to a filesystem file, the application would open the
/// filesystem file (getting a <c>FileStream</c>), save the custom sfx stub
/// into it, and then call <c>ZipFile.Save()</c>, specifying the same
/// FileStream. <c>ZipFile.Save()</c> does the right thing for the zipentry
/// offsets, by inquiring the Position of the <c>FileStream</c> before writing
/// any data, and then adding that initial offset into any ZipEntry
/// offsets in the zip directory. Everything works fine.
/// </para>
/// <para>
/// Now suppose the application is an ASPNET application and it saves
/// directly to <c>Response.OutputStream</c>. It's not possible for DotNetZip to
/// inquire the <c>Position</c>, so the offsets for the SFX will be wrong.
/// </para>
/// <para>
/// The workaround is for the application to use this class to wrap
/// <c>HttpResponse.OutputStream</c>, then write the SFX stub and the ZipFile
/// into that wrapper stream. Because <c>ZipFile.Save()</c> can inquire the
/// <c>Position</c>, it will then do the right thing with the offsets.
/// </para>
/// </remarks>
public class CountingStream : System.IO.Stream
{
// workitem 12374: this class is now public
private System.IO.Stream _s;
private Int64 _bytesWritten;
private Int64 _bytesRead;
private Int64 _initialOffset;
/// <summary>
/// The constructor.
/// </summary>
/// <param name="stream">The underlying stream</param>
public CountingStream(System.IO.Stream stream)
: base()
{
_s = stream;
try
{
_initialOffset = _s.Position;
}
catch
{
_initialOffset = 0L;
}
}
/// <summary>
/// Gets the wrapped stream.
/// </summary>
public Stream WrappedStream
{
get
{
return _s;
}
}
/// <summary>
/// The count of bytes written out to the stream.
/// </summary>
public Int64 BytesWritten
{
get { return _bytesWritten; }
}
/// <summary>
/// the count of bytes that have been read from the stream.
/// </summary>
public Int64 BytesRead
{
get { return _bytesRead; }
}
/// <summary>
/// Adjust the byte count on the stream.
/// </summary>
///
/// <param name='delta'>
/// the number of bytes to subtract from the count.
/// </param>
///
/// <remarks>
/// <para>
/// Subtract delta from the count of bytes written to the stream.
/// This is necessary when seeking back, and writing additional data,
/// as happens in some cases when saving Zip files.
/// </para>
/// </remarks>
public void Adjust(Int64 delta)
{
_bytesWritten -= delta;
if (_bytesWritten < 0)
throw new InvalidOperationException();
if (_s as CountingStream != null)
((CountingStream)_s).Adjust(delta);
}
/// <summary>
/// The read method.
/// </summary>
/// <param name="buffer">The buffer to hold the data read from the stream.</param>
/// <param name="offset">the offset within the buffer to copy the first byte read.</param>
/// <param name="count">the number of bytes to read.</param>
/// <returns>the number of bytes read, after decryption and decompression.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
int n = _s.Read(buffer, offset, count);
_bytesRead += n;
return n;
}
/// <summary>
/// Write data into the stream.
/// </summary>
/// <param name="buffer">The buffer holding data to write to the stream.</param>
/// <param name="offset">the offset within that data array to find the first byte to write.</param>
/// <param name="count">the number of bytes to write.</param>
public override void Write(byte[] buffer, int offset, int count)
{
if (count == 0) return;
_s.Write(buffer, offset, count);
_bytesWritten += count;
}
/// <summary>
/// Whether the stream can be read.
/// </summary>
public override bool CanRead
{
get { return _s.CanRead; }
}
/// <summary>
/// Whether it is possible to call Seek() on the stream.
/// </summary>
public override bool CanSeek
{
get { return _s.CanSeek; }
}
/// <summary>
/// Whether it is possible to call Write() on the stream.
/// </summary>
public override bool CanWrite
{
get { return _s.CanWrite; }
}
/// <summary>
/// Flushes the underlying stream.
/// </summary>
public override void Flush()
{
_s.Flush();
}
/// <summary>
/// The length of the underlying stream.
/// </summary>
public override long Length
{
get { return _s.Length; } // bytesWritten??
}
/// <summary>
/// Returns the sum of number of bytes written, plus the initial
/// offset before writing.
/// </summary>
public long ComputedPosition
{
get { return _initialOffset + _bytesWritten; }
}
/// <summary>
/// The Position of the stream.
/// </summary>
public override long Position
{
get { return _s.Position; }
set
{
_s.Seek(value, System.IO.SeekOrigin.Begin);
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_s);
}
}
/// <summary>
/// Seek in the stream.
/// </summary>
/// <param name="offset">the offset point to seek to</param>
/// <param name="origin">the reference point from which to seek</param>
/// <returns>The new position</returns>
public override long Seek(long offset, System.IO.SeekOrigin origin)
{
return _s.Seek(offset, origin);
}
/// <summary>
/// Set the length of the underlying stream. Be careful with this!
/// </summary>
///
/// <param name='value'>the length to set on the underlying stream.</param>
public override void SetLength(long value)
{
_s.SetLength(value);
}
}
}

View file

@ -1,941 +0,0 @@
//#define Trace
// WinZipAes.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009-2011 Dino Chiesa.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2011-July-12 13:42:06>
//
// ------------------------------------------------------------------
//
// This module defines the classes for dealing with WinZip's AES encryption,
// according to the specifications for the format available on WinZip's website.
//
// Created: January 2009
//
// ------------------------------------------------------------------
using System;
using System.IO;
using System.Collections.Generic;
using System.Security.Cryptography;
#if AESCRYPTO
namespace Ionic.Zip
{
/// <summary>
/// This is a helper class supporting WinZip AES encryption.
/// This class is intended for use only by the DotNetZip library.
/// </summary>
///
/// <remarks>
/// Most uses of the DotNetZip library will not involve direct calls into
/// the WinZipAesCrypto class. Instead, the WinZipAesCrypto class is
/// instantiated and used by the ZipEntry() class when WinZip AES
/// encryption or decryption on an entry is employed.
/// </remarks>
internal class WinZipAesCrypto
{
internal byte[] _Salt;
internal byte[] _providedPv;
internal byte[] _generatedPv;
internal int _KeyStrengthInBits;
private byte[] _MacInitializationVector;
private byte[] _StoredMac;
private byte[] _keyBytes;
private Int16 PasswordVerificationStored;
private Int16 PasswordVerificationGenerated;
private int Rfc2898KeygenIterations = 1000;
private string _Password;
private bool _cryptoGenerated ;
private WinZipAesCrypto(string password, int KeyStrengthInBits)
{
_Password = password;
_KeyStrengthInBits = KeyStrengthInBits;
}
public static WinZipAesCrypto Generate(string password, int KeyStrengthInBits)
{
WinZipAesCrypto c = new WinZipAesCrypto(password, KeyStrengthInBits);
int saltSizeInBytes = c._KeyStrengthInBytes / 2;
c._Salt = new byte[saltSizeInBytes];
Random rnd = new Random();
rnd.NextBytes(c._Salt);
return c;
}
public static WinZipAesCrypto ReadFromStream(string password, int KeyStrengthInBits, Stream s)
{
// from http://www.winzip.com/aes_info.htm
//
// Size(bytes) Content
// -----------------------------------
// Variable Salt value
// 2 Password verification value
// Variable Encrypted file data
// 10 Authentication code
//
// ZipEntry.CompressedSize represents the size of all of those elements.
// salt size varies with key length:
// 128 bit key => 8 bytes salt
// 192 bits => 12 bytes salt
// 256 bits => 16 bytes salt
WinZipAesCrypto c = new WinZipAesCrypto(password, KeyStrengthInBits);
int saltSizeInBytes = c._KeyStrengthInBytes / 2;
c._Salt = new byte[saltSizeInBytes];
c._providedPv = new byte[2];
s.Read(c._Salt, 0, c._Salt.Length);
s.Read(c._providedPv, 0, c._providedPv.Length);
c.PasswordVerificationStored = (Int16)(c._providedPv[0] + c._providedPv[1] * 256);
if (password != null)
{
c.PasswordVerificationGenerated = (Int16)(c.GeneratedPV[0] + c.GeneratedPV[1] * 256);
if (c.PasswordVerificationGenerated != c.PasswordVerificationStored)
throw new BadPasswordException("bad password");
}
return c;
}
public byte[] GeneratedPV
{
get
{
if (!_cryptoGenerated) _GenerateCryptoBytes();
return _generatedPv;
}
}
public byte[] Salt
{
get
{
return _Salt;
}
}
private int _KeyStrengthInBytes
{
get
{
return _KeyStrengthInBits / 8;
}
}
public int SizeOfEncryptionMetadata
{
get
{
// 10 bytes after, (n-10) before the compressed data
return _KeyStrengthInBytes / 2 + 10 + 2;
}
}
public string Password
{
set
{
_Password = value;
if (_Password != null)
{
PasswordVerificationGenerated = (Int16)(GeneratedPV[0] + GeneratedPV[1] * 256);
if (PasswordVerificationGenerated != PasswordVerificationStored)
throw new Ionic.Zip.BadPasswordException();
}
}
private get
{
return _Password;
}
}
private void _GenerateCryptoBytes()
{
//Console.WriteLine(" provided password: '{0}'", _Password);
System.Security.Cryptography.Rfc2898DeriveBytes rfc2898 =
new System.Security.Cryptography.Rfc2898DeriveBytes(_Password, Salt, Rfc2898KeygenIterations);
_keyBytes = rfc2898.GetBytes(_KeyStrengthInBytes); // 16 or 24 or 32 ???
_MacInitializationVector = rfc2898.GetBytes(_KeyStrengthInBytes);
_generatedPv = rfc2898.GetBytes(2);
_cryptoGenerated = true;
}
public byte[] KeyBytes
{
get
{
if (!_cryptoGenerated) _GenerateCryptoBytes();
return _keyBytes;
}
}
public byte[] MacIv
{
get
{
if (!_cryptoGenerated) _GenerateCryptoBytes();
return _MacInitializationVector;
}
}
public byte[] CalculatedMac;
public void ReadAndVerifyMac(System.IO.Stream s)
{
bool invalid = false;
// read integrityCheckVector.
// caller must ensure that the file pointer is in the right spot!
_StoredMac = new byte[10]; // aka "authentication code"
s.Read(_StoredMac, 0, _StoredMac.Length);
if (_StoredMac.Length != CalculatedMac.Length)
invalid = true;
if (!invalid)
{
for (int i = 0; i < _StoredMac.Length; i++)
{
if (_StoredMac[i] != CalculatedMac[i])
invalid = true;
}
}
if (invalid)
throw new Ionic.Zip.BadStateException("The MAC does not match.");
}
}
#region DONT_COMPILE_BUT_KEEP_FOR_POTENTIAL_FUTURE_USE
#if NO
internal class Util
{
private static void _Format(System.Text.StringBuilder sb1,
byte[] b,
int offset,
int length)
{
System.Text.StringBuilder sb2 = new System.Text.StringBuilder();
sb1.Append("0000 ");
int i;
for (i = 0; i < length; i++)
{
int x = offset+i;
if (i != 0 && i % 16 == 0)
{
sb1.Append(" ")
.Append(sb2)
.Append("\n")
.Append(String.Format("{0:X4} ", i));
sb2.Remove(0,sb2.Length);
}
sb1.Append(System.String.Format("{0:X2} ", b[x]));
if (b[x] >=32 && b[x] <= 126)
sb2.Append((char)b[x]);
else
sb2.Append(".");
}
if (sb2.Length > 0)
{
sb1.Append(new String(' ', ((16 - i%16) * 3) + 4))
.Append(sb2);
}
}
internal static string FormatByteArray(byte[] b, int limit)
{
System.Text.StringBuilder sb1 = new System.Text.StringBuilder();
if ((limit * 2 > b.Length) || limit == 0)
{
_Format(sb1, b, 0, b.Length);
}
else
{
// first N bytes of the buffer
_Format(sb1, b, 0, limit);
if (b.Length > limit * 2)
sb1.Append(String.Format("\n ...({0} other bytes here)....\n", b.Length - limit * 2));
// last N bytes of the buffer
_Format(sb1, b, b.Length - limit, limit);
}
return sb1.ToString();
}
internal static string FormatByteArray(byte[] b)
{
return FormatByteArray(b, 0);
}
}
#endif
#endregion
/// <summary>
/// A stream that encrypts as it writes, or decrypts as it reads. The
/// Crypto is AES in CTR (counter) mode, which is compatible with the AES
/// encryption employed by WinZip 12.0.
/// </summary>
/// <remarks>
/// <para>
/// The AES/CTR encryption protocol used by WinZip works like this:
///
/// - start with a counter, initialized to zero.
///
/// - to encrypt, take the data by 16-byte blocks. For each block:
/// - apply the transform to the counter
/// - increement the counter
/// - XOR the result of the transform with the plaintext to
/// get the ciphertext.
/// - compute the mac on the encrypted bytes
/// - when finished with all blocks, store the computed MAC.
///
/// - to decrypt, take the data by 16-byte blocks. For each block:
/// - compute the mac on the encrypted bytes,
/// - apply the transform to the counter
/// - increement the counter
/// - XOR the result of the transform with the ciphertext to
/// get the plaintext.
/// - when finished with all blocks, compare the computed MAC against
/// the stored MAC
///
/// </para>
/// </remarks>
//
internal class WinZipAesCipherStream : Stream
{
private WinZipAesCrypto _params;
private System.IO.Stream _s;
private CryptoMode _mode;
private int _nonce;
private bool _finalBlock;
internal HMACSHA1 _mac;
// Use RijndaelManaged from .NET 2.0.
// AesManaged came in .NET 3.5, but we want to limit
// dependency to .NET 2.0. AES is just a restricted form
// of Rijndael (fixed block size of 128, some crypto modes not supported).
internal RijndaelManaged _aesCipher;
internal ICryptoTransform _xform;
private const int BLOCK_SIZE_IN_BYTES = 16;
private byte[] counter = new byte[BLOCK_SIZE_IN_BYTES];
private byte[] counterOut = new byte[BLOCK_SIZE_IN_BYTES];
// I've had a problem when wrapping a WinZipAesCipherStream inside
// a DeflateStream. Calling Read() on the DeflateStream results in
// a Read() on the WinZipAesCipherStream, but the buffer is larger
// than the total size of the encrypted data, and larger than the
// initial Read() on the DeflateStream! When the encrypted
// bytestream is embedded within a larger stream (As in a zip
// archive), the Read() doesn't fail with EOF. This causes bad
// data to be returned, and it messes up the MAC.
// This field is used to provide a hard-stop to the size of
// data that can be read from the stream. In Read(), if the buffer or
// read request goes beyond the stop, we truncate it.
private long _length;
private long _totalBytesXferred;
private byte[] _PendingWriteBlock;
private int _pendingCount;
private byte[] _iobuf;
/// <summary>
/// The constructor.
/// </summary>
/// <param name="s">The underlying stream</param>
/// <param name="mode">To either encrypt or decrypt.</param>
/// <param name="cryptoParams">The pre-initialized WinZipAesCrypto object.</param>
/// <param name="length">The maximum number of bytes to read from the stream.</param>
internal WinZipAesCipherStream(System.IO.Stream s, WinZipAesCrypto cryptoParams, long length, CryptoMode mode)
: this(s, cryptoParams, mode)
{
// don't read beyond this limit!
_length = length;
//Console.WriteLine("max length of AES stream: {0}", _length);
}
#if WANT_TRACE
Stream untransformed;
String traceFileUntransformed;
Stream transformed;
String traceFileTransformed;
#endif
internal WinZipAesCipherStream(System.IO.Stream s, WinZipAesCrypto cryptoParams, CryptoMode mode)
: base()
{
TraceOutput("-------------------------------------------------------");
TraceOutput("Create {0:X8}", this.GetHashCode());
_params = cryptoParams;
_s = s;
_mode = mode;
_nonce = 1;
if (_params == null)
throw new BadPasswordException("Supply a password to use AES encryption.");
int keySizeInBits = _params.KeyBytes.Length * 8;
if (keySizeInBits != 256 && keySizeInBits != 128 && keySizeInBits != 192)
throw new ArgumentOutOfRangeException("keysize",
"size of key must be 128, 192, or 256");
_mac = new HMACSHA1(_params.MacIv);
_aesCipher = new System.Security.Cryptography.RijndaelManaged();
_aesCipher.BlockSize = 128;
_aesCipher.KeySize = keySizeInBits; // 128, 192, 256
_aesCipher.Mode = CipherMode.ECB;
_aesCipher.Padding = PaddingMode.None;
byte[] iv = new byte[BLOCK_SIZE_IN_BYTES]; // all zeroes
// Create an ENCRYPTOR, regardless whether doing decryption or encryption.
// It is reflexive.
_xform = _aesCipher.CreateEncryptor(_params.KeyBytes, iv);
if (_mode == CryptoMode.Encrypt)
{
_iobuf = new byte[2048];
_PendingWriteBlock = new byte[BLOCK_SIZE_IN_BYTES];
}
#if WANT_TRACE
traceFileUntransformed = "unpack\\WinZipAesCipherStream.trace.untransformed.out";
traceFileTransformed = "unpack\\WinZipAesCipherStream.trace.transformed.out";
untransformed = System.IO.File.Create(traceFileUntransformed);
transformed = System.IO.File.Create(traceFileTransformed);
#endif
}
private void XorInPlace(byte[] buffer, int offset, int count)
{
for (int i = 0; i < count; i++)
{
buffer[offset + i] = (byte)(counterOut[i] ^ buffer[offset + i]);
}
}
private void WriteTransformOneBlock(byte[] buffer, int offset)
{
System.Array.Copy(BitConverter.GetBytes(_nonce++), 0, counter, 0, 4);
_xform.TransformBlock(counter,
0,
BLOCK_SIZE_IN_BYTES,
counterOut,
0);
XorInPlace(buffer, offset, BLOCK_SIZE_IN_BYTES);
_mac.TransformBlock(buffer, offset, BLOCK_SIZE_IN_BYTES, null, 0);
}
private void WriteTransformBlocks(byte[] buffer, int offset, int count)
{
int posn = offset;
int last = count + offset;
while (posn < buffer.Length && posn < last)
{
WriteTransformOneBlock (buffer, posn);
posn += BLOCK_SIZE_IN_BYTES;
}
}
private void WriteTransformFinalBlock()
{
if (_pendingCount == 0)
throw new InvalidOperationException("No bytes available.");
if (_finalBlock)
throw new InvalidOperationException("The final block has already been transformed.");
System.Array.Copy(BitConverter.GetBytes(_nonce++), 0, counter, 0, 4);
counterOut = _xform.TransformFinalBlock(counter,
0,
BLOCK_SIZE_IN_BYTES);
XorInPlace(_PendingWriteBlock, 0, _pendingCount);
_mac.TransformFinalBlock(_PendingWriteBlock, 0, _pendingCount);
_finalBlock = true;
}
private int ReadTransformOneBlock(byte[] buffer, int offset, int last)
{
if (_finalBlock)
throw new NotSupportedException();
int bytesRemaining = last - offset;
int bytesToRead = (bytesRemaining > BLOCK_SIZE_IN_BYTES)
? BLOCK_SIZE_IN_BYTES
: bytesRemaining;
// update the counter
System.Array.Copy(BitConverter.GetBytes(_nonce++), 0, counter, 0, 4);
// Determine if this is the final block
if ((bytesToRead == bytesRemaining) &&
(_length > 0) &&
(_totalBytesXferred + last == _length))
{
_mac.TransformFinalBlock(buffer, offset, bytesToRead);
counterOut = _xform.TransformFinalBlock(counter,
0,
BLOCK_SIZE_IN_BYTES);
_finalBlock = true;
}
else
{
_mac.TransformBlock(buffer, offset, bytesToRead, null, 0);
_xform.TransformBlock(counter,
0, // offset
BLOCK_SIZE_IN_BYTES,
counterOut,
0); // offset
}
XorInPlace(buffer, offset, bytesToRead);
return bytesToRead;
}
private void ReadTransformBlocks(byte[] buffer, int offset, int count)
{
int posn = offset;
int last = count + offset;
while (posn < buffer.Length && posn < last )
{
int n = ReadTransformOneBlock (buffer, posn, last);
posn += n;
}
}
public override int Read(byte[] buffer, int offset, int count)
{
if (_mode == CryptoMode.Encrypt)
throw new NotSupportedException();
if (buffer == null)
throw new ArgumentNullException("buffer");
if (offset < 0)
throw new ArgumentOutOfRangeException("offset",
"Must not be less than zero.");
if (count < 0)
throw new ArgumentOutOfRangeException("count",
"Must not be less than zero.");
if (buffer.Length < offset + count)
throw new ArgumentException("The buffer is too small");
// When I wrap a WinZipAesStream in a DeflateStream, the
// DeflateStream asks its captive to read 4k blocks, even if the
// encrypted bytestream is smaller than that. This is a way to
// limit the number of bytes read.
int bytesToRead = count;
if (_totalBytesXferred >= _length)
{
return 0; // EOF
}
long bytesRemaining = _length - _totalBytesXferred;
if (bytesRemaining < count) bytesToRead = (int)bytesRemaining;
int n = _s.Read(buffer, offset, bytesToRead);
#if WANT_TRACE
untransformed.Write(buffer, offset, bytesToRead);
#endif
ReadTransformBlocks(buffer, offset, bytesToRead);
#if WANT_TRACE
transformed.Write(buffer, offset, bytesToRead);
#endif
_totalBytesXferred += n;
return n;
}
/// <summary>
/// Returns the final HMAC-SHA1-80 for the data that was encrypted.
/// </summary>
public byte[] FinalAuthentication
{
get
{
if (!_finalBlock)
{
// special-case zero-byte files
if ( _totalBytesXferred != 0)
throw new BadStateException("The final hash has not been computed.");
// Must call ComputeHash on an empty byte array when no data
// has run through the MAC.
byte[] b = { };
_mac.ComputeHash(b);
// fall through
}
byte[] macBytes10 = new byte[10];
System.Array.Copy(_mac.Hash, 0, macBytes10, 0, 10);
return macBytes10;
}
}
public override void Write(byte[] buffer, int offset, int count)
{
if (_finalBlock)
throw new InvalidOperationException("The final block has already been transformed.");
if (_mode == CryptoMode.Decrypt)
throw new NotSupportedException();
if (buffer == null)
throw new ArgumentNullException("buffer");
if (offset < 0)
throw new ArgumentOutOfRangeException("offset",
"Must not be less than zero.");
if (count < 0)
throw new ArgumentOutOfRangeException("count",
"Must not be less than zero.");
if (buffer.Length < offset + count)
throw new ArgumentException("The offset and count are too large");
if (count == 0)
return;
TraceOutput("Write off({0}) count({1})", offset, count);
#if WANT_TRACE
untransformed.Write(buffer, offset, count);
#endif
// For proper AES encryption, an AES encryptor application calls
// TransformBlock repeatedly for all 16-byte blocks except the
// last. For the last block, it then calls TransformFinalBlock().
//
// This class is a stream that encrypts via Write(). But, it's not
// possible to recognize which are the "last" bytes from within the call
// to Write(). The caller can call Write() several times in succession,
// with varying buffers. This class only "knows" that the last bytes
// have been written when the app calls Close().
//
// Therefore, this class buffers writes: After completion every Write(),
// a 16-byte "pending" block (_PendingWriteBlock) must hold between 1
// and 16 bytes, which will be used in TransformFinalBlock if the app
// calls Close() immediately thereafter. Also, every write must
// transform any pending bytes, before transforming the data passed in
// to the current call.
//
// In operation, after the first call to Write() and before the call to
// Close(), one full or partial block of bytes is always available,
// pending. At time of Close(), this class calls
// WriteTransformFinalBlock() to flush the pending bytes.
//
// This approach works whether the caller writes in odd-sized batches,
// for example 5000 bytes, or in batches that are neat multiples of the
// blocksize (16).
//
// Logicaly, what we do is this:
//
// 1. if there are fewer than 16 bytes (pending + current), then
// just copy them into th pending buffer and return.
//
// 2. there are more than 16 bytes to write. So, take the leading slice
// of bytes from the current buffer, enough to fill the pending
// buffer. Transform the pending block, and write it out.
//
// 3. Take the trailing slice of bytes (a full block or a partial block),
// and copy it to the pending block for next time.
//
// 4. transform and write all the other blocks, the middle slice.
//
// There are 16 or fewer bytes, so just buffer the bytes.
if (count + _pendingCount <= BLOCK_SIZE_IN_BYTES)
{
Buffer.BlockCopy(buffer,
offset,
_PendingWriteBlock,
_pendingCount,
count);
_pendingCount += count;
// At this point, _PendingWriteBlock contains up to
// BLOCK_SIZE_IN_BYTES bytes, and _pendingCount ranges from 0 to
// BLOCK_SIZE_IN_BYTES. We don't want to xform+write them yet,
// because this may have been the last block. The last block gets
// written at Close().
return;
}
// We know there are at least 17 bytes, counting those in the current
// buffer, along with the (possibly empty) pending block.
int bytesRemaining = count;
int curOffset = offset;
// workitem 12815
//
// xform chunkwise ... Cannot transform in place using the original
// buffer because that is user-maintained.
if (_pendingCount != 0)
{
// We have more than one block of data to write, therefore it is safe
// to xform+write.
int fillCount = BLOCK_SIZE_IN_BYTES - _pendingCount;
// fillCount is possibly zero here. That happens when the pending
// buffer held 16 bytes (one complete block) before this call to
// Write.
if (fillCount > 0)
{
Buffer.BlockCopy(buffer,
offset,
_PendingWriteBlock,
_pendingCount,
fillCount);
// adjust counts:
bytesRemaining -= fillCount;
curOffset += fillCount;
}
// xform and write:
WriteTransformOneBlock(_PendingWriteBlock, 0);
_s.Write(_PendingWriteBlock, 0, BLOCK_SIZE_IN_BYTES);
_totalBytesXferred += BLOCK_SIZE_IN_BYTES;
_pendingCount = 0;
}
// At this point _PendingWriteBlock is empty, and bytesRemaining is
// always greater than 0.
// Now, xform N blocks, where N = floor((bytesRemaining-1)/16). If
// writing 32 bytes, then xform 1 block, and stage the remaining 16. If
// writing 10037 bytes, xform 627 blocks of 16 bytes, then stage the
// remaining 5 bytes.
int blocksToXform = (bytesRemaining-1)/BLOCK_SIZE_IN_BYTES;
_pendingCount = bytesRemaining - (blocksToXform * BLOCK_SIZE_IN_BYTES);
// _pendingCount is ALWAYS between 1 and 16.
// Put the last _pendingCount bytes into the pending block.
Buffer.BlockCopy(buffer,
curOffset + bytesRemaining - _pendingCount,
_PendingWriteBlock,
0,
_pendingCount);
bytesRemaining -= _pendingCount;
_totalBytesXferred += bytesRemaining; // will be true after the loop
// now, transform all the full blocks preceding that.
// bytesRemaining is always a multiple of 16 .
if (blocksToXform > 0)
{
do
{
int c = _iobuf.Length;
if (c > bytesRemaining) c = bytesRemaining;
Buffer.BlockCopy(buffer,
curOffset,
_iobuf,
0,
c);
WriteTransformBlocks(_iobuf, 0, c);
_s.Write(_iobuf, 0, c);
bytesRemaining -= c;
curOffset += c;
} while(bytesRemaining > 0);
}
}
/// <summary>
/// Close the stream.
/// </summary>
public override void Close()
{
TraceOutput("Close {0:X8}", this.GetHashCode());
// In the degenerate case, no bytes have been written to the
// stream at all. Need to check here, and NOT emit the
// final block if Write has not been called.
if (_pendingCount > 0)
{
WriteTransformFinalBlock();
_s.Write(_PendingWriteBlock, 0, _pendingCount);
_totalBytesXferred += _pendingCount;
_pendingCount = 0;
}
_s.Close();
#if WANT_TRACE
untransformed.Close();
transformed.Close();
Console.WriteLine("\nuntransformed bytestream is in {0}", traceFileUntransformed);
Console.WriteLine("\ntransformed bytestream is in {0}", traceFileTransformed);
#endif
TraceOutput("-------------------------------------------------------");
}
/// <summary>
/// Returns true if the stream can be read.
/// </summary>
public override bool CanRead
{
get
{
if (_mode != CryptoMode.Decrypt) return false;
return true;
}
}
/// <summary>
/// Always returns false.
/// </summary>
public override bool CanSeek
{
get { return false; }
}
/// <summary>
/// Returns true if the CryptoMode is Encrypt.
/// </summary>
public override bool CanWrite
{
get { return (_mode == CryptoMode.Encrypt); }
}
/// <summary>
/// Flush the content in the stream.
/// </summary>
public override void Flush()
{
_s.Flush();
}
/// <summary>
/// Getting this property throws a NotImplementedException.
/// </summary>
public override long Length
{
get { throw new NotImplementedException(); }
}
/// <summary>
/// Getting or Setting this property throws a NotImplementedException.
/// </summary>
public override long Position
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
/// <summary>
/// This method throws a NotImplementedException.
/// </summary>
public override long Seek(long offset, System.IO.SeekOrigin origin)
{
throw new NotImplementedException();
}
/// <summary>
/// This method throws a NotImplementedException.
/// </summary>
public override void SetLength(long value)
{
throw new NotImplementedException();
}
[System.Diagnostics.ConditionalAttribute("Trace")]
private void TraceOutput(string format, params object[] varParams)
{
lock(_outputLock)
{
int tid = System.Threading.Thread.CurrentThread.GetHashCode();
Console.ForegroundColor = (ConsoleColor) (tid % 8 + 8);
Console.Write("{0:000} WZACS ", tid);
Console.WriteLine(format, varParams);
Console.ResetColor();
}
}
private object _outputLock = new Object();
}
}
#endif

View file

@ -1,51 +0,0 @@
// ZipConstants.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2006, 2007, 2008, 2009 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2009-August-27 23:22:32>
//
// ------------------------------------------------------------------
//
// This module defines a few constants that are used in the project.
//
// ------------------------------------------------------------------
using System;
namespace Ionic.Zip
{
static class ZipConstants
{
public const UInt32 PackedToRemovableMedia = 0x30304b50;
public const UInt32 Zip64EndOfCentralDirectoryRecordSignature = 0x06064b50;
public const UInt32 Zip64EndOfCentralDirectoryLocatorSignature = 0x07064b50;
public const UInt32 EndOfCentralDirectorySignature = 0x06054b50;
public const int ZipEntrySignature = 0x04034b50;
public const int ZipEntryDataDescriptorSignature = 0x08074b50;
public const int SplitArchiveSignature = 0x08074b50;
public const int ZipDirEntrySignature = 0x02014b50;
// These are dictated by the Zip Spec.See APPNOTE.txt
public const int AesKeySize = 192; // 128, 192, 256
public const int AesBlockSize = 128; // ???
public const UInt16 AesAlgId128 = 0x660E;
public const UInt16 AesAlgId192 = 0x660F;
public const UInt16 AesAlgId256 = 0x6610;
}
}

View file

@ -1,455 +0,0 @@
// ZipCrypto.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2008, 2009, 2011 Dino Chiesa
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2011-July-28 06:30:59>
//
// ------------------------------------------------------------------
//
// This module provides the implementation for "traditional" Zip encryption.
//
// Created Tue Apr 15 17:39:56 2008
//
// ------------------------------------------------------------------
using System;
namespace Ionic.Zip
{
/// <summary>
/// This class implements the "traditional" or "classic" PKZip encryption,
/// which today is considered to be weak. On the other hand it is
/// ubiquitous. This class is intended for use only by the DotNetZip
/// library.
/// </summary>
///
/// <remarks>
/// Most uses of the DotNetZip library will not involve direct calls into
/// the ZipCrypto class. Instead, the ZipCrypto class is instantiated and
/// used by the ZipEntry() class when encryption or decryption on an entry
/// is employed. If for some reason you really wanted to use a weak
/// encryption algorithm in some other application, you might use this
/// library. But you would be much better off using one of the built-in
/// strong encryption libraries in the .NET Framework, like the AES
/// algorithm or SHA.
/// </remarks>
internal class ZipCrypto
{
/// <summary>
/// The default constructor for ZipCrypto.
/// </summary>
///
/// <remarks>
/// This class is intended for internal use by the library only. It's
/// probably not useful to you. Seriously. Stop reading this
/// documentation. It's a waste of your time. Go do something else.
/// Check the football scores. Go get an ice cream with a friend.
/// Seriously.
/// </remarks>
///
private ZipCrypto() { }
public static ZipCrypto ForWrite(string password)
{
ZipCrypto z = new ZipCrypto();
if (password == null)
throw new BadPasswordException("This entry requires a password.");
z.InitCipher(password);
return z;
}
public static ZipCrypto ForRead(string password, ZipEntry e)
{
System.IO.Stream s = e._archiveStream;
e._WeakEncryptionHeader = new byte[12];
byte[] eh = e._WeakEncryptionHeader;
ZipCrypto z = new ZipCrypto();
if (password == null)
throw new BadPasswordException("This entry requires a password.");
z.InitCipher(password);
ZipEntry.ReadWeakEncryptionHeader(s, eh);
// Decrypt the header. This has a side effect of "further initializing the
// encryption keys" in the traditional zip encryption.
byte[] DecryptedHeader = z.DecryptMessage(eh, eh.Length);
// CRC check
// According to the pkzip spec, the final byte in the decrypted header
// is the highest-order byte in the CRC. We check it here.
if (DecryptedHeader[11] != (byte)((e._Crc32 >> 24) & 0xff))
{
// In the case that bit 3 of the general purpose bit flag is set to
// indicate the presence of an 'Extended File Header' or a 'data
// descriptor' (signature 0x08074b50), the last byte of the decrypted
// header is sometimes compared with the high-order byte of the
// lastmodified time, rather than the high-order byte of the CRC, to
// verify the password.
//
// This is not documented in the PKWare Appnote.txt. It was
// discovered this by analysis of the Crypt.c source file in the
// InfoZip library http://www.info-zip.org/pub/infozip/
//
// The reason for this is that the CRC for a file cannot be known
// until the entire contents of the file have been streamed. This
// means a tool would have to read the file content TWICE in its
// entirety in order to perform PKZIP encryption - once to compute
// the CRC, and again to actually encrypt.
//
// This is so important for performance that using the timeblob as
// the verification should be the standard practice for DotNetZip
// when using PKZIP encryption. This implies that bit 3 must be
// set. The downside is that some tools still cannot cope with ZIP
// files that use bit 3. Therefore, DotNetZip DOES NOT force bit 3
// when PKZIP encryption is in use, and instead, reads the stream
// twice.
//
if ((e._BitField & 0x0008) != 0x0008)
{
throw new BadPasswordException("The password did not match.");
}
else if (DecryptedHeader[11] != (byte)((e._TimeBlob >> 8) & 0xff))
{
throw new BadPasswordException("The password did not match.");
}
// We have a good password.
}
else
{
// A-OK
}
return z;
}
/// <summary>
/// From AppNote.txt:
/// unsigned char decrypt_byte()
/// local unsigned short temp
/// temp :=- Key(2) | 2
/// decrypt_byte := (temp * (temp ^ 1)) bitshift-right 8
/// end decrypt_byte
/// </summary>
private byte MagicByte
{
get
{
UInt16 t = (UInt16)((UInt16)(_Keys[2] & 0xFFFF) | 2);
return (byte)((t * (t ^ 1)) >> 8);
}
}
// Decrypting:
// From AppNote.txt:
// loop for i from 0 to 11
// C := buffer(i) ^ decrypt_byte()
// update_keys(C)
// buffer(i) := C
// end loop
/// <summary>
/// Call this method on a cipher text to render the plaintext. You must
/// first initialize the cipher with a call to InitCipher.
/// </summary>
///
/// <example>
/// <code>
/// var cipher = new ZipCrypto();
/// cipher.InitCipher(Password);
/// // Decrypt the header. This has a side effect of "further initializing the
/// // encryption keys" in the traditional zip encryption.
/// byte[] DecryptedMessage = cipher.DecryptMessage(EncryptedMessage);
/// </code>
/// </example>
///
/// <param name="cipherText">The encrypted buffer.</param>
/// <param name="length">
/// The number of bytes to encrypt.
/// Should be less than or equal to CipherText.Length.
/// </param>
///
/// <returns>The plaintext.</returns>
public byte[] DecryptMessage(byte[] cipherText, int length)
{
if (cipherText == null)
throw new ArgumentNullException("cipherText");
if (length > cipherText.Length)
throw new ArgumentOutOfRangeException("length",
"Bad length during Decryption: the length parameter must be smaller than or equal to the size of the destination array.");
byte[] plainText = new byte[length];
for (int i = 0; i < length; i++)
{
byte C = (byte)(cipherText[i] ^ MagicByte);
UpdateKeys(C);
plainText[i] = C;
}
return plainText;
}
/// <summary>
/// This is the converse of DecryptMessage. It encrypts the plaintext
/// and produces a ciphertext.
/// </summary>
///
/// <param name="plainText">The plain text buffer.</param>
///
/// <param name="length">
/// The number of bytes to encrypt.
/// Should be less than or equal to plainText.Length.
/// </param>
///
/// <returns>The ciphertext.</returns>
public byte[] EncryptMessage(byte[] plainText, int length)
{
if (plainText == null)
throw new ArgumentNullException("plaintext");
if (length > plainText.Length)
throw new ArgumentOutOfRangeException("length",
"Bad length during Encryption: The length parameter must be smaller than or equal to the size of the destination array.");
byte[] cipherText = new byte[length];
for (int i = 0; i < length; i++)
{
byte C = plainText[i];
cipherText[i] = (byte)(plainText[i] ^ MagicByte);
UpdateKeys(C);
}
return cipherText;
}
/// <summary>
/// This initializes the cipher with the given password.
/// See AppNote.txt for details.
/// </summary>
///
/// <param name="passphrase">
/// The passphrase for encrypting or decrypting with this cipher.
/// </param>
///
/// <remarks>
/// <code>
/// Step 1 - Initializing the encryption keys
/// -----------------------------------------
/// Start with these keys:
/// Key(0) := 305419896 (0x12345678)
/// Key(1) := 591751049 (0x23456789)
/// Key(2) := 878082192 (0x34567890)
///
/// Then, initialize the keys with a password:
///
/// loop for i from 0 to length(password)-1
/// update_keys(password(i))
/// end loop
///
/// Where update_keys() is defined as:
///
/// update_keys(char):
/// Key(0) := crc32(key(0),char)
/// Key(1) := Key(1) + (Key(0) bitwiseAND 000000ffH)
/// Key(1) := Key(1) * 134775813 + 1
/// Key(2) := crc32(key(2),key(1) rightshift 24)
/// end update_keys
///
/// Where crc32(old_crc,char) is a routine that given a CRC value and a
/// character, returns an updated CRC value after applying the CRC-32
/// algorithm described elsewhere in this document.
///
/// </code>
///
/// <para>
/// After the keys are initialized, then you can use the cipher to
/// encrypt the plaintext.
/// </para>
///
/// <para>
/// Essentially we encrypt the password with the keys, then discard the
/// ciphertext for the password. This initializes the keys for later use.
/// </para>
///
/// </remarks>
public void InitCipher(string passphrase)
{
byte[] p = SharedUtilities.StringToByteArray(passphrase);
for (int i = 0; i < passphrase.Length; i++)
UpdateKeys(p[i]);
}
private void UpdateKeys(byte byteValue)
{
_Keys[0] = (UInt32)crc32.ComputeCrc32((int)_Keys[0], byteValue);
_Keys[1] = _Keys[1] + (byte)_Keys[0];
_Keys[1] = _Keys[1] * 0x08088405 + 1;
_Keys[2] = (UInt32)crc32.ComputeCrc32((int)_Keys[2], (byte)(_Keys[1] >> 24));
}
///// <summary>
///// The byte array representing the seed keys used.
///// Get this after calling InitCipher. The 12 bytes represents
///// what the zip spec calls the "EncryptionHeader".
///// </summary>
//public byte[] KeyHeader
//{
// get
// {
// byte[] result = new byte[12];
// result[0] = (byte)(_Keys[0] & 0xff);
// result[1] = (byte)((_Keys[0] >> 8) & 0xff);
// result[2] = (byte)((_Keys[0] >> 16) & 0xff);
// result[3] = (byte)((_Keys[0] >> 24) & 0xff);
// result[4] = (byte)(_Keys[1] & 0xff);
// result[5] = (byte)((_Keys[1] >> 8) & 0xff);
// result[6] = (byte)((_Keys[1] >> 16) & 0xff);
// result[7] = (byte)((_Keys[1] >> 24) & 0xff);
// result[8] = (byte)(_Keys[2] & 0xff);
// result[9] = (byte)((_Keys[2] >> 8) & 0xff);
// result[10] = (byte)((_Keys[2] >> 16) & 0xff);
// result[11] = (byte)((_Keys[2] >> 24) & 0xff);
// return result;
// }
//}
// private fields for the crypto stuff:
private UInt32[] _Keys = { 0x12345678, 0x23456789, 0x34567890 };
private Ionic.Crc.CRC32 crc32 = new Ionic.Crc.CRC32();
}
internal enum CryptoMode
{
Encrypt,
Decrypt
}
/// <summary>
/// A Stream for reading and concurrently decrypting data from a zip file,
/// or for writing and concurrently encrypting data to a zip file.
/// </summary>
internal class ZipCipherStream : System.IO.Stream
{
private ZipCrypto _cipher;
private System.IO.Stream _s;
private CryptoMode _mode;
/// <summary> The constructor. </summary>
/// <param name="s">The underlying stream</param>
/// <param name="mode">To either encrypt or decrypt.</param>
/// <param name="cipher">The pre-initialized ZipCrypto object.</param>
public ZipCipherStream(System.IO.Stream s, ZipCrypto cipher, CryptoMode mode)
: base()
{
_cipher = cipher;
_s = s;
_mode = mode;
}
public override int Read(byte[] buffer, int offset, int count)
{
if (_mode == CryptoMode.Encrypt)
throw new NotSupportedException("This stream does not encrypt via Read()");
if (buffer == null)
throw new ArgumentNullException("buffer");
byte[] db = new byte[count];
int n = _s.Read(db, 0, count);
byte[] decrypted = _cipher.DecryptMessage(db, n);
for (int i = 0; i < n; i++)
{
buffer[offset + i] = decrypted[i];
}
return n;
}
public override void Write(byte[] buffer, int offset, int count)
{
if (_mode == CryptoMode.Decrypt)
throw new NotSupportedException("This stream does not Decrypt via Write()");
if (buffer == null)
throw new ArgumentNullException("buffer");
// workitem 7696
if (count == 0) return;
byte[] plaintext = null;
if (offset != 0)
{
plaintext = new byte[count];
for (int i = 0; i < count; i++)
{
plaintext[i] = buffer[offset + i];
}
}
else plaintext = buffer;
byte[] encrypted = _cipher.EncryptMessage(plaintext, count);
_s.Write(encrypted, 0, encrypted.Length);
}
public override bool CanRead
{
get { return (_mode == CryptoMode.Decrypt); }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return (_mode == CryptoMode.Encrypt); }
}
public override void Flush()
{
//throw new NotSupportedException();
}
public override long Length
{
get { throw new NotSupportedException(); }
}
public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
public override long Seek(long offset, System.IO.SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
}
}

View file

@ -1,381 +0,0 @@
// ZipDirEntry.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2006-2011 Dino Chiesa .
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2011-July-11 12:03:03>
//
// ------------------------------------------------------------------
//
// This module defines members of the ZipEntry class for reading the
// Zip file central directory.
//
// Created: Tue, 27 Mar 2007 15:30
//
// ------------------------------------------------------------------
using System;
using System.Collections.Generic;
namespace Ionic.Zip
{
partial class ZipEntry
{
/// <summary>
/// True if the referenced entry is a directory.
/// </summary>
internal bool AttributesIndicateDirectory
{
get { return ((_InternalFileAttrs == 0) && ((_ExternalFileAttrs & 0x0010) == 0x0010)); }
}
internal void ResetDirEntry()
{
// __FileDataPosition is the position of the file data for an entry.
// It is _RelativeOffsetOfLocalHeader + size of local header.
// We cannot know the __FileDataPosition until we read the local
// header.
// The local header is not necessarily the same length as the record
// in the central directory.
// Set to -1, to indicate we need to read this later.
this.__FileDataPosition = -1;
// set _LengthOfHeader to 0, to indicate we need to read later.
this._LengthOfHeader = 0;
}
/// <summary>
/// Provides a human-readable string with information about the ZipEntry.
/// </summary>
public string Info
{
get
{
var builder = new System.Text.StringBuilder();
builder
.Append(string.Format(" ZipEntry: {0}\n", this.FileName))
.Append(string.Format(" Version Made By: {0}\n", this._VersionMadeBy))
.Append(string.Format(" Needed to extract: {0}\n", this.VersionNeeded));
if (this._IsDirectory)
builder.Append(" Entry type: directory\n");
else
{
builder.Append(string.Format(" File type: {0}\n", this._IsText? "text":"binary"))
.Append(string.Format(" Compression: {0}\n", this.CompressionMethod))
.Append(string.Format(" Compressed: 0x{0:X}\n", this.CompressedSize))
.Append(string.Format(" Uncompressed: 0x{0:X}\n", this.UncompressedSize))
.Append(string.Format(" CRC32: 0x{0:X8}\n", this._Crc32));
}
builder.Append(string.Format(" Disk Number: {0}\n", this._diskNumber));
if (this._RelativeOffsetOfLocalHeader > 0xFFFFFFFF)
builder
.Append(string.Format(" Relative Offset: 0x{0:X16}\n", this._RelativeOffsetOfLocalHeader));
else
builder
.Append(string.Format(" Relative Offset: 0x{0:X8}\n", this._RelativeOffsetOfLocalHeader));
builder
.Append(string.Format(" Bit Field: 0x{0:X4}\n", this._BitField))
.Append(string.Format(" Encrypted?: {0}\n", this._sourceIsEncrypted))
.Append(string.Format(" Timeblob: 0x{0:X8}\n", this._TimeBlob))
.Append(string.Format(" Time: {0}\n", Ionic.Zip.SharedUtilities.PackedToDateTime(this._TimeBlob)));
builder.Append(string.Format(" Is Zip64?: {0}\n", this._InputUsesZip64));
if (!string.IsNullOrEmpty(this._Comment))
{
builder.Append(string.Format(" Comment: {0}\n", this._Comment));
}
builder.Append("\n");
return builder.ToString();
}
}
// workitem 10330
private class CopyHelper
{
private static System.Text.RegularExpressions.Regex re =
new System.Text.RegularExpressions.Regex(" \\(copy (\\d+)\\)$");
private static int callCount = 0;
internal static string AppendCopyToFileName(string f)
{
callCount++;
if (callCount > 25)
throw new OverflowException("overflow while creating filename");
int n = 1;
int r = f.LastIndexOf(".");
if (r == -1)
{
// there is no extension
System.Text.RegularExpressions.Match m = re.Match(f);
if (m.Success)
{
n = Int32.Parse(m.Groups[1].Value) + 1;
string copy = String.Format(" (copy {0})", n);
f = f.Substring(0, m.Index) + copy;
}
else
{
string copy = String.Format(" (copy {0})", n);
f = f + copy;
}
}
else
{
//System.Console.WriteLine("HasExtension");
System.Text.RegularExpressions.Match m = re.Match(f.Substring(0, r));
if (m.Success)
{
n = Int32.Parse(m.Groups[1].Value) + 1;
string copy = String.Format(" (copy {0})", n);
f = f.Substring(0, m.Index) + copy + f.Substring(r);
}
else
{
string copy = String.Format(" (copy {0})", n);
f = f.Substring(0, r) + copy + f.Substring(r);
}
//System.Console.WriteLine("returning f({0})", f);
}
return f;
}
}
/// <summary>
/// Reads one entry from the zip directory structure in the zip file.
/// </summary>
///
/// <param name="zf">
/// The zipfile for which a directory entry will be read. From this param, the
/// method gets the ReadStream and the expected text encoding
/// (ProvisionalAlternateEncoding) which is used if the entry is not marked
/// UTF-8.
/// </param>
///
/// <param name="previouslySeen">
/// a list of previously seen entry names; used to prevent duplicates.
/// </param>
///
/// <returns>the entry read from the archive.</returns>
internal static ZipEntry ReadDirEntry(ZipFile zf,
Dictionary<String,Object> previouslySeen)
{
System.IO.Stream s = zf.ReadStream;
System.Text.Encoding expectedEncoding = (zf.AlternateEncodingUsage == ZipOption.Always)
? zf.AlternateEncoding
: ZipFile.DefaultEncoding;
int signature = Ionic.Zip.SharedUtilities.ReadSignature(s);
// return null if this is not a local file header signature
if (IsNotValidZipDirEntrySig(signature))
{
s.Seek(-4, System.IO.SeekOrigin.Current);
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(s);
// Getting "not a ZipDirEntry signature" here is not always wrong or an
// error. This can happen when walking through a zipfile. After the
// last ZipDirEntry, we expect to read an
// EndOfCentralDirectorySignature. When we get this is how we know
// we've reached the end of the central directory.
if (signature != ZipConstants.EndOfCentralDirectorySignature &&
signature != ZipConstants.Zip64EndOfCentralDirectoryRecordSignature &&
signature != ZipConstants.ZipEntrySignature // workitem 8299
)
{
throw new BadReadException(String.Format(" Bad signature (0x{0:X8}) at position 0x{1:X8}", signature, s.Position));
}
return null;
}
int bytesRead = 42 + 4;
byte[] block = new byte[42];
int n = s.Read(block, 0, block.Length);
if (n != block.Length) return null;
int i = 0;
ZipEntry zde = new ZipEntry();
zde.AlternateEncoding = expectedEncoding;
zde._Source = ZipEntrySource.ZipFile;
zde._container = new ZipContainer(zf);
unchecked
{
zde._VersionMadeBy = (short)(block[i++] + block[i++] * 256);
zde._VersionNeeded = (short)(block[i++] + block[i++] * 256);
zde._BitField = (short)(block[i++] + block[i++] * 256);
zde._CompressionMethod = (Int16)(block[i++] + block[i++] * 256);
zde._TimeBlob = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;
zde._LastModified = Ionic.Zip.SharedUtilities.PackedToDateTime(zde._TimeBlob);
zde._timestamp |= ZipEntryTimestamp.DOS;
zde._Crc32 = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;
zde._CompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
zde._UncompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
}
// preserve
zde._CompressionMethod_FromZipFile = zde._CompressionMethod;
zde._filenameLength = (short)(block[i++] + block[i++] * 256);
zde._extraFieldLength = (short)(block[i++] + block[i++] * 256);
zde._commentLength = (short)(block[i++] + block[i++] * 256);
zde._diskNumber = (UInt32)(block[i++] + block[i++] * 256);
zde._InternalFileAttrs = (short)(block[i++] + block[i++] * 256);
zde._ExternalFileAttrs = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;
zde._RelativeOffsetOfLocalHeader = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
// workitem 7801
zde.IsText = ((zde._InternalFileAttrs & 0x01) == 0x01);
block = new byte[zde._filenameLength];
n = s.Read(block, 0, block.Length);
bytesRead += n;
if ((zde._BitField & 0x0800) == 0x0800)
{
// UTF-8 is in use
zde._FileNameInArchive = Ionic.Zip.SharedUtilities.Utf8StringFromBuffer(block);
}
else
{
zde._FileNameInArchive = Ionic.Zip.SharedUtilities.StringFromBuffer(block, expectedEncoding);
}
// workitem 10330
// insure unique entry names
while (previouslySeen.ContainsKey(zde._FileNameInArchive))
{
zde._FileNameInArchive = CopyHelper.AppendCopyToFileName(zde._FileNameInArchive);
zde._metadataChanged = true;
}
if (zde.AttributesIndicateDirectory)
zde.MarkAsDirectory(); // may append a slash to filename if nec.
// workitem 6898
else if (zde._FileNameInArchive.EndsWith("/")) zde.MarkAsDirectory();
zde._CompressedFileDataSize = zde._CompressedSize;
if ((zde._BitField & 0x01) == 0x01)
{
// this may change after processing the Extra field
zde._Encryption_FromZipFile = zde._Encryption =
EncryptionAlgorithm.PkzipWeak;
zde._sourceIsEncrypted = true;
}
if (zde._extraFieldLength > 0)
{
zde._InputUsesZip64 = (zde._CompressedSize == 0xFFFFFFFF ||
zde._UncompressedSize == 0xFFFFFFFF ||
zde._RelativeOffsetOfLocalHeader == 0xFFFFFFFF);
// Console.WriteLine(" Input uses Z64?: {0}", zde._InputUsesZip64);
bytesRead += zde.ProcessExtraField(s, zde._extraFieldLength);
zde._CompressedFileDataSize = zde._CompressedSize;
}
// we've processed the extra field, so we know the encryption method is set now.
if (zde._Encryption == EncryptionAlgorithm.PkzipWeak)
{
// the "encryption header" of 12 bytes precedes the file data
zde._CompressedFileDataSize -= 12;
}
#if AESCRYPTO
else if (zde.Encryption == EncryptionAlgorithm.WinZipAes128 ||
zde.Encryption == EncryptionAlgorithm.WinZipAes256)
{
zde._CompressedFileDataSize = zde.CompressedSize -
(ZipEntry.GetLengthOfCryptoHeaderBytes(zde.Encryption) + 10);
zde._LengthOfTrailer = 10;
}
#endif
// tally the trailing descriptor
if ((zde._BitField & 0x0008) == 0x0008)
{
// sig, CRC, Comp and Uncomp sizes
if (zde._InputUsesZip64)
zde._LengthOfTrailer += 24;
else
zde._LengthOfTrailer += 16;
}
// workitem 12744
zde.AlternateEncoding = ((zde._BitField & 0x0800) == 0x0800)
? System.Text.Encoding.UTF8
:expectedEncoding;
zde.AlternateEncodingUsage = ZipOption.Always;
if (zde._commentLength > 0)
{
block = new byte[zde._commentLength];
n = s.Read(block, 0, block.Length);
bytesRead += n;
if ((zde._BitField & 0x0800) == 0x0800)
{
// UTF-8 is in use
zde._Comment = Ionic.Zip.SharedUtilities.Utf8StringFromBuffer(block);
}
else
{
zde._Comment = Ionic.Zip.SharedUtilities.StringFromBuffer(block, expectedEncoding);
}
}
//zde._LengthOfDirEntry = bytesRead;
return zde;
}
/// <summary>
/// Returns true if the passed-in value is a valid signature for a ZipDirEntry.
/// </summary>
/// <param name="signature">the candidate 4-byte signature value.</param>
/// <returns>true, if the signature is valid according to the PKWare spec.</returns>
internal static bool IsNotValidZipDirEntrySig(int signature)
{
return (signature != ZipConstants.ZipDirEntrySignature);
}
private Int16 _VersionMadeBy;
private Int16 _InternalFileAttrs;
private Int32 _ExternalFileAttrs;
//private Int32 _LengthOfDirEntry;
private Int16 _filenameLength;
private Int16 _extraFieldLength;
private Int16 _commentLength;
}
}

View file

@ -1,798 +0,0 @@
// ZipEntry.Read.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009-2011 Dino Chiesa
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2011-July-09 21:31:28>
//
// ------------------------------------------------------------------
//
// This module defines logic for Reading the ZipEntry from a
// zip file.
//
// ------------------------------------------------------------------
using System;
using System.IO;
namespace Ionic.Zip
{
public partial class ZipEntry
{
private int _readExtraDepth;
private void ReadExtraField()
{
_readExtraDepth++;
// workitem 8098: ok (restore)
long posn = this.ArchiveStream.Position;
this.ArchiveStream.Seek(this._RelativeOffsetOfLocalHeader, SeekOrigin.Begin);
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(this.ArchiveStream);
byte[] block = new byte[30];
this.ArchiveStream.Read(block, 0, block.Length);
int i = 26;
Int16 filenameLength = (short)(block[i++] + block[i++] * 256);
Int16 extraFieldLength = (short)(block[i++] + block[i++] * 256);
// workitem 8098: ok (relative)
this.ArchiveStream.Seek(filenameLength, SeekOrigin.Current);
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(this.ArchiveStream);
ProcessExtraField(this.ArchiveStream, extraFieldLength);
// workitem 8098: ok (restore)
this.ArchiveStream.Seek(posn, SeekOrigin.Begin);
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(this.ArchiveStream);
_readExtraDepth--;
}
private static bool ReadHeader(ZipEntry ze, System.Text.Encoding defaultEncoding)
{
int bytesRead = 0;
// change for workitem 8098
ze._RelativeOffsetOfLocalHeader = ze.ArchiveStream.Position;
int signature = Ionic.Zip.SharedUtilities.ReadEntrySignature(ze.ArchiveStream);
bytesRead += 4;
// Return false if this is not a local file header signature.
if (ZipEntry.IsNotValidSig(signature))
{
// Getting "not a ZipEntry signature" is not always wrong or an error.
// This will happen after the last entry in a zipfile. In that case, we
// expect to read :
// a ZipDirEntry signature (if a non-empty zip file) or
// a ZipConstants.EndOfCentralDirectorySignature.
//
// Anything else is a surprise.
ze.ArchiveStream.Seek(-4, SeekOrigin.Current); // unread the signature
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(ze.ArchiveStream);
if (ZipEntry.IsNotValidZipDirEntrySig(signature) && (signature != ZipConstants.EndOfCentralDirectorySignature))
{
throw new BadReadException(String.Format(" Bad signature (0x{0:X8}) at position 0x{1:X8}", signature, ze.ArchiveStream.Position));
}
return false;
}
byte[] block = new byte[26];
int n = ze.ArchiveStream.Read(block, 0, block.Length);
if (n != block.Length) return false;
bytesRead += n;
int i = 0;
ze._VersionNeeded = (Int16)(block[i++] + block[i++] * 256);
ze._BitField = (Int16)(block[i++] + block[i++] * 256);
ze._CompressionMethod_FromZipFile = ze._CompressionMethod = (Int16)(block[i++] + block[i++] * 256);
ze._TimeBlob = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;
// transform the time data into something usable (a DateTime)
ze._LastModified = Ionic.Zip.SharedUtilities.PackedToDateTime(ze._TimeBlob);
ze._timestamp |= ZipEntryTimestamp.DOS;
if ((ze._BitField & 0x01) == 0x01)
{
ze._Encryption_FromZipFile = ze._Encryption = EncryptionAlgorithm.PkzipWeak; // this *may* change after processing the Extra field
ze._sourceIsEncrypted = true;
}
// NB: if ((ze._BitField & 0x0008) != 0x0008), then the Compressed, uncompressed and
// CRC values are not true values; the true values will follow the entry data.
// But, regardless of the status of bit 3 in the bitfield, the slots for
// the three amigos may contain marker values for ZIP64. So we must read them.
{
ze._Crc32 = (Int32)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
ze._CompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
ze._UncompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
if ((uint)ze._CompressedSize == 0xFFFFFFFF ||
(uint)ze._UncompressedSize == 0xFFFFFFFF)
ze._InputUsesZip64 = true;
}
Int16 filenameLength = (short)(block[i++] + block[i++] * 256);
Int16 extraFieldLength = (short)(block[i++] + block[i++] * 256);
block = new byte[filenameLength];
n = ze.ArchiveStream.Read(block, 0, block.Length);
bytesRead += n;
// if the UTF8 bit is set for this entry, override the
// encoding the application requested.
if ((ze._BitField & 0x0800) == 0x0800)
{
// workitem 12744
ze.AlternateEncoding = System.Text.Encoding.UTF8;
ze.AlternateEncodingUsage = ZipOption.Always;
}
// need to use this form of GetString() for .NET CF
ze._FileNameInArchive = ze.AlternateEncoding.GetString(block, 0, block.Length);
// workitem 6898
if (ze._FileNameInArchive.EndsWith("/")) ze.MarkAsDirectory();
bytesRead += ze.ProcessExtraField(ze.ArchiveStream, extraFieldLength);
ze._LengthOfTrailer = 0;
// workitem 6607 - don't read for directories
// actually get the compressed size and CRC if necessary
if (!ze._FileNameInArchive.EndsWith("/") && (ze._BitField & 0x0008) == 0x0008)
{
// This descriptor exists only if bit 3 of the general
// purpose bit flag is set (see below). It is byte aligned
// and immediately follows the last byte of compressed data,
// as well as any encryption trailer, as with AES.
// This descriptor is used only when it was not possible to
// seek in the output .ZIP file, e.g., when the output .ZIP file
// was standard output or a non-seekable device. For ZIP64(tm) format
// archives, the compressed and uncompressed sizes are 8 bytes each.
// workitem 8098: ok (restore)
long posn = ze.ArchiveStream.Position;
// Here, we're going to loop until we find a ZipEntryDataDescriptorSignature and
// a consistent data record after that. To be consistent, the data record must
// indicate the length of the entry data.
bool wantMore = true;
long SizeOfDataRead = 0;
int tries = 0;
while (wantMore)
{
tries++;
// We call the FindSignature shared routine to find the specified signature
// in the already-opened zip archive, starting from the current cursor
// position in that filestream. If we cannot find the signature, then the
// routine returns -1, and the ReadHeader() method returns false,
// indicating we cannot read a legal entry header. If we have found it,
// then the FindSignature() method returns the number of bytes in the
// stream we had to seek forward, to find the sig. We need this to
// determine if the zip entry is valid, later.
if (ze._container.ZipFile != null)
ze._container.ZipFile.OnReadBytes(ze);
long d = Ionic.Zip.SharedUtilities.FindSignature(ze.ArchiveStream, ZipConstants.ZipEntryDataDescriptorSignature);
if (d == -1) return false;
// total size of data read (through all loops of this).
SizeOfDataRead += d;
if (ze._InputUsesZip64)
{
// read 1x 4-byte (CRC) and 2x 8-bytes (Compressed Size, Uncompressed Size)
block = new byte[20];
n = ze.ArchiveStream.Read(block, 0, block.Length);
if (n != 20) return false;
// do not increment bytesRead - it is for entry header only.
// the data we have just read is a footer (falls after the file data)
//bytesRead += n;
i = 0;
ze._Crc32 = (Int32)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
ze._CompressedSize = BitConverter.ToInt64(block, i);
i += 8;
ze._UncompressedSize = BitConverter.ToInt64(block, i);
i += 8;
ze._LengthOfTrailer += 24; // bytes including sig, CRC, Comp and Uncomp sizes
}
else
{
// read 3x 4-byte fields (CRC, Compressed Size, Uncompressed Size)
block = new byte[12];
n = ze.ArchiveStream.Read(block, 0, block.Length);
if (n != 12) return false;
// do not increment bytesRead - it is for entry header only.
// the data we have just read is a footer (falls after the file data)
//bytesRead += n;
i = 0;
ze._Crc32 = (Int32)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
ze._CompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
ze._UncompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
ze._LengthOfTrailer += 16; // bytes including sig, CRC, Comp and Uncomp sizes
}
wantMore = (SizeOfDataRead != ze._CompressedSize);
if (wantMore)
{
// Seek back to un-read the last 12 bytes - maybe THEY contain
// the ZipEntryDataDescriptorSignature.
// (12 bytes for the CRC, Comp and Uncomp size.)
ze.ArchiveStream.Seek(-12, SeekOrigin.Current);
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(ze.ArchiveStream);
// Adjust the size to account for the false signature read in
// FindSignature().
SizeOfDataRead += 4;
}
}
// seek back to previous position, to prepare to read file data
// workitem 8098: ok (restore)
ze.ArchiveStream.Seek(posn, SeekOrigin.Begin);
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(ze.ArchiveStream);
}
ze._CompressedFileDataSize = ze._CompressedSize;
// bit 0 set indicates that some kind of encryption is in use
if ((ze._BitField & 0x01) == 0x01)
{
#if AESCRYPTO
if (ze.Encryption == EncryptionAlgorithm.WinZipAes128 ||
ze.Encryption == EncryptionAlgorithm.WinZipAes256)
{
int bits = ZipEntry.GetKeyStrengthInBits(ze._Encryption_FromZipFile);
// read in the WinZip AES metadata: salt + PV. 18 bytes for AES256. 10 bytes for AES128.
ze._aesCrypto_forExtract = WinZipAesCrypto.ReadFromStream(null, bits, ze.ArchiveStream);
bytesRead += ze._aesCrypto_forExtract.SizeOfEncryptionMetadata - 10; // MAC (follows crypto bytes)
// according to WinZip, the CompressedSize includes the AES Crypto framing data.
ze._CompressedFileDataSize -= ze._aesCrypto_forExtract.SizeOfEncryptionMetadata;
ze._LengthOfTrailer += 10; // MAC
}
else
#endif
{
// read in the header data for "weak" encryption
ze._WeakEncryptionHeader = new byte[12];
bytesRead += ZipEntry.ReadWeakEncryptionHeader(ze._archiveStream, ze._WeakEncryptionHeader);
// decrease the filedata size by 12 bytes
ze._CompressedFileDataSize -= 12;
}
}
// Remember the size of the blob for this entry.
// We also have the starting position in the stream for this entry.
ze._LengthOfHeader = bytesRead;
ze._TotalEntrySize = ze._LengthOfHeader + ze._CompressedFileDataSize + ze._LengthOfTrailer;
// We've read in the regular entry header, the extra field, and any
// encryption header. The pointer in the file is now at the start of the
// filedata, which is potentially compressed and encrypted. Just ahead in
// the file, there are _CompressedFileDataSize bytes of data, followed by
// potentially a non-zero length trailer, consisting of optionally, some
// encryption stuff (10 byte MAC for AES), and the bit-3 trailer (16 or 24
// bytes).
return true;
}
internal static int ReadWeakEncryptionHeader(Stream s, byte[] buffer)
{
// PKZIP encrypts the compressed data stream. Encrypted files must
// be decrypted before they can be extracted.
// Each PKZIP-encrypted file has an extra 12 bytes stored at the start of the data
// area defining the encryption header for that file. The encryption header is
// originally set to random values, and then itself encrypted, using three, 32-bit
// keys. The key values are initialized using the supplied encryption password.
// After each byte is encrypted, the keys are then updated using pseudo-random
// number generation techniques in combination with the same CRC-32 algorithm used
// in PKZIP and implemented in the CRC32.cs module in this project.
// read the 12-byte encryption header
int additionalBytesRead = s.Read(buffer, 0, 12);
if (additionalBytesRead != 12)
throw new ZipException(String.Format("Unexpected end of data at position 0x{0:X8}", s.Position));
return additionalBytesRead;
}
private static bool IsNotValidSig(int signature)
{
return (signature != ZipConstants.ZipEntrySignature);
}
/// <summary>
/// Reads one <c>ZipEntry</c> from the given stream. The content for
/// the entry does not get decompressed or decrypted. This method
/// basically reads metadata, and seeks.
/// </summary>
/// <param name="zc">the ZipContainer this entry belongs to.</param>
/// <param name="first">
/// true of this is the first entry being read from the stream.
/// </param>
/// <returns>the <c>ZipEntry</c> read from the stream.</returns>
internal static ZipEntry ReadEntry(ZipContainer zc, bool first)
{
ZipFile zf = zc.ZipFile;
Stream s = zc.ReadStream;
System.Text.Encoding defaultEncoding = zc.AlternateEncoding;
ZipEntry entry = new ZipEntry();
entry._Source = ZipEntrySource.ZipFile;
entry._container = zc;
entry._archiveStream = s;
if (zf != null)
zf.OnReadEntry(true, null);
if (first) HandlePK00Prefix(s);
// Read entry header, including any encryption header
if (!ReadHeader(entry, defaultEncoding)) return null;
// Store the position in the stream for this entry
// change for workitem 8098
entry.__FileDataPosition = entry.ArchiveStream.Position;
// seek past the data without reading it. We will read on Extract()
s.Seek(entry._CompressedFileDataSize + entry._LengthOfTrailer, SeekOrigin.Current);
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(s);
// ReadHeader moves the file pointer to the end of the entry header,
// as well as any encryption header.
// CompressedFileDataSize includes:
// the maybe compressed, maybe encrypted file data
// the encryption trailer, if any
// the bit 3 descriptor, if any
// workitem 5306
// http://www.codeplex.com/DotNetZip/WorkItem/View.aspx?WorkItemId=5306
HandleUnexpectedDataDescriptor(entry);
if (zf != null)
{
zf.OnReadBytes(entry);
zf.OnReadEntry(false, entry);
}
return entry;
}
internal static void HandlePK00Prefix(Stream s)
{
// in some cases, the zip file begins with "PK00". This is a throwback and is rare,
// but we handle it anyway. We do not change behavior based on it.
uint datum = (uint)Ionic.Zip.SharedUtilities.ReadInt(s);
if (datum != ZipConstants.PackedToRemovableMedia)
{
s.Seek(-4, SeekOrigin.Current); // unread the block
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(s);
}
}
private static void HandleUnexpectedDataDescriptor(ZipEntry entry)
{
Stream s = entry.ArchiveStream;
// In some cases, the "data descriptor" is present, without a signature, even when
// bit 3 of the BitField is NOT SET. This is the CRC, followed
// by the compressed length and the uncompressed length (4 bytes for each
// of those three elements). Need to check that here.
//
uint datum = (uint)Ionic.Zip.SharedUtilities.ReadInt(s);
if (datum == entry._Crc32)
{
int sz = Ionic.Zip.SharedUtilities.ReadInt(s);
if (sz == entry._CompressedSize)
{
sz = Ionic.Zip.SharedUtilities.ReadInt(s);
if (sz == entry._UncompressedSize)
{
// ignore everything and discard it.
}
else
{
s.Seek(-12, SeekOrigin.Current); // unread the three blocks
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(s);
}
}
else
{
s.Seek(-8, SeekOrigin.Current); // unread the two blocks
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(s);
}
}
else
{
s.Seek(-4, SeekOrigin.Current); // unread the block
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(s);
}
}
/// <summary>
/// Finds a particular segment in the given extra field.
/// This is used when modifying a previously-generated
/// extra field, in particular when removing the AES crypto
/// segment in the extra field.
/// </summary>
static internal int FindExtraFieldSegment(byte[] extra, int offx, UInt16 targetHeaderId)
{
int j = offx;
while (j + 3 < extra.Length)
{
UInt16 headerId = (UInt16)(extra[j++] + extra[j++] * 256);
if (headerId == targetHeaderId) return j-2;
// else advance to next segment
Int16 dataSize = (short)(extra[j++] + extra[j++] * 256);
j+= dataSize;
}
return -1;
}
/// <summary>
/// At current cursor position in the stream, read the extra
/// field, and set the properties on the ZipEntry instance
/// appropriately. This can be called when processing the
/// Extra field in the Central Directory, or in the local
/// header.
/// </summary>
internal int ProcessExtraField(Stream s, Int16 extraFieldLength)
{
int additionalBytesRead = 0;
if (extraFieldLength > 0)
{
byte[] buffer = this._Extra = new byte[extraFieldLength];
additionalBytesRead = s.Read(buffer, 0, buffer.Length);
long posn = s.Position - additionalBytesRead;
int j = 0;
while (j + 3 < buffer.Length)
{
int start = j;
UInt16 headerId = (UInt16)(buffer[j++] + buffer[j++] * 256);
Int16 dataSize = (short)(buffer[j++] + buffer[j++] * 256);
switch (headerId)
{
case 0x000a: // NTFS ctime, atime, mtime
j = ProcessExtraFieldWindowsTimes(buffer, j, dataSize, posn);
break;
case 0x5455: // Unix ctime, atime, mtime
j = ProcessExtraFieldUnixTimes(buffer, j, dataSize, posn);
break;
case 0x5855: // Info-zip Extra field (outdated)
// This is outdated, so the field is supported on
// read only.
j = ProcessExtraFieldInfoZipTimes(buffer, j, dataSize, posn);
break;
case 0x7855: // Unix uid/gid
// ignored. DotNetZip does not handle this field.
break;
case 0x7875: // ??
// ignored. I could not find documentation on this field,
// though it appears in some zip files.
break;
case 0x0001: // ZIP64
j = ProcessExtraFieldZip64(buffer, j, dataSize, posn);
break;
#if AESCRYPTO
case 0x9901: // WinZip AES encryption is in use. (workitem 6834)
// we will handle this extra field only if compressionmethod is 0x63
j = ProcessExtraFieldWinZipAes(buffer, j, dataSize, posn);
break;
#endif
case 0x0017: // workitem 7968: handle PKWare Strong encryption header
j = ProcessExtraFieldPkwareStrongEncryption(buffer, j);
break;
}
// move to the next Header in the extra field
j = start + dataSize + 4;
}
}
return additionalBytesRead;
}
private int ProcessExtraFieldPkwareStrongEncryption(byte[] Buffer, int j)
{
// Value Size Description
// ----- ---- -----------
// 0x0017 2 bytes Tag for this "extra" block type
// TSize 2 bytes Size of data that follows
// Format 2 bytes Format definition for this record
// AlgID 2 bytes Encryption algorithm identifier
// Bitlen 2 bytes Bit length of encryption key
// Flags 2 bytes Processing flags
// CertData TSize-8 Certificate decryption extra field data
// (refer to the explanation for CertData
// in the section describing the
// Certificate Processing Method under
// the Strong Encryption Specification)
j += 2;
_UnsupportedAlgorithmId = (UInt16)(Buffer[j++] + Buffer[j++] * 256);
_Encryption_FromZipFile = _Encryption = EncryptionAlgorithm.Unsupported;
// DotNetZip doesn't support this algorithm, but we don't need to throw
// here. we might just be reading the archive, which is fine. We'll
// need to throw if Extract() is called.
return j;
}
#if AESCRYPTO
private int ProcessExtraFieldWinZipAes(byte[] buffer, int j, Int16 dataSize, long posn)
{
if (this._CompressionMethod == 0x0063)
{
if ((this._BitField & 0x01) != 0x01)
throw new BadReadException(String.Format(" Inconsistent metadata at position 0x{0:X16}", posn));
this._sourceIsEncrypted = true;
//this._aesCrypto = new WinZipAesCrypto(this);
// see spec at http://www.winzip.com/aes_info.htm
if (dataSize != 7)
throw new BadReadException(String.Format(" Inconsistent size (0x{0:X4}) in WinZip AES field at position 0x{1:X16}", dataSize, posn));
this._WinZipAesMethod = BitConverter.ToInt16(buffer, j);
j += 2;
if (this._WinZipAesMethod != 0x01 && this._WinZipAesMethod != 0x02)
throw new BadReadException(String.Format(" Unexpected vendor version number (0x{0:X4}) for WinZip AES metadata at position 0x{1:X16}",
this._WinZipAesMethod, posn));
Int16 vendorId = BitConverter.ToInt16(buffer, j);
j += 2;
if (vendorId != 0x4541)
throw new BadReadException(String.Format(" Unexpected vendor ID (0x{0:X4}) for WinZip AES metadata at position 0x{1:X16}", vendorId, posn));
int keystrength = (buffer[j] == 1) ? 128 : (buffer[j] == 3) ? 256 : -1;
if (keystrength < 0)
throw new BadReadException(String.Format("Invalid key strength ({0})", keystrength));
_Encryption_FromZipFile = this._Encryption = (keystrength == 128)
? EncryptionAlgorithm.WinZipAes128
: EncryptionAlgorithm.WinZipAes256;
j++;
// set the actual compression method
this._CompressionMethod_FromZipFile =
this._CompressionMethod = BitConverter.ToInt16(buffer, j);
j += 2; // for the next segment of the extra field
}
return j;
}
#endif
private delegate T Func<T>();
private int ProcessExtraFieldZip64(byte[] buffer, int j, Int16 dataSize, long posn)
{
// The PKWare spec says that any of {UncompressedSize, CompressedSize,
// RelativeOffset} exceeding 0xFFFFFFFF can lead to the ZIP64 header,
// and the ZIP64 header may contain one or more of those. If the
// values are present, they will be found in the prescribed order.
// There may also be a 4-byte "disk start number."
// This means that the DataSize must be 28 bytes or less.
this._InputUsesZip64 = true;
// workitem 7941: check datasize before reading.
if (dataSize > 28)
throw new BadReadException(String.Format(" Inconsistent size (0x{0:X4}) for ZIP64 extra field at position 0x{1:X16}",
dataSize, posn));
int remainingData = dataSize;
var slurp = new Func<Int64>( () => {
if (remainingData < 8)
throw new BadReadException(String.Format(" Missing data for ZIP64 extra field, position 0x{0:X16}", posn));
var x = BitConverter.ToInt64(buffer, j);
j+= 8;
remainingData -= 8;
return x;
});
if (this._UncompressedSize == 0xFFFFFFFF)
this._UncompressedSize = slurp();
if (this._CompressedSize == 0xFFFFFFFF)
this._CompressedSize = slurp();
if (this._RelativeOffsetOfLocalHeader == 0xFFFFFFFF)
this._RelativeOffsetOfLocalHeader = slurp();
// Ignore anything else. Potentially there are 4 more bytes for the
// disk start number. DotNetZip currently doesn't handle multi-disk
// archives.
return j;
}
private int ProcessExtraFieldInfoZipTimes(byte[] buffer, int j, Int16 dataSize, long posn)
{
if (dataSize != 12 && dataSize != 8)
throw new BadReadException(String.Format(" Unexpected size (0x{0:X4}) for InfoZip v1 extra field at position 0x{1:X16}", dataSize, posn));
Int32 timet = BitConverter.ToInt32(buffer, j);
this._Mtime = _unixEpoch.AddSeconds(timet);
j += 4;
timet = BitConverter.ToInt32(buffer, j);
this._Atime = _unixEpoch.AddSeconds(timet);
j += 4;
this._Ctime = DateTime.UtcNow;
_ntfsTimesAreSet = true;
_timestamp |= ZipEntryTimestamp.InfoZip1; return j;
}
private int ProcessExtraFieldUnixTimes(byte[] buffer, int j, Int16 dataSize, long posn)
{
// The Unix filetimes are 32-bit unsigned integers,
// storing seconds since Unix epoch.
if (dataSize != 13 && dataSize != 9 && dataSize != 5)
throw new BadReadException(String.Format(" Unexpected size (0x{0:X4}) for Extended Timestamp extra field at position 0x{1:X16}", dataSize, posn));
int remainingData = dataSize;
var slurp = new Func<DateTime>( () => {
Int32 timet = BitConverter.ToInt32(buffer, j);
j += 4;
remainingData -= 4;
return _unixEpoch.AddSeconds(timet);
});
if (dataSize == 13 || _readExtraDepth > 0)
{
byte flag = buffer[j++];
remainingData--;
if ((flag & 0x0001) != 0 && remainingData >= 4)
this._Mtime = slurp();
this._Atime = ((flag & 0x0002) != 0 && remainingData >= 4)
? slurp()
: DateTime.UtcNow;
this._Ctime = ((flag & 0x0004) != 0 && remainingData >= 4)
? slurp()
:DateTime.UtcNow;
_timestamp |= ZipEntryTimestamp.Unix;
_ntfsTimesAreSet = true;
_emitUnixTimes = true;
}
else
ReadExtraField(); // will recurse
return j;
}
private int ProcessExtraFieldWindowsTimes(byte[] buffer, int j, Int16 dataSize, long posn)
{
// The NTFS filetimes are 64-bit unsigned integers, stored in Intel
// (least significant byte first) byte order. They are expressed as the
// number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch",
// which is "01-Jan-1601 00:00:00 UTC".
//
// HeaderId 2 bytes 0x000a == NTFS stuff
// Datasize 2 bytes ?? (usually 32)
// reserved 4 bytes ??
// timetag 2 bytes 0x0001 == time
// size 2 bytes 24 == 8 bytes each for ctime, mtime, atime
// mtime 8 bytes win32 ticks since win32epoch
// atime 8 bytes win32 ticks since win32epoch
// ctime 8 bytes win32 ticks since win32epoch
if (dataSize != 32)
throw new BadReadException(String.Format(" Unexpected size (0x{0:X4}) for NTFS times extra field at position 0x{1:X16}", dataSize, posn));
j += 4; // reserved
Int16 timetag = (Int16)(buffer[j] + buffer[j + 1] * 256);
Int16 addlsize = (Int16)(buffer[j + 2] + buffer[j + 3] * 256);
j += 4; // tag and size
if (timetag == 0x0001 && addlsize == 24)
{
Int64 z = BitConverter.ToInt64(buffer, j);
this._Mtime = DateTime.FromFileTimeUtc(z);
j += 8;
// At this point the library *could* set the LastModified value
// to coincide with the Mtime value. In theory, they refer to
// the same property of the file, and should be the same anyway,
// allowing for differences in precision. But they are
// independent quantities in the zip archive, and this library
// will keep them separate in the object model. There is no ill
// effect from this, because as files are extracted, the
// higher-precision value (Mtime) is used if it is present.
// Apps may wish to compare the Mtime versus LastModified
// values, but any difference when both are present is not
// germaine to the correctness of the library. but note: when
// explicitly setting either value, both are set. See the setter
// for LastModified or the SetNtfsTimes() method.
z = BitConverter.ToInt64(buffer, j);
this._Atime = DateTime.FromFileTimeUtc(z);
j += 8;
z = BitConverter.ToInt64(buffer, j);
this._Ctime = DateTime.FromFileTimeUtc(z);
j += 8;
_ntfsTimesAreSet = true;
_timestamp |= ZipEntryTimestamp.Windows;
_emitNtfsTimes = true;
}
return j;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,69 +0,0 @@
// ZipEntrySource.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009 Dino Chiesa
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2009-November-19 11:18:42>
//
// ------------------------------------------------------------------
//
namespace Ionic.Zip
{
/// <summary>
/// An enum that specifies the source of the ZipEntry.
/// </summary>
public enum ZipEntrySource
{
/// <summary>
/// Default value. Invalid on a bonafide ZipEntry.
/// </summary>
None = 0,
/// <summary>
/// The entry was instantiated by calling AddFile() or another method that
/// added an entry from the filesystem.
/// </summary>
FileSystem,
/// <summary>
/// The entry was instantiated via <see cref="Ionic.Zip.ZipFile.AddEntry(string,string)"/> or
/// <see cref="Ionic.Zip.ZipFile.AddEntry(string,System.IO.Stream)"/> .
/// </summary>
Stream,
/// <summary>
/// The ZipEntry was instantiated by reading a zipfile.
/// </summary>
ZipFile,
/// <summary>
/// The content for the ZipEntry will be or was provided by the WriteDelegate.
/// </summary>
WriteDelegate,
/// <summary>
/// The content for the ZipEntry will be obtained from the stream dispensed by the <c>OpenDelegate</c>.
/// The entry was instantiated via <see cref="Ionic.Zip.ZipFile.AddEntry(string,OpenDelegate,CloseDelegate)"/>.
/// </summary>
JitStream,
/// <summary>
/// The content for the ZipEntry will be or was obtained from a <c>ZipOutputStream</c>.
/// </summary>
ZipOutputStream,
}
}

View file

@ -1,97 +0,0 @@
// ZipErrorAction.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009 Dino Chiesa
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2009-September-01 18:43:20>
//
// ------------------------------------------------------------------
//
// This module defines the ZipErrorAction enum, which provides
// an action to take when errors occur when opening or reading
// files to be added to a zip file.
//
// ------------------------------------------------------------------
namespace Ionic.Zip
{
/// <summary>
/// An enum providing the options when an error occurs during opening or reading
/// of a file or directory that is being saved to a zip file.
/// </summary>
///
/// <remarks>
/// <para>
/// This enum describes the actions that the library can take when an error occurs
/// opening or reading a file, as it is being saved into a Zip archive.
/// </para>
///
/// <para>
/// In some cases an error will occur when DotNetZip tries to open a file to be
/// added to the zip archive. In other cases, an error might occur after the
/// file has been successfully opened, while DotNetZip is reading the file.
/// </para>
///
/// <para>
/// The first problem might occur when calling AddDirectory() on a directory
/// that contains a Clipper .dbf file; the file is locked by Clipper and
/// cannot be opened by another process. An example of the second problem is
/// the ERROR_LOCK_VIOLATION that results when a file is opened by another
/// process, but not locked, and a range lock has been taken on the file.
/// Microsoft Outlook takes range locks on .PST files.
/// </para>
/// </remarks>
public enum ZipErrorAction
{
/// <summary>
/// Throw an exception when an error occurs while zipping. This is the default
/// behavior. (For COM clients, this is a 0 (zero).)
/// </summary>
Throw,
/// <summary>
/// When an error occurs during zipping, for example a file cannot be opened,
/// skip the file causing the error, and continue zipping. (For COM clients,
/// this is a 1.)
/// </summary>
Skip,
/// <summary>
/// When an error occurs during zipping, for example a file cannot be opened,
/// retry the operation that caused the error. Be careful with this option. If
/// the error is not temporary, the library will retry forever. (For COM
/// clients, this is a 2.)
/// </summary>
Retry,
/// <summary>
/// When an error occurs, invoke the zipError event. The event type used is
/// <see cref="ZipProgressEventType.Error_Saving"/>. A typical use of this option:
/// a GUI application may wish to pop up a dialog to allow the user to view the
/// error that occurred, and choose an appropriate action. After your
/// processing in the error event, if you want to skip the file, set <see
/// cref="ZipEntry.ZipErrorAction"/> on the
/// <c>ZipProgressEventArgs.CurrentEntry</c> to <c>Skip</c>. If you want the
/// exception to be thrown, set <c>ZipErrorAction</c> on the <c>CurrentEntry</c>
/// to <c>Throw</c>. If you want to cancel the zip, set
/// <c>ZipProgressEventArgs.Cancel</c> to true. Cancelling differs from using
/// Skip in that a cancel will not save any further entries, if there are any.
/// (For COM clients, the value of this enum is a 3.)
/// </summary>
InvokeErrorEvent,
}
}

View file

@ -1,352 +0,0 @@
// ZipFile.Check.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009-2011 Dino Chiesa.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2011-July-31 14:40:50>
//
// ------------------------------------------------------------------
//
// This module defines the methods for doing Checks on zip files.
// These are not necessary to include in the Reduced or CF
// version of the library.
//
// ------------------------------------------------------------------
//
using System;
using System.IO;
using System.Collections.Generic;
namespace Ionic.Zip
{
public partial class ZipFile
{
/// <summary>
/// Checks a zip file to see if its directory is consistent.
/// </summary>
///
/// <remarks>
///
/// <para>
/// In cases of data error, the directory within a zip file can get out
/// of synch with the entries in the zip file. This method checks the
/// given zip file and returns true if this has occurred.
/// </para>
///
/// <para> This method may take a long time to run for large zip files. </para>
///
/// <para>
/// This method is not supported in the Reduced or Compact Framework
/// versions of DotNetZip.
/// </para>
///
/// <para>
/// Developers using COM can use the <see
/// cref="ComHelper.CheckZip(String)">ComHelper.CheckZip(String)</see>
/// method.
/// </para>
///
/// </remarks>
///
/// <param name="zipFileName">The filename to of the zip file to check.</param>
///
/// <returns>true if the named zip file checks OK. Otherwise, false. </returns>
///
/// <seealso cref="FixZipDirectory(string)"/>
/// <seealso cref="CheckZip(string,bool,System.IO.TextWriter)"/>
public static bool CheckZip(string zipFileName)
{
return CheckZip(zipFileName, false, null);
}
/// <summary>
/// Checks a zip file to see if its directory is consistent,
/// and optionally fixes the directory if necessary.
/// </summary>
///
/// <remarks>
///
/// <para>
/// In cases of data error, the directory within a zip file can get out of
/// synch with the entries in the zip file. This method checks the given
/// zip file, and returns true if this has occurred. It also optionally
/// fixes the zipfile, saving the fixed copy in <em>Name</em>_Fixed.zip.
/// </para>
///
/// <para>
/// This method may take a long time to run for large zip files. It
/// will take even longer if the file actually needs to be fixed, and if
/// <c>fixIfNecessary</c> is true.
/// </para>
///
/// <para>
/// This method is not supported in the Reduced or Compact
/// Framework versions of DotNetZip.
/// </para>
///
/// </remarks>
///
/// <param name="zipFileName">The filename to of the zip file to check.</param>
///
/// <param name="fixIfNecessary">If true, the method will fix the zip file if
/// necessary.</param>
///
/// <param name="writer">
/// a TextWriter in which messages generated while checking will be written.
/// </param>
///
/// <returns>true if the named zip is OK; false if the file needs to be fixed.</returns>
///
/// <seealso cref="CheckZip(string)"/>
/// <seealso cref="FixZipDirectory(string)"/>
public static bool CheckZip(string zipFileName, bool fixIfNecessary,
TextWriter writer)
{
ZipFile zip1 = null, zip2 = null;
bool isOk = true;
try
{
zip1 = new ZipFile();
zip1.FullScan = true;
zip1.Initialize(zipFileName);
zip2 = ZipFile.Read(zipFileName);
foreach (var e1 in zip1)
{
foreach (var e2 in zip2)
{
if (e1.FileName == e2.FileName)
{
if (e1._RelativeOffsetOfLocalHeader != e2._RelativeOffsetOfLocalHeader)
{
isOk = false;
if (writer != null)
writer.WriteLine("{0}: mismatch in RelativeOffsetOfLocalHeader (0x{1:X16} != 0x{2:X16})",
e1.FileName, e1._RelativeOffsetOfLocalHeader,
e2._RelativeOffsetOfLocalHeader);
}
if (e1._CompressedSize != e2._CompressedSize)
{
isOk = false;
if (writer != null)
writer.WriteLine("{0}: mismatch in CompressedSize (0x{1:X16} != 0x{2:X16})",
e1.FileName, e1._CompressedSize,
e2._CompressedSize);
}
if (e1._UncompressedSize != e2._UncompressedSize)
{
isOk = false;
if (writer != null)
writer.WriteLine("{0}: mismatch in UncompressedSize (0x{1:X16} != 0x{2:X16})",
e1.FileName, e1._UncompressedSize,
e2._UncompressedSize);
}
if (e1.CompressionMethod != e2.CompressionMethod)
{
isOk = false;
if (writer != null)
writer.WriteLine("{0}: mismatch in CompressionMethod (0x{1:X4} != 0x{2:X4})",
e1.FileName, e1.CompressionMethod,
e2.CompressionMethod);
}
if (e1.Crc != e2.Crc)
{
isOk = false;
if (writer != null)
writer.WriteLine("{0}: mismatch in Crc32 (0x{1:X4} != 0x{2:X4})",
e1.FileName, e1.Crc,
e2.Crc);
}
// found a match, so stop the inside loop
break;
}
}
}
zip2.Dispose();
zip2 = null;
if (!isOk && fixIfNecessary)
{
string newFileName = Path.GetFileNameWithoutExtension(zipFileName);
newFileName = System.String.Format("{0}_fixed.zip", newFileName);
zip1.Save(newFileName);
}
}
finally
{
if (zip1 != null) zip1.Dispose();
if (zip2 != null) zip2.Dispose();
}
return isOk;
}
/// <summary>
/// Rewrite the directory within a zipfile.
/// </summary>
///
/// <remarks>
///
/// <para>
/// In cases of data error, the directory in a zip file can get out of
/// synch with the entries in the zip file. This method attempts to fix
/// the zip file if this has occurred.
/// </para>
///
/// <para> This can take a long time for large zip files. </para>
///
/// <para> This won't work if the zip file uses a non-standard
/// code page - neither IBM437 nor UTF-8. </para>
///
/// <para>
/// This method is not supported in the Reduced or Compact Framework
/// versions of DotNetZip.
/// </para>
///
/// <para>
/// Developers using COM can use the <see
/// cref="ComHelper.FixZipDirectory(String)">ComHelper.FixZipDirectory(String)</see>
/// method.
/// </para>
///
/// </remarks>
///
/// <param name="zipFileName">The filename to of the zip file to fix.</param>
///
/// <seealso cref="CheckZip(string)"/>
/// <seealso cref="CheckZip(string,bool,System.IO.TextWriter)"/>
public static void FixZipDirectory(string zipFileName)
{
using (var zip = new ZipFile())
{
zip.FullScan = true;
zip.Initialize(zipFileName);
zip.Save(zipFileName);
}
}
/// <summary>
/// Verify the password on a zip file.
/// </summary>
///
/// <remarks>
/// <para>
/// Keep in mind that passwords in zipfiles are applied to
/// zip entries, not to the entire zip file. So testing a
/// zipfile for a particular password doesn't work in the
/// general case. On the other hand, it's often the case
/// that a single password will be used on all entries in a
/// zip file. This method works for that case.
/// </para>
/// <para>
/// There is no way to check a password without doing the
/// decryption. So this code decrypts and extracts the given
/// zipfile into <see cref="System.IO.Stream.Null"/>
/// </para>
/// </remarks>
///
/// <param name="zipFileName">The filename to of the zip file to fix.</param>
///
/// <param name="password">The password to check.</param>
///
/// <returns>a bool indicating whether the password matches.</returns>
public static bool CheckZipPassword(string zipFileName, string password)
{
// workitem 13664
bool success = false;
try
{
using (ZipFile zip1 = ZipFile.Read(zipFileName))
{
foreach (var e in zip1)
{
if (!e.IsDirectory && e.UsesEncryption)
{
e.ExtractWithPassword(System.IO.Stream.Null, password);
}
}
}
success = true;
}
catch(Ionic.Zip.BadPasswordException) { }
return success;
}
/// <summary>
/// Provides a human-readable string with information about the ZipFile.
/// </summary>
///
/// <remarks>
/// <para>
/// The information string contains 10 lines or so, about each ZipEntry,
/// describing whether encryption is in use, the compressed and uncompressed
/// length of the entry, the offset of the entry, and so on. As a result the
/// information string can be very long for zip files that contain many
/// entries.
/// </para>
/// <para>
/// This information is mostly useful for diagnostic purposes.
/// </para>
/// </remarks>
public string Info
{
get
{
var builder = new System.Text.StringBuilder();
builder.Append(string.Format(" ZipFile: {0}\n", this.Name));
if (!string.IsNullOrEmpty(this._Comment))
{
builder.Append(string.Format(" Comment: {0}\n", this._Comment));
}
if (this._versionMadeBy != 0)
{
builder.Append(string.Format(" version made by: 0x{0:X4}\n", this._versionMadeBy));
}
if (this._versionNeededToExtract != 0)
{
builder.Append(string.Format("needed to extract: 0x{0:X4}\n", this._versionNeededToExtract));
}
builder.Append(string.Format(" uses ZIP64: {0}\n", this.InputUsesZip64));
builder.Append(string.Format(" disk with CD: {0}\n", this._diskNumberWithCd));
if (this._OffsetOfCentralDirectory == 0xFFFFFFFF)
builder.Append(string.Format(" CD64 offset: 0x{0:X16}\n", this._OffsetOfCentralDirectory64));
else
builder.Append(string.Format(" CD offset: 0x{0:X8}\n", this._OffsetOfCentralDirectory));
builder.Append("\n");
foreach (ZipEntry entry in this._entries.Values)
{
builder.Append(entry.Info);
}
return builder.ToString();
}
}
}
}

View file

@ -1,298 +0,0 @@
// ZipFile.Extract.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009 Dino Chiesa.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2011-July-31 14:45:18>
//
// ------------------------------------------------------------------
//
// This module defines the methods for Extract operations on zip files.
//
// ------------------------------------------------------------------
//
using System;
using System.IO;
using System.Collections.Generic;
namespace Ionic.Zip
{
public partial class ZipFile
{
/// <summary>
/// Extracts all of the items in the zip archive, to the specified path in the
/// filesystem. The path can be relative or fully-qualified.
/// </summary>
///
/// <remarks>
/// <para>
/// This method will extract all entries in the <c>ZipFile</c> to the
/// specified path.
/// </para>
///
/// <para>
/// If an extraction of a file from the zip archive would overwrite an
/// existing file in the filesystem, the action taken is dictated by the
/// ExtractExistingFile property, which overrides any setting you may have
/// made on individual ZipEntry instances. By default, if you have not
/// set that property on the <c>ZipFile</c> instance, the entry will not
/// be extracted, the existing file will not be overwritten and an
/// exception will be thrown. To change this, set the property, or use the
/// <see cref="ZipFile.ExtractAll(string,
/// Ionic.Zip.ExtractExistingFileAction)" /> overload that allows you to
/// specify an ExtractExistingFileAction parameter.
/// </para>
///
/// <para>
/// The action to take when an extract would overwrite an existing file
/// applies to all entries. If you want to set this on a per-entry basis,
/// then you must use one of the <see
/// cref="ZipEntry.Extract()">ZipEntry.Extract</see> methods.
/// </para>
///
/// <para>
/// This method will send verbose output messages to the <see
/// cref="StatusMessageTextWriter"/>, if it is set on the <c>ZipFile</c>
/// instance.
/// </para>
///
/// <para>
/// You may wish to take advantage of the <c>ExtractProgress</c> event.
/// </para>
///
/// <para>
/// About timestamps: When extracting a file entry from a zip archive, the
/// extracted file gets the last modified time of the entry as stored in
/// the archive. The archive may also store extended file timestamp
/// information, including last accessed and created times. If these are
/// present in the <c>ZipEntry</c>, then the extracted file will also get
/// these times.
/// </para>
///
/// <para>
/// A Directory entry is somewhat different. It will get the times as
/// described for a file entry, but, if there are file entries in the zip
/// archive that, when extracted, appear in the just-created directory,
/// then when those file entries are extracted, the last modified and last
/// accessed times of the directory will change, as a side effect. The
/// result is that after an extraction of a directory and a number of
/// files within the directory, the last modified and last accessed
/// timestamps on the directory will reflect the time that the last file
/// was extracted into the directory, rather than the time stored in the
/// zip archive for the directory.
/// </para>
///
/// <para>
/// To compensate, when extracting an archive with <c>ExtractAll</c>,
/// DotNetZip will extract all the file and directory entries as described
/// above, but it will then make a second pass on the directories, and
/// reset the times on the directories to reflect what is stored in the
/// zip archive.
/// </para>
///
/// <para>
/// This compensation is performed only within the context of an
/// <c>ExtractAll</c>. If you call <c>ZipEntry.Extract</c> on a directory
/// entry, the timestamps on directory in the filesystem will reflect the
/// times stored in the zip. If you then call <c>ZipEntry.Extract</c> on
/// a file entry, which is extracted into the directory, the timestamps on
/// the directory will be updated to the current time.
/// </para>
/// </remarks>
///
/// <example>
/// This example extracts all the entries in a zip archive file, to the
/// specified target directory. The extraction will overwrite any
/// existing files silently.
///
/// <code>
/// String TargetDirectory= "unpack";
/// using(ZipFile zip= ZipFile.Read(ZipFileToExtract))
/// {
/// zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently;
/// zip.ExtractAll(TargetDirectory);
/// }
/// </code>
///
/// <code lang="VB">
/// Dim TargetDirectory As String = "unpack"
/// Using zip As ZipFile = ZipFile.Read(ZipFileToExtract)
/// zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently
/// zip.ExtractAll(TargetDirectory)
/// End Using
/// </code>
/// </example>
///
/// <seealso cref="Ionic.Zip.ZipFile.ExtractProgress"/>
/// <seealso cref="Ionic.Zip.ZipFile.ExtractExistingFile"/>
///
/// <param name="path">
/// The path to which the contents of the zipfile will be extracted.
/// The path can be relative or fully-qualified.
/// </param>
///
public void ExtractAll(string path)
{
_InternalExtractAll(path, true);
}
/// <summary>
/// Extracts all of the items in the zip archive, to the specified path in the
/// filesystem, using the specified behavior when extraction would overwrite an
/// existing file.
/// </summary>
///
/// <remarks>
///
/// <para>
/// This method will extract all entries in the <c>ZipFile</c> to the specified
/// path. For an extraction that would overwrite an existing file, the behavior
/// is dictated by <paramref name="extractExistingFile"/>, which overrides any
/// setting you may have made on individual ZipEntry instances.
/// </para>
///
/// <para>
/// The action to take when an extract would overwrite an existing file
/// applies to all entries. If you want to set this on a per-entry basis,
/// then you must use <see cref="ZipEntry.Extract(String,
/// ExtractExistingFileAction)" /> or one of the similar methods.
/// </para>
///
/// <para>
/// Calling this method is equivalent to setting the <see
/// cref="ExtractExistingFile"/> property and then calling <see
/// cref="ExtractAll(String)"/>.
/// </para>
///
/// <para>
/// This method will send verbose output messages to the
/// <see cref="StatusMessageTextWriter"/>, if it is set on the <c>ZipFile</c> instance.
/// </para>
/// </remarks>
///
/// <example>
/// This example extracts all the entries in a zip archive file, to the
/// specified target directory. It does not overwrite any existing files.
/// <code>
/// String TargetDirectory= "c:\\unpack";
/// using(ZipFile zip= ZipFile.Read(ZipFileToExtract))
/// {
/// zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite);
/// }
/// </code>
///
/// <code lang="VB">
/// Dim TargetDirectory As String = "c:\unpack"
/// Using zip As ZipFile = ZipFile.Read(ZipFileToExtract)
/// zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite)
/// End Using
/// </code>
/// </example>
///
/// <param name="path">
/// The path to which the contents of the zipfile will be extracted.
/// The path can be relative or fully-qualified.
/// </param>
///
/// <param name="extractExistingFile">
/// The action to take if extraction would overwrite an existing file.
/// </param>
/// <seealso cref="ExtractSelectedEntries(String,ExtractExistingFileAction)"/>
public void ExtractAll(string path, ExtractExistingFileAction extractExistingFile)
{
ExtractExistingFile = extractExistingFile;
_InternalExtractAll(path, true);
}
private void _InternalExtractAll(string path, bool overrideExtractExistingProperty)
{
bool header = Verbose;
_inExtractAll = true;
try
{
OnExtractAllStarted(path);
int n = 0;
foreach (ZipEntry e in _entries.Values)
{
if (header)
{
StatusMessageTextWriter.WriteLine("\n{1,-22} {2,-8} {3,4} {4,-8} {0}",
"Name", "Modified", "Size", "Ratio", "Packed");
StatusMessageTextWriter.WriteLine(new System.String('-', 72));
header = false;
}
if (Verbose)
{
StatusMessageTextWriter.WriteLine("{1,-22} {2,-8} {3,4:F0}% {4,-8} {0}",
e.FileName,
e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"),
e.UncompressedSize,
e.CompressionRatio,
e.CompressedSize);
if (!String.IsNullOrEmpty(e.Comment))
StatusMessageTextWriter.WriteLine(" Comment: {0}", e.Comment);
}
e.Password = _Password; // this may be null
OnExtractEntry(n, true, e, path);
if (overrideExtractExistingProperty)
e.ExtractExistingFile = this.ExtractExistingFile;
e.Extract(path);
n++;
OnExtractEntry(n, false, e, path);
if (_extractOperationCanceled)
break;
}
if (!_extractOperationCanceled)
{
// workitem 8264:
// now, set times on directory entries, again.
// The problem is, extracting a file changes the times on the parent
// directory. So after all files have been extracted, we have to
// run through the directories again.
foreach (ZipEntry e in _entries.Values)
{
// check if it is a directory
if ((e.IsDirectory) || (e.FileName.EndsWith("/")))
{
string outputFile = (e.FileName.StartsWith("/"))
? Path.Combine(path, e.FileName.Substring(1))
: Path.Combine(path, e.FileName);
e._SetTimes(outputFile, false);
}
}
OnExtractAllCompleted(path);
}
}
finally
{
_inExtractAll = false;
}
}
}
}

View file

@ -1,964 +0,0 @@
// ZipFile.Save.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009 Dino Chiesa.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2011-August-05 13:31:23>
//
// ------------------------------------------------------------------
//
// This module defines the methods for Save operations on zip files.
//
// ------------------------------------------------------------------
//
using System;
using System.IO;
using System.Collections.Generic;
namespace Ionic.Zip
{
public partial class ZipFile
{
/// <summary>
/// Delete file with retry on UnauthorizedAccessException.
/// </summary>
///
/// <remarks>
/// <para>
/// When calling File.Delete() on a file that has been "recently"
/// created, the call sometimes fails with
/// UnauthorizedAccessException. This method simply retries the Delete 3
/// times with a sleep between tries.
/// </para>
/// </remarks>
///
/// <param name='filename'>the name of the file to be deleted</param>
private void DeleteFileWithRetry(string filename)
{
bool done = false;
int nRetries = 3;
for (int i=0; i < nRetries && !done; i++)
{
try
{
File.Delete(filename);
done = true;
}
catch (System.UnauthorizedAccessException)
{
Console.WriteLine("************************************************** Retry delete.");
System.Threading.Thread.Sleep(200+i*200);
}
}
}
/// <summary>
/// Saves the Zip archive to a file, specified by the Name property of the
/// <c>ZipFile</c>.
/// </summary>
///
/// <remarks>
/// <para>
/// The <c>ZipFile</c> instance is written to storage, typically a zip file
/// in a filesystem, only when the caller calls <c>Save</c>. In the typical
/// case, the Save operation writes the zip content to a temporary file, and
/// then renames the temporary file to the desired name. If necessary, this
/// method will delete a pre-existing file before the rename.
/// </para>
///
/// <para>
/// The <see cref="ZipFile.Name"/> property is specified either explicitly,
/// or implicitly using one of the parameterized ZipFile constructors. For
/// COM Automation clients, the <c>Name</c> property must be set explicitly,
/// because COM Automation clients cannot call parameterized constructors.
/// </para>
///
/// <para>
/// When using a filesystem file for the Zip output, it is possible to call
/// <c>Save</c> multiple times on the <c>ZipFile</c> instance. With each
/// call the zip content is re-written to the same output file.
/// </para>
///
/// <para>
/// Data for entries that have been added to the <c>ZipFile</c> instance is
/// written to the output when the <c>Save</c> method is called. This means
/// that the input streams for those entries must be available at the time
/// the application calls <c>Save</c>. If, for example, the application
/// adds entries with <c>AddEntry</c> using a dynamically-allocated
/// <c>MemoryStream</c>, the memory stream must not have been disposed
/// before the call to <c>Save</c>. See the <see
/// cref="ZipEntry.InputStream"/> property for more discussion of the
/// availability requirements of the input stream for an entry, and an
/// approach for providing just-in-time stream lifecycle management.
/// </para>
///
/// </remarks>
///
/// <seealso cref="Ionic.Zip.ZipFile.AddEntry(String, System.IO.Stream)"/>
///
/// <exception cref="Ionic.Zip.BadStateException">
/// Thrown if you haven't specified a location or stream for saving the zip,
/// either in the constructor or by setting the Name property, or if you try
/// to save a regular zip archive to a filename with a .exe extension.
/// </exception>
///
/// <exception cref="System.OverflowException">
/// Thrown if <see cref="MaxOutputSegmentSize"/> is non-zero, and the number
/// of segments that would be generated for the spanned zip file during the
/// save operation exceeds 99. If this happens, you need to increase the
/// segment size.
/// </exception>
///
public void Save()
{
try
{
bool thisSaveUsedZip64 = false;
_saveOperationCanceled = false;
_numberOfSegmentsForMostRecentSave = 0;
OnSaveStarted();
if (WriteStream == null)
throw new BadStateException("You haven't specified where to save the zip.");
if (_name != null && _name.EndsWith(".exe") && !_SavingSfx)
throw new BadStateException("You specified an EXE for a plain zip file.");
// check if modified, before saving.
if (!_contentsChanged)
{
OnSaveCompleted();
if (Verbose) StatusMessageTextWriter.WriteLine("No save is necessary....");
return;
}
Reset(true);
if (Verbose) StatusMessageTextWriter.WriteLine("saving....");
// validate the number of entries
if (_entries.Count >= 0xFFFF && _zip64 == Zip64Option.Never)
throw new ZipException("The number of entries is 65535 or greater. Consider setting the UseZip64WhenSaving property on the ZipFile instance.");
// write an entry in the zip for each file
int n = 0;
// workitem 9831
ICollection<ZipEntry> c = (SortEntriesBeforeSaving) ? EntriesSorted : Entries;
foreach (ZipEntry e in c) // _entries.Values
{
OnSaveEntry(n, e, true);
e.Write(WriteStream);
if (_saveOperationCanceled)
break;
n++;
OnSaveEntry(n, e, false);
if (_saveOperationCanceled)
break;
// Some entries can be skipped during the save.
if (e.IncludedInMostRecentSave)
thisSaveUsedZip64 |= e.OutputUsedZip64.Value;
}
if (_saveOperationCanceled)
return;
var zss = WriteStream as ZipSegmentedStream;
_numberOfSegmentsForMostRecentSave = (zss!=null)
? zss.CurrentSegment
: 1;
bool directoryNeededZip64 =
ZipOutput.WriteCentralDirectoryStructure
(WriteStream,
c,
_numberOfSegmentsForMostRecentSave,
_zip64,
Comment,
new ZipContainer(this));
OnSaveEvent(ZipProgressEventType.Saving_AfterSaveTempArchive);
_hasBeenSaved = true;
_contentsChanged = false;
thisSaveUsedZip64 |= directoryNeededZip64;
_OutputUsesZip64 = new Nullable<bool>(thisSaveUsedZip64);
// do the rename as necessary
if (_name != null &&
(_temporaryFileName!=null || zss != null))
{
// _temporaryFileName may remain null if we are writing to a stream.
// only close the stream if there is a file behind it.
#if NETCF
WriteStream.Close();
#else
WriteStream.Dispose();
#endif
if (_saveOperationCanceled)
return;
if (_fileAlreadyExists && this._readstream != null)
{
// This means we opened and read a zip file.
// If we are now saving to the same file, we need to close the
// orig file, first.
this._readstream.Close();
this._readstream = null;
// the archiveStream for each entry needs to be null
foreach (var e in c)
{
var zss1 = e._archiveStream as ZipSegmentedStream;
if (zss1 != null)
#if NETCF
zss1.Close();
#else
zss1.Dispose();
#endif
e._archiveStream = null;
}
}
string tmpName = null;
if (File.Exists(_name))
{
// the steps:
//
// 1. Delete tmpName
// 2. move existing zip to tmpName
// 3. rename (File.Move) working file to name of existing zip
// 4. delete tmpName
//
// This series of steps avoids the exception,
// System.IO.IOException:
// "Cannot create a file when that file already exists."
//
// Cannot just call File.Replace() here because
// there is a possibility that the TEMP volume is different
// that the volume for the final file (c:\ vs d:\).
// So we need to do a Delete+Move pair.
//
// But, when doing the delete, Windows allows a process to
// delete the file, even though it is held open by, say, a
// virus scanner. It gets internally marked as "delete
// pending". The file does not actually get removed from the
// file system, it is still there after the File.Delete
// call.
//
// Therefore, we need to move the existing zip, which may be
// held open, to some other name. Then rename our working
// file to the desired name, then delete (possibly delete
// pending) the "other name".
//
// Ideally this would be transactional. It's possible that the
// delete succeeds and the move fails. Lacking transactions, if
// this kind of failure happens, we're hosed, and this logic will
// throw on the next File.Move().
//
//File.Delete(_name);
// workitem 10447
#if NETCF || SILVERLIGHT
tmpName = _name + "." + SharedUtilities.GenerateRandomStringImpl(8,0) + ".tmp";
#else
tmpName = _name + "." + Path.GetRandomFileName();
#endif
if (File.Exists(tmpName))
DeleteFileWithRetry(tmpName);
File.Move(_name, tmpName);
}
OnSaveEvent(ZipProgressEventType.Saving_BeforeRenameTempArchive);
File.Move((zss != null) ? zss.CurrentTempName : _temporaryFileName,
_name);
OnSaveEvent(ZipProgressEventType.Saving_AfterRenameTempArchive);
if (tmpName != null)
{
try
{
// not critical
if (File.Exists(tmpName))
File.Delete(tmpName);
}
catch
{
// don't care about exceptions here.
}
}
_fileAlreadyExists = true;
}
NotifyEntriesSaveComplete(c);
OnSaveCompleted();
_JustSaved = true;
}
// workitem 5043
finally
{
CleanupAfterSaveOperation();
}
return;
}
private static void NotifyEntriesSaveComplete(ICollection<ZipEntry> c)
{
foreach (ZipEntry e in c)
{
e.NotifySaveComplete();
}
}
private void RemoveTempFile()
{
try
{
if (File.Exists(_temporaryFileName))
{
File.Delete(_temporaryFileName);
}
}
catch (IOException ex1)
{
if (Verbose)
StatusMessageTextWriter.WriteLine("ZipFile::Save: could not delete temp file: {0}.", ex1.Message);
}
}
private void CleanupAfterSaveOperation()
{
if (_name != null)
{
// close the stream if there is a file behind it.
if (_writestream != null)
{
try
{
// workitem 7704
#if NETCF
_writestream.Close();
#else
_writestream.Dispose();
#endif
}
catch (System.IO.IOException) { }
}
_writestream = null;
if (_temporaryFileName != null)
{
RemoveTempFile();
_temporaryFileName = null;
}
}
}
/// <summary>
/// Save the file to a new zipfile, with the given name.
/// </summary>
///
/// <remarks>
/// <para>
/// This method allows the application to explicitly specify the name of the zip
/// file when saving. Use this when creating a new zip file, or when
/// updating a zip archive.
/// </para>
///
/// <para>
/// An application can also save a zip archive in several places by calling this
/// method multiple times in succession, with different filenames.
/// </para>
///
/// <para>
/// The <c>ZipFile</c> instance is written to storage, typically a zip file in a
/// filesystem, only when the caller calls <c>Save</c>. The Save operation writes
/// the zip content to a temporary file, and then renames the temporary file
/// to the desired name. If necessary, this method will delete a pre-existing file
/// before the rename.
/// </para>
///
/// </remarks>
///
/// <exception cref="System.ArgumentException">
/// Thrown if you specify a directory for the filename.
/// </exception>
///
/// <param name="fileName">
/// The name of the zip archive to save to. Existing files will
/// be overwritten with great prejudice.
/// </param>
///
/// <example>
/// This example shows how to create and Save a zip file.
/// <code>
/// using (ZipFile zip = new ZipFile())
/// {
/// zip.AddDirectory(@"c:\reports\January");
/// zip.Save("January.zip");
/// }
/// </code>
///
/// <code lang="VB">
/// Using zip As New ZipFile()
/// zip.AddDirectory("c:\reports\January")
/// zip.Save("January.zip")
/// End Using
/// </code>
///
/// </example>
///
/// <example>
/// This example shows how to update a zip file.
/// <code>
/// using (ZipFile zip = ZipFile.Read("ExistingArchive.zip"))
/// {
/// zip.AddFile("NewData.csv");
/// zip.Save("UpdatedArchive.zip");
/// }
/// </code>
///
/// <code lang="VB">
/// Using zip As ZipFile = ZipFile.Read("ExistingArchive.zip")
/// zip.AddFile("NewData.csv")
/// zip.Save("UpdatedArchive.zip")
/// End Using
/// </code>
///
/// </example>
public void Save(String fileName)
{
// Check for the case where we are re-saving a zip archive
// that was originally instantiated with a stream. In that case,
// the _name will be null. If so, we set _writestream to null,
// which insures that we'll cons up a new WriteStream (with a filesystem
// file backing it) in the Save() method.
if (_name == null)
_writestream = null;
else _readName = _name; // workitem 13915
_name = fileName;
if (Directory.Exists(_name))
throw new ZipException("Bad Directory", new System.ArgumentException("That name specifies an existing directory. Please specify a filename.", "fileName"));
_contentsChanged = true;
_fileAlreadyExists = File.Exists(_name);
Save();
}
/// <summary>
/// Save the zip archive to the specified stream.
/// </summary>
///
/// <remarks>
/// <para>
/// The <c>ZipFile</c> instance is written to storage - typically a zip file
/// in a filesystem, but using this overload, the storage can be anything
/// accessible via a writable stream - only when the caller calls <c>Save</c>.
/// </para>
///
/// <para>
/// Use this method to save the zip content to a stream directly. A common
/// scenario is an ASP.NET application that dynamically generates a zip file
/// and allows the browser to download it. The application can call
/// <c>Save(Response.OutputStream)</c> to write a zipfile directly to the
/// output stream, without creating a zip file on the disk on the ASP.NET
/// server.
/// </para>
///
/// <para>
/// Be careful when saving a file to a non-seekable stream, including
/// <c>Response.OutputStream</c>. When DotNetZip writes to a non-seekable
/// stream, the zip archive is formatted in such a way that may not be
/// compatible with all zip tools on all platforms. It's a perfectly legal
/// and compliant zip file, but some people have reported problems opening
/// files produced this way using the Mac OS archive utility.
/// </para>
///
/// </remarks>
///
/// <example>
///
/// This example saves the zipfile content into a MemoryStream, and
/// then gets the array of bytes from that MemoryStream.
///
/// <code lang="C#">
/// using (var zip = new Ionic.Zip.ZipFile())
/// {
/// zip.CompressionLevel= Ionic.Zlib.CompressionLevel.BestCompression;
/// zip.Password = "VerySecret.";
/// zip.Encryption = EncryptionAlgorithm.WinZipAes128;
/// zip.AddFile(sourceFileName);
/// MemoryStream output = new MemoryStream();
/// zip.Save(output);
///
/// byte[] zipbytes = output.ToArray();
/// }
/// </code>
/// </example>
///
/// <example>
/// <para>
/// This example shows a pitfall you should avoid. DO NOT read
/// from a stream, then try to save to the same stream. DO
/// NOT DO THIS:
/// </para>
///
/// <code lang="C#">
/// using (var fs = new FileSteeam(filename, FileMode.Open))
/// {
/// using (var zip = Ionic.Zip.ZipFile.Read(inputStream))
/// {
/// zip.AddEntry("Name1.txt", "this is the content");
/// zip.Save(inputStream); // NO NO NO!!
/// }
/// }
/// </code>
///
/// <para>
/// Better like this:
/// </para>
///
/// <code lang="C#">
/// using (var zip = Ionic.Zip.ZipFile.Read(filename))
/// {
/// zip.AddEntry("Name1.txt", "this is the content");
/// zip.Save(); // YES!
/// }
/// </code>
///
/// </example>
///
/// <param name="outputStream">
/// The <c>System.IO.Stream</c> to write to. It must be
/// writable. If you created the ZipFile instanct by calling
/// ZipFile.Read(), this stream must not be the same stream
/// you passed to ZipFile.Read().
/// </param>
public void Save(Stream outputStream)
{
if (outputStream == null)
throw new ArgumentNullException("outputStream");
if (!outputStream.CanWrite)
throw new ArgumentException("Must be a writable stream.", "outputStream");
// if we had a filename to save to, we are now obliterating it.
_name = null;
_writestream = new CountingStream(outputStream);
_contentsChanged = true;
_fileAlreadyExists = false;
Save();
}
}
internal static class ZipOutput
{
public static bool WriteCentralDirectoryStructure(Stream s,
ICollection<ZipEntry> entries,
uint numSegments,
Zip64Option zip64,
String comment,
ZipContainer container)
{
var zss = s as ZipSegmentedStream;
if (zss != null)
zss.ContiguousWrite = true;
// write to a memory stream in order to keep the
// CDR contiguous
Int64 aLength = 0;
using (var ms = new MemoryStream())
{
foreach (ZipEntry e in entries)
{
if (e.IncludedInMostRecentSave)
{
// this writes a ZipDirEntry corresponding to the ZipEntry
e.WriteCentralDirectoryEntry(ms);
}
}
var a = ms.ToArray();
s.Write(a, 0, a.Length);
aLength = a.Length;
}
// We need to keep track of the start and
// Finish of the Central Directory Structure.
// Cannot always use WriteStream.Length or Position; some streams do
// not support these. (eg, ASP.NET Response.OutputStream) In those
// cases we have a CountingStream.
// Also, we cannot just set Start as s.Position bfore the write, and Finish
// as s.Position after the write. In a split zip, the write may actually
// flip to the next segment. In that case, Start will be zero. But we
// don't know that til after we know the size of the thing to write. So the
// answer is to compute the directory, then ask the ZipSegmentedStream which
// segment that directory would fall in, it it were written. Then, include
// that data into the directory, and finally, write the directory to the
// output stream.
var output = s as CountingStream;
long Finish = (output != null) ? output.ComputedPosition : s.Position; // BytesWritten
long Start = Finish - aLength;
// need to know which segment the EOCD record starts in
UInt32 startSegment = (zss != null)
? zss.CurrentSegment
: 0;
Int64 SizeOfCentralDirectory = Finish - Start;
int countOfEntries = CountEntries(entries);
bool needZip64CentralDirectory =
zip64 == Zip64Option.Always ||
countOfEntries >= 0xFFFF ||
SizeOfCentralDirectory > 0xFFFFFFFF ||
Start > 0xFFFFFFFF;
byte[] a2 = null;
// emit ZIP64 extensions as required
if (needZip64CentralDirectory)
{
if (zip64 == Zip64Option.Never)
{
#if NETCF
throw new ZipException("The archive requires a ZIP64 Central Directory. Consider enabling ZIP64 extensions.");
#else
System.Diagnostics.StackFrame sf = new System.Diagnostics.StackFrame(1);
if (sf.GetMethod().DeclaringType == typeof(ZipFile))
throw new ZipException("The archive requires a ZIP64 Central Directory. Consider setting the ZipFile.UseZip64WhenSaving property.");
else
throw new ZipException("The archive requires a ZIP64 Central Directory. Consider setting the ZipOutputStream.EnableZip64 property.");
#endif
}
var a = GenZip64EndOfCentralDirectory(Start, Finish, countOfEntries, numSegments);
a2 = GenCentralDirectoryFooter(Start, Finish, zip64, countOfEntries, comment, container);
if (startSegment != 0)
{
UInt32 thisSegment = zss.ComputeSegment(a.Length + a2.Length);
int i = 16;
// number of this disk
Array.Copy(BitConverter.GetBytes(thisSegment), 0, a, i, 4);
i += 4;
// number of the disk with the start of the central directory
//Array.Copy(BitConverter.GetBytes(startSegment), 0, a, i, 4);
Array.Copy(BitConverter.GetBytes(thisSegment), 0, a, i, 4);
i = 60;
// offset 60
// number of the disk with the start of the zip64 eocd
Array.Copy(BitConverter.GetBytes(thisSegment), 0, a, i, 4);
i += 4;
i += 8;
// offset 72
// total number of disks
Array.Copy(BitConverter.GetBytes(thisSegment), 0, a, i, 4);
}
s.Write(a, 0, a.Length);
}
else
a2 = GenCentralDirectoryFooter(Start, Finish, zip64, countOfEntries, comment, container);
// now, the regular footer
if (startSegment != 0)
{
// The assumption is the central directory is never split across
// segment boundaries.
UInt16 thisSegment = (UInt16) zss.ComputeSegment(a2.Length);
int i = 4;
// number of this disk
Array.Copy(BitConverter.GetBytes(thisSegment), 0, a2, i, 2);
i += 2;
// number of the disk with the start of the central directory
//Array.Copy(BitConverter.GetBytes((UInt16)startSegment), 0, a2, i, 2);
Array.Copy(BitConverter.GetBytes(thisSegment), 0, a2, i, 2);
i += 2;
}
s.Write(a2, 0, a2.Length);
// reset the contiguous write property if necessary
if (zss != null)
zss.ContiguousWrite = false;
return needZip64CentralDirectory;
}
private static System.Text.Encoding GetEncoding(ZipContainer container, string t)
{
switch (container.AlternateEncodingUsage)
{
case ZipOption.Always:
return container.AlternateEncoding;
case ZipOption.Never:
return container.DefaultEncoding;
}
// AsNecessary is in force
var e = container.DefaultEncoding;
if (t == null) return e;
var bytes = e.GetBytes(t);
var t2 = e.GetString(bytes,0,bytes.Length);
if (t2.Equals(t)) return e;
return container.AlternateEncoding;
}
private static byte[] GenCentralDirectoryFooter(long StartOfCentralDirectory,
long EndOfCentralDirectory,
Zip64Option zip64,
int entryCount,
string comment,
ZipContainer container)
{
System.Text.Encoding encoding = GetEncoding(container, comment);
int j = 0;
int bufferLength = 22;
byte[] block = null;
Int16 commentLength = 0;
if ((comment != null) && (comment.Length != 0))
{
block = encoding.GetBytes(comment);
commentLength = (Int16)block.Length;
}
bufferLength += commentLength;
byte[] bytes = new byte[bufferLength];
int i = 0;
// signature
byte[] sig = BitConverter.GetBytes(ZipConstants.EndOfCentralDirectorySignature);
Array.Copy(sig, 0, bytes, i, 4);
i+=4;
// number of this disk
// (this number may change later)
bytes[i++] = 0;
bytes[i++] = 0;
// number of the disk with the start of the central directory
// (this number may change later)
bytes[i++] = 0;
bytes[i++] = 0;
// handle ZIP64 extensions for the end-of-central-directory
if (entryCount >= 0xFFFF || zip64 == Zip64Option.Always)
{
// the ZIP64 version.
for (j = 0; j < 4; j++)
bytes[i++] = 0xFF;
}
else
{
// the standard version.
// total number of entries in the central dir on this disk
bytes[i++] = (byte)(entryCount & 0x00FF);
bytes[i++] = (byte)((entryCount & 0xFF00) >> 8);
// total number of entries in the central directory
bytes[i++] = (byte)(entryCount & 0x00FF);
bytes[i++] = (byte)((entryCount & 0xFF00) >> 8);
}
// size of the central directory
Int64 SizeOfCentralDirectory = EndOfCentralDirectory - StartOfCentralDirectory;
if (SizeOfCentralDirectory >= 0xFFFFFFFF || StartOfCentralDirectory >= 0xFFFFFFFF)
{
// The actual data is in the ZIP64 central directory structure
for (j = 0; j < 8; j++)
bytes[i++] = 0xFF;
}
else
{
// size of the central directory (we just get the low 4 bytes)
bytes[i++] = (byte)(SizeOfCentralDirectory & 0x000000FF);
bytes[i++] = (byte)((SizeOfCentralDirectory & 0x0000FF00) >> 8);
bytes[i++] = (byte)((SizeOfCentralDirectory & 0x00FF0000) >> 16);
bytes[i++] = (byte)((SizeOfCentralDirectory & 0xFF000000) >> 24);
// offset of the start of the central directory (we just get the low 4 bytes)
bytes[i++] = (byte)(StartOfCentralDirectory & 0x000000FF);
bytes[i++] = (byte)((StartOfCentralDirectory & 0x0000FF00) >> 8);
bytes[i++] = (byte)((StartOfCentralDirectory & 0x00FF0000) >> 16);
bytes[i++] = (byte)((StartOfCentralDirectory & 0xFF000000) >> 24);
}
// zip archive comment
if ((comment == null) || (comment.Length == 0))
{
// no comment!
bytes[i++] = (byte)0;
bytes[i++] = (byte)0;
}
else
{
// the size of our buffer defines the max length of the comment we can write
if (commentLength + i + 2 > bytes.Length) commentLength = (Int16)(bytes.Length - i - 2);
bytes[i++] = (byte)(commentLength & 0x00FF);
bytes[i++] = (byte)((commentLength & 0xFF00) >> 8);
if (commentLength != 0)
{
// now actually write the comment itself into the byte buffer
for (j = 0; (j < commentLength) && (i + j < bytes.Length); j++)
{
bytes[i + j] = block[j];
}
i += j;
}
}
// s.Write(bytes, 0, i);
return bytes;
}
private static byte[] GenZip64EndOfCentralDirectory(long StartOfCentralDirectory,
long EndOfCentralDirectory,
int entryCount,
uint numSegments)
{
const int bufferLength = 12 + 44 + 20;
byte[] bytes = new byte[bufferLength];
int i = 0;
// signature
byte[] sig = BitConverter.GetBytes(ZipConstants.Zip64EndOfCentralDirectoryRecordSignature);
Array.Copy(sig, 0, bytes, i, 4);
i+=4;
// There is a possibility to include "Extensible" data in the zip64
// end-of-central-dir record. I cannot figure out what it might be used to
// store, so the size of this record is always fixed. Maybe it is used for
// strong encryption data? That is for another day.
long DataSize = 44;
Array.Copy(BitConverter.GetBytes(DataSize), 0, bytes, i, 8);
i += 8;
// offset 12
// VersionMadeBy = 45;
bytes[i++] = 45;
bytes[i++] = 0x00;
// VersionNeededToExtract = 45;
bytes[i++] = 45;
bytes[i++] = 0x00;
// offset 16
// number of the disk, and the disk with the start of the central dir.
// (this may change later)
for (int j = 0; j < 8; j++)
bytes[i++] = 0x00;
// offset 24
long numberOfEntries = entryCount;
Array.Copy(BitConverter.GetBytes(numberOfEntries), 0, bytes, i, 8);
i += 8;
Array.Copy(BitConverter.GetBytes(numberOfEntries), 0, bytes, i, 8);
i += 8;
// offset 40
Int64 SizeofCentraldirectory = EndOfCentralDirectory - StartOfCentralDirectory;
Array.Copy(BitConverter.GetBytes(SizeofCentraldirectory), 0, bytes, i, 8);
i += 8;
Array.Copy(BitConverter.GetBytes(StartOfCentralDirectory), 0, bytes, i, 8);
i += 8;
// offset 56
// now, the locator
// signature
sig = BitConverter.GetBytes(ZipConstants.Zip64EndOfCentralDirectoryLocatorSignature);
Array.Copy(sig, 0, bytes, i, 4);
i+=4;
// offset 60
// number of the disk with the start of the zip64 eocd
// (this will change later) (it will?)
uint x2 = (numSegments==0)?0:(uint)(numSegments-1);
Array.Copy(BitConverter.GetBytes(x2), 0, bytes, i, 4);
i+=4;
// offset 64
// relative offset of the zip64 eocd
Array.Copy(BitConverter.GetBytes(EndOfCentralDirectory), 0, bytes, i, 8);
i += 8;
// offset 72
// total number of disks
// (this will change later)
Array.Copy(BitConverter.GetBytes(numSegments), 0, bytes, i, 4);
i+=4;
return bytes;
}
private static int CountEntries(ICollection<ZipEntry> _entries)
{
// Cannot just emit _entries.Count, because some of the entries
// may have been skipped.
int count = 0;
foreach (var entry in _entries)
if (entry.IncludedInMostRecentSave) count++;
return count;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,154 +0,0 @@
// ZipFile.x-IEnumerable.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2006, 2007, 2008, 2009 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2009-December-26 15:13:26>
//
// ------------------------------------------------------------------
//
// This module defines smoe methods for IEnumerable support. It is
// particularly important for COM to have these things in a separate module.
//
// ------------------------------------------------------------------
namespace Ionic.Zip
{
// For some weird reason, the method with the DispId(-4) attribute, which is used as
// the _NewEnum() method, and which is required to get enumeration to work from COM
// environments like VBScript and Javascript (etc) must be the LAST MEMBER in the
// source. In the event of Partial classes, it needs to be the last member defined
// in the last source module. The source modules are ordered alphabetically by
// filename. Not sure why this is true. In any case, we put the enumeration stuff
// here in this oddly-named module, for this reason.
//
public partial class ZipFile
{
/// <summary>
/// Generic IEnumerator support, for use of a ZipFile in an enumeration.
/// </summary>
///
/// <remarks>
/// You probably do not want to call <c>GetEnumerator</c> explicitly. Instead
/// it is implicitly called when you use a <see langword="foreach"/> loop in C#, or a
/// <c>For Each</c> loop in VB.NET.
/// </remarks>
///
/// <example>
/// This example reads a zipfile of a given name, then enumerates the
/// entries in that zip file, and displays the information about each
/// entry on the Console.
/// <code>
/// using (ZipFile zip = ZipFile.Read(zipfile))
/// {
/// bool header = true;
/// foreach (ZipEntry e in zip)
/// {
/// if (header)
/// {
/// System.Console.WriteLine("Zipfile: {0}", zip.Name);
/// System.Console.WriteLine("Version Needed: 0x{0:X2}", e.VersionNeeded);
/// System.Console.WriteLine("BitField: 0x{0:X2}", e.BitField);
/// System.Console.WriteLine("Compression Method: 0x{0:X2}", e.CompressionMethod);
/// System.Console.WriteLine("\n{1,-22} {2,-6} {3,4} {4,-8} {0}",
/// "Filename", "Modified", "Size", "Ratio", "Packed");
/// System.Console.WriteLine(new System.String('-', 72));
/// header = false;
/// }
///
/// System.Console.WriteLine("{1,-22} {2,-6} {3,4:F0}% {4,-8} {0}",
/// e.FileName,
/// e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"),
/// e.UncompressedSize,
/// e.CompressionRatio,
/// e.CompressedSize);
///
/// e.Extract();
/// }
/// }
/// </code>
///
/// <code lang="VB">
/// Dim ZipFileToExtract As String = "c:\foo.zip"
/// Using zip As ZipFile = ZipFile.Read(ZipFileToExtract)
/// Dim header As Boolean = True
/// Dim e As ZipEntry
/// For Each e In zip
/// If header Then
/// Console.WriteLine("Zipfile: {0}", zip.Name)
/// Console.WriteLine("Version Needed: 0x{0:X2}", e.VersionNeeded)
/// Console.WriteLine("BitField: 0x{0:X2}", e.BitField)
/// Console.WriteLine("Compression Method: 0x{0:X2}", e.CompressionMethod)
/// Console.WriteLine(ChrW(10) &amp; "{1,-22} {2,-6} {3,4} {4,-8} {0}", _
/// "Filename", "Modified", "Size", "Ratio", "Packed" )
/// Console.WriteLine(New String("-"c, 72))
/// header = False
/// End If
/// Console.WriteLine("{1,-22} {2,-6} {3,4:F0}% {4,-8} {0}", _
/// e.FileName, _
/// e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"), _
/// e.UncompressedSize, _
/// e.CompressionRatio, _
/// e.CompressedSize )
/// e.Extract
/// Next
/// End Using
/// </code>
/// </example>
///
/// <returns>A generic enumerator suitable for use within a foreach loop.</returns>
public System.Collections.Generic.IEnumerator<ZipEntry> GetEnumerator()
{
foreach (ZipEntry e in _entries.Values)
yield return e;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// An IEnumerator, for use of a ZipFile in a foreach construct.
/// </summary>
///
/// <remarks>
/// This method is included for COM support. An application generally does not call
/// this method directly. It is called implicitly by COM clients when enumerating
/// the entries in the ZipFile instance. In VBScript, this is done with a <c>For Each</c>
/// statement. In Javascript, this is done with <c>new Enumerator(zipfile)</c>.
/// </remarks>
///
/// <returns>
/// The IEnumerator over the entries in the ZipFile.
/// </returns>
[System.Runtime.InteropServices.DispId(-4)]
public System.Collections.IEnumerator GetNewEnum() // the name of this method is not significant
{
return GetEnumerator();
}
}
}

View file

@ -1,827 +0,0 @@
// ZipInputStream.cs
//
// ------------------------------------------------------------------
//
// Copyright (c) 2009-2010 Dino Chiesa.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2011-July-31 14:48:30>
//
// ------------------------------------------------------------------
//
// This module defines the ZipInputStream class, which is a stream metaphor for
// reading zip files. This class does not depend on Ionic.Zip.ZipFile, but rather
// stands alongside it as an alternative "container" for ZipEntry, when reading zips.
//
// It adds one interesting method to the normal "stream" interface: GetNextEntry.
//
// ------------------------------------------------------------------
//
using System;
using System.Threading;
using System.Collections.Generic;
using System.IO;
using Ionic.Zip;
namespace Ionic.Zip
{
/// <summary>
/// Provides a stream metaphor for reading zip files.
/// </summary>
///
/// <remarks>
/// <para>
/// This class provides an alternative programming model for reading zip files to
/// the one enabled by the <see cref="ZipFile"/> class. Use this when reading zip
/// files, as an alternative to the <see cref="ZipFile"/> class, when you would
/// like to use a Stream class to read the file.
/// </para>
///
/// <para>
/// Some application designs require a readable stream for input. This stream can
/// be used to read a zip file, and extract entries.
/// </para>
///
/// <para>
/// Both the <c>ZipInputStream</c> class and the <c>ZipFile</c> class can be used
/// to read and extract zip files. Both of them support many of the common zip
/// features, including Unicode, different compression levels, and ZIP64. The
/// programming models differ. For example, when extracting entries via calls to
/// the <c>GetNextEntry()</c> and <c>Read()</c> methods on the
/// <c>ZipInputStream</c> class, the caller is responsible for creating the file,
/// writing the bytes into the file, setting the attributes on the file, and
/// setting the created, last modified, and last accessed timestamps on the
/// file. All of these things are done automatically by a call to <see
/// cref="ZipEntry.Extract()">ZipEntry.Extract()</see>. For this reason, the
/// <c>ZipInputStream</c> is generally recommended for when your application wants
/// to extract the data, without storing that data into a file.
/// </para>
///
/// <para>
/// Aside from the obvious differences in programming model, there are some
/// differences in capability between the <c>ZipFile</c> class and the
/// <c>ZipInputStream</c> class.
/// </para>
///
/// <list type="bullet">
/// <item>
/// <c>ZipFile</c> can be used to create or update zip files, or read and
/// extract zip files. <c>ZipInputStream</c> can be used only to read and
/// extract zip files. If you want to use a stream to create zip files, check
/// out the <see cref="ZipOutputStream"/>.
/// </item>
///
/// <item>
/// <c>ZipInputStream</c> cannot read segmented or spanned
/// zip files.
/// </item>
///
/// <item>
/// <c>ZipInputStream</c> will not read Zip file comments.
/// </item>
///
/// <item>
/// When reading larger files, <c>ZipInputStream</c> will always underperform
/// <c>ZipFile</c>. This is because the <c>ZipInputStream</c> does a full scan on the
/// zip file, while the <c>ZipFile</c> class reads the central directory of the
/// zip file.
/// </item>
///
/// </list>
///
/// </remarks>
public class ZipInputStream : Stream
{
/// <summary>
/// Create a <c>ZipInputStream</c>, wrapping it around an existing stream.
/// </summary>
///
/// <remarks>
///
/// <para>
/// While the <see cref="ZipFile"/> class is generally easier
/// to use, this class provides an alternative to those
/// applications that want to read from a zipfile directly,
/// using a <see cref="System.IO.Stream"/>.
/// </para>
///
/// <para>
/// Both the <c>ZipInputStream</c> class and the <c>ZipFile</c> class can be used
/// to read and extract zip files. Both of them support many of the common zip
/// features, including Unicode, different compression levels, and ZIP64. The
/// programming models differ. For example, when extracting entries via calls to
/// the <c>GetNextEntry()</c> and <c>Read()</c> methods on the
/// <c>ZipInputStream</c> class, the caller is responsible for creating the file,
/// writing the bytes into the file, setting the attributes on the file, and
/// setting the created, last modified, and last accessed timestamps on the
/// file. All of these things are done automatically by a call to <see
/// cref="ZipEntry.Extract()">ZipEntry.Extract()</see>. For this reason, the
/// <c>ZipInputStream</c> is generally recommended for when your application wants
/// to extract the data, without storing that data into a file.
/// </para>
///
/// <para>
/// Aside from the obvious differences in programming model, there are some
/// differences in capability between the <c>ZipFile</c> class and the
/// <c>ZipInputStream</c> class.
/// </para>
///
/// <list type="bullet">
/// <item>
/// <c>ZipFile</c> can be used to create or update zip files, or read and extract
/// zip files. <c>ZipInputStream</c> can be used only to read and extract zip
/// files. If you want to use a stream to create zip files, check out the <see
/// cref="ZipOutputStream"/>.
/// </item>
///
/// <item>
/// <c>ZipInputStream</c> cannot read segmented or spanned
/// zip files.
/// </item>
///
/// <item>
/// <c>ZipInputStream</c> will not read Zip file comments.
/// </item>
///
/// <item>
/// When reading larger files, <c>ZipInputStream</c> will always underperform
/// <c>ZipFile</c>. This is because the <c>ZipInputStream</c> does a full scan on the
/// zip file, while the <c>ZipFile</c> class reads the central directory of the
/// zip file.
/// </item>
///
/// </list>
///
/// </remarks>
///
/// <param name="stream">
/// The stream to read. It must be readable. This stream will be closed at
/// the time the <c>ZipInputStream</c> is closed.
/// </param>
///
/// <example>
///
/// This example shows how to read a zip file, and extract entries, using the
/// <c>ZipInputStream</c> class.
///
/// <code lang="C#">
/// private void Unzip()
/// {
/// byte[] buffer= new byte[2048];
/// int n;
/// using (var raw = File.Open(inputFileName, FileMode.Open, FileAccess.Read))
/// {
/// using (var input= new ZipInputStream(raw))
/// {
/// ZipEntry e;
/// while (( e = input.GetNextEntry()) != null)
/// {
/// if (e.IsDirectory) continue;
/// string outputPath = Path.Combine(extractDir, e.FileName);
/// using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite))
/// {
/// while ((n= input.Read(buffer, 0, buffer.Length)) > 0)
/// {
/// output.Write(buffer,0,n);
/// }
/// }
/// }
/// }
/// }
/// }
/// </code>
///
/// <code lang="VB">
/// Private Sub UnZip()
/// Dim inputFileName As String = "MyArchive.zip"
/// Dim extractDir As String = "extract"
/// Dim buffer As Byte() = New Byte(2048) {}
/// Using raw As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read)
/// Using input As ZipInputStream = New ZipInputStream(raw)
/// Dim e As ZipEntry
/// Do While (Not e = input.GetNextEntry Is Nothing)
/// If Not e.IsDirectory Then
/// Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _
/// FileMode.Create, FileAccess.ReadWrite)
/// Dim n As Integer
/// Do While (n = input.Read(buffer, 0, buffer.Length) > 0)
/// output.Write(buffer, 0, n)
/// Loop
/// End Using
/// End If
/// Loop
/// End Using
/// End Using
/// End Sub
/// </code>
/// </example>
public ZipInputStream(Stream stream) : this (stream, false) { }
/// <summary>
/// Create a <c>ZipInputStream</c>, given the name of an existing zip file.
/// </summary>
///
/// <remarks>
///
/// <para>
/// This constructor opens a <c>FileStream</c> for the given zipfile, and
/// wraps a <c>ZipInputStream</c> around that. See the documentation for the
/// <see cref="ZipInputStream(Stream)"/> constructor for full details.
/// </para>
///
/// <para>
/// While the <see cref="ZipFile"/> class is generally easier
/// to use, this class provides an alternative to those
/// applications that want to read from a zipfile directly,
/// using a <see cref="System.IO.Stream"/>.
/// </para>
///
/// </remarks>
///
/// <param name="fileName">
/// The name of the filesystem file to read.
/// </param>
///
/// <example>
///
/// This example shows how to read a zip file, and extract entries, using the
/// <c>ZipInputStream</c> class.
///
/// <code lang="C#">
/// private void Unzip()
/// {
/// byte[] buffer= new byte[2048];
/// int n;
/// using (var input= new ZipInputStream(inputFileName))
/// {
/// ZipEntry e;
/// while (( e = input.GetNextEntry()) != null)
/// {
/// if (e.IsDirectory) continue;
/// string outputPath = Path.Combine(extractDir, e.FileName);
/// using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite))
/// {
/// while ((n= input.Read(buffer, 0, buffer.Length)) > 0)
/// {
/// output.Write(buffer,0,n);
/// }
/// }
/// }
/// }
/// }
/// </code>
///
/// <code lang="VB">
/// Private Sub UnZip()
/// Dim inputFileName As String = "MyArchive.zip"
/// Dim extractDir As String = "extract"
/// Dim buffer As Byte() = New Byte(2048) {}
/// Using input As ZipInputStream = New ZipInputStream(inputFileName)
/// Dim e As ZipEntry
/// Do While (Not e = input.GetNextEntry Is Nothing)
/// If Not e.IsDirectory Then
/// Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _
/// FileMode.Create, FileAccess.ReadWrite)
/// Dim n As Integer
/// Do While (n = input.Read(buffer, 0, buffer.Length) > 0)
/// output.Write(buffer, 0, n)
/// Loop
/// End Using
/// End If
/// Loop
/// End Using
/// End Sub
/// </code>
/// </example>
public ZipInputStream(String fileName)
{
Stream stream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read );
_Init(stream, false, fileName);
}
/// <summary>
/// Create a <c>ZipInputStream</c>, explicitly specifying whether to
/// keep the underlying stream open.
/// </summary>
///
/// <remarks>
/// See the documentation for the <see
/// cref="ZipInputStream(Stream)">ZipInputStream(Stream)</see>
/// constructor for a discussion of the class, and an example of how to use the class.
/// </remarks>
///
/// <param name="stream">
/// The stream to read from. It must be readable.
/// </param>
///
/// <param name="leaveOpen">
/// true if the application would like the stream
/// to remain open after the <c>ZipInputStream</c> has been closed.
/// </param>
public ZipInputStream(Stream stream, bool leaveOpen)
{
_Init(stream, leaveOpen, null);
}
private void _Init(Stream stream, bool leaveOpen, string name)
{
_inputStream = stream;
if (!_inputStream.CanRead)
throw new ZipException("The stream must be readable.");
_container= new ZipContainer(this);
_provisionalAlternateEncoding = System.Text.Encoding.GetEncoding("IBM437");
_leaveUnderlyingStreamOpen = leaveOpen;
_findRequired= true;
_name = name ?? "(stream)";
}
/// <summary>Provides a string representation of the instance.</summary>
/// <remarks>
/// <para>
/// This can be useful for debugging purposes.
/// </para>
/// </remarks>
/// <returns>a string representation of the instance.</returns>
public override String ToString()
{
return String.Format ("ZipInputStream::{0}(leaveOpen({1})))", _name, _leaveUnderlyingStreamOpen);
}
/// <summary>
/// The text encoding to use when reading entries into the zip archive, for
/// those entries whose filenames or comments cannot be encoded with the
/// default (IBM437) encoding.
/// </summary>
///
/// <remarks>
/// <para>
/// In <see href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">its
/// zip specification</see>, PKWare describes two options for encoding
/// filenames and comments: using IBM437 or UTF-8. But, some archiving tools
/// or libraries do not follow the specification, and instead encode
/// characters using the system default code page. For example, WinRAR when
/// run on a machine in Shanghai may encode filenames with the Big-5 Chinese
/// (950) code page. This behavior is contrary to the Zip specification, but
/// it occurs anyway.
/// </para>
///
/// <para>
/// When using DotNetZip to read zip archives that use something other than
/// UTF-8 or IBM437, set this property to specify the code page to use when
/// reading encoded filenames and comments for each <c>ZipEntry</c> in the zip
/// file.
/// </para>
///
/// <para>
/// This property is "provisional". When the entry in the zip archive is not
/// explicitly marked as using UTF-8, then IBM437 is used to decode filenames
/// and comments. If a loss of data would result from using IBM436 -
/// specifically when encoding and decoding is not reflexive - the codepage
/// specified here is used. It is possible, therefore, to have a given entry
/// with a <c>Comment</c> encoded in IBM437 and a <c>FileName</c> encoded with
/// the specified "provisional" codepage.
/// </para>
///
/// <para>
/// When a zip file uses an arbitrary, non-UTF8 code page for encoding, there
/// is no standard way for the reader application - whether DotNetZip, WinZip,
/// WinRar, or something else - to know which codepage has been used for the
/// entries. Readers of zip files are not able to inspect the zip file and
/// determine the codepage that was used for the entries contained within it.
/// It is left to the application or user to determine the necessary codepage
/// when reading zip files encoded this way. If you use an incorrect codepage
/// when reading a zipfile, you will get entries with filenames that are
/// incorrect, and the incorrect filenames may even contain characters that
/// are not legal for use within filenames in Windows. Extracting entries with
/// illegal characters in the filenames will lead to exceptions. It's too bad,
/// but this is just the way things are with code pages in zip files. Caveat
/// Emptor.
/// </para>
///
/// </remarks>
public System.Text.Encoding ProvisionalAlternateEncoding
{
get
{
return _provisionalAlternateEncoding;
}
set
{
_provisionalAlternateEncoding = value;
}
}
/// <summary>
/// Size of the work buffer to use for the ZLIB codec during decompression.
/// </summary>
///
/// <remarks>
/// Setting this affects the performance and memory efficiency of compression
/// and decompression. For larger files, setting this to a larger size may
/// improve performance, but the exact numbers vary depending on available
/// memory, and a bunch of other variables. I don't have good firm
/// recommendations on how to set it. You'll have to test it yourself. Or
/// just leave it alone and accept the default.
/// </remarks>
public int CodecBufferSize
{
get;
set;
}
/// <summary>
/// Sets the password to be used on the <c>ZipInputStream</c> instance.
/// </summary>
///
/// <remarks>
///
/// <para>
/// When reading a zip archive, this password is used to read and decrypt the
/// entries that are encrypted within the zip file. When entries within a zip
/// file use different passwords, set the appropriate password for the entry
/// before the first call to <c>Read()</c> for each entry.
/// </para>
///
/// <para>
/// When reading an entry that is not encrypted, the value of this property is
/// ignored.
/// </para>
///
/// </remarks>
///
/// <example>
///
/// This example uses the ZipInputStream to read and extract entries from a
/// zip file, using a potentially different password for each entry.
///
/// <code lang="C#">
/// byte[] buffer= new byte[2048];
/// int n;
/// using (var raw = File.Open(_inputFileName, FileMode.Open, FileAccess.Read ))
/// {
/// using (var input= new ZipInputStream(raw))
/// {
/// ZipEntry e;
/// while (( e = input.GetNextEntry()) != null)
/// {
/// input.Password = PasswordForEntry(e.FileName);
/// if (e.IsDirectory) continue;
/// string outputPath = Path.Combine(_extractDir, e.FileName);
/// using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite))
/// {
/// while ((n= input.Read(buffer,0,buffer.Length)) > 0)
/// {
/// output.Write(buffer,0,n);
/// }
/// }
/// }
/// }
/// }
///
/// </code>
/// </example>
public String Password
{
set
{
if (_closed)
{
_exceptionPending = true;
throw new System.InvalidOperationException("The stream has been closed.");
}
_Password = value;
}
}
private void SetupStream()
{
// Seek to the correct posn in the file, and open a
// stream that can be read.
_crcStream= _currentEntry.InternalOpenReader(_Password);
_LeftToRead = _crcStream.Length;
_needSetup = false;
}
internal Stream ReadStream
{
get
{
return _inputStream;
}
}
/// <summary>
/// Read the data from the stream into the buffer.
/// </summary>
///
/// <remarks>
/// <para>
/// The data for the zipentry will be decrypted and uncompressed, as
/// necessary, before being copied into the buffer.
/// </para>
///
/// <para>
/// You must set the <see cref="Password"/> property before calling
/// <c>Read()</c> the first time for an encrypted entry. To determine if an
/// entry is encrypted and requires a password, check the <see
/// cref="ZipEntry.Encryption">ZipEntry.Encryption</see> property.
/// </para>
/// </remarks>
///
/// <param name="buffer">The buffer to hold the data read from the stream.</param>
/// <param name="offset">the offset within the buffer to copy the first byte read.</param>
/// <param name="count">the number of bytes to read.</param>
/// <returns>the number of bytes read, after decryption and decompression.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
if (_closed)
{
_exceptionPending = true;
throw new System.InvalidOperationException("The stream has been closed.");
}
if (_needSetup)
SetupStream();
if (_LeftToRead == 0) return 0;
int len = (_LeftToRead > count) ? count : (int)_LeftToRead;
int n = _crcStream.Read(buffer, offset, len);
_LeftToRead -= n;
if (_LeftToRead == 0)
{
int CrcResult = _crcStream.Crc;
_currentEntry.VerifyCrcAfterExtract(CrcResult);
_inputStream.Seek(_endOfEntry, SeekOrigin.Begin);
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_inputStream);
}
return n;
}
/// <summary>
/// Read the next entry from the zip file.
/// </summary>
///
/// <remarks>
/// <para>
/// Call this method just before calling <see cref="Read(byte[], int, int)"/>,
/// to position the pointer in the zip file to the next entry that can be
/// read. Subsequent calls to <c>Read()</c>, will decrypt and decompress the
/// data in the zip file, until <c>Read()</c> returns 0.
/// </para>
///
/// <para>
/// Each time you call <c>GetNextEntry()</c>, the pointer in the wrapped
/// stream is moved to the next entry in the zip file. If you call <see
/// cref="Seek(long, SeekOrigin)"/>, and thus re-position the pointer within
/// the file, you will need to call <c>GetNextEntry()</c> again, to insure
/// that the file pointer is positioned at the beginning of a zip entry.
/// </para>
///
/// <para>
/// This method returns the <c>ZipEntry</c>. Using a stream approach, you will
/// read the raw bytes for an entry in a zip file via calls to <c>Read()</c>.
/// Alternatively, you can extract an entry into a file, or a stream, by
/// calling <see cref="ZipEntry.Extract()"/>, or one of its siblings.
/// </para>
///
/// </remarks>
///
/// <returns>
/// The <c>ZipEntry</c> read. Returns null (or Nothing in VB) if there are no more
/// entries in the zip file.
/// </returns>
///
public ZipEntry GetNextEntry()
{
if (_findRequired)
{
// find the next signature
long d = SharedUtilities.FindSignature(_inputStream, ZipConstants.ZipEntrySignature);
if (d == -1) return null;
// back up 4 bytes: ReadEntry assumes the file pointer is positioned before the entry signature
_inputStream.Seek(-4, SeekOrigin.Current);
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_inputStream);
}
// workitem 10923
else if (_firstEntry)
{
// we've already read one entry.
// Seek to the end of it.
_inputStream.Seek(_endOfEntry, SeekOrigin.Begin);
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_inputStream);
}
_currentEntry = ZipEntry.ReadEntry(_container, !_firstEntry);
// ReadEntry leaves the file position after all the entry
// data and the optional bit-3 data descriptpr. This is
// where the next entry would normally start.
_endOfEntry = _inputStream.Position;
_firstEntry = true;
_needSetup = true;
_findRequired= false;
return _currentEntry;
}
/// <summary>
/// Dispose the stream.
/// </summary>
///
/// <remarks>
/// <para>
/// This method disposes the ZipInputStream. It may also close the
/// underlying stream, depending on which constructor was used.
/// </para>
///
/// <para>
/// Typically the application will call <c>Dispose()</c> implicitly, via
/// a <c>using</c> statement in C#, or a <c>Using</c> statement in VB.
/// </para>
///
/// <para>
/// Application code won't call this code directly. This method may
/// be invoked in two distinct scenarios. If disposing == true, the
/// method has been called directly or indirectly by a user's code,
/// for example via the public Dispose() method. In this case, both
/// managed and unmanaged resources can be referenced and disposed.
/// If disposing == false, the method has been called by the runtime
/// from inside the object finalizer and this method should not
/// reference other objects; in that case only unmanaged resources
/// must be referenced or disposed.
/// </para>
/// </remarks>
///
/// <param name="disposing">
/// true if the Dispose method was invoked by user code.
/// </param>
protected override void Dispose(bool disposing)
{
if (_closed) return;
if (disposing) // not called from finalizer
{
// When ZipInputStream is used within a using clause, and an
// exception is thrown, Close() is invoked. But we don't want to
// try to write anything in that case. Eventually the exception
// will be propagated to the application.
if (_exceptionPending) return;
if (!_leaveUnderlyingStreamOpen)
{
#if NETCF
_inputStream.Close();
#else
_inputStream.Dispose();
#endif
}
}
_closed= true;
}
/// <summary>
/// Always returns true.
/// </summary>
public override bool CanRead { get { return true; }}
/// <summary>
/// Returns the value of <c>CanSeek</c> for the underlying (wrapped) stream.
/// </summary>
public override bool CanSeek { get { return _inputStream.CanSeek; } }
/// <summary>
/// Always returns false.
/// </summary>
public override bool CanWrite { get { return false; } }
/// <summary>
/// Returns the length of the underlying stream.
/// </summary>
public override long Length { get { return _inputStream.Length; }}
/// <summary>
/// Gets or sets the position of the underlying stream.
/// </summary>
/// <remarks>
/// Setting the position is equivalent to calling <c>Seek(value, SeekOrigin.Begin)</c>.
/// </remarks>
public override long Position
{
get { return _inputStream.Position;}
set { Seek(value, SeekOrigin.Begin); }
}
/// <summary>
/// This is a no-op.
/// </summary>
public override void Flush()
{
throw new NotSupportedException("Flush");
}
/// <summary>
/// This method always throws a NotSupportedException.
/// </summary>
/// <param name="buffer">ignored</param>
/// <param name="offset">ignored</param>
/// <param name="count">ignored</param>
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException("Write");
}
/// <summary>
/// This method seeks in the underlying stream.
/// </summary>
///
/// <remarks>
/// <para>
/// Call this method if you want to seek around within the zip file for random access.
/// </para>
///
/// <para>
/// Applications can intermix calls to <c>Seek()</c> with calls to <see
/// cref="GetNextEntry()"/>. After a call to <c>Seek()</c>,
/// <c>GetNextEntry()</c> will get the next <c>ZipEntry</c> that falls after
/// the current position in the input stream. You're on your own for finding
/// out just where to seek in the stream, to get to the various entries.
/// </para>
///
/// </remarks>
///
/// <param name="offset">the offset point to seek to</param>
/// <param name="origin">the reference point from which to seek</param>
/// <returns>The new position</returns>
public override long Seek(long offset, SeekOrigin origin)
{
_findRequired= true;
var x = _inputStream.Seek(offset, origin);
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_inputStream);
return x;
}
/// <summary>
/// This method always throws a NotSupportedException.
/// </summary>
/// <param name="value">ignored</param>
public override void SetLength(long value)
{
throw new NotSupportedException();
}
private Stream _inputStream;
private System.Text.Encoding _provisionalAlternateEncoding;
private ZipEntry _currentEntry;
private bool _firstEntry;
private bool _needSetup;
private ZipContainer _container;
private Ionic.Crc.CrcCalculatorStream _crcStream;
private Int64 _LeftToRead;
internal String _Password;
private Int64 _endOfEntry;
private string _name;
private bool _leaveUnderlyingStreamOpen;
private bool _closed;
private bool _findRequired;
private bool _exceptionPending;
}
}

View file

@ -1,571 +0,0 @@
// ZipSegmentedStream.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009-2011 Dino Chiesa.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2011-July-13 22:25:45>
//
// ------------------------------------------------------------------
//
// This module defines logic for zip streams that span disk files.
//
// ------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.IO;
namespace Ionic.Zip
{
internal class ZipSegmentedStream : System.IO.Stream
{
enum RwMode
{
None = 0,
ReadOnly = 1,
Write = 2,
//Update = 3
}
private RwMode rwMode;
private bool _exceptionPending; // **see note below
private string _baseName;
private string _baseDir;
//private bool _isDisposed;
private string _currentName;
private string _currentTempName;
private uint _currentDiskNumber;
private uint _maxDiskNumber;
private int _maxSegmentSize;
private System.IO.Stream _innerStream;
// **Note regarding exceptions:
//
// When ZipSegmentedStream is employed within a using clause,
// which is the typical scenario, and an exception is thrown
// within the scope of the using, Dispose() is invoked
// implicitly before processing the initial exception. If that
// happens, this class sets _exceptionPending to true, and then
// within the Dispose(bool), takes special action as
// appropriate. Need to be careful: any additional exceptions
// will mask the original one.
private ZipSegmentedStream() : base()
{
_exceptionPending = false;
}
public static ZipSegmentedStream ForReading(string name,
uint initialDiskNumber,
uint maxDiskNumber)
{
ZipSegmentedStream zss = new ZipSegmentedStream()
{
rwMode = RwMode.ReadOnly,
CurrentSegment = initialDiskNumber,
_maxDiskNumber = maxDiskNumber,
_baseName = name,
};
// Console.WriteLine("ZSS: ForReading ({0})",
// Path.GetFileName(zss.CurrentName));
zss._SetReadStream();
return zss;
}
public static ZipSegmentedStream ForWriting(string name, int maxSegmentSize)
{
ZipSegmentedStream zss = new ZipSegmentedStream()
{
rwMode = RwMode.Write,
CurrentSegment = 0,
_baseName = name,
_maxSegmentSize = maxSegmentSize,
_baseDir = Path.GetDirectoryName(name)
};
// workitem 9522
if (zss._baseDir=="") zss._baseDir=".";
zss._SetWriteStream(0);
// Console.WriteLine("ZSS: ForWriting ({0})",
// Path.GetFileName(zss.CurrentName));
return zss;
}
/// <summary>
/// Sort-of like a factory method, ForUpdate is used only when
/// the application needs to update the zip entry metadata for
/// a segmented zip file, when the starting segment is earlier
/// than the ending segment, for a particular entry.
/// </summary>
/// <remarks>
/// <para>
/// The update is always contiguous, never rolls over. As a
/// result, this method doesn't need to return a ZSS; it can
/// simply return a FileStream. That's why it's "sort of"
/// like a Factory method.
/// </para>
/// <para>
/// Caller must Close/Dispose the stream object returned by
/// this method.
/// </para>
/// </remarks>
public static Stream ForUpdate(string name, uint diskNumber)
{
if (diskNumber >= 99)
throw new ArgumentOutOfRangeException("diskNumber");
string fname =
String.Format("{0}.z{1:D2}",
Path.Combine(Path.GetDirectoryName(name),
Path.GetFileNameWithoutExtension(name)),
diskNumber + 1);
// Console.WriteLine("ZSS: ForUpdate ({0})",
// Path.GetFileName(fname));
// This class assumes that the update will not expand the
// size of the segment. Update is used only for an in-place
// update of zip metadata. It never will try to write beyond
// the end of a segment.
return File.Open(fname,
FileMode.Open,
FileAccess.ReadWrite,
FileShare.None);
}
public bool ContiguousWrite
{
get;
set;
}
public UInt32 CurrentSegment
{
get
{
return _currentDiskNumber;
}
private set
{
_currentDiskNumber = value;
_currentName = null; // it will get updated next time referenced
}
}
/// <summary>
/// Name of the filesystem file corresponding to the current segment.
/// </summary>
/// <remarks>
/// <para>
/// The name is not always the name currently being used in the
/// filesystem. When rwMode is RwMode.Write, the filesystem file has a
/// temporary name until the stream is closed or until the next segment is
/// started.
/// </para>
/// </remarks>
public String CurrentName
{
get
{
if (_currentName==null)
_currentName = _NameForSegment(CurrentSegment);
return _currentName;
}
}
public String CurrentTempName
{
get
{
return _currentTempName;
}
}
private string _NameForSegment(uint diskNumber)
{
if (diskNumber >= 99)
{
_exceptionPending = true;
throw new OverflowException("The number of zip segments would exceed 99.");
}
return String.Format("{0}.z{1:D2}",
Path.Combine(Path.GetDirectoryName(_baseName),
Path.GetFileNameWithoutExtension(_baseName)),
diskNumber + 1);
}
// Returns the segment that WILL be current if writing
// a block of the given length.
// This isn't exactly true. It could roll over beyond
// this number.
public UInt32 ComputeSegment(int length)
{
if (_innerStream.Position + length > _maxSegmentSize)
// the block will go AT LEAST into the next segment
return CurrentSegment + 1;
// it will fit in the current segment
return CurrentSegment;
}
public override String ToString()
{
return String.Format("{0}[{1}][{2}], pos=0x{3:X})",
"ZipSegmentedStream", CurrentName,
rwMode.ToString(),
this.Position);
}
private void _SetReadStream()
{
if (_innerStream != null)
{
#if NETCF
_innerStream.Close();
#else
_innerStream.Dispose();
#endif
}
if (CurrentSegment + 1 == _maxDiskNumber)
_currentName = _baseName;
// Console.WriteLine("ZSS: SRS ({0})",
// Path.GetFileName(CurrentName));
_innerStream = File.OpenRead(CurrentName);
}
/// <summary>
/// Read from the stream
/// </summary>
/// <param name="buffer">the buffer to read</param>
/// <param name="offset">the offset at which to start</param>
/// <param name="count">the number of bytes to read</param>
/// <returns>the number of bytes actually read</returns>
public override int Read(byte[] buffer, int offset, int count)
{
if (rwMode != RwMode.ReadOnly)
{
_exceptionPending = true;
throw new InvalidOperationException("Stream Error: Cannot Read.");
}
int r = _innerStream.Read(buffer, offset, count);
int r1 = r;
while (r1 != count)
{
if (_innerStream.Position != _innerStream.Length)
{
_exceptionPending = true;
throw new ZipException(String.Format("Read error in file {0}", CurrentName));
}
if (CurrentSegment + 1 == _maxDiskNumber)
return r; // no more to read
CurrentSegment++;
_SetReadStream();
offset += r1;
count -= r1;
r1 = _innerStream.Read(buffer, offset, count);
r += r1;
}
return r;
}
private void _SetWriteStream(uint increment)
{
if (_innerStream != null)
{
#if NETCF
_innerStream.Close();
#else
_innerStream.Dispose();
#endif
if (File.Exists(CurrentName))
File.Delete(CurrentName);
File.Move(_currentTempName, CurrentName);
// Console.WriteLine("ZSS: SWS close ({0})",
// Path.GetFileName(CurrentName));
}
if (increment > 0)
CurrentSegment += increment;
SharedUtilities.CreateAndOpenUniqueTempFile(_baseDir,
out _innerStream,
out _currentTempName);
// Console.WriteLine("ZSS: SWS open ({0})",
// Path.GetFileName(_currentTempName));
if (CurrentSegment == 0)
_innerStream.Write(BitConverter.GetBytes(ZipConstants.SplitArchiveSignature), 0, 4);
}
/// <summary>
/// Write to the stream.
/// </summary>
/// <param name="buffer">the buffer from which to write</param>
/// <param name="offset">the offset at which to start writing</param>
/// <param name="count">the number of bytes to write</param>
public override void Write(byte[] buffer, int offset, int count)
{
if (rwMode != RwMode.Write)
{
_exceptionPending = true;
throw new InvalidOperationException("Stream Error: Cannot Write.");
}
if (ContiguousWrite)
{
// enough space for a contiguous write?
if (_innerStream.Position + count > _maxSegmentSize)
_SetWriteStream(1);
}
else
{
while (_innerStream.Position + count > _maxSegmentSize)
{
int c = unchecked(_maxSegmentSize - (int)_innerStream.Position);
_innerStream.Write(buffer, offset, c);
_SetWriteStream(1);
count -= c;
offset += c;
}
}
_innerStream.Write(buffer, offset, count);
}
public long TruncateBackward(uint diskNumber, long offset)
{
// Console.WriteLine("***ZSS.Trunc to disk {0}", diskNumber);
// Console.WriteLine("***ZSS.Trunc: current disk {0}", CurrentSegment);
if (diskNumber >= 99)
throw new ArgumentOutOfRangeException("diskNumber");
if (rwMode != RwMode.Write)
{
_exceptionPending = true;
throw new ZipException("bad state.");
}
// Seek back in the segmented stream to a (maybe) prior segment.
// Check if it is the same segment. If it is, very simple.
if (diskNumber == CurrentSegment)
{
var x =_innerStream.Seek(offset, SeekOrigin.Begin);
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_innerStream);
return x;
}
// Seeking back to a prior segment.
// The current segment and any intervening segments must be removed.
// First, close the current segment, and then remove it.
if (_innerStream != null)
{
#if NETCF
_innerStream.Close();
#else
_innerStream.Dispose();
#endif
if (File.Exists(_currentTempName))
File.Delete(_currentTempName);
}
// Now, remove intervening segments.
for (uint j= CurrentSegment-1; j > diskNumber; j--)
{
string s = _NameForSegment(j);
// Console.WriteLine("***ZSS.Trunc: removing file {0}", s);
if (File.Exists(s))
File.Delete(s);
}
// now, open the desired segment. It must exist.
CurrentSegment = diskNumber;
// get a new temp file, try 3 times:
for (int i = 0; i < 3; i++)
{
try
{
_currentTempName = SharedUtilities.InternalGetTempFileName();
// move the .z0x file back to a temp name
File.Move(CurrentName, _currentTempName);
break; // workitem 12403
}
catch(IOException)
{
if (i == 2) throw;
}
}
// open it
_innerStream = new FileStream(_currentTempName, FileMode.Open);
var r = _innerStream.Seek(offset, SeekOrigin.Begin);
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_innerStream);
return r;
}
public override bool CanRead
{
get
{
return (rwMode == RwMode.ReadOnly &&
(_innerStream != null) &&
_innerStream.CanRead);
}
}
public override bool CanSeek
{
get
{
return (_innerStream != null) &&
_innerStream.CanSeek;
}
}
public override bool CanWrite
{
get
{
return (rwMode == RwMode.Write) &&
(_innerStream != null) &&
_innerStream.CanWrite;
}
}
public override void Flush()
{
_innerStream.Flush();
}
public override long Length
{
get
{
return _innerStream.Length;
}
}
public override long Position
{
get { return _innerStream.Position; }
set { _innerStream.Position = value; }
}
public override long Seek(long offset, System.IO.SeekOrigin origin)
{
var x = _innerStream.Seek(offset, origin);
// workitem 10178
Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_innerStream);
return x;
}
public override void SetLength(long value)
{
if (rwMode != RwMode.Write)
{
_exceptionPending = true;
throw new InvalidOperationException();
}
_innerStream.SetLength(value);
}
protected override void Dispose(bool disposing)
{
// this gets called by Stream.Close()
// if (_isDisposed) return;
// _isDisposed = true;
//Console.WriteLine("Dispose (mode={0})\n", rwMode.ToString());
try
{
if (_innerStream != null)
{
#if NETCF
_innerStream.Close();
#else
_innerStream.Dispose();
#endif
//_innerStream = null;
if (rwMode == RwMode.Write)
{
if (_exceptionPending)
{
// possibly could try to clean up all the
// temp files created so far...
}
else
{
// // move the final temp file to the .zNN name
// if (File.Exists(CurrentName))
// File.Delete(CurrentName);
// if (File.Exists(_currentTempName))
// File.Move(_currentTempName, CurrentName);
}
}
}
}
finally
{
base.Dispose(disposing);
}
}
}
}

View file

@ -1,548 +0,0 @@
// Zlib.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009-2011 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// Last Saved: <2011-August-03 19:52:28>
//
// ------------------------------------------------------------------
//
// This module defines classes for ZLIB compression and
// decompression. This code is derived from the jzlib implementation of
// zlib, but significantly modified. The object model is not the same,
// and many of the behaviors are new or different. Nonetheless, in
// keeping with the license for jzlib, the copyright to that code is
// included below.
//
// ------------------------------------------------------------------
//
// The following notice applies to jzlib:
//
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the distribution.
//
// 3. The names of the authors may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------
//
// jzlib is based on zlib-1.1.3.
//
// The following notice applies to zlib:
//
// -----------------------------------------------------------------------
//
// Copyright (C) 1995-2004 Jean-loup Gailly and Mark Adler
//
// The ZLIB software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
// Jean-loup Gailly jloup@gzip.org
// Mark Adler madler@alumni.caltech.edu
//
// -----------------------------------------------------------------------
using System;
using System.Runtime.CompilerServices;
using Interop=System.Runtime.InteropServices;
namespace Ionic.Zlib
{
/// <summary>
/// Describes how to flush the current deflate operation.
/// </summary>
/// <remarks>
/// The different FlushType values are useful when using a Deflate in a streaming application.
/// </remarks>
public enum FlushType
{
/// <summary>No flush at all.</summary>
None = 0,
/// <summary>Closes the current block, but doesn't flush it to
/// the output. Used internally only in hypothetical
/// scenarios. This was supposed to be removed by Zlib, but it is
/// still in use in some edge cases.
/// </summary>
Partial,
/// <summary>
/// Use this during compression to specify that all pending output should be
/// flushed to the output buffer and the output should be aligned on a byte
/// boundary. You might use this in a streaming communication scenario, so that
/// the decompressor can get all input data available so far. When using this
/// with a ZlibCodec, <c>AvailableBytesIn</c> will be zero after the call if
/// enough output space has been provided before the call. Flushing will
/// degrade compression and so it should be used only when necessary.
/// </summary>
Sync,
/// <summary>
/// Use this during compression to specify that all output should be flushed, as
/// with <c>FlushType.Sync</c>, but also, the compression state should be reset
/// so that decompression can restart from this point if previous compressed
/// data has been damaged or if random access is desired. Using
/// <c>FlushType.Full</c> too often can significantly degrade the compression.
/// </summary>
Full,
/// <summary>Signals the end of the compression/decompression stream.</summary>
Finish,
}
/// <summary>
/// The compression level to be used when using a DeflateStream or ZlibStream with CompressionMode.Compress.
/// </summary>
public enum CompressionLevel
{
/// <summary>
/// None means that the data will be simply stored, with no change at all.
/// If you are producing ZIPs for use on Mac OSX, be aware that archives produced with CompressionLevel.None
/// cannot be opened with the default zip reader. Use a different CompressionLevel.
/// </summary>
None= 0,
/// <summary>
/// Same as None.
/// </summary>
Level0 = 0,
/// <summary>
/// The fastest but least effective compression.
/// </summary>
BestSpeed = 1,
/// <summary>
/// A synonym for BestSpeed.
/// </summary>
Level1 = 1,
/// <summary>
/// A little slower, but better, than level 1.
/// </summary>
Level2 = 2,
/// <summary>
/// A little slower, but better, than level 2.
/// </summary>
Level3 = 3,
/// <summary>
/// A little slower, but better, than level 3.
/// </summary>
Level4 = 4,
/// <summary>
/// A little slower than level 4, but with better compression.
/// </summary>
Level5 = 5,
/// <summary>
/// The default compression level, with a good balance of speed and compression efficiency.
/// </summary>
Default = 6,
/// <summary>
/// A synonym for Default.
/// </summary>
Level6 = 6,
/// <summary>
/// Pretty good compression!
/// </summary>
Level7 = 7,
/// <summary>
/// Better compression than Level7!
/// </summary>
Level8 = 8,
/// <summary>
/// The "best" compression, where best means greatest reduction in size of the input data stream.
/// This is also the slowest compression.
/// </summary>
BestCompression = 9,
/// <summary>
/// A synonym for BestCompression.
/// </summary>
Level9 = 9,
}
/// <summary>
/// Describes options for how the compression algorithm is executed. Different strategies
/// work better on different sorts of data. The strategy parameter can affect the compression
/// ratio and the speed of compression but not the correctness of the compresssion.
/// </summary>
public enum CompressionStrategy
{
/// <summary>
/// The default strategy is probably the best for normal data.
/// </summary>
Default = 0,
/// <summary>
/// The <c>Filtered</c> strategy is intended to be used most effectively with data produced by a
/// filter or predictor. By this definition, filtered data consists mostly of small
/// values with a somewhat random distribution. In this case, the compression algorithm
/// is tuned to compress them better. The effect of <c>Filtered</c> is to force more Huffman
/// coding and less string matching; it is a half-step between <c>Default</c> and <c>HuffmanOnly</c>.
/// </summary>
Filtered = 1,
/// <summary>
/// Using <c>HuffmanOnly</c> will force the compressor to do Huffman encoding only, with no
/// string matching.
/// </summary>
HuffmanOnly = 2,
}
/// <summary>
/// An enum to specify the direction of transcoding - whether to compress or decompress.
/// </summary>
public enum CompressionMode
{
/// <summary>
/// Used to specify that the stream should compress the data.
/// </summary>
Compress= 0,
/// <summary>
/// Used to specify that the stream should decompress the data.
/// </summary>
Decompress = 1,
}
/// <summary>
/// A general purpose exception class for exceptions in the Zlib library.
/// </summary>
[Interop.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000E")]
public class ZlibException : System.Exception
{
/// <summary>
/// The ZlibException class captures exception information generated
/// by the Zlib library.
/// </summary>
public ZlibException()
: base()
{
}
/// <summary>
/// This ctor collects a message attached to the exception.
/// </summary>
/// <param name="s">the message for the exception.</param>
public ZlibException(System.String s)
: base(s)
{
}
}
internal class SharedUtils
{
/// <summary>
/// Performs an unsigned bitwise right shift with the specified number
/// </summary>
/// <param name="number">Number to operate on</param>
/// <param name="bits">Ammount of bits to shift</param>
/// <returns>The resulting number from the shift operation</returns>
public static int URShift(int number, int bits)
{
return (int)((uint)number >> bits);
}
#if NOT
/// <summary>
/// Performs an unsigned bitwise right shift with the specified number
/// </summary>
/// <param name="number">Number to operate on</param>
/// <param name="bits">Ammount of bits to shift</param>
/// <returns>The resulting number from the shift operation</returns>
public static long URShift(long number, int bits)
{
return (long) ((UInt64)number >> bits);
}
#endif
/// <summary>
/// Reads a number of characters from the current source TextReader and writes
/// the data to the target array at the specified index.
/// </summary>
///
/// <param name="sourceTextReader">The source TextReader to read from</param>
/// <param name="target">Contains the array of characteres read from the source TextReader.</param>
/// <param name="start">The starting index of the target array.</param>
/// <param name="count">The maximum number of characters to read from the source TextReader.</param>
///
/// <returns>
/// The number of characters read. The number will be less than or equal to
/// count depending on the data available in the source TextReader. Returns -1
/// if the end of the stream is reached.
/// </returns>
public static System.Int32 ReadInput(System.IO.TextReader sourceTextReader, byte[] target, int start, int count)
{
// Returns 0 bytes if not enough space in target
if (target.Length == 0) return 0;
char[] charArray = new char[target.Length];
int bytesRead = sourceTextReader.Read(charArray, start, count);
// Returns -1 if EOF
if (bytesRead == 0) return -1;
for (int index = start; index < start + bytesRead; index++)
target[index] = (byte)charArray[index];
return bytesRead;
}
internal static byte[] ToByteArray(System.String sourceString)
{
return System.Text.UTF8Encoding.UTF8.GetBytes(sourceString);
}
internal static char[] ToCharArray(byte[] byteArray)
{
return System.Text.UTF8Encoding.UTF8.GetChars(byteArray);
}
}
internal static class InternalConstants
{
internal static readonly int MAX_BITS = 15;
internal static readonly int BL_CODES = 19;
internal static readonly int D_CODES = 30;
internal static readonly int LITERALS = 256;
internal static readonly int LENGTH_CODES = 29;
internal static readonly int L_CODES = (LITERALS + 1 + LENGTH_CODES);
// Bit length codes must not exceed MAX_BL_BITS bits
internal static readonly int MAX_BL_BITS = 7;
// repeat previous bit length 3-6 times (2 bits of repeat count)
internal static readonly int REP_3_6 = 16;
// repeat a zero length 3-10 times (3 bits of repeat count)
internal static readonly int REPZ_3_10 = 17;
// repeat a zero length 11-138 times (7 bits of repeat count)
internal static readonly int REPZ_11_138 = 18;
}
internal sealed class StaticTree
{
internal static readonly short[] lengthAndLiteralsTreeCodes = new short[] {
12, 8, 140, 8, 76, 8, 204, 8, 44, 8, 172, 8, 108, 8, 236, 8,
28, 8, 156, 8, 92, 8, 220, 8, 60, 8, 188, 8, 124, 8, 252, 8,
2, 8, 130, 8, 66, 8, 194, 8, 34, 8, 162, 8, 98, 8, 226, 8,
18, 8, 146, 8, 82, 8, 210, 8, 50, 8, 178, 8, 114, 8, 242, 8,
10, 8, 138, 8, 74, 8, 202, 8, 42, 8, 170, 8, 106, 8, 234, 8,
26, 8, 154, 8, 90, 8, 218, 8, 58, 8, 186, 8, 122, 8, 250, 8,
6, 8, 134, 8, 70, 8, 198, 8, 38, 8, 166, 8, 102, 8, 230, 8,
22, 8, 150, 8, 86, 8, 214, 8, 54, 8, 182, 8, 118, 8, 246, 8,
14, 8, 142, 8, 78, 8, 206, 8, 46, 8, 174, 8, 110, 8, 238, 8,
30, 8, 158, 8, 94, 8, 222, 8, 62, 8, 190, 8, 126, 8, 254, 8,
1, 8, 129, 8, 65, 8, 193, 8, 33, 8, 161, 8, 97, 8, 225, 8,
17, 8, 145, 8, 81, 8, 209, 8, 49, 8, 177, 8, 113, 8, 241, 8,
9, 8, 137, 8, 73, 8, 201, 8, 41, 8, 169, 8, 105, 8, 233, 8,
25, 8, 153, 8, 89, 8, 217, 8, 57, 8, 185, 8, 121, 8, 249, 8,
5, 8, 133, 8, 69, 8, 197, 8, 37, 8, 165, 8, 101, 8, 229, 8,
21, 8, 149, 8, 85, 8, 213, 8, 53, 8, 181, 8, 117, 8, 245, 8,
13, 8, 141, 8, 77, 8, 205, 8, 45, 8, 173, 8, 109, 8, 237, 8,
29, 8, 157, 8, 93, 8, 221, 8, 61, 8, 189, 8, 125, 8, 253, 8,
19, 9, 275, 9, 147, 9, 403, 9, 83, 9, 339, 9, 211, 9, 467, 9,
51, 9, 307, 9, 179, 9, 435, 9, 115, 9, 371, 9, 243, 9, 499, 9,
11, 9, 267, 9, 139, 9, 395, 9, 75, 9, 331, 9, 203, 9, 459, 9,
43, 9, 299, 9, 171, 9, 427, 9, 107, 9, 363, 9, 235, 9, 491, 9,
27, 9, 283, 9, 155, 9, 411, 9, 91, 9, 347, 9, 219, 9, 475, 9,
59, 9, 315, 9, 187, 9, 443, 9, 123, 9, 379, 9, 251, 9, 507, 9,
7, 9, 263, 9, 135, 9, 391, 9, 71, 9, 327, 9, 199, 9, 455, 9,
39, 9, 295, 9, 167, 9, 423, 9, 103, 9, 359, 9, 231, 9, 487, 9,
23, 9, 279, 9, 151, 9, 407, 9, 87, 9, 343, 9, 215, 9, 471, 9,
55, 9, 311, 9, 183, 9, 439, 9, 119, 9, 375, 9, 247, 9, 503, 9,
15, 9, 271, 9, 143, 9, 399, 9, 79, 9, 335, 9, 207, 9, 463, 9,
47, 9, 303, 9, 175, 9, 431, 9, 111, 9, 367, 9, 239, 9, 495, 9,
31, 9, 287, 9, 159, 9, 415, 9, 95, 9, 351, 9, 223, 9, 479, 9,
63, 9, 319, 9, 191, 9, 447, 9, 127, 9, 383, 9, 255, 9, 511, 9,
0, 7, 64, 7, 32, 7, 96, 7, 16, 7, 80, 7, 48, 7, 112, 7,
8, 7, 72, 7, 40, 7, 104, 7, 24, 7, 88, 7, 56, 7, 120, 7,
4, 7, 68, 7, 36, 7, 100, 7, 20, 7, 84, 7, 52, 7, 116, 7,
3, 8, 131, 8, 67, 8, 195, 8, 35, 8, 163, 8, 99, 8, 227, 8
};
internal static readonly short[] distTreeCodes = new short[] {
0, 5, 16, 5, 8, 5, 24, 5, 4, 5, 20, 5, 12, 5, 28, 5,
2, 5, 18, 5, 10, 5, 26, 5, 6, 5, 22, 5, 14, 5, 30, 5,
1, 5, 17, 5, 9, 5, 25, 5, 5, 5, 21, 5, 13, 5, 29, 5,
3, 5, 19, 5, 11, 5, 27, 5, 7, 5, 23, 5 };
internal static readonly StaticTree Literals;
internal static readonly StaticTree Distances;
internal static readonly StaticTree BitLengths;
internal short[] treeCodes; // static tree or null
internal int[] extraBits; // extra bits for each code or null
internal int extraBase; // base index for extra_bits
internal int elems; // max number of elements in the tree
internal int maxLength; // max bit length for the codes
private StaticTree(short[] treeCodes, int[] extraBits, int extraBase, int elems, int maxLength)
{
this.treeCodes = treeCodes;
this.extraBits = extraBits;
this.extraBase = extraBase;
this.elems = elems;
this.maxLength = maxLength;
}
static StaticTree()
{
Literals = new StaticTree(lengthAndLiteralsTreeCodes, Tree.ExtraLengthBits, InternalConstants.LITERALS + 1, InternalConstants.L_CODES, InternalConstants.MAX_BITS);
Distances = new StaticTree(distTreeCodes, Tree.ExtraDistanceBits, 0, InternalConstants.D_CODES, InternalConstants.MAX_BITS);
BitLengths = new StaticTree(null, Tree.extra_blbits, 0, InternalConstants.BL_CODES, InternalConstants.MAX_BL_BITS);
}
}
/// <summary>
/// Computes an Adler-32 checksum.
/// </summary>
/// <remarks>
/// The Adler checksum is similar to a CRC checksum, but faster to compute, though less
/// reliable. It is used in producing RFC1950 compressed streams. The Adler checksum
/// is a required part of the "ZLIB" standard. Applications will almost never need to
/// use this class directly.
/// </remarks>
///
/// <exclude/>
public sealed class Adler
{
// largest prime smaller than 65536
private static readonly uint BASE = 65521;
// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
private static readonly int NMAX = 5552;
#pragma warning disable 3001
#pragma warning disable 3002
/// <summary>
/// Calculates the Adler32 checksum.
/// </summary>
/// <remarks>
/// <para>
/// This is used within ZLIB. You probably don't need to use this directly.
/// </para>
/// </remarks>
/// <example>
/// To compute an Adler32 checksum on a byte array:
/// <code>
/// var adler = Adler.Adler32(0, null, 0, 0);
/// adler = Adler.Adler32(adler, buffer, index, length);
/// </code>
/// </example>
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static uint Adler32(uint adler, byte[] buf, int index, int len)
{
if (buf == null)
return 1;
uint s1 = (uint) (adler & 0xffff);
uint s2 = (uint) ((adler >> 16) & 0xffff);
while (len > 0)
{
int k = len < NMAX ? len : NMAX;
len -= k;
while (k >= 16)
{
//s1 += (buf[index++] & 0xff); s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
s1 += buf[index++]; s2 += s1;
k -= 16;
}
if (k != 0)
{
do
{
s1 += buf[index++];
s2 += s1;
}
while (--k != 0);
}
s1 %= BASE;
s2 %= BASE;
}
return (uint)((s2 << 16) | s1);
}
#pragma warning restore 3001
#pragma warning restore 3002
}
}

View file

@ -1,627 +0,0 @@
// ZlibBaseStream.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2011-August-06 21:22:38>
//
// ------------------------------------------------------------------
//
// This module defines the ZlibBaseStream class, which is an intnernal
// base class for DeflateStream, ZlibStream and GZipStream.
//
// ------------------------------------------------------------------
using System;
using System.IO;
using System.Runtime.CompilerServices;
namespace Ionic.Zlib
{
internal enum ZlibStreamFlavor { ZLIB = 1950, DEFLATE = 1951, GZIP = 1952 }
internal class ZlibBaseStream : System.IO.Stream
{
protected internal ZlibCodec _z = null; // deferred init... new ZlibCodec();
protected internal StreamMode _streamMode = StreamMode.Undefined;
protected internal FlushType _flushMode;
protected internal ZlibStreamFlavor _flavor;
protected internal CompressionMode _compressionMode;
protected internal CompressionLevel _level;
protected internal bool _leaveOpen;
protected internal byte[] _workingBuffer;
protected internal int _bufferSize = ZlibConstants.WorkingBufferSizeDefault;
protected internal byte[] _buf1 = new byte[1];
protected internal System.IO.Stream _stream;
protected internal CompressionStrategy Strategy = CompressionStrategy.Default;
// workitem 7159
Ionic.Crc.CRC32 crc;
protected internal string _GzipFileName;
protected internal string _GzipComment;
protected internal DateTime _GzipMtime;
protected internal int _gzipHeaderByteCount;
internal int Crc32 { get { if (crc == null) return 0; return crc.Crc32Result; } }
public ZlibBaseStream(System.IO.Stream stream,
CompressionMode compressionMode,
CompressionLevel level,
ZlibStreamFlavor flavor,
bool leaveOpen)
: base()
{
this._flushMode = FlushType.None;
//this._workingBuffer = new byte[WORKING_BUFFER_SIZE_DEFAULT];
this._stream = stream;
this._leaveOpen = leaveOpen;
this._compressionMode = compressionMode;
this._flavor = flavor;
this._level = level;
// workitem 7159
if (flavor == ZlibStreamFlavor.GZIP)
{
this.crc = new Ionic.Crc.CRC32();
}
}
protected internal bool _wantCompress
{
get
{
return (this._compressionMode == CompressionMode.Compress);
}
}
private ZlibCodec z
{
get
{
if (_z == null)
{
bool wantRfc1950Header = (this._flavor == ZlibStreamFlavor.ZLIB);
_z = new ZlibCodec();
if (this._compressionMode == CompressionMode.Decompress)
{
_z.InitializeInflate(wantRfc1950Header);
}
else
{
_z.Strategy = Strategy;
_z.InitializeDeflate(this._level, wantRfc1950Header);
}
}
return _z;
}
}
private byte[] workingBuffer
{
get
{
if (_workingBuffer == null)
_workingBuffer = new byte[_bufferSize];
return _workingBuffer;
}
}
public override void Write(System.Byte[] buffer, int offset, int count)
{
// workitem 7159
// calculate the CRC on the unccompressed data (before writing)
if (crc != null)
crc.SlurpBlock(buffer, offset, count);
if (_streamMode == StreamMode.Undefined)
_streamMode = StreamMode.Writer;
else if (_streamMode != StreamMode.Writer)
throw new ZlibException("Cannot Write after Reading.");
if (count == 0)
return;
// first reference of z property will initialize the private var _z
z.InputBuffer = buffer;
_z.NextIn = offset;
_z.AvailableBytesIn = count;
bool done = false;
do
{
_z.OutputBuffer = workingBuffer;
_z.NextOut = 0;
_z.AvailableBytesOut = _workingBuffer.Length;
int rc = (_wantCompress)
? _z.Deflate(_flushMode)
: _z.Inflate(_flushMode);
if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
throw new ZlibException((_wantCompress ? "de" : "in") + "flating: " + _z.Message);
//if (_workingBuffer.Length - _z.AvailableBytesOut > 0)
_stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut);
done = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0;
// If GZIP and de-compress, we're done when 8 bytes remain.
if (_flavor == ZlibStreamFlavor.GZIP && !_wantCompress)
done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0);
}
while (!done);
}
private void finish()
{
if (_z == null) return;
if (_streamMode == StreamMode.Writer)
{
bool done = false;
do
{
_z.OutputBuffer = workingBuffer;
_z.NextOut = 0;
_z.AvailableBytesOut = _workingBuffer.Length;
int rc = (_wantCompress)
? _z.Deflate(FlushType.Finish)
: _z.Inflate(FlushType.Finish);
if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK)
{
string verb = (_wantCompress ? "de" : "in") + "flating";
if (_z.Message == null)
throw new ZlibException(String.Format("{0}: (rc = {1})", verb, rc));
else
throw new ZlibException(verb + ": " + _z.Message);
}
if (_workingBuffer.Length - _z.AvailableBytesOut > 0)
{
_stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut);
}
done = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0;
// If GZIP and de-compress, we're done when 8 bytes remain.
if (_flavor == ZlibStreamFlavor.GZIP && !_wantCompress)
done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0);
}
while (!done);
Flush();
// workitem 7159
if (_flavor == ZlibStreamFlavor.GZIP)
{
if (_wantCompress)
{
// Emit the GZIP trailer: CRC32 and size mod 2^32
int c1 = crc.Crc32Result;
_stream.Write(BitConverter.GetBytes(c1), 0, 4);
int c2 = (Int32)(crc.TotalBytesRead & 0x00000000FFFFFFFF);
_stream.Write(BitConverter.GetBytes(c2), 0, 4);
}
else
{
throw new ZlibException("Writing with decompression is not supported.");
}
}
}
// workitem 7159
else if (_streamMode == StreamMode.Reader)
{
if (_flavor == ZlibStreamFlavor.GZIP)
{
if (!_wantCompress)
{
// workitem 8501: handle edge case (decompress empty stream)
if (_z.TotalBytesOut == 0L)
return;
// Read and potentially verify the GZIP trailer:
// CRC32 and size mod 2^32
byte[] trailer = new byte[8];
// workitems 8679 & 12554
if (_z.AvailableBytesIn < 8)
{
// Make sure we have read to the end of the stream
Array.Copy(_z.InputBuffer, _z.NextIn, trailer, 0, _z.AvailableBytesIn);
int bytesNeeded = 8 - _z.AvailableBytesIn;
int bytesRead = _stream.Read(trailer,
_z.AvailableBytesIn,
bytesNeeded);
if (bytesNeeded != bytesRead)
{
throw new ZlibException(String.Format("Missing or incomplete GZIP trailer. Expected 8 bytes, got {0}.",
_z.AvailableBytesIn + bytesRead));
}
}
else
{
Array.Copy(_z.InputBuffer, _z.NextIn, trailer, 0, trailer.Length);
}
Int32 crc32_expected = BitConverter.ToInt32(trailer, 0);
Int32 crc32_actual = crc.Crc32Result;
Int32 isize_expected = BitConverter.ToInt32(trailer, 4);
Int32 isize_actual = (Int32)(_z.TotalBytesOut & 0x00000000FFFFFFFF);
if (crc32_actual != crc32_expected)
throw new ZlibException(String.Format("Bad CRC32 in GZIP trailer. (actual({0:X8})!=expected({1:X8}))", crc32_actual, crc32_expected));
if (isize_actual != isize_expected)
throw new ZlibException(String.Format("Bad size in GZIP trailer. (actual({0})!=expected({1}))", isize_actual, isize_expected));
}
else
{
throw new ZlibException("Reading with compression is not supported.");
}
}
}
}
private void end()
{
if (z == null)
return;
if (_wantCompress)
{
_z.EndDeflate();
}
else
{
_z.EndInflate();
}
_z = null;
}
public override void Close()
{
if (_stream == null) return;
try
{
finish();
}
finally
{
end();
if (!_leaveOpen) _stream.Close();
_stream = null;
}
}
public override void Flush()
{
_stream.Flush();
}
public override System.Int64 Seek(System.Int64 offset, System.IO.SeekOrigin origin)
{
throw new NotImplementedException();
//_outStream.Seek(offset, origin);
}
public override void SetLength(System.Int64 value)
{
_stream.SetLength(value);
}
#if NOT
public int Read()
{
if (Read(_buf1, 0, 1) == 0)
return 0;
// calculate CRC after reading
if (crc!=null)
crc.SlurpBlock(_buf1,0,1);
return (_buf1[0] & 0xFF);
}
#endif
private bool nomoreinput = false;
private string ReadZeroTerminatedString()
{
var list = new System.Collections.Generic.List<byte>();
bool done = false;
do
{
// workitem 7740
int n = _stream.Read(_buf1, 0, 1);
if (n != 1)
throw new ZlibException("Unexpected EOF reading GZIP header.");
else
{
if (_buf1[0] == 0)
done = true;
else
list.Add(_buf1[0]);
}
} while (!done);
byte[] a = list.ToArray();
return GZipStream.iso8859dash1.GetString(a, 0, a.Length);
}
private int _ReadAndValidateGzipHeader()
{
int totalBytesRead = 0;
// read the header on the first read
byte[] header = new byte[10];
int n = _stream.Read(header, 0, header.Length);
// workitem 8501: handle edge case (decompress empty stream)
if (n == 0)
return 0;
if (n != 10)
throw new ZlibException("Not a valid GZIP stream.");
if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8)
throw new ZlibException("Bad GZIP header.");
Int32 timet = BitConverter.ToInt32(header, 4);
_GzipMtime = GZipStream._unixEpoch.AddSeconds(timet);
totalBytesRead += n;
if ((header[3] & 0x04) == 0x04)
{
// read and discard extra field
n = _stream.Read(header, 0, 2); // 2-byte length field
totalBytesRead += n;
Int16 extraLength = (Int16)(header[0] + header[1] * 256);
byte[] extra = new byte[extraLength];
n = _stream.Read(extra, 0, extra.Length);
if (n != extraLength)
throw new ZlibException("Unexpected end-of-file reading GZIP header.");
totalBytesRead += n;
}
if ((header[3] & 0x08) == 0x08)
_GzipFileName = ReadZeroTerminatedString();
if ((header[3] & 0x10) == 0x010)
_GzipComment = ReadZeroTerminatedString();
if ((header[3] & 0x02) == 0x02)
Read(_buf1, 0, 1); // CRC16, ignore
return totalBytesRead;
}
public override System.Int32 Read(System.Byte[] buffer, System.Int32 offset, System.Int32 count)
{
// According to MS documentation, any implementation of the IO.Stream.Read function must:
// (a) throw an exception if offset & count reference an invalid part of the buffer,
// or if count < 0, or if buffer is null
// (b) return 0 only upon EOF, or if count = 0
// (c) if not EOF, then return at least 1 byte, up to <count> bytes
if (_streamMode == StreamMode.Undefined)
{
if (!this._stream.CanRead) throw new ZlibException("The stream is not readable.");
// for the first read, set up some controls.
_streamMode = StreamMode.Reader;
// (The first reference to _z goes through the private accessor which
// may initialize it.)
z.AvailableBytesIn = 0;
if (_flavor == ZlibStreamFlavor.GZIP)
{
_gzipHeaderByteCount = _ReadAndValidateGzipHeader();
// workitem 8501: handle edge case (decompress empty stream)
if (_gzipHeaderByteCount == 0)
return 0;
}
}
if (_streamMode != StreamMode.Reader)
throw new ZlibException("Cannot Read after Writing.");
if (count == 0) return 0;
if (nomoreinput && _wantCompress) return 0; // workitem 8557
if (buffer == null) throw new ArgumentNullException("buffer");
if (count < 0) throw new ArgumentOutOfRangeException("count");
if (offset < buffer.GetLowerBound(0)) throw new ArgumentOutOfRangeException("offset");
if ((offset + count) > buffer.GetLength(0)) throw new ArgumentOutOfRangeException("count");
int rc = 0;
// set up the output of the deflate/inflate codec:
_z.OutputBuffer = buffer;
_z.NextOut = offset;
_z.AvailableBytesOut = count;
// This is necessary in case _workingBuffer has been resized. (new byte[])
// (The first reference to _workingBuffer goes through the private accessor which
// may initialize it.)
_z.InputBuffer = workingBuffer;
do
{
// need data in _workingBuffer in order to deflate/inflate. Here, we check if we have any.
if ((_z.AvailableBytesIn == 0) && (!nomoreinput))
{
// No data available, so try to Read data from the captive stream.
_z.NextIn = 0;
_z.AvailableBytesIn = _stream.Read(_workingBuffer, 0, _workingBuffer.Length);
if (_z.AvailableBytesIn == 0)
nomoreinput = true;
}
// we have data in InputBuffer; now compress or decompress as appropriate
rc = (_wantCompress)
? _z.Deflate(_flushMode)
: _z.Inflate(_flushMode);
if (nomoreinput && (rc == ZlibConstants.Z_BUF_ERROR))
return 0;
if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
throw new ZlibException(String.Format("{0}flating: rc={1} msg={2}", (_wantCompress ? "de" : "in"), rc, _z.Message));
if ((nomoreinput || rc == ZlibConstants.Z_STREAM_END) && (_z.AvailableBytesOut == count))
break; // nothing more to read
}
//while (_z.AvailableBytesOut == count && rc == ZlibConstants.Z_OK);
while (_z.AvailableBytesOut > 0 && !nomoreinput && rc == ZlibConstants.Z_OK);
// workitem 8557
// is there more room in output?
if (_z.AvailableBytesOut > 0)
{
if (rc == ZlibConstants.Z_OK && _z.AvailableBytesIn == 0)
{
// deferred
}
// are we completely done reading?
if (nomoreinput)
{
// and in compression?
if (_wantCompress)
{
// no more input data available; therefore we flush to
// try to complete the read
rc = _z.Deflate(FlushType.Finish);
if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
throw new ZlibException(String.Format("Deflating: rc={0} msg={1}", rc, _z.Message));
}
}
}
rc = (count - _z.AvailableBytesOut);
// calculate CRC after reading
if (crc != null)
crc.SlurpBlock(buffer, offset, rc);
return rc;
}
public override System.Boolean CanRead
{
get { return this._stream.CanRead; }
}
public override System.Boolean CanSeek
{
get { return this._stream.CanSeek; }
}
public override System.Boolean CanWrite
{
get { return this._stream.CanWrite; }
}
public override System.Int64 Length
{
get { return _stream.Length; }
}
public override long Position
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
internal enum StreamMode
{
Writer,
Reader,
Undefined,
}
public static void CompressString(String s, Stream compressor)
{
byte[] uncompressed = System.Text.Encoding.UTF8.GetBytes(s);
using (compressor)
{
compressor.Write(uncompressed, 0, uncompressed.Length);
}
}
public static void CompressBuffer(byte[] b, Stream compressor)
{
// workitem 8460
using (compressor)
{
compressor.Write(b, 0, b.Length);
}
}
public static String UncompressString(byte[] compressed, Stream decompressor)
{
// workitem 8460
byte[] working = new byte[1024];
var encoding = System.Text.Encoding.UTF8;
using (var output = new MemoryStream())
{
using (decompressor)
{
int n;
while ((n = decompressor.Read(working, 0, working.Length)) != 0)
{
output.Write(working, 0, n);
}
}
// reset to allow read from start
output.Seek(0, SeekOrigin.Begin);
var sr = new StreamReader(output, encoding);
return sr.ReadToEnd();
}
}
public static byte[] UncompressBuffer(byte[] compressed, Stream decompressor)
{
// workitem 8460
byte[] working = new byte[1024];
using (var output = new MemoryStream())
{
using (decompressor)
{
int n;
while ((n = decompressor.Read(working, 0, working.Length)) != 0)
{
output.Write(working, 0, n);
}
}
return output.ToArray();
}
}
}
}

View file

@ -1,718 +0,0 @@
// ZlibCodec.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2009-November-03 15:40:51>
//
// ------------------------------------------------------------------
//
// This module defines a Codec for ZLIB compression and
// decompression. This code extends code that was based the jzlib
// implementation of zlib, but this code is completely novel. The codec
// class is new, and encapsulates some behaviors that are new, and some
// that were present in other classes in the jzlib code base. In
// keeping with the license for jzlib, the copyright to the jzlib code
// is included below.
//
// ------------------------------------------------------------------
//
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the distribution.
//
// 3. The names of the authors may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------
//
// This program is based on zlib-1.1.3; credit to authors
// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
// and contributors of zlib.
//
// -----------------------------------------------------------------------
using System;
using System.Runtime.CompilerServices;
using Interop=System.Runtime.InteropServices;
namespace Ionic.Zlib
{
/// <summary>
/// Encoder and Decoder for ZLIB and DEFLATE (IETF RFC1950 and RFC1951).
/// </summary>
///
/// <remarks>
/// This class compresses and decompresses data according to the Deflate algorithm
/// and optionally, the ZLIB format, as documented in <see
/// href="http://www.ietf.org/rfc/rfc1950.txt">RFC 1950 - ZLIB</see> and <see
/// href="http://www.ietf.org/rfc/rfc1951.txt">RFC 1951 - DEFLATE</see>.
/// </remarks>
[Interop.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000D")]
[Interop.ComVisible(true)]
#if !NETCF
[Interop.ClassInterface(Interop.ClassInterfaceType.AutoDispatch)]
#endif
sealed public class ZlibCodec
{
/// <summary>
/// The buffer from which data is taken.
/// </summary>
public byte[] InputBuffer;
/// <summary>
/// An index into the InputBuffer array, indicating where to start reading.
/// </summary>
public int NextIn;
/// <summary>
/// The number of bytes available in the InputBuffer, starting at NextIn.
/// </summary>
/// <remarks>
/// Generally you should set this to InputBuffer.Length before the first Inflate() or Deflate() call.
/// The class will update this number as calls to Inflate/Deflate are made.
/// </remarks>
public int AvailableBytesIn;
/// <summary>
/// Total number of bytes read so far, through all calls to Inflate()/Deflate().
/// </summary>
public long TotalBytesIn;
/// <summary>
/// Buffer to store output data.
/// </summary>
public byte[] OutputBuffer;
/// <summary>
/// An index into the OutputBuffer array, indicating where to start writing.
/// </summary>
public int NextOut;
/// <summary>
/// The number of bytes available in the OutputBuffer, starting at NextOut.
/// </summary>
/// <remarks>
/// Generally you should set this to OutputBuffer.Length before the first Inflate() or Deflate() call.
/// The class will update this number as calls to Inflate/Deflate are made.
/// </remarks>
public int AvailableBytesOut;
/// <summary>
/// Total number of bytes written to the output so far, through all calls to Inflate()/Deflate().
/// </summary>
public long TotalBytesOut;
/// <summary>
/// used for diagnostics, when something goes wrong!
/// </summary>
public System.String Message;
internal DeflateManager dstate;
internal InflateManager istate;
internal uint _Adler32;
/// <summary>
/// The compression level to use in this codec. Useful only in compression mode.
/// </summary>
public CompressionLevel CompressLevel = CompressionLevel.Default;
/// <summary>
/// The number of Window Bits to use.
/// </summary>
/// <remarks>
/// This gauges the size of the sliding window, and hence the
/// compression effectiveness as well as memory consumption. It's best to just leave this
/// setting alone if you don't know what it is. The maximum value is 15 bits, which implies
/// a 32k window.
/// </remarks>
public int WindowBits = ZlibConstants.WindowBitsDefault;
/// <summary>
/// The compression strategy to use.
/// </summary>
/// <remarks>
/// This is only effective in compression. The theory offered by ZLIB is that different
/// strategies could potentially produce significant differences in compression behavior
/// for different data sets. Unfortunately I don't have any good recommendations for how
/// to set it differently. When I tested changing the strategy I got minimally different
/// compression performance. It's best to leave this property alone if you don't have a
/// good feel for it. Or, you may want to produce a test harness that runs through the
/// different strategy options and evaluates them on different file types. If you do that,
/// let me know your results.
/// </remarks>
public CompressionStrategy Strategy = CompressionStrategy.Default;
/// <summary>
/// The Adler32 checksum on the data transferred through the codec so far. You probably don't need to look at this.
/// </summary>
public int Adler32 { get { return (int)_Adler32; } }
/// <summary>
/// Create a ZlibCodec.
/// </summary>
/// <remarks>
/// If you use this default constructor, you will later have to explicitly call
/// InitializeInflate() or InitializeDeflate() before using the ZlibCodec to compress
/// or decompress.
/// </remarks>
public ZlibCodec() { }
/// <summary>
/// Create a ZlibCodec that either compresses or decompresses.
/// </summary>
/// <param name="mode">
/// Indicates whether the codec should compress (deflate) or decompress (inflate).
/// </param>
public ZlibCodec(CompressionMode mode)
{
if (mode == CompressionMode.Compress)
{
int rc = InitializeDeflate();
if (rc != ZlibConstants.Z_OK) throw new ZlibException("Cannot initialize for deflate.");
}
else if (mode == CompressionMode.Decompress)
{
int rc = InitializeInflate();
if (rc != ZlibConstants.Z_OK) throw new ZlibException("Cannot initialize for inflate.");
}
else throw new ZlibException("Invalid ZlibStreamFlavor.");
}
/// <summary>
/// Initialize the inflation state.
/// </summary>
/// <remarks>
/// It is not necessary to call this before using the ZlibCodec to inflate data;
/// It is implicitly called when you call the constructor.
/// </remarks>
/// <returns>Z_OK if everything goes well.</returns>
public int InitializeInflate()
{
return InitializeInflate(this.WindowBits);
}
/// <summary>
/// Initialize the inflation state with an explicit flag to
/// govern the handling of RFC1950 header bytes.
/// </summary>
///
/// <remarks>
/// By default, the ZLIB header defined in <see
/// href="http://www.ietf.org/rfc/rfc1950.txt">RFC 1950</see> is expected. If
/// you want to read a zlib stream you should specify true for
/// expectRfc1950Header. If you have a deflate stream, you will want to specify
/// false. It is only necessary to invoke this initializer explicitly if you
/// want to specify false.
/// </remarks>
///
/// <param name="expectRfc1950Header">whether to expect an RFC1950 header byte
/// pair when reading the stream of data to be inflated.</param>
///
/// <returns>Z_OK if everything goes well.</returns>
public int InitializeInflate(bool expectRfc1950Header)
{
return InitializeInflate(this.WindowBits, expectRfc1950Header);
}
/// <summary>
/// Initialize the ZlibCodec for inflation, with the specified number of window bits.
/// </summary>
/// <param name="windowBits">The number of window bits to use. If you need to ask what that is,
/// then you shouldn't be calling this initializer.</param>
/// <returns>Z_OK if all goes well.</returns>
public int InitializeInflate(int windowBits)
{
this.WindowBits = windowBits;
return InitializeInflate(windowBits, true);
}
/// <summary>
/// Initialize the inflation state with an explicit flag to govern the handling of
/// RFC1950 header bytes.
/// </summary>
///
/// <remarks>
/// If you want to read a zlib stream you should specify true for
/// expectRfc1950Header. In this case, the library will expect to find a ZLIB
/// header, as defined in <see href="http://www.ietf.org/rfc/rfc1950.txt">RFC
/// 1950</see>, in the compressed stream. If you will be reading a DEFLATE or
/// GZIP stream, which does not have such a header, you will want to specify
/// false.
/// </remarks>
///
/// <param name="expectRfc1950Header">whether to expect an RFC1950 header byte pair when reading
/// the stream of data to be inflated.</param>
/// <param name="windowBits">The number of window bits to use. If you need to ask what that is,
/// then you shouldn't be calling this initializer.</param>
/// <returns>Z_OK if everything goes well.</returns>
public int InitializeInflate(int windowBits, bool expectRfc1950Header)
{
this.WindowBits = windowBits;
if (dstate != null) throw new ZlibException("You may not call InitializeInflate() after calling InitializeDeflate().");
istate = new InflateManager(expectRfc1950Header);
return istate.Initialize(this, windowBits);
}
/// <summary>
/// Inflate the data in the InputBuffer, placing the result in the OutputBuffer.
/// </summary>
/// <remarks>
/// You must have set InputBuffer and OutputBuffer, NextIn and NextOut, and AvailableBytesIn and
/// AvailableBytesOut before calling this method.
/// </remarks>
/// <example>
/// <code>
/// private void InflateBuffer()
/// {
/// int bufferSize = 1024;
/// byte[] buffer = new byte[bufferSize];
/// ZlibCodec decompressor = new ZlibCodec();
///
/// Console.WriteLine("\n============================================");
/// Console.WriteLine("Size of Buffer to Inflate: {0} bytes.", CompressedBytes.Length);
/// MemoryStream ms = new MemoryStream(DecompressedBytes);
///
/// int rc = decompressor.InitializeInflate();
///
/// decompressor.InputBuffer = CompressedBytes;
/// decompressor.NextIn = 0;
/// decompressor.AvailableBytesIn = CompressedBytes.Length;
///
/// decompressor.OutputBuffer = buffer;
///
/// // pass 1: inflate
/// do
/// {
/// decompressor.NextOut = 0;
/// decompressor.AvailableBytesOut = buffer.Length;
/// rc = decompressor.Inflate(FlushType.None);
///
/// if (rc != ZlibConstants.Z_OK &amp;&amp; rc != ZlibConstants.Z_STREAM_END)
/// throw new Exception("inflating: " + decompressor.Message);
///
/// ms.Write(decompressor.OutputBuffer, 0, buffer.Length - decompressor.AvailableBytesOut);
/// }
/// while (decompressor.AvailableBytesIn &gt; 0 || decompressor.AvailableBytesOut == 0);
///
/// // pass 2: finish and flush
/// do
/// {
/// decompressor.NextOut = 0;
/// decompressor.AvailableBytesOut = buffer.Length;
/// rc = decompressor.Inflate(FlushType.Finish);
///
/// if (rc != ZlibConstants.Z_STREAM_END &amp;&amp; rc != ZlibConstants.Z_OK)
/// throw new Exception("inflating: " + decompressor.Message);
///
/// if (buffer.Length - decompressor.AvailableBytesOut &gt; 0)
/// ms.Write(buffer, 0, buffer.Length - decompressor.AvailableBytesOut);
/// }
/// while (decompressor.AvailableBytesIn &gt; 0 || decompressor.AvailableBytesOut == 0);
///
/// decompressor.EndInflate();
/// }
///
/// </code>
/// </example>
/// <param name="flush">The flush to use when inflating.</param>
/// <returns>Z_OK if everything goes well.</returns>
public int Inflate(FlushType flush)
{
if (istate == null)
throw new ZlibException("No Inflate State!");
return istate.Inflate(flush);
}
/// <summary>
/// Ends an inflation session.
/// </summary>
/// <remarks>
/// Call this after successively calling Inflate(). This will cause all buffers to be flushed.
/// After calling this you cannot call Inflate() without a intervening call to one of the
/// InitializeInflate() overloads.
/// </remarks>
/// <returns>Z_OK if everything goes well.</returns>
public int EndInflate()
{
if (istate == null)
throw new ZlibException("No Inflate State!");
int ret = istate.End();
istate = null;
return ret;
}
/// <summary>
/// I don't know what this does!
/// </summary>
/// <returns>Z_OK if everything goes well.</returns>
public int SyncInflate()
{
if (istate == null)
throw new ZlibException("No Inflate State!");
return istate.Sync();
}
/// <summary>
/// Initialize the ZlibCodec for deflation operation.
/// </summary>
/// <remarks>
/// The codec will use the MAX window bits and the default level of compression.
/// </remarks>
/// <example>
/// <code>
/// int bufferSize = 40000;
/// byte[] CompressedBytes = new byte[bufferSize];
/// byte[] DecompressedBytes = new byte[bufferSize];
///
/// ZlibCodec compressor = new ZlibCodec();
///
/// compressor.InitializeDeflate(CompressionLevel.Default);
///
/// compressor.InputBuffer = System.Text.ASCIIEncoding.ASCII.GetBytes(TextToCompress);
/// compressor.NextIn = 0;
/// compressor.AvailableBytesIn = compressor.InputBuffer.Length;
///
/// compressor.OutputBuffer = CompressedBytes;
/// compressor.NextOut = 0;
/// compressor.AvailableBytesOut = CompressedBytes.Length;
///
/// while (compressor.TotalBytesIn != TextToCompress.Length &amp;&amp; compressor.TotalBytesOut &lt; bufferSize)
/// {
/// compressor.Deflate(FlushType.None);
/// }
///
/// while (true)
/// {
/// int rc= compressor.Deflate(FlushType.Finish);
/// if (rc == ZlibConstants.Z_STREAM_END) break;
/// }
///
/// compressor.EndDeflate();
///
/// </code>
/// </example>
/// <returns>Z_OK if all goes well. You generally don't need to check the return code.</returns>
public int InitializeDeflate()
{
return _InternalInitializeDeflate(true);
}
/// <summary>
/// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel.
/// </summary>
/// <remarks>
/// The codec will use the maximum window bits (15) and the specified
/// CompressionLevel. It will emit a ZLIB stream as it compresses.
/// </remarks>
/// <param name="level">The compression level for the codec.</param>
/// <returns>Z_OK if all goes well.</returns>
public int InitializeDeflate(CompressionLevel level)
{
this.CompressLevel = level;
return _InternalInitializeDeflate(true);
}
/// <summary>
/// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel,
/// and the explicit flag governing whether to emit an RFC1950 header byte pair.
/// </summary>
/// <remarks>
/// The codec will use the maximum window bits (15) and the specified CompressionLevel.
/// If you want to generate a zlib stream, you should specify true for
/// wantRfc1950Header. In this case, the library will emit a ZLIB
/// header, as defined in <see href="http://www.ietf.org/rfc/rfc1950.txt">RFC
/// 1950</see>, in the compressed stream.
/// </remarks>
/// <param name="level">The compression level for the codec.</param>
/// <param name="wantRfc1950Header">whether to emit an initial RFC1950 byte pair in the compressed stream.</param>
/// <returns>Z_OK if all goes well.</returns>
public int InitializeDeflate(CompressionLevel level, bool wantRfc1950Header)
{
this.CompressLevel = level;
return _InternalInitializeDeflate(wantRfc1950Header);
}
/// <summary>
/// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel,
/// and the specified number of window bits.
/// </summary>
/// <remarks>
/// The codec will use the specified number of window bits and the specified CompressionLevel.
/// </remarks>
/// <param name="level">The compression level for the codec.</param>
/// <param name="bits">the number of window bits to use. If you don't know what this means, don't use this method.</param>
/// <returns>Z_OK if all goes well.</returns>
public int InitializeDeflate(CompressionLevel level, int bits)
{
this.CompressLevel = level;
this.WindowBits = bits;
return _InternalInitializeDeflate(true);
}
/// <summary>
/// Initialize the ZlibCodec for deflation operation, using the specified
/// CompressionLevel, the specified number of window bits, and the explicit flag
/// governing whether to emit an RFC1950 header byte pair.
/// </summary>
///
/// <param name="level">The compression level for the codec.</param>
/// <param name="wantRfc1950Header">whether to emit an initial RFC1950 byte pair in the compressed stream.</param>
/// <param name="bits">the number of window bits to use. If you don't know what this means, don't use this method.</param>
/// <returns>Z_OK if all goes well.</returns>
public int InitializeDeflate(CompressionLevel level, int bits, bool wantRfc1950Header)
{
this.CompressLevel = level;
this.WindowBits = bits;
return _InternalInitializeDeflate(wantRfc1950Header);
}
private int _InternalInitializeDeflate(bool wantRfc1950Header)
{
if (istate != null) throw new ZlibException("You may not call InitializeDeflate() after calling InitializeInflate().");
dstate = new DeflateManager();
dstate.WantRfc1950HeaderBytes = wantRfc1950Header;
return dstate.Initialize(this, this.CompressLevel, this.WindowBits, this.Strategy);
}
/// <summary>
/// Deflate one batch of data.
/// </summary>
/// <remarks>
/// You must have set InputBuffer and OutputBuffer before calling this method.
/// </remarks>
/// <example>
/// <code>
/// private void DeflateBuffer(CompressionLevel level)
/// {
/// int bufferSize = 1024;
/// byte[] buffer = new byte[bufferSize];
/// ZlibCodec compressor = new ZlibCodec();
///
/// Console.WriteLine("\n============================================");
/// Console.WriteLine("Size of Buffer to Deflate: {0} bytes.", UncompressedBytes.Length);
/// MemoryStream ms = new MemoryStream();
///
/// int rc = compressor.InitializeDeflate(level);
///
/// compressor.InputBuffer = UncompressedBytes;
/// compressor.NextIn = 0;
/// compressor.AvailableBytesIn = UncompressedBytes.Length;
///
/// compressor.OutputBuffer = buffer;
///
/// // pass 1: deflate
/// do
/// {
/// compressor.NextOut = 0;
/// compressor.AvailableBytesOut = buffer.Length;
/// rc = compressor.Deflate(FlushType.None);
///
/// if (rc != ZlibConstants.Z_OK &amp;&amp; rc != ZlibConstants.Z_STREAM_END)
/// throw new Exception("deflating: " + compressor.Message);
///
/// ms.Write(compressor.OutputBuffer, 0, buffer.Length - compressor.AvailableBytesOut);
/// }
/// while (compressor.AvailableBytesIn &gt; 0 || compressor.AvailableBytesOut == 0);
///
/// // pass 2: finish and flush
/// do
/// {
/// compressor.NextOut = 0;
/// compressor.AvailableBytesOut = buffer.Length;
/// rc = compressor.Deflate(FlushType.Finish);
///
/// if (rc != ZlibConstants.Z_STREAM_END &amp;&amp; rc != ZlibConstants.Z_OK)
/// throw new Exception("deflating: " + compressor.Message);
///
/// if (buffer.Length - compressor.AvailableBytesOut &gt; 0)
/// ms.Write(buffer, 0, buffer.Length - compressor.AvailableBytesOut);
/// }
/// while (compressor.AvailableBytesIn &gt; 0 || compressor.AvailableBytesOut == 0);
///
/// compressor.EndDeflate();
///
/// ms.Seek(0, SeekOrigin.Begin);
/// CompressedBytes = new byte[compressor.TotalBytesOut];
/// ms.Read(CompressedBytes, 0, CompressedBytes.Length);
/// }
/// </code>
/// </example>
/// <param name="flush">whether to flush all data as you deflate. Generally you will want to
/// use Z_NO_FLUSH here, in a series of calls to Deflate(), and then call EndDeflate() to
/// flush everything.
/// </param>
/// <returns>Z_OK if all goes well.</returns>
public int Deflate(FlushType flush)
{
if (dstate == null)
throw new ZlibException("No Deflate State!");
return dstate.Deflate(flush);
}
/// <summary>
/// End a deflation session.
/// </summary>
/// <remarks>
/// Call this after making a series of one or more calls to Deflate(). All buffers are flushed.
/// </remarks>
/// <returns>Z_OK if all goes well.</returns>
public int EndDeflate()
{
if (dstate == null)
throw new ZlibException("No Deflate State!");
//dinoch Tue, 03 Nov 2009 15:39 (test this)
//int ret = dstate.End();
dstate = null;
return ZlibConstants.Z_OK; //ret;
}
/// <summary>
/// Reset a codec for another deflation session.
/// </summary>
/// <remarks>
/// Call this to reset the deflation state. For example if a thread is deflating
/// non-consecutive blocks, you can call Reset() after the Deflate(Sync) of the first
/// block and before the next Deflate(None) of the second block.
/// </remarks>
/// <returns>Z_OK if all goes well.</returns>
public void ResetDeflate()
{
if (dstate == null)
throw new ZlibException("No Deflate State!");
dstate.Reset();
}
/// <summary>
/// Set the CompressionStrategy and CompressionLevel for a deflation session.
/// </summary>
/// <param name="level">the level of compression to use.</param>
/// <param name="strategy">the strategy to use for compression.</param>
/// <returns>Z_OK if all goes well.</returns>
public int SetDeflateParams(CompressionLevel level, CompressionStrategy strategy)
{
if (dstate == null)
throw new ZlibException("No Deflate State!");
return dstate.SetParams(level, strategy);
}
/// <summary>
/// Set the dictionary to be used for either Inflation or Deflation.
/// </summary>
/// <param name="dictionary">The dictionary bytes to use.</param>
/// <returns>Z_OK if all goes well.</returns>
public int SetDictionary(byte[] dictionary)
{
if (istate != null)
return istate.SetDictionary(dictionary);
if (dstate != null)
return dstate.SetDictionary(dictionary);
throw new ZlibException("No Inflate or Deflate state!");
}
// Flush as much pending output as possible. All deflate() output goes
// through this function so some applications may wish to modify it
// to avoid allocating a large strm->next_out buffer and copying into it.
// (See also read_buf()).
internal void flush_pending()
{
int len = dstate.pendingCount;
if (len > AvailableBytesOut)
len = AvailableBytesOut;
if (len == 0)
return;
if (dstate.pending.Length <= dstate.nextPending ||
OutputBuffer.Length <= NextOut ||
dstate.pending.Length < (dstate.nextPending + len) ||
OutputBuffer.Length < (NextOut + len))
{
throw new ZlibException(String.Format("Invalid State. (pending.Length={0}, pendingCount={1})",
dstate.pending.Length, dstate.pendingCount));
}
Array.Copy(dstate.pending, dstate.nextPending, OutputBuffer, NextOut, len);
NextOut += len;
dstate.nextPending += len;
TotalBytesOut += len;
AvailableBytesOut -= len;
dstate.pendingCount -= len;
if (dstate.pendingCount == 0)
{
dstate.nextPending = 0;
}
}
// Read a new buffer from the current input stream, update the adler32
// and total number of bytes read. All deflate() input goes through
// this function so some applications may wish to modify it to avoid
// allocating a large strm->next_in buffer and copying from it.
// (See also flush_pending()).
internal int read_buf(byte[] buf, int start, int size)
{
int len = AvailableBytesIn;
if (len > size)
len = size;
if (len == 0)
return 0;
AvailableBytesIn -= len;
if (dstate.WantRfc1950HeaderBytes)
{
_Adler32 = Adler.Adler32(_Adler32, InputBuffer, NextIn, len);
}
Array.Copy(InputBuffer, NextIn, buf, start, len);
NextIn += len;
TotalBytesIn += len;
return len;
}
}
}

View file

@ -1,127 +0,0 @@
// ZlibConstants.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2009-November-03 18:50:19>
//
// ------------------------------------------------------------------
//
// This module defines constants used by the zlib class library. This
// code is derived from the jzlib implementation of zlib, but
// significantly modified. In keeping with the license for jzlib, the
// copyright to that code is included here.
//
// ------------------------------------------------------------------
//
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the distribution.
//
// 3. The names of the authors may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------
//
// This program is based on zlib-1.1.3; credit to authors
// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
// and contributors of zlib.
//
// -----------------------------------------------------------------------
using System;
namespace Ionic.Zlib
{
/// <summary>
/// A bunch of constants used in the Zlib interface.
/// </summary>
public static class ZlibConstants
{
/// <summary>
/// The maximum number of window bits for the Deflate algorithm.
/// </summary>
public const int WindowBitsMax = 15; // 32K LZ77 window
/// <summary>
/// The default number of window bits for the Deflate algorithm.
/// </summary>
public const int WindowBitsDefault = WindowBitsMax;
/// <summary>
/// indicates everything is A-OK
/// </summary>
public const int Z_OK = 0;
/// <summary>
/// Indicates that the last operation reached the end of the stream.
/// </summary>
public const int Z_STREAM_END = 1;
/// <summary>
/// The operation ended in need of a dictionary.
/// </summary>
public const int Z_NEED_DICT = 2;
/// <summary>
/// There was an error with the stream - not enough data, not open and readable, etc.
/// </summary>
public const int Z_STREAM_ERROR = -2;
/// <summary>
/// There was an error with the data - not enough data, bad data, etc.
/// </summary>
public const int Z_DATA_ERROR = -3;
/// <summary>
/// There was an error with the working buffer.
/// </summary>
public const int Z_BUF_ERROR = -5;
/// <summary>
/// The size of the working buffer used in the ZlibCodec class. Defaults to 8192 bytes.
/// </summary>
#if NETCF
public const int WorkingBufferSizeDefault = 8192;
#else
public const int WorkingBufferSizeDefault = 16384;
#endif
/// <summary>
/// The minimum size of the working buffer used in the ZlibCodec class. Currently it is 128 bytes.
/// </summary>
public const int WorkingBufferSizeMin = 1024;
}
}

View file

@ -1,726 +0,0 @@
// ZlibStream.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2011-July-31 14:53:33>
//
// ------------------------------------------------------------------
//
// This module defines the ZlibStream class, which is similar in idea to
// the System.IO.Compression.DeflateStream and
// System.IO.Compression.GZipStream classes in the .NET BCL.
//
// ------------------------------------------------------------------
using System;
using System.IO;
using System.Runtime.CompilerServices;
namespace Ionic.Zlib
{
/// <summary>
/// Represents a Zlib stream for compression or decompression.
/// </summary>
/// <remarks>
///
/// <para>
/// The ZlibStream is a <see
/// href="http://en.wikipedia.org/wiki/Decorator_pattern">Decorator</see> on a <see
/// cref="System.IO.Stream"/>. It adds ZLIB compression or decompression to any
/// stream.
/// </para>
///
/// <para> Using this stream, applications can compress or decompress data via
/// stream <c>Read()</c> and <c>Write()</c> operations. Either compresssion or
/// decompression can occur through either reading or writing. The compression
/// format used is ZLIB, which is documented in <see
/// href="http://www.ietf.org/rfc/rfc1950.txt">IETF RFC 1950</see>, "ZLIB Compressed
/// Data Format Specification version 3.3". This implementation of ZLIB always uses
/// DEFLATE as the compression method. (see <see
/// href="http://www.ietf.org/rfc/rfc1951.txt">IETF RFC 1951</see>, "DEFLATE
/// Compressed Data Format Specification version 1.3.") </para>
///
/// <para>
/// The ZLIB format allows for varying compression methods, window sizes, and dictionaries.
/// This implementation always uses the DEFLATE compression method, a preset dictionary,
/// and 15 window bits by default.
/// </para>
///
/// <para>
/// This class is similar to <see cref="DeflateStream"/>, except that it adds the
/// RFC1950 header and trailer bytes to a compressed stream when compressing, or expects
/// the RFC1950 header and trailer bytes when decompressing. It is also similar to the
/// <see cref="GZipStream"/>.
/// </para>
/// </remarks>
/// <seealso cref="DeflateStream" />
/// <seealso cref="GZipStream" />
public class ZlibStream : System.IO.Stream
{
internal ZlibBaseStream _baseStream;
bool _disposed;
/// <summary>
/// Create a <c>ZlibStream</c> using the specified <c>CompressionMode</c>.
/// </summary>
/// <remarks>
///
/// <para>
/// When mode is <c>CompressionMode.Compress</c>, the <c>ZlibStream</c>
/// will use the default compression level. The "captive" stream will be
/// closed when the <c>ZlibStream</c> is closed.
/// </para>
///
/// </remarks>
///
/// <example>
/// This example uses a <c>ZlibStream</c> to compress a file, and writes the
/// compressed data to another file.
/// <code>
/// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
/// {
/// using (var raw = System.IO.File.Create(fileToCompress + ".zlib"))
/// {
/// using (Stream compressor = new ZlibStream(raw, CompressionMode.Compress))
/// {
/// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
/// int n;
/// while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
/// {
/// compressor.Write(buffer, 0, n);
/// }
/// }
/// }
/// }
/// </code>
/// <code lang="VB">
/// Using input As Stream = File.OpenRead(fileToCompress)
/// Using raw As FileStream = File.Create(fileToCompress &amp; ".zlib")
/// Using compressor As Stream = New ZlibStream(raw, CompressionMode.Compress)
/// Dim buffer As Byte() = New Byte(4096) {}
/// Dim n As Integer = -1
/// Do While (n &lt;&gt; 0)
/// If (n &gt; 0) Then
/// compressor.Write(buffer, 0, n)
/// End If
/// n = input.Read(buffer, 0, buffer.Length)
/// Loop
/// End Using
/// End Using
/// End Using
/// </code>
/// </example>
///
/// <param name="stream">The stream which will be read or written.</param>
/// <param name="mode">Indicates whether the ZlibStream will compress or decompress.</param>
public ZlibStream(System.IO.Stream stream, CompressionMode mode)
: this(stream, mode, CompressionLevel.Default, false)
{
}
/// <summary>
/// Create a <c>ZlibStream</c> using the specified <c>CompressionMode</c> and
/// the specified <c>CompressionLevel</c>.
/// </summary>
///
/// <remarks>
///
/// <para>
/// When mode is <c>CompressionMode.Decompress</c>, the level parameter is ignored.
/// The "captive" stream will be closed when the <c>ZlibStream</c> is closed.
/// </para>
///
/// </remarks>
///
/// <example>
/// This example uses a <c>ZlibStream</c> to compress data from a file, and writes the
/// compressed data to another file.
///
/// <code>
/// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
/// {
/// using (var raw = System.IO.File.Create(fileToCompress + ".zlib"))
/// {
/// using (Stream compressor = new ZlibStream(raw,
/// CompressionMode.Compress,
/// CompressionLevel.BestCompression))
/// {
/// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
/// int n;
/// while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
/// {
/// compressor.Write(buffer, 0, n);
/// }
/// }
/// }
/// }
/// </code>
///
/// <code lang="VB">
/// Using input As Stream = File.OpenRead(fileToCompress)
/// Using raw As FileStream = File.Create(fileToCompress &amp; ".zlib")
/// Using compressor As Stream = New ZlibStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression)
/// Dim buffer As Byte() = New Byte(4096) {}
/// Dim n As Integer = -1
/// Do While (n &lt;&gt; 0)
/// If (n &gt; 0) Then
/// compressor.Write(buffer, 0, n)
/// End If
/// n = input.Read(buffer, 0, buffer.Length)
/// Loop
/// End Using
/// End Using
/// End Using
/// </code>
/// </example>
///
/// <param name="stream">The stream to be read or written while deflating or inflating.</param>
/// <param name="mode">Indicates whether the ZlibStream will compress or decompress.</param>
/// <param name="level">A tuning knob to trade speed for effectiveness.</param>
public ZlibStream(System.IO.Stream stream, CompressionMode mode, CompressionLevel level)
: this(stream, mode, level, false)
{
}
/// <summary>
/// Create a <c>ZlibStream</c> using the specified <c>CompressionMode</c>, and
/// explicitly specify whether the captive stream should be left open after
/// Deflation or Inflation.
/// </summary>
///
/// <remarks>
///
/// <para>
/// When mode is <c>CompressionMode.Compress</c>, the <c>ZlibStream</c> will use
/// the default compression level.
/// </para>
///
/// <para>
/// This constructor allows the application to request that the captive stream
/// remain open after the deflation or inflation occurs. By default, after
/// <c>Close()</c> is called on the stream, the captive stream is also
/// closed. In some cases this is not desired, for example if the stream is a
/// <see cref="System.IO.MemoryStream"/> that will be re-read after
/// compression. Specify true for the <paramref name="leaveOpen"/> parameter to leave the stream
/// open.
/// </para>
///
/// <para>
/// See the other overloads of this constructor for example code.
/// </para>
///
/// </remarks>
///
/// <param name="stream">The stream which will be read or written. This is called the
/// "captive" stream in other places in this documentation.</param>
/// <param name="mode">Indicates whether the ZlibStream will compress or decompress.</param>
/// <param name="leaveOpen">true if the application would like the stream to remain
/// open after inflation/deflation.</param>
public ZlibStream(System.IO.Stream stream, CompressionMode mode, bool leaveOpen)
: this(stream, mode, CompressionLevel.Default, leaveOpen)
{
}
/// <summary>
/// Create a <c>ZlibStream</c> using the specified <c>CompressionMode</c>
/// and the specified <c>CompressionLevel</c>, and explicitly specify
/// whether the stream should be left open after Deflation or Inflation.
/// </summary>
///
/// <remarks>
///
/// <para>
/// This constructor allows the application to request that the captive
/// stream remain open after the deflation or inflation occurs. By
/// default, after <c>Close()</c> is called on the stream, the captive
/// stream is also closed. In some cases this is not desired, for example
/// if the stream is a <see cref="System.IO.MemoryStream"/> that will be
/// re-read after compression. Specify true for the <paramref
/// name="leaveOpen"/> parameter to leave the stream open.
/// </para>
///
/// <para>
/// When mode is <c>CompressionMode.Decompress</c>, the level parameter is
/// ignored.
/// </para>
///
/// </remarks>
///
/// <example>
///
/// This example shows how to use a ZlibStream to compress the data from a file,
/// and store the result into another file. The filestream remains open to allow
/// additional data to be written to it.
///
/// <code>
/// using (var output = System.IO.File.Create(fileToCompress + ".zlib"))
/// {
/// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
/// {
/// using (Stream compressor = new ZlibStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, true))
/// {
/// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
/// int n;
/// while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
/// {
/// compressor.Write(buffer, 0, n);
/// }
/// }
/// }
/// // can write additional data to the output stream here
/// }
/// </code>
/// <code lang="VB">
/// Using output As FileStream = File.Create(fileToCompress &amp; ".zlib")
/// Using input As Stream = File.OpenRead(fileToCompress)
/// Using compressor As Stream = New ZlibStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, True)
/// Dim buffer As Byte() = New Byte(4096) {}
/// Dim n As Integer = -1
/// Do While (n &lt;&gt; 0)
/// If (n &gt; 0) Then
/// compressor.Write(buffer, 0, n)
/// End If
/// n = input.Read(buffer, 0, buffer.Length)
/// Loop
/// End Using
/// End Using
/// ' can write additional data to the output stream here.
/// End Using
/// </code>
/// </example>
///
/// <param name="stream">The stream which will be read or written.</param>
///
/// <param name="mode">Indicates whether the ZlibStream will compress or decompress.</param>
///
/// <param name="leaveOpen">
/// true if the application would like the stream to remain open after
/// inflation/deflation.
/// </param>
///
/// <param name="level">
/// A tuning knob to trade speed for effectiveness. This parameter is
/// effective only when mode is <c>CompressionMode.Compress</c>.
/// </param>
public ZlibStream(System.IO.Stream stream, CompressionMode mode, CompressionLevel level, bool leaveOpen)
{
_baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.ZLIB, leaveOpen);
}
#region Zlib properties
/// <summary>
/// This property sets the flush behavior on the stream.
/// Sorry, though, not sure exactly how to describe all the various settings.
/// </summary>
virtual public FlushType FlushMode
{
get { return (this._baseStream._flushMode); }
set
{
if (_disposed) throw new ObjectDisposedException("ZlibStream");
this._baseStream._flushMode = value;
}
}
/// <summary>
/// The size of the working buffer for the compression codec.
/// </summary>
///
/// <remarks>
/// <para>
/// The working buffer is used for all stream operations. The default size is
/// 1024 bytes. The minimum size is 128 bytes. You may get better performance
/// with a larger buffer. Then again, you might not. You would have to test
/// it.
/// </para>
///
/// <para>
/// Set this before the first call to <c>Read()</c> or <c>Write()</c> on the
/// stream. If you try to set it afterwards, it will throw.
/// </para>
/// </remarks>
public int BufferSize
{
get
{
return this._baseStream._bufferSize;
}
set
{
if (_disposed) throw new ObjectDisposedException("ZlibStream");
if (this._baseStream._workingBuffer != null)
throw new ZlibException("The working buffer is already set.");
if (value < ZlibConstants.WorkingBufferSizeMin)
throw new ZlibException(String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value, ZlibConstants.WorkingBufferSizeMin));
this._baseStream._bufferSize = value;
}
}
/// <summary> Returns the total number of bytes input so far.</summary>
virtual public long TotalIn
{
get { return this._baseStream._z.TotalBytesIn; }
}
/// <summary> Returns the total number of bytes output so far.</summary>
virtual public long TotalOut
{
get { return this._baseStream._z.TotalBytesOut; }
}
#endregion
#region System.IO.Stream methods
/// <summary>
/// Dispose the stream.
/// </summary>
/// <remarks>
/// <para>
/// This may or may not result in a <c>Close()</c> call on the captive
/// stream. See the constructors that have a <c>leaveOpen</c> parameter
/// for more information.
/// </para>
/// <para>
/// This method may be invoked in two distinct scenarios. If disposing
/// == true, the method has been called directly or indirectly by a
/// user's code, for example via the public Dispose() method. In this
/// case, both managed and unmanaged resources can be referenced and
/// disposed. If disposing == false, the method has been called by the
/// runtime from inside the object finalizer and this method should not
/// reference other objects; in that case only unmanaged resources must
/// be referenced or disposed.
/// </para>
/// </remarks>
/// <param name="disposing">
/// indicates whether the Dispose method was invoked by user code.
/// </param>
protected override void Dispose(bool disposing)
{
try
{
if (!_disposed)
{
if (disposing && (this._baseStream != null))
this._baseStream.Close();
_disposed = true;
}
}
finally
{
base.Dispose(disposing);
}
}
/// <summary>
/// Indicates whether the stream can be read.
/// </summary>
/// <remarks>
/// The return value depends on whether the captive stream supports reading.
/// </remarks>
public override bool CanRead
{
get
{
if (_disposed) throw new ObjectDisposedException("ZlibStream");
return _baseStream._stream.CanRead;
}
}
/// <summary>
/// Indicates whether the stream supports Seek operations.
/// </summary>
/// <remarks>
/// Always returns false.
/// </remarks>
public override bool CanSeek
{
get { return false; }
}
/// <summary>
/// Indicates whether the stream can be written.
/// </summary>
/// <remarks>
/// The return value depends on whether the captive stream supports writing.
/// </remarks>
public override bool CanWrite
{
get
{
if (_disposed) throw new ObjectDisposedException("ZlibStream");
return _baseStream._stream.CanWrite;
}
}
/// <summary>
/// Flush the stream.
/// </summary>
public override void Flush()
{
if (_disposed) throw new ObjectDisposedException("ZlibStream");
_baseStream.Flush();
}
/// <summary>
/// Reading this property always throws a <see cref="NotSupportedException"/>.
/// </summary>
public override long Length
{
get { throw new NotSupportedException(); }
}
/// <summary>
/// The position of the stream pointer.
/// </summary>
///
/// <remarks>
/// Setting this property always throws a <see
/// cref="NotSupportedException"/>. Reading will return the total bytes
/// written out, if used in writing, or the total bytes read in, if used in
/// reading. The count may refer to compressed bytes or uncompressed bytes,
/// depending on how you've used the stream.
/// </remarks>
public override long Position
{
get
{
if (this._baseStream._streamMode == Ionic.Zlib.ZlibBaseStream.StreamMode.Writer)
return this._baseStream._z.TotalBytesOut;
if (this._baseStream._streamMode == Ionic.Zlib.ZlibBaseStream.StreamMode.Reader)
return this._baseStream._z.TotalBytesIn;
return 0;
}
set { throw new NotSupportedException(); }
}
/// <summary>
/// Read data from the stream.
/// </summary>
///
/// <remarks>
///
/// <para>
/// If you wish to use the <c>ZlibStream</c> to compress data while reading,
/// you can create a <c>ZlibStream</c> with <c>CompressionMode.Compress</c>,
/// providing an uncompressed data stream. Then call <c>Read()</c> on that
/// <c>ZlibStream</c>, and the data read will be compressed. If you wish to
/// use the <c>ZlibStream</c> to decompress data while reading, you can create
/// a <c>ZlibStream</c> with <c>CompressionMode.Decompress</c>, providing a
/// readable compressed data stream. Then call <c>Read()</c> on that
/// <c>ZlibStream</c>, and the data will be decompressed as it is read.
/// </para>
///
/// <para>
/// A <c>ZlibStream</c> can be used for <c>Read()</c> or <c>Write()</c>, but
/// not both.
/// </para>
///
/// </remarks>
///
/// <param name="buffer">
/// The buffer into which the read data should be placed.</param>
///
/// <param name="offset">
/// the offset within that data array to put the first byte read.</param>
///
/// <param name="count">the number of bytes to read.</param>
///
/// <returns>the number of bytes read</returns>
public override int Read(byte[] buffer, int offset, int count)
{
if (_disposed) throw new ObjectDisposedException("ZlibStream");
return _baseStream.Read(buffer, offset, count);
}
/// <summary>
/// Calling this method always throws a <see cref="NotSupportedException"/>.
/// </summary>
/// <param name="offset">
/// The offset to seek to....
/// IF THIS METHOD ACTUALLY DID ANYTHING.
/// </param>
/// <param name="origin">
/// The reference specifying how to apply the offset.... IF
/// THIS METHOD ACTUALLY DID ANYTHING.
/// </param>
///
/// <returns>nothing. This method always throws.</returns>
public override long Seek(long offset, System.IO.SeekOrigin origin)
{
throw new NotSupportedException();
}
/// <summary>
/// Calling this method always throws a <see cref="NotSupportedException"/>.
/// </summary>
/// <param name="value">
/// The new value for the stream length.... IF
/// THIS METHOD ACTUALLY DID ANYTHING.
/// </param>
public override void SetLength(long value)
{
throw new NotSupportedException();
}
/// <summary>
/// Write data to the stream.
/// </summary>
///
/// <remarks>
///
/// <para>
/// If you wish to use the <c>ZlibStream</c> to compress data while writing,
/// you can create a <c>ZlibStream</c> with <c>CompressionMode.Compress</c>,
/// and a writable output stream. Then call <c>Write()</c> on that
/// <c>ZlibStream</c>, providing uncompressed data as input. The data sent to
/// the output stream will be the compressed form of the data written. If you
/// wish to use the <c>ZlibStream</c> to decompress data while writing, you
/// can create a <c>ZlibStream</c> with <c>CompressionMode.Decompress</c>, and a
/// writable output stream. Then call <c>Write()</c> on that stream,
/// providing previously compressed data. The data sent to the output stream
/// will be the decompressed form of the data written.
/// </para>
///
/// <para>
/// A <c>ZlibStream</c> can be used for <c>Read()</c> or <c>Write()</c>, but not both.
/// </para>
/// </remarks>
/// <param name="buffer">The buffer holding data to write to the stream.</param>
/// <param name="offset">the offset within that data array to find the first byte to write.</param>
/// <param name="count">the number of bytes to write.</param>
public override void Write(byte[] buffer, int offset, int count)
{
if (_disposed) throw new ObjectDisposedException("ZlibStream");
_baseStream.Write(buffer, offset, count);
}
#endregion
/// <summary>
/// Compress a string into a byte array using ZLIB.
/// </summary>
///
/// <remarks>
/// Uncompress it with <see cref="ZlibStream.UncompressString(byte[])"/>.
/// </remarks>
///
/// <seealso cref="ZlibStream.UncompressString(byte[])"/>
/// <seealso cref="ZlibStream.CompressBuffer(byte[])"/>
/// <seealso cref="GZipStream.CompressString(string)"/>
///
/// <param name="s">
/// A string to compress. The string will first be encoded
/// using UTF8, then compressed.
/// </param>
///
/// <returns>The string in compressed form</returns>
public static byte[] CompressString(String s)
{
using (var ms = new MemoryStream())
{
Stream compressor =
new ZlibStream(ms, CompressionMode.Compress, CompressionLevel.BestCompression);
ZlibBaseStream.CompressString(s, compressor);
return ms.ToArray();
}
}
/// <summary>
/// Compress a byte array into a new byte array using ZLIB.
/// </summary>
///
/// <remarks>
/// Uncompress it with <see cref="ZlibStream.UncompressBuffer(byte[])"/>.
/// </remarks>
///
/// <seealso cref="ZlibStream.CompressString(string)"/>
/// <seealso cref="ZlibStream.UncompressBuffer(byte[])"/>
///
/// <param name="b">
/// A buffer to compress.
/// </param>
///
/// <returns>The data in compressed form</returns>
public static byte[] CompressBuffer(byte[] b)
{
using (var ms = new MemoryStream())
{
Stream compressor =
new ZlibStream( ms, CompressionMode.Compress, CompressionLevel.BestCompression );
ZlibBaseStream.CompressBuffer(b, compressor);
return ms.ToArray();
}
}
/// <summary>
/// Uncompress a ZLIB-compressed byte array into a single string.
/// </summary>
///
/// <seealso cref="ZlibStream.CompressString(String)"/>
/// <seealso cref="ZlibStream.UncompressBuffer(byte[])"/>
///
/// <param name="compressed">
/// A buffer containing ZLIB-compressed data.
/// </param>
///
/// <returns>The uncompressed string</returns>
public static String UncompressString(byte[] compressed)
{
using (var input = new MemoryStream(compressed))
{
Stream decompressor =
new ZlibStream(input, CompressionMode.Decompress);
return ZlibBaseStream.UncompressString(compressed, decompressor);
}
}
/// <summary>
/// Uncompress a ZLIB-compressed byte array into a byte array.
/// </summary>
///
/// <seealso cref="ZlibStream.CompressBuffer(byte[])"/>
/// <seealso cref="ZlibStream.UncompressString(byte[])"/>
///
/// <param name="compressed">
/// A buffer containing ZLIB-compressed data.
/// </param>
///
/// <returns>The data in uncompressed form</returns>
public static byte[] UncompressBuffer(byte[] compressed)
{
using (var input = new MemoryStream(compressed))
{
Stream decompressor =
new ZlibStream( input, CompressionMode.Decompress );
return ZlibBaseStream.UncompressBuffer(compressed, decompressor);
}
}
}
}

View file

@ -1,14 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using MinecraftClient.Mapping;
using MinecraftClient.Crypto;
using MinecraftClient.Inventory;
using MinecraftClient.Mapping.EntityPalettes;
using MinecraftClient.Inventory.ItemPalettes;
using System.Runtime.CompilerServices;
using System.Text;
using MinecraftClient.Inventory;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Mapping;
using MinecraftClient.Mapping.EntityPalettes;
namespace MinecraftClient.Protocol.Handlers
{
@ -20,7 +17,7 @@ namespace MinecraftClient.Protocol.Handlers
/// <summary>
/// Protocol version for adjusting data types
/// </summary>
private int protocolversion;
private readonly int protocolversion;
/// <summary>
/// Initialize a new DataTypes instance
@ -28,7 +25,7 @@ namespace MinecraftClient.Protocol.Handlers
/// <param name="protocol">Protocol version</param>
public DataTypes(int protocol)
{
this.protocolversion = protocol;
protocolversion = protocol;
}
/// <summary>
@ -223,7 +220,7 @@ namespace MinecraftClient.Protocol.Handlers
Span<byte> javaUUID = stackalloc byte[16];
for (int i = 0; i < 16; ++i)
javaUUID[i] = cache.Dequeue();
Guid guid = new Guid(javaUUID);
Guid guid = new(javaUUID);
if (BitConverter.IsLittleEndian)
guid = guid.ToLittleEndian();
return guid;
@ -402,9 +399,8 @@ namespace MinecraftClient.Protocol.Handlers
/// Read a single item slot from a cache of bytes and remove it from the cache
/// </summary>
/// <returns>The item that was read or NULL for an empty slot</returns>
public Item ReadNextItemSlot(Queue<byte> cache, ItemPalette itemPalette)
public Item? ReadNextItemSlot(Queue<byte> cache, ItemPalette itemPalette)
{
List<byte> slotData = new List<byte>();
if (protocolversion > Protocol18Handler.MC_1_13_Version)
{
// MC 1.13 and greater
@ -440,21 +436,15 @@ namespace MinecraftClient.Protocol.Handlers
public Entity ReadNextEntity(Queue<byte> cache, EntityPalette entityPalette, bool living)
{
int entityID = ReadNextVarInt(cache);
Guid entityUUID = Guid.Empty;
if (protocolversion > Protocol18Handler.MC_1_8_Version)
{
entityUUID = ReadNextUUID(cache);
}
ReadNextUUID(cache);
EntityType entityType;
// Entity type data type change from byte to varint after 1.14
if (protocolversion > Protocol18Handler.MC_1_13_Version)
{
entityType = entityPalette.FromId(ReadNextVarInt(cache), living);
}
else
{
entityType = entityPalette.FromId(ReadNextByte(cache), living);
}
Double entityX = ReadNextDouble(cache);
Double entityY = ReadNextDouble(cache);
@ -493,7 +483,7 @@ namespace MinecraftClient.Protocol.Handlers
/// </summary>
private Dictionary<string, object> ReadNextNbt(Queue<byte> cache, bool root)
{
Dictionary<string, object> nbtData = new Dictionary<string, object>();
Dictionary<string, object> nbtData = new();
if (root)
{
@ -736,9 +726,9 @@ namespace MinecraftClient.Protocol.Handlers
/// <returns>The item that was read or NULL for an empty slot</returns>
public VillagerTrade ReadNextTrade(Queue<byte> cache, ItemPalette itemPalette)
{
Item inputItem1 = ReadNextItemSlot(cache, itemPalette);
Item outputItem = ReadNextItemSlot(cache, itemPalette);
Item inputItem2 = null;
Item inputItem1 = ReadNextItemSlot(cache, itemPalette)!;
Item outputItem = ReadNextItemSlot(cache, itemPalette)!;
Item? inputItem2 = null;
if (ReadNextBool(cache)) //check if villager has second item
{
inputItem2 = ReadNextItemSlot(cache, itemPalette);
@ -774,20 +764,19 @@ namespace MinecraftClient.Protocol.Handlers
if (nbt == null || nbt.Count == 0)
return new byte[] { 0 }; // TAG_End
List<byte> bytes = new List<byte>();
List<byte> bytes = new();
if (root)
{
bytes.Add(10); // TAG_Compound
// NBT root name
string rootName = null;
string? rootName = null;
if (nbt.ContainsKey(""))
rootName = nbt[""] as string;
if (rootName == null)
rootName = "";
rootName ??= "";
bytes.AddRange(GetUShort((ushort)rootName.Length));
bytes.AddRange(Encoding.ASCII.GetBytes(rootName));
@ -799,10 +788,9 @@ namespace MinecraftClient.Protocol.Handlers
if (item.Key == "" && root)
continue;
byte fieldType;
byte[] fieldNameLength = GetUShort((ushort)item.Key.Length);
byte[] fieldName = Encoding.ASCII.GetBytes(item.Key);
byte[] fieldData = GetNbtField(item.Value, out fieldType);
byte[] fieldData = GetNbtField(item.Value, out byte fieldType);
bytes.Add(fieldType);
bytes.AddRange(fieldNameLength);
bytes.AddRange(fieldName);
@ -866,7 +854,7 @@ namespace MinecraftClient.Protocol.Handlers
{
fieldType = 9; // TAG_List
List<object> list = new List<object>((object[])obj);
List<object> list = new((object[])obj);
int arrayLengthTotal = list.Count;
// Treat empty list as TAG_Byte, length 0
@ -874,17 +862,15 @@ namespace MinecraftClient.Protocol.Handlers
return ConcatBytes(new[] { (byte)1 }, GetInt(0));
// Encode first list item, retain its type
byte firstItemType;
string firstItemTypeString = list[0].GetType().Name;
byte[] firstItemBytes = GetNbtField(list[0], out firstItemType);
byte[] firstItemBytes = GetNbtField(list[0], out byte firstItemType);
list.RemoveAt(0);
// Encode further list items, check they have the same type
byte subsequentItemType;
List<byte> subsequentItemsBytes = new List<byte>();
List<byte> subsequentItemsBytes = new();
foreach (object item in list)
{
subsequentItemsBytes.AddRange(GetNbtField(item, out subsequentItemType));
subsequentItemsBytes.AddRange(GetNbtField(item, out byte subsequentItemType));
if (subsequentItemType != firstItemType)
throw new System.IO.InvalidDataException(
"GetNbt: Cannot encode object[] list with mixed types: " + firstItemTypeString + ", " + item.GetType().Name + " into NBT!");
@ -903,7 +889,7 @@ namespace MinecraftClient.Protocol.Handlers
fieldType = 11; // TAG_Int_Array
int[] srcIntList = (int[])obj;
List<byte> encIntList = new List<byte>();
List<byte> encIntList = new();
encIntList.AddRange(GetInt(srcIntList.Length));
foreach (int item in srcIntList)
encIntList.AddRange(GetInt(item));
@ -914,7 +900,7 @@ namespace MinecraftClient.Protocol.Handlers
fieldType = 12; // TAG_Long_Array
long[] srcLongList = (long[])obj;
List<byte> encLongList = new List<byte>();
List<byte> encLongList = new();
encLongList.AddRange(GetInt(srcLongList.Length));
foreach (long item in srcLongList)
encLongList.AddRange(GetLong(item));
@ -933,7 +919,7 @@ namespace MinecraftClient.Protocol.Handlers
/// <returns>Byte array for this integer</returns>
public byte[] GetVarInt(int paramInt)
{
List<byte> bytes = new List<byte>();
List<byte> bytes = new();
while ((paramInt & -128) != 0)
{
bytes.Add((byte)(paramInt & 127 | 128));
@ -950,8 +936,10 @@ namespace MinecraftClient.Protocol.Handlers
/// <returns>Byte array for this boolean</returns>
public byte[] GetBool(bool paramBool)
{
List<byte> bytes = new List<byte>();
bytes.Add((byte)Convert.ToByte(paramBool));
List<byte> bytes = new()
{
(byte)Convert.ToByte(paramBool)
};
return bytes.ToArray();
}
@ -1138,16 +1126,16 @@ namespace MinecraftClient.Protocol.Handlers
/// <returns>Block face byte enum</returns>
public byte GetBlockFace(Direction direction)
{
switch (direction)
return direction switch
{
case Direction.Down: return 0;
case Direction.Up: return 1;
case Direction.North: return 2;
case Direction.South: return 3;
case Direction.West: return 4;
case Direction.East: return 5;
default: throw new NotImplementedException("Unknown direction: " + direction.ToString());
}
Direction.Down => 0,
Direction.Up => 1,
Direction.North => 2,
Direction.South => 3,
Direction.West => 4,
Direction.East => 5,
_ => throw new NotImplementedException("Unknown direction: " + direction.ToString()),
};
}
/// <summary>
@ -1167,7 +1155,7 @@ namespace MinecraftClient.Protocol.Handlers
/// <returns>Array containing all the data</returns>
public byte[] ConcatBytes(params byte[][] bytes)
{
List<byte> result = new List<byte>();
List<byte> result = new();
foreach (byte[] array in bytes)
result.AddRange(array);
return result.ToArray();

View file

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Protocol.Handlers.Forge
namespace MinecraftClient.Protocol.Handlers.Forge
{
/// <summary>
/// Copy of the forge enum for client states.

View file

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Protocol.Handlers.Forge
namespace MinecraftClient.Protocol.Handlers.Forge
{
/// <summary>
/// Different "discriminator byte" values for the forge handshake.

View file

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Protocol.Handlers.Forge
namespace MinecraftClient.Protocol.Handlers.Forge
{
/// <summary>
/// Version of the FML protocol

View file

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Protocol.Handlers.Forge
{
@ -42,9 +40,11 @@ namespace MinecraftClient.Protocol.Handlers.Forge
switch (fmlVersion)
{
case FMLVersion.FML2:
this.Mods = new List<ForgeMod>();
this.Mods.Add(new ForgeMod("forge", "ANY"));
this.Version = fmlVersion;
Mods = new List<ForgeMod>
{
new ForgeMod("forge", "ANY")
};
Version = fmlVersion;
break;
default:
throw new InvalidOperationException(Translations.Get("error.forgeforce"));
@ -58,8 +58,8 @@ namespace MinecraftClient.Protocol.Handlers.Forge
/// <param name="fmlVersion">Forge protocol version</param>
internal ForgeInfo(Json.JSONData data, FMLVersion fmlVersion)
{
this.Mods = new List<ForgeMod>();
this.Version = fmlVersion;
Mods = new List<ForgeMod>();
Version = fmlVersion;
switch (fmlVersion)
{
@ -89,7 +89,7 @@ namespace MinecraftClient.Protocol.Handlers.Forge
String modid = mod.Properties["modid"].StringValue;
String modversion = mod.Properties["version"].StringValue;
this.Mods.Add(new ForgeMod(modid, modversion));
Mods.Add(new ForgeMod(modid, modversion));
}
break;
@ -129,7 +129,7 @@ namespace MinecraftClient.Protocol.Handlers.Forge
String modid = mod.Properties["modId"].StringValue;
String modmarker = mod.Properties["modmarker"].StringValue;
this.Mods.Add(new ForgeMod(modid, modmarker));
Mods.Add(new ForgeMod(modid, modmarker));
}
break;

View file

@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{
public class PacketPalette110 : PacketTypePalette
{
private Dictionary<int, PacketTypesIn> typeIn = new Dictionary<int, PacketTypesIn>()
private readonly Dictionary<int, PacketTypesIn> typeIn = new()
{
{ 0x00, PacketTypesIn.SpawnEntity },
{ 0x01, PacketTypesIn.SpawnExperienceOrb },
@ -87,7 +84,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x4B, PacketTypesIn.EntityEffect },
};
private Dictionary<int, PacketTypesOut> typeOut = new Dictionary<int, PacketTypesOut>()
private readonly Dictionary<int, PacketTypesOut> typeOut = new()
{
{ 0x00, PacketTypesOut.TeleportConfirm },
{ 0x01, PacketTypesOut.TabComplete },

View file

@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{
public class PacketPalette112 : PacketTypePalette
{
private Dictionary<int, PacketTypesIn> typeIn = new Dictionary<int, PacketTypesIn>()
private readonly Dictionary<int, PacketTypesIn> typeIn = new()
{
{ 0x00, PacketTypesIn.SpawnEntity },
{ 0x01, PacketTypesIn.SpawnExperienceOrb },
@ -90,7 +87,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x4E, PacketTypesIn.EntityEffect },
};
private Dictionary<int, PacketTypesOut> typeOut = new Dictionary<int, PacketTypesOut>()
private readonly Dictionary<int, PacketTypesOut> typeOut = new()
{
{ 0x00, PacketTypesOut.TeleportConfirm },
{ 0x01, PacketTypesOut.Unknown },

View file

@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{
public class PacketPalette1122 : PacketTypePalette
{
private Dictionary<int, PacketTypesIn> typeIn = new Dictionary<int, PacketTypesIn>()
private readonly Dictionary<int, PacketTypesIn> typeIn = new()
{
{ 0x00, PacketTypesIn.SpawnEntity },
{ 0x01, PacketTypesIn.SpawnExperienceOrb },
@ -91,7 +88,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x4F, PacketTypesIn.EntityEffect },
};
private Dictionary<int, PacketTypesOut> typeOut = new Dictionary<int, PacketTypesOut>()
private readonly Dictionary<int, PacketTypesOut> typeOut = new()
{
{ 0x00, PacketTypesOut.TeleportConfirm },
{ 0x01, PacketTypesOut.TabComplete },

View file

@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{
public class PacketPalette113 : PacketTypePalette
{
private Dictionary<int, PacketTypesIn> typeIn = new Dictionary<int, PacketTypesIn>()
private readonly Dictionary<int, PacketTypesIn> typeIn = new()
{
{ 0x00, PacketTypesIn.SpawnEntity },
{ 0x01, PacketTypesIn.SpawnExperienceOrb },
@ -97,7 +94,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x55, PacketTypesIn.Tags },
};
private Dictionary<int, PacketTypesOut> typeOut = new Dictionary<int, PacketTypesOut>()
private readonly Dictionary<int, PacketTypesOut> typeOut = new()
{
{ 0x00, PacketTypesOut.TeleportConfirm },
{ 0x01, PacketTypesOut.QueryBlockNBT },

View file

@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{
public class PacketPalette114 : PacketTypePalette
{
private Dictionary<int, PacketTypesIn> typeIn = new Dictionary<int, PacketTypesIn>()
private readonly Dictionary<int, PacketTypesIn> typeIn = new()
{
{ 0x00, PacketTypesIn.SpawnEntity },
{ 0x01, PacketTypesIn.SpawnExperienceOrb },
@ -104,7 +101,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x5C, PacketTypesIn.AcknowledgePlayerDigging },
};
private Dictionary<int, PacketTypesOut> typeOut = new Dictionary<int, PacketTypesOut>()
private readonly Dictionary<int, PacketTypesOut> typeOut = new()
{
{ 0x00, PacketTypesOut.TeleportConfirm },
{ 0x01, PacketTypesOut.QueryBlockNBT },

View file

@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{
public class PacketPalette115 : PacketTypePalette
{
private Dictionary<int, PacketTypesIn> typeIn = new Dictionary<int, PacketTypesIn>()
private readonly Dictionary<int, PacketTypesIn> typeIn = new()
{
{ 0x00, PacketTypesIn.SpawnEntity },
{ 0x01, PacketTypesIn.SpawnExperienceOrb },
@ -104,7 +101,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x5C, PacketTypesIn.Tags },
};
private Dictionary<int, PacketTypesOut> typeOut = new Dictionary<int, PacketTypesOut>()
private readonly Dictionary<int, PacketTypesOut> typeOut = new()
{
{ 0x00, PacketTypesOut.TeleportConfirm },
{ 0x01, PacketTypesOut.QueryBlockNBT },

View file

@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{
public class PacketPalette116 : PacketTypePalette
{
private Dictionary<int, PacketTypesIn> typeIn = new Dictionary<int, PacketTypesIn>()
private readonly Dictionary<int, PacketTypesIn> typeIn = new()
{
{ 0x00, PacketTypesIn.SpawnEntity },
{ 0x01, PacketTypesIn.SpawnExperienceOrb },
@ -103,7 +100,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x5B, PacketTypesIn.Tags },
};
private Dictionary<int, PacketTypesOut> typeOut = new Dictionary<int, PacketTypesOut>()
private readonly Dictionary<int, PacketTypesOut> typeOut = new()
{
{ 0x00, PacketTypesOut.TeleportConfirm },
{ 0x01, PacketTypesOut.QueryBlockNBT },

View file

@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{
public class PacketPalette1162 : PacketTypePalette
{
private Dictionary<int, PacketTypesIn> typeIn = new Dictionary<int, PacketTypesIn>()
private readonly Dictionary<int, PacketTypesIn> typeIn = new()
{
{ 0x00, PacketTypesIn.SpawnEntity },
{ 0x01, PacketTypesIn.SpawnExperienceOrb },
@ -103,7 +100,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x5B, PacketTypesIn.Tags },
};
private Dictionary<int, PacketTypesOut> typeOut = new Dictionary<int, PacketTypesOut>()
private readonly Dictionary<int, PacketTypesOut> typeOut = new()
{
{ 0x00, PacketTypesOut.TeleportConfirm },
{ 0x01, PacketTypesOut.QueryBlockNBT },

View file

@ -4,7 +4,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{
public class PacketPalette117 : PacketTypePalette
{
private Dictionary<int, PacketTypesIn> typeIn = new Dictionary<int, PacketTypesIn>()
private readonly Dictionary<int, PacketTypesIn> typeIn = new()
{
{ 0x00, PacketTypesIn.SpawnEntity },
{ 0x01, PacketTypesIn.SpawnExperienceOrb },
@ -111,7 +111,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x66, PacketTypesIn.Tags },
};
private Dictionary<int, PacketTypesOut> typeOut = new Dictionary<int, PacketTypesOut>()
private readonly Dictionary<int, PacketTypesOut> typeOut = new()
{
{ 0x00, PacketTypesOut.TeleportConfirm },
{ 0x01, PacketTypesOut.QueryBlockNBT },

View file

@ -4,7 +4,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{
public class PacketPalette118 : PacketTypePalette
{
private Dictionary<int, PacketTypesIn> typeIn = new Dictionary<int, PacketTypesIn>()
private readonly Dictionary<int, PacketTypesIn> typeIn = new()
{
{ 0x00, PacketTypesIn.SpawnEntity },
{ 0x01, PacketTypesIn.SpawnExperienceOrb },
@ -112,7 +112,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x67, PacketTypesIn.Tags },
};
private Dictionary<int, PacketTypesOut> typeOut = new Dictionary<int, PacketTypesOut>()
private readonly Dictionary<int, PacketTypesOut> typeOut = new()
{
{ 0x00, PacketTypesOut.TeleportConfirm },
{ 0x01, PacketTypesOut.QueryBlockNBT },

View file

@ -4,7 +4,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{
public class PacketPalette119 : PacketTypePalette
{
private Dictionary<int, PacketTypesIn> typeIn = new Dictionary<int, PacketTypesIn>()
private readonly Dictionary<int, PacketTypesIn> typeIn = new()
{
{ 0x00, PacketTypesIn.SpawnEntity }, // Changed in 1.19 (Wiki name: Spawn Entity) - DONE
{ 0x01, PacketTypesIn.SpawnExperienceOrb }, // (Wiki name: Spawn Exeprience Orb)
@ -113,7 +113,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x68, PacketTypesIn.Tags }, // (Wiki name: Update Tags)
};
private Dictionary<int, PacketTypesOut> typeOut = new Dictionary<int, PacketTypesOut>()
private readonly Dictionary<int, PacketTypesOut> typeOut = new()
{
{ 0x00, PacketTypesOut.TeleportConfirm }, // (Wiki name: Confirm Teleportation)
{ 0x01, PacketTypesOut.QueryBlockNBT }, // (Wiki name: Query Block Entity Tag)

View file

@ -4,7 +4,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{
public class PacketPalette1192 : PacketTypePalette
{
private Dictionary<int, PacketTypesIn> typeIn = new Dictionary<int, PacketTypesIn>()
private readonly Dictionary<int, PacketTypesIn> typeIn = new()
{
{ 0x00, PacketTypesIn.SpawnEntity }, // Changed in 1.19 (Wiki name: Spawn Entity) - DONE
{ 0x01, PacketTypesIn.SpawnExperienceOrb }, // (Wiki name: Spawn Exeprience Orb)
@ -116,7 +116,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x6B, PacketTypesIn.Tags }, // (Wiki name: Update Tags)
};
private Dictionary<int, PacketTypesOut> typeOut = new Dictionary<int, PacketTypesOut>()
private readonly Dictionary<int, PacketTypesOut> typeOut = new()
{
{ 0x00, PacketTypesOut.TeleportConfirm }, // (Wiki name: Confirm Teleportation)
{ 0x01, PacketTypesOut.QueryBlockNBT }, // (Wiki name: Query Block Entity Tag)

View file

@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{
public class PacketPalette17 : PacketTypePalette
{
private Dictionary<int, PacketTypesIn> typeIn = new Dictionary<int, PacketTypesIn>()
private readonly Dictionary<int, PacketTypesIn> typeIn = new()
{
{ 0x00, PacketTypesIn.KeepAlive },
{ 0x01, PacketTypesIn.JoinGame },
@ -85,7 +82,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x49, PacketTypesIn.UpdateEntityNBT },
};
private Dictionary<int, PacketTypesOut> typeOut = new Dictionary<int, PacketTypesOut>()
private readonly Dictionary<int, PacketTypesOut> typeOut = new()
{
{ 0x00, PacketTypesOut.KeepAlive },
{ 0x01, PacketTypesOut.ChatMessage },

View file

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Generic;
using System.IO;
namespace MinecraftClient.Protocol.Handlers.PacketPalettes
@ -33,10 +30,12 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
public static void UpdatePacketIdByItemPosition(PacketTypePalette palette, string outputFile)
{
// I am just too tired to create another full .cs file so... please just copy and paste
List<string> lines = new List<string>();
lines.Add("=== Inbound Packets ===");
List<string> lines = new()
{
"=== Inbound Packets ==="
};
int i = 0;
foreach(var t in palette.GetMappingIn())
foreach (var t in palette.GetMappingIn())
{
lines.Add(string.Format("{{ 0x{0}, {1} }},", i.ToString("X2"), t.Value));
i++;
@ -78,8 +77,10 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
public static void UpdatePacketPositionToAscending(PacketTypePalette palette, string outputFile)
{
// I am just too tired to create another full .cs file so... please just copy and paste
List<string> lines = new List<string>();
lines.Add("=== Inbound Packets ===");
List<string> lines = new()
{
"=== Inbound Packets ==="
};
for (int i = 0; i < palette.GetMappingIn().Count; i++)
{
lines.Add(string.Format("{{ 0x{0}, {1} }},", i.ToString("X2"), palette.GetMappingIn()[i]));
@ -119,25 +120,24 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
const string TAB = " ";
const string TAB2 = " ";
const string TAB3 = " ";
List<string> lines = new List<string>();
lines.Add("using System;");
lines.Add("using System.Collections.Generic;");
lines.Add("using System.Linq;");
lines.Add("using System.Text;");
lines.Add("");
lines.Add("namespace " + namespaceToUse);
lines.Add("{");
lines.Add(TAB + "public class " + className + " : PacketTypePalette");
lines.Add(TAB + "{");
lines.Add(TAB2 + "private Dictionary<int, PacketTypesIn> typeIn = new Dictionary<int, PacketTypesIn>()");
lines.Add(TAB2 + "{");
List<string> lines = new()
{
"using System.Collections.Generic;",
"",
"namespace " + namespaceToUse,
"{",
TAB + "public class " + className + " : PacketTypePalette",
TAB + "{",
TAB2 + "private readonly Dictionary<int, PacketTypesIn> typeIn = new()",
TAB2 + "{"
};
for (int i = 0; i < pIn.Count; i++)
{
lines.Add(TAB3 + string.Format("{{ 0x{0}, PacketTypesIn.{1} }},", i.ToString("X2"), pIn[i]));
}
lines.Add(TAB2 + "};");
lines.Add("");
lines.Add(TAB2 + "private Dictionary<int, PacketTypesOut> typeOut = new Dictionary<int, PacketTypesOut>()");
lines.Add(TAB2 + "private readonly Dictionary<int, PacketTypesOut> typeOut = new()");
lines.Add(TAB2 + "{");
for (int i = 0; i < pOut.Count; i++)
{

View file

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Collections.Generic;
namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{
@ -34,9 +30,9 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
protected abstract Dictionary<int, PacketTypesIn> GetListIn();
protected abstract Dictionary<int, PacketTypesOut> GetListOut();
private Dictionary<PacketTypesIn, int> reverseMappingIn = new Dictionary<PacketTypesIn, int>();
private readonly Dictionary<PacketTypesIn, int> reverseMappingIn = new();
private Dictionary<PacketTypesOut, int> reverseMappingOut = new Dictionary<PacketTypesOut, int>();
private readonly Dictionary<PacketTypesOut, int> reverseMappingOut = new();
private bool forgeEnabled = false;
@ -59,8 +55,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
/// <returns>Packet type</returns>
public PacketTypesIn GetIncommingTypeById(int packetId)
{
PacketTypesIn p;
if (GetListIn().TryGetValue(packetId, out p))
if (GetListIn().TryGetValue(packetId, out PacketTypesIn p))
{
return p;
}
@ -91,8 +86,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
/// <returns>Packet type</returns>
public PacketTypesOut GetOutgoingTypeById(int packetId)
{
PacketTypesOut p;
if (GetListOut().TryGetValue(packetId, out p))
if (GetListOut().TryGetValue(packetId, out PacketTypesOut p))
{
return p;
}
@ -130,7 +124,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
/// Public method for getting the type mapping
/// </summary>
/// <returns>PacketTypesOut with packet ID as index</returns>
public Dictionary<int ,PacketTypesOut> GetMappingOut()
public Dictionary<int, PacketTypesOut> GetMappingOut()
{
return GetListOut();
}
@ -146,7 +140,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
/// <param name="enabled"></param>
public void SetForgeEnabled(bool enabled)
{
this.forgeEnabled = enabled;
forgeEnabled = enabled;
}
}
}

View file

@ -1,16 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MinecraftClient.Protocol.Handlers;
using MinecraftClient.Protocol.Handlers.PacketPalettes;
namespace MinecraftClient.Protocol.Handlers
{
public class PacketTypeHandler
{
private int protocol;
private bool forgeEnabled = false;
private readonly int protocol;
private readonly bool forgeEnabled = false;
/// <summary>
/// Initialize the handler
@ -41,7 +37,7 @@ namespace MinecraftClient.Protocol.Handlers
/// <returns></returns>
public PacketTypePalette GetTypeHandler()
{
return GetTypeHandler(this.protocol);
return GetTypeHandler(protocol);
}
/// <summary>
/// Get the packet type palette
@ -81,7 +77,7 @@ namespace MinecraftClient.Protocol.Handlers
else
p = new PacketPalette1192();
p.SetForgeEnabled(this.forgeEnabled);
p.SetForgeEnabled(forgeEnabled);
return p;
}
}

View file

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Protocol.Handlers
namespace MinecraftClient.Protocol.Handlers
{
/// <summary>
/// Incomming packet types

View file

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Protocol.Handlers
namespace MinecraftClient.Protocol.Handlers
{
/// <summary>
/// Outgoing packet types

View file

@ -1,17 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using MinecraftClient.Crypto;
using MinecraftClient.Proxy;
using System.Security.Cryptography;
using MinecraftClient.Mapping;
using MinecraftClient.Inventory;
using MinecraftClient.Mapping;
using MinecraftClient.Protocol.Keys;
using MinecraftClient.Protocol.Session;
using MinecraftClient.Protocol.Message;
using MinecraftClient.Protocol.Session;
using MinecraftClient.Proxy;
namespace MinecraftClient.Protocol.Handlers
{
@ -21,23 +21,23 @@ namespace MinecraftClient.Protocol.Handlers
class Protocol16Handler : IMinecraftCom
{
IMinecraftComHandler handler;
readonly IMinecraftComHandler handler;
private bool autocomplete_received = false;
private string autocomplete_result = "";
private bool encrypted = false;
private int protocolversion;
private readonly int protocolversion;
private Tuple<Thread, CancellationTokenSource>? netRead = null;
Crypto.AesCfb8Stream s;
TcpClient c;
Crypto.AesCfb8Stream? s;
readonly TcpClient c;
public Protocol16Handler(TcpClient Client, int ProtocolVersion, IMinecraftComHandler Handler)
{
ConsoleIO.SetAutoCompleteEngine(this);
if (protocolversion >= 72)
ChatParser.InitTranslations();
this.c = Client;
this.protocolversion = ProtocolVersion;
this.handler = Handler;
c = Client;
protocolversion = ProtocolVersion;
handler = Handler;
if (Handler.GetTerrainEnabled())
{
@ -58,9 +58,12 @@ namespace MinecraftClient.Protocol.Handlers
}
}
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
// "IMinecraftComHandler handler" will not be used here.
private Protocol16Handler(TcpClient Client)
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
{
this.c = Client;
c = Client;
}
private void Updater(object? o)
@ -94,15 +97,15 @@ namespace MinecraftClient.Protocol.Handlers
bool connection_ok = true;
while (c.Client.Available > 0 && connection_ok)
{
byte id = readNextByte();
connection_ok = processPacket(id);
byte id = ReadNextByte();
connection_ok = ProcessPacket(id);
}
return connection_ok;
}
private bool processPacket(byte id)
private bool ProcessPacket(byte id)
{
int nbr = 0;
int nbr;
switch (id)
{
case 0x00:
@ -110,98 +113,98 @@ namespace MinecraftClient.Protocol.Handlers
Receive(keepalive, 1, 4, SocketFlags.None);
handler.OnServerKeepAlive();
Send(keepalive); break;
case 0x01: readData(4); readNextString(); readData(5); break;
case 0x02: readData(1); readNextString(); readNextString(); readData(4); break;
case 0x01: ReadData(4); ReadNextString(); ReadData(5); break;
case 0x02: ReadData(1); ReadNextString(); ReadNextString(); ReadData(4); break;
case 0x03:
string message = readNextString();
string message = ReadNextString();
handler.OnTextReceived(new ChatMessage(message, protocolversion >= 72, 0, Guid.Empty)); break;
case 0x04: readData(16); break;
case 0x05: readData(6); readNextItemSlot(); break;
case 0x06: readData(12); break;
case 0x07: readData(9); break;
case 0x08: if (protocolversion >= 72) { readData(10); } else readData(8); break;
case 0x09: readData(8); readNextString(); break;
case 0x0A: readData(1); break;
case 0x0B: readData(33); break;
case 0x0C: readData(9); break;
case 0x0D: readData(41); break;
case 0x0E: readData(11); break;
case 0x0F: readData(10); readNextItemSlot(); readData(3); break;
case 0x10: readData(2); break;
case 0x11: readData(14); break;
case 0x12: readData(5); break;
case 0x13: if (protocolversion >= 72) { readData(9); } else readData(5); break;
case 0x14: readData(4); readNextString(); readData(16); readNextEntityMetaData(); break;
case 0x16: readData(8); break;
case 0x17: readData(19); readNextObjectData(); break;
case 0x18: readData(26); readNextEntityMetaData(); break;
case 0x19: readData(4); readNextString(); readData(16); break;
case 0x1A: readData(18); break;
case 0x1B: if (protocolversion >= 72) { readData(10); } break;
case 0x1C: readData(10); break;
case 0x1D: nbr = (int)readNextByte(); readData(nbr * 4); break;
case 0x1E: readData(4); break;
case 0x1F: readData(7); break;
case 0x20: readData(6); break;
case 0x21: readData(9); break;
case 0x22: readData(18); break;
case 0x23: readData(5); break;
case 0x26: readData(5); break;
case 0x27: if (protocolversion >= 72) { readData(9); } else readData(8); break;
case 0x28: readData(4); readNextEntityMetaData(); break;
case 0x29: readData(8); break;
case 0x2A: readData(5); break;
case 0x2B: readData(8); break;
case 0x2C: if (protocolversion >= 72) { readNextEntityProperties(protocolversion); } break;
case 0x33: readData(13); nbr = readNextInt(); readData(nbr); break;
case 0x34: readData(10); nbr = readNextInt(); readData(nbr); break;
case 0x35: readData(12); break;
case 0x36: readData(14); break;
case 0x37: readData(17); break;
case 0x38: readNextChunkBulkData(); break;
case 0x3C: readData(28); nbr = readNextInt(); readData(3 * nbr); readData(12); break;
case 0x3D: readData(18); break;
case 0x3E: readNextString(); readData(17); break;
case 0x3F: if (protocolversion > 51) { readNextString(); readData(32); } break;
case 0x46: readData(2); break;
case 0x47: readData(17); break;
case 0x64: readNextWindowData(protocolversion); break;
case 0x65: readData(1); break;
case 0x66: readData(7); readNextItemSlot(); break;
case 0x67: readData(3); readNextItemSlot(); break;
case 0x68: readData(1); for (nbr = readNextShort(); nbr > 0; nbr--) { readNextItemSlot(); } break;
case 0x69: readData(5); break;
case 0x6A: readData(4); break;
case 0x6B: readData(2); readNextItemSlot(); break;
case 0x6C: readData(2); break;
case 0x82: readData(10); readNextString(); readNextString(); readNextString(); readNextString(); break;
case 0x83: readData(4); nbr = readNextShort(); readData(nbr); break;
case 0x84: readData(11); nbr = readNextShort(); if (nbr > 0) { readData(nbr); } break;
case 0x85: if (protocolversion >= 74) { readData(13); } break;
case 0x04: ReadData(16); break;
case 0x05: ReadData(6); ReadNextItemSlot(); break;
case 0x06: ReadData(12); break;
case 0x07: ReadData(9); break;
case 0x08: if (protocolversion >= 72) { ReadData(10); } else ReadData(8); break;
case 0x09: ReadData(8); ReadNextString(); break;
case 0x0A: ReadData(1); break;
case 0x0B: ReadData(33); break;
case 0x0C: ReadData(9); break;
case 0x0D: ReadData(41); break;
case 0x0E: ReadData(11); break;
case 0x0F: ReadData(10); ReadNextItemSlot(); ReadData(3); break;
case 0x10: ReadData(2); break;
case 0x11: ReadData(14); break;
case 0x12: ReadData(5); break;
case 0x13: if (protocolversion >= 72) { ReadData(9); } else ReadData(5); break;
case 0x14: ReadData(4); ReadNextString(); ReadData(16); ReadNextEntityMetaData(); break;
case 0x16: ReadData(8); break;
case 0x17: ReadData(19); ReadNextObjectData(); break;
case 0x18: ReadData(26); ReadNextEntityMetaData(); break;
case 0x19: ReadData(4); ReadNextString(); ReadData(16); break;
case 0x1A: ReadData(18); break;
case 0x1B: if (protocolversion >= 72) { ReadData(10); } break;
case 0x1C: ReadData(10); break;
case 0x1D: nbr = (int)ReadNextByte(); ReadData(nbr * 4); break;
case 0x1E: ReadData(4); break;
case 0x1F: ReadData(7); break;
case 0x20: ReadData(6); break;
case 0x21: ReadData(9); break;
case 0x22: ReadData(18); break;
case 0x23: ReadData(5); break;
case 0x26: ReadData(5); break;
case 0x27: if (protocolversion >= 72) { ReadData(9); } else ReadData(8); break;
case 0x28: ReadData(4); ReadNextEntityMetaData(); break;
case 0x29: ReadData(8); break;
case 0x2A: ReadData(5); break;
case 0x2B: ReadData(8); break;
case 0x2C: if (protocolversion >= 72) { ReadNextEntityProperties(protocolversion); } break;
case 0x33: ReadData(13); nbr = ReadNextInt(); ReadData(nbr); break;
case 0x34: ReadData(10); nbr = ReadNextInt(); ReadData(nbr); break;
case 0x35: ReadData(12); break;
case 0x36: ReadData(14); break;
case 0x37: ReadData(17); break;
case 0x38: ReadNextChunkBulkData(); break;
case 0x3C: ReadData(28); nbr = ReadNextInt(); ReadData(3 * nbr); ReadData(12); break;
case 0x3D: ReadData(18); break;
case 0x3E: ReadNextString(); ReadData(17); break;
case 0x3F: if (protocolversion > 51) { ReadNextString(); ReadData(32); } break;
case 0x46: ReadData(2); break;
case 0x47: ReadData(17); break;
case 0x64: ReadNextWindowData(protocolversion); break;
case 0x65: ReadData(1); break;
case 0x66: ReadData(7); ReadNextItemSlot(); break;
case 0x67: ReadData(3); ReadNextItemSlot(); break;
case 0x68: ReadData(1); for (nbr = ReadNextShort(); nbr > 0; nbr--) { ReadNextItemSlot(); } break;
case 0x69: ReadData(5); break;
case 0x6A: ReadData(4); break;
case 0x6B: ReadData(2); ReadNextItemSlot(); break;
case 0x6C: ReadData(2); break;
case 0x82: ReadData(10); ReadNextString(); ReadNextString(); ReadNextString(); ReadNextString(); break;
case 0x83: ReadData(4); nbr = ReadNextShort(); ReadData(nbr); break;
case 0x84: ReadData(11); nbr = ReadNextShort(); if (nbr > 0) { ReadData(nbr); } break;
case 0x85: if (protocolversion >= 74) { ReadData(13); } break;
case 0xC8:
if (readNextInt() == 2022) { Translations.WriteLogLine("mcc.player_dead"); }
if (protocolversion >= 72) { readData(4); } else readData(1);
if (ReadNextInt() == 2022) { Translations.WriteLogLine("mcc.player_dead"); }
if (protocolversion >= 72) { ReadData(4); } else ReadData(1);
break;
case 0xC9:
string name = readNextString(); bool online = readNextByte() != 0x00; readData(2);
Guid FakeUUID = new Guid(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(name)).Take(16).ToArray());
string name = ReadNextString(); bool online = ReadNextByte() != 0x00; ReadData(2);
Guid FakeUUID = new(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(name)).Take(16).ToArray());
if (online) { handler.OnPlayerJoin(new PlayerInfo(name, FakeUUID)); } else { handler.OnPlayerLeave(FakeUUID); }
break;
case 0xCA: if (protocolversion >= 72) { readData(9); } else readData(3); break;
case 0xCB: autocomplete_result = readNextString(); autocomplete_received = true; break;
case 0xCC: readNextString(); readData(4); break;
case 0xCD: readData(1); break;
case 0xCE: if (protocolversion > 51) { readNextString(); readNextString(); readData(1); } break;
case 0xCF: if (protocolversion > 51) { readNextString(); readData(1); readNextString(); } readData(4); break;
case 0xD0: if (protocolversion > 51) { readData(1); readNextString(); } break;
case 0xD1: if (protocolversion > 51) { readNextTeamData(); } break;
case 0xCA: if (protocolversion >= 72) { ReadData(9); } else ReadData(3); break;
case 0xCB: autocomplete_result = ReadNextString(); autocomplete_received = true; break;
case 0xCC: ReadNextString(); ReadData(4); break;
case 0xCD: ReadData(1); break;
case 0xCE: if (protocolversion > 51) { ReadNextString(); ReadNextString(); ReadData(1); } break;
case 0xCF: if (protocolversion > 51) { ReadNextString(); ReadData(1); ReadNextString(); } ReadData(4); break;
case 0xD0: if (protocolversion > 51) { ReadData(1); ReadNextString(); } break;
case 0xD1: if (protocolversion > 51) { ReadNextTeamData(); } break;
case 0xFA:
string channel = readNextString();
byte[] payload = readNextByteArray();
string channel = ReadNextString();
byte[] payload = ReadNextByteArray();
handler.OnPluginChannelMessage(channel, payload);
break;
case 0xFF:
string reason = readNextString();
string reason = ReadNextString();
handler.OnConnectionLost(ChatBot.DisconnectReason.InGameKick, reason); break;
default: return false; //unknown packet!
}
@ -237,7 +240,7 @@ namespace MinecraftClient.Protocol.Handlers
catch { }
}
private void readData(int offset)
private void ReadData(int offset)
{
if (offset > 0)
{
@ -250,9 +253,9 @@ namespace MinecraftClient.Protocol.Handlers
}
}
private string readNextString()
private string ReadNextString()
{
ushort length = (ushort)readNextShort();
ushort length = (ushort)ReadNextShort();
if (length > 0)
{
byte[] cache = new byte[length * 2];
@ -267,15 +270,15 @@ namespace MinecraftClient.Protocol.Handlers
return false;
}
private byte[] readNextByteArray()
private byte[] ReadNextByteArray()
{
short len = readNextShort();
short len = ReadNextShort();
byte[] data = new byte[len];
Receive(data, 0, len, SocketFlags.None);
return data;
}
private short readNextShort()
private short ReadNextShort()
{
byte[] tmp = new byte[2];
Receive(tmp, 0, 2, SocketFlags.None);
@ -283,7 +286,7 @@ namespace MinecraftClient.Protocol.Handlers
return BitConverter.ToInt16(tmp, 0);
}
private int readNextInt()
private int ReadNextInt()
{
byte[] tmp = new byte[4];
Receive(tmp, 0, 4, SocketFlags.None);
@ -291,28 +294,28 @@ namespace MinecraftClient.Protocol.Handlers
return BitConverter.ToInt32(tmp, 0);
}
private byte readNextByte()
private byte ReadNextByte()
{
byte[] result = new byte[1];
Receive(result, 0, 1, SocketFlags.None);
return result[0];
}
private void readNextItemSlot()
private void ReadNextItemSlot()
{
short itemid = readNextShort();
short itemid = ReadNextShort();
//If slot not empty (item ID != -1)
if (itemid != -1)
{
readData(1); //Item count
readData(2); //Item damage
short length = readNextShort();
ReadData(1); //Item count
ReadData(2); //Item damage
short length = ReadNextShort();
//If length of optional NBT data > 0, read it
if (length > 0) { readData(length); }
if (length > 0) { ReadData(length); }
}
}
private void readNextEntityMetaData()
private void ReadNextEntityMetaData()
{
do
{
@ -323,100 +326,100 @@ namespace MinecraftClient.Protocol.Handlers
int type = id[0] >> 5;
switch (type)
{
case 0: readData(1); break; //Byte
case 1: readData(2); break; //Short
case 2: readData(4); break; //Int
case 3: readData(4); break; //Float
case 4: readNextString(); break; //String
case 5: readNextItemSlot(); break; //Slot
case 6: readData(12); break; //Vector (3 Int)
case 0: ReadData(1); break; //Byte
case 1: ReadData(2); break; //Short
case 2: ReadData(4); break; //Int
case 3: ReadData(4); break; //Float
case 4: ReadNextString(); break; //String
case 5: ReadNextItemSlot(); break; //Slot
case 6: ReadData(12); break; //Vector (3 Int)
}
} while (true);
}
private void readNextObjectData()
private void ReadNextObjectData()
{
int id = readNextInt();
if (id != 0) { readData(6); }
int id = ReadNextInt();
if (id != 0) { ReadData(6); }
}
private void readNextTeamData()
private void ReadNextTeamData()
{
readNextString(); //Internal Name
byte mode = readNextByte();
ReadNextString(); //Internal Name
byte mode = ReadNextByte();
if (mode == 0 || mode == 2)
{
readNextString(); //Display Name
readNextString(); //Prefix
readNextString(); //Suffix
readData(1); //Friendly Fire
ReadNextString(); //Display Name
ReadNextString(); //Prefix
ReadNextString(); //Suffix
ReadData(1); //Friendly Fire
}
if (mode == 0 || mode == 3 || mode == 4)
{
short count = readNextShort();
short count = ReadNextShort();
for (int i = 0; i < count; i++)
{
readNextString(); //Players
ReadNextString(); //Players
}
}
}
private void readNextEntityProperties(int protocolversion)
private void ReadNextEntityProperties(int protocolversion)
{
if (protocolversion >= 72)
{
if (protocolversion >= 74)
{
//Minecraft 1.6.2
readNextInt(); //Entity ID
int count = readNextInt();
ReadNextInt(); //Entity ID
int count = ReadNextInt();
for (int i = 0; i < count; i++)
{
readNextString(); //Property name
readData(8); //Property value (Double)
short othercount = readNextShort();
readData(25 * othercount);
ReadNextString(); //Property name
ReadData(8); //Property value (Double)
short othercount = ReadNextShort();
ReadData(25 * othercount);
}
}
else
{
//Minecraft 1.6.0 / 1.6.1
readNextInt(); //Entity ID
int count = readNextInt();
ReadNextInt(); //Entity ID
int count = ReadNextInt();
for (int i = 0; i < count; i++)
{
readNextString(); //Property name
readData(8); //Property value (Double)
ReadNextString(); //Property name
ReadData(8); //Property value (Double)
}
}
}
}
private void readNextWindowData(int protocolversion)
private void ReadNextWindowData(int protocolversion)
{
readData(1);
byte windowtype = readNextByte();
readNextString();
readData(1);
ReadData(1);
byte windowtype = ReadNextByte();
ReadNextString();
ReadData(1);
if (protocolversion > 51)
{
readData(1);
ReadData(1);
if (protocolversion >= 72 && windowtype == 0xb)
{
readNextInt();
ReadNextInt();
}
}
}
private void readNextChunkBulkData()
private void ReadNextChunkBulkData()
{
short chunkcount = readNextShort();
int datalen = readNextInt();
readData(1);
readData(datalen);
readData(12 * (chunkcount));
short chunkcount = ReadNextShort();
int datalen = ReadNextInt();
ReadData(1);
ReadData(datalen);
ReadData(12 * (chunkcount));
}
private void Receive(byte[] buffer, int start, int offset, SocketFlags f)
@ -425,20 +428,18 @@ namespace MinecraftClient.Protocol.Handlers
while (read < offset)
{
if (encrypted)
{
read += s.Read(buffer, start + read, offset - read);
}
else read += c.Client.Receive(buffer, start + read, offset - read, f);
read += s!.Read(buffer, start + read, offset - read);
else
read += c.Client.Receive(buffer, start + read, offset - read, f);
}
}
private void Send(byte[] buffer)
{
if (encrypted)
{
s.Write(buffer, 0, buffer.Length);
}
else c.Client.Send(buffer);
s!.Write(buffer, 0, buffer.Length);
else
c.Client.Send(buffer);
}
private bool Handshake(string uuid, string username, string sessionID, string host, int port, SessionToken session)
@ -481,14 +482,14 @@ namespace MinecraftClient.Protocol.Handlers
Receive(pid, 0, 1, SocketFlags.None);
while (pid[0] == 0xFA) //Skip some early plugin messages
{
processPacket(pid[0]);
ProcessPacket(pid[0]);
Receive(pid, 0, 1, SocketFlags.None);
}
if (pid[0] == 0xFD)
{
string serverID = readNextString();
byte[] PublicServerkey = readNextByteArray();
byte[] token = readNextByteArray();
string serverID = ReadNextString();
byte[] PublicServerkey = ReadNextByteArray();
byte[] token = ReadNextByteArray();
if (serverID == "-")
Translations.WriteLineFormatted("mcc.server_offline");
@ -506,7 +507,7 @@ namespace MinecraftClient.Protocol.Handlers
private bool StartEncryption(string uuid, string username, string sessionID, byte[] token, string serverIDhash, byte[] serverPublicKey, SessionToken session)
{
RSACryptoServiceProvider RSAService = CryptoHandler.DecodeRSAPublicKey(serverPublicKey);
RSACryptoServiceProvider RSAService = CryptoHandler.DecodeRSAPublicKey(serverPublicKey)!;
byte[] secretKey = CryptoHandler.ClientAESPrivateKey ?? CryptoHandler.GenerateAESPrivateKey();
if (Settings.DebugMessages)
@ -515,7 +516,7 @@ namespace MinecraftClient.Protocol.Handlers
if (serverIDhash != "-")
{
Translations.WriteLine("mcc.session");
string serverHash = CryptoHandler.getServerHash(serverIDhash, serverPublicKey, secretKey);
string serverHash = CryptoHandler.GetServerHash(serverIDhash, serverPublicKey, secretKey);
bool needCheckSession = true;
if (session.ServerPublicKey != null && session.SessionPreCheckTask != null
@ -568,7 +569,7 @@ namespace MinecraftClient.Protocol.Handlers
Receive(pid, 0, 1, SocketFlags.None);
if (pid[0] == 0xFC)
{
readData(4);
ReadData(4);
s = new AesCfb8Stream(c.GetStream(), secretKey);
encrypted = true;
return true;
@ -595,18 +596,18 @@ namespace MinecraftClient.Protocol.Handlers
Receive(pid, 0, 1, SocketFlags.None);
while (pid[0] >= 0xC0 && pid[0] != 0xFF) //Skip some early packets or plugin messages
{
processPacket(pid[0]);
ProcessPacket(pid[0]);
Receive(pid, 0, 1, SocketFlags.None);
}
if (pid[0] == (byte)1)
{
readData(4); readNextString(); readData(5);
ReadData(4); ReadNextString(); ReadData(5);
StartUpdating();
return true; //The Server accepted the request
}
else if (pid[0] == (byte)0xFF)
{
string reason = readNextString();
string reason = ReadNextString();
handler.OnConnectionLost(ChatBot.DisconnectReason.LoginRejected, reason);
return false;
}
@ -804,7 +805,7 @@ namespace MinecraftClient.Protocol.Handlers
byte[] dataLength = BitConverter.GetBytes((short)data.Length);
Array.Reverse(dataLength);
Send(concatBytes(new byte[] { 0xFA }, channelLength, channelData, dataLength, data));
Send(ConcatBytes(new byte[] { 0xFA }, channelLength, channelData, dataLength, data));
return true;
}
@ -815,7 +816,7 @@ namespace MinecraftClient.Protocol.Handlers
IEnumerable<string> IAutoComplete.AutoComplete(string BehindCursor)
{
if (String.IsNullOrEmpty(BehindCursor))
return new string[] { };
return Array.Empty<string>();
byte[] autocomplete = new byte[3 + (BehindCursor.Length * 2)];
autocomplete[0] = 0xCB;
@ -835,20 +836,20 @@ namespace MinecraftClient.Protocol.Handlers
return autocomplete_result.Split((char)0x00);
}
private static byte[] concatBytes(params byte[][] bytes)
private static byte[] ConcatBytes(params byte[][] bytes)
{
List<byte> result = new List<byte>();
List<byte> result = new();
foreach (byte[] array in bytes)
result.AddRange(array);
return result.ToArray();
}
public static bool doPing(string host, int port, ref int protocolversion)
public static bool DoPing(string host, int port, ref int protocolversion)
{
try
{
string version = "";
TcpClient tcp = ProxyHandler.newTcpClient(host, port);
TcpClient tcp = ProxyHandler.NewTcpClient(host, port);
tcp.ReceiveTimeout = 30000; // 30 seconds
tcp.ReceiveTimeout = 5000; //MC 1.7.2+ SpigotMC servers won't respond, so we need a reasonable timeout.
byte[] ping = new byte[2] { 0xfe, 0x01 };
@ -857,8 +858,8 @@ namespace MinecraftClient.Protocol.Handlers
if (ping[0] == 0xff)
{
Protocol16Handler ComTmp = new Protocol16Handler(tcp);
string result = ComTmp.readNextString();
Protocol16Handler ComTmp = new(tcp);
string result = ComTmp.ReadNextString();
if (Settings.DebugMessages)
{

View file

@ -1,26 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Security.Cryptography;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using MinecraftClient.Crypto;
using MinecraftClient.Proxy;
using MinecraftClient.Inventory;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Logger;
using MinecraftClient.Mapping;
using MinecraftClient.Mapping.BlockPalettes;
using MinecraftClient.Mapping.EntityPalettes;
using MinecraftClient.Protocol.Handlers.Forge;
using MinecraftClient.Inventory;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.PacketPalettes;
using MinecraftClient.Logger;
using MinecraftClient.Protocol.Keys;
using MinecraftClient.Protocol.Session;
using MinecraftClient.Protocol.Message;
using MinecraftClient.Protocol.Session;
using MinecraftClient.Proxy;
namespace MinecraftClient.Protocol.Handlers
{
@ -63,44 +63,43 @@ namespace MinecraftClient.Protocol.Handlers
private int compression_treshold = 0;
private bool autocomplete_received = false;
private int autocomplete_transaction_id = 0;
private readonly List<string> autocomplete_result = new List<string>();
private readonly Dictionary<int, short> window_actions = new Dictionary<int, short>();
private readonly List<string> autocomplete_result = new();
private readonly Dictionary<int, short> window_actions = new();
private bool login_phase = true;
private int protocolVersion;
private readonly int protocolVersion;
private int currentDimension;
private bool isOnlineMode = false;
private readonly BlockingCollection<Tuple<int, Queue<byte>>> packetQueue = new();
private int pendingAcknowledgments = 0;
private LastSeenMessagesCollector lastSeenMessagesCollector = new(5);
private readonly LastSeenMessagesCollector lastSeenMessagesCollector = new(5);
private LastSeenMessageList.Entry? lastReceivedMessage = null;
Protocol18Forge pForge;
Protocol18Terrain pTerrain;
IMinecraftComHandler handler;
EntityPalette entityPalette;
ItemPalette itemPalette;
PacketTypePalette packetPalette;
SocketWrapper socketWrapper;
DataTypes dataTypes;
readonly Protocol18Forge pForge;
readonly Protocol18Terrain pTerrain;
readonly IMinecraftComHandler handler;
readonly EntityPalette entityPalette;
readonly ItemPalette itemPalette;
readonly PacketTypePalette packetPalette;
readonly SocketWrapper socketWrapper;
readonly DataTypes dataTypes;
Tuple<Thread, CancellationTokenSource>? netMain = null; // main thread
Tuple<Thread, CancellationTokenSource>? netReader = null; // reader thread
ILogger log;
RandomNumberGenerator randomGen;
readonly ILogger log;
readonly RandomNumberGenerator randomGen;
public Protocol18Handler(TcpClient Client, int protocolVersion, IMinecraftComHandler handler, ForgeInfo forgeInfo)
public Protocol18Handler(TcpClient Client, int protocolVersion, IMinecraftComHandler handler, ForgeInfo? forgeInfo)
{
ConsoleIO.SetAutoCompleteEngine(this);
ChatParser.InitTranslations();
this.socketWrapper = new SocketWrapper(Client);
this.dataTypes = new DataTypes(protocolVersion);
socketWrapper = new SocketWrapper(Client);
dataTypes = new DataTypes(protocolVersion);
this.protocolVersion = protocolVersion;
this.handler = handler;
this.pForge = new Protocol18Forge(forgeInfo, protocolVersion, dataTypes, this, handler);
this.pTerrain = new Protocol18Terrain(protocolVersion, dataTypes, handler);
this.packetPalette = new PacketTypeHandler(protocolVersion, forgeInfo != null).GetTypeHandler();
this.log = handler.GetLogger();
this.randomGen = RandomNumberGenerator.Create();
pForge = new Protocol18Forge(forgeInfo, protocolVersion, dataTypes, this, handler);
pTerrain = new Protocol18Terrain(protocolVersion, dataTypes, handler);
packetPalette = new PacketTypeHandler(protocolVersion, forgeInfo != null).GetTypeHandler();
log = handler.GetLogger();
randomGen = RandomNumberGenerator.Create();
if (handler.GetTerrainEnabled() && protocolVersion > MC_1_19_2_Version)
{
@ -335,7 +334,7 @@ namespace MinecraftClient.Protocol.Handlers
case 0x04:
int messageId = dataTypes.ReadNextVarInt(packetData);
string channel = dataTypes.ReadNextString(packetData);
List<byte> responseData = new List<byte>();
List<byte> responseData = new();
bool understood = pForge.HandleLoginPluginRequest(channel, packetData, ref responseData);
SendLoginPluginResponse(messageId, understood, responseData.ToArray());
return understood;
@ -391,12 +390,12 @@ namespace MinecraftClient.Protocol.Handlers
dimensionType = dataTypes.ReadNextNbt(packetData); // Dimension Type: NBT Tag Compound
else
dataTypes.ReadNextString(packetData);
this.currentDimension = 0;
currentDimension = 0;
}
else if (protocolVersion >= MC_1_9_1_Version)
this.currentDimension = dataTypes.ReadNextInt(packetData);
currentDimension = dataTypes.ReadNextInt(packetData);
else
this.currentDimension = (sbyte)dataTypes.ReadNextByte(packetData);
currentDimension = (sbyte)dataTypes.ReadNextByte(packetData);
if (protocolVersion < MC_1_14_Version)
dataTypes.ReadNextByte(packetData); // Difficulty - 1.13 and below
@ -506,7 +505,7 @@ namespace MinecraftClient.Protocol.Handlers
else
{
PlayerInfo? player = handler.GetPlayerInfo(senderUUID);
verifyResult = player == null ? false : player.VerifyMessage(signedChat, timestamp, salt, ref messageSignature);
verifyResult = player != null && player.VerifyMessage(signedChat, timestamp, salt, ref messageSignature);
}
ChatMessage chat = new(signedChat, true, messageType, senderUUID, unsignedChatContent, senderDisplayName, senderTeamName, timestamp, messageSignature, verifyResult);
@ -572,8 +571,8 @@ namespace MinecraftClient.Protocol.Handlers
}
ChatMessage chat = new(signedChat, false, chatTypeId, senderUUID, unsignedChatContent, senderDisplayName, senderTeamName, timestamp, headerSignature, verifyResult);
if (isOnlineMode && !chat.lacksSender())
this.acknowledge(chat);
if (isOnlineMode && !chat.LacksSender())
Acknowledge(chat);
handler.OnTextReceived(chat);
}
break;
@ -618,11 +617,11 @@ namespace MinecraftClient.Protocol.Handlers
dimensionTypeRespawn = dataTypes.ReadNextNbt(packetData); // Dimension Type: NBT Tag Compound
else
dataTypes.ReadNextString(packetData);
this.currentDimension = 0;
currentDimension = 0;
}
else
{ // 1.15 and below
this.currentDimension = dataTypes.ReadNextInt(packetData);
currentDimension = dataTypes.ReadNextInt(packetData);
}
if (protocolVersion >= MC_1_16_Version)
@ -816,7 +815,7 @@ namespace MinecraftClient.Protocol.Handlers
List<MapIcon> icons = new();
// 1,9 + = needs tracking position to be true to get the icons
if (protocolVersion > MC_1_9_Version ? trackingPosition : true)
if (protocolVersion <= MC_1_9_Version || trackingPosition)
{
iconcount = dataTypes.ReadNextVarInt(packetData);
@ -888,13 +887,13 @@ namespace MinecraftClient.Protocol.Handlers
// MC 1.14 or greater
int windowID = dataTypes.ReadNextVarInt(packetData);
int size = dataTypes.ReadNextByte(packetData);
List<VillagerTrade> trades = new List<VillagerTrade>();
List<VillagerTrade> trades = new();
for (int tradeId = 0; tradeId < size; tradeId++)
{
VillagerTrade trade = dataTypes.ReadNextTrade(packetData, itemPalette);
trades.Add(trade);
}
VillagerInfo villagerInfo = new VillagerInfo()
VillagerInfo villagerInfo = new()
{
Level = dataTypes.ReadNextVarInt(packetData),
Experience = dataTypes.ReadNextVarInt(packetData),
@ -980,7 +979,7 @@ namespace MinecraftClient.Protocol.Handlers
int localZ = (int)((block >> 4) & 0x0F);
int localY = (int)(block & 0x0F);
Block b = new Block((ushort)blockId);
Block b = new((ushort)blockId);
int blockX = (sectionX * 16) + localX;
int blockY = (sectionY * 16) + localY;
int blockZ = (sectionZ * 16) + localZ;
@ -1017,7 +1016,7 @@ namespace MinecraftClient.Protocol.Handlers
int blockX = locationXZ >> 4;
int blockZ = locationXZ & 0x0F;
Block block = new Block(blockIdMeta);
Block block = new(blockIdMeta);
handler.GetWorld().SetBlock(new Location(chunkX, chunkZ, blockX, blockY, blockZ), block);
}
}
@ -1159,6 +1158,7 @@ namespace MinecraftClient.Protocol.Handlers
// Property: Tuple<Name, Value, Signature(empty if there is no signature)
// The Property field looks as in the response of https://wiki.vg/Mojang_API#UUID_to_Profile_and_Skin.2FCape
const bool useProperty = false;
#pragma warning disable CS0162 // Unreachable code detected
Tuple<string, string, string?>[]? properties = useProperty ?
new Tuple<string, string, string?>[propNum] : null;
for (int p = 0; p < propNum; p++)
@ -1171,6 +1171,7 @@ namespace MinecraftClient.Protocol.Handlers
if (useProperty)
properties![p] = new(propertyName, val, propertySignature);
}
#pragma warning restore CS0162 // Unreachable code detected
int gameMode = dataTypes.ReadNextVarInt(packetData); // Gamemode
handler.OnGamemodeUpdate(uuid, gameMode);
@ -1233,7 +1234,7 @@ namespace MinecraftClient.Protocol.Handlers
string name = dataTypes.ReadNextString(packetData);
bool online = dataTypes.ReadNextBool(packetData);
short ping = dataTypes.ReadNextShort(packetData);
Guid FakeUUID = new Guid(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(name)).Take(16).ToArray());
Guid FakeUUID = new(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(name)).Take(16).ToArray());
if (online)
handler.OnPlayerJoin(new PlayerInfo(name, FakeUUID));
else handler.OnPlayerLeave(FakeUUID);
@ -1288,7 +1289,7 @@ namespace MinecraftClient.Protocol.Handlers
ContainerTypeOld inventoryType = (ContainerTypeOld)Enum.Parse(typeof(ContainerTypeOld), type);
string title = dataTypes.ReadNextString(packetData);
byte slots = dataTypes.ReadNextByte(packetData);
Container inventory = new Container(windowID, inventoryType, ChatParser.ParseText(title));
Container inventory = new(windowID, inventoryType, ChatParser.ParseText(title));
handler.OnInventoryOpen(windowID, inventory);
}
else
@ -1297,7 +1298,7 @@ namespace MinecraftClient.Protocol.Handlers
int windowID = dataTypes.ReadNextVarInt(packetData);
int windowType = dataTypes.ReadNextVarInt(packetData);
string title = dataTypes.ReadNextString(packetData);
Container inventory = new Container(windowID, windowType, ChatParser.ParseText(title));
Container inventory = new(windowID, windowType, ChatParser.ParseText(title));
handler.OnInventoryOpen(windowID, inventory);
}
}
@ -1329,10 +1330,10 @@ namespace MinecraftClient.Protocol.Handlers
dataTypes.ReadNextShort(packetData);
}
Dictionary<int, Item> inventorySlots = new Dictionary<int, Item>();
Dictionary<int, Item> inventorySlots = new();
for (int slotId = 0; slotId < elements; slotId++)
{
Item item = dataTypes.ReadNextItemSlot(packetData, itemPalette);
Item? item = dataTypes.ReadNextItemSlot(packetData, itemPalette);
if (item != null)
inventorySlots[slotId] = item;
}
@ -1351,7 +1352,7 @@ namespace MinecraftClient.Protocol.Handlers
if (protocolVersion >= MC_1_17_1_Version)
stateId = dataTypes.ReadNextVarInt(packetData); // State ID - 1.17.1 and above
short slotID = dataTypes.ReadNextShort(packetData);
Item item = dataTypes.ReadNextItemSlot(packetData, itemPalette);
Item? item = dataTypes.ReadNextItemSlot(packetData, itemPalette);
handler.OnSetSlot(windowID, slotID, item, stateId);
}
break;
@ -1382,7 +1383,7 @@ namespace MinecraftClient.Protocol.Handlers
if (!url.StartsWith("http") && hash.Length != 40) // Some server may have null hash value
break;
//Send back "accepted" and "successfully loaded" responses for plugins or server config making use of resource pack mandatory
byte[] responseHeader = new byte[0];
byte[] responseHeader = Array.Empty<byte>();
if (protocolVersion < MC_1_10_Version) //MC 1.10 does not include resource pack hash in responses
responseHeader = dataTypes.ConcatBytes(dataTypes.GetVarInt(hash.Length), Encoding.UTF8.GetBytes(hash));
SendPacket(PacketTypesOut.ResourcePackStatus, dataTypes.ConcatBytes(responseHeader, dataTypes.GetVarInt(3))); //Accepted pack
@ -1406,16 +1407,16 @@ namespace MinecraftClient.Protocol.Handlers
{
byte bitsData = dataTypes.ReadNextByte(packetData);
// Top bit set if another entry follows, and otherwise unset if this is the last item in the array
hasNext = (bitsData >> 7) == 1 ? true : false;
hasNext = (bitsData >> 7) == 1;
int slot2 = bitsData >> 1;
Item item = dataTypes.ReadNextItemSlot(packetData, itemPalette);
Item? item = dataTypes.ReadNextItemSlot(packetData, itemPalette);
handler.OnEntityEquipment(entityid, slot2, item);
} while (hasNext);
}
else
{
int slot2 = dataTypes.ReadNextVarInt(packetData);
Item item = dataTypes.ReadNextItemSlot(packetData, itemPalette);
Item? item = dataTypes.ReadNextItemSlot(packetData, itemPalette);
handler.OnEntityEquipment(entityid, slot2, item);
}
}
@ -1441,7 +1442,7 @@ namespace MinecraftClient.Protocol.Handlers
byte Yaw = dataTypes.ReadNextByte(packetData);
byte Pitch = dataTypes.ReadNextByte(packetData);
Location EntityLocation = new Location(X, Y, Z);
Location EntityLocation = new(X, Y, Z);
handler.OnSpawnPlayer(EntityID, UUID, EntityLocation, Yaw, Pitch);
}
@ -1495,9 +1496,9 @@ namespace MinecraftClient.Protocol.Handlers
Double DeltaY = Convert.ToDouble(dataTypes.ReadNextShort(packetData));
Double DeltaZ = Convert.ToDouble(dataTypes.ReadNextShort(packetData));
bool OnGround = dataTypes.ReadNextBool(packetData);
DeltaX = DeltaX / (128 * 32);
DeltaY = DeltaY / (128 * 32);
DeltaZ = DeltaZ / (128 * 32);
DeltaX /= (128 * 32);
DeltaY /= (128 * 32);
DeltaZ /= (128 * 32);
handler.OnEntityPosition(EntityID, DeltaX, DeltaY, DeltaZ, OnGround);
}
break;
@ -1511,9 +1512,9 @@ namespace MinecraftClient.Protocol.Handlers
byte _yaw = dataTypes.ReadNextByte(packetData);
byte _pitch = dataTypes.ReadNextByte(packetData);
bool OnGround = dataTypes.ReadNextBool(packetData);
DeltaX = DeltaX / (128 * 32);
DeltaY = DeltaY / (128 * 32);
DeltaZ = DeltaZ / (128 * 32);
DeltaX /= (128 * 32);
DeltaY /= (128 * 32);
DeltaZ /= (128 * 32);
handler.OnEntityPosition(EntityID, DeltaX, DeltaY, DeltaZ, OnGround);
}
break;
@ -1522,15 +1523,15 @@ namespace MinecraftClient.Protocol.Handlers
{
int EntityID = dataTypes.ReadNextVarInt(packetData);
int NumberOfProperties = protocolVersion >= MC_1_17_Version ? dataTypes.ReadNextVarInt(packetData) : dataTypes.ReadNextInt(packetData);
Dictionary<string, Double> keys = new Dictionary<string, Double>();
Dictionary<string, Double> keys = new();
for (int i = 0; i < NumberOfProperties; i++)
{
string _key = dataTypes.ReadNextString(packetData);
Double _value = dataTypes.ReadNextDouble(packetData);
List<double> op0 = new List<double>();
List<double> op1 = new List<double>();
List<double> op2 = new List<double>();
List<double> op0 = new();
List<double> op1 = new();
List<double> op2 = new();
int NumberOfModifiers = dataTypes.ReadNextVarInt(packetData);
for (int j = 0; j < NumberOfModifiers; j++)
{
@ -1716,13 +1717,17 @@ namespace MinecraftClient.Protocol.Handlers
/// </summary>
private void StartUpdating()
{
Thread threadUpdater = new Thread(new ParameterizedThreadStart(Updater));
threadUpdater.Name = "ProtocolPacketHandler";
Thread threadUpdater = new(new ParameterizedThreadStart(Updater))
{
Name = "ProtocolPacketHandler"
};
netMain = new Tuple<Thread, CancellationTokenSource>(threadUpdater, new CancellationTokenSource());
threadUpdater.Start(netMain.Item2.Token);
Thread threadReader = new Thread(new ParameterizedThreadStart(PacketReader));
threadReader.Name = "ProtocolPacketReader";
Thread threadReader = new(new ParameterizedThreadStart(PacketReader))
{
Name = "ProtocolPacketReader"
};
netReader = new Tuple<Thread, CancellationTokenSource>(threadReader, new CancellationTokenSource());
threadReader.Start(netReader.Item2.Token);
}
@ -1814,7 +1819,7 @@ namespace MinecraftClient.Protocol.Handlers
byte[] handshake_packet = dataTypes.ConcatBytes(protocol_version, dataTypes.GetString(server_address), server_port, next_state);
SendPacket(0x00, handshake_packet);
List<byte> fullLoginPacket = new List<byte>();
List<byte> fullLoginPacket = new();
fullLoginPacket.AddRange(dataTypes.GetString(handler.GetUsername())); // Username
if (protocolVersion >= MC_1_19_Version)
{
@ -1854,7 +1859,7 @@ namespace MinecraftClient.Protocol.Handlers
}
else if (packetID == 0x01) //Encryption request
{
this.isOnlineMode = true;
isOnlineMode = true;
string serverID = dataTypes.ReadNextString(packetData);
byte[] serverPublicKey = dataTypes.ReadNextByteArray(packetData);
byte[] token = dataTypes.ReadNextByteArray(packetData);
@ -1884,7 +1889,7 @@ namespace MinecraftClient.Protocol.Handlers
/// <returns>True if encryption was successful</returns>
private bool StartEncryption(string uuid, string sessionID, byte[] token, string serverIDhash, byte[] serverPublicKey, PlayerKeyPair? playerKeyPair, SessionToken session)
{
RSACryptoServiceProvider RSAService = CryptoHandler.DecodeRSAPublicKey(serverPublicKey);
RSACryptoServiceProvider RSAService = CryptoHandler.DecodeRSAPublicKey(serverPublicKey)!;
byte[] secretKey = CryptoHandler.ClientAESPrivateKey ?? CryptoHandler.GenerateAESPrivateKey();
log.Debug(Translations.Get("debug.crypto"));
@ -1904,7 +1909,7 @@ namespace MinecraftClient.Protocol.Handlers
if (needCheckSession)
{
string serverHash = CryptoHandler.getServerHash(serverIDhash, serverPublicKey, secretKey);
string serverHash = CryptoHandler.GetServerHash(serverIDhash, serverPublicKey, secretKey);
if (ProtocolHandler.SessionCheck(uuid, sessionID, serverHash))
{
@ -2020,13 +2025,13 @@ namespace MinecraftClient.Protocol.Handlers
{
if (String.IsNullOrEmpty(BehindCursor))
return new string[] { };
return Array.Empty<string>();
byte[] transaction_id = dataTypes.GetVarInt(autocomplete_transaction_id);
byte[] assume_command = new byte[] { 0x00 };
byte[] has_position = new byte[] { 0x00 };
byte[] tabcomplete_packet = new byte[] { };
byte[] tabcomplete_packet = Array.Empty<byte>();
if (protocolVersion >= MC_1_8_Version)
{
@ -2058,12 +2063,13 @@ namespace MinecraftClient.Protocol.Handlers
SendPacket(PacketTypesOut.TabComplete, tabcomplete_packet);
int wait_left = 50; //do not wait more than 5 seconds (50 * 100 ms)
Thread t1 = new Thread(new ThreadStart(delegate
{
while (wait_left > 0 && !autocomplete_received) { System.Threading.Thread.Sleep(100); wait_left--; }
if (autocomplete_result.Count > 0)
ConsoleIO.WriteLineFormatted("§8" + String.Join(" ", autocomplete_result), false);
}));
ThreadStart start = new(delegate
{
while (wait_left > 0 && !autocomplete_received) { System.Threading.Thread.Sleep(100); wait_left--; }
if (autocomplete_result.Count > 0)
ConsoleIO.WriteLineFormatted("§8" + String.Join(" ", autocomplete_result), false);
});
Thread t1 = new(start);
t1.Start();
return autocomplete_result;
}
@ -2072,14 +2078,14 @@ namespace MinecraftClient.Protocol.Handlers
/// Ping a Minecraft server to get information about the server
/// </summary>
/// <returns>True if ping was successful</returns>
public static bool doPing(string host, int port, ref int protocolVersion, ref ForgeInfo? forgeInfo)
public static bool DoPing(string host, int port, ref int protocolVersion, ref ForgeInfo? forgeInfo)
{
string version = "";
TcpClient tcp = ProxyHandler.newTcpClient(host, port);
TcpClient tcp = ProxyHandler.NewTcpClient(host, port);
tcp.ReceiveTimeout = 30000; // 30 seconds
tcp.ReceiveBufferSize = 1024 * 1024;
SocketWrapper socketWrapper = new SocketWrapper(tcp);
DataTypes dataTypes = new DataTypes(MC_1_8_Version);
SocketWrapper socketWrapper = new(tcp);
DataTypes dataTypes = new(MC_1_8_Version);
byte[] packet_id = dataTypes.GetVarInt(0);
byte[] protocol_version = dataTypes.GetVarInt(-1);
@ -2098,7 +2104,7 @@ namespace MinecraftClient.Protocol.Handlers
int packetLength = dataTypes.ReadNextVarIntRAW(socketWrapper);
if (packetLength > 0) //Read Response length
{
Queue<byte> packetData = new Queue<byte>(socketWrapper.ReadDataRAW(packetLength));
Queue<byte> packetData = new(socketWrapper.ReadDataRAW(packetLength));
if (dataTypes.ReadNextVarInt(packetData) == 0x00) //Read Packet ID
{
string result = dataTypes.ReadNextString(packetData); //Get the Json data
@ -2182,15 +2188,15 @@ namespace MinecraftClient.Protocol.Handlers
catch (ObjectDisposedException) { return false; }
}
public LastSeenMessageList.Acknowledgment consumeAcknowledgment()
public LastSeenMessageList.Acknowledgment ConsumeAcknowledgment()
{
this.pendingAcknowledgments = 0;
return new LastSeenMessageList.Acknowledgment(this.lastSeenMessagesCollector.GetLastSeenMessages(), this.lastReceivedMessage);
pendingAcknowledgments = 0;
return new LastSeenMessageList.Acknowledgment(lastSeenMessagesCollector.GetLastSeenMessages(), lastReceivedMessage);
}
public void acknowledge(ChatMessage message)
public void Acknowledge(ChatMessage message)
{
LastSeenMessageList.Entry? entry = message.toLastSeenMessageEntry();
LastSeenMessageList.Entry? entry = message.ToLastSeenMessageEntry();
if (entry != null)
{
@ -2198,7 +2204,7 @@ namespace MinecraftClient.Protocol.Handlers
lastReceivedMessage = null;
if (pendingAcknowledgments++ > 64)
SendMessageAcknowledgment(this.consumeAcknowledgment());
SendMessageAcknowledgment(ConsumeAcknowledgment());
}
}
@ -2272,7 +2278,7 @@ namespace MinecraftClient.Protocol.Handlers
try
{
LastSeenMessageList.Acknowledgment? acknowledgment =
(protocolVersion >= MC_1_19_2_Version) ? this.consumeAcknowledgment() : null;
(protocolVersion >= MC_1_19_2_Version) ? ConsumeAcknowledgment() : null;
List<byte> fields = new();
@ -2349,7 +2355,7 @@ namespace MinecraftClient.Protocol.Handlers
if (protocolVersion >= MC_1_19_Version)
{
LastSeenMessageList.Acknowledgment? acknowledgment =
(protocolVersion >= MC_1_19_2_Version) ? this.consumeAcknowledgment() : null;
(protocolVersion >= MC_1_19_2_Version) ? ConsumeAcknowledgment() : null;
// Timestamp: Instant(Long)
DateTimeOffset timeNow = DateTimeOffset.UtcNow;
@ -2396,7 +2402,7 @@ namespace MinecraftClient.Protocol.Handlers
{
try
{
List<byte> fields = new List<byte>();
List<byte> fields = new();
fields.AddRange(dataTypes.GetVarInt(PlayerEntityID));
fields.AddRange(dataTypes.GetVarInt(ActionID));
fields.AddRange(dataTypes.GetVarInt(0));
@ -2460,7 +2466,7 @@ namespace MinecraftClient.Protocol.Handlers
{
try
{
List<byte> fields = new List<byte>();
List<byte> fields = new();
fields.AddRange(dataTypes.GetString(language));
fields.Add(viewDistance);
@ -2507,7 +2513,7 @@ namespace MinecraftClient.Protocol.Handlers
{
if (handler.GetTerrainEnabled())
{
byte[] yawpitch = new byte[0];
byte[] yawpitch = Array.Empty<byte>();
PacketTypesOut packetType = PacketTypesOut.PlayerPosition;
if (yaw.HasValue && pitch.HasValue)
@ -2523,7 +2529,7 @@ namespace MinecraftClient.Protocol.Handlers
dataTypes.GetDouble(location.Y),
protocolVersion < MC_1_8_Version
? dataTypes.GetDouble(location.Y + 1.62)
: new byte[0],
: Array.Empty<byte>(),
dataTypes.GetDouble(location.Z),
yawpitch,
new byte[] { onGround ? (byte)1 : (byte)0 }));
@ -2595,7 +2601,7 @@ namespace MinecraftClient.Protocol.Handlers
{
try
{
List<byte> fields = new List<byte>();
List<byte> fields = new();
fields.AddRange(dataTypes.GetVarInt(EntityID));
fields.AddRange(dataTypes.GetVarInt(type));
@ -2618,7 +2624,7 @@ namespace MinecraftClient.Protocol.Handlers
{
try
{
List<byte> fields = new List<byte>();
List<byte> fields = new();
fields.AddRange(dataTypes.GetVarInt(EntityID));
fields.AddRange(dataTypes.GetVarInt(type));
fields.AddRange(dataTypes.GetFloat(X));
@ -2641,7 +2647,7 @@ namespace MinecraftClient.Protocol.Handlers
{
try
{
List<byte> fields = new List<byte>();
List<byte> fields = new();
fields.AddRange(dataTypes.GetVarInt(EntityID));
fields.AddRange(dataTypes.GetVarInt(type));
fields.AddRange(dataTypes.GetVarInt(hand));
@ -2671,7 +2677,7 @@ namespace MinecraftClient.Protocol.Handlers
// TODO once Player Block Placement is implemented for older versions
try
{
List<byte> packet = new List<byte>();
List<byte> packet = new();
packet.AddRange(dataTypes.GetVarInt(hand));
if (protocolVersion >= MC_1_19_Version)
packet.AddRange(dataTypes.GetVarInt(sequenceId));
@ -2687,7 +2693,7 @@ namespace MinecraftClient.Protocol.Handlers
{
try
{
List<byte> packet = new List<byte>();
List<byte> packet = new();
packet.AddRange(dataTypes.GetVarInt(status));
packet.AddRange(dataTypes.GetLocation(location));
packet.AddRange(dataTypes.GetVarInt(dataTypes.GetBlockFace(face)));
@ -2707,7 +2713,7 @@ namespace MinecraftClient.Protocol.Handlers
return false; // NOT IMPLEMENTED for older MC versions
try
{
List<byte> packet = new List<byte>();
List<byte> packet = new();
packet.AddRange(dataTypes.GetVarInt(hand));
packet.AddRange(dataTypes.GetLocation(location));
packet.AddRange(dataTypes.GetVarInt(dataTypes.GetBlockFace(face)));
@ -2729,7 +2735,7 @@ namespace MinecraftClient.Protocol.Handlers
{
try
{
List<byte> packet = new List<byte>();
List<byte> packet = new();
packet.AddRange(dataTypes.GetShort(slot));
SendPacket(PacketTypesOut.HeldItemChange, packet);
return true;
@ -2774,8 +2780,10 @@ namespace MinecraftClient.Protocol.Handlers
case WindowActionType.AddDragMiddle: button = 9; mode = 5; item = new Item(ItemType.Null, 0, null); break;
}
List<byte> packet = new();
packet.Add((byte)windowId); // Window ID
List<byte> packet = new()
{
(byte)windowId // Window ID
};
// 1.18+
if (protocolVersion >= MC_1_18_1_Version)
@ -2829,7 +2837,7 @@ namespace MinecraftClient.Protocol.Handlers
{
try
{
List<byte> packet = new List<byte>();
List<byte> packet = new();
packet.AddRange(dataTypes.GetShort((short)slot));
packet.AddRange(dataTypes.GetItemSlot(new Item(itemType, count, nbt), itemPalette));
SendPacket(PacketTypesOut.CreativeInventoryAction, packet);
@ -2846,7 +2854,7 @@ namespace MinecraftClient.Protocol.Handlers
{
if (animation == 0 || animation == 1)
{
List<byte> packet = new List<byte>();
List<byte> packet = new();
if (protocolVersion < MC_1_8_Version)
{
@ -2897,15 +2905,15 @@ namespace MinecraftClient.Protocol.Handlers
try
{
if (line1.Length > 23)
line1 = line1.Substring(0, 23);
line1 = line1[..23];
if (line2.Length > 23)
line2 = line1.Substring(0, 23);
line2 = line1[..23];
if (line3.Length > 23)
line3 = line1.Substring(0, 23);
line3 = line1[..23];
if (line4.Length > 23)
line4 = line1.Substring(0, 23);
line4 = line1[..23];
List<byte> packet = new List<byte>();
List<byte> packet = new();
packet.AddRange(dataTypes.GetLocation(sign));
packet.AddRange(dataTypes.GetString(line1));
packet.AddRange(dataTypes.GetString(line2));
@ -2925,7 +2933,7 @@ namespace MinecraftClient.Protocol.Handlers
{
try
{
List<byte> packet = new List<byte>();
List<byte> packet = new();
packet.AddRange(dataTypes.GetLocation(location));
packet.AddRange(dataTypes.GetString(command));
packet.AddRange(dataTypes.GetVarInt((int)mode));
@ -2944,7 +2952,7 @@ namespace MinecraftClient.Protocol.Handlers
{
try
{
List<byte> packet = new List<byte>();
List<byte> packet = new();
packet.Add(windowID);
packet.AddRange(dataTypes.GetShort(actionID));
packet.Add(accepted ? (byte)1 : (byte)0);
@ -2963,7 +2971,7 @@ namespace MinecraftClient.Protocol.Handlers
{
try
{
List<byte> packet = new List<byte>();
List<byte> packet = new();
packet.AddRange(dataTypes.GetVarInt(selectedSlot));
SendPacket(PacketTypesOut.SelectTrade, packet);
return true;
@ -2982,7 +2990,7 @@ namespace MinecraftClient.Protocol.Handlers
{
try
{
List<byte> packet = new List<byte>();
List<byte> packet = new();
packet.AddRange(dataTypes.GetUUID(UUID));
SendPacket(PacketTypesOut.Spectate, packet);
return true;

View file

@ -2,8 +2,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MinecraftClient.Protocol.Handlers.Forge;
using System.Threading;
using MinecraftClient.Protocol.Handlers.Forge;
namespace MinecraftClient.Protocol.Handlers
{
@ -12,12 +12,12 @@ namespace MinecraftClient.Protocol.Handlers
/// </summary>
class Protocol18Forge
{
private int protocolversion;
private DataTypes dataTypes;
private Protocol18Handler protocol18;
private IMinecraftComHandler mcHandler;
private readonly int protocolversion;
private readonly DataTypes dataTypes;
private readonly Protocol18Handler protocol18;
private readonly IMinecraftComHandler mcHandler;
private ForgeInfo forgeInfo;
private readonly ForgeInfo? forgeInfo;
private FMLHandshakeClientState fmlHandshakeState = FMLHandshakeClientState.START;
private bool ForgeEnabled() { return forgeInfo != null; }
@ -27,10 +27,10 @@ namespace MinecraftClient.Protocol.Handlers
/// <param name="forgeInfo">Forge Server Information</param>
/// <param name="protocolVersion">Minecraft protocol version</param>
/// <param name="dataTypes">Minecraft data types handler</param>
public Protocol18Forge(ForgeInfo forgeInfo, int protocolVersion, DataTypes dataTypes, Protocol18Handler protocol18, IMinecraftComHandler mcHandler)
public Protocol18Forge(ForgeInfo? forgeInfo, int protocolVersion, DataTypes dataTypes, Protocol18Handler protocol18, IMinecraftComHandler mcHandler)
{
this.forgeInfo = forgeInfo;
this.protocolversion = protocolVersion;
protocolversion = protocolVersion;
this.dataTypes = dataTypes;
this.protocol18 = protocol18;
this.mcHandler = mcHandler;
@ -44,7 +44,7 @@ namespace MinecraftClient.Protocol.Handlers
public string GetServerAddress(string serverAddress)
{
if (ForgeEnabled())
return serverAddress + "\0" + forgeInfo.Version + "\0";
return serverAddress + "\0" + forgeInfo!.Version + "\0";
return serverAddress;
}
@ -54,7 +54,7 @@ namespace MinecraftClient.Protocol.Handlers
/// <returns>Whether the handshake was successful.</returns>
public bool CompleteForgeHandshake()
{
if (ForgeEnabled() && forgeInfo.Version == FMLVersion.FML)
if (ForgeEnabled() && forgeInfo!.Version == FMLVersion.FML)
{
while (fmlHandshakeState != FMLHandshakeClientState.DONE)
{
@ -103,7 +103,7 @@ namespace MinecraftClient.Protocol.Handlers
/// <returns>TRUE if the plugin message was recognized and handled</returns>
public bool HandlePluginMessage(string channel, Queue<byte> packetData, ref int currentDimension)
{
if (ForgeEnabled() && forgeInfo.Version == FMLVersion.FML && fmlHandshakeState != FMLHandshakeClientState.DONE)
if (ForgeEnabled() && forgeInfo!.Version == FMLVersion.FML && fmlHandshakeState != FMLHandshakeClientState.DONE)
{
if (channel == "FML|HS")
{
@ -239,7 +239,7 @@ namespace MinecraftClient.Protocol.Handlers
/// <returns>TRUE/FALSE depending on whether the packet was understood or not</returns>
public bool HandleLoginPluginRequest(string channel, Queue<byte> packetData, ref List<byte> responseData)
{
if (ForgeEnabled() && forgeInfo.Version == FMLVersion.FML2 && channel == "fml:loginwrapper")
if (ForgeEnabled() && forgeInfo!.Version == FMLVersion.FML2 && channel == "fml:loginwrapper")
{
// Forge Handshake handler source code used to implement the FML2 packets:
// https://github.com/MinecraftForge/MinecraftForge/blob/master/src/main/java/net/minecraftforge/fml/network/FMLNetworkConstants.java
@ -283,7 +283,7 @@ namespace MinecraftClient.Protocol.Handlers
if (fmlChannel == "fml:handshake")
{
bool fmlResponseReady = false;
List<byte> fmlResponsePacket = new List<byte>();
List<byte> fmlResponsePacket = new();
switch (packetID)
{
@ -303,17 +303,17 @@ namespace MinecraftClient.Protocol.Handlers
if (Settings.DebugMessages)
Translations.WriteLineFormatted("forge.fml2.mod");
List<string> mods = new List<string>();
List<string> mods = new();
int modCount = dataTypes.ReadNextVarInt(packetData);
for (int i = 0; i < modCount; i++)
mods.Add(dataTypes.ReadNextString(packetData));
Dictionary<string, string> channels = new Dictionary<string, string>();
Dictionary<string, string> channels = new();
int channelCount = dataTypes.ReadNextVarInt(packetData);
for (int i = 0; i < channelCount; i++)
channels.Add(dataTypes.ReadNextString(packetData), dataTypes.ReadNextString(packetData));
List<string> registries = new List<string>();
List<string> registries = new();
int registryCount = dataTypes.ReadNextVarInt(packetData);
for (int i = 0; i < registryCount; i++)
registries.Add(dataTypes.ReadNextString(packetData));

View file

@ -3,8 +3,6 @@ using System.Collections.Generic;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
//using System.Linq;
//using System.Text;
using MinecraftClient.Mapping;
@ -16,9 +14,9 @@ namespace MinecraftClient.Protocol.Handlers
/// </summary>
class Protocol18Terrain
{
private int protocolversion;
private DataTypes dataTypes;
private IMinecraftComHandler handler;
private readonly int protocolversion;
private readonly DataTypes dataTypes;
private readonly IMinecraftComHandler handler;
/// <summary>
/// Initialize a new Terrain Decoder
@ -27,7 +25,7 @@ namespace MinecraftClient.Protocol.Handlers
/// <param name="dataTypes">Minecraft Protocol Data Types</param>
public Protocol18Terrain(int protocolVersion, DataTypes dataTypes, IMinecraftComHandler handler)
{
this.protocolversion = protocolVersion;
protocolversion = protocolVersion;
this.dataTypes = dataTypes;
this.handler = handler;
}
@ -179,7 +177,7 @@ namespace MinecraftClient.Protocol.Handlers
// 1.18 and above always contains all chunk section in data
// 1.17 and 1.17.1 need vertical strip bitmask to know if the chunk section is included
if ((protocolversion >= Protocol18Handler.MC_1_18_1_Version) ||
if ((protocolversion >= Protocol18Handler.MC_1_18_1_Version) ||
((verticalStripBitmask![chunkY / 64] & (1UL << (chunkY % 64))) != 0))
{
// Non-air block count inside chunk section, for lighting purposes
@ -277,7 +275,7 @@ namespace MinecraftClient.Protocol.Handlers
// Block IDs are packed in the array of 64-bits integers
ulong[] dataArray = dataTypes.ReadNextULongArray(cache);
Chunk chunk = new Chunk();
Chunk chunk = new();
if (dataArray.Length > 0)
{
@ -399,10 +397,10 @@ namespace MinecraftClient.Protocol.Handlers
{
if ((chunkMask & (1 << chunkY)) != 0)
{
Chunk chunk = new Chunk();
Chunk chunk = new();
//Read chunk data, all at once for performance reasons, and build the chunk object
Queue<ushort> queue = new Queue<ushort>(dataTypes.ReadNextUShortsLittleEndian(Chunk.SizeX * Chunk.SizeY * Chunk.SizeZ, cache));
Queue<ushort> queue = new(dataTypes.ReadNextUShortsLittleEndian(Chunk.SizeX * Chunk.SizeY * Chunk.SizeZ, cache));
for (int blockY = 0; blockY < Chunk.SizeY; blockY++)
for (int blockZ = 0; blockZ < Chunk.SizeZ; blockZ++)
for (int blockX = 0; blockX < Chunk.SizeX; blockX++)
@ -457,8 +455,8 @@ namespace MinecraftClient.Protocol.Handlers
}
//Read chunk data, unpacking 4-bit values into 8-bit values for block metadata
Queue<byte> blockTypes = new Queue<byte>(dataTypes.ReadData(Chunk.SizeX * Chunk.SizeY * Chunk.SizeZ * sectionCount, cache));
Queue<byte> blockMeta = new Queue<byte>();
Queue<byte> blockTypes = new(dataTypes.ReadData(Chunk.SizeX * Chunk.SizeY * Chunk.SizeZ * sectionCount, cache));
Queue<byte> blockMeta = new();
foreach (byte packed in dataTypes.ReadData((Chunk.SizeX * Chunk.SizeY * Chunk.SizeZ * sectionCount) / 2, cache))
{
byte hig = (byte)(packed >> 4);
@ -481,7 +479,7 @@ namespace MinecraftClient.Protocol.Handlers
{
if ((chunkMask & (1 << chunkY)) != 0)
{
Chunk chunk = new Chunk();
Chunk chunk = new();
for (int blockY = 0; blockY < Chunk.SizeY; blockY++)
for (int blockZ = 0; blockZ < Chunk.SizeZ; blockZ++)

View file

@ -9,8 +9,8 @@ namespace MinecraftClient.Protocol.Handlers
/// </summary>
class SocketWrapper
{
TcpClient c;
AesCfb8Stream s;
readonly TcpClient c;
AesCfb8Stream? s;
bool encrypted = false;
/// <summary>
@ -19,7 +19,7 @@ namespace MinecraftClient.Protocol.Handlers
/// <param name="client">TcpClient connected to the server</param>
public SocketWrapper(TcpClient client)
{
this.c = client;
c = client;
}
/// <summary>
@ -49,8 +49,8 @@ namespace MinecraftClient.Protocol.Handlers
{
if (encrypted)
throw new InvalidOperationException("Stream is already encrypted!?");
this.s = new AesCfb8Stream(c.GetStream(), secretKey);
this.encrypted = true;
s = new AesCfb8Stream(c.GetStream(), secretKey);
encrypted = true;
}
/// <summary>
@ -62,10 +62,9 @@ namespace MinecraftClient.Protocol.Handlers
while (read < offset)
{
if (encrypted)
{
read += s.Read(buffer, start + read, offset - read);
}
else read += c.Client.Receive(buffer, start + read, offset - read, f);
read += s!.Read(buffer, start + read, offset - read);
else
read += c.Client.Receive(buffer, start + read, offset - read, f);
}
}
@ -92,10 +91,9 @@ namespace MinecraftClient.Protocol.Handlers
public void SendDataRAW(byte[] buffer)
{
if (encrypted)
{
s.Write(buffer, 0, buffer.Length);
}
else c.Client.Send(buffer);
s!.Write(buffer, 0, buffer.Length);
else
c.Client.Send(buffer);
}
/// <summary>

View file

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using Ionic.Zlib;
using Ionic.Zlib;
namespace MinecraftClient.Protocol.Handlers
{
@ -23,9 +18,9 @@ namespace MinecraftClient.Protocol.Handlers
public static byte[] Compress(byte[] to_compress)
{
byte[] data;
using (System.IO.MemoryStream memstream = new System.IO.MemoryStream())
using (System.IO.MemoryStream memstream = new())
{
using (ZlibStream stream = new ZlibStream(memstream, CompressionMode.Compress))
using (ZlibStream stream = new(memstream, CompressionMode.Compress))
{
stream.Write(to_compress, 0, to_compress.Length);
}
@ -42,7 +37,7 @@ namespace MinecraftClient.Protocol.Handlers
/// <returns>Decompressed data as a byte array</returns>
public static byte[] Decompress(byte[] to_decompress, int size_uncompressed)
{
ZlibStream stream = new ZlibStream(new System.IO.MemoryStream(to_decompress, false), CompressionMode.Decompress);
ZlibStream stream = new(new System.IO.MemoryStream(to_decompress, false), CompressionMode.Decompress);
byte[] packetData_decompressed = new byte[size_uncompressed];
stream.Read(packetData_decompressed, 0, size_uncompressed);
stream.Close();
@ -56,15 +51,13 @@ namespace MinecraftClient.Protocol.Handlers
/// <returns>Decompressed data as byte array</returns>
public static byte[] Decompress(byte[] to_decompress)
{
ZlibStream stream = new ZlibStream(new System.IO.MemoryStream(to_decompress, false), CompressionMode.Decompress);
ZlibStream stream = new(new System.IO.MemoryStream(to_decompress, false), CompressionMode.Decompress);
byte[] buffer = new byte[16 * 1024];
using (System.IO.MemoryStream decompressedBuffer = new System.IO.MemoryStream())
{
int read;
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
decompressedBuffer.Write(buffer, 0, read);
return decompressedBuffer.ToArray();
}
using System.IO.MemoryStream decompressedBuffer = new();
int read;
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
decompressedBuffer.Write(buffer, 0, read);
return decompressedBuffer.ToArray();
}
}
}