using System;
using System.IO;
using System.Text;
namespace Common.Xml
{
///
/// A StreamReader that excludes XML-illegal characters while reading.
///
public class XmlSanitizingStream : StreamReader
{
///
/// The charactet that denotes the end of a file has been reached.
///
private const int Eof = -1;
/// Create an instance of XmlSanitizingStream.
///
/// The stream to sanitize of illegal XML characters.
///
public XmlSanitizingStream(Stream streamToSanitize)
: base(streamToSanitize, true)
{ }
public XmlSanitizingStream(Stream streamToSanitize, Encoding encoding)
: base(streamToSanitize, encoding)
{ }
///
/// Get whether an integer represents a legal XML 1.0 or 1.1 character. See
/// the specification at w3.org for these characters.
///
///
/// The version number as a string. Use "1.0" for XML 1.0 character
/// validation, and use "1.1" for XML 1.1 character validation.
///
///
public static bool IsLegalXmlChar(string xmlVersion, int character)
{
switch (xmlVersion)
{
case "1.1": // http://www.w3.org/TR/xml11/#charsets
{
return
!(
character <= 0x8 ||
character == 0xB ||
character == 0xC ||
(character >= 0xE && character <= 0x1F) ||
(character >= 0x7F && character <= 0x84) ||
(character >= 0x86 && character <= 0x9F) ||
character > 0x10FFFF
);
}
case "1.0": // http://www.w3.org/TR/REC-xml/#charsets
{
return
(
character == 0x9 /* == '\t' == 9 */ ||
character == 0xA /* == '\n' == 10 */ ||
character == 0xD /* == '\r' == 13 */ ||
(character >= 0x20 && character <= 0xD7FF) ||
(character >= 0xE000 && character <= 0xFFFD) ||
(character >= 0x10000 && character <= 0x10FFFF)
);
}
default:
{
throw new ArgumentOutOfRangeException
("xmlVersion", string.Format("'{0}' is not a valid XML version.", xmlVersion));
}
}
}
///
/// Get whether an integer represents a legal XML 1.0 character. See the
/// specification at w3.org for these characters.
///
public static bool IsLegalXmlChar(int character)
{
return IsLegalXmlChar("1.0", character);
}
public override int Read()
{
// Read each character, skipping over characters that XML has prohibited
int nextCharacter;
do
{
// Read a character
if ((nextCharacter = base.Read()) == Eof)
{
// If the character denotes the end of the file, stop reading
break;
}
}
// Skip the character if it's prohibited, and try the next
while (!IsLegalXmlChar(nextCharacter));
return nextCharacter;
}
public override int Peek()
{
// Return the next legl XML character without reading it
int nextCharacter;
do
{
// See what the next character is
nextCharacter = base.Peek();
}
while
(
// If it's prohibited XML, skip over the character in the stream
// and try the next.
!IsLegalXmlChar(nextCharacter) &&
(nextCharacter = base.Read()) != Eof
);
return nextCharacter;
} // method
#region Read*() method overrides
// The following methods are exact copies of the methods in TextReader,
// extracting by disassembling it in Refelctor
public override int Read(char[] buffer, int index, int count)
{
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
if (index < 0)
{
throw new ArgumentOutOfRangeException("index");
}
if (count < 0)
{
throw new ArgumentOutOfRangeException("count");
}
if ((buffer.Length - index) < count)
{
throw new ArgumentException();
}
int num = 0;
do
{
int num2 = Read();
if (num2 == -1)
{
return num;
}
buffer[index + num++] = (char) num2;
}
while (num < count);
return num;
}
public override int ReadBlock(char[] buffer, int index, int count)
{
int num;
int num2 = 0;
do
{
num2 += num = Read(buffer, index + num2, count - num2);
}
while ((num > 0) && (num2 < count));
return num2;
}
public override string ReadLine()
{
StringBuilder builder = new StringBuilder();
while (true)
{
int num = Read();
switch (num)
{
case -1:
if (builder.Length > 0)
{
return builder.ToString();
}
return null;
case 13:
case 10:
if ((num == 13) && (Peek() == 10))
{
Read();
}
return builder.ToString();
}
builder.Append((char) num);
}
}
public override string ReadToEnd()
{
int num;
char[] buffer = new char[0x1000];
StringBuilder builder = new StringBuilder(0x1000);
while ((num = Read(buffer, 0, buffer.Length)) != 0)
{
builder.Append(buffer, 0, num);
}
return builder.ToString();
}
#endregion
} // class
}