677 lines
21 KiB
C#
677 lines
21 KiB
C#
|
// 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
|
||
|
}
|
||
|
}
|