RewindableStream.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. using System;
  2. using System.IO;
  3. using SharpCompress.Compressors.Filters;
  4. namespace SharpCompress.IO
  5. {
  6. internal class RewindableStream : Stream
  7. {
  8. private readonly Stream stream;
  9. private MemoryStream bufferStream = new MemoryStream();
  10. private bool isRewound;
  11. private bool isDisposed;
  12. public RewindableStream(Stream stream)
  13. {
  14. this.stream = stream;
  15. }
  16. internal bool IsRecording { get; private set; }
  17. protected override void Dispose(bool disposing)
  18. {
  19. if (isDisposed)
  20. {
  21. return;
  22. }
  23. isDisposed = true;
  24. base.Dispose(disposing);
  25. if (disposing)
  26. {
  27. stream.Dispose();
  28. }
  29. }
  30. public void Rewind(bool stopRecording)
  31. {
  32. isRewound = true;
  33. IsRecording = !stopRecording;
  34. bufferStream.Position = 0;
  35. }
  36. public void Rewind(MemoryStream buffer)
  37. {
  38. if (bufferStream.Position >= buffer.Length)
  39. {
  40. bufferStream.Position -= buffer.Length;
  41. }
  42. else
  43. {
  44. bufferStream.TransferTo(buffer);
  45. //create new memorystream to allow proper resizing as memorystream could be a user provided buffer
  46. //https://github.com/adamhathcock/sharpcompress/issues/306
  47. bufferStream = new MemoryStream();
  48. buffer.Position = 0;
  49. buffer.TransferTo(bufferStream);
  50. bufferStream.Position = 0;
  51. }
  52. isRewound = true;
  53. }
  54. public void StartRecording()
  55. {
  56. //if (isRewound && bufferStream.Position != 0)
  57. // throw new System.NotImplementedException();
  58. if (bufferStream.Position != 0)
  59. {
  60. byte[] data = bufferStream.ToArray();
  61. long position = bufferStream.Position;
  62. bufferStream.SetLength(0);
  63. bufferStream.Write(data, (int)position, data.Length - (int)position);
  64. bufferStream.Position = 0;
  65. }
  66. IsRecording = true;
  67. }
  68. public override bool CanRead => true;
  69. public override bool CanSeek => stream.CanSeek;
  70. public override bool CanWrite => false;
  71. public override void Flush()
  72. {
  73. throw new NotSupportedException();
  74. }
  75. public override long Length => throw new NotSupportedException();
  76. public override long Position
  77. {
  78. get { return stream.Position + bufferStream.Position - bufferStream.Length; }
  79. set
  80. {
  81. if (!isRewound)
  82. {
  83. stream.Position = value;
  84. }
  85. else if (value < stream.Position - bufferStream.Length || value >= stream.Position)
  86. {
  87. stream.Position = value;
  88. isRewound = false;
  89. bufferStream.SetLength(0);
  90. }
  91. else
  92. {
  93. bufferStream.Position = value - stream.Position + bufferStream.Length;
  94. }
  95. }
  96. }
  97. public override int Read(byte[] buffer, int offset, int count)
  98. {
  99. //don't actually read if we don't really want to read anything
  100. //currently a network stream bug on Windows for .NET Core
  101. if (count == 0)
  102. {
  103. return 0;
  104. }
  105. int read;
  106. if (isRewound && bufferStream.Position != bufferStream.Length)
  107. {
  108. read = bufferStream.Read(buffer, offset, count);
  109. if (read < count)
  110. {
  111. int tempRead = stream.Read(buffer, offset + read, count - read);
  112. if (IsRecording)
  113. {
  114. bufferStream.Write(buffer, offset + read, tempRead);
  115. }
  116. read += tempRead;
  117. }
  118. if (bufferStream.Position == bufferStream.Length && !IsRecording)
  119. {
  120. isRewound = false;
  121. bufferStream.SetLength(0);
  122. }
  123. return read;
  124. }
  125. read = stream.Read(buffer, offset, count);
  126. if (IsRecording)
  127. {
  128. bufferStream.Write(buffer, offset, read);
  129. }
  130. return read;
  131. }
  132. public override long Seek(long offset, SeekOrigin origin)
  133. {
  134. throw new NotSupportedException();
  135. }
  136. public override void SetLength(long value)
  137. {
  138. throw new NotSupportedException();
  139. }
  140. public override void Write(byte[] buffer, int offset, int count)
  141. {
  142. throw new NotSupportedException();
  143. }
  144. }
  145. }