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
17 #region XmlStreamReader
18 public class XmlStreamReader : StreamReader
22 XmlStreamReader (XmlInputStream input)
23 : base (input, input.ActualEncoding != null ? input.ActualEncoding : Encoding.UTF8)
28 public XmlStreamReader (Stream input)
29 : this (new XmlInputStream (input, true))
33 public XmlStreamReader (Stream input, bool docent)
34 : this (new XmlInputStream (input, docent))
38 // public XmlStreamReader (string url)
43 // public XmlStreamReader (string url, bool docent)
44 // : this (new XmlInputStream (url, docent, null, null))
48 public XmlStreamReader (string url, XmlResolver resolver, string baseURI)
49 : this (url, true, resolver, baseURI)
53 public XmlStreamReader (string url, bool docent, XmlResolver resolver,
55 : this (new XmlInputStream (url, docent, resolver, baseURI))
59 public override void Close ()
64 protected override void Dispose (bool disposing)
66 base.Dispose (disposing);
74 class XmlInputStream : Stream
78 byte[] buffer = new byte[256];
81 bool isDocumentEntity; // allow omitting "version" or not.
83 static XmlException encodingException = new XmlException ("invalid encoding specification.");
85 public XmlInputStream (string url)
90 public XmlInputStream (string url, bool docent, XmlResolver resolver, string baseURI)
92 this.isDocumentEntity = docent;
93 // Use XmlResolver to resolve external entity.
94 #if true // #if REMOVE_IT_AFTER_URI_IMPLEMENTED
96 resolver = new XmlUrlResolver ();
97 Uri uri = resolver.ResolveUri (
98 baseURI == null || baseURI == String.Empty ?
99 null : new Uri (baseURI), url);
100 Stream s = resolver.GetEntity (uri, null, typeof (Stream)) as Stream;
102 Stream s = new FileStream (url, FileMode.Open, FileAccess.Read);
107 public XmlInputStream (Stream stream)
108 : this (stream, true)
112 public XmlInputStream (Stream stream, bool docent)
114 this.isDocumentEntity = docent;
118 private void Initialize (Stream stream)
120 // FIXME: seems too waste...
121 MemoryStream ms = new MemoryStream ();
122 this.stream = stream;
123 int c = stream.ReadByte ();
126 c = stream.ReadByte ();
128 // BOM-ed little endian utf-16
129 enc = Encoding.Unicode;
131 // It doesn't start from "<?xml" then its encoding is utf-8
133 ms.WriteByte ((byte)0xFF);
134 ms.WriteByte ((byte)c);
138 c = stream.ReadByte ();
140 // BOM-ed big endian utf-16
141 enc = Encoding.BigEndianUnicode;
144 // It doesn't start from "<?xml" then its encoding is utf-8
146 ms.WriteByte ((byte)0xFE);
147 ms.WriteByte ((byte)c);
156 ms.WriteByte ((byte)0xEF);
157 ms.WriteByte ((byte)0xBB);
158 ms.WriteByte ((byte)c);
161 ms.WriteByte ((byte)0xEF);
165 // try to get encoding name from XMLDecl.
166 ms.WriteByte ((byte)'<');
167 int size = stream.Read (buffer, 1, 4);
168 ms.Write (buffer, 1, 4);
169 if (Encoding.ASCII.GetString (buffer, 1, 4) == "?xml") {
171 c = SkipWhitespace (ms);
173 // version. It is optional here.
175 // FIXME: temporarily comment out here.
176 // if (isDocumentEntity)
177 // throw new XmlException ("invalid xml declaration.");
179 ms.WriteByte ((byte)'v');
180 while (loop++ >= 0 && c >= 0) {
181 c = stream.ReadByte ();
182 ms.WriteByte ((byte)c);
183 if (c == '0') { // 0 of 1.0
184 ms.WriteByte ((byte)stream.ReadByte ());
188 c = SkipWhitespace (ms);
192 ms.WriteByte ((byte)'e');
193 size = stream.Read (buffer, 0, 7);
194 ms.Write (buffer, 0, 7);
195 if (Encoding.ASCII.GetString(buffer, 0, 7) == "ncoding") {
196 c = this.SkipWhitespace(ms);
198 throw encodingException;
199 ms.WriteByte ((byte)'=');
200 c = this.SkipWhitespace (ms);
202 ms.WriteByte ((byte)c);
203 int start = (int)ms.Position;
204 while (loop++ >= 0) {
205 c = stream.ReadByte ();
209 throw encodingException;
210 ms.WriteByte ((byte)c);
212 string encodingName = Encoding.UTF8.GetString (ms.GetBuffer (), start, (int)ms.Position - start);
213 if (!XmlChar.IsValidIANAEncoding (encodingName))
214 throw encodingException;
215 ms.WriteByte ((byte)quoteChar);
216 enc = Encoding.GetEncoding (encodingName);
219 ms.Write (buffer, 0, size);
222 ms.WriteByte ((byte)c);
224 buffer = ms.ToArray ();
225 bufLength = buffer.Length;
229 buffer [0] = (byte)c;
236 // skips whitespace and returns misc char that was read from stream
237 private int SkipWhitespace (MemoryStream ms) // ms may be null
241 while (loop++ >= 0) { // defends infinite loop (expecting overflow)
242 c = stream.ReadByte ();
244 case '\r': goto case ' ';
245 case '\n': goto case ' ';
246 case '\t': goto case ' ';
249 ms.WriteByte ((byte)c);
255 throw new InvalidOperationException ();
258 public Encoding ActualEncoding {
262 #region Public Overrides
263 public override bool CanRead {
264 get { return stream.CanRead; }
267 public override bool CanSeek {
268 get { return false; } //stream.CanSeek; }
271 public override bool CanWrite {
272 get { return false; }
275 public override long Length {
277 return stream.Length;
281 public override long Position {
283 return stream.Position + bufLength;
286 if(value < bufLength)
289 stream.Position = value - bufLength;
293 public override void Close ()
298 public override void Flush ()
303 public override int Read (byte[] buffer, int offset, int count)
306 if (count <= bufLength - bufPos) { // all from buffer
307 Array.Copy (this.buffer, bufPos, buffer, offset, count);
311 int bufRest = bufLength - bufPos;
312 if (bufLength > bufPos) {
313 Array.Copy (this.buffer, bufPos, buffer, offset, bufRest);
317 stream.Read (buffer, offset + bufRest, count - bufRest);
322 public override int ReadByte ()
324 if (bufLength > bufPos) {
325 return buffer [bufPos++];
327 return stream.ReadByte ();
330 public override long Seek (long offset, System.IO.SeekOrigin origin)
332 int bufRest = bufLength - bufPos;
333 if (origin == SeekOrigin.Current)
334 if (offset < bufRest)
335 return buffer [bufPos + offset];
337 return stream.Seek (offset - bufRest, origin);
339 return stream.Seek (offset, origin);
342 public override void SetLength (long value)
344 stream.SetLength (value);
347 public override void Write (byte[] buffer, int offset, int count)
349 throw new NotSupportedException ();