First commit
Send all results
This commit is contained in:
@@ -0,0 +1,676 @@
|
||||
// DeflaterOutputStream.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.
|
||||
|
||||
// HISTORY
|
||||
// 22-12-2009 DavidPierson Added AES support
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using PdfSharp.SharpZipLib.Checksums;
|
||||
|
||||
// ReSharper disable RedundantThisQualifier
|
||||
|
||||
//#if !NETCF_1_0
|
||||
//using System.Security.Cryptography;
|
||||
//using PdfSharp.SharpZipLib.Encryption;
|
||||
//#endif
|
||||
|
||||
namespace PdfSharp.SharpZipLib.Zip.Compression.Streams
|
||||
{
|
||||
/// <summary>
|
||||
/// A special stream deflating or compressing the bytes that are
|
||||
/// written to it. It uses a Deflater to perform actual deflating.<br/>
|
||||
/// Authors of the original java version: Tom Tromey, Jochen Hoenicke
|
||||
/// </summary>
|
||||
internal class DeflaterOutputStream : Stream
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Creates a new DeflaterOutputStream with a default Deflater and default buffer size.
|
||||
/// </summary>
|
||||
/// <param name="baseOutputStream">
|
||||
/// the output stream where deflated output should be written.
|
||||
/// </param>
|
||||
public DeflaterOutputStream(Stream baseOutputStream)
|
||||
: this(baseOutputStream, new Deflater(), 512)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new DeflaterOutputStream with the given Deflater and
|
||||
/// default buffer size.
|
||||
/// </summary>
|
||||
/// <param name="baseOutputStream">
|
||||
/// the output stream where deflated output should be written.
|
||||
/// </param>
|
||||
/// <param name="deflater">
|
||||
/// the underlying deflater.
|
||||
/// </param>
|
||||
public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater)
|
||||
: this(baseOutputStream, deflater, 512)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new DeflaterOutputStream with the given Deflater and
|
||||
/// buffer size.
|
||||
/// </summary>
|
||||
/// <param name="baseOutputStream">
|
||||
/// The output stream where deflated output is written.
|
||||
/// </param>
|
||||
/// <param name="deflater">
|
||||
/// The underlying deflater to use
|
||||
/// </param>
|
||||
/// <param name="bufferSize">
|
||||
/// The buffer size in bytes to use when deflating (minimum value 512)
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// bufsize is less than or equal to zero.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// baseOutputStream does not support writing
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// deflater instance is null
|
||||
/// </exception>
|
||||
public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater, int bufferSize)
|
||||
{
|
||||
if (baseOutputStream == null)
|
||||
{
|
||||
throw new ArgumentNullException("baseOutputStream");
|
||||
}
|
||||
|
||||
if (baseOutputStream.CanWrite == false)
|
||||
{
|
||||
throw new ArgumentException("Must support writing", "baseOutputStream");
|
||||
}
|
||||
|
||||
if (deflater == null)
|
||||
{
|
||||
throw new ArgumentNullException("deflater");
|
||||
}
|
||||
|
||||
if (bufferSize < 512)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("bufferSize");
|
||||
}
|
||||
|
||||
baseOutputStream_ = baseOutputStream;
|
||||
buffer_ = new byte[bufferSize];
|
||||
deflater_ = deflater;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public API
|
||||
/// <summary>
|
||||
/// Finishes the stream by calling finish() on the deflater.
|
||||
/// </summary>
|
||||
/// <exception cref="SharpZipBaseException">
|
||||
/// Not all input is deflated
|
||||
/// </exception>
|
||||
public virtual void Finish()
|
||||
{
|
||||
deflater_.Finish();
|
||||
while (!deflater_.IsFinished)
|
||||
{
|
||||
int len = deflater_.Deflate(buffer_, 0, buffer_.Length);
|
||||
if (len <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
#if true//NETCF_1_0
|
||||
if (keys != null)
|
||||
{
|
||||
#else
|
||||
if (cryptoTransform_ != null) {
|
||||
#endif
|
||||
EncryptBlock(buffer_, 0, len);
|
||||
}
|
||||
|
||||
baseOutputStream_.Write(buffer_, 0, len);
|
||||
}
|
||||
|
||||
if (!deflater_.IsFinished)
|
||||
{
|
||||
throw new SharpZipBaseException("Can't deflate all input?");
|
||||
}
|
||||
|
||||
baseOutputStream_.Flush();
|
||||
|
||||
#if true//NETCF_1_0
|
||||
if (keys != null)
|
||||
{
|
||||
keys = null;
|
||||
}
|
||||
#else
|
||||
if (cryptoTransform_ != null) {
|
||||
#if !NET_1_1 && !NETCF_2_0
|
||||
if (cryptoTransform_ is ZipAESTransform) {
|
||||
AESAuthCode = ((ZipAESTransform)cryptoTransform_).GetAuthCode();
|
||||
}
|
||||
#endif
|
||||
cryptoTransform_.Dispose();
|
||||
cryptoTransform_ = null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set flag indicating ownership of the underlying stream.
|
||||
/// When the flag is true <see cref="Close"></see> will close the underlying stream also.
|
||||
/// </summary>
|
||||
public bool IsStreamOwner
|
||||
{
|
||||
get { return isStreamOwner_; }
|
||||
set { isStreamOwner_ = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows client to determine if an entry can be patched after its added
|
||||
/// </summary>
|
||||
public bool CanPatchEntries
|
||||
{
|
||||
get
|
||||
{
|
||||
return baseOutputStream_.CanSeek;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Encryption
|
||||
|
||||
string password;
|
||||
|
||||
#if true//NETCF_1_0
|
||||
uint[] keys;
|
||||
#else
|
||||
ICryptoTransform cryptoTransform_;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the 10 byte AUTH CODE to be appended immediately following the AES data stream.
|
||||
/// </summary>
|
||||
protected byte[] AESAuthCode;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the password used for encryption.
|
||||
/// </summary>
|
||||
/// <remarks>When set to null or if the password is empty no encryption is performed</remarks>
|
||||
public string Password
|
||||
{
|
||||
get
|
||||
{
|
||||
return password;
|
||||
}
|
||||
set
|
||||
{
|
||||
if ((value != null) && (value.Length == 0))
|
||||
{
|
||||
password = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
password = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encrypt a block of data
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// Data to encrypt. NOTE the original contents of the buffer are lost
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// Offset of first byte in buffer to encrypt
|
||||
/// </param>
|
||||
/// <param name="length">
|
||||
/// Number of bytes in buffer to encrypt
|
||||
/// </param>
|
||||
protected void EncryptBlock(byte[] buffer, int offset, int length)
|
||||
{
|
||||
#if true//NETCF_1_0
|
||||
for (int i = offset; i < offset + length; ++i)
|
||||
{
|
||||
byte oldbyte = buffer[i];
|
||||
buffer[i] ^= EncryptByte();
|
||||
UpdateKeys(oldbyte);
|
||||
}
|
||||
#else
|
||||
cryptoTransform_.TransformBlock(buffer, 0, length, buffer, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes encryption keys based on given <paramref name="password"/>.
|
||||
/// </summary>
|
||||
/// <param name="password">The password.</param>
|
||||
protected void InitializePassword(string password)
|
||||
{
|
||||
#if true//NETCF_1_0
|
||||
keys = new uint[] {
|
||||
0x12345678,
|
||||
0x23456789,
|
||||
0x34567890
|
||||
};
|
||||
|
||||
byte[] rawPassword = ZipConstants.ConvertToArray(password);
|
||||
|
||||
for (int i = 0; i < rawPassword.Length; ++i)
|
||||
{
|
||||
UpdateKeys((byte)rawPassword[i]);
|
||||
}
|
||||
|
||||
#else
|
||||
PkzipClassicManaged pkManaged = new PkzipClassicManaged();
|
||||
byte[] key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(password));
|
||||
cryptoTransform_ = pkManaged.CreateEncryptor(key, null);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if false//!NET_1_1 && !NETCF_2_0
|
||||
/// <summary>
|
||||
/// Initializes encryption keys based on given password.
|
||||
/// </summary>
|
||||
protected void InitializeAESPassword(ZipEntry entry, string rawPassword,
|
||||
out byte[] salt, out byte[] pwdVerifier) {
|
||||
salt = new byte[entry.AESSaltLen];
|
||||
// Salt needs to be cryptographically random, and unique per file
|
||||
if (_aesRnd == null)
|
||||
_aesRnd = new RNGCryptoServiceProvider();
|
||||
_aesRnd.GetBytes(salt);
|
||||
int blockSize = entry.AESKeySize / 8; // bits to bytes
|
||||
|
||||
cryptoTransform_ = new ZipAESTransform(rawPassword, salt, blockSize, true);
|
||||
pwdVerifier = ((ZipAESTransform)cryptoTransform_).PwdVerifier;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if true//NETCF_1_0
|
||||
|
||||
/// <summary>
|
||||
/// Encrypt a single byte
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The encrypted value
|
||||
/// </returns>
|
||||
protected byte EncryptByte()
|
||||
{
|
||||
uint temp = ((keys[2] & 0xFFFF) | 2);
|
||||
return (byte)((temp * (temp ^ 1)) >> 8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update encryption keys
|
||||
/// </summary>
|
||||
protected void UpdateKeys(byte ch)
|
||||
{
|
||||
keys[0] = Crc32.ComputeCrc32(keys[0], ch);
|
||||
keys[1] = keys[1] + (byte)keys[0];
|
||||
keys[1] = keys[1] * 134775813 + 1;
|
||||
keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region Deflation Support
|
||||
/// <summary>
|
||||
/// Deflates everything in the input buffers. This will call
|
||||
/// <code>def.deflate()</code> until all bytes from the input buffers
|
||||
/// are processed.
|
||||
/// </summary>
|
||||
protected void Deflate()
|
||||
{
|
||||
while (!deflater_.IsNeedingInput)
|
||||
{
|
||||
int deflateCount = deflater_.Deflate(buffer_, 0, buffer_.Length);
|
||||
|
||||
if (deflateCount <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
#if true//NETCF_1_0
|
||||
if (keys != null)
|
||||
#else
|
||||
if (cryptoTransform_ != null)
|
||||
#endif
|
||||
{
|
||||
EncryptBlock(buffer_, 0, deflateCount);
|
||||
}
|
||||
|
||||
baseOutputStream_.Write(buffer_, 0, deflateCount);
|
||||
}
|
||||
|
||||
if (!deflater_.IsNeedingInput)
|
||||
{
|
||||
throw new SharpZipBaseException("DeflaterOutputStream can't deflate all input?");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Stream Overrides
|
||||
/// <summary>
|
||||
/// Gets value indicating stream can be read from
|
||||
/// </summary>
|
||||
public override bool CanRead
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating if seeking is supported for this stream
|
||||
/// This property always returns false
|
||||
/// </summary>
|
||||
public override bool CanSeek
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get value indicating if this stream supports writing
|
||||
/// </summary>
|
||||
public override bool CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
return baseOutputStream_.CanWrite;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get current length of stream
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return baseOutputStream_.Length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current position within the stream.
|
||||
/// </summary>
|
||||
/// <exception cref="NotSupportedException">Any attempt to set position</exception>
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return baseOutputStream_.Position;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotSupportedException("Position property not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current position of this stream to the given value. Not supported by this class!
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset relative to the <paramref name="origin"/> to seek.</param>
|
||||
/// <param name="origin">The <see cref="SeekOrigin"/> to seek from.</param>
|
||||
/// <returns>The new position in the stream.</returns>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException("DeflaterOutputStream Seek not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the length of this stream to the given value. Not supported by this class!
|
||||
/// </summary>
|
||||
/// <param name="value">The new stream length.</param>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException("DeflaterOutputStream SetLength not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a byte from stream advancing position by one
|
||||
/// </summary>
|
||||
/// <returns>The byte read cast to an int. THe value is -1 if at the end of the stream.</returns>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override int ReadByte()
|
||||
{
|
||||
throw new NotSupportedException("DeflaterOutputStream ReadByte not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a block of bytes from stream
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to store read data in.</param>
|
||||
/// <param name="offset">The offset to start storing at.</param>
|
||||
/// <param name="count">The maximum number of bytes to read.</param>
|
||||
/// <returns>The actual number of bytes read. Zero if end of stream is detected.</returns>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException("DeflaterOutputStream Read not supported");
|
||||
}
|
||||
|
||||
#if !NETFX_CORE && !UWP
|
||||
/// <summary>
|
||||
/// Asynchronous reads are not supported a NotSupportedException is always thrown
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to read into.</param>
|
||||
/// <param name="offset">The offset to start storing data at.</param>
|
||||
/// <param name="count">The number of bytes to read</param>
|
||||
/// <param name="callback">The async callback to use.</param>
|
||||
/// <param name="state">The state to use.</param>
|
||||
/// <returns>Returns an <see cref="IAsyncResult"/></returns>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
||||
{
|
||||
throw new NotSupportedException("DeflaterOutputStream BeginRead not currently supported");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !NETFX_CORE && !UWP
|
||||
/// <summary>
|
||||
/// Asynchronous writes arent supported, a NotSupportedException is always thrown
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to write.</param>
|
||||
/// <param name="offset">The offset to begin writing at.</param>
|
||||
/// <param name="count">The number of bytes to write.</param>
|
||||
/// <param name="callback">The <see cref="AsyncCallback"/> to use.</param>
|
||||
/// <param name="state">The state object.</param>
|
||||
/// <returns>Returns an IAsyncResult.</returns>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
||||
{
|
||||
throw new NotSupportedException("BeginWrite is not supported");
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Flushes the stream by calling <see cref="DeflaterOutputStream.Flush">Flush</see> on the deflater and then
|
||||
/// on the underlying stream. This ensures that all bytes are flushed.
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
deflater_.Flush();
|
||||
Deflate();
|
||||
baseOutputStream_.Flush();
|
||||
}
|
||||
|
||||
#if !NETFX_CORE && !UWP
|
||||
/// <summary>
|
||||
/// Calls <see cref="Finish"/> and closes the underlying
|
||||
/// stream when <see cref="IsStreamOwner"></see> is true.
|
||||
/// </summary>
|
||||
public override void Close()
|
||||
{
|
||||
if ( !isClosed_ ) {
|
||||
isClosed_ = true;
|
||||
|
||||
try {
|
||||
Finish();
|
||||
#if true//NETCF_1_0
|
||||
keys =null;
|
||||
#else
|
||||
if ( cryptoTransform_ != null ) {
|
||||
GetAuthCodeIfAES();
|
||||
cryptoTransform_.Dispose();
|
||||
cryptoTransform_ = null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
finally {
|
||||
if( isStreamOwner_ ) {
|
||||
baseOutputStream_.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
public void Close()
|
||||
{
|
||||
if (!isClosed_)
|
||||
{
|
||||
isClosed_ = true;
|
||||
|
||||
try
|
||||
{
|
||||
Finish();
|
||||
#if true//NETCF_1_0
|
||||
keys = null;
|
||||
#else
|
||||
if ( cryptoTransform_ != null ) {
|
||||
GetAuthCodeIfAES();
|
||||
cryptoTransform_.Dispose();
|
||||
cryptoTransform_ = null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (isStreamOwner_)
|
||||
{
|
||||
//baseOutputStream_.Close();
|
||||
baseOutputStream_.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
private void GetAuthCodeIfAES()
|
||||
{
|
||||
#if false//!NET_1_1 && !NETCF_2_0
|
||||
if (cryptoTransform_ is ZipAESTransform) {
|
||||
AESAuthCode = ((ZipAESTransform)cryptoTransform_).GetAuthCode();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a single byte to the compressed output stream.
|
||||
/// </summary>
|
||||
/// <param name="value">
|
||||
/// The byte value.
|
||||
/// </param>
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
byte[] b = new byte[1];
|
||||
b[0] = value;
|
||||
Write(b, 0, 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes bytes from an array to the compressed stream.
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// The byte array
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// The offset into the byte array where to start.
|
||||
/// </param>
|
||||
/// <param name="count">
|
||||
/// The number of bytes to write.
|
||||
/// </param>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
deflater_.SetInput(buffer, offset, count);
|
||||
Deflate();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Instance Fields
|
||||
/// <summary>
|
||||
/// This buffer is used temporarily to retrieve the bytes from the
|
||||
/// deflater and write them to the underlying output stream.
|
||||
/// </summary>
|
||||
byte[] buffer_;
|
||||
|
||||
/// <summary>
|
||||
/// The deflater which is used to deflate the stream.
|
||||
/// </summary>
|
||||
protected Deflater deflater_;
|
||||
|
||||
/// <summary>
|
||||
/// Base stream the deflater depends on.
|
||||
/// </summary>
|
||||
protected Stream baseOutputStream_;
|
||||
|
||||
#if true || !NETFX_CORE && !UWP
|
||||
bool isClosed_;
|
||||
#endif
|
||||
|
||||
bool isStreamOwner_ = true;
|
||||
#endregion
|
||||
|
||||
#region Static Fields
|
||||
|
||||
#if false//!NET_1_1 && !NETCF_2_0
|
||||
// Static to help ensure that multiple files within a zip will get different random salt
|
||||
private static RNGCryptoServiceProvider _aesRnd;
|
||||
#endif
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,811 @@
|
||||
// InflaterInputStream.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.
|
||||
|
||||
// HISTORY
|
||||
// 11-08-2009 GeoffHart T9121 Added Multi-member gzip support
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
// ReSharper disable RedundantThisQualifier
|
||||
|
||||
#if false//!NETCF_1_0
|
||||
using System.Security.Cryptography;
|
||||
#endif
|
||||
|
||||
namespace PdfSharp.SharpZipLib.Zip.Compression.Streams
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// An input buffer customised for use by <see cref="InflaterInputStream"/>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The buffer supports decryption of incoming data.
|
||||
/// </remarks>
|
||||
internal class InflaterInputBuffer
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="InflaterInputBuffer"/> with a default buffer size
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to buffer.</param>
|
||||
public InflaterInputBuffer(Stream stream)
|
||||
: this(stream, 4096)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise a new instance of <see cref="InflaterInputBuffer"/>
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to buffer.</param>
|
||||
/// <param name="bufferSize">The size to use for the buffer</param>
|
||||
/// <remarks>A minimum buffer size of 1KB is permitted. Lower sizes are treated as 1KB.</remarks>
|
||||
public InflaterInputBuffer(Stream stream, int bufferSize)
|
||||
{
|
||||
inputStream = stream;
|
||||
if (bufferSize < 1024)
|
||||
{
|
||||
bufferSize = 1024;
|
||||
}
|
||||
rawData = new byte[bufferSize];
|
||||
clearText = rawData;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Get the length of bytes bytes in the <see cref="RawData"/>
|
||||
/// </summary>
|
||||
public int RawLength
|
||||
{
|
||||
get
|
||||
{
|
||||
return rawLength;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the contents of the raw data buffer.
|
||||
/// </summary>
|
||||
/// <remarks>This may contain encrypted data.</remarks>
|
||||
public byte[] RawData
|
||||
{
|
||||
get
|
||||
{
|
||||
return rawData;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of useable bytes in <see cref="ClearText"/>
|
||||
/// </summary>
|
||||
public int ClearTextLength
|
||||
{
|
||||
get
|
||||
{
|
||||
return clearTextLength;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the contents of the clear text buffer.
|
||||
/// </summary>
|
||||
public byte[] ClearText
|
||||
{
|
||||
get
|
||||
{
|
||||
return clearText;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the number of bytes available
|
||||
/// </summary>
|
||||
public int Available
|
||||
{
|
||||
get { return available; }
|
||||
set { available = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call <see cref="Inflater.SetInput(byte[], int, int)"/> passing the current clear text buffer contents.
|
||||
/// </summary>
|
||||
/// <param name="inflater">The inflater to set input for.</param>
|
||||
public void SetInflaterInput(Inflater inflater)
|
||||
{
|
||||
if (available > 0)
|
||||
{
|
||||
inflater.SetInput(clearText, clearTextLength - available, available);
|
||||
available = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill the buffer from the underlying input stream.
|
||||
/// </summary>
|
||||
public void Fill()
|
||||
{
|
||||
rawLength = 0;
|
||||
int toRead = rawData.Length;
|
||||
|
||||
while (toRead > 0)
|
||||
{
|
||||
int count = inputStream.Read(rawData, rawLength, toRead);
|
||||
if (count <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
rawLength += count;
|
||||
toRead -= count;
|
||||
}
|
||||
|
||||
#if false//!NETCF_1_0
|
||||
if ( cryptoTransform != null ) {
|
||||
clearTextLength = cryptoTransform.TransformBlock(rawData, 0, rawLength, clearText, 0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
clearTextLength = rawLength;
|
||||
}
|
||||
|
||||
available = clearTextLength;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a buffer directly from the input stream
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to fill</param>
|
||||
/// <returns>Returns the number of bytes read.</returns>
|
||||
public int ReadRawBuffer(byte[] buffer)
|
||||
{
|
||||
return ReadRawBuffer(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a buffer directly from the input stream
|
||||
/// </summary>
|
||||
/// <param name="outBuffer">The buffer to read into</param>
|
||||
/// <param name="offset">The offset to start reading data into.</param>
|
||||
/// <param name="length">The number of bytes to read.</param>
|
||||
/// <returns>Returns the number of bytes read.</returns>
|
||||
public int ReadRawBuffer(byte[] outBuffer, int offset, int length)
|
||||
{
|
||||
if (length < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("length");
|
||||
}
|
||||
|
||||
int currentOffset = offset;
|
||||
int currentLength = length;
|
||||
|
||||
while (currentLength > 0)
|
||||
{
|
||||
if (available <= 0)
|
||||
{
|
||||
Fill();
|
||||
if (available <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
int toCopy = Math.Min(currentLength, available);
|
||||
System.Array.Copy(rawData, rawLength - (int)available, outBuffer, currentOffset, toCopy);
|
||||
currentOffset += toCopy;
|
||||
currentLength -= toCopy;
|
||||
available -= toCopy;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read clear text data from the input stream.
|
||||
/// </summary>
|
||||
/// <param name="outBuffer">The buffer to add data to.</param>
|
||||
/// <param name="offset">The offset to start adding data at.</param>
|
||||
/// <param name="length">The number of bytes to read.</param>
|
||||
/// <returns>Returns the number of bytes actually read.</returns>
|
||||
public int ReadClearTextBuffer(byte[] outBuffer, int offset, int length)
|
||||
{
|
||||
if (length < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("length");
|
||||
}
|
||||
|
||||
int currentOffset = offset;
|
||||
int currentLength = length;
|
||||
|
||||
while (currentLength > 0)
|
||||
{
|
||||
if (available <= 0)
|
||||
{
|
||||
Fill();
|
||||
if (available <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int toCopy = Math.Min(currentLength, available);
|
||||
Array.Copy(clearText, clearTextLength - (int)available, outBuffer, currentOffset, toCopy);
|
||||
currentOffset += toCopy;
|
||||
currentLength -= toCopy;
|
||||
available -= toCopy;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a <see cref="byte"/> from the input stream.
|
||||
/// </summary>
|
||||
/// <returns>Returns the byte read.</returns>
|
||||
public int ReadLeByte()
|
||||
{
|
||||
if (available <= 0)
|
||||
{
|
||||
Fill();
|
||||
if (available <= 0)
|
||||
{
|
||||
throw new ZipException("EOF in header");
|
||||
}
|
||||
}
|
||||
byte result = rawData[rawLength - available];
|
||||
available -= 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an <see cref="short"/> in little endian byte order.
|
||||
/// </summary>
|
||||
/// <returns>The short value read case to an int.</returns>
|
||||
public int ReadLeShort()
|
||||
{
|
||||
return ReadLeByte() | (ReadLeByte() << 8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an <see cref="int"/> in little endian byte order.
|
||||
/// </summary>
|
||||
/// <returns>The int value read.</returns>
|
||||
public int ReadLeInt()
|
||||
{
|
||||
return ReadLeShort() | (ReadLeShort() << 16);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a <see cref="long"/> in little endian byte order.
|
||||
/// </summary>
|
||||
/// <returns>The long value read.</returns>
|
||||
public long ReadLeLong()
|
||||
{
|
||||
return (uint)ReadLeInt() | ((long)ReadLeInt() << 32);
|
||||
}
|
||||
|
||||
#if false//!NETCF_1_0
|
||||
/// <summary>
|
||||
/// Get/set the <see cref="ICryptoTransform"/> to apply to any data.
|
||||
/// </summary>
|
||||
/// <remarks>Set this value to null to have no transform applied.</remarks>
|
||||
public ICryptoTransform CryptoTransform
|
||||
{
|
||||
set {
|
||||
cryptoTransform = value;
|
||||
if ( cryptoTransform != null ) {
|
||||
if ( rawData == clearText ) {
|
||||
if ( internalClearText == null ) {
|
||||
internalClearText = new byte[rawData.Length];
|
||||
}
|
||||
clearText = internalClearText;
|
||||
}
|
||||
clearTextLength = rawLength;
|
||||
if ( available > 0 ) {
|
||||
cryptoTransform.TransformBlock(rawData, rawLength - available, available, clearText, rawLength - available);
|
||||
}
|
||||
} else {
|
||||
clearText = rawData;
|
||||
clearTextLength = rawLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#region Instance Fields
|
||||
int rawLength;
|
||||
byte[] rawData;
|
||||
|
||||
int clearTextLength;
|
||||
byte[] clearText;
|
||||
#if false//!NETCF_1_0
|
||||
byte[] internalClearText;
|
||||
#endif
|
||||
|
||||
int available;
|
||||
|
||||
#if false//!NETCF_1_0
|
||||
ICryptoTransform cryptoTransform;
|
||||
#endif
|
||||
Stream inputStream;
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This filter stream is used to decompress data compressed using the "deflate"
|
||||
/// format. The "deflate" format is described in RFC 1951.
|
||||
///
|
||||
/// This stream may form the basis for other decompression filters, such
|
||||
/// as the GZipInputStream.
|
||||
///
|
||||
/// Author of the original java version: John Leuner.
|
||||
/// </summary>
|
||||
internal class InflaterInputStream : Stream
|
||||
{
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Create an InflaterInputStream with the default decompressor
|
||||
/// and a default buffer size of 4KB.
|
||||
/// </summary>
|
||||
/// <param name = "baseInputStream">
|
||||
/// The InputStream to read bytes from
|
||||
/// </param>
|
||||
public InflaterInputStream(Stream baseInputStream)
|
||||
: this(baseInputStream, new Inflater(), 4096)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an InflaterInputStream with the specified decompressor
|
||||
/// and a default buffer size of 4KB.
|
||||
/// </summary>
|
||||
/// <param name = "baseInputStream">
|
||||
/// The source of input data
|
||||
/// </param>
|
||||
/// <param name = "inf">
|
||||
/// The decompressor used to decompress data read from baseInputStream
|
||||
/// </param>
|
||||
public InflaterInputStream(Stream baseInputStream, Inflater inf)
|
||||
: this(baseInputStream, inf, 4096)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an InflaterInputStream with the specified decompressor
|
||||
/// and the specified buffer size.
|
||||
/// </summary>
|
||||
/// <param name = "baseInputStream">
|
||||
/// The InputStream to read bytes from
|
||||
/// </param>
|
||||
/// <param name = "inflater">
|
||||
/// The decompressor to use
|
||||
/// </param>
|
||||
/// <param name = "bufferSize">
|
||||
/// Size of the buffer to use
|
||||
/// </param>
|
||||
public InflaterInputStream(Stream baseInputStream, Inflater inflater, int bufferSize)
|
||||
{
|
||||
if (baseInputStream == null)
|
||||
{
|
||||
throw new ArgumentNullException("baseInputStream");
|
||||
}
|
||||
|
||||
if (inflater == null)
|
||||
{
|
||||
throw new ArgumentNullException("inflater");
|
||||
}
|
||||
|
||||
if (bufferSize <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("bufferSize");
|
||||
}
|
||||
|
||||
this.baseInputStream = baseInputStream;
|
||||
this.inf = inflater;
|
||||
|
||||
inputBuffer = new InflaterInputBuffer(baseInputStream, bufferSize);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Get/set flag indicating ownership of underlying stream.
|
||||
/// When the flag is true <see cref="Close"/> will close the underlying stream also.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default value is true.
|
||||
/// </remarks>
|
||||
public bool IsStreamOwner
|
||||
{
|
||||
get { return isStreamOwner; }
|
||||
set { isStreamOwner = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Skip specified number of bytes of uncompressed data
|
||||
/// </summary>
|
||||
/// <param name ="count">
|
||||
/// Number of bytes to skip
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The number of bytes skipped, zero if the end of
|
||||
/// stream has been reached
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="count">The number of bytes</paramref> to skip is less than or equal to zero.
|
||||
/// </exception>
|
||||
public long Skip(long count)
|
||||
{
|
||||
if (count <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
}
|
||||
|
||||
// v0.80 Skip by seeking if underlying stream supports it...
|
||||
if (baseInputStream.CanSeek)
|
||||
{
|
||||
baseInputStream.Seek(count, SeekOrigin.Current);
|
||||
return count;
|
||||
}
|
||||
else
|
||||
{
|
||||
int length = 2048;
|
||||
if (count < length)
|
||||
{
|
||||
length = (int)count;
|
||||
}
|
||||
|
||||
byte[] tmp = new byte[length];
|
||||
int readCount = 1;
|
||||
long toSkip = count;
|
||||
|
||||
while ((toSkip > 0) && (readCount > 0))
|
||||
{
|
||||
if (toSkip < length)
|
||||
{
|
||||
length = (int)toSkip;
|
||||
}
|
||||
|
||||
readCount = baseInputStream.Read(tmp, 0, length);
|
||||
toSkip -= readCount;
|
||||
}
|
||||
|
||||
return count - toSkip;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear any cryptographic state.
|
||||
/// </summary>
|
||||
protected void StopDecrypting()
|
||||
{
|
||||
#if false//!NETCF_1_0
|
||||
inputBuffer.CryptoTransform = null;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns 0 once the end of the stream (EOF) has been reached.
|
||||
/// Otherwise returns 1.
|
||||
/// </summary>
|
||||
public virtual int Available
|
||||
{
|
||||
get
|
||||
{
|
||||
return inf.IsFinished ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fills the buffer with more data to decompress.
|
||||
/// </summary>
|
||||
/// <exception cref="SharpZipBaseException">
|
||||
/// Stream ends early
|
||||
/// </exception>
|
||||
protected void Fill()
|
||||
{
|
||||
// Protect against redundant calls
|
||||
if (inputBuffer.Available <= 0)
|
||||
{
|
||||
inputBuffer.Fill();
|
||||
if (inputBuffer.Available <= 0)
|
||||
{
|
||||
throw new SharpZipBaseException("Unexpected EOF");
|
||||
}
|
||||
}
|
||||
inputBuffer.SetInflaterInput(inf);
|
||||
}
|
||||
|
||||
#region Stream Overrides
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current stream supports reading
|
||||
/// </summary>
|
||||
public override bool CanRead
|
||||
{
|
||||
get
|
||||
{
|
||||
return baseInputStream.CanRead;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value of false indicating seeking is not supported for this stream.
|
||||
/// </summary>
|
||||
public override bool CanSeek
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value of false indicating that this stream is not writeable.
|
||||
/// </summary>
|
||||
public override bool CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A value representing the length of the stream in bytes.
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return inputBuffer.RawLength;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The current position within the stream.
|
||||
/// Throws a NotSupportedException when attempting to set the position
|
||||
/// </summary>
|
||||
/// <exception cref="NotSupportedException">Attempting to set the position</exception>
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return baseInputStream.Position;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotSupportedException("InflaterInputStream Position not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes the baseInputStream
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
baseInputStream.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the position within the current stream
|
||||
/// Always throws a NotSupportedException
|
||||
/// </summary>
|
||||
/// <param name="offset">The relative offset to seek to.</param>
|
||||
/// <param name="origin">The <see cref="SeekOrigin"/> defining where to seek from.</param>
|
||||
/// <returns>The new position in the stream.</returns>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException("Seek not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the length of the current stream
|
||||
/// Always throws a NotSupportedException
|
||||
/// </summary>
|
||||
/// <param name="value">The new length value for the stream.</param>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException("InflaterInputStream SetLength not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a sequence of bytes to stream and advances the current position
|
||||
/// This method always throws a NotSupportedException
|
||||
/// </summary>
|
||||
/// <param name="buffer">Thew buffer containing data to write.</param>
|
||||
/// <param name="offset">The offset of the first byte to write.</param>
|
||||
/// <param name="count">The number of bytes to write.</param>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException("InflaterInputStream Write not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes one byte to the current stream and advances the current position
|
||||
/// Always throws a NotSupportedException
|
||||
/// </summary>
|
||||
/// <param name="value">The byte to write.</param>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
throw new NotSupportedException("InflaterInputStream WriteByte not supported");
|
||||
}
|
||||
|
||||
#if !NETFX_CORE && !UWP
|
||||
/// <summary>
|
||||
/// Entry point to begin an asynchronous write. Always throws a NotSupportedException.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to write data from</param>
|
||||
/// <param name="offset">Offset of first byte to write</param>
|
||||
/// <param name="count">The maximum number of bytes to write</param>
|
||||
/// <param name="callback">The method to be called when the asynchronous write operation is completed</param>
|
||||
/// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from other requests</param>
|
||||
/// <returns>An <see cref="System.IAsyncResult">IAsyncResult</see> that references the asynchronous write</returns>
|
||||
/// <exception cref="NotSupportedException">Any access</exception>
|
||||
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
||||
{
|
||||
throw new NotSupportedException("InflaterInputStream BeginWrite not supported");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !NETFX_CORE && !UWP
|
||||
/// <summary>
|
||||
/// Closes the input stream. When <see cref="IsStreamOwner"></see>
|
||||
/// is true the underlying stream is also closed.
|
||||
/// </summary>
|
||||
public override void Close()
|
||||
{
|
||||
if (!isClosed)
|
||||
{
|
||||
isClosed = true;
|
||||
if (isStreamOwner)
|
||||
{
|
||||
baseInputStream.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
public void Close()
|
||||
{
|
||||
if (!isClosed)
|
||||
{
|
||||
isClosed = true;
|
||||
if (isStreamOwner)
|
||||
{
|
||||
//baseInputStream.Close();
|
||||
baseInputStream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Reads decompressed data into the provided buffer byte array
|
||||
/// </summary>
|
||||
/// <param name ="buffer">
|
||||
/// The array to read and decompress data into
|
||||
/// </param>
|
||||
/// <param name ="offset">
|
||||
/// The offset indicating where the data should be placed
|
||||
/// </param>
|
||||
/// <param name ="count">
|
||||
/// The number of bytes to decompress
|
||||
/// </param>
|
||||
/// <returns>The number of bytes read. Zero signals the end of stream</returns>
|
||||
/// <exception cref="SharpZipBaseException">
|
||||
/// Inflater needs a dictionary
|
||||
/// </exception>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (inf.IsNeedingDictionary)
|
||||
{
|
||||
throw new SharpZipBaseException("Need a dictionary");
|
||||
}
|
||||
|
||||
int remainingBytes = count;
|
||||
while (true)
|
||||
{
|
||||
int bytesRead = inf.Inflate(buffer, offset, remainingBytes);
|
||||
offset += bytesRead;
|
||||
remainingBytes -= bytesRead;
|
||||
|
||||
if (remainingBytes == 0 || inf.IsFinished)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (inf.IsNeedingInput)
|
||||
{
|
||||
try
|
||||
{
|
||||
Fill();
|
||||
}
|
||||
catch (SharpZipBaseException ex)
|
||||
{
|
||||
// Hack 16-05-25: Some PDF files lead to an "Unexpected EOF" exception. Is it safe to ignore this exception?
|
||||
if (ex.Message != "Unexpected EOF")
|
||||
throw;
|
||||
// WB! early EOF: apparently not a big deal for some PDF pages: break out of the loop.
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (bytesRead == 0)
|
||||
{
|
||||
throw new ZipException("Don't know what to do");
|
||||
}
|
||||
}
|
||||
return count - remainingBytes;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Instance Fields
|
||||
/// <summary>
|
||||
/// Decompressor for this stream
|
||||
/// </summary>
|
||||
protected Inflater inf;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="InflaterInputBuffer">Input buffer</see> for this stream.
|
||||
/// </summary>
|
||||
protected InflaterInputBuffer inputBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// Base stream the inflater reads from.
|
||||
/// </summary>
|
||||
private Stream baseInputStream;
|
||||
|
||||
///// <summary>
|
||||
///// The compressed size
|
||||
///// </summary>
|
||||
////protected long csize;
|
||||
|
||||
#if true || !NETFX_CORE
|
||||
/// <summary>
|
||||
/// Flag indicating wether this instance has been closed or not.
|
||||
/// </summary>
|
||||
bool isClosed;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating wether this instance is designated the stream owner.
|
||||
/// When closing if this flag is true the underlying stream is closed.
|
||||
/// </summary>
|
||||
bool isStreamOwner = true;
|
||||
#endregion
|
||||
}
|
||||
}
|
256
PdfSharp/SharpZipLib/Zip/Compression/Streams/OutputWindow.cs
Normal file
256
PdfSharp/SharpZipLib/Zip/Compression/Streams/OutputWindow.cs
Normal file
@@ -0,0 +1,256 @@
|
||||
// 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 PdfSharp.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>
|
||||
internal 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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,318 @@
|
||||
// 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 PdfSharp.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>
|
||||
internal 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
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user