BSA_SubReadOnlyStream.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // Better Streaming Assets, Piotr Gwiazdowski <gwiazdorrr+github at gmail.com>, 2017
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Text;
  8. namespace Better.StreamingAssets
  9. {
  10. internal class SubReadOnlyStream: Stream
  11. {
  12. private readonly long m_offset;
  13. private readonly bool m_leaveOpen;
  14. private long? m_length;
  15. private Stream m_actualStream;
  16. private long m_position;
  17. public SubReadOnlyStream(Stream actualStream, bool leaveOpen = false)
  18. {
  19. if (actualStream == null)
  20. throw new ArgumentNullException("superStream");
  21. m_actualStream = actualStream;
  22. m_leaveOpen = leaveOpen;
  23. }
  24. public SubReadOnlyStream(Stream actualStream, long offset, long length, bool leaveOpen = false)
  25. : this(actualStream, leaveOpen)
  26. {
  27. if (offset < 0)
  28. throw new ArgumentOutOfRangeException("offset");
  29. if (length < 0)
  30. throw new ArgumentOutOfRangeException("length");
  31. Debug.Assert(offset <= actualStream.Length);
  32. Debug.Assert(actualStream.Length >= length);
  33. Debug.Assert(offset + length <= actualStream.Length);
  34. m_offset = offset;
  35. m_position = offset;
  36. m_length = length;
  37. }
  38. public override long Length
  39. {
  40. get
  41. {
  42. ThrowIfDisposed();
  43. if (!m_length.HasValue)
  44. m_length = m_actualStream.Length - m_offset;
  45. return m_length.Value;
  46. }
  47. }
  48. public override long Position
  49. {
  50. get
  51. {
  52. ThrowIfDisposed();
  53. return m_position - m_offset;
  54. }
  55. set
  56. {
  57. ThrowIfDisposed();
  58. m_position = m_offset + value;
  59. }
  60. }
  61. public override bool CanRead { get { return m_actualStream.CanRead; } }
  62. public override bool CanSeek { get { return m_actualStream.CanSeek; } }
  63. public override bool CanWrite { get { return false; } }
  64. public override int Read(byte[] buffer, int offset, int count)
  65. {
  66. ThrowIfCantRead();
  67. ThrowIfDisposed();
  68. if ( m_actualStream.Position != m_position )
  69. m_actualStream.Seek(m_position, SeekOrigin.Begin);
  70. if ( m_length.HasValue )
  71. {
  72. var endPosition = m_offset + m_length.Value;
  73. if (m_position + count > endPosition)
  74. {
  75. count = (int)(endPosition - m_position);
  76. }
  77. }
  78. int bytesRead = m_actualStream.Read(buffer, offset, count);
  79. m_position += bytesRead;
  80. return bytesRead;
  81. }
  82. public override long Seek(long offset, SeekOrigin origin)
  83. {
  84. ThrowIfDisposed();
  85. if ( origin == SeekOrigin.Begin )
  86. {
  87. m_position = m_actualStream.Seek(m_offset + offset, SeekOrigin.Begin);
  88. }
  89. else if ( origin == SeekOrigin.End )
  90. {
  91. m_position = m_actualStream.Seek(m_offset + Length + offset, SeekOrigin.Begin);
  92. }
  93. else
  94. {
  95. m_position = m_actualStream.Seek(offset, SeekOrigin.Current);
  96. }
  97. return m_position - m_offset;
  98. }
  99. public override void SetLength(long value)
  100. {
  101. throw new NotSupportedException();
  102. }
  103. public override void Write(byte[] buffer, int offset, int count)
  104. {
  105. throw new NotSupportedException();
  106. }
  107. public override void Flush()
  108. {
  109. throw new NotSupportedException();
  110. }
  111. // Close the stream for reading. Note that this does NOT close the superStream (since
  112. // the substream is just 'a chunk' of the super-stream
  113. protected override void Dispose(bool disposing)
  114. {
  115. if ( disposing )
  116. {
  117. if (m_actualStream != null)
  118. {
  119. if (!m_leaveOpen)
  120. m_actualStream.Dispose();
  121. m_actualStream = null;
  122. }
  123. }
  124. base.Dispose(disposing);
  125. }
  126. private void ThrowIfDisposed()
  127. {
  128. if (m_actualStream == null)
  129. throw new ObjectDisposedException(GetType().ToString(), "");
  130. }
  131. private void ThrowIfCantRead()
  132. {
  133. if (!CanRead)
  134. throw new NotSupportedException();
  135. }
  136. }
  137. }