BridgeStream.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. using SevenZip;
  10. namespace SevenRepacker
  11. {
  12. //SOURCE: https://stackoverflow.com/a/3729877/2430943 With modify
  13. public class BridgeStream : Stream
  14. {
  15. private readonly long? _length;
  16. private readonly SevenZipExtractor _inArchive;
  17. private readonly int _archiveIndex;
  18. private bool _isInit;
  19. private readonly BlockingCollection<byte[]> _blocks;
  20. private byte[] _currentBlock;
  21. private int _currentBlockIndex;
  22. public BridgeStream(int streamWriteCountCache, long? length, SevenZipExtractor inArchive, int archiveIndex)
  23. {
  24. _length = length;
  25. _inArchive = inArchive;
  26. _archiveIndex = archiveIndex;
  27. _blocks = new BlockingCollection<byte[]>(streamWriteCountCache);
  28. }
  29. public override bool CanTimeout => false;
  30. public override bool CanRead => true;
  31. /// <summary>
  32. /// FAKE!
  33. /// </summary>
  34. public override bool CanSeek => true;
  35. public override bool CanWrite => true;
  36. public override long Length => _length ?? throw new NotSupportedException();
  37. public override void Flush() { }
  38. public long TotalBytesWritten { get; private set; }
  39. public int WriteCount { get; private set; }
  40. public override long Position
  41. {
  42. get { throw new NotSupportedException(); }
  43. set { throw new NotSupportedException(); }
  44. }
  45. public override long Seek(long offset, SeekOrigin origin)
  46. {
  47. throw new NotSupportedException();
  48. }
  49. public override void SetLength(long value)
  50. {
  51. throw new NotSupportedException();
  52. }
  53. public override int Read(byte[] buffer, int offset, int count)
  54. {
  55. ValidateBufferArgs(buffer, offset, count);
  56. if (!_isInit)
  57. {
  58. Task.Run(() =>
  59. {
  60. _inArchive.ExtractFile(_archiveIndex, this);
  61. CompleteWriting();
  62. });
  63. _isInit = true;
  64. }
  65. int bytesRead = 0;
  66. while (true)
  67. {
  68. if (_currentBlock != null)
  69. {
  70. int copy = Math.Min(count - bytesRead, _currentBlock.Length - _currentBlockIndex);
  71. Array.Copy(_currentBlock, _currentBlockIndex, buffer, offset + bytesRead, copy);
  72. _currentBlockIndex += copy;
  73. bytesRead += copy;
  74. if (_currentBlock.Length <= _currentBlockIndex)
  75. {
  76. _currentBlock = null;
  77. _currentBlockIndex = 0;
  78. }
  79. if (bytesRead == count)
  80. return bytesRead;
  81. }
  82. if (!_blocks.TryTake(out _currentBlock, Timeout.Infinite))
  83. return bytesRead;
  84. }
  85. }
  86. public override void Write(byte[] buffer, int offset, int count)
  87. {
  88. ValidateBufferArgs(buffer, offset, count);
  89. var newBuf = new byte[count];
  90. Array.Copy(buffer, offset, newBuf, 0, count);
  91. _blocks.Add(newBuf);
  92. TotalBytesWritten += count;
  93. WriteCount++;
  94. }
  95. protected override void Dispose(bool disposing)
  96. {
  97. base.Dispose(disposing);
  98. if (disposing)
  99. {
  100. _blocks.Dispose();
  101. }
  102. }
  103. public override void Close()
  104. {
  105. CompleteWriting();
  106. base.Close();
  107. }
  108. public void CompleteWriting()
  109. {
  110. _blocks.CompleteAdding();
  111. }
  112. private static void ValidateBufferArgs(byte[] buffer, int offset, int count)
  113. {
  114. if (buffer == null)
  115. throw new ArgumentNullException("buffer");
  116. if (offset < 0)
  117. throw new ArgumentOutOfRangeException("offset");
  118. if (count < 0)
  119. throw new ArgumentOutOfRangeException("count");
  120. if (buffer.Length - offset < count)
  121. throw new ArgumentException("buffer.Length - offset < count");
  122. }
  123. }
  124. }