StreamReader.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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. private class NullStreamReader : StreamReader {
  27. public override int Peek ()
  28. {
  29. return -1;
  30. }
  31. public override int Read ()
  32. {
  33. return -1;
  34. }
  35. public override int Read (char[] buffer, int index, int count)
  36. {
  37. return 0;
  38. }
  39. public override string ReadLine ()
  40. {
  41. return null;
  42. }
  43. public override string ReadToEnd ()
  44. {
  45. return String.Empty;
  46. }
  47. public override Stream BaseStream
  48. {
  49. get { return Stream.Null; }
  50. }
  51. public override Encoding CurrentEncoding
  52. {
  53. get { return Encoding.Unicode; }
  54. }
  55. }
  56. public new static readonly StreamReader Null = (StreamReader)(new NullStreamReader());
  57. internal StreamReader() {}
  58. public StreamReader(Stream stream)
  59. : this (stream, null, false, DefaultBufferSize) { }
  60. public StreamReader(Stream stream, bool detectEncodingFromByteOrderMarks)
  61. : this (stream, null, detectEncodingFromByteOrderMarks, DefaultBufferSize) { }
  62. public StreamReader(Stream stream, Encoding encoding)
  63. : this (stream, encoding, false, DefaultBufferSize) { }
  64. public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks)
  65. : this (stream, encoding, detectEncodingFromByteOrderMarks, DefaultBufferSize) { }
  66. public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)
  67. {
  68. Initialize (stream, encoding, detectEncodingFromByteOrderMarks, bufferSize);
  69. }
  70. public StreamReader(string path)
  71. : this (path, null, false, DefaultFileBufferSize) { }
  72. public StreamReader(string path, bool detectEncodingFromByteOrderMarks)
  73. : this (path, null, detectEncodingFromByteOrderMarks, DefaultFileBufferSize) { }
  74. public StreamReader(string path, Encoding encoding)
  75. : this (path, encoding, false, DefaultFileBufferSize) { }
  76. public StreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks)
  77. : this (path, encoding, detectEncodingFromByteOrderMarks, DefaultFileBufferSize) { }
  78. [MonoTODO]
  79. public StreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)
  80. {
  81. if (null == path)
  82. throw new ArgumentNullException();
  83. if (String.Empty == path)
  84. throw new ArgumentException();
  85. if (path.IndexOfAny (Path.InvalidPathChars) != -1)
  86. throw new ArgumentException("path contains invalid characters");
  87. string DirName = Path.GetDirectoryName(path);
  88. if (DirName != String.Empty && !Directory.Exists(DirName))
  89. throw new DirectoryNotFoundException();
  90. if (!File.Exists(path))
  91. throw new FileNotFoundException(path);
  92. Stream stream = (Stream) File.OpenRead (path);
  93. Initialize (stream, encoding, detectEncodingFromByteOrderMarks, bufferSize);
  94. }
  95. [MonoTODO]
  96. protected void Initialize (Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)
  97. {
  98. if (null == stream)
  99. throw new ArgumentNullException();
  100. if (!stream.CanRead)
  101. throw new ArgumentException("Cannot read stream");
  102. internalStream = stream;
  103. // use detect encoding flag
  104. if (encoding == null) {
  105. internalEncoding = Encoding.UTF8;
  106. decoder = Encoding.UTF8.GetDecoder ();
  107. } else {
  108. internalEncoding = encoding;
  109. decoder = encoding.GetDecoder ();
  110. }
  111. if (bufferSize < MinimumBufferSize)
  112. bufferSize = MinimumBufferSize;
  113. rgbEncoded = new byte [bufferSize];
  114. rgchDecoded = new char [internalEncoding.GetMaxCharCount (bufferSize)];
  115. pos = 0;
  116. cchDecoded = 0;
  117. }
  118. public virtual Stream BaseStream
  119. {
  120. get {
  121. return internalStream;
  122. }
  123. }
  124. public virtual Encoding CurrentEncoding
  125. {
  126. get {
  127. return internalEncoding;
  128. }
  129. }
  130. public override void Close ()
  131. {
  132. Dispose (true);
  133. }
  134. protected override void Dispose (bool disposing)
  135. {
  136. if (disposing)
  137. internalStream.Close ();
  138. rgbEncoded = null;
  139. rgchDecoded = null;
  140. }
  141. public void DiscardBufferedData ()
  142. {
  143. pos = 0;
  144. cchDecoded = 0;
  145. /* I'm sure there's no need to do all this
  146. if ((cchDecoded == null) || (pos == cchDecoded.Length))
  147. return;
  148. if (!internalStream.CanSeek)
  149. return;
  150. int seek_back = pos - cchDecoded.Length;
  151. internalStream.Seek (seek_back, SeekOrigin.Current);
  152. */
  153. }
  154. // the buffer is empty, fill it again
  155. [MonoTODO ("handle byte order marks here")]
  156. private int ReadBuffer ()
  157. {
  158. pos = 0;
  159. int cbEncoded = 0;
  160. cchDecoded = 0;
  161. do // keep looping until the decoder gives us some chars
  162. {
  163. cbEncoded = internalStream.Read (rgbEncoded, 0, rgbEncoded.Length);
  164. // TODO: remove this line when iconv is fixed
  165. int bufcnt = decoder.GetCharCount (rgbEncoded, 0, cbEncoded);
  166. if (cbEncoded == 0)
  167. return 0;
  168. // TODO: remove byte order marks here
  169. cchDecoded += decoder.GetChars (rgbEncoded, 0, cbEncoded, rgchDecoded, 0);
  170. } while (cchDecoded == 0);
  171. return cchDecoded;
  172. }
  173. public override int Peek ()
  174. {
  175. if (!internalStream.CanSeek)
  176. return -1;
  177. if (pos >= cchDecoded && ReadBuffer () == 0)
  178. return -1;
  179. return rgchDecoded [pos];
  180. }
  181. public override int Read ()
  182. {
  183. if (pos >= cchDecoded && ReadBuffer () == 0)
  184. return -1;
  185. return rgchDecoded [pos++];
  186. }
  187. public override int Read (char[] dest_buffer, int index, int count)
  188. {
  189. if (dest_buffer == null)
  190. throw new ArgumentException ();
  191. if ((index < 0) || (count < 0))
  192. throw new ArgumentOutOfRangeException ();
  193. if (index + count > dest_buffer.Length)
  194. throw new ArgumentException ();
  195. int cchRead = 0;
  196. while (count > 0)
  197. {
  198. if (pos >= cchDecoded && ReadBuffer () == 0)
  199. return cchRead > 0? cchRead: -1;
  200. int cch = Math.Min (cchDecoded - pos, count);
  201. Array.Copy (rgchDecoded, pos, dest_buffer, index, cch);
  202. pos += cch;
  203. index += cch;
  204. count -= cch;
  205. cchRead += cch;
  206. }
  207. return cchRead;
  208. }
  209. public override string ReadLine()
  210. {
  211. StringBuilder text = new StringBuilder ();
  212. while (true) {
  213. int c = Read ();
  214. if (c == -1) { // end of stream
  215. if (text.Length == 0)
  216. return null;
  217. break;
  218. }
  219. if (c == '\n') { // newline
  220. if ((text.Length > 0) && (text [text.Length - 1] == '\r'))
  221. text.Length--;
  222. break;
  223. }
  224. text.Append ((char) c);
  225. }
  226. return text.ToString ();
  227. }
  228. public override string ReadToEnd()
  229. {
  230. StringBuilder text = new StringBuilder ();
  231. int c;
  232. while ((c = Read ()) != -1) {
  233. text.Append ((char) c);
  234. }
  235. if (text.Length == 0)
  236. return String.Empty;
  237. return text.ToString ();
  238. }
  239. }
  240. }