/* This file is part of SevenZipSharp. SevenZipSharp is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SevenZipSharp 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with SevenZipSharp. If not, see . */ #define DOTNET20 #define UNMANAGED #define COMPRESS using System; using System.IO; using SevenZip.Sdk.Compression.Lzma; namespace SevenZip { #if LZMA_STREAM #if COMPRESS /// /// The stream which compresses data with LZMA on the fly. /// public class LzmaEncodeStream : Stream { private const int MAX_BUFFER_CAPACITY = 1 << 30; //1 Gb private readonly MemoryStream _buffer = new MemoryStream(); private readonly int _bufferCapacity = 1 << 18; //256 kb private readonly bool _ownOutput; private bool _disposed; private Encoder _lzmaEncoder; private Stream _output; /// /// Initializes a new instance of the LzmaEncodeStream class. /// public LzmaEncodeStream() { _output = new MemoryStream(); _ownOutput = true; Init(); } /// /// Initializes a new instance of the LzmaEncodeStream class. /// /// The buffer size. The bigger size, the better compression. public LzmaEncodeStream(int bufferCapacity) { _output = new MemoryStream(); _ownOutput = true; if (bufferCapacity > MAX_BUFFER_CAPACITY) { throw new ArgumentException("Too large capacity.", "bufferCapacity"); } _bufferCapacity = bufferCapacity; Init(); } /// /// Initializes a new instance of the LzmaEncodeStream class. /// /// An output stream which supports writing. public LzmaEncodeStream(Stream outputStream) { if (!outputStream.CanWrite) { throw new ArgumentException("The specified stream can not write.", "outputStream"); } _output = outputStream; Init(); } /// /// Initializes a new instance of the LzmaEncodeStream class. /// /// An output stream which supports writing. /// A buffer size. The bigger size, the better compression. public LzmaEncodeStream(Stream outputStream, int bufferCapacity) { if (!outputStream.CanWrite) { throw new ArgumentException("The specified stream can not write.", "outputStream"); } _output = outputStream; if (bufferCapacity > 1 << 30) { throw new ArgumentException("Too large capacity.", "bufferCapacity"); } _bufferCapacity = bufferCapacity; Init(); } /// /// Gets a value indicating whether the current stream supports reading. /// public override bool CanRead { get { return false; } } /// /// Gets a value indicating whether the current stream supports seeking. /// public override bool CanSeek { get { return false; } } /// /// Gets a value indicating whether the current stream supports writing. /// public override bool CanWrite { get { DisposedCheck(); return _buffer.CanWrite; } } /// /// Gets the length in bytes of the output stream. /// public override long Length { get { DisposedCheck(); if (_output.CanSeek) { return _output.Length; } return _buffer.Position; } } /// /// Gets or sets the position within the output stream. /// public override long Position { get { DisposedCheck(); if (_output.CanSeek) { return _output.Position; } return _buffer.Position; } set { throw new NotSupportedException(); } } private void Init() { _buffer.Capacity = _bufferCapacity; SevenZipCompressor.LzmaDictionarySize = _bufferCapacity; _lzmaEncoder = new Encoder(); SevenZipCompressor.WriteLzmaProperties(_lzmaEncoder); } /// /// Checked whether the class was disposed. /// /// private void DisposedCheck() { if (_disposed) { throw new ObjectDisposedException("SevenZipExtractor"); } } private void WriteChunk() { _lzmaEncoder.WriteCoderProperties(_output); long streamSize = _buffer.Position; if (_buffer.Length != _buffer.Position) { _buffer.SetLength(_buffer.Position); } _buffer.Position = 0; for (int i = 0; i < 8; i++) { _output.WriteByte((byte) (streamSize >> (8*i))); } _lzmaEncoder.Code(_buffer, _output, -1, -1, null); _buffer.Position = 0; } /// /// Converts the LzmaEncodeStream to the LzmaDecodeStream to read data. /// /// public LzmaDecodeStream ToDecodeStream() { DisposedCheck(); Flush(); return new LzmaDecodeStream(_output); } /// /// Clears all buffers for this stream and causes any buffered data to be compressed and written. /// public override void Flush() { DisposedCheck(); WriteChunk(); } /// /// Releases all unmanaged resources used by LzmaEncodeStream. /// protected override void Dispose(bool disposing) { if (!_disposed) { if (disposing) { Flush(); _buffer.Close(); if (_ownOutput) { _output.Dispose(); } _output = null; } _disposed = true; } } /// /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. /// /// An array of bytes. /// The zero-based byte offset in buffer at which to begin storing the data read from the current stream. /// The maximum number of bytes to be read from the current stream. /// The total number of bytes read into the buffer. public override int Read(byte[] buffer, int offset, int count) { DisposedCheck(); throw new NotSupportedException(); } /// /// Sets the position within the current stream. /// /// A byte offset relative to the origin parameter. /// A value of type System.IO.SeekOrigin indicating the reference point used to obtain the new position. /// The new position within the current stream. public override long Seek(long offset, SeekOrigin origin) { DisposedCheck(); throw new NotSupportedException(); } /// /// Sets the length of the current stream. /// /// The desired length of the current stream in bytes. public override void SetLength(long value) { DisposedCheck(); throw new NotSupportedException(); } /// /// Writes a sequence of bytes to the current stream and compresses it if necessary. /// /// An array of bytes. /// The zero-based byte offset in buffer at which to begin storing the data read from the current stream. /// The maximum number of bytes to be read from the current stream. public override void Write(byte[] buffer, int offset, int count) { DisposedCheck(); int dataLength = Math.Min(buffer.Length - offset, count); while (_buffer.Position + dataLength >= _bufferCapacity) { int length = _bufferCapacity - (int) _buffer.Position; _buffer.Write(buffer, offset, length); offset = length + offset; dataLength -= length; WriteChunk(); } _buffer.Write(buffer, offset, dataLength); } } #endif #endif }