StreamReader.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. //
  2. // System.IO.StreamReader.cs
  3. //
  4. // Author:
  5. // Dietmar Maurer ([email protected])
  6. //
  7. // (C) Ximian, Inc. http://www.ximian.com
  8. //
  9. using System;
  10. using System.Text;
  11. namespace System.IO {
  12. [Serializable]
  13. public class StreamReader : TextReader {
  14. private const int DefaultBufferSize = 1024;
  15. private const int DefaultFileBufferSize = 4096;
  16. private const int MinimumBufferSize = 128;
  17. // buffering members
  18. private byte [] rgbEncoded;
  19. // private int cbEncoded;
  20. private char [] rgchDecoded;
  21. private int cchDecoded;
  22. private int pos;
  23. private Encoding internalEncoding;
  24. private Decoder decoder;
  25. private Stream internalStream;
  26. [MonoTODO("Make Read methods return 0, etc.")]
  27. private class NullStreamReader : StreamReader {
  28. }
  29. public new static readonly StreamReader Null = (StreamReader)(new NullStreamReader());
  30. internal StreamReader() {}
  31. public StreamReader(Stream stream)
  32. : this (stream, null, false, DefaultBufferSize) { }
  33. public StreamReader(Stream stream, bool detectEncodingFromByteOrderMarks)
  34. : this (stream, null, detectEncodingFromByteOrderMarks, DefaultBufferSize) { }
  35. public StreamReader(Stream stream, Encoding encoding)
  36. : this (stream, encoding, false, DefaultBufferSize) { }
  37. public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks)
  38. : this (stream, encoding, detectEncodingFromByteOrderMarks, DefaultBufferSize) { }
  39. public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)
  40. {
  41. Initialize (stream, encoding, detectEncodingFromByteOrderMarks, bufferSize);
  42. }
  43. public StreamReader(string path)
  44. : this (path, null, false, DefaultFileBufferSize) { }
  45. public StreamReader(string path, bool detectEncodingFromByteOrderMarks)
  46. : this (path, null, detectEncodingFromByteOrderMarks, DefaultFileBufferSize) { }
  47. public StreamReader(string path, Encoding encoding)
  48. : this (path, encoding, false, DefaultFileBufferSize) { }
  49. public StreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks)
  50. : this (path, encoding, detectEncodingFromByteOrderMarks, DefaultFileBufferSize) { }
  51. [MonoTODO]
  52. public StreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)
  53. {
  54. if (null == path)
  55. throw new ArgumentNullException();
  56. if (String.Empty == path)
  57. throw new ArgumentException();
  58. Stream stream = (Stream) File.OpenRead (path);
  59. Initialize (stream, encoding, detectEncodingFromByteOrderMarks, bufferSize);
  60. }
  61. [MonoTODO]
  62. protected void Initialize (Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)
  63. {
  64. if (null == stream)
  65. throw new ArgumentNullException();
  66. if (!stream.CanRead)
  67. throw new ArgumentException("Cannot read stream");
  68. internalStream = stream;
  69. // use detect encoding flag
  70. if (encoding == null) {
  71. internalEncoding = Encoding.UTF8;
  72. decoder = Encoding.UTF8.GetDecoder ();
  73. } else {
  74. internalEncoding = encoding;
  75. decoder = encoding.GetDecoder ();
  76. }
  77. if (bufferSize < MinimumBufferSize)
  78. bufferSize = MinimumBufferSize;
  79. rgbEncoded = new byte [bufferSize];
  80. rgchDecoded = new char [internalEncoding.GetMaxCharCount (bufferSize)];
  81. pos = 0;
  82. cchDecoded = 0;
  83. }
  84. public virtual Stream BaseStream
  85. {
  86. get {
  87. return internalStream;
  88. }
  89. }
  90. public virtual Encoding CurrentEncoding
  91. {
  92. get {
  93. return internalEncoding;
  94. }
  95. }
  96. public override void Close ()
  97. {
  98. Dispose (true);
  99. }
  100. public void DiscardBufferedData ()
  101. {
  102. pos = 0;
  103. cchDecoded = 0;
  104. /* I'm sure there's no need to do all this
  105. if ((cchDecoded == null) || (pos == cchDecoded.Length))
  106. return;
  107. if (!internalStream.CanSeek)
  108. return;
  109. int seek_back = pos - cchDecoded.Length;
  110. internalStream.Seek (seek_back, SeekOrigin.Current);
  111. */
  112. }
  113. // the buffer is empty, fill it again
  114. [MonoTODO ("handle byte order marks here")]
  115. private int ReadBuffer ()
  116. {
  117. pos = 0;
  118. int cbEncoded = 0;
  119. cchDecoded = 0;
  120. do // keep looping until the decoder gives us some chars
  121. {
  122. cbEncoded = internalStream.Read (rgbEncoded, 0, rgbEncoded.Length);
  123. // TODO: remove this line when iconv is fixed
  124. int bufcnt = decoder.GetCharCount (rgbEncoded, 0, cbEncoded);
  125. if (cbEncoded == 0)
  126. return 0;
  127. // TODO: remove byte order marks here
  128. cchDecoded += decoder.GetChars (rgbEncoded, 0, cbEncoded, rgchDecoded, 0);
  129. } while (cchDecoded == 0);
  130. return cchDecoded;
  131. }
  132. public override int Peek ()
  133. {
  134. if (!internalStream.CanSeek)
  135. return -1;
  136. if (pos >= cchDecoded && ReadBuffer () == 0)
  137. return -1;
  138. return rgchDecoded [pos];
  139. }
  140. public override int Read ()
  141. {
  142. if (pos >= cchDecoded && ReadBuffer () == 0)
  143. return -1;
  144. return rgchDecoded [pos++];
  145. }
  146. public override int Read (char[] dest_buffer, int index, int count)
  147. {
  148. if (dest_buffer == null)
  149. throw new ArgumentException ();
  150. if ((index < 0) || (count < 0))
  151. throw new ArgumentOutOfRangeException ();
  152. if (index + count > dest_buffer.Length)
  153. throw new ArgumentException ();
  154. int cchRead = 0;
  155. while (count > 0)
  156. {
  157. if (pos >= cchDecoded && ReadBuffer () == 0)
  158. return cchRead > 0? cchRead: -1;
  159. int cch = Math.Min (cchDecoded - pos, count);
  160. Array.Copy (rgchDecoded, pos, dest_buffer, index, cch);
  161. pos += cch;
  162. index += cch;
  163. count -= cch;
  164. cchRead += cch;
  165. }
  166. return cchRead;
  167. }
  168. public override string ReadLine()
  169. {
  170. StringBuilder text = new StringBuilder ();
  171. while (true) {
  172. int c = Read ();
  173. if (c == -1) { // end of stream
  174. if (text.Length == 0)
  175. return null;
  176. break;
  177. }
  178. if (c == '\n') // newline
  179. break;
  180. if (c == '\r' && Peek () == '\n') { // cr, newline
  181. Read ();
  182. break;
  183. }
  184. text.Append ((char) c);
  185. }
  186. return text.ToString ();
  187. }
  188. public override string ReadToEnd()
  189. {
  190. StringBuilder text = new StringBuilder ();
  191. int c;
  192. while ((c = Read ()) != -1) {
  193. text.Append ((char) c);
  194. }
  195. if (text.Length == 0)
  196. return String.Empty;
  197. return text.ToString ();
  198. }
  199. }
  200. }