123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- using SharpCompress.Common.Zip;
- using SharpCompress.Compressors.Deflate;
- using System;
- using System.Diagnostics;
- using System.IO;
- using System.Runtime.CompilerServices;
- namespace SharpCompress.Compressors.Deflate64
- {
- public sealed class Deflate64Stream : Stream
- {
- private const int DEFAULT_BUFFER_SIZE = 8192;
- private Stream _stream;
- private CompressionMode _mode;
- private InflaterManaged _inflater;
- private byte[] _buffer;
- public Deflate64Stream(Stream stream, CompressionMode mode)
- {
- if (stream == null)
- throw new ArgumentNullException(nameof(stream));
- if (mode != CompressionMode.Decompress)
- throw new NotImplementedException("Deflate64: this implementation only supports decompression");
- if (!stream.CanRead)
- throw new ArgumentException("Deflate64: input stream is not readable", nameof(stream));
- InitializeInflater(stream, ZipCompressionMethod.Deflate64);
- }
- /// <summary>
- /// Sets up this DeflateManagedStream to be used for Inflation/Decompression
- /// </summary>
- private void InitializeInflater(Stream stream, ZipCompressionMethod method = ZipCompressionMethod.Deflate)
- {
- Debug.Assert(stream != null);
- Debug.Assert(method == ZipCompressionMethod.Deflate || method == ZipCompressionMethod.Deflate64);
- if (!stream.CanRead)
- throw new ArgumentException("Deflate64: input stream is not readable", nameof(stream));
- _inflater = new InflaterManaged(method == ZipCompressionMethod.Deflate64);
- _stream = stream;
- _mode = CompressionMode.Decompress;
- _buffer = new byte[DEFAULT_BUFFER_SIZE];
- }
- public override bool CanRead
- {
- get
- {
- if (_stream == null)
- {
- return false;
- }
- return (_mode == CompressionMode.Decompress && _stream.CanRead);
- }
- }
- public override bool CanWrite
- {
- get
- {
- if (_stream == null)
- {
- return false;
- }
- return (_mode == CompressionMode.Compress && _stream.CanWrite);
- }
- }
- public override bool CanSeek => false;
- public override long Length
- {
- get { throw new NotSupportedException("Deflate64: not supported"); }
- }
- public override long Position
- {
- get { throw new NotSupportedException("Deflate64: not supported"); }
- set { throw new NotSupportedException("Deflate64: not supported"); }
- }
- public override void Flush()
- {
- EnsureNotDisposed();
- }
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotSupportedException("Deflate64: not supported");
- }
- public override void SetLength(long value)
- {
- throw new NotSupportedException("Deflate64: not supported");
- }
- public override int Read(byte[] array, int offset, int count)
- {
- EnsureDecompressionMode();
- ValidateParameters(array, offset, count);
- EnsureNotDisposed();
- int bytesRead;
- int currentOffset = offset;
- int remainingCount = count;
- while (true)
- {
- bytesRead = _inflater.Inflate(array, currentOffset, remainingCount);
- currentOffset += bytesRead;
- remainingCount -= bytesRead;
- if (remainingCount == 0)
- {
- break;
- }
- if (_inflater.Finished())
- {
- // if we finished decompressing, we can't have anything left in the outputwindow.
- Debug.Assert(_inflater.AvailableOutput == 0, "We should have copied all stuff out!");
- break;
- }
- int bytes = _stream.Read(_buffer, 0, _buffer.Length);
- if (bytes <= 0)
- {
- break;
- }
- else if (bytes > _buffer.Length)
- {
- // The stream is either malicious or poorly implemented and returned a number of
- // bytes larger than the buffer supplied to it.
- throw new InvalidDataException("Deflate64: invalid data");
- }
- _inflater.SetInput(_buffer, 0, bytes);
- }
- return count - remainingCount;
- }
- private void ValidateParameters(byte[] array, int offset, int count)
- {
- if (array == null)
- throw new ArgumentNullException(nameof(array));
- if (offset < 0)
- throw new ArgumentOutOfRangeException(nameof(offset));
- if (count < 0)
- throw new ArgumentOutOfRangeException(nameof(count));
- if (array.Length - offset < count)
- throw new ArgumentException("Deflate64: invalid offset/count combination");
- }
- private void EnsureNotDisposed()
- {
- if (_stream == null)
- ThrowStreamClosedException();
- }
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static void ThrowStreamClosedException()
- {
- throw new ObjectDisposedException(null, "Deflate64: stream has been disposed");
- }
- private void EnsureDecompressionMode()
- {
- if (_mode != CompressionMode.Decompress)
- ThrowCannotReadFromDeflateManagedStreamException();
- }
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static void ThrowCannotReadFromDeflateManagedStreamException()
- {
- throw new InvalidOperationException("Deflate64: cannot read from this stream");
- }
- private void EnsureCompressionMode()
- {
- if (_mode != CompressionMode.Compress)
- ThrowCannotWriteToDeflateManagedStreamException();
- }
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static void ThrowCannotWriteToDeflateManagedStreamException()
- {
- throw new InvalidOperationException("Deflate64: cannot write to this stream");
- }
- public override void Write(byte[] array, int offset, int count)
- {
- ThrowCannotWriteToDeflateManagedStreamException();
- }
- // This is called by Dispose:
- private void PurgeBuffers(bool disposing)
- {
- if (!disposing)
- return;
- if (_stream == null)
- return;
- Flush();
- }
- protected override void Dispose(bool disposing)
- {
- try
- {
- PurgeBuffers(disposing);
- }
- finally
- {
- // Close the underlying stream even if PurgeBuffers threw.
- // Stream.Close() may throw here (may or may not be due to the same error).
- // In this case, we still need to clean up internal resources, hence the inner finally blocks.
- try
- {
- if (disposing)
- {
- _stream?.Dispose();
- }
- }
- finally
- {
- _stream = null;
- try
- {
- _inflater?.Dispose();
- }
- finally
- {
- _inflater = null;
- base.Dispose(disposing);
- }
- }
- }
- }
- }
- }
|