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
14 namespace System.Xml
\r
16 #region XmlStreamReader
17 internal class XmlStreamReader : StreamReader
19 public XmlStreamReader (XmlInputStream input)
20 : base (input, input.ActualEncoding != null ? input.ActualEncoding : Encoding.UTF8)
26 public class XmlInputStream : Stream
\r
30 byte[] buffer = new byte[256];
\r
34 static XmlException encodingException = new XmlException ("invalid encoding specification.");
\r
36 public XmlInputStream (string uri)
\r
38 Initialize (new System.Net.WebClient ().OpenRead (uri));
\r
41 public XmlInputStream (Stream stream)
\r
43 Initialize (stream);
\r
46 private void Initialize (Stream stream)
\r
48 // FIXME: seems too waste...
\r
49 MemoryStream ms = new MemoryStream ();
\r
50 this.stream = stream;
\r
51 int c = stream.ReadByte ();
\r
54 c = stream.ReadByte ();
\r
56 // BOM-ed little endian utf-16
\r
57 enc = Encoding.Unicode;
\r
59 // It doesn't start from "<?xml" then its encoding is utf-8
\r
60 enc = Encoding.UTF8;
\r
61 ms.WriteByte ((byte)0xFF);
\r
62 ms.WriteByte ((byte)c);
\r
66 c = stream.ReadByte ();
\r
68 // BOM-ed big endian utf-16
\r
69 enc = Encoding.BigEndianUnicode;
\r
72 // It doesn't start from "<?xml" then its encoding is utf-8
\r
73 enc = Encoding.UTF8;
\r
74 ms.WriteByte ((byte)0xFE);
\r
75 ms.WriteByte ((byte)c);
\r
79 enc = Encoding.UTF8;
\r
84 ms.WriteByte ((byte)0xEF);
\r
85 ms.WriteByte ((byte)0xBB);
\r
86 ms.WriteByte ((byte)c);
\r
89 ms.WriteByte ((byte)0xEF);
\r
93 // try to get encoding name from XMLDecl.
\r
94 ms.WriteByte ((byte)'<');
\r
95 int size = stream.Read (buffer, 1, 4);
\r
96 ms.Write (buffer, 1, 4);
\r
97 if (Encoding.ASCII.GetString (buffer, 1, 4) == "?xml") {
\r
99 c = SkipWhitespace (ms);
\r
101 if (c != 'v' || stream.ReadByte () != 'e')
\r
102 throw new XmlException ("invalid xml declaration.");
\r
103 ms.WriteByte ((byte)'v');
\r
104 ms.WriteByte ((byte)'e');
\r
105 while (loop++ >= 0) {
\r
106 c = stream.ReadByte ();
\r
107 ms.WriteByte ((byte)c);
\r
109 ms.WriteByte ((byte)stream.ReadByte ());
\r
113 c = SkipWhitespace (ms);
\r
115 ms.WriteByte ((byte)'e');
\r
116 size = stream.Read (buffer, 0, 7);
\r
117 ms.Write (buffer, 0, 7);
\r
118 if (Encoding.ASCII.GetString(buffer, 0, 7) == "ncoding") {
\r
119 c = this.SkipWhitespace(ms);
\r
121 throw encodingException;
\r
122 ms.WriteByte ((byte)'=');
\r
123 c = this.SkipWhitespace (ms);
\r
125 ms.WriteByte ((byte)c);
\r
126 int start = (int)ms.Position;
\r
127 while (loop++ >= 0) {
\r
128 c = stream.ReadByte ();
\r
129 if (c == quoteChar)
\r
132 throw encodingException;
\r
133 ms.WriteByte ((byte)c);
\r
135 string encodingName = Encoding.UTF8.GetString (ms.GetBuffer (), start, (int)ms.Position - start);
\r
136 if (!XmlConstructs.IsValidIANAEncoding (encodingName))
\r
137 throw encodingException;
\r
138 ms.WriteByte ((byte)quoteChar);
\r
139 enc = Encoding.GetEncoding (encodingName);
\r
142 ms.Write (buffer, 0, size);
\r
145 ms.WriteByte ((byte)c);
\r
147 buffer = ms.ToArray ();
\r
148 bufLength = buffer.Length;
\r
152 buffer [0] = (byte)c;
\r
154 enc = Encoding.UTF8;
\r
159 // skips whitespace and returns misc char that was read from stream
\r
160 private int SkipWhitespace (MemoryStream ms) // ms may be null
\r
164 while (loop++ >= 0) { // defends infinite loop (expecting overflow)
\r
165 c = stream.ReadByte ();
\r
167 case '\r': goto case ' ';
\r
168 case '\n': goto case ' ';
\r
169 case '\t': goto case ' ';
\r
172 ms.WriteByte ((byte)c);
\r
178 throw new InvalidOperationException ();
\r
181 public Encoding ActualEncoding {
\r
182 get { return enc; }
\r
185 #region Public Overrides
\r
186 public override bool CanRead {
\r
187 get { return stream.CanRead; }
\r
190 public override bool CanSeek {
\r
191 get { return false; } //stream.CanSeek; }
\r
194 public override bool CanWrite {
\r
195 get { return false; }
\r
198 public override long Length {
\r
200 return stream.Length;
\r
204 public override long Position {
\r
206 return stream.Position + bufLength;
\r
209 if(value < bufLength)
\r
210 bufPos = (int)value;
\r
212 stream.Position = value - bufLength;
\r
216 public override void Flush()
\r
221 public override int Read (byte[] buffer, int offset, int count)
\r
224 if (count <= bufLength - bufPos) { // all from buffer
\r
225 Array.Copy (this.buffer, bufPos, buffer, offset, count);
\r
229 int bufRest = bufLength - bufPos;
\r
230 if (bufLength > bufPos) {
\r
231 Array.Copy (this.buffer, bufPos, buffer, offset, bufRest);
\r
235 stream.Read (buffer, offset + bufRest, count - bufRest);
\r
240 public override int ReadByte ()
\r
242 if (bufLength > bufPos) {
\r
243 return buffer [bufPos++];
\r
245 return stream.ReadByte ();
\r
248 public override long Seek (long offset, System.IO.SeekOrigin origin)
\r
250 int bufRest = bufLength - bufPos;
\r
251 if (origin == SeekOrigin.Current)
\r
252 if (offset < bufRest)
\r
253 return buffer [bufPos + offset];
\r
255 return stream.Seek (offset - bufRest, origin);
\r
257 return stream.Seek (offset, origin);
\r
260 public override void SetLength (long value)
\r
262 stream.SetLength (value);
\r
265 public override void Write (byte[] buffer, int offset, int count)
\r
267 throw new NotSupportedException ();
\r