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, true))
30 public XmlStreamReader (Stream input, bool docent)
31 : this (new XmlInputStream (input, docent))
35 public XmlStreamReader (string url)
40 public XmlStreamReader (string url, bool docent)
41 : this (new XmlInputStream (url, docent))
47 class XmlInputStream : Stream
\r
51 byte[] buffer = new byte[256];
\r
54 bool isDocumentEntity; // allow omitting "version" or not.
\r
56 static XmlException encodingException = new XmlException ("invalid encoding specification.");
\r
58 public XmlInputStream (string url)
\r
63 public XmlInputStream (string url, bool docent)
\r
65 this.isDocumentEntity = docent;
\r
68 Uri uri = new Uri (url);
\r
69 Initialize (new MemoryStream (new System.Net.WebClient ().DownloadData (url)));
\r
70 } catch (UriFormatException ex) {
\r
71 Initialize (new FileStream (url, FileMode.Open));
\r
74 Initialize (new FileStream (url, FileMode.Open, FileAccess.Read));
\r
78 public XmlInputStream (Stream stream)
\r
79 : this (stream, true)
\r
83 public XmlInputStream (Stream stream, bool docent)
\r
85 this.isDocumentEntity = docent;
\r
86 Initialize (stream);
\r
89 private void Initialize (Stream stream)
\r
91 // FIXME: seems too waste...
\r
92 MemoryStream ms = new MemoryStream ();
\r
93 this.stream = stream;
\r
94 int c = stream.ReadByte ();
\r
97 c = stream.ReadByte ();
\r
99 // BOM-ed little endian utf-16
\r
100 enc = Encoding.Unicode;
\r
102 // It doesn't start from "<?xml" then its encoding is utf-8
\r
103 enc = Encoding.UTF8;
\r
104 ms.WriteByte ((byte)0xFF);
\r
105 ms.WriteByte ((byte)c);
\r
109 c = stream.ReadByte ();
\r
111 // BOM-ed big endian utf-16
\r
112 enc = Encoding.BigEndianUnicode;
\r
115 // It doesn't start from "<?xml" then its encoding is utf-8
\r
116 enc = Encoding.UTF8;
\r
117 ms.WriteByte ((byte)0xFE);
\r
118 ms.WriteByte ((byte)c);
\r
122 enc = Encoding.UTF8;
\r
127 ms.WriteByte ((byte)0xEF);
\r
128 ms.WriteByte ((byte)0xBB);
\r
129 ms.WriteByte ((byte)c);
\r
132 ms.WriteByte ((byte)0xEF);
\r
136 // try to get encoding name from XMLDecl.
\r
137 ms.WriteByte ((byte)'<');
\r
138 int size = stream.Read (buffer, 1, 4);
\r
139 ms.Write (buffer, 1, 4);
\r
140 if (Encoding.ASCII.GetString (buffer, 1, 4) == "?xml") {
\r
142 c = SkipWhitespace (ms);
\r
144 // version. It is optional here.
\r
146 if (isDocumentEntity)
\r
147 throw new XmlException ("invalid xml declaration.");
\r
149 ms.WriteByte ((byte)'v');
\r
150 while (loop++ >= 0 && c >= 0) {
\r
151 c = stream.ReadByte ();
\r
152 ms.WriteByte ((byte)c);
\r
153 if (c == '0') { // 0 of 1.0
\r
154 ms.WriteByte ((byte)stream.ReadByte ());
\r
158 c = SkipWhitespace (ms);
\r
162 ms.WriteByte ((byte)'e');
\r
163 size = stream.Read (buffer, 0, 7);
\r
164 ms.Write (buffer, 0, 7);
\r
165 if (Encoding.ASCII.GetString(buffer, 0, 7) == "ncoding") {
\r
166 c = this.SkipWhitespace(ms);
\r
168 throw encodingException;
\r
169 ms.WriteByte ((byte)'=');
\r
170 c = this.SkipWhitespace (ms);
\r
172 ms.WriteByte ((byte)c);
\r
173 int start = (int)ms.Position;
\r
174 while (loop++ >= 0) {
\r
175 c = stream.ReadByte ();
\r
176 if (c == quoteChar)
\r
179 throw encodingException;
\r
180 ms.WriteByte ((byte)c);
\r
182 string encodingName = Encoding.UTF8.GetString (ms.GetBuffer (), start, (int)ms.Position - start);
\r
183 if (!XmlConstructs.IsValidIANAEncoding (encodingName))
\r
184 throw encodingException;
\r
185 ms.WriteByte ((byte)quoteChar);
\r
186 enc = Encoding.GetEncoding (encodingName);
\r
189 ms.Write (buffer, 0, size);
\r
192 ms.WriteByte ((byte)c);
\r
194 buffer = ms.ToArray ();
\r
195 bufLength = buffer.Length;
\r
199 buffer [0] = (byte)c;
\r
201 enc = Encoding.UTF8;
\r
206 // skips whitespace and returns misc char that was read from stream
\r
207 private int SkipWhitespace (MemoryStream ms) // ms may be null
\r
211 while (loop++ >= 0) { // defends infinite loop (expecting overflow)
\r
212 c = stream.ReadByte ();
\r
214 case '\r': goto case ' ';
\r
215 case '\n': goto case ' ';
\r
216 case '\t': goto case ' ';
\r
219 ms.WriteByte ((byte)c);
\r
225 throw new InvalidOperationException ();
\r
228 public Encoding ActualEncoding {
\r
229 get { return enc; }
\r
232 #region Public Overrides
\r
233 public override bool CanRead {
\r
234 get { return stream.CanRead; }
\r
237 public override bool CanSeek {
\r
238 get { return false; } //stream.CanSeek; }
\r
241 public override bool CanWrite {
\r
242 get { return false; }
\r
245 public override long Length {
\r
247 return stream.Length;
\r
251 public override long Position {
\r
253 return stream.Position + bufLength;
\r
256 if(value < bufLength)
\r
257 bufPos = (int)value;
\r
259 stream.Position = value - bufLength;
\r
263 public override void Flush()
\r
268 public override int Read (byte[] buffer, int offset, int count)
\r
271 if (count <= bufLength - bufPos) { // all from buffer
\r
272 Array.Copy (this.buffer, bufPos, buffer, offset, count);
\r
276 int bufRest = bufLength - bufPos;
\r
277 if (bufLength > bufPos) {
\r
278 Array.Copy (this.buffer, bufPos, buffer, offset, bufRest);
\r
282 stream.Read (buffer, offset + bufRest, count - bufRest);
\r
287 public override int ReadByte ()
\r
289 if (bufLength > bufPos) {
\r
290 return buffer [bufPos++];
\r
292 return stream.ReadByte ();
\r
295 public override long Seek (long offset, System.IO.SeekOrigin origin)
\r
297 int bufRest = bufLength - bufPos;
\r
298 if (origin == SeekOrigin.Current)
\r
299 if (offset < bufRest)
\r
300 return buffer [bufPos + offset];
\r
302 return stream.Seek (offset - bufRest, origin);
\r
304 return stream.Seek (offset, origin);
\r
307 public override void SetLength (long value)
\r
309 stream.SetLength (value);
\r
312 public override void Write (byte[] buffer, int offset, int count)
\r
314 throw new NotSupportedException ();
\r