using System;
using System.IO;
using System.Text;
-using System.Xml;
+using System.Runtime.InteropServices;
namespace System.Xml
{
#region XmlStreamReader
- internal class XmlStreamReader : StreamReader
+ internal class XmlStreamReader : NonBlockingStreamReader
{
XmlInputStream input;
{
}
+ static XmlException invalidDataException = new XmlException ("invalid data.");
+
public override void Close ()
{
this.input.Close ();
}
+ public override int Read ([In, Out] char[] dest_buffer, int index, int count)
+ {
+ try {
+ return base.Read (dest_buffer, index, count);
+ }
+#if NET_1_1
+ catch (System.ArgumentException) {
+ throw invalidDataException;
+ }
+#else
+ catch (System.Text.DecoderFallbackException) {
+ throw invalidDataException;
+ }
+#endif
+ }
+
protected override void Dispose (bool disposing)
{
base.Dispose (disposing);
}
#endregion
+ #region NonBlockingStreamReader
+ // mostly copied from StreamReader, removing BOM checks, ctor
+ // parameter checks and some extra public members.
+ internal class NonBlockingStreamReader : TextReader {
+
+ const int DefaultBufferSize = 1024;
+ const int DefaultFileBufferSize = 4096;
+ const int MinimumBufferSize = 128;
+
+ //
+ // The input buffer
+ //
+ byte [] input_buffer;
+
+ //
+ // The decoded buffer from the above input buffer
+ //
+ char [] decoded_buffer;
+
+ //
+ // Decoded bytes in decoded_buffer.
+ //
+ int decoded_count;
+
+ //
+ // Current position in the decoded_buffer
+ //
+ int pos;
+
+ //
+ // The buffer size that we are using
+ //
+ int buffer_size;
+
+ Encoding encoding;
+ Decoder decoder;
+
+ Stream base_stream;
+ bool mayBlock;
+ StringBuilder line_builder;
+
+ public NonBlockingStreamReader(Stream stream, Encoding encoding)
+ {
+ int buffer_size = DefaultBufferSize;
+ base_stream = stream;
+ input_buffer = new byte [buffer_size];
+ this.buffer_size = buffer_size;
+ this.encoding = encoding;
+ decoder = encoding.GetDecoder ();
+
+ decoded_buffer = new char [encoding.GetMaxCharCount (buffer_size)];
+ decoded_count = 0;
+ pos = 0;
+ }
+
+ public Encoding Encoding {
+ get { return encoding; }
+ }
+
+ public override void Close ()
+ {
+ Dispose (true);
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ if (disposing && base_stream != null)
+ base_stream.Close ();
+
+ input_buffer = null;
+ decoded_buffer = null;
+ encoding = null;
+ decoder = null;
+ base_stream = null;
+ base.Dispose (disposing);
+ }
+
+ public void DiscardBufferedData ()
+ {
+ pos = decoded_count = 0;
+ mayBlock = false;
+#if NET_2_0
+ decoder.Reset ();
+#else
+ decoder = encoding.GetDecoder ();
+#endif
+ }
+
+ // the buffer is empty, fill it again
+ private int ReadBuffer ()
+ {
+ pos = 0;
+ int cbEncoded = 0;
+
+ // keep looping until the decoder gives us some chars
+ decoded_count = 0;
+ int parse_start = 0;
+ do
+ {
+ cbEncoded = base_stream.Read (input_buffer, 0, buffer_size);
+
+ if (cbEncoded == 0)
+ return 0;
+
+ mayBlock = (cbEncoded < buffer_size);
+ decoded_count += decoder.GetChars (input_buffer, parse_start, cbEncoded, decoded_buffer, 0);
+ parse_start = 0;
+ } while (decoded_count == 0);
+
+ return decoded_count;
+ }
+
+ public override int Peek ()
+ {
+ if (base_stream == null)
+ throw new ObjectDisposedException ("StreamReader", "Cannot read from a closed StreamReader");
+ if (pos >= decoded_count && (mayBlock || ReadBuffer () == 0))
+ return -1;
+
+ return decoded_buffer [pos];
+ }
+
+ public override int Read ()
+ {
+ if (base_stream == null)
+ throw new ObjectDisposedException ("StreamReader", "Cannot read from a closed StreamReader");
+ if (pos >= decoded_count && ReadBuffer () == 0)
+ return -1;
+
+ return decoded_buffer [pos++];
+ }
+
+ public override int Read ([In, Out] char[] dest_buffer, int index, int count)
+ {
+ if (base_stream == null)
+ throw new ObjectDisposedException ("StreamReader", "Cannot read from a closed StreamReader");
+ if (dest_buffer == null)
+ throw new ArgumentNullException ("dest_buffer");
+ if (index < 0)
+ throw new ArgumentOutOfRangeException ("index", "< 0");
+ if (count < 0)
+ throw new ArgumentOutOfRangeException ("count", "< 0");
+ // re-ordered to avoid possible integer overflow
+ if (index > dest_buffer.Length - count)
+ throw new ArgumentException ("index + count > dest_buffer.Length");
+
+ int chars_read = 0;
+// while (count > 0)
+ {
+ if (pos >= decoded_count && ReadBuffer () == 0)
+ return chars_read > 0 ? chars_read : 0;
+
+ int cch = Math.Min (decoded_count - pos, count);
+ Array.Copy (decoded_buffer, pos, dest_buffer, index, cch);
+ pos += cch;
+ index += cch;
+ count -= cch;
+ chars_read += cch;
+ }
+ return chars_read;
+ }
+
+ bool foundCR;
+ int FindNextEOL ()
+ {
+ char c = '\0';
+ for (; pos < decoded_count; pos++) {
+ c = decoded_buffer [pos];
+ if (c == '\n') {
+ pos++;
+ int res = (foundCR) ? (pos - 2) : (pos - 1);
+ if (res < 0)
+ res = 0; // if a new buffer starts with a \n and there was a \r at
+ // the end of the previous one, we get here.
+ foundCR = false;
+ return res;
+ } else if (foundCR) {
+ foundCR = false;
+ return pos - 1;
+ }
+
+ foundCR = (c == '\r');
+ }
+
+ return -1;
+ }
+
+ public override string ReadLine()
+ {
+ if (base_stream == null)
+ throw new ObjectDisposedException ("StreamReader", "Cannot read from a closed StreamReader");
+
+ if (pos >= decoded_count && ReadBuffer () == 0)
+ return null;
+
+ int begin = pos;
+ int end = FindNextEOL ();
+ if (end < decoded_count && end >= begin)
+ return new string (decoded_buffer, begin, end - begin);
+
+ if (line_builder == null)
+ line_builder = new StringBuilder ();
+ else
+ line_builder.Length = 0;
+
+ while (true) {
+ if (foundCR) // don't include the trailing CR if present
+ decoded_count--;
+
+ line_builder.Append (new string (decoded_buffer, begin, decoded_count - begin));
+ if (ReadBuffer () == 0) {
+ if (line_builder.Capacity > 32768) {
+ StringBuilder sb = line_builder;
+ line_builder = null;
+ return sb.ToString (0, sb.Length);
+ }
+ return line_builder.ToString (0, line_builder.Length);
+ }
+
+ begin = pos;
+ end = FindNextEOL ();
+ if (end < decoded_count && end >= begin) {
+ line_builder.Append (new string (decoded_buffer, begin, end - begin));
+ if (line_builder.Capacity > 32768) {
+ StringBuilder sb = line_builder;
+ line_builder = null;
+ return sb.ToString (0, sb.Length);
+ }
+ return line_builder.ToString (0, line_builder.Length);
+ }
+ }
+ }
+
+ public override string ReadToEnd()
+ {
+ if (base_stream == null)
+ throw new ObjectDisposedException ("StreamReader", "Cannot read from a closed StreamReader");
+
+ StringBuilder text = new StringBuilder ();
+
+ int size = decoded_buffer.Length;
+ char [] buffer = new char [size];
+ int len;
+
+ while ((len = Read (buffer, 0, size)) != 0)
+ text.Append (buffer, 0, len);
+
+ return text.ToString ();
+ }
+ }
+ #endregion
+
class XmlInputStream : Stream
{
public static readonly Encoding StrictUTF8;
Initialize (stream);
}
+ static string GetStringFromBytes (byte [] bytes, int index, int count)
+ {
+#if MOONLIGHT
+ char [] chars = new char [count];
+ for (int i = index; i < count; i++)
+ chars [i] = (char) bytes [i];
+
+ return new string (chars);
+#else
+ return Encoding.ASCII.GetString (bytes, index, count);
+#endif
+ }
+
private void Initialize (Stream stream)
{
buffer = new byte [64];
break;
case '<':
// try to get encoding name from XMLDecl.
- if (bufLength >= 5 && Encoding.ASCII.GetString (buffer, 1, 4) == "?xml") {
+ if (bufLength >= 5 && GetStringFromBytes (buffer, 1, 4) == "?xml") {
bufPos += 4;
c = SkipWhitespace ();
if (c == 'e') {
int remaining = bufLength - bufPos;
- if (remaining >= 7 && Encoding.ASCII.GetString(buffer, bufPos, 7) == "ncoding") {
+ if (remaining >= 7 && GetStringFromBytes (buffer, bufPos, 7) == "ncoding") {
bufPos += 7;
c = SkipWhitespace();
if (c != '=')
}
}
}
+#if TARGET_JVM
+ else {
+ if (bufLength >= 10 && Encoding.Unicode.GetString (buffer, 2, 8) == "?xml")
+ enc = Encoding.Unicode;
+ }
+#endif
bufPos = 0;
break;
default:
return c;
}
}
- throw new InvalidOperationException ();
}
public Encoding ActualEncoding {