BufferedStream.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. //
  2. // System.IO.BufferedStream
  3. //
  4. // Author:
  5. // Matt Kimball ([email protected])
  6. // Ville Palo <[email protected]>
  7. //
  8. using System.Runtime.InteropServices;
  9. namespace System.IO {
  10. public sealed class BufferedStream : Stream {
  11. Stream m_stream;
  12. byte[] m_buffer;
  13. int m_buffer_pos;
  14. int m_buffer_read_ahead;
  15. bool m_buffer_reading;
  16. private bool disposed = false;
  17. public BufferedStream(Stream stream) : this(stream, 4096) {
  18. }
  19. public BufferedStream(Stream stream, int buffer_size) {
  20. if (stream == null)
  21. throw new ArgumentNullException ("stream was null");
  22. if (buffer_size < 0)
  23. throw new ArgumentOutOfRangeException ();
  24. if (!stream.CanRead && !stream.CanWrite)
  25. throw new ObjectDisposedException ("Cannot access a closed Stream.");
  26. m_stream = stream;
  27. m_buffer = new byte[buffer_size];
  28. }
  29. public override bool CanRead {
  30. get {
  31. return m_stream.CanRead;
  32. }
  33. }
  34. public override bool CanWrite {
  35. get {
  36. return m_stream.CanWrite;
  37. }
  38. }
  39. public override bool CanSeek {
  40. get {
  41. return m_stream.CanSeek;
  42. }
  43. }
  44. public override long Length {
  45. get {
  46. Flush ();
  47. return m_stream.Length;
  48. }
  49. }
  50. public override long Position {
  51. get {
  52. CheckObjectDisposedException ();
  53. return m_stream.Position - m_buffer_read_ahead + m_buffer_pos;
  54. }
  55. set {
  56. Flush();
  57. m_stream.Position = value;
  58. }
  59. }
  60. public override void Close() {
  61. if (m_buffer != null)
  62. Flush();
  63. m_stream.Close();
  64. m_buffer = null;
  65. disposed = true;
  66. }
  67. public override void Flush() {
  68. CheckObjectDisposedException ();
  69. if (m_buffer_reading) {
  70. if (CanSeek)
  71. m_stream.Position = Position;
  72. } else if (m_buffer_pos > 0) {
  73. m_stream.Write(m_buffer, 0, m_buffer_pos);
  74. }
  75. m_buffer_read_ahead = 0;
  76. m_buffer_pos = 0;
  77. }
  78. public override long Seek(long offset, SeekOrigin origin) {
  79. Flush();
  80. return m_stream.Seek(offset, origin);
  81. }
  82. public override void SetLength(long value) {
  83. m_stream.SetLength(value);
  84. }
  85. public override int ReadByte() {
  86. CheckObjectDisposedException ();
  87. byte[] b = new byte[1];
  88. if (Read(b, 0, 1) == 1) {
  89. return b[0];
  90. } else {
  91. return -1;
  92. }
  93. }
  94. public override void WriteByte(byte value) {
  95. CheckObjectDisposedException ();
  96. byte[] b = new byte[1];
  97. b[0] = value;
  98. Write(b, 0, 1);
  99. }
  100. public override int Read([In,Out] byte[] array, int offset, int count) {
  101. CheckObjectDisposedException ();
  102. if (array.Length < offset + count)
  103. throw new ArgumentException ();
  104. if (offset < 0)
  105. throw new ArgumentOutOfRangeException ("Offset was negative value.");
  106. if (!m_buffer_reading) {
  107. Flush();
  108. m_buffer_reading = true;
  109. }
  110. if (count <= m_buffer_read_ahead - m_buffer_pos) {
  111. Array.Copy(m_buffer, m_buffer_pos, array, offset, count);
  112. m_buffer_pos += count;
  113. if (m_buffer_pos == m_buffer_read_ahead) {
  114. m_buffer_pos = 0;
  115. m_buffer_read_ahead = 0;
  116. }
  117. return count;
  118. }
  119. int ret = m_buffer_read_ahead - m_buffer_pos;
  120. Array.Copy(m_buffer, m_buffer_pos, array, offset, ret);
  121. m_buffer_pos = 0;
  122. m_buffer_read_ahead = 0;
  123. offset += ret;
  124. count -= ret;
  125. if (count >= m_buffer.Length) {
  126. ret += m_stream.Read(array, offset, count);
  127. } else {
  128. m_buffer_read_ahead = m_stream.Read(m_buffer, 0, m_buffer.Length);
  129. if (count < m_buffer_read_ahead) {
  130. Array.Copy(m_buffer, 0, array, offset, count);
  131. m_buffer_pos = count;
  132. ret += count;
  133. } else {
  134. Array.Copy(m_buffer, 0, array, offset, m_buffer_read_ahead);
  135. ret += m_buffer_read_ahead;
  136. m_buffer_read_ahead = 0;
  137. }
  138. }
  139. return ret;
  140. }
  141. public override void Write(byte[] array, int offset, int count) {
  142. CheckObjectDisposedException ();
  143. if (!m_stream.CanWrite)
  144. throw new NotSupportedException ();
  145. if (offset < 0)
  146. throw new ArgumentOutOfRangeException ();
  147. if (m_buffer_reading) {
  148. Flush();
  149. m_buffer_reading = false;
  150. }
  151. if (m_buffer_pos + count >= m_buffer.Length) {
  152. Flush();
  153. m_stream.Write(array, offset, count);
  154. } else {
  155. Array.Copy(array, offset, m_buffer, m_buffer_pos, count);
  156. m_buffer_pos += count;
  157. }
  158. }
  159. private void CheckObjectDisposedException ()
  160. {
  161. if (disposed)
  162. throw new ObjectDisposedException ("BufferedStream", "Stream is closed");
  163. }
  164. }
  165. }