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
17 #region XmlStreamReader
18 internal 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))
33 public override void Close ()
38 protected override void Dispose (bool disposing)
40 base.Dispose (disposing);
49 class XmlInputStream : Stream
57 static XmlException encodingException = new XmlException ("invalid encoding specification.");
59 public XmlInputStream (Stream stream)
64 private void Initialize (Stream stream)
66 buffer = new byte [1024];
68 enc = Encoding.UTF8; // Default to UTF8 if we can't guess it
69 bufLength = stream.Read (buffer, 0, buffer.Length);
70 if (bufLength == -1 || bufLength == 0) {
74 int c = ReadByteSpecial ();
77 c = ReadByteSpecial ();
79 // BOM-ed little endian utf-16
80 enc = Encoding.Unicode;
82 // It doesn't start from "<?xml" then its encoding is utf-8
87 c = ReadByteSpecial ();
89 // BOM-ed big endian utf-16
90 enc = Encoding.BigEndianUnicode;
93 // It doesn't start from "<?xml" then its encoding is utf-8
98 c = ReadByteSpecial ();
100 c = ReadByteSpecial ();
105 buffer [--bufPos] = 0xEF;
109 // try to get encoding name from XMLDecl.
110 if (bufLength >= 5 && Encoding.ASCII.GetString (buffer, 1, 4) == "?xml") {
113 c = SkipWhitespace ();
115 // version. It is optional here.
117 while (loop++ >= 0 && c >= 0) {
119 c = ReadByteSpecial ();
120 if (c == '0') { // 0 of 1.0
124 c = SkipWhitespace ();
128 int remaining = bufLength - bufPos;
129 if (remaining >= 7 && Encoding.ASCII.GetString(buffer, 0, 7) == "ncoding") {
131 c = SkipWhitespace();
133 throw encodingException;
134 c = SkipWhitespace ();
136 StringBuilder sb = new StringBuilder ();
137 while (loop++ >= 0) {
138 c = ReadByteSpecial ();
142 throw encodingException;
144 sb.Append ((char) c);
146 string encodingName = sb.ToString ();
147 if (!XmlChar.IsValidIANAEncoding (encodingName))
148 throw encodingException;
149 enc = Encoding.GetEncoding (encodingName);
161 // Just like readbyte, but grows the buffer too.
162 int ReadByteSpecial ()
164 if (bufLength > bufPos)
165 return buffer [bufPos++];
167 byte [] newbuf = new byte [buffer.Length * 2];
168 Buffer.BlockCopy (buffer, 0, newbuf, 0, bufLength);
169 int nbytes = stream.Read (newbuf, bufLength, buffer.Length);
170 if (nbytes == -1 || nbytes == 0)
175 return buffer [bufPos++];
178 // skips whitespace and returns misc char that was read from stream
179 private int SkipWhitespace () // ms may be null
183 while (loop++ >= 0) { // defends infinite loop (expecting overflow)
184 c = ReadByteSpecial ();
186 case '\r': goto case ' ';
187 case '\n': goto case ' ';
188 case '\t': goto case ' ';
195 throw new InvalidOperationException ();
198 public Encoding ActualEncoding {
202 #region Public Overrides
203 public override bool CanRead {
205 if (bufLength > bufPos)
208 return stream.CanRead;
212 // FIXME: It should support base stream's CanSeek.
213 public override bool CanSeek {
214 get { return false; } // stream.CanSeek; }
217 public override bool CanWrite {
218 get { return false; }
221 public override long Length {
223 return stream.Length;
227 public override long Position {
229 return stream.Position - bufLength + bufPos;
232 if(value < bufLength)
235 stream.Position = value - bufLength;
239 public override void Close ()
244 public override void Flush ()
249 public override int Read (byte[] buffer, int offset, int count)
252 if (count <= bufLength - bufPos) { // all from buffer
253 Array.Copy (this.buffer, bufPos, buffer, offset, count);
257 int bufRest = bufLength - bufPos;
258 if (bufLength > bufPos) {
259 Array.Copy (this.buffer, bufPos, buffer, offset, bufRest);
263 stream.Read (buffer, offset + bufRest, count - bufRest);
268 public override int ReadByte ()
270 if (bufLength > bufPos) {
271 return buffer [bufPos++];
273 return stream.ReadByte ();
276 public override long Seek (long offset, System.IO.SeekOrigin origin)
278 int bufRest = bufLength - bufPos;
279 if (origin == SeekOrigin.Current)
280 if (offset < bufRest)
281 return buffer [bufPos + offset];
283 return stream.Seek (offset - bufRest, origin);
285 return stream.Seek (offset, origin);
288 public override void SetLength (long value)
290 stream.SetLength (value);
293 public override void Write (byte[] buffer, int offset, int count)
295 throw new NotSupportedException ();