Merge pull request #93 from konrad-kruczynski/dispatcher_timer_fix
[mono.git] / mcs / class / System.XML / System.Xml / XmlInputStream.cs
index 82bb9505cf5e89caa88b7fcfea983e6584cabf6c..01e0ab0461e62390c3f7d16e75a25505f616463f 100644 (file)
@@ -51,11 +51,29 @@ namespace System.Xml
                {
                }
 
+               static XmlException invalidDataException = new XmlException ("invalid data.");
+
                public override void Close ()
                {
                        this.input.Close ();
                }
 
+               public override int Read ([In, Out] char[] dest_buffer, int index, int count)
+               {
+                       try {
+                               return base.Read (dest_buffer, index, count);
+                       }
+#if NET_1_1
+                       catch (System.ArgumentException ex) {
+                               throw new XmlException ("Invalid data", ex);
+                       }
+#else
+                       catch (System.Text.DecoderFallbackException) {
+                               throw invalidDataException;
+                       }
+#endif
+               }
+
                protected override void Dispose (bool disposing)
                {
                        base.Dispose (disposing);
@@ -321,11 +339,14 @@ namespace System.Xml
 
        class XmlInputStream : Stream
        {
-               public static readonly Encoding StrictUTF8;
+               internal static readonly Encoding StrictUTF8, Strict1234UTF32, StrictBigEndianUTF16, StrictUTF16;
 
                static XmlInputStream ()
                {
                        StrictUTF8 = new UTF8Encoding (false, true);
+                       Strict1234UTF32 = new UTF32Encoding (true, false, true);
+                       StrictBigEndianUTF16 = new UnicodeEncoding (true, false, true);
+                       StrictUTF16 = new UnicodeEncoding (false, false, true);
                }
 
                Encoding enc;
@@ -341,22 +362,28 @@ namespace System.Xml
                        Initialize (stream);
                }
 
-               static string GetStringFromBytes (byte [] bytes, int index, int count)
+               // this returns null, instead of throwing ArgumentOutOfRangeException
+               string GetStringFromBytes (int index, int count)
                {
-#if NET_2_1
+                       int posBak = bufPos;
+                       while (bufPos < index + count)
+                               if (ReadByteSpecial () < 0)
+                                       return null;
+                       bufPos = posBak;
+#if MOONLIGHT
                        char [] chars = new char [count];
                        for (int i = index; i < count; i++)
-                               chars [i] = (char) bytes [i];
+                               chars [i] = (char) buffer [i];
 
                        return new string (chars);
 #else
-                       return Encoding.ASCII.GetString (bytes, index, count);
+                       return Encoding.ASCII.GetString (buffer, index, count);
 #endif
                }
 
                private void Initialize (Stream stream)
                {
-                       buffer = new byte [64];
+                       buffer = new byte [6];
                        this.stream = stream;
                        enc = StrictUTF8; // Default to UTF8 if we can't guess it
                        bufLength = stream.Read (buffer, 0, buffer.Length);
@@ -398,9 +425,23 @@ namespace System.Xml
                                        buffer [--bufPos] = 0xEF;
                                }
                                break;
+                       case 0:
+                               // It could still be 1234/2143/3412 variants of UTF32, but only 1234 version is available on .NET.
+                               c = ReadByteSpecial ();
+                               if (c == 0)
+                                       enc = Strict1234UTF32;
+                               else
+                                       enc = StrictBigEndianUTF16;
+                               break;
                        case '<':
-                               // try to get encoding name from XMLDecl.
-                               if (bufLength >= 5 && GetStringFromBytes (buffer, 1, 4) == "?xml") {
+                               c = ReadByteSpecial ();
+                               if (c == 0) {
+                                       if (ReadByteSpecial () == 0)
+                                               enc = Encoding.UTF32; // little endian UTF32
+                                       else
+                                               enc = Encoding.Unicode; // little endian UTF16
+                               } else if (bufLength >= 4 && GetStringFromBytes (1, 4) == "?xml") {
+                                       // try to get encoding name from XMLDecl.
                                        bufPos += 4;
                                        c = SkipWhitespace ();
 
@@ -417,8 +458,7 @@ namespace System.Xml
                                        }
 
                                        if (c == 'e') {
-                                               int remaining = bufLength - bufPos;
-                                               if (remaining >= 7 && GetStringFromBytes (buffer, bufPos, 7) == "ncoding") {
+                                               if (GetStringFromBytes (bufPos, 7) == "ncoding") {
                                                        bufPos += 7;
                                                        c = SkipWhitespace();
                                                        if (c != '=')
@@ -451,6 +491,8 @@ namespace System.Xml
                                bufPos = 0;
                                break;
                        default:
+                               if (c == 0)
+                                       enc = StrictUTF16;
                                bufPos = 0;
                                break;
                        }