Add the code from SharpZipLib that de4dot uses

This commit is contained in:
de4dot 2012-06-11 21:18:03 +02:00
parent b964996388
commit 31118c11ba
12 changed files with 2377 additions and 9 deletions

Binary file not shown.

View File

@ -32,8 +32,3 @@
</LICENSE>
Official site: http://www.icsharpcode.net/opensource/sharpziplib/
de4dot is using the library compiled by the official developers which you
can get here (see the offical site for the source code):
http://sourceforge.net/projects/sharpdevelop/files/SharpZipLib/0.86/SharpZipLib_0860_Bin.zip/download
(the one compiled for .NET 2.0).

View File

@ -0,0 +1,237 @@
// Adler32.cs - Computes Adler32 data checksum of a data stream
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
namespace ICSharpCode.SharpZipLib.Checksums
{
/// <summary>
/// Computes Adler32 checksum for a stream of data. An Adler32
/// checksum is not as reliable as a CRC32 checksum, but a lot faster to
/// compute.
///
/// The specification for Adler32 may be found in RFC 1950.
/// ZLIB Compressed Data Format Specification version 3.3)
///
///
/// From that document:
///
/// "ADLER32 (Adler-32 checksum)
/// This contains a checksum value of the uncompressed data
/// (excluding any dictionary data) computed according to Adler-32
/// algorithm. This algorithm is a 32-bit extension and improvement
/// of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073
/// standard.
///
/// Adler-32 is composed of two sums accumulated per byte: s1 is
/// the sum of all bytes, s2 is the sum of all s1 values. Both sums
/// are done modulo 65521. s1 is initialized to 1, s2 to zero. The
/// Adler-32 checksum is stored as s2*65536 + s1 in most-
/// significant-byte first (network) order."
///
/// "8.2. The Adler-32 algorithm
///
/// The Adler-32 algorithm is much faster than the CRC32 algorithm yet
/// still provides an extremely low probability of undetected errors.
///
/// The modulo on unsigned long accumulators can be delayed for 5552
/// bytes, so the modulo operation time is negligible. If the bytes
/// are a, b, c, the second sum is 3a + 2b + c + 3, and so is position
/// and order sensitive, unlike the first sum, which is just a
/// checksum. That 65521 is prime is important to avoid a possible
/// large class of two-byte errors that leave the check unchanged.
/// (The Fletcher checksum uses 255, which is not prime and which also
/// makes the Fletcher check insensitive to single byte changes 0 -
/// 255.)
///
/// The sum s1 is initialized to 1 instead of zero to make the length
/// of the sequence part of s2, so that the length does not have to be
/// checked separately. (Any sequence of zeroes has a Fletcher
/// checksum of zero.)"
/// </summary>
/// <see cref="ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream"/>
/// <see cref="ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream"/>
public sealed class Adler32 : IChecksum
{
/// <summary>
/// largest prime smaller than 65536
/// </summary>
const uint BASE = 65521;
/// <summary>
/// Returns the Adler32 data checksum computed so far.
/// </summary>
public long Value {
get {
return checksum;
}
}
/// <summary>
/// Creates a new instance of the Adler32 class.
/// The checksum starts off with a value of 1.
/// </summary>
public Adler32()
{
Reset();
}
/// <summary>
/// Resets the Adler32 checksum to the initial value.
/// </summary>
public void Reset()
{
checksum = 1;
}
/// <summary>
/// Updates the checksum with a byte value.
/// </summary>
/// <param name="value">
/// The data value to add. The high byte of the int is ignored.
/// </param>
public void Update(int value)
{
// We could make a length 1 byte array and call update again, but I
// would rather not have that overhead
uint s1 = checksum & 0xFFFF;
uint s2 = checksum >> 16;
s1 = (s1 + ((uint)value & 0xFF)) % BASE;
s2 = (s1 + s2) % BASE;
checksum = (s2 << 16) + s1;
}
/// <summary>
/// Updates the checksum with an array of bytes.
/// </summary>
/// <param name="buffer">
/// The source of the data to update with.
/// </param>
public void Update(byte[] buffer)
{
if ( buffer == null ) {
throw new ArgumentNullException("buffer");
}
Update(buffer, 0, buffer.Length);
}
/// <summary>
/// Updates the checksum with the bytes taken from the array.
/// </summary>
/// <param name="buffer">
/// an array of bytes
/// </param>
/// <param name="offset">
/// the start of the data used for this update
/// </param>
/// <param name="count">
/// the number of bytes to use for this update
/// </param>
public void Update(byte[] buffer, int offset, int count)
{
if (buffer == null) {
throw new ArgumentNullException("buffer");
}
if (offset < 0) {
#if NETCF_1_0
throw new ArgumentOutOfRangeException("offset");
#else
throw new ArgumentOutOfRangeException("offset", "cannot be negative");
#endif
}
if ( count < 0 )
{
#if NETCF_1_0
throw new ArgumentOutOfRangeException("count");
#else
throw new ArgumentOutOfRangeException("count", "cannot be negative");
#endif
}
if (offset >= buffer.Length)
{
#if NETCF_1_0
throw new ArgumentOutOfRangeException("offset");
#else
throw new ArgumentOutOfRangeException("offset", "not a valid index into buffer");
#endif
}
if (offset + count > buffer.Length)
{
#if NETCF_1_0
throw new ArgumentOutOfRangeException("count");
#else
throw new ArgumentOutOfRangeException("count", "exceeds buffer size");
#endif
}
//(By Per Bothner)
uint s1 = checksum & 0xFFFF;
uint s2 = checksum >> 16;
while (count > 0) {
// We can defer the modulo operation:
// s1 maximally grows from 65521 to 65521 + 255 * 3800
// s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31
int n = 3800;
if (n > count) {
n = count;
}
count -= n;
while (--n >= 0) {
s1 = s1 + (uint)(buffer[offset++] & 0xff);
s2 = s2 + s1;
}
s1 %= BASE;
s2 %= BASE;
}
checksum = (s2 << 16) | s1;
}
#region Instance Fields
uint checksum;
#endregion
}
}

View File

@ -0,0 +1,93 @@
// IChecksum.cs - Interface to compute a data checksum
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
namespace ICSharpCode.SharpZipLib.Checksums
{
/// <summary>
/// Interface to compute a data checksum used by checked input/output streams.
/// A data checksum can be updated by one byte or with a byte array. After each
/// update the value of the current checksum can be returned by calling
/// <code>getValue</code>. The complete checksum object can also be reset
/// so it can be used again with new data.
/// </summary>
public interface IChecksum
{
/// <summary>
/// Returns the data checksum computed so far.
/// </summary>
long Value
{
get;
}
/// <summary>
/// Resets the data checksum as if no update was ever called.
/// </summary>
void Reset();
/// <summary>
/// Adds one byte to the data checksum.
/// </summary>
/// <param name = "value">
/// the data value to add. The high byte of the int is ignored.
/// </param>
void Update(int value);
/// <summary>
/// Updates the data checksum with the bytes taken from the array.
/// </summary>
/// <param name="buffer">
/// buffer an array of bytes
/// </param>
void Update(byte[] buffer);
/// <summary>
/// Adds the byte array to the data checksum.
/// </summary>
/// <param name = "buffer">
/// The buffer which contains the data
/// </param>
/// <param name = "offset">
/// The offset in the buffer where the data starts
/// </param>
/// <param name = "count">
/// the number of data bytes to add.
/// </param>
void Update(byte[] buffer, int offset, int count);
}
}

View File

@ -0,0 +1,36 @@
// Main.cs
//
// Copyright (C) 2001 Mike Krueger
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
//

View File

@ -0,0 +1,94 @@
// SharpZipBaseException.cs
//
// Copyright 2004 John Reilly
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
#if !NETCF_1_0 && !NETCF_2_0
using System.Runtime.Serialization;
#endif
namespace ICSharpCode.SharpZipLib
{
/// <summary>
/// SharpZipBaseException is the base exception class for the SharpZipLibrary.
/// All library exceptions are derived from this.
/// </summary>
/// <remarks>NOTE: Not all exceptions thrown will be derived from this class.
/// A variety of other exceptions are possible for example <see cref="ArgumentNullException"></see></remarks>
#if !NETCF_1_0 && !NETCF_2_0
[Serializable]
#endif
public class SharpZipBaseException : ApplicationException
{
#if !NETCF_1_0 && !NETCF_2_0
/// <summary>
/// Deserialization constructor
/// </summary>
/// <param name="info"><see cref="System.Runtime.Serialization.SerializationInfo"/> for this constructor</param>
/// <param name="context"><see cref="StreamingContext"/> for this constructor</param>
protected SharpZipBaseException(SerializationInfo info, StreamingContext context )
: base( info, context )
{
}
#endif
/// <summary>
/// Initializes a new instance of the SharpZipBaseException class.
/// </summary>
public SharpZipBaseException()
{
}
/// <summary>
/// Initializes a new instance of the SharpZipBaseException class with a specified error message.
/// </summary>
/// <param name="message">A message describing the exception.</param>
public SharpZipBaseException(string message)
: base(message)
{
}
/// <summary>
/// Initializes a new instance of the SharpZipBaseException class with a specified
/// error message and a reference to the inner exception that is the cause of this exception.
/// </summary>
/// <param name="message">A message describing the exception.</param>
/// <param name="innerException">The inner exception</param>
public SharpZipBaseException(string message, Exception innerException)
: base(message, innerException)
{
}
}
}

View File

@ -0,0 +1,894 @@
// Inflater.cs
//
// Copyright (C) 2001 Mike Krueger
// Copyright (C) 2004 John Reilly
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
namespace ICSharpCode.SharpZipLib.Zip.Compression
{
/// <summary>
/// Inflater is used to decompress data that has been compressed according
/// to the "deflate" standard described in rfc1951.
///
/// By default Zlib (rfc1950) headers and footers are expected in the input.
/// You can use constructor <code> public Inflater(bool noHeader)</code> passing true
/// if there is no Zlib header information
///
/// The usage is as following. First you have to set some input with
/// <code>SetInput()</code>, then Inflate() it. If inflate doesn't
/// inflate any bytes there may be three reasons:
/// <ul>
/// <li>IsNeedingInput() returns true because the input buffer is empty.
/// You have to provide more input with <code>SetInput()</code>.
/// NOTE: IsNeedingInput() also returns true when, the stream is finished.
/// </li>
/// <li>IsNeedingDictionary() returns true, you have to provide a preset
/// dictionary with <code>SetDictionary()</code>.</li>
/// <li>IsFinished returns true, the inflater has finished.</li>
/// </ul>
/// Once the first output byte is produced, a dictionary will not be
/// needed at a later stage.
///
/// author of the original java version : John Leuner, Jochen Hoenicke
/// </summary>
public class Inflater
{
#region Constants/Readonly
/// <summary>
/// Copy lengths for literal codes 257..285
/// </summary>
static readonly int[] CPLENS = {
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
};
/// <summary>
/// Extra bits for literal codes 257..285
/// </summary>
static readonly int[] CPLEXT = {
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
};
/// <summary>
/// Copy offsets for distance codes 0..29
/// </summary>
static readonly int[] CPDIST = {
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
};
/// <summary>
/// Extra bits for distance codes
/// </summary>
static readonly int[] CPDEXT = {
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
};
/// <summary>
/// These are the possible states for an inflater
/// </summary>
const int DECODE_HEADER = 0;
const int DECODE_DICT = 1;
const int DECODE_BLOCKS = 2;
const int DECODE_STORED_LEN1 = 3;
//const int DECODE_STORED_LEN2 = 4;
const int DECODE_STORED = 5;
const int DECODE_DYN_HEADER = 6;
const int DECODE_HUFFMAN = 7;
const int DECODE_HUFFMAN_LENBITS = 8;
const int DECODE_HUFFMAN_DIST = 9;
const int DECODE_HUFFMAN_DISTBITS = 10;
const int DECODE_CHKSUM = 11;
const int FINISHED = 12;
public const int DEFLATED = 8;
/// <summary>
/// Written to Zip file to identify a stored block
/// </summary>
public const int STORED_BLOCK = 0;
/// <summary>
/// Identifies static tree in Zip file
/// </summary>
public const int STATIC_TREES = 1;
/// <summary>
/// Identifies dynamic tree in Zip file
/// </summary>
public const int DYN_TREES = 2;
#endregion
#region Instance Fields
/// <summary>
/// This variable contains the current state.
/// </summary>
int mode;
/// <summary>
/// The adler checksum of the dictionary or of the decompressed
/// stream, as it is written in the header resp. footer of the
/// compressed stream.
/// Only valid if mode is DECODE_DICT or DECODE_CHKSUM.
/// </summary>
int readAdler;
/// <summary>
/// The number of bits needed to complete the current state. This
/// is valid, if mode is DECODE_DICT, DECODE_CHKSUM,
/// DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS.
/// </summary>
int neededBits;
int repLength;
int repDist;
protected int uncomprLen;
/// <summary>
/// True, if the last block flag was set in the last block of the
/// inflated stream. This means that the stream ends after the
/// current block.
/// </summary>
bool isLastBlock;
/// <summary>
/// The total number of inflated bytes.
/// </summary>
long totalOut;
/// <summary>
/// The total number of bytes set with setInput(). This is not the
/// value returned by the TotalIn property, since this also includes the
/// unprocessed input.
/// </summary>
long totalIn;
/// <summary>
/// This variable stores the noHeader flag that was given to the constructor.
/// True means, that the inflated stream doesn't contain a Zlib header or
/// footer.
/// </summary>
bool noHeader;
protected StreamManipulator input;
OutputWindow outputWindow;
InflaterDynHeader dynHeader;
InflaterHuffmanTree litlenTree, distTree;
Adler32 adler;
#endregion
#region Constructors
/// <summary>
/// Creates a new inflater or RFC1951 decompressor
/// RFC1950/Zlib headers and footers will be expected in the input data
/// </summary>
public Inflater() : this(false)
{
}
/// <summary>
/// Creates a new inflater.
/// </summary>
/// <param name="noHeader">
/// True if no RFC1950/Zlib header and footer fields are expected in the input data
///
/// This is used for GZIPed/Zipped input.
///
/// For compatibility with
/// Sun JDK you should provide one byte of input more than needed in
/// this case.
/// </param>
public Inflater(bool noHeader)
{
this.noHeader = noHeader;
this.adler = new Adler32();
input = new StreamManipulator();
outputWindow = new OutputWindow();
mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER;
}
#endregion
/// <summary>
/// Resets the inflater so that a new stream can be decompressed. All
/// pending input and output will be discarded.
/// </summary>
public void Reset()
{
mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER;
totalIn = 0;
totalOut = 0;
input.Reset();
outputWindow.Reset();
dynHeader = null;
litlenTree = null;
distTree = null;
isLastBlock = false;
adler.Reset();
}
/// <summary>
/// Decodes a zlib/RFC1950 header.
/// </summary>
/// <returns>
/// False if more input is needed.
/// </returns>
/// <exception cref="SharpZipBaseException">
/// The header is invalid.
/// </exception>
private bool DecodeHeader()
{
int header = input.PeekBits(16);
if (header < 0) {
return false;
}
input.DropBits(16);
// The header is written in "wrong" byte order
header = ((header << 8) | (header >> 8)) & 0xffff;
if (header % 31 != 0) {
throw new SharpZipBaseException("Header checksum illegal");
}
if ((header & 0x0f00) != (DEFLATED << 8)) {
throw new SharpZipBaseException("Compression Method unknown");
}
/* Maximum size of the backwards window in bits.
* We currently ignore this, but we could use it to make the
* inflater window more space efficient. On the other hand the
* full window (15 bits) is needed most times, anyway.
int max_wbits = ((header & 0x7000) >> 12) + 8;
*/
if ((header & 0x0020) == 0) { // Dictionary flag?
mode = DECODE_BLOCKS;
} else {
mode = DECODE_DICT;
neededBits = 32;
}
return true;
}
/// <summary>
/// Decodes the dictionary checksum after the deflate header.
/// </summary>
/// <returns>
/// False if more input is needed.
/// </returns>
private bool DecodeDict()
{
while (neededBits > 0) {
int dictByte = input.PeekBits(8);
if (dictByte < 0) {
return false;
}
input.DropBits(8);
readAdler = (readAdler << 8) | dictByte;
neededBits -= 8;
}
return false;
}
/// <summary>
/// Decodes the huffman encoded symbols in the input stream.
/// </summary>
/// <returns>
/// false if more input is needed, true if output window is
/// full or the current block ends.
/// </returns>
/// <exception cref="SharpZipBaseException">
/// if deflated stream is invalid.
/// </exception>
private bool DecodeHuffman()
{
int free = outputWindow.GetFreeSpace();
while (free >= 258)
{
int symbol;
switch (mode)
{
case DECODE_HUFFMAN:
// This is the inner loop so it is optimized a bit
while (((symbol = litlenTree.GetSymbol(input)) & ~0xff) == 0)
{
outputWindow.Write(symbol);
if (--free < 258)
{
return true;
}
}
if (symbol < 257)
{
if (symbol < 0)
{
return false;
}
else
{
// symbol == 256: end of block
distTree = null;
litlenTree = null;
mode = DECODE_BLOCKS;
return true;
}
}
try
{
repLength = CPLENS[symbol - 257];
neededBits = CPLEXT[symbol - 257];
}
catch (Exception)
{
throw new SharpZipBaseException("Illegal rep length code");
}
goto case DECODE_HUFFMAN_LENBITS; // fall through
case DECODE_HUFFMAN_LENBITS:
if (neededBits > 0)
{
mode = DECODE_HUFFMAN_LENBITS;
int i = input.PeekBits(neededBits);
if (i < 0)
{
return false;
}
input.DropBits(neededBits);
repLength += i;
}
mode = DECODE_HUFFMAN_DIST;
goto case DECODE_HUFFMAN_DIST; // fall through
case DECODE_HUFFMAN_DIST:
symbol = distTree.GetSymbol(input);
if (symbol < 0)
{
return false;
}
try
{
repDist = CPDIST[symbol];
neededBits = CPDEXT[symbol];
}
catch (Exception)
{
throw new SharpZipBaseException("Illegal rep dist code");
}
goto case DECODE_HUFFMAN_DISTBITS; // fall through
case DECODE_HUFFMAN_DISTBITS:
if (neededBits > 0)
{
mode = DECODE_HUFFMAN_DISTBITS;
int i = input.PeekBits(neededBits);
if (i < 0)
{
return false;
}
input.DropBits(neededBits);
repDist += i;
}
outputWindow.Repeat(repLength, repDist);
free -= repLength;
mode = DECODE_HUFFMAN;
break;
default:
throw new SharpZipBaseException("Inflater unknown mode");
}
}
return true;
}
/// <summary>
/// Decodes the adler checksum after the deflate stream.
/// </summary>
/// <returns>
/// false if more input is needed.
/// </returns>
/// <exception cref="SharpZipBaseException">
/// If checksum doesn't match.
/// </exception>
private bool DecodeChksum()
{
while (neededBits > 0) {
int chkByte = input.PeekBits(8);
if (chkByte < 0) {
return false;
}
input.DropBits(8);
readAdler = (readAdler << 8) | chkByte;
neededBits -= 8;
}
if ((int) adler.Value != readAdler) {
throw new SharpZipBaseException("Adler chksum doesn't match: " + (int)adler.Value + " vs. " + readAdler);
}
mode = FINISHED;
return false;
}
/// <summary>
/// Decodes the deflated stream.
/// </summary>
/// <returns>
/// false if more input is needed, or if finished.
/// </returns>
/// <exception cref="SharpZipBaseException">
/// if deflated stream is invalid.
/// </exception>
private bool Decode()
{
switch (mode) {
case DECODE_HEADER:
return DecodeHeader();
case DECODE_DICT:
return DecodeDict();
case DECODE_CHKSUM:
return DecodeChksum();
case DECODE_BLOCKS:
if (isLastBlock) {
if (noHeader) {
mode = FINISHED;
return false;
} else {
input.SkipToByteBoundary();
neededBits = 32;
mode = DECODE_CHKSUM;
return true;
}
}
int blockType;
if (!ReadHeader(ref isLastBlock, out blockType)) {
return false;
}
switch (blockType){
case STORED_BLOCK:
input.SkipToByteBoundary();
mode = DECODE_STORED_LEN1;
break;
case STATIC_TREES:
litlenTree = InflaterHuffmanTree.defLitLenTree;
distTree = InflaterHuffmanTree.defDistTree;
mode = DECODE_HUFFMAN;
break;
case DYN_TREES:
dynHeader = new InflaterDynHeader();
mode = DECODE_DYN_HEADER;
break;
default:
throw new SharpZipBaseException("Unknown block type " + blockType);
}
return true;
case DECODE_STORED_LEN1:
if (!DecodeStoredLength()) {
return false;
}
mode = DECODE_STORED;
goto case DECODE_STORED; // fall through
case DECODE_STORED:
{
int more = outputWindow.CopyStored(input, uncomprLen);
uncomprLen -= more;
if (uncomprLen == 0) {
mode = DECODE_BLOCKS;
return true;
}
return !input.IsNeedingInput;
}
case DECODE_DYN_HEADER:
if (!dynHeader.Decode(input)) {
return false;
}
litlenTree = dynHeader.BuildLitLenTree();
distTree = dynHeader.BuildDistTree();
mode = DECODE_HUFFMAN;
goto case DECODE_HUFFMAN; // fall through
case DECODE_HUFFMAN:
case DECODE_HUFFMAN_LENBITS:
case DECODE_HUFFMAN_DIST:
case DECODE_HUFFMAN_DISTBITS:
return DecodeHuffman();
case FINISHED:
return false;
default:
throw new SharpZipBaseException("Inflater.Decode unknown mode");
}
}
protected virtual bool ReadHeader(ref bool isLastBlock, out int blockType)
{
int type = input.PeekBits(3);
if (type < 0) {
blockType = -1;
return false;
}
input.DropBits(3);
if ((type & 1) != 0) {
isLastBlock = true;
}
blockType = type >> 1;
return true;
}
protected virtual bool DecodeStoredLength()
{
if ((uncomprLen = input.PeekBits(16)) < 0) {
return false;
}
input.DropBits(16);
int nlen = input.PeekBits(16);
if (nlen < 0) {
return false;
}
input.DropBits(16);
if (nlen != (uncomprLen ^ 0xffff)) {
throw new SharpZipBaseException("broken uncompressed block");
}
return true;
}
/// <summary>
/// Sets the preset dictionary. This should only be called, if
/// needsDictionary() returns true and it should set the same
/// dictionary, that was used for deflating. The getAdler()
/// function returns the checksum of the dictionary needed.
/// </summary>
/// <param name="buffer">
/// The dictionary.
/// </param>
public void SetDictionary(byte[] buffer)
{
SetDictionary(buffer, 0, buffer.Length);
}
/// <summary>
/// Sets the preset dictionary. This should only be called, if
/// needsDictionary() returns true and it should set the same
/// dictionary, that was used for deflating. The getAdler()
/// function returns the checksum of the dictionary needed.
/// </summary>
/// <param name="buffer">
/// The dictionary.
/// </param>
/// <param name="index">
/// The index into buffer where the dictionary starts.
/// </param>
/// <param name="count">
/// The number of bytes in the dictionary.
/// </param>
/// <exception cref="System.InvalidOperationException">
/// No dictionary is needed.
/// </exception>
/// <exception cref="SharpZipBaseException">
/// The adler checksum for the buffer is invalid
/// </exception>
public void SetDictionary(byte[] buffer, int index, int count)
{
if ( buffer == null ) {
throw new ArgumentNullException("buffer");
}
if ( index < 0 ) {
throw new ArgumentOutOfRangeException("index");
}
if ( count < 0 ) {
throw new ArgumentOutOfRangeException("count");
}
if (!IsNeedingDictionary) {
throw new InvalidOperationException("Dictionary is not needed");
}
adler.Update(buffer, index, count);
if ((int)adler.Value != readAdler) {
throw new SharpZipBaseException("Wrong adler checksum");
}
adler.Reset();
outputWindow.CopyDict(buffer, index, count);
mode = DECODE_BLOCKS;
}
/// <summary>
/// Sets the input. This should only be called, if needsInput()
/// returns true.
/// </summary>
/// <param name="buffer">
/// the input.
/// </param>
public void SetInput(byte[] buffer)
{
SetInput(buffer, 0, buffer.Length);
}
/// <summary>
/// Sets the input. This should only be called, if needsInput()
/// returns true.
/// </summary>
/// <param name="buffer">
/// The source of input data
/// </param>
/// <param name="index">
/// The index into buffer where the input starts.
/// </param>
/// <param name="count">
/// The number of bytes of input to use.
/// </param>
/// <exception cref="System.InvalidOperationException">
/// No input is needed.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// The index and/or count are wrong.
/// </exception>
public void SetInput(byte[] buffer, int index, int count)
{
input.SetInput(buffer, index, count);
totalIn += (long)count;
}
/// <summary>
/// Inflates the compressed stream to the output buffer. If this
/// returns 0, you should check, whether IsNeedingDictionary(),
/// IsNeedingInput() or IsFinished() returns true, to determine why no
/// further output is produced.
/// </summary>
/// <param name="buffer">
/// the output buffer.
/// </param>
/// <returns>
/// The number of bytes written to the buffer, 0 if no further
/// output can be produced.
/// </returns>
/// <exception cref="System.ArgumentOutOfRangeException">
/// if buffer has length 0.
/// </exception>
/// <exception cref="System.FormatException">
/// if deflated stream is invalid.
/// </exception>
public int Inflate(byte[] buffer)
{
if ( buffer == null )
{
throw new ArgumentNullException("buffer");
}
return Inflate(buffer, 0, buffer.Length);
}
/// <summary>
/// Inflates the compressed stream to the output buffer. If this
/// returns 0, you should check, whether needsDictionary(),
/// needsInput() or finished() returns true, to determine why no
/// further output is produced.
/// </summary>
/// <param name="buffer">
/// the output buffer.
/// </param>
/// <param name="offset">
/// the offset in buffer where storing starts.
/// </param>
/// <param name="count">
/// the maximum number of bytes to output.
/// </param>
/// <returns>
/// the number of bytes written to the buffer, 0 if no further output can be produced.
/// </returns>
/// <exception cref="System.ArgumentOutOfRangeException">
/// if count is less than 0.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// if the index and / or count are wrong.
/// </exception>
/// <exception cref="System.FormatException">
/// if deflated stream is invalid.
/// </exception>
public int Inflate(byte[] buffer, int offset, int count)
{
if ( buffer == null )
{
throw new ArgumentNullException("buffer");
}
if ( count < 0 ) {
#if NETCF_1_0
throw new ArgumentOutOfRangeException("count");
#else
throw new ArgumentOutOfRangeException("count", "count cannot be negative");
#endif
}
if ( offset < 0 ) {
#if NETCF_1_0
throw new ArgumentOutOfRangeException("offset");
#else
throw new ArgumentOutOfRangeException("offset", "offset cannot be negative");
#endif
}
if ( offset + count > buffer.Length ) {
throw new ArgumentException("count exceeds buffer bounds");
}
// Special case: count may be zero
if (count == 0)
{
if (!IsFinished) { // -jr- 08-Nov-2003 INFLATE_BUG fix..
Decode();
}
return 0;
}
int bytesCopied = 0;
do {
if (mode != DECODE_CHKSUM) {
/* Don't give away any output, if we are waiting for the
* checksum in the input stream.
*
* With this trick we have always:
* IsNeedingInput() and not IsFinished()
* implies more output can be produced.
*/
int more = outputWindow.CopyOutput(buffer, offset, count);
if ( more > 0 ) {
adler.Update(buffer, offset, more);
offset += more;
bytesCopied += more;
totalOut += (long)more;
count -= more;
if (count == 0) {
return bytesCopied;
}
}
}
} while (Decode() || ((outputWindow.GetAvailable() > 0) && (mode != DECODE_CHKSUM)));
return bytesCopied;
}
/// <summary>
/// Returns true, if the input buffer is empty.
/// You should then call setInput().
/// NOTE: This method also returns true when the stream is finished.
/// </summary>
public bool IsNeedingInput {
get {
return input.IsNeedingInput;
}
}
/// <summary>
/// Returns true, if a preset dictionary is needed to inflate the input.
/// </summary>
public bool IsNeedingDictionary {
get {
return mode == DECODE_DICT && neededBits == 0;
}
}
/// <summary>
/// Returns true, if the inflater has finished. This means, that no
/// input is needed and no output can be produced.
/// </summary>
public bool IsFinished {
get {
return mode == FINISHED && outputWindow.GetAvailable() == 0;
}
}
/// <summary>
/// Gets the adler checksum. This is either the checksum of all
/// uncompressed bytes returned by inflate(), or if needsDictionary()
/// returns true (and thus no output was yet produced) this is the
/// adler checksum of the expected dictionary.
/// </summary>
/// <returns>
/// the adler checksum.
/// </returns>
public int Adler {
get {
return IsNeedingDictionary ? readAdler : (int) adler.Value;
}
}
/// <summary>
/// Gets the total number of output bytes returned by Inflate().
/// </summary>
/// <returns>
/// the total number of output bytes.
/// </returns>
public long TotalOut {
get {
return totalOut;
}
}
/// <summary>
/// Gets the total number of processed compressed input bytes.
/// </summary>
/// <returns>
/// The total number of bytes of processed input bytes.
/// </returns>
public long TotalIn {
get {
return totalIn - (long)RemainingInput;
}
}
/// <summary>
/// Gets the number of unprocessed input bytes. Useful, if the end of the
/// stream is reached and you want to further process the bytes after
/// the deflate stream.
/// </summary>
/// <returns>
/// The number of bytes of the input which have not been processed.
/// </returns>
public int RemainingInput {
// TODO: This should be a long?
get {
return input.AvailableBytes;
}
}
}
}

View File

@ -0,0 +1,218 @@
// InflaterDynHeader.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
namespace ICSharpCode.SharpZipLib.Zip.Compression
{
class InflaterDynHeader
{
#region Constants
const int LNUM = 0;
const int DNUM = 1;
const int BLNUM = 2;
const int BLLENS = 3;
const int LENS = 4;
const int REPS = 5;
static readonly int[] repMin = { 3, 3, 11 };
static readonly int[] repBits = { 2, 3, 7 };
static readonly int[] BL_ORDER =
{ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
#endregion
#region Constructors
public InflaterDynHeader()
{
}
#endregion
public bool Decode(StreamManipulator input)
{
decode_loop:
for (;;) {
switch (mode) {
case LNUM:
lnum = input.PeekBits(5);
if (lnum < 0) {
return false;
}
lnum += 257;
input.DropBits(5);
// System.err.println("LNUM: "+lnum);
mode = DNUM;
goto case DNUM; // fall through
case DNUM:
dnum = input.PeekBits(5);
if (dnum < 0) {
return false;
}
dnum++;
input.DropBits(5);
// System.err.println("DNUM: "+dnum);
num = lnum+dnum;
litdistLens = new byte[num];
mode = BLNUM;
goto case BLNUM; // fall through
case BLNUM:
blnum = input.PeekBits(4);
if (blnum < 0) {
return false;
}
blnum += 4;
input.DropBits(4);
blLens = new byte[19];
ptr = 0;
// System.err.println("BLNUM: "+blnum);
mode = BLLENS;
goto case BLLENS; // fall through
case BLLENS:
while (ptr < blnum) {
int len = input.PeekBits(3);
if (len < 0) {
return false;
}
input.DropBits(3);
// System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len);
blLens[BL_ORDER[ptr]] = (byte) len;
ptr++;
}
blTree = new InflaterHuffmanTree(blLens);
blLens = null;
ptr = 0;
mode = LENS;
goto case LENS; // fall through
case LENS:
{
int symbol;
while (((symbol = blTree.GetSymbol(input)) & ~15) == 0) {
/* Normal case: symbol in [0..15] */
// System.err.println("litdistLens["+ptr+"]: "+symbol);
litdistLens[ptr++] = lastLen = (byte)symbol;
if (ptr == num) {
/* Finished */
return true;
}
}
/* need more input ? */
if (symbol < 0) {
return false;
}
/* otherwise repeat code */
if (symbol >= 17) {
/* repeat zero */
// System.err.println("repeating zero");
lastLen = 0;
} else {
if (ptr == 0) {
throw new SharpZipBaseException();
}
}
repSymbol = symbol-16;
}
mode = REPS;
goto case REPS; // fall through
case REPS:
{
int bits = repBits[repSymbol];
int count = input.PeekBits(bits);
if (count < 0) {
return false;
}
input.DropBits(bits);
count += repMin[repSymbol];
// System.err.println("litdistLens repeated: "+count);
if (ptr + count > num) {
throw new SharpZipBaseException();
}
while (count-- > 0) {
litdistLens[ptr++] = lastLen;
}
if (ptr == num) {
/* Finished */
return true;
}
}
mode = LENS;
goto decode_loop;
}
}
}
public InflaterHuffmanTree BuildLitLenTree()
{
byte[] litlenLens = new byte[lnum];
Array.Copy(litdistLens, 0, litlenLens, 0, lnum);
return new InflaterHuffmanTree(litlenLens);
}
public InflaterHuffmanTree BuildDistTree()
{
byte[] distLens = new byte[dnum];
Array.Copy(litdistLens, lnum, distLens, 0, dnum);
return new InflaterHuffmanTree(distLens);
}
#region Instance Fields
byte[] blLens;
byte[] litdistLens;
InflaterHuffmanTree blTree;
/// <summary>
/// The current decode mode
/// </summary>
int mode;
int lnum, dnum, blnum, num;
int repSymbol;
byte lastLen;
int ptr;
#endregion
}
}

View File

@ -0,0 +1,264 @@
// InflaterHuffmanTree.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
namespace ICSharpCode.SharpZipLib.Zip.Compression
{
/// <summary>
/// Huffman tree used for inflation
/// </summary>
public class InflaterHuffmanTree
{
#region Constants
const int MAX_BITLEN = 15;
static readonly byte[] bit4Reverse = {
0,
8,
4,
12,
2,
10,
6,
14,
1,
9,
5,
13,
3,
11,
7,
15
};
#endregion
#region Instance Fields
short[] tree;
#endregion
/// <summary>
/// Literal length tree
/// </summary>
public static InflaterHuffmanTree defLitLenTree;
/// <summary>
/// Distance tree
/// </summary>
public static InflaterHuffmanTree defDistTree;
static InflaterHuffmanTree()
{
try {
byte[] codeLengths = new byte[288];
int i = 0;
while (i < 144) {
codeLengths[i++] = 8;
}
while (i < 256) {
codeLengths[i++] = 9;
}
while (i < 280) {
codeLengths[i++] = 7;
}
while (i < 288) {
codeLengths[i++] = 8;
}
defLitLenTree = new InflaterHuffmanTree(codeLengths);
codeLengths = new byte[32];
i = 0;
while (i < 32) {
codeLengths[i++] = 5;
}
defDistTree = new InflaterHuffmanTree(codeLengths);
} catch (Exception) {
throw new SharpZipBaseException("InflaterHuffmanTree: static tree length illegal");
}
}
#region Constructors
/// <summary>
/// Constructs a Huffman tree from the array of code lengths.
/// </summary>
/// <param name = "codeLengths">
/// the array of code lengths
/// </param>
public InflaterHuffmanTree(byte[] codeLengths)
{
BuildTree(codeLengths);
}
#endregion
void BuildTree(byte[] codeLengths)
{
int[] blCount = new int[MAX_BITLEN + 1];
int[] nextCode = new int[MAX_BITLEN + 1];
for (int i = 0; i < codeLengths.Length; i++) {
int bits = codeLengths[i];
if (bits > 0) {
blCount[bits]++;
}
}
int code = 0;
int treeSize = 512;
for (int bits = 1; bits <= MAX_BITLEN; bits++) {
nextCode[bits] = code;
code += blCount[bits] << (16 - bits);
if (bits >= 10) {
/* We need an extra table for bit lengths >= 10. */
int start = nextCode[bits] & 0x1ff80;
int end = code & 0x1ff80;
treeSize += (end - start) >> (16 - bits);
}
}
/* -jr comment this out! doesnt work for dynamic trees and pkzip 2.04g
if (code != 65536)
{
throw new SharpZipBaseException("Code lengths don't add up properly.");
}
*/
/* Now create and fill the extra tables from longest to shortest
* bit len. This way the sub trees will be aligned.
*/
tree = new short[treeSize];
int treePtr = 512;
for (int bits = MAX_BITLEN; bits >= 10; bits--) {
int end = code & 0x1ff80;
code -= blCount[bits] << (16 - bits);
int start = code & 0x1ff80;
for (int i = start; i < end; i += 1 << 7) {
tree[BitReverse(i)] = (short) ((-treePtr << 4) | bits);
treePtr += 1 << (bits-9);
}
}
for (int i = 0; i < codeLengths.Length; i++) {
int bits = codeLengths[i];
if (bits == 0) {
continue;
}
code = nextCode[bits];
int revcode = BitReverse(code);
if (bits <= 9) {
do {
tree[revcode] = (short) ((i << 4) | bits);
revcode += 1 << bits;
} while (revcode < 512);
} else {
int subTree = tree[revcode & 511];
int treeLen = 1 << (subTree & 15);
subTree = -(subTree >> 4);
do {
tree[subTree | (revcode >> 9)] = (short) ((i << 4) | bits);
revcode += 1 << bits;
} while (revcode < treeLen);
}
nextCode[bits] = code + (1 << (16 - bits));
}
}
/// <summary>
/// Reverse the bits of a 16 bit value.
/// </summary>
/// <param name="toReverse">Value to reverse bits</param>
/// <returns>Value with bits reversed</returns>
public static short BitReverse(int toReverse)
{
return (short) (bit4Reverse[toReverse & 0xF] << 12 |
bit4Reverse[(toReverse >> 4) & 0xF] << 8 |
bit4Reverse[(toReverse >> 8) & 0xF] << 4 |
bit4Reverse[toReverse >> 12]);
}
/// <summary>
/// Reads the next symbol from input. The symbol is encoded using the
/// huffman tree.
/// </summary>
/// <param name="input">
/// input the input source.
/// </param>
/// <returns>
/// the next symbol, or -1 if not enough input is available.
/// </returns>
public int GetSymbol(StreamManipulator input)
{
int lookahead, symbol;
if ((lookahead = input.PeekBits(9)) >= 0) {
if ((symbol = tree[lookahead]) >= 0) {
input.DropBits(symbol & 15);
return symbol >> 4;
}
int subtree = -(symbol >> 4);
int bitlen = symbol & 15;
if ((lookahead = input.PeekBits(bitlen)) >= 0) {
symbol = tree[subtree | (lookahead >> 9)];
input.DropBits(symbol & 15);
return symbol >> 4;
} else {
int bits = input.AvailableBits;
lookahead = input.PeekBits(bits);
symbol = tree[subtree | (lookahead >> 9)];
if ((symbol & 15) <= bits) {
input.DropBits(symbol & 15);
return symbol >> 4;
} else {
return -1;
}
}
} else {
int bits = input.AvailableBits;
lookahead = input.PeekBits(bits);
symbol = tree[lookahead];
if (symbol >= 0 && (symbol & 15) <= bits) {
input.DropBits(symbol & 15);
return symbol >> 4;
} else {
return -1;
}
}
}
}
}

View File

@ -0,0 +1,235 @@
// OutputWindow.cs
//
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
{
/// <summary>
/// Contains the output from the Inflation process.
/// We need to have a window so that we can refer backwards into the output stream
/// to repeat stuff.<br/>
/// Author of the original java version : John Leuner
/// </summary>
public class OutputWindow
{
#region Constants
const int WindowSize = 1 << 15;
const int WindowMask = WindowSize - 1;
#endregion
#region Instance Fields
byte[] window = new byte[WindowSize]; //The window is 2^15 bytes
int windowEnd;
int windowFilled;
#endregion
/// <summary>
/// Write a byte to this output window
/// </summary>
/// <param name="value">value to write</param>
/// <exception cref="InvalidOperationException">
/// if window is full
/// </exception>
public void Write(int value)
{
if (windowFilled++ == WindowSize) {
throw new InvalidOperationException("Window full");
}
window[windowEnd++] = (byte) value;
windowEnd &= WindowMask;
}
private void SlowRepeat(int repStart, int length, int distance)
{
while (length-- > 0) {
window[windowEnd++] = window[repStart++];
windowEnd &= WindowMask;
repStart &= WindowMask;
}
}
/// <summary>
/// Append a byte pattern already in the window itself
/// </summary>
/// <param name="length">length of pattern to copy</param>
/// <param name="distance">distance from end of window pattern occurs</param>
/// <exception cref="InvalidOperationException">
/// If the repeated data overflows the window
/// </exception>
public void Repeat(int length, int distance)
{
if ((windowFilled += length) > WindowSize) {
throw new InvalidOperationException("Window full");
}
int repStart = (windowEnd - distance) & WindowMask;
int border = WindowSize - length;
if ( (repStart <= border) && (windowEnd < border) ) {
if (length <= distance) {
System.Array.Copy(window, repStart, window, windowEnd, length);
windowEnd += length;
} else {
// We have to copy manually, since the repeat pattern overlaps.
while (length-- > 0) {
window[windowEnd++] = window[repStart++];
}
}
} else {
SlowRepeat(repStart, length, distance);
}
}
/// <summary>
/// Copy from input manipulator to internal window
/// </summary>
/// <param name="input">source of data</param>
/// <param name="length">length of data to copy</param>
/// <returns>the number of bytes copied</returns>
public int CopyStored(StreamManipulator input, int length)
{
length = Math.Min(Math.Min(length, WindowSize - windowFilled), input.AvailableBytes);
int copied;
int tailLen = WindowSize - windowEnd;
if (length > tailLen) {
copied = input.CopyBytes(window, windowEnd, tailLen);
if (copied == tailLen) {
copied += input.CopyBytes(window, 0, length - tailLen);
}
} else {
copied = input.CopyBytes(window, windowEnd, length);
}
windowEnd = (windowEnd + copied) & WindowMask;
windowFilled += copied;
return copied;
}
/// <summary>
/// Copy dictionary to window
/// </summary>
/// <param name="dictionary">source dictionary</param>
/// <param name="offset">offset of start in source dictionary</param>
/// <param name="length">length of dictionary</param>
/// <exception cref="InvalidOperationException">
/// If window isnt empty
/// </exception>
public void CopyDict(byte[] dictionary, int offset, int length)
{
if ( dictionary == null ) {
throw new ArgumentNullException("dictionary");
}
if (windowFilled > 0) {
throw new InvalidOperationException();
}
if (length > WindowSize) {
offset += length - WindowSize;
length = WindowSize;
}
System.Array.Copy(dictionary, offset, window, 0, length);
windowEnd = length & WindowMask;
}
/// <summary>
/// Get remaining unfilled space in window
/// </summary>
/// <returns>Number of bytes left in window</returns>
public int GetFreeSpace()
{
return WindowSize - windowFilled;
}
/// <summary>
/// Get bytes available for output in window
/// </summary>
/// <returns>Number of bytes filled</returns>
public int GetAvailable()
{
return windowFilled;
}
/// <summary>
/// Copy contents of window to output
/// </summary>
/// <param name="output">buffer to copy to</param>
/// <param name="offset">offset to start at</param>
/// <param name="len">number of bytes to count</param>
/// <returns>The number of bytes copied</returns>
/// <exception cref="InvalidOperationException">
/// If a window underflow occurs
/// </exception>
public int CopyOutput(byte[] output, int offset, int len)
{
int copyEnd = windowEnd;
if (len > windowFilled) {
len = windowFilled;
} else {
copyEnd = (windowEnd - windowFilled + len) & WindowMask;
}
int copied = len;
int tailLen = len - copyEnd;
if (tailLen > 0) {
System.Array.Copy(window, WindowSize - tailLen, output, offset, tailLen);
offset += tailLen;
len = copyEnd;
}
System.Array.Copy(window, copyEnd - len, output, offset, len);
windowFilled -= copied;
if (windowFilled < 0) {
throw new InvalidOperationException();
}
return copied;
}
/// <summary>
/// Reset by clearing window so <see cref="GetAvailable">GetAvailable</see> returns 0
/// </summary>
public void Reset()
{
windowFilled = windowEnd = 0;
}
}
}

View File

@ -0,0 +1,297 @@
// StreamManipulator.cs
//
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
{
/// <summary>
/// This class allows us to retrieve a specified number of bits from
/// the input buffer, as well as copy big byte blocks.
///
/// It uses an int buffer to store up to 31 bits for direct
/// manipulation. This guarantees that we can get at least 16 bits,
/// but we only need at most 15, so this is all safe.
///
/// There are some optimizations in this class, for example, you must
/// never peek more than 8 bits more than needed, and you must first
/// peek bits before you may drop them. This is not a general purpose
/// class but optimized for the behaviour of the Inflater.
///
/// authors of the original java version : John Leuner, Jochen Hoenicke
/// </summary>
public class StreamManipulator
{
#region Constructors
/// <summary>
/// Constructs a default StreamManipulator with all buffers empty
/// </summary>
public StreamManipulator()
{
}
#endregion
/// <summary>
/// Get the next sequence of bits but don't increase input pointer. bitCount must be
/// less or equal 16 and if this call succeeds, you must drop
/// at least n - 8 bits in the next call.
/// </summary>
/// <param name="bitCount">The number of bits to peek.</param>
/// <returns>
/// the value of the bits, or -1 if not enough bits available. */
/// </returns>
public int PeekBits(int bitCount)
{
if (bitsInBuffer_ < bitCount) {
if (windowStart_ == windowEnd_) {
return -1; // ok
}
buffer_ |= (uint)((window_[windowStart_++] & 0xff |
(window_[windowStart_++] & 0xff) << 8) << bitsInBuffer_);
bitsInBuffer_ += 16;
}
return (int)(buffer_ & ((1 << bitCount) - 1));
}
/// <summary>
/// Drops the next n bits from the input. You should have called PeekBits
/// with a bigger or equal n before, to make sure that enough bits are in
/// the bit buffer.
/// </summary>
/// <param name="bitCount">The number of bits to drop.</param>
public void DropBits(int bitCount)
{
buffer_ >>= bitCount;
bitsInBuffer_ -= bitCount;
}
/// <summary>
/// Gets the next n bits and increases input pointer. This is equivalent
/// to <see cref="PeekBits"/> followed by <see cref="DropBits"/>, except for correct error handling.
/// </summary>
/// <param name="bitCount">The number of bits to retrieve.</param>
/// <returns>
/// the value of the bits, or -1 if not enough bits available.
/// </returns>
public int GetBits(int bitCount)
{
int bits = PeekBits(bitCount);
if (bits >= 0) {
DropBits(bitCount);
}
return bits;
}
/// <summary>
/// Gets the number of bits available in the bit buffer. This must be
/// only called when a previous PeekBits() returned -1.
/// </summary>
/// <returns>
/// the number of bits available.
/// </returns>
public int AvailableBits {
get {
return bitsInBuffer_;
}
}
/// <summary>
/// Gets the number of bytes available.
/// </summary>
/// <returns>
/// The number of bytes available.
/// </returns>
public int AvailableBytes {
get {
return windowEnd_ - windowStart_ + (bitsInBuffer_ >> 3);
}
}
/// <summary>
/// Skips to the next byte boundary.
/// </summary>
public void SkipToByteBoundary()
{
buffer_ >>= (bitsInBuffer_ & 7);
bitsInBuffer_ &= ~7;
}
/// <summary>
/// Returns true when SetInput can be called
/// </summary>
public bool IsNeedingInput {
get {
return windowStart_ == windowEnd_;
}
}
/// <summary>
/// Copies bytes from input buffer to output buffer starting
/// at output[offset]. You have to make sure, that the buffer is
/// byte aligned. If not enough bytes are available, copies fewer
/// bytes.
/// </summary>
/// <param name="output">
/// The buffer to copy bytes to.
/// </param>
/// <param name="offset">
/// The offset in the buffer at which copying starts
/// </param>
/// <param name="length">
/// The length to copy, 0 is allowed.
/// </param>
/// <returns>
/// The number of bytes copied, 0 if no bytes were available.
/// </returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Length is less than zero
/// </exception>
/// <exception cref="InvalidOperationException">
/// Bit buffer isnt byte aligned
/// </exception>
public int CopyBytes(byte[] output, int offset, int length)
{
if (length < 0) {
throw new ArgumentOutOfRangeException("length");
}
if ((bitsInBuffer_ & 7) != 0) {
// bits_in_buffer may only be 0 or a multiple of 8
throw new InvalidOperationException("Bit buffer is not byte aligned!");
}
int count = 0;
while ((bitsInBuffer_ > 0) && (length > 0)) {
output[offset++] = (byte) buffer_;
buffer_ >>= 8;
bitsInBuffer_ -= 8;
length--;
count++;
}
if (length == 0) {
return count;
}
int avail = windowEnd_ - windowStart_;
if (length > avail) {
length = avail;
}
System.Array.Copy(window_, windowStart_, output, offset, length);
windowStart_ += length;
if (((windowStart_ - windowEnd_) & 1) != 0) {
// We always want an even number of bytes in input, see peekBits
buffer_ = (uint)(window_[windowStart_++] & 0xff);
bitsInBuffer_ = 8;
}
return count + length;
}
/// <summary>
/// Resets state and empties internal buffers
/// </summary>
public void Reset()
{
buffer_ = 0;
windowStart_ = windowEnd_ = bitsInBuffer_ = 0;
}
/// <summary>
/// Add more input for consumption.
/// Only call when IsNeedingInput returns true
/// </summary>
/// <param name="buffer">data to be input</param>
/// <param name="offset">offset of first byte of input</param>
/// <param name="count">number of bytes of input to add.</param>
public void SetInput(byte[] buffer, int offset, int count)
{
if ( buffer == null ) {
throw new ArgumentNullException("buffer");
}
if ( offset < 0 ) {
#if NETCF_1_0
throw new ArgumentOutOfRangeException("offset");
#else
throw new ArgumentOutOfRangeException("offset", "Cannot be negative");
#endif
}
if ( count < 0 ) {
#if NETCF_1_0
throw new ArgumentOutOfRangeException("count");
#else
throw new ArgumentOutOfRangeException("count", "Cannot be negative");
#endif
}
if (windowStart_ < windowEnd_) {
throw new InvalidOperationException("Old input was not completely processed");
}
int end = offset + count;
// We want to throw an ArrayIndexOutOfBoundsException early.
// Note the check also handles integer wrap around.
if ((offset > end) || (end > buffer.Length) ) {
throw new ArgumentOutOfRangeException("count");
}
if ((count & 1) != 0) {
// We always want an even number of bytes in input, see PeekBits
buffer_ |= (uint)((buffer[offset++] & 0xff) << bitsInBuffer_);
bitsInBuffer_ += 8;
}
window_ = buffer;
windowStart_ = offset;
windowEnd_ = end;
}
#region Instance Fields
private byte[] window_;
private int windowStart_;
private int windowEnd_;
private uint buffer_;
private int bitsInBuffer_;
#endregion
}
}

View File

@ -39,9 +39,6 @@
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="ICSharpCode.SharpZipLib">
<HintPath>..\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Drawing" />
<Reference Include="System.Runtime.Remoting" />
@ -290,6 +287,15 @@
<Compile Include="resources\ResourceWriter.cs" />
<Compile Include="resources\UserResourceData.cs" />
<Compile Include="resources\UserResourceType.cs" />
<Compile Include="SharpZipLib\Checksums\Adler32.cs" />
<Compile Include="SharpZipLib\Checksums\IChecksum.cs" />
<Compile Include="SharpZipLib\Main.cs" />
<Compile Include="SharpZipLib\SharpZipBaseException.cs" />
<Compile Include="SharpZipLib\Zip\Compression\Inflater.cs" />
<Compile Include="SharpZipLib\Zip\Compression\InflaterDynHeader.cs" />
<Compile Include="SharpZipLib\Zip\Compression\InflaterHuffmanTree.cs" />
<Compile Include="SharpZipLib\Zip\Compression\Streams\OutputWindow.cs" />
<Compile Include="SharpZipLib\Zip\Compression\Streams\StreamManipulator.cs" />
<Compile Include="StringInliner.cs" />
<Compile Include="UserException.cs" />
<Compile Include="Utils.cs" />
@ -313,7 +319,6 @@
<Name>de4dot.mdecrypt</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>copy "$(SolutionDir)LICENSE*.txt" "..\$(OutDir).."