Reverted last patch. It breaks configuration reading
[mono.git] / mcs / class / System.XML / System.Xml / XmlInputStream.cs
1 //
2 // System.Xml.XmlInputStream 
3 //      encoding-specification-wise XML input stream and reader
4 //
5 // Author:
6 //      Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 //
8 //      (C)2003 Atsushi Enomoto
9 //
10 using System;\r
11 using System.IO;\r
12 using System.Text;\r
13 \r
14 namespace System.Xml\r
15 {\r
16         #region XmlStreamReader
17         internal class XmlStreamReader : StreamReader
18         {
19                 public XmlStreamReader (XmlInputStream input)
20                         : base (input, input.ActualEncoding != null ? input.ActualEncoding : Encoding.UTF8)
21                 {
22                 }
23         }
24         #endregion
25 \r
26         public class XmlInputStream : Stream\r
27         {\r
28                 Encoding enc;\r
29                 Stream stream;\r
30                 byte[] buffer = new byte[256];\r
31                 int bufLength;\r
32                 int bufPos;\r
33 \r
34                 static XmlException encodingException = new XmlException ("invalid encoding specification.");\r
35 \r
36                 public XmlInputStream (string uri)\r
37                 {\r
38                         Initialize (new System.Net.WebClient ().OpenRead (uri));\r
39                 }\r
40 \r
41                 public XmlInputStream (Stream stream)\r
42                 {\r
43                         Initialize (stream);\r
44                 }\r
45 \r
46                 private void Initialize (Stream stream)\r
47                 {\r
48                         // FIXME: seems too waste...\r
49                         MemoryStream ms = new MemoryStream ();\r
50                         this.stream = stream;\r
51                         int c = stream.ReadByte ();\r
52                         switch (c) {\r
53                         case 0xFF:\r
54                                 c = stream.ReadByte ();\r
55                                 if (c == 0xFE) {\r
56                                         // BOM-ed little endian utf-16\r
57                                         enc = Encoding.Unicode;\r
58                                 } else {\r
59                                         // It doesn't start from "<?xml" then its encoding is utf-8\r
60                                         enc = Encoding.UTF8;\r
61                                         ms.WriteByte ((byte)0xFF);\r
62                                         ms.WriteByte ((byte)c);\r
63                                 }\r
64                                 break;\r
65                         case 0xFE:\r
66                                 c = stream.ReadByte ();\r
67                                 if (c == 0xFF) {\r
68                                         // BOM-ed big endian utf-16\r
69                                         enc = Encoding.BigEndianUnicode;\r
70                                         return;\r
71                                 } else {\r
72                                         // It doesn't start from "<?xml" then its encoding is utf-8\r
73                                         enc = Encoding.UTF8;\r
74                                         ms.WriteByte ((byte)0xFE);\r
75                                         ms.WriteByte ((byte)c);\r
76                                 }\r
77                                 break;\r
78                         case 0xEF:\r
79                                 enc = Encoding.UTF8;\r
80                                 c = ReadByte ();\r
81                                 if (c == 0xBB) {\r
82                                         c = ReadByte ();\r
83                                         if (c != 0xBF) {\r
84                                                 ms.WriteByte ((byte)0xEF);\r
85                                                 ms.WriteByte ((byte)0xBB);\r
86                                                 ms.WriteByte ((byte)c);\r
87                                         }\r
88                                 } else {\r
89                                         ms.WriteByte ((byte)0xEF);\r
90                                 }\r
91                                 break;\r
92                         case '<':\r
93                                 // try to get encoding name from XMLDecl.\r
94                                 ms.WriteByte ((byte)'<');\r
95                                 int size = stream.Read (buffer, 1, 4);\r
96                                 ms.Write (buffer, 1, 4);\r
97                                 if (Encoding.ASCII.GetString (buffer, 1, 4) == "?xml") {\r
98                                         int loop = 0;\r
99                                         c = SkipWhitespace (ms);\r
100                                         // version\r
101                                         if (c != 'v' || stream.ReadByte () != 'e')\r
102                                                 throw new XmlException ("invalid xml declaration.");\r
103                                         ms.WriteByte ((byte)'v');\r
104                                         ms.WriteByte ((byte)'e');\r
105                                         while (loop++ >= 0) {\r
106                                                 c = stream.ReadByte ();\r
107                                                 ms.WriteByte ((byte)c);\r
108                                                 if (c == '0') {\r
109                                                         ms.WriteByte ((byte)stream.ReadByte ());\r
110                                                         break;\r
111                                                 }\r
112                                         }\r
113                                         c = SkipWhitespace (ms);\r
114                                         if (c == 'e') {\r
115                                                 ms.WriteByte ((byte)'e');\r
116                                                 size = stream.Read (buffer, 0, 7);\r
117                                                 ms.Write (buffer, 0, 7);\r
118                                                 if (Encoding.ASCII.GetString(buffer, 0, 7) == "ncoding") {\r
119                                                         c = this.SkipWhitespace(ms);\r
120                                                         if (c != '=')\r
121                                                                 throw encodingException;\r
122                                                         ms.WriteByte ((byte)'=');\r
123                                                         c = this.SkipWhitespace (ms);\r
124                                                         int quoteChar = c;\r
125                                                         ms.WriteByte ((byte)c);\r
126                                                         int start = (int)ms.Position;\r
127                                                         while (loop++ >= 0) {\r
128                                                                 c = stream.ReadByte ();\r
129                                                                 if (c == quoteChar)\r
130                                                                         break;\r
131                                                                 else if (c < 0)\r
132                                                                         throw encodingException;\r
133                                                                 ms.WriteByte ((byte)c);\r
134                                                         }\r
135                                                         string encodingName = Encoding.UTF8.GetString (ms.GetBuffer (), start, (int)ms.Position - start);\r
136                                                         if (!XmlConstructs.IsValidIANAEncoding (encodingName))\r
137                                                                 throw encodingException;\r
138                                                         ms.WriteByte ((byte)quoteChar);\r
139                                                         enc = Encoding.GetEncoding (encodingName);\r
140                                                 }\r
141                                                 else\r
142                                                         ms.Write (buffer, 0, size);\r
143                                         }\r
144                                         else\r
145                                                 ms.WriteByte ((byte)c);\r
146                                 }\r
147                                 buffer = ms.ToArray ();\r
148                                 bufLength = buffer.Length;\r
149                                 bufPos = 0;\r
150                                 break;\r
151                         default:\r
152                                 buffer [0] = (byte)c;\r
153                                 bufLength = 1;\r
154                                 enc = Encoding.UTF8;\r
155                                 break;\r
156                         }\r
157                 }\r
158 \r
159                 // skips whitespace and returns misc char that was read from stream\r
160                 private int SkipWhitespace (MemoryStream ms)    // ms may be null\r
161                 {\r
162                         int loop = 0;\r
163                         int c;\r
164                         while (loop++ >= 0) { // defends infinite loop (expecting overflow)\r
165                                 c = stream.ReadByte ();\r
166                                 switch (c) {\r
167                                 case '\r': goto case ' ';\r
168                                 case '\n': goto case ' ';\r
169                                 case '\t': goto case ' ';\r
170                                 case ' ':\r
171                                         if (ms != null)\r
172                                                 ms.WriteByte ((byte)c);\r
173                                         continue;\r
174                                 default:\r
175                                         return c;\r
176                                 }\r
177                         }\r
178                         throw new InvalidOperationException ();\r
179                 }\r
180 \r
181                 public Encoding ActualEncoding {\r
182                         get { return enc; }\r
183                 }\r
184 \r
185                 #region Public Overrides\r
186                 public override bool CanRead {\r
187                         get { return stream.CanRead; }\r
188                 }\r
189 \r
190                 public override bool CanSeek {\r
191                         get { return false; } //stream.CanSeek; }\r
192                 }\r
193 \r
194                 public override bool CanWrite {\r
195                         get { return false; }\r
196                 }\r
197 \r
198                 public override long Length {\r
199                         get {\r
200                                 return stream.Length;\r
201                         }\r
202                 }\r
203 \r
204                 public override long Position {\r
205                         get {\r
206                                 return stream.Position + bufLength;\r
207                         }\r
208                         set {\r
209                                 if(value < bufLength)\r
210                                         bufPos = (int)value;\r
211                                 else\r
212                                         stream.Position = value - bufLength;\r
213                         }\r
214                 }\r
215 \r
216                 public override void Flush()\r
217                 {\r
218                         stream.Flush ();\r
219                 }\r
220 \r
221                 public override int Read (byte[] buffer, int offset, int count)\r
222                 {\r
223                         int ret;\r
224                         if (count <= bufLength - bufPos)        {       // all from buffer\r
225                                 Array.Copy (this.buffer, bufPos, buffer, offset, count);\r
226                                 bufPos += count;\r
227                                 ret = count;\r
228                         } else {\r
229                                 int bufRest = bufLength - bufPos;\r
230                                 if (bufLength > bufPos) {\r
231                                         Array.Copy (this.buffer, bufPos, buffer, offset, bufRest);\r
232                                         bufPos += bufRest;\r
233                                 }\r
234                                 ret = bufRest +\r
235                                         stream.Read (buffer, offset + bufRest, count - bufRest);\r
236                         }\r
237                         return ret;\r
238                 }\r
239 \r
240                 public override int ReadByte ()\r
241                 {\r
242                         if (bufLength > bufPos) {\r
243                                 return buffer [bufPos++];\r
244                         }\r
245                         return stream.ReadByte ();\r
246                 }\r
247 \r
248                 public override long Seek (long offset, System.IO.SeekOrigin origin)\r
249                 {\r
250                         int bufRest = bufLength - bufPos;\r
251                         if (origin == SeekOrigin.Current)\r
252                                 if (offset < bufRest)\r
253                                         return buffer [bufPos + offset];\r
254                                 else\r
255                                         return stream.Seek (offset - bufRest, origin);\r
256                         else\r
257                                 return stream.Seek (offset, origin);\r
258                 }\r
259 \r
260                 public override void SetLength (long value)\r
261                 {\r
262                         stream.SetLength (value);\r
263                 }\r
264 \r
265                 public override void Write (byte[] buffer, int offset, int count)\r
266                 {\r
267                         throw new NotSupportedException ();\r
268                 }\r
269                 #endregion\r
270         }\r
271 }\r