//
// (C)2003 Atsushi Enomoto
//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
using System;
using System.IO;
using System.Text;
using System.Xml;
-namespace Mono.Xml.Native
+namespace System.Xml
{
#region XmlStreamReader
- public class XmlStreamReader : StreamReader
+ internal class XmlStreamReader : StreamReader
{
XmlInputStream input;
}
public XmlStreamReader (Stream input)
- : this (new XmlInputStream (input, true))
- {
- }
-
- public XmlStreamReader (Stream input, bool docent)
- : this (new XmlInputStream (input, docent))
- {
- }
-
-// public XmlStreamReader (string url)
-// : this (url, true)
-// {
-// }
-//
-// public XmlStreamReader (string url, bool docent)
-// : this (new XmlInputStream (url, docent, null, null))
-// {
-// }
-
- public XmlStreamReader (string url, XmlResolver resolver, string baseURI)
- : this (url, true, resolver, baseURI)
- {
- }
-
- public XmlStreamReader (string url, bool docent, XmlResolver resolver,
- string baseURI)
- : this (new XmlInputStream (url, docent, resolver, baseURI))
+ : this (new XmlInputStream (input))
{
}
Close ();
}
}
+
}
#endregion
{
Encoding enc;
Stream stream;
- byte[] buffer = new byte[256];
+ byte[] buffer;
int bufLength;
int bufPos;
- bool isDocumentEntity; // allow omitting "version" or not.
static XmlException encodingException = new XmlException ("invalid encoding specification.");
-/*
- public XmlInputStream (string url)
- : this (url, true)
- {
- }
-*/
- public XmlInputStream (string url, bool docent, XmlResolver resolver, string baseURI)
- {
- this.isDocumentEntity = docent;
- // Use XmlResolver to resolve external entity.
-#if true // #if REMOVE_IT_AFTER_URI_IMPLEMENTED
- if (resolver == null)
- resolver = new XmlUrlResolver ();
- Uri uri = resolver.ResolveUri (
- baseURI == null || baseURI == String.Empty ?
- null : new Uri (baseURI), url);
- Stream s = resolver.GetEntity (uri, null, typeof (Stream)) as Stream;
-#else
- Stream s = new FileStream (url, FileMode.Open, FileAccess.Read);
-#endif
- Initialize (s);
- }
public XmlInputStream (Stream stream)
- : this (stream, true)
- {
- }
-
- public XmlInputStream (Stream stream, bool docent)
{
- this.isDocumentEntity = docent;
Initialize (stream);
}
private void Initialize (Stream stream)
{
- // FIXME: seems too waste...
- MemoryStream ms = new MemoryStream ();
+ buffer = new byte [64];
this.stream = stream;
- int c = stream.ReadByte ();
+ enc = Encoding.UTF8; // Default to UTF8 if we can't guess it
+ bufLength = stream.Read (buffer, 0, buffer.Length);
+ if (bufLength == -1 || bufLength == 0) {
+ return;
+ }
+
+ int c = ReadByteSpecial ();
switch (c) {
case 0xFF:
- c = stream.ReadByte ();
+ c = ReadByteSpecial ();
if (c == 0xFE) {
// BOM-ed little endian utf-16
enc = Encoding.Unicode;
} else {
// It doesn't start from "<?xml" then its encoding is utf-8
- enc = Encoding.UTF8;
- ms.WriteByte ((byte)0xFF);
- ms.WriteByte ((byte)c);
+ bufPos = 0;
}
break;
case 0xFE:
- c = stream.ReadByte ();
+ c = ReadByteSpecial ();
if (c == 0xFF) {
// BOM-ed big endian utf-16
enc = Encoding.BigEndianUnicode;
return;
} else {
// It doesn't start from "<?xml" then its encoding is utf-8
- enc = Encoding.UTF8;
- ms.WriteByte ((byte)0xFE);
- ms.WriteByte ((byte)c);
+ bufPos = 0;
}
break;
case 0xEF:
- enc = Encoding.UTF8;
- c = ReadByte ();
+ c = ReadByteSpecial ();
if (c == 0xBB) {
- c = ReadByte ();
+ c = ReadByteSpecial ();
if (c != 0xBF) {
- ms.WriteByte ((byte)0xEF);
- ms.WriteByte ((byte)0xBB);
- ms.WriteByte ((byte)c);
+ bufPos = 0;
}
} else {
- ms.WriteByte ((byte)0xEF);
+ buffer [--bufPos] = 0xEF;
}
break;
case '<':
// try to get encoding name from XMLDecl.
- ms.WriteByte ((byte)'<');
- int size = stream.Read (buffer, 1, 4);
- ms.Write (buffer, 1, 4);
- if (Encoding.ASCII.GetString (buffer, 1, 4) == "?xml") {
- int loop = 0;
- c = SkipWhitespace (ms);
+ if (bufLength >= 5 && Encoding.ASCII.GetString (buffer, 1, 4) == "?xml") {
+ bufPos += 4;
+ c = SkipWhitespace ();
// version. It is optional here.
- if (c != 'v') {
- // FIXME: temporarily comment out here.
-// if (isDocumentEntity)
-// throw new XmlException ("invalid xml declaration.");
- } else {
- ms.WriteByte ((byte)'v');
- while (loop++ >= 0 && c >= 0) {
- c = stream.ReadByte ();
- ms.WriteByte ((byte)c);
+ if (c == 'v') {
+ while (c >= 0) {
+ c = ReadByteSpecial ();
if (c == '0') { // 0 of 1.0
- ms.WriteByte ((byte)stream.ReadByte ());
+ ReadByteSpecial ();
break;
}
}
- c = SkipWhitespace (ms);
+ c = SkipWhitespace ();
}
if (c == 'e') {
- ms.WriteByte ((byte)'e');
- size = stream.Read (buffer, 0, 7);
- ms.Write (buffer, 0, 7);
- if (Encoding.ASCII.GetString(buffer, 0, 7) == "ncoding") {
- c = this.SkipWhitespace(ms);
+ int remaining = bufLength - bufPos;
+ if (remaining >= 7 && Encoding.ASCII.GetString(buffer, bufPos, 7) == "ncoding") {
+ bufPos += 7;
+ c = SkipWhitespace();
if (c != '=')
throw encodingException;
- ms.WriteByte ((byte)'=');
- c = this.SkipWhitespace (ms);
+ c = SkipWhitespace ();
int quoteChar = c;
- ms.WriteByte ((byte)c);
- int start = (int)ms.Position;
- while (loop++ >= 0) {
- c = stream.ReadByte ();
+ StringBuilder sb = new StringBuilder ();
+ while (true) {
+ c = ReadByteSpecial ();
if (c == quoteChar)
break;
else if (c < 0)
throw encodingException;
- ms.WriteByte ((byte)c);
+
+ sb.Append ((char) c);
}
- string encodingName = Encoding.UTF8.GetString (ms.GetBuffer (), start, (int)ms.Position - start);
+ string encodingName = sb.ToString ();
if (!XmlChar.IsValidIANAEncoding (encodingName))
throw encodingException;
- ms.WriteByte ((byte)quoteChar);
enc = Encoding.GetEncoding (encodingName);
}
- else
- ms.Write (buffer, 0, size);
}
- else
- ms.WriteByte ((byte)c);
}
- buffer = ms.ToArray ();
- bufLength = buffer.Length;
bufPos = 0;
break;
default:
- buffer [0] = (byte)c;
- bufLength = 1;
- enc = Encoding.UTF8;
+ bufPos = 0;
break;
}
}
+ // Just like readbyte, but grows the buffer too.
+ int ReadByteSpecial ()
+ {
+ if (bufLength > bufPos)
+ return buffer [bufPos++];
+
+ byte [] newbuf = new byte [buffer.Length * 2];
+ Buffer.BlockCopy (buffer, 0, newbuf, 0, bufLength);
+ int nbytes = stream.Read (newbuf, bufLength, buffer.Length);
+ if (nbytes == -1 || nbytes == 0)
+ return -1;
+
+ bufLength += nbytes;
+ buffer = newbuf;
+ return buffer [bufPos++];
+ }
+
// skips whitespace and returns misc char that was read from stream
- private int SkipWhitespace (MemoryStream ms) // ms may be null
+ private int SkipWhitespace ()
{
- int loop = 0;
int c;
- while (loop++ >= 0) { // defends infinite loop (expecting overflow)
- c = stream.ReadByte ();
- switch (c) {
+ while (true) {
+ c = ReadByteSpecial ();
+ switch ((char) c) {
case '\r': goto case ' ';
case '\n': goto case ' ';
case '\t': goto case ' ';
case ' ':
- if (ms != null)
- ms.WriteByte ((byte)c);
continue;
default:
return c;
#region Public Overrides
public override bool CanRead {
- get { return stream.CanRead; }
+ get {
+ if (bufLength > bufPos)
+ return true;
+ else
+ return stream.CanRead;
+ }
}
+ // FIXME: It should support base stream's CanSeek.
public override bool CanSeek {
- get { return false; } //stream.CanSeek; }
+ get { return false; } // stream.CanSeek; }
}
public override bool CanWrite {
public override long Position {
get {
- return stream.Position + bufLength;
+ return stream.Position - bufLength + bufPos;
}
set {
if(value < bufLength)
{
int ret;
if (count <= bufLength - bufPos) { // all from buffer
- Array.Copy (this.buffer, bufPos, buffer, offset, count);
+ Buffer.BlockCopy (this.buffer, bufPos, buffer, offset, count);
bufPos += count;
ret = count;
} else {
int bufRest = bufLength - bufPos;
if (bufLength > bufPos) {
- Array.Copy (this.buffer, bufPos, buffer, offset, bufRest);
+ Buffer.BlockCopy (this.buffer, bufPos, buffer, offset, bufRest);
bufPos += bufRest;
}
ret = bufRest +