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
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 #region XmlStreamReader
39 internal class XmlStreamReader : StreamReader
43 XmlStreamReader (XmlInputStream input)
44 : base (input, input.ActualEncoding != null ? input.ActualEncoding : Encoding.UTF8)
49 public XmlStreamReader (Stream input)
50 : this (new XmlInputStream (input))
54 public override void Close ()
59 protected override void Dispose (bool disposing)
61 base.Dispose (disposing);
70 class XmlInputStream : Stream
78 static XmlException encodingException = new XmlException ("invalid encoding specification.");
80 public XmlInputStream (Stream stream)
85 private void Initialize (Stream stream)
87 buffer = new byte [1024];
89 enc = Encoding.UTF8; // Default to UTF8 if we can't guess it
90 bufLength = stream.Read (buffer, 0, buffer.Length);
91 if (bufLength == -1 || bufLength == 0) {
95 int c = ReadByteSpecial ();
98 c = ReadByteSpecial ();
100 // BOM-ed little endian utf-16
101 enc = Encoding.Unicode;
103 // It doesn't start from "<?xml" then its encoding is utf-8
108 c = ReadByteSpecial ();
110 // BOM-ed big endian utf-16
111 enc = Encoding.BigEndianUnicode;
114 // It doesn't start from "<?xml" then its encoding is utf-8
119 c = ReadByteSpecial ();
121 c = ReadByteSpecial ();
126 buffer [--bufPos] = 0xEF;
130 // try to get encoding name from XMLDecl.
131 if (bufLength >= 5 && Encoding.ASCII.GetString (buffer, 1, 4) == "?xml") {
133 c = SkipWhitespace ();
135 // version. It is optional here.
138 c = ReadByteSpecial ();
139 if (c == '0') { // 0 of 1.0
144 c = SkipWhitespace ();
148 int remaining = bufLength - bufPos;
149 if (remaining >= 7 && Encoding.ASCII.GetString(buffer, bufPos, 7) == "ncoding") {
151 c = SkipWhitespace();
153 throw encodingException;
154 c = SkipWhitespace ();
156 StringBuilder sb = new StringBuilder ();
158 c = ReadByteSpecial ();
162 throw encodingException;
164 sb.Append ((char) c);
166 string encodingName = sb.ToString ();
167 if (!XmlChar.IsValidIANAEncoding (encodingName))
168 throw encodingException;
169 enc = Encoding.GetEncoding (encodingName);
181 // Just like readbyte, but grows the buffer too.
182 int ReadByteSpecial ()
184 if (bufLength > bufPos)
185 return buffer [bufPos++];
187 byte [] newbuf = new byte [buffer.Length * 2];
188 Buffer.BlockCopy (buffer, 0, newbuf, 0, bufLength);
189 int nbytes = stream.Read (newbuf, bufLength, buffer.Length);
190 if (nbytes == -1 || nbytes == 0)
195 return buffer [bufPos++];
198 // skips whitespace and returns misc char that was read from stream
199 private int SkipWhitespace ()
203 c = ReadByteSpecial ();
205 case '\r': goto case ' ';
206 case '\n': goto case ' ';
207 case '\t': goto case ' ';
214 throw new InvalidOperationException ();
217 public Encoding ActualEncoding {
221 #region Public Overrides
222 public override bool CanRead {
224 if (bufLength > bufPos)
227 return stream.CanRead;
231 // FIXME: It should support base stream's CanSeek.
232 public override bool CanSeek {
233 get { return false; } // stream.CanSeek; }
236 public override bool CanWrite {
237 get { return false; }
240 public override long Length {
242 return stream.Length;
246 public override long Position {
248 return stream.Position - bufLength + bufPos;
251 if(value < bufLength)
254 stream.Position = value - bufLength;
258 public override void Close ()
263 public override void Flush ()
268 public override int Read (byte[] buffer, int offset, int count)
271 if (count <= bufLength - bufPos) { // all from buffer
272 Array.Copy (this.buffer, bufPos, buffer, offset, count);
276 int bufRest = bufLength - bufPos;
277 if (bufLength > bufPos) {
278 Array.Copy (this.buffer, bufPos, buffer, offset, bufRest);
282 stream.Read (buffer, offset + bufRest, count - bufRest);
287 public override int ReadByte ()
289 if (bufLength > bufPos) {
290 return buffer [bufPos++];
292 return stream.ReadByte ();
295 public override long Seek (long offset, System.IO.SeekOrigin origin)
297 int bufRest = bufLength - bufPos;
298 if (origin == SeekOrigin.Current)
299 if (offset < bufRest)
300 return buffer [bufPos + offset];
302 return stream.Seek (offset - bufRest, origin);
304 return stream.Seek (offset, origin);
307 public override void SetLength (long value)
309 stream.SetLength (value);
312 public override void Write (byte[] buffer, int offset, int count)
314 throw new NotSupportedException ();