using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using SevenZip; namespace SevenRepacker { //SOURCE: https://stackoverflow.com/a/3729877/2430943 With modify public class BridgeStream : Stream { private readonly long? _length; private readonly SevenZipExtractor _inArchive; private readonly int _archiveIndex; private bool _isInit; private readonly BlockingCollection _blocks; private byte[] _currentBlock; private int _currentBlockIndex; public BridgeStream(int streamWriteCountCache, long? length, SevenZipExtractor inArchive, int archiveIndex) { _length = length; _inArchive = inArchive; _archiveIndex = archiveIndex; _blocks = new BlockingCollection(streamWriteCountCache); } public override bool CanTimeout => false; public override bool CanRead => true; /// /// FAKE! /// public override bool CanSeek => true; public override bool CanWrite => true; public override long Length => _length ?? throw new NotSupportedException(); public override void Flush() { } public long TotalBytesWritten { get; private set; } public int WriteCount { get; private set; } public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override int Read(byte[] buffer, int offset, int count) { ValidateBufferArgs(buffer, offset, count); if (!_isInit) { Task.Run(() => { _inArchive.ExtractFile(_archiveIndex, this); CompleteWriting(); }); _isInit = true; } int bytesRead = 0; while (true) { if (_currentBlock != null) { int copy = Math.Min(count - bytesRead, _currentBlock.Length - _currentBlockIndex); Array.Copy(_currentBlock, _currentBlockIndex, buffer, offset + bytesRead, copy); _currentBlockIndex += copy; bytesRead += copy; if (_currentBlock.Length <= _currentBlockIndex) { _currentBlock = null; _currentBlockIndex = 0; } if (bytesRead == count) return bytesRead; } if (!_blocks.TryTake(out _currentBlock, Timeout.Infinite)) return bytesRead; } } public override void Write(byte[] buffer, int offset, int count) { ValidateBufferArgs(buffer, offset, count); var newBuf = new byte[count]; Array.Copy(buffer, offset, newBuf, 0, count); _blocks.Add(newBuf); TotalBytesWritten += count; WriteCount++; } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { _blocks.Dispose(); } } public override void Close() { CompleteWriting(); base.Close(); } public void CompleteWriting() { _blocks.CompleteAdding(); } private static void ValidateBufferArgs(byte[] buffer, int offset, int count) { if (buffer == null) throw new ArgumentNullException("buffer"); if (offset < 0) throw new ArgumentOutOfRangeException("offset"); if (count < 0) throw new ArgumentOutOfRangeException("count"); if (buffer.Length - offset < count) throw new ArgumentException("buffer.Length - offset < count"); } } }