2 // System.Xml.XmlInputStream
3 // encoding-specification-wise XML input stream and reader
6 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
8 // (C)2003 Atsushi Enomoto
15 namespace Mono.Xml.Native
\r
17 #region XmlStreamReader
18 public class XmlStreamReader : StreamReader
20 XmlStreamReader (XmlInputStream input)
21 : base (input, input.ActualEncoding != null ? input.ActualEncoding : Encoding.UTF8)
25 public XmlStreamReader (Stream input)
26 : this (new XmlInputStream (input))
30 public XmlStreamReader (string url)
31 : this (new XmlInputStream (url))
37 class XmlInputStream : Stream
\r
41 byte[] buffer = new byte[256];
\r
45 static XmlException encodingException = new XmlException ("invalid encoding specification.");
\r
47 public XmlInputStream (string url)
\r
51 Uri uri = new Uri (url);
\r
52 Initialize (new MemoryStream (new System.Net.WebClient ().DownloadData (url)));
\r
53 } catch (UriFormatException ex) {
\r
54 Initialize (new FileStream (url, FileMode.Open));
\r
57 Initialize (new FileStream (url, FileMode.Open, FileAccess.Read));
\r
61 public XmlInputStream (Stream stream)
\r
63 Initialize (stream);
\r
66 private void Initialize (Stream stream)
\r
68 // FIXME: seems too waste...
\r
69 MemoryStream ms = new MemoryStream ();
\r
70 this.stream = stream;
\r
71 int c = stream.ReadByte ();
\r
74 c = stream.ReadByte ();
\r
76 // BOM-ed little endian utf-16
\r
77 enc = Encoding.Unicode;
\r
79 // It doesn't start from "<?xml" then its encoding is utf-8
\r
80 enc = Encoding.UTF8;
\r
81 ms.WriteByte ((byte)0xFF);
\r
82 ms.WriteByte ((byte)c);
\r
86 c = stream.ReadByte ();
\r
88 // BOM-ed big endian utf-16
\r
89 enc = Encoding.BigEndianUnicode;
\r
92 // It doesn't start from "<?xml" then its encoding is utf-8
\r
93 enc = Encoding.UTF8;
\r
94 ms.WriteByte ((byte)0xFE);
\r
95 ms.WriteByte ((byte)c);
\r
99 enc = Encoding.UTF8;
\r
104 ms.WriteByte ((byte)0xEF);
\r
105 ms.WriteByte ((byte)0xBB);
\r
106 ms.WriteByte ((byte)c);
\r
109 ms.WriteByte ((byte)0xEF);
\r
113 // try to get encoding name from XMLDecl.
\r
114 ms.WriteByte ((byte)'<');
\r
115 int size = stream.Read (buffer, 1, 4);
\r
116 ms.Write (buffer, 1, 4);
\r
117 if (Encoding.ASCII.GetString (buffer, 1, 4) == "?xml") {
\r
119 c = SkipWhitespace (ms);
\r
121 if (c != 'v' || stream.ReadByte () != 'e')
\r
122 throw new XmlException ("invalid xml declaration.");
\r
123 ms.WriteByte ((byte)'v');
\r
124 ms.WriteByte ((byte)'e');
\r
125 while (loop++ >= 0) {
\r
126 c = stream.ReadByte ();
\r
127 ms.WriteByte ((byte)c);
\r
129 ms.WriteByte ((byte)stream.ReadByte ());
\r
133 c = SkipWhitespace (ms);
\r
135 ms.WriteByte ((byte)'e');
\r
136 size = stream.Read (buffer, 0, 7);
\r
137 ms.Write (buffer, 0, 7);
\r
138 if (Encoding.ASCII.GetString(buffer, 0, 7) == "ncoding") {
\r
139 c = this.SkipWhitespace(ms);
\r
141 throw encodingException;
\r
142 ms.WriteByte ((byte)'=');
\r
143 c = this.SkipWhitespace (ms);
\r
145 ms.WriteByte ((byte)c);
\r
146 int start = (int)ms.Position;
\r
147 while (loop++ >= 0) {
\r
148 c = stream.ReadByte ();
\r
149 if (c == quoteChar)
\r
152 throw encodingException;
\r
153 ms.WriteByte ((byte)c);
\r
155 string encodingName = Encoding.UTF8.GetString (ms.GetBuffer (), start, (int)ms.Position - start);
\r
156 if (!XmlConstructs.IsValidIANAEncoding (encodingName))
\r
157 throw encodingException;
\r
158 ms.WriteByte ((byte)quoteChar);
\r
159 enc = Encoding.GetEncoding (encodingName);
\r
162 ms.Write (buffer, 0, size);
\r
165 ms.WriteByte ((byte)c);
\r
167 buffer = ms.ToArray ();
\r
168 bufLength = buffer.Length;
\r
172 buffer [0] = (byte)c;
\r
174 enc = Encoding.UTF8;
\r
179 // skips whitespace and returns misc char that was read from stream
\r
180 private int SkipWhitespace (MemoryStream ms) // ms may be null
\r
184 while (loop++ >= 0) { // defends infinite loop (expecting overflow)
\r
185 c = stream.ReadByte ();
\r
187 case '\r': goto case ' ';
\r
188 case '\n': goto case ' ';
\r
189 case '\t': goto case ' ';
\r
192 ms.WriteByte ((byte)c);
\r
198 throw new InvalidOperationException ();
\r
201 public Encoding ActualEncoding {
\r
202 get { return enc; }
\r
205 #region Public Overrides
\r
206 public override bool CanRead {
\r
207 get { return stream.CanRead; }
\r
210 public override bool CanSeek {
\r
211 get { return false; } //stream.CanSeek; }
\r
214 public override bool CanWrite {
\r
215 get { return false; }
\r
218 public override long Length {
\r
220 return stream.Length;
\r
224 public override long Position {
\r
226 return stream.Position + bufLength;
\r
229 if(value < bufLength)
\r
230 bufPos = (int)value;
\r
232 stream.Position = value - bufLength;
\r
236 public override void Flush()
\r
241 public override int Read (byte[] buffer, int offset, int count)
\r
244 if (count <= bufLength - bufPos) { // all from buffer
\r
245 Array.Copy (this.buffer, bufPos, buffer, offset, count);
\r
249 int bufRest = bufLength - bufPos;
\r
250 if (bufLength > bufPos) {
\r
251 Array.Copy (this.buffer, bufPos, buffer, offset, bufRest);
\r
255 stream.Read (buffer, offset + bufRest, count - bufRest);
\r
260 public override int ReadByte ()
\r
262 if (bufLength > bufPos) {
\r
263 return buffer [bufPos++];
\r
265 return stream.ReadByte ();
\r
268 public override long Seek (long offset, System.IO.SeekOrigin origin)
\r
270 int bufRest = bufLength - bufPos;
\r
271 if (origin == SeekOrigin.Current)
\r
272 if (offset < bufRest)
\r
273 return buffer [bufPos + offset];
\r
275 return stream.Seek (offset - bufRest, origin);
\r
277 return stream.Seek (offset, origin);
\r
280 public override void SetLength (long value)
\r
282 stream.SetLength (value);
\r
285 public override void Write (byte[] buffer, int offset, int count)
\r
287 throw new NotSupportedException ();
\r