2006-06-02 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / corlib / System.IO / BinaryReader.cs
index ae382eac48f461b8993a19caa46a2376c5ae4f70..510d9dd58ba74d12d212dc7c0221be839a7e4936 100644 (file)
@@ -32,6 +32,7 @@
 using System;
 using System.Text;
 using System.Globalization;
+using Mono.Security;
 
 namespace System.IO {
        public class BinaryReader : IDisposable {
@@ -40,6 +41,15 @@ namespace System.IO {
                int m_encoding_max_byte;
 
                byte[] m_buffer;
+
+               Decoder decoder;
+               char [] charBuffer;
+               
+               //
+               // 128 chars should cover most strings in one grab.
+               //
+               const int MaxBufferSize = 128;
+
                
                private bool m_disposed = false;
 
@@ -54,7 +64,7 @@ namespace System.IO {
 
                        m_stream = input;
                        m_encoding = encoding;
-                       m_encoding_max_byte = m_encoding.GetMaxByteCount(1);
+                       decoder = encoding.GetDecoder ();
                        m_buffer = new byte [32];
                }
 
@@ -78,6 +88,7 @@ namespace System.IO {
                        m_buffer = null;
                        m_encoding = null;
                        m_stream = null;
+                       charBuffer = null;
                }
 
                void IDisposable.Dispose() 
@@ -307,7 +318,7 @@ namespace System.IO {
                                
                        if (pos!=count) {
                                byte[] new_buffer=new byte[pos];
-                               Array.Copy(buf, new_buffer, pos);
+                               Buffer.BlockCopyInternal (buf, 0, new_buffer, 0, pos);
                                return(new_buffer);
                        }
                        
@@ -329,6 +340,9 @@ namespace System.IO {
                                throw new ArgumentOutOfRangeException("count is less than 0");
                        }
 
+                       if (count == 0)
+                               return new char [0];
+                                       
                        char[] full = new char[count];
                        int chars = Read(full, 0, count);
                        
@@ -348,29 +362,47 @@ namespace System.IO {
 
                        decimal ret;
                        byte* ret_ptr = (byte *)&ret;
-                       for (int i = 0; i < 16; i++) {
-                         
-                               /*
-                                * internal representation of decimal is 
-                                * ss32, hi32, lo32, mi32, 
-                                * but in stream it is 
-                                * lo32, mi32, hi32, ss32
-                                * So we have to rerange this int32 values
-                                */                       
-                         
-                               if (i < 4) {
-                                       // lo 8 - 12                      
-                                       ret_ptr [i + 8] = m_buffer [i];
-                               } else if (i < 8) {
-                                       // mid 12 - 16
-                                       ret_ptr [i + 8] = m_buffer [i];
-                               } else if (i < 12) {
-                                       // hi 4 - 8
-                                       ret_ptr [i - 4] = m_buffer [i];
-                               } else if (i < 16) {
-                                       // ss 0 - 4
-                                       ret_ptr [i - 12] = m_buffer [i];
-                               }                               
+                       
+                       /*
+                        * internal representation of decimal is 
+                        * ss32, hi32, lo32, mi32, 
+                        * but in stream it is 
+                        * lo32, mi32, hi32, ss32
+                        * So we have to rerange this int32 values
+                        */                       
+                 
+                       if (BitConverter.IsLittleEndian) {
+                               for (int i = 0; i < 16; i++) {
+                                       if (i < 4) {
+                                               // lo 8 - 12                      
+                                               ret_ptr [i + 8] = m_buffer [i];
+                                       } else if (i < 8) {
+                                               // mid 12 - 16
+                                               ret_ptr [i + 8] = m_buffer [i];
+                                       } else if (i < 12) {
+                                               // hi 4 - 8
+                                               ret_ptr [i - 4] = m_buffer [i];
+                                       } else if (i < 16) {
+                                               // ss 0 - 4
+                                               ret_ptr [i - 12] = m_buffer [i];
+                                       }                               
+                               }
+                       } else {
+                               for (int i = 0; i < 16; i++) {
+                                       if (i < 4) {
+                                               // lo 8 - 12                      
+                                               ret_ptr [11 - i] = m_buffer [i];
+                                       } else if (i < 8) {
+                                               // mid 12 - 16
+                                               ret_ptr [19 - i] = m_buffer [i];
+                                       } else if (i < 12) {
+                                               // hi 4 - 8
+                                               ret_ptr [15 - i] = m_buffer [i];
+                                       } else if (i < 16) {
+                                               // ss 0 - 4
+                                               ret_ptr [15 - i] = m_buffer [i];
+                                       }                               
+                               }
                        }
 
                        return ret;
@@ -379,7 +411,7 @@ namespace System.IO {
                public virtual double ReadDouble() {
                        FillBuffer(8);
 
-                       return(BitConverter.ToDouble(m_buffer, 0));
+                       return(BitConverterLE.ToDouble(m_buffer, 0));
                }
 
                public virtual short ReadInt16() {
@@ -422,18 +454,50 @@ namespace System.IO {
                         * not chars
                         */
                        int len = Read7BitEncodedInt();
+                       
+                       if (len < 0)
+                               throw new IOException ("Invalid binary file (string len < 0)");
 
-                       FillBuffer(len);
+                       if (len == 0)
+                               return String.Empty;
                        
-                       char[] str = m_encoding.GetChars(m_buffer, 0, len);
+                       
+                       if (charBuffer == null)
+                               charBuffer = new char [MaxBufferSize];
+
+                       //
+                       // We read the string here in small chunks. Also, we
+                       // Attempt to optimize the common case of short strings.
+                       //
+                       StringBuilder sb = null;
+                       do {
+                               int readLen = (len > MaxBufferSize)
+                                               ? MaxBufferSize
+                                               : len;
+                               
+                               FillBuffer (readLen);
+                               
+                               int cch = decoder.GetChars (m_buffer, 0, readLen, charBuffer, 0);
+
+                               if (sb == null && readLen == len) // ok, we got out the easy way, dont bother with the sb
+                                       return new String (charBuffer, 0, cch);
+
+                               if (sb == null)
+                                       // Len is a fairly good estimate of the number of chars in a string
+                                       // Most of the time 1 byte == 1 char
+                                       sb = new StringBuilder (len);
+                               
+                               sb.Append (charBuffer, 0, cch);
+                               len -= readLen;
+                       } while (len > 0);
 
-                       return(new String(str));
+                       return sb.ToString();
                }
 
                public virtual float ReadSingle() {
                        FillBuffer(4);
 
-                       return(BitConverter.ToSingle(m_buffer, 0));
+                       return(BitConverterLE.ToSingle(m_buffer, 0));
                }
 
                [CLSCompliant(false)]
@@ -478,8 +542,7 @@ namespace System.IO {
                {
                        if(m_buffer.Length <= length) {
                                byte[] new_buffer=new byte[length];
-                               Array.Copy(m_buffer, new_buffer,
-                                          m_buffer.Length);
+                               Buffer.BlockCopyInternal (m_buffer, 0, new_buffer, 0, m_buffer.Length);
                                m_buffer=new_buffer;
                        }
                }