BinaryReader.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. //
  2. // System.IO.BinaryReader
  3. //
  4. // Author:
  5. // Matt Kimball ([email protected])
  6. // Dick Porter ([email protected])
  7. //
  8. using System;
  9. using System.Text;
  10. using System.Globalization;
  11. namespace System.IO {
  12. public class BinaryReader : IDisposable {
  13. Stream m_stream;
  14. Encoding m_encoding;
  15. int m_encoding_max_byte;
  16. byte[] m_buffer;
  17. byte[] m_peekBuffer;
  18. int m_peekIndex = 0;
  19. int m_peekLimit = 0;
  20. private bool m_disposed = false;
  21. public BinaryReader(Stream input) : this(input, Encoding.UTF8Unmarked) {
  22. }
  23. public BinaryReader(Stream input, Encoding encoding) {
  24. if (input == null || encoding == null)
  25. throw new ArgumentNullException(Locale.GetText ("Input or Encoding is a null reference."));
  26. if (!input.CanRead)
  27. throw new ArgumentException(Locale.GetText ("The stream doesn't support reading."));
  28. m_stream = input;
  29. m_encoding = encoding;
  30. m_encoding_max_byte = m_encoding.GetMaxByteCount(1);
  31. m_buffer = new byte [32];
  32. }
  33. public virtual Stream BaseStream {
  34. get {
  35. return m_stream;
  36. }
  37. }
  38. public virtual void Close() {
  39. Dispose (true);
  40. m_disposed = true;
  41. }
  42. protected virtual void Dispose (bool disposing)
  43. {
  44. if (disposing && m_stream != null)
  45. m_stream.Close ();
  46. m_disposed = true;
  47. m_buffer = null;
  48. m_encoding = null;
  49. m_stream = null;
  50. }
  51. void IDisposable.Dispose()
  52. {
  53. Dispose (true);
  54. }
  55. protected virtual void FillBuffer(int bytes) {
  56. if(m_stream==null) {
  57. throw new IOException("Stream is invalid");
  58. }
  59. CheckBuffer(bytes);
  60. /* Cope with partial reads */
  61. int pos=0;
  62. while (m_peekIndex < m_peekLimit)
  63. m_buffer[pos++] = m_peekBuffer[m_peekIndex++];
  64. while(pos<bytes) {
  65. int n=m_stream.Read(m_buffer, pos, bytes-pos);
  66. if(n==0) {
  67. throw new EndOfStreamException();
  68. }
  69. pos+=n;
  70. }
  71. }
  72. public virtual int PeekChar() {
  73. if(m_stream==null) {
  74. if (m_disposed)
  75. throw new ObjectDisposedException ("BinaryReader", "Cannot read from a closed BinaryReader.");
  76. throw new IOException("Stream is invalid");
  77. }
  78. char[] result = new char[1];
  79. byte[] bytes;
  80. int bcount;
  81. int ccount = ReadCharBytes (result, 0, 1, out bytes, out bcount);
  82. if (m_peekBuffer == null || m_peekBuffer.Length < bcount)
  83. m_peekBuffer = new byte[bcount];
  84. Array.Copy (bytes, m_peekBuffer, bcount);
  85. m_peekIndex = 0;
  86. m_peekLimit = bcount;
  87. if (ccount == 0) return -1;
  88. else return result[0];
  89. }
  90. public virtual int Read() {
  91. char[] decode = new char[1];
  92. int count=Read(decode, 0, 1);
  93. if(count==0) {
  94. /* No chars available */
  95. return(-1);
  96. }
  97. return decode[0];
  98. }
  99. public virtual int Read(byte[] buffer, int index, int count) {
  100. if(m_stream==null) {
  101. if (m_disposed)
  102. throw new ObjectDisposedException ("BinaryReader", "Cannot read from a closed BinaryReader.");
  103. throw new IOException("Stream is invalid");
  104. }
  105. if (buffer == null) {
  106. throw new ArgumentNullException("buffer is null");
  107. }
  108. if (buffer.Length - index < count) {
  109. throw new ArgumentException("buffer is too small");
  110. }
  111. if (index < 0) {
  112. throw new ArgumentOutOfRangeException("index is less than 0");
  113. }
  114. if (count < 0) {
  115. throw new ArgumentOutOfRangeException("count is less than 0");
  116. }
  117. while (m_peekIndex < m_peekLimit) {
  118. buffer[index++] = m_peekBuffer[m_peekIndex++]; count--;
  119. }
  120. int bytes_read=m_stream.Read(buffer, index, count);
  121. return(bytes_read);
  122. }
  123. public virtual int Read(char[] buffer, int index, int count) {
  124. if(m_stream==null) {
  125. if (m_disposed)
  126. throw new ObjectDisposedException ("BinaryReader", "Cannot read from a closed BinaryReader.");
  127. throw new IOException("Stream is invalid");
  128. }
  129. if (buffer == null) {
  130. throw new ArgumentNullException("buffer is null");
  131. }
  132. if (buffer.Length - index < count) {
  133. throw new ArgumentException("buffer is too small");
  134. }
  135. if (index < 0) {
  136. throw new ArgumentOutOfRangeException("index is less than 0");
  137. }
  138. if (count < 0) {
  139. throw new ArgumentOutOfRangeException("count is less than 0");
  140. }
  141. int bytes_read;
  142. byte[] bytes;
  143. return ReadCharBytes (buffer, index, count, out bytes, out bytes_read);
  144. }
  145. private int ReadCharBytes(char[] buffer, int index, int count, out byte[] bytes, out int bytes_read)
  146. {
  147. int chars_read=0;
  148. bytes_read=0;
  149. while(chars_read < count) {
  150. CheckBuffer(bytes_read + 1);
  151. int read_byte = (m_peekIndex < m_peekLimit) ? m_peekBuffer[m_peekIndex++] : m_stream.ReadByte();
  152. if(read_byte==-1) {
  153. /* EOF */
  154. bytes = m_buffer;
  155. return(chars_read);
  156. }
  157. m_buffer[bytes_read]=(byte)read_byte;
  158. bytes_read++;
  159. chars_read=m_encoding.GetChars(m_buffer, 0,
  160. bytes_read,
  161. buffer, index);
  162. }
  163. bytes = m_buffer;
  164. return(chars_read);
  165. }
  166. protected int Read7BitEncodedInt() {
  167. int ret = 0;
  168. int shift = 0;
  169. byte b;
  170. do {
  171. b = ReadByte();
  172. ret = ret | ((b & 0x7f) << shift);
  173. shift += 7;
  174. } while ((b & 0x80) == 0x80);
  175. return ret;
  176. }
  177. public virtual bool ReadBoolean() {
  178. FillBuffer(1);
  179. // Return value:
  180. // true if the byte is non-zero; otherwise false.
  181. return(m_buffer[0] != 0);
  182. }
  183. public virtual byte ReadByte() {
  184. FillBuffer(1);
  185. return(m_buffer[0]);
  186. }
  187. public virtual byte[] ReadBytes(int count) {
  188. if(m_stream==null) {
  189. if (m_disposed)
  190. throw new ObjectDisposedException ("BinaryReader", "Cannot read from a closed BinaryReader.");
  191. throw new IOException("Stream is invalid");
  192. }
  193. if (count < 0) {
  194. throw new ArgumentOutOfRangeException("count is less than 0");
  195. }
  196. /* Can't use FillBuffer() here, because it's OK to
  197. * return fewer bytes than were requested
  198. */
  199. byte[] buf = new byte[count];
  200. int pos=0;
  201. while (m_peekIndex < m_peekLimit)
  202. buf[pos++] = m_peekBuffer[m_peekIndex++];
  203. while(pos < count)
  204. {
  205. int n=m_stream.Read(buf, pos, count-pos);
  206. if(n==0) {
  207. /* EOF */
  208. break;
  209. }
  210. pos+=n;
  211. }
  212. if (pos!=count) {
  213. byte[] new_buffer=new byte[pos];
  214. Array.Copy(buf, new_buffer, pos);
  215. return(new_buffer);
  216. }
  217. return(buf);
  218. }
  219. public virtual char ReadChar() {
  220. int ch=Read();
  221. if(ch==-1) {
  222. throw new EndOfStreamException();
  223. }
  224. return((char)ch);
  225. }
  226. public virtual char[] ReadChars(int count) {
  227. if (count < 0) {
  228. throw new ArgumentOutOfRangeException("count is less than 0");
  229. }
  230. char[] full = new char[count];
  231. int chars = Read(full, 0, count);
  232. if (chars == 0) {
  233. throw new EndOfStreamException();
  234. } else if (chars != full.Length) {
  235. char[] ret = new char[chars];
  236. Array.Copy(full, 0, ret, 0, chars);
  237. return ret;
  238. } else {
  239. return full;
  240. }
  241. }
  242. unsafe public virtual decimal ReadDecimal() {
  243. FillBuffer(16);
  244. decimal ret;
  245. byte* ret_ptr = (byte *)&ret;
  246. for (int i = 0; i < 16; i++) {
  247. /*
  248. * internal representation of decimal is
  249. * ss32, hi32, lo32, mi32,
  250. * but in stream it is
  251. * lo32, mi32, hi32, ss32
  252. * So we have to rerange this int32 values
  253. */
  254. if (i < 4) {
  255. // lo 8 - 12
  256. ret_ptr [i + 8] = m_buffer [i];
  257. } else if (i < 8) {
  258. // mid 12 - 16
  259. ret_ptr [i + 8] = m_buffer [i];
  260. } else if (i < 12) {
  261. // hi 4 - 8
  262. ret_ptr [i - 4] = m_buffer [i];
  263. } else if (i < 16) {
  264. // ss 0 - 4
  265. ret_ptr [i - 12] = m_buffer [i];
  266. }
  267. }
  268. return ret;
  269. }
  270. public virtual double ReadDouble() {
  271. FillBuffer(8);
  272. return(BitConverter.ToDouble(m_buffer, 0));
  273. }
  274. public virtual short ReadInt16() {
  275. FillBuffer(2);
  276. return((short) (m_buffer[0] | (m_buffer[1] << 8)));
  277. }
  278. public virtual int ReadInt32() {
  279. FillBuffer(4);
  280. return(m_buffer[0] | (m_buffer[1] << 8) |
  281. (m_buffer[2] << 16) | (m_buffer[3] << 24));
  282. }
  283. public virtual long ReadInt64() {
  284. FillBuffer(8);
  285. uint ret_low = (uint) (m_buffer[0] |
  286. (m_buffer[1] << 8) |
  287. (m_buffer[2] << 16) |
  288. (m_buffer[3] << 24)
  289. );
  290. uint ret_high = (uint) (m_buffer[4] |
  291. (m_buffer[5] << 8) |
  292. (m_buffer[6] << 16) |
  293. (m_buffer[7] << 24)
  294. );
  295. return (long) ((((ulong) ret_high) << 32) | ret_low);
  296. }
  297. [CLSCompliant(false)]
  298. public virtual sbyte ReadSByte() {
  299. FillBuffer(1);
  300. return((sbyte)m_buffer[0]);
  301. }
  302. public virtual string ReadString() {
  303. /* Inspection of BinaryWriter-written files
  304. * shows that the length is given in bytes,
  305. * not chars
  306. */
  307. int len = Read7BitEncodedInt();
  308. FillBuffer(len);
  309. char[] str = m_encoding.GetChars(m_buffer, 0, len);
  310. return(new String(str));
  311. }
  312. public virtual float ReadSingle() {
  313. FillBuffer(4);
  314. return(BitConverter.ToSingle(m_buffer, 0));
  315. }
  316. [CLSCompliant(false)]
  317. public virtual ushort ReadUInt16() {
  318. FillBuffer(2);
  319. return((ushort) (m_buffer[0] | (m_buffer[1] << 8)));
  320. }
  321. [CLSCompliant(false)]
  322. public virtual uint ReadUInt32() {
  323. FillBuffer(4);
  324. return((uint) (m_buffer[0] |
  325. (m_buffer[1] << 8) |
  326. (m_buffer[2] << 16) |
  327. (m_buffer[3] << 24)));
  328. }
  329. [CLSCompliant(false)]
  330. public virtual ulong ReadUInt64() {
  331. FillBuffer(8);
  332. uint ret_low = (uint) (m_buffer[0] |
  333. (m_buffer[1] << 8) |
  334. (m_buffer[2] << 16) |
  335. (m_buffer[3] << 24)
  336. );
  337. uint ret_high = (uint) (m_buffer[4] |
  338. (m_buffer[5] << 8) |
  339. (m_buffer[6] << 16) |
  340. (m_buffer[7] << 24)
  341. );
  342. return (((ulong) ret_high) << 32) | ret_low;
  343. }
  344. /* Ensures that m_buffer is at least length bytes
  345. * long, growing it if necessary
  346. */
  347. private void CheckBuffer(int length)
  348. {
  349. if(m_buffer.Length <= length) {
  350. byte[] new_buffer=new byte[length];
  351. Array.Copy(m_buffer, new_buffer,
  352. m_buffer.Length);
  353. m_buffer=new_buffer;
  354. }
  355. }
  356. }
  357. }