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 : XmlInputStream.StrictUTF8)
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
72 public static readonly Encoding StrictUTF8;
74 static XmlInputStream ()
76 StrictUTF8 = new UTF8Encoding (false, true);
85 static XmlException encodingException = new XmlException ("invalid encoding specification.");
87 public XmlInputStream (Stream stream)
92 private void Initialize (Stream stream)
94 buffer = new byte [64];
96 enc = StrictUTF8; // Default to UTF8 if we can't guess it
97 bufLength = stream.Read (buffer, 0, buffer.Length);
98 if (bufLength == -1 || bufLength == 0) {
102 int c = ReadByteSpecial ();
105 c = ReadByteSpecial ();
107 // BOM-ed little endian utf-16
108 enc = Encoding.Unicode;
110 // It doesn't start from "<?xml" then its encoding is utf-8
115 c = ReadByteSpecial ();
117 // BOM-ed big endian utf-16
118 enc = Encoding.BigEndianUnicode;
121 // It doesn't start from "<?xml" then its encoding is utf-8
126 c = ReadByteSpecial ();
128 c = ReadByteSpecial ();
133 buffer [--bufPos] = 0xEF;
137 // try to get encoding name from XMLDecl.
138 if (bufLength >= 5 && Encoding.ASCII.GetString (buffer, 1, 4) == "?xml") {
140 c = SkipWhitespace ();
142 // version. It is optional here.
145 c = ReadByteSpecial ();
146 if (c == '0') { // 0 of 1.0
151 c = SkipWhitespace ();
155 int remaining = bufLength - bufPos;
156 if (remaining >= 7 && Encoding.ASCII.GetString(buffer, bufPos, 7) == "ncoding") {
158 c = SkipWhitespace();
160 throw encodingException;
161 c = SkipWhitespace ();
163 StringBuilder sb = new StringBuilder ();
165 c = ReadByteSpecial ();
169 throw encodingException;
171 sb.Append ((char) c);
173 string encodingName = sb.ToString ();
174 if (!XmlChar.IsValidIANAEncoding (encodingName))
175 throw encodingException;
176 enc = Encoding.GetEncoding (encodingName);
188 // Just like readbyte, but grows the buffer too.
189 int ReadByteSpecial ()
191 if (bufLength > bufPos)
192 return buffer [bufPos++];
194 byte [] newbuf = new byte [buffer.Length * 2];
195 Buffer.BlockCopy (buffer, 0, newbuf, 0, bufLength);
196 int nbytes = stream.Read (newbuf, bufLength, buffer.Length);
197 if (nbytes == -1 || nbytes == 0)
202 return buffer [bufPos++];
205 // skips whitespace and returns misc char that was read from stream
206 private int SkipWhitespace ()
210 c = ReadByteSpecial ();
212 case '\r': goto case ' ';
213 case '\n': goto case ' ';
214 case '\t': goto case ' ';
221 throw new InvalidOperationException ();
224 public Encoding ActualEncoding {
228 #region Public Overrides
229 public override bool CanRead {
231 if (bufLength > bufPos)
234 return stream.CanRead;
238 // FIXME: It should support base stream's CanSeek.
239 public override bool CanSeek {
240 get { return false; } // stream.CanSeek; }
243 public override bool CanWrite {
244 get { return false; }
247 public override long Length {
249 return stream.Length;
253 public override long Position {
255 return stream.Position - bufLength + bufPos;
258 if(value < bufLength)
261 stream.Position = value - bufLength;
265 public override void Close ()
270 public override void Flush ()
275 public override int Read (byte[] buffer, int offset, int count)
278 if (count <= bufLength - bufPos) { // all from buffer
279 Buffer.BlockCopy (this.buffer, bufPos, buffer, offset, count);
283 int bufRest = bufLength - bufPos;
284 if (bufLength > bufPos) {
285 Buffer.BlockCopy (this.buffer, bufPos, buffer, offset, bufRest);
289 stream.Read (buffer, offset + bufRest, count - bufRest);
294 public override int ReadByte ()
296 if (bufLength > bufPos) {
297 return buffer [bufPos++];
299 return stream.ReadByte ();
302 public override long Seek (long offset, System.IO.SeekOrigin origin)
304 int bufRest = bufLength - bufPos;
305 if (origin == SeekOrigin.Current)
306 if (offset < bufRest)
307 return buffer [bufPos + offset];
309 return stream.Seek (offset - bufRest, origin);
311 return stream.Seek (offset, origin);
314 public override void SetLength (long value)
316 stream.SetLength (value);
319 public override void Write (byte[] buffer, int offset, int count)
321 throw new NotSupportedException ();