diff --git a/PocketSharp/PocketReader.cs b/PocketSharp/PocketReader.cs
index a2c5c1f..8074f00 100644
--- a/PocketSharp/PocketReader.cs
+++ b/PocketSharp/PocketReader.cs
@@ -57,7 +57,7 @@ namespace PocketSharp
string htmlResponse = await Request(uri);
- TranscodingInput input = new TranscodingInput(htmlResponse);
+ TranscodingInput input = new TranscodingInput("
HALLO
was geht
");
TranscodingResult result = transcoder.Transcode(input);
// //new TranscodingInput(
diff --git a/PocketSharp/PocketSharp.csproj b/PocketSharp/PocketSharp.csproj
index 1767bb8..962b3a1 100644
--- a/PocketSharp/PocketSharp.csproj
+++ b/PocketSharp/PocketSharp.csproj
@@ -11,7 +11,7 @@
PocketSharp
PocketSharp
v4.0
- Profile96
+ Profile104
512
{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
..\
diff --git a/PortablePorts/NReadability/NReadability.csproj b/PortablePorts/NReadability/NReadability.csproj
index 93fead0..b4cc528 100644
--- a/PortablePorts/NReadability/NReadability.csproj
+++ b/PortablePorts/NReadability/NReadability.csproj
@@ -1,4 +1,4 @@
-
+
@@ -11,7 +11,7 @@
NReadability
NReadability
v4.0
- Profile96
+ Profile104
512
{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
@@ -73,4 +73,4 @@
-->
-
+
\ No newline at end of file
diff --git a/PortablePorts/SgmlReader/HTMLspecial.ent b/PortablePorts/SgmlReader/HTMLspecial.ent
new file mode 100644
index 0000000..5ce5c6a
--- /dev/null
+++ b/PortablePorts/SgmlReader/HTMLspecial.ent
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PortablePorts/SgmlReader/HTMLsymbol.ent b/PortablePorts/SgmlReader/HTMLsymbol.ent
new file mode 100644
index 0000000..524bfe1
--- /dev/null
+++ b/PortablePorts/SgmlReader/HTMLsymbol.ent
@@ -0,0 +1,241 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PortablePorts/SgmlReader/SgmlParser.cs b/PortablePorts/SgmlReader/SgmlParser.cs
index 2ec3564..1daf38d 100644
--- a/PortablePorts/SgmlReader/SgmlParser.cs
+++ b/PortablePorts/SgmlReader/SgmlParser.cs
@@ -1,4 +1,4 @@
-/*
+/*
*
* Copyright (c) 2007-2013 MindTouch. All rights reserved.
* www.mindtouch.com oss@mindtouch.com
@@ -31,3398 +31,3374 @@ using System.Text;
using System.Threading;
using System.Xml;
-namespace Sgml
-{
- ///
- /// Thrown if any errors occur while parsing the source.
- ///
- public class SgmlParseException : Exception
- {
- private string m_entityContext;
-
+namespace Sgml {
///
- /// Instantiates a new instance of SgmlParseException with no specific error information.
+ /// Thrown if any errors occur while parsing the source.
///
- public SgmlParseException()
+#if !PORTABLE
+ [Serializable]
+#endif
+ public class SgmlParseException : Exception
{
- }
+ private string m_entityContext;
- ///
- /// Instantiates a new instance of SgmlParseException with an error message describing the problem.
- ///
- /// A message describing the error that occurred
- public SgmlParseException(string message)
- : base(message)
- {
- }
-
- ///
- /// Instantiates a new instance of SgmlParseException with an error message describing the problem.
- ///
- /// A message describing the error that occurred
- /// The entity on which the error occurred.
- public SgmlParseException(string message, Entity e)
- : base(message)
- {
- if (e != null)
- m_entityContext = e.Context();
- }
-
- ///
- /// Instantiates a new instance of SgmlParseException with an error message describing the problem.
- ///
- /// A message describing the error that occurred
- /// The original exception that caused the problem.
- public SgmlParseException(string message, Exception innerException)
- : base(message, innerException)
- {
- }
-
- ///
- /// Contextual information detailing the entity on which the error occurred.
- ///
- public string EntityContext
- {
- get
- {
- return m_entityContext;
- }
- }
-
- }
-
- ///
- /// The different types of literal text returned by the SgmlParser.
- ///
- public enum LiteralType
- {
- ///
- /// CDATA text literals.
- ///
- [SuppressMessage("Microsoft.Naming", "CA1705", Justification = "This capitalisation is appropriate since the value it represents has all upper-case capitalisation.")]
- CDATA,
-
- ///
- /// SDATA entities.
- ///
- [SuppressMessage("Microsoft.Naming", "CA1705", Justification = "This capitalisation is appropriate since the value it represents has all upper-case capitalisation.")]
- SDATA,
-
- ///
- /// The contents of a Processing Instruction.
- ///
- [SuppressMessage("Microsoft.Naming", "CA1705", Justification = "This capitalisation is appropriate since the value it represents has all upper-case capitalisation.")]
- PI
- };
-
- ///
- /// An Entity declared in a DTD.
- ///
- public class Entity : IDisposable
- {
- ///
- /// The character indicating End Of File.
- ///
- [SuppressMessage("Microsoft.Naming", "CA1705", Justification = "The capitalisation is correct since EOF is an acronym.")]
- public const char EOF = (char)65535;
-
- private string m_proxy;
- private string m_name;
- private bool m_isInternal;
- private string m_publicId;
- private string m_uri;
- private string m_literal;
- private LiteralType m_literalType;
- private Entity m_parent;
- private bool m_isHtml;
- private int m_line;
- private char m_lastchar;
- private bool m_isWhitespace;
-
- private Encoding m_encoding;
- private Uri m_resolvedUri;
- private TextReader m_stm;
- private bool m_weOwnTheStream;
- private int m_lineStart;
- private int m_absolutePos;
-
- ///
- /// Initialises a new instance of an Entity declared in a DTD.
- ///
- /// The name of the entity.
- /// The public id of the entity.
- /// The uri of the entity.
- /// The proxy server to use when retrieving any web content.
- public Entity(string name, string pubid, string uri, string proxy)
- {
- m_name = name;
- m_publicId = pubid;
- m_uri = uri;
- m_proxy = proxy;
- m_isHtml = (name != null && StringUtilities.EqualsIgnoreCase(name, "html"));
- }
-
- ///
- /// Initialises a new instance of an Entity declared in a DTD.
- ///
- /// The name of the entity.
- /// The literal value of the entity.
- public Entity(string name, string literal)
- {
- m_name = name;
- m_literal = literal;
- m_isInternal = true;
- }
-
- ///
- /// Initialises a new instance of an Entity declared in a DTD.
- ///
- /// The name of the entity.
- /// The baseUri for the entity to read from the TextReader.
- /// The TextReader to read the entity from.
- /// The proxy server to use when retrieving any web content.
- public Entity(string name, Uri baseUri, TextReader stm, string proxy)
- {
- m_name = name;
- m_isInternal = true;
- m_stm = stm;
- m_resolvedUri = baseUri;
- m_proxy = proxy;
- m_isHtml = string.Equals(name, "html", StringComparison.OrdinalIgnoreCase);
- }
-
- ///
- /// The name of the entity.
- ///
- public string Name
- {
- get
- {
- return m_name;
- }
- }
-
- ///
- /// True if the entity is the html element entity.
- ///
- public bool IsHtml
- {
- get
- {
- return m_isHtml;
- }
- set
- {
- m_isHtml = value;
- }
- }
-
- ///
- /// The public identifier of this entity.
- ///
- public string PublicId
- {
- get
- {
- return m_publicId;
- }
- }
-
- ///
- /// The Uri that is the source for this entity.
- ///
- public string Uri
- {
- get
- {
- return m_uri;
- }
- }
-
- ///
- /// The resolved location of the DTD this entity is from.
- ///
- public Uri ResolvedUri
- {
- get
- {
- if (this.m_resolvedUri != null)
- return this.m_resolvedUri;
- else if (m_parent != null)
- return m_parent.ResolvedUri;
- else
- return null;
- }
- }
-
- ///
- /// Gets the parent Entity of this Entity.
- ///
- public Entity Parent
- {
- get
- {
- return m_parent;
- }
- }
-
- ///
- /// The last character read from the input stream for this entity.
- ///
- public char Lastchar
- {
- get
- {
- return m_lastchar;
- }
- }
-
- ///
- /// The line on which this entity was defined.
- ///
- public int Line
- {
- get
- {
- return m_line;
- }
- }
-
- ///
- /// The index into the line where this entity is defined.
- ///
- public int LinePosition
- {
- get
- {
- return this.m_absolutePos - this.m_lineStart + 1;
- }
- }
-
- ///
- /// Whether this entity is an internal entity or not.
- ///
- /// true if this entity is internal, otherwise false.
- public bool IsInternal
- {
- get
- {
- return m_isInternal;
- }
- }
-
- ///
- /// The literal value of this entity.
- ///
- public string Literal
- {
- get
- {
- return m_literal;
- }
- }
-
- ///
- /// The of this entity.
- ///
- public LiteralType LiteralType
- {
- get
- {
- return m_literalType;
- }
- }
-
- ///
- /// Whether the last char read for this entity is a whitespace character.
- ///
- public bool IsWhitespace
- {
- get
- {
- return m_isWhitespace;
- }
- }
-
- ///
- /// The proxy server to use when making web requests to resolve entities.
- ///
- public string Proxy
- {
- get
- {
- return m_proxy;
- }
- }
-
- ///
- /// Reads the next character from the DTD stream.
- ///
- /// The next character from the DTD stream.
- public char ReadChar()
- {
- char ch = (char)this.m_stm.Read();
- if (ch == 0)
- {
- // convert nulls to whitespace, since they are not valid in XML anyway.
- ch = ' ';
- }
- this.m_absolutePos++;
- if (ch == 0xa)
- {
- m_isWhitespace = true;
- this.m_lineStart = this.m_absolutePos + 1;
- this.m_line++;
- }
- else if (ch == ' ' || ch == '\t')
- {
- m_isWhitespace = true;
- if (m_lastchar == 0xd)
+ ///
+ /// Instantiates a new instance of SgmlParseException with no specific error information.
+ ///
+ public SgmlParseException()
{
- this.m_lineStart = this.m_absolutePos;
- m_line++;
- }
- }
- else if (ch == 0xd)
- {
- m_isWhitespace = true;
- }
- else
- {
- m_isWhitespace = false;
- if (m_lastchar == 0xd)
- {
- m_line++;
- this.m_lineStart = this.m_absolutePos;
- }
- }
-
- m_lastchar = ch;
- return ch;
- }
-
- ///
- /// Begins processing an entity.
- ///
- /// The parent of this entity.
- /// The base Uri for processing this entity within.
- public void Open(Entity parent, Uri baseUri)
- {
- this.m_parent = parent;
- if (parent != null)
- this.m_isHtml = parent.IsHtml;
- this.m_line = 1;
- if (m_isInternal)
- {
- if (this.m_literal != null)
- this.m_stm = new StringReader(this.m_literal);
- }
- else if (this.m_uri == null)
- {
- this.Error("Unresolvable entity '{0}'", this.m_name);
- }
- else
- {
- if (baseUri != null)
- {
- this.m_resolvedUri = new Uri(baseUri, this.m_uri);
- }
- else
- {
- this.m_resolvedUri = new Uri(this.m_uri);
}
- Stream stream = null;
- Encoding e = Encoding.UTF8;
- switch (this.m_resolvedUri.Scheme)
+ ///
+ /// Instantiates a new instance of SgmlParseException with an error message describing the problem.
+ ///
+ /// A message describing the error that occurred
+ public SgmlParseException(string message)
+ : base(message)
{
- case "file":
- {
- throw new NotSupportedException("The file scheme is not supported by the .NETPortable framework.");
- }
- default:
- //Console.WriteLine("Fetching:" + ResolvedUri.AbsoluteUri);
- HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(ResolvedUri);
- WebResponse resp = GetResponse(wr, TimeSpan.FromSeconds(10));
- Uri actual = resp.ResponseUri;
- if (!string.Equals(actual.AbsoluteUri, this.m_resolvedUri.AbsoluteUri, StringComparison.OrdinalIgnoreCase))
- {
- this.m_resolvedUri = actual;
- }
- string contentType = resp.ContentType.ToLowerInvariant();
- string mimeType = contentType;
- int i = contentType.IndexOf(';');
- if (i >= 0)
- {
- mimeType = contentType.Substring(0, i);
- }
+ }
- if (StringUtilities.EqualsIgnoreCase(mimeType, "text/html"))
+ ///
+ /// Instantiates a new instance of SgmlParseException with an error message describing the problem.
+ ///
+ /// A message describing the error that occurred
+ /// The entity on which the error occurred.
+ public SgmlParseException(string message, Entity e)
+ : base(message)
+ {
+ if (e != null)
+ m_entityContext = e.Context();
+ }
+
+ ///
+ /// Instantiates a new instance of SgmlParseException with an error message describing the problem.
+ ///
+ /// A message describing the error that occurred
+ /// The original exception that caused the problem.
+ public SgmlParseException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+
+#if !PORTABLE
+ ///
+ /// Initializes a new instance of the SgmlParseException class with serialized data.
+ ///
+ /// The object that holds the serialized object data.
+ /// The contextual information about the source or destination.
+ protected SgmlParseException(System.Runtime.Serialization.SerializationInfo streamInfo, System.Runtime.Serialization.StreamingContext streamCtx)
+ : base(streamInfo, streamCtx)
+ {
+ if (streamInfo != null)
+ m_entityContext = streamInfo.GetString("entityContext");
+ }
+
+ ///
+ /// Populates a SerializationInfo with the data needed to serialize the exception.
+ ///
+ /// The to populate with data.
+ /// The destination (see ) for this serialization.
+ [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, SerializationFormatter = true)]
+ public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
+ {
+ if (info == null)
+ throw new ArgumentNullException("info");
+
+ info.AddValue("entityContext", m_entityContext);
+ base.GetObjectData(info, context);
+ }
+#endif
+
+ ///
+ /// Contextual information detailing the entity on which the error occurred.
+ ///
+ public string EntityContext
+ {
+ get
{
- this.m_isHtml = true;
+ return m_entityContext;
}
+ }
- i = contentType.IndexOf("charset");
- e = Encoding.UTF8;
+ }
- if (i >= 0)
+ ///
+ /// The different types of literal text returned by the SgmlParser.
+ ///
+ public enum LiteralType
+ {
+ ///
+ /// CDATA text literals.
+ ///
+ [SuppressMessage("Microsoft.Naming", "CA1705", Justification = "This capitalisation is appropriate since the value it represents has all upper-case capitalisation.")]
+ CDATA,
+
+ ///
+ /// SDATA entities.
+ ///
+ [SuppressMessage("Microsoft.Naming", "CA1705", Justification = "This capitalisation is appropriate since the value it represents has all upper-case capitalisation.")]
+ SDATA,
+
+ ///
+ /// The contents of a Processing Instruction.
+ ///
+ [SuppressMessage("Microsoft.Naming", "CA1705", Justification = "This capitalisation is appropriate since the value it represents has all upper-case capitalisation.")]
+ PI
+ };
+
+ ///
+ /// An Entity declared in a DTD.
+ ///
+ public class Entity : IDisposable
+ {
+ ///
+ /// The character indicating End Of File.
+ ///
+ [SuppressMessage("Microsoft.Naming", "CA1705", Justification = "The capitalisation is correct since EOF is an acronym.")]
+ public const char EOF = (char)65535;
+
+ private string m_proxy;
+ private string m_name;
+ private bool m_isInternal;
+ private string m_publicId;
+ private string m_uri;
+ private string m_literal;
+ private LiteralType m_literalType;
+ private Entity m_parent;
+ private bool m_isHtml;
+ private int m_line;
+ private char m_lastchar;
+ private bool m_isWhitespace;
+
+ private Encoding m_encoding;
+ private Uri m_resolvedUri;
+ private TextReader m_stm;
+ private bool m_weOwnTheStream;
+ private int m_lineStart;
+ private int m_absolutePos;
+
+ ///
+ /// Initialises a new instance of an Entity declared in a DTD.
+ ///
+ /// The name of the entity.
+ /// The public id of the entity.
+ /// The uri of the entity.
+ /// The proxy server to use when retrieving any web content.
+ public Entity(string name, string pubid, string uri, string proxy)
+ {
+ m_name = name;
+ m_publicId = pubid;
+ m_uri = uri;
+ m_proxy = proxy;
+ m_isHtml = (name != null && StringUtilities.EqualsIgnoreCase(name, "html"));
+ }
+
+ ///
+ /// Initialises a new instance of an Entity declared in a DTD.
+ ///
+ /// The name of the entity.
+ /// The literal value of the entity.
+ public Entity(string name, string literal)
+ {
+ m_name = name;
+ m_literal = literal;
+ m_isInternal = true;
+ }
+
+ ///
+ /// Initialises a new instance of an Entity declared in a DTD.
+ ///
+ /// The name of the entity.
+ /// The baseUri for the entity to read from the TextReader.
+ /// The TextReader to read the entity from.
+ /// The proxy server to use when retrieving any web content.
+ public Entity(string name, Uri baseUri, TextReader stm, string proxy)
+ {
+ m_name = name;
+ m_isInternal = true;
+ m_stm = stm;
+ m_resolvedUri = baseUri;
+ m_proxy = proxy;
+ m_isHtml = string.Equals(name, "html", StringComparison.OrdinalIgnoreCase);
+ }
+
+ ///
+ /// The name of the entity.
+ ///
+ public string Name
+ {
+ get
{
- int j = contentType.IndexOf("=", i);
- int k = contentType.IndexOf(";", j);
- if (k < 0)
- k = contentType.Length;
+ return m_name;
+ }
+ }
- if (j > 0)
- {
- j++;
- string charset = contentType.Substring(j, k - j).Trim();
- try
+ ///
+ /// True if the entity is the html element entity.
+ ///
+ public bool IsHtml
+ {
+ get
+ {
+ return m_isHtml;
+ }
+ set
+ {
+ m_isHtml = value;
+ }
+ }
+
+ ///
+ /// The public identifier of this entity.
+ ///
+ public string PublicId
+ {
+ get
+ {
+ return m_publicId;
+ }
+ }
+
+ ///
+ /// The Uri that is the source for this entity.
+ ///
+ public string Uri
+ {
+ get
+ {
+ return m_uri;
+ }
+ }
+
+ ///
+ /// The resolved location of the DTD this entity is from.
+ ///
+ public Uri ResolvedUri
+ {
+ get
+ {
+ if (this.m_resolvedUri != null)
+ return this.m_resolvedUri;
+ else if (m_parent != null)
+ return m_parent.ResolvedUri;
+ else
+ return null;
+ }
+ }
+
+ ///
+ /// Gets the parent Entity of this Entity.
+ ///
+ public Entity Parent
+ {
+ get
+ {
+ return m_parent;
+ }
+ }
+
+ ///
+ /// The last character read from the input stream for this entity.
+ ///
+ public char Lastchar
+ {
+ get
+ {
+ return m_lastchar;
+ }
+ }
+
+ ///
+ /// The line on which this entity was defined.
+ ///
+ public int Line
+ {
+ get
+ {
+ return m_line;
+ }
+ }
+
+ ///
+ /// The index into the line where this entity is defined.
+ ///
+ public int LinePosition
+ {
+ get
+ {
+ return this.m_absolutePos - this.m_lineStart + 1;
+ }
+ }
+
+ ///
+ /// Whether this entity is an internal entity or not.
+ ///
+ /// true if this entity is internal, otherwise false.
+ public bool IsInternal
+ {
+ get
+ {
+ return m_isInternal;
+ }
+ }
+
+ ///
+ /// The literal value of this entity.
+ ///
+ public string Literal
+ {
+ get
+ {
+ return m_literal;
+ }
+ }
+
+ ///
+ /// The of this entity.
+ ///
+ public LiteralType LiteralType
+ {
+ get
+ {
+ return m_literalType;
+ }
+ }
+
+ ///
+ /// Whether the last char read for this entity is a whitespace character.
+ ///
+ public bool IsWhitespace
+ {
+ get
+ {
+ return m_isWhitespace;
+ }
+ }
+
+ ///
+ /// The proxy server to use when making web requests to resolve entities.
+ ///
+ public string Proxy
+ {
+ get
+ {
+ return m_proxy;
+ }
+ }
+
+ ///
+ /// Reads the next character from the DTD stream.
+ ///
+ /// The next character from the DTD stream.
+ public char ReadChar()
+ {
+ char ch = (char)this.m_stm.Read();
+ if (ch == 0)
+ {
+ // convert nulls to whitespace, since they are not valid in XML anyway.
+ ch = ' ';
+ }
+ this.m_absolutePos++;
+ if (ch == 0xa)
+ {
+ m_isWhitespace = true;
+ this.m_lineStart = this.m_absolutePos + 1;
+ this.m_line++;
+ }
+ else if (ch == ' ' || ch == '\t')
+ {
+ m_isWhitespace = true;
+ if (m_lastchar == 0xd)
{
- e = Encoding.GetEncoding(charset);
+ this.m_lineStart = this.m_absolutePos;
+ m_line++;
}
- catch (ArgumentException)
- {
- }
- }
}
-
- stream = resp.GetResponseStream();
- break;
- }
-
- this.m_weOwnTheStream = true;
- HtmlStream html = new HtmlStream(stream, e);
- this.m_encoding = html.Encoding;
- this.m_stm = html;
- }
- }
-
- private static HttpWebResponse GetResponse(HttpWebRequest wr, TimeSpan timeout)
- {
- HttpWebResponse response = null;
- Exception exception = null;
- var signal = new ManualResetEvent(false);
-
- wr.BeginGetResponse(ar =>
- {
- try
- {
- response = (HttpWebResponse)wr.EndGetResponse(ar);
- }
- catch (Exception ex)
- {
- exception = ex;
- }
- finally
- {
- signal.Set();
- }
- }, null);
-
- if (!signal.WaitOne(timeout))
- {
- throw new TimeoutException("Timeout waiting for response");
- }
-
- if (exception != null)
- {
- throw new IOException(exception.Message, exception);
- }
-
- return response;
- }
-
- ///
- /// Gets the character encoding for this entity.
- ///
- public Encoding Encoding
- {
- get
- {
- return this.m_encoding;
- }
- }
-
- ///
- /// Closes the reader from which the entity is being read.
- ///
- public void Close()
- {
- if (this.m_weOwnTheStream)
- this.m_stm.Dispose();
- }
-
- ///
- /// Returns the next character after any whitespace.
- ///
- /// The next character that is not whitespace.
- public char SkipWhitespace()
- {
- char ch = m_lastchar;
- while (ch != Entity.EOF && (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t'))
- {
- ch = ReadChar();
- }
- return ch;
- }
-
- ///
- /// Scans a token from the input stream and returns the result.
- ///
- /// The to use to process the token.
- /// A set of characters to look for as terminators for the token.
- /// true if the token should be a NMToken, otherwise false.
- /// The scanned token.
- public string ScanToken(StringBuilder sb, string term, bool nmtoken)
- {
- if (sb == null)
- throw new ArgumentNullException("sb");
-
- if (term == null)
- throw new ArgumentNullException("term");
-
- sb.Length = 0;
- char ch = m_lastchar;
- if (nmtoken && ch != '_' && !char.IsLetter(ch))
- {
- throw new SgmlParseException(string.Format(CultureInfo.CurrentUICulture, "Invalid name start character '{0}'", ch));
- }
-
- while (ch != Entity.EOF && term.IndexOf(ch) < 0)
- {
- if (!nmtoken || ch == '_' || ch == '.' || ch == '-' || ch == ':' || char.IsLetterOrDigit(ch))
- {
- sb.Append(ch);
- }
- else
- {
- throw new SgmlParseException(
- string.Format(CultureInfo.CurrentUICulture, "Invalid name character '{0}'", ch));
- }
- ch = ReadChar();
- }
-
- return sb.ToString();
- }
-
- ///
- /// Read a literal from the input stream.
- ///
- /// The to use to build the literal.
- /// The delimiter for the literal.
- /// The literal scanned from the input stream.
- public string ScanLiteral(StringBuilder sb, char quote)
- {
- if (sb == null)
- throw new ArgumentNullException("sb");
-
- sb.Length = 0;
- char ch = ReadChar();
- while (ch != Entity.EOF && ch != quote)
- {
- if (ch == '&')
- {
- ch = ReadChar();
- if (ch == '#')
- {
- string charent = ExpandCharEntity();
- sb.Append(charent);
- ch = this.m_lastchar;
- }
- else
- {
- sb.Append('&');
- sb.Append(ch);
- ch = ReadChar();
- }
- }
- else
- {
- sb.Append(ch);
- ch = ReadChar();
- }
- }
-
- ReadChar(); // consume end quote.
- return sb.ToString();
- }
-
- ///
- /// Reads input until the end of the input stream or until a string of terminator characters is found.
- ///
- /// The to use to build the string.
- /// The type of the element being read (only used in reporting errors).
- /// The string of terminator characters to look for.
- /// The string read from the input stream.
- public string ScanToEnd(StringBuilder sb, string type, string terminators)
- {
- if (terminators == null)
- throw new ArgumentNullException("terminators");
-
- if (sb != null)
- sb.Length = 0;
-
- int start = m_line;
- // This method scans over a chunk of text looking for the
- // termination sequence specified by the 'terminators' parameter.
- char ch = ReadChar();
- int state = 0;
- char next = terminators[state];
- while (ch != Entity.EOF)
- {
- if (ch == next)
- {
- state++;
- if (state >= terminators.Length)
- {
- // found it!
- break;
- }
- next = terminators[state];
- }
- else if (state > 0)
- {
- // char didn't match, so go back and see how much does still match.
- int i = state - 1;
- int newstate = 0;
- while (i >= 0 && newstate == 0)
- {
- if (terminators[i] == ch)
+ else if (ch == 0xd)
{
- // character is part of the terminators pattern, ok, so see if we can
- // match all the way back to the beginning of the pattern.
- int j = 1;
- while (i - j >= 0)
- {
- if (terminators[i - j] != terminators[state - j])
- break;
-
- j++;
- }
-
- if (j > i)
- {
- newstate = i + 1;
- }
+ m_isWhitespace = true;
}
else
{
- i--;
- }
- }
+ m_isWhitespace = false;
+ if (m_lastchar == 0xd)
+ {
+ m_line++;
+ this.m_lineStart = this.m_absolutePos;
+ }
+ }
- if (sb != null)
- {
- i = (i < 0) ? 1 : 0;
- for (int k = 0; k <= state - newstate - i; k++)
+ m_lastchar = ch;
+ return ch;
+ }
+
+ ///
+ /// Begins processing an entity.
+ ///
+ /// The parent of this entity.
+ /// The base Uri for processing this entity within.
+ public void Open(Entity parent, Uri baseUri)
+ {
+ this.m_parent = parent;
+ if (parent != null)
+ this.m_isHtml = parent.IsHtml;
+ this.m_line = 1;
+ if (m_isInternal)
{
- sb.Append(terminators[k]);
- }
-
- if (i > 0) // see if we've matched this char or not
- sb.Append(ch); // if not then append it to buffer.
- }
-
- state = newstate;
- next = terminators[newstate];
- }
- else
- {
- if (sb != null)
- sb.Append(ch);
- }
-
- ch = ReadChar();
- }
-
- if (ch == 0)
- Error(type + " starting on line {0} was never closed", start);
-
- ReadChar(); // consume last char in termination sequence.
- if (sb != null)
- return sb.ToString();
- else
- return string.Empty;
- }
-
- ///
- /// Expands a character entity to be read from the input stream.
- ///
- /// The string for the character entity.
- public string ExpandCharEntity()
- {
- string value;
- int v = ReadNumericEntityCode(out value);
- if (v == -1)
- {
- return value;
- }
-
- // HACK ALERT: IE and Netscape map the unicode characters
- if (this.m_isHtml && v >= 0x80 & v <= 0x9F)
- {
- // This range of control characters is mapped to Windows-1252!
- int i = v - 0x80;
- int unicode = CtrlMap[i];
- return Convert.ToChar(unicode).ToString();
- }
-
- if (0xD800 <= v && v <= 0xDBFF)
- {
- // high surrogate
- if (m_lastchar == '&')
- {
- char ch = ReadChar();
- if (ch == '#')
- {
- string value2;
- int v2 = ReadNumericEntityCode(out value2);
- if (v2 == -1)
+ if (this.m_literal != null)
+ this.m_stm = new StringReader(this.m_literal);
+ }
+ else if (this.m_uri == null)
{
- return value + ";" + value2;
+ this.Error("Unresolvable entity '{0}'", this.m_name);
}
- if (0xDC00 <= v2 && v2 <= 0xDFFF)
+ else
{
+ if (baseUri != null)
+ {
+ this.m_resolvedUri = new Uri(baseUri, this.m_uri);
+ }
+ else
+ {
+ this.m_resolvedUri = new Uri(this.m_uri);
+ }
- // low surrogate
- v = UTF32Utilities.ConvertToUtf32((char)v, (char)v2);
+ Stream stream = null;
+#if PORTABLE
+ Encoding e = Encoding.UTF8;
+#else
+ Encoding e = Encoding.Default;
+#endif
+ switch (this.m_resolvedUri.Scheme)
+ {
+ case "file":
+ {
+#if PORTABLE
+ throw new NotSupportedException("The file scheme is not supported by the .NETPortable framework.");
+#else
+ string path = this.m_resolvedUri.LocalPath;
+ stream = new FileStream(path, FileMode.Open, FileAccess.Read);
+#endif
+ }
+ break;
+ default:
+ //Console.WriteLine("Fetching:" + ResolvedUri.AbsoluteUri);
+ HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(ResolvedUri);
+#if !PORTABLE
+ wr.UserAgent = "Mozilla/4.0 (compatible;);";
+ wr.Timeout = 10000; // in case this is running in an ASPX page.
+ if (m_proxy != null)
+ wr.Proxy = new WebProxy(m_proxy);
+ wr.PreAuthenticate = false;
+ // Pass the credentials of the process.
+ wr.Credentials = CredentialCache.DefaultCredentials;
+#endif
+ WebResponse resp = GetResponse(wr, TimeSpan.FromSeconds(10));
+ Uri actual = resp.ResponseUri;
+ if (!string.Equals(actual.AbsoluteUri, this.m_resolvedUri.AbsoluteUri, StringComparison.OrdinalIgnoreCase))
+ {
+ this.m_resolvedUri = actual;
+ }
+ string contentType = resp.ContentType.ToLowerInvariant();
+ string mimeType = contentType;
+ int i = contentType.IndexOf(';');
+ if (i >= 0)
+ {
+ mimeType = contentType.Substring(0, i);
+ }
+
+ if (StringUtilities.EqualsIgnoreCase(mimeType, "text/html"))
+ {
+ this.m_isHtml = true;
+ }
+
+ i = contentType.IndexOf("charset");
+#if PORTABLE
+ e = Encoding.UTF8;
+#else
+ e = Encoding.Default;
+#endif
+
+ if (i >= 0)
+ {
+ int j = contentType.IndexOf("=", i);
+ int k = contentType.IndexOf(";", j);
+ if (k < 0)
+ k = contentType.Length;
+
+ if (j > 0)
+ {
+ j++;
+ string charset = contentType.Substring(j, k - j).Trim();
+ try
+ {
+ e = Encoding.GetEncoding(charset);
+ }
+ catch (ArgumentException)
+ {
+ }
+ }
+ }
+
+ stream = resp.GetResponseStream();
+ break;
+ }
+
+ this.m_weOwnTheStream = true;
+ HtmlStream html = new HtmlStream(stream, e);
+ this.m_encoding = html.Encoding;
+ this.m_stm = html;
}
- }
- else
- {
- Error("Premature {0} parsing surrogate pair", ch);
- }
}
- else
- {
- Error("Premature {0} parsing surrogate pair", m_lastchar);
- }
- }
- // NOTE (steveb): we need to use ConvertFromUtf32 to allow for extended numeric encodings
- return UTF32Utilities.ConvertFromUtf32(v);
- }
+ private static HttpWebResponse GetResponse(HttpWebRequest wr, TimeSpan timeout)
+ {
+ HttpWebResponse response = null;
+ Exception exception = null;
+ var signal = new ManualResetEvent(false);
- private int ReadNumericEntityCode(out string value)
- {
- int v = 0;
- char ch = ReadChar();
- value = "";
- if (ch == 'x')
- {
- bool sawHexDigit = false;
- value += "x";
- ch = ReadChar();
- for (; ch != Entity.EOF && ch != ';'; ch = ReadChar())
- {
- int p = 0;
- if (ch >= '0' && ch <= '9')
- {
- p = (int)(ch - '0');
- sawHexDigit = true;
- }
- else if (ch >= 'a' && ch <= 'f')
- {
- p = (int)(ch - 'a') + 10;
- sawHexDigit = true;
- }
- else if (ch >= 'A' && ch <= 'F')
- {
- p = (int)(ch - 'A') + 10;
- sawHexDigit = true;
- }
- else
- {
- break; //we must be done!
- //Error("Hex digit out of range '{0}'", (int)ch);
- }
- value += ch;
- v = (v * 16) + p;
- }
- if (!sawHexDigit)
- {
- return -1;
- }
- }
- else
- {
- bool sawDigit = false;
- for (; ch != Entity.EOF && ch != ';'; ch = ReadChar())
- {
- if (ch >= '0' && ch <= '9')
- {
- v = (v * 10) + (int)(ch - '0');
- sawDigit = true;
- }
- else
- {
- break; // we must be done!
- //Error("Decimal digit out of range '{0}'", (int)ch);
- }
- value += ch;
- }
- if (!sawDigit)
- {
- return -1;
- }
- }
- if (ch == 0)
- {
- Error("Premature {0} parsing entity reference", ch);
- }
- else if (ch == ';')
- {
- ReadChar();
- }
- return v;
- }
+ wr.BeginGetResponse(ar =>
+ {
+ try
+ {
+ response = (HttpWebResponse) wr.EndGetResponse(ar);
+ }
+ catch (Exception ex)
+ {
+ exception = ex;
+ }
+ finally
+ {
+ signal.Set();
+ }
+ }, null);
- static int[] CtrlMap = new int[] {
+ if (!signal.WaitOne(timeout))
+ {
+ throw new TimeoutException("Timeout waiting for response");
+ }
+
+ if (exception != null)
+ {
+ throw new IOException(exception.Message, exception);
+ }
+
+ return response;
+ }
+
+ ///
+ /// Gets the character encoding for this entity.
+ ///
+ public Encoding Encoding
+ {
+ get
+ {
+ return this.m_encoding;
+ }
+ }
+
+ ///
+ /// Closes the reader from which the entity is being read.
+ ///
+ public void Close()
+ {
+ if (this.m_weOwnTheStream)
+ this.m_stm.Dispose();
+ }
+
+ ///
+ /// Returns the next character after any whitespace.
+ ///
+ /// The next character that is not whitespace.
+ public char SkipWhitespace()
+ {
+ char ch = m_lastchar;
+ while (ch != Entity.EOF && (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t'))
+ {
+ ch = ReadChar();
+ }
+ return ch;
+ }
+
+ ///
+ /// Scans a token from the input stream and returns the result.
+ ///
+ /// The to use to process the token.
+ /// A set of characters to look for as terminators for the token.
+ /// true if the token should be a NMToken, otherwise false.
+ /// The scanned token.
+ public string ScanToken(StringBuilder sb, string term, bool nmtoken)
+ {
+ if (sb == null)
+ throw new ArgumentNullException("sb");
+
+ if (term == null)
+ throw new ArgumentNullException("term");
+
+ sb.Length = 0;
+ char ch = m_lastchar;
+ if (nmtoken && ch != '_' && !char.IsLetter(ch))
+ {
+ throw new SgmlParseException(string.Format(CultureInfo.CurrentUICulture, "Invalid name start character '{0}'", ch));
+ }
+
+ while (ch != Entity.EOF && term.IndexOf(ch) < 0)
+ {
+ if (!nmtoken || ch == '_' || ch == '.' || ch == '-' || ch == ':' || char.IsLetterOrDigit(ch)) {
+ sb.Append(ch);
+ }
+ else {
+ throw new SgmlParseException(
+ string.Format(CultureInfo.CurrentUICulture, "Invalid name character '{0}'", ch));
+ }
+ ch = ReadChar();
+ }
+
+ return sb.ToString();
+ }
+
+ ///
+ /// Read a literal from the input stream.
+ ///
+ /// The to use to build the literal.
+ /// The delimiter for the literal.
+ /// The literal scanned from the input stream.
+ public string ScanLiteral(StringBuilder sb, char quote)
+ {
+ if (sb == null)
+ throw new ArgumentNullException("sb");
+
+ sb.Length = 0;
+ char ch = ReadChar();
+ while (ch != Entity.EOF && ch != quote)
+ {
+ if (ch == '&')
+ {
+ ch = ReadChar();
+ if (ch == '#')
+ {
+ string charent = ExpandCharEntity();
+ sb.Append(charent);
+ ch = this.m_lastchar;
+ }
+ else
+ {
+ sb.Append('&');
+ sb.Append(ch);
+ ch = ReadChar();
+ }
+ }
+ else
+ {
+ sb.Append(ch);
+ ch = ReadChar();
+ }
+ }
+
+ ReadChar(); // consume end quote.
+ return sb.ToString();
+ }
+
+ ///
+ /// Reads input until the end of the input stream or until a string of terminator characters is found.
+ ///
+ /// The to use to build the string.
+ /// The type of the element being read (only used in reporting errors).
+ /// The string of terminator characters to look for.
+ /// The string read from the input stream.
+ public string ScanToEnd(StringBuilder sb, string type, string terminators)
+ {
+ if (terminators == null)
+ throw new ArgumentNullException("terminators");
+
+ if (sb != null)
+ sb.Length = 0;
+
+ int start = m_line;
+ // This method scans over a chunk of text looking for the
+ // termination sequence specified by the 'terminators' parameter.
+ char ch = ReadChar();
+ int state = 0;
+ char next = terminators[state];
+ while (ch != Entity.EOF)
+ {
+ if (ch == next)
+ {
+ state++;
+ if (state >= terminators.Length)
+ {
+ // found it!
+ break;
+ }
+ next = terminators[state];
+ }
+ else if (state > 0)
+ {
+ // char didn't match, so go back and see how much does still match.
+ int i = state - 1;
+ int newstate = 0;
+ while (i >= 0 && newstate == 0)
+ {
+ if (terminators[i] == ch)
+ {
+ // character is part of the terminators pattern, ok, so see if we can
+ // match all the way back to the beginning of the pattern.
+ int j = 1;
+ while (i - j >= 0)
+ {
+ if (terminators[i - j] != terminators[state - j])
+ break;
+
+ j++;
+ }
+
+ if (j > i)
+ {
+ newstate = i + 1;
+ }
+ }
+ else
+ {
+ i--;
+ }
+ }
+
+ if (sb != null)
+ {
+ i = (i < 0) ? 1 : 0;
+ for (int k = 0; k <= state - newstate - i; k++)
+ {
+ sb.Append(terminators[k]);
+ }
+
+ if (i > 0) // see if we've matched this char or not
+ sb.Append(ch); // if not then append it to buffer.
+ }
+
+ state = newstate;
+ next = terminators[newstate];
+ }
+ else
+ {
+ if (sb != null)
+ sb.Append(ch);
+ }
+
+ ch = ReadChar();
+ }
+
+ if (ch == 0)
+ Error(type + " starting on line {0} was never closed", start);
+
+ ReadChar(); // consume last char in termination sequence.
+ if (sb != null)
+ return sb.ToString();
+ else
+ return string.Empty;
+ }
+
+ ///
+ /// Expands a character entity to be read from the input stream.
+ ///
+ /// The string for the character entity.
+ public string ExpandCharEntity()
+ {
+ string value;
+ int v = ReadNumericEntityCode(out value);
+ if(v == -1)
+ {
+ return value;
+ }
+
+ // HACK ALERT: IE and Netscape map the unicode characters
+ if (this.m_isHtml && v >= 0x80 & v <= 0x9F)
+ {
+ // This range of control characters is mapped to Windows-1252!
+ int i = v - 0x80;
+ int unicode = CtrlMap[i];
+ return Convert.ToChar(unicode).ToString();
+ }
+
+ if (0xD800 <= v && v <= 0xDBFF)
+ {
+ // high surrogate
+ if (m_lastchar == '&')
+ {
+ char ch = ReadChar();
+ if (ch == '#')
+ {
+ string value2;
+ int v2 = ReadNumericEntityCode(out value2);
+ if(v2 == -1)
+ {
+ return value + ";" + value2;
+ }
+ if (0xDC00 <= v2 && v2 <= 0xDFFF)
+ {
+
+ // low surrogate
+ v = UTF32Utilities.ConvertToUtf32((char)v, (char)v2);
+ }
+ }
+ else
+ {
+ Error("Premature {0} parsing surrogate pair", ch);
+ }
+ }
+ else
+ {
+ Error("Premature {0} parsing surrogate pair", m_lastchar);
+ }
+ }
+
+ // NOTE (steveb): we need to use ConvertFromUtf32 to allow for extended numeric encodings
+ return UTF32Utilities.ConvertFromUtf32(v);
+ }
+
+ private int ReadNumericEntityCode(out string value)
+ {
+ int v = 0;
+ char ch = ReadChar();
+ value = "";
+ if (ch == 'x')
+ {
+ bool sawHexDigit = false;
+ value += "x";
+ ch = ReadChar();
+ for (; ch != Entity.EOF && ch != ';'; ch = ReadChar())
+ {
+ int p = 0;
+ if (ch >= '0' && ch <= '9')
+ {
+ p = (int)(ch - '0');
+ sawHexDigit = true;
+ }
+ else if (ch >= 'a' && ch <= 'f')
+ {
+ p = (int)(ch - 'a') + 10;
+ sawHexDigit = true;
+ }
+ else if (ch >= 'A' && ch <= 'F')
+ {
+ p = (int)(ch - 'A') + 10;
+ sawHexDigit = true;
+ }
+ else
+ {
+ break; //we must be done!
+ //Error("Hex digit out of range '{0}'", (int)ch);
+ }
+ value += ch;
+ v = (v*16) + p;
+ }
+ if (!sawHexDigit)
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ bool sawDigit = false;
+ for (; ch != Entity.EOF && ch != ';'; ch = ReadChar())
+ {
+ if (ch >= '0' && ch <= '9')
+ {
+ v = (v*10) + (int)(ch - '0');
+ sawDigit = true;
+ }
+ else
+ {
+ break; // we must be done!
+ //Error("Decimal digit out of range '{0}'", (int)ch);
+ }
+ value += ch;
+ }
+ if (!sawDigit)
+ {
+ return -1;
+ }
+ }
+ if (ch == 0)
+ {
+ Error("Premature {0} parsing entity reference", ch);
+ }
+ else if (ch == ';')
+ {
+ ReadChar();
+ }
+ return v;
+ }
+
+ static int[] CtrlMap = new int[] {
// This is the windows-1252 mapping of the code points 0x80 through 0x9f.
8364, 129, 8218, 402, 8222, 8230, 8224, 8225, 710, 8240, 352, 8249, 338, 141,
381, 143, 144, 8216, 8217, 8220, 8221, 8226, 8211, 8212, 732, 8482, 353, 8250,
339, 157, 382, 376
};
- ///
- /// Raise a processing error.
- ///
- /// The error message to use in the exception.
- /// Always thrown.
- public void Error(string msg)
- {
- throw new SgmlParseException(msg, this);
- }
-
- ///
- /// Raise a processing error.
- ///
- /// The error message to use in the exception.
- /// The unexpected character causing the error.
- /// Always thrown.
- public void Error(string msg, char ch)
- {
- string str = (ch == Entity.EOF) ? "EOF" : char.ToString(ch);
- throw new SgmlParseException(string.Format(CultureInfo.CurrentUICulture, msg, str), this);
- }
-
- ///
- /// Raise a processing error.
- ///
- /// The error message to use in the exception.
- /// The value causing the error.
- /// Always thrown.
- public void Error(string msg, int x)
- {
- throw new SgmlParseException(string.Format(CultureInfo.CurrentUICulture, msg, x), this);
- }
-
- ///
- /// Raise a processing error.
- ///
- /// The error message to use in the exception.
- /// The argument for the error.
- /// Always thrown.
- public void Error(string msg, string arg)
- {
- throw new SgmlParseException(string.Format(CultureInfo.CurrentUICulture, msg, arg), this);
- }
-
- ///
- /// Returns a string giving information on how the entity is referenced and declared, walking up the parents until the top level parent entity is found.
- ///
- /// Contextual information for the entity.
- public string Context()
- {
- Entity p = this;
- StringBuilder sb = new StringBuilder();
- while (p != null)
- {
- string msg;
- if (p.m_isInternal)
+ ///
+ /// Raise a processing error.
+ ///
+ /// The error message to use in the exception.
+ /// Always thrown.
+ public void Error(string msg)
{
- msg = string.Format(CultureInfo.InvariantCulture, "\nReferenced on line {0}, position {1} of internal entity '{2}'", p.m_line, p.LinePosition, p.m_name);
+ throw new SgmlParseException(msg, this);
}
- else
+
+ ///
+ /// Raise a processing error.
+ ///
+ /// The error message to use in the exception.
+ /// The unexpected character causing the error.
+ /// Always thrown.
+ public void Error(string msg, char ch)
{
- msg = string.Format(CultureInfo.InvariantCulture, "\nReferenced on line {0}, position {1} of '{2}' entity at [{3}]", p.m_line, p.LinePosition, p.m_name, p.ResolvedUri.AbsolutePath);
+ string str = (ch == Entity.EOF) ? "EOF" : char.ToString(ch);
+ throw new SgmlParseException(string.Format(CultureInfo.CurrentUICulture, msg, str), this);
}
- sb.Append(msg);
- p = p.Parent;
- }
- return sb.ToString();
- }
-
- ///
- /// Checks whether a token denotes a literal entity or not.
- ///
- /// The token to check.
- /// true if the token is "CDATA", "SDATA" or "PI", otherwise false.
- public static bool IsLiteralType(string token)
- {
- return string.Equals(token, "CDATA", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(token, "SDATA", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(token, "PI", StringComparison.OrdinalIgnoreCase);
- }
-
- ///
- /// Sets the entity to be a literal of the type specified.
- ///
- /// One of "CDATA", "SDATA" or "PI".
- public void SetLiteralType(string token)
- {
- switch (token)
- {
- case "CDATA":
- this.m_literalType = LiteralType.CDATA;
- break;
- case "SDATA":
- this.m_literalType = LiteralType.SDATA;
- break;
- case "PI":
- this.m_literalType = LiteralType.PI;
- break;
- }
- }
-
- #region IDisposable Members
-
- ///
- /// The finalizer for the Entity class.
- ///
- ~Entity()
- {
- Dispose(false);
- }
-
- ///
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- ///
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- ///
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- ///
- /// true if this method has been called by user code, false if it has been called through a finalizer.
- protected virtual void Dispose(bool isDisposing)
- {
- if (isDisposing)
- {
- if (m_stm != null)
+ ///
+ /// Raise a processing error.
+ ///
+ /// The error message to use in the exception.
+ /// The value causing the error.
+ /// Always thrown.
+ public void Error(string msg, int x)
{
- m_stm.Dispose();
- m_stm = null;
+ throw new SgmlParseException(string.Format(CultureInfo.CurrentUICulture, msg, x), this);
}
- }
- }
- #endregion
- }
-
- // This class decodes an HTML/XML stream correctly.
- internal class HtmlStream : TextReader
- {
- private Stream stm;
- private byte[] rawBuffer;
- private int rawPos;
- private int rawUsed;
- private Encoding m_encoding;
- private Decoder m_decoder;
- private char[] m_buffer;
- private int used;
- private int pos;
- private const int BUFSIZE = 16384;
- private const int EOF = -1;
-
- public HtmlStream(Stream stm, Encoding defaultEncoding)
- {
- if (defaultEncoding == null) defaultEncoding = Encoding.UTF8; // default is UTF8
- if (!stm.CanSeek)
- {
- // Need to be able to seek to sniff correctly.
- stm = CopyToMemoryStream(stm);
- }
- this.stm = stm;
- rawBuffer = new Byte[BUFSIZE];
- rawUsed = stm.Read(rawBuffer, 0, 4); // maximum byte order mark
- this.m_buffer = new char[BUFSIZE];
-
- // Check byte order marks
- this.m_decoder = AutoDetectEncoding(rawBuffer, ref rawPos, rawUsed);
- int bom = rawPos;
- if (this.m_decoder == null)
- {
- this.m_decoder = defaultEncoding.GetDecoder();
- rawUsed += stm.Read(rawBuffer, 4, BUFSIZE - 4);
- DecodeBlock();
- // Now sniff to see if there is an XML declaration or HTML tag.
- Decoder sd = SniffEncoding();
- if (sd != null)
+ ///
+ /// Raise a processing error.
+ ///
+ /// The error message to use in the exception.
+ /// The argument for the error.
+ /// Always thrown.
+ public void Error(string msg, string arg)
{
- this.m_decoder = sd;
+ throw new SgmlParseException(string.Format(CultureInfo.CurrentUICulture, msg, arg), this);
}
- }
- // Reset to get ready for Read()
- this.stm.Seek(0, SeekOrigin.Begin);
- this.pos = this.used = 0;
- // skip bom
- if (bom > 0)
- {
- stm.Read(this.rawBuffer, 0, bom);
- }
- this.rawPos = this.rawUsed = 0;
-
- }
-
- public Encoding Encoding
- {
- get
- {
- return this.m_encoding;
- }
- }
-
- private static Stream CopyToMemoryStream(Stream s)
- {
- int size = 100000; // large heap is more efficient
- byte[] copyBuff = new byte[size];
- int len;
- MemoryStream r = new MemoryStream();
- while ((len = s.Read(copyBuff, 0, size)) > 0)
- r.Write(copyBuff, 0, len);
-
- r.Seek(0, SeekOrigin.Begin);
- s.Dispose();
- return r;
- }
-
- internal void DecodeBlock()
- {
- // shift current chars to beginning.
- if (pos > 0)
- {
- if (pos < used)
+ ///
+ /// Returns a string giving information on how the entity is referenced and declared, walking up the parents until the top level parent entity is found.
+ ///
+ /// Contextual information for the entity.
+ public string Context()
{
- System.Array.Copy(m_buffer, pos, m_buffer, 0, used - pos);
- }
- used -= pos;
- pos = 0;
- }
- int len = m_decoder.GetCharCount(rawBuffer, rawPos, rawUsed - rawPos);
- int available = m_buffer.Length - used;
- if (available < len)
- {
- char[] newbuf = new char[m_buffer.Length + len];
- System.Array.Copy(m_buffer, pos, newbuf, 0, used - pos);
- m_buffer = newbuf;
- }
- used = pos + m_decoder.GetChars(rawBuffer, rawPos, rawUsed - rawPos, m_buffer, pos);
- rawPos = rawUsed; // consumed the whole buffer!
- }
- internal static Decoder AutoDetectEncoding(byte[] buffer, ref int index, int length)
- {
- if (4 <= (length - index))
- {
- uint w = (uint)buffer[index + 0] << 24 | (uint)buffer[index + 1] << 16 | (uint)buffer[index + 2] << 8 | (uint)buffer[index + 3];
- // see if it's a 4-byte encoding
- switch (w)
- {
- case 0xfefffeff:
- index += 4;
- return new Ucs4DecoderBigEngian();
-
- case 0xfffefffe:
- index += 4;
- return new Ucs4DecoderLittleEndian();
-
- case 0x3c000000:
- goto case 0xfefffeff;
-
- case 0x0000003c:
- goto case 0xfffefffe;
- }
- w >>= 8;
- if (w == 0xefbbbf)
- {
- index += 3;
- return Encoding.UTF8.GetDecoder();
- }
- w >>= 8;
- switch (w)
- {
- case 0xfeff:
- index += 2;
- return UnicodeEncoding.BigEndianUnicode.GetDecoder();
-
- case 0xfffe:
- index += 2;
- return new UnicodeEncoding(false, false).GetDecoder();
-
- case 0x3c00:
- goto case 0xfeff;
-
- case 0x003c:
- goto case 0xfffe;
- }
- }
- return null;
- }
- private int ReadChar()
- {
- // Read only up to end of current buffer then stop.
- if (pos < used) return m_buffer[pos++];
- return EOF;
- }
- private int PeekChar()
- {
- int ch = ReadChar();
- if (ch != EOF)
- {
- pos--;
- }
- return ch;
- }
- private bool SniffPattern(string pattern)
- {
- int ch = PeekChar();
- if (ch != pattern[0]) return false;
- for (int i = 0, n = pattern.Length; ch != EOF && i < n; i++)
- {
- ch = ReadChar();
- char m = pattern[i];
- if (ch != m)
- {
- return false;
- }
- }
- return true;
- }
- private void SniffWhitespace()
- {
- char ch = (char)PeekChar();
- while (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
- {
- int i = pos;
- ch = (char)ReadChar();
- if (ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n')
- pos = i;
- }
- }
-
- private string SniffLiteral()
- {
- int quoteChar = PeekChar();
- if (quoteChar == '\'' || quoteChar == '"')
- {
- ReadChar();// consume quote char
- int i = this.pos;
- int ch = ReadChar();
- while (ch != EOF && ch != quoteChar)
- {
- ch = ReadChar();
- }
- return (pos > i) ? new string(m_buffer, i, pos - i - 1) : "";
- }
- return null;
- }
- private string SniffAttribute(string name)
- {
- SniffWhitespace();
- string id = SniffName();
- if (string.Equals(name, id, StringComparison.OrdinalIgnoreCase))
- {
- SniffWhitespace();
- if (SniffPattern("="))
- {
- SniffWhitespace();
- return SniffLiteral();
- }
- }
- return null;
- }
- private string SniffAttribute(out string name)
- {
- SniffWhitespace();
- name = SniffName();
- if (name != null)
- {
- SniffWhitespace();
- if (SniffPattern("="))
- {
- SniffWhitespace();
- return SniffLiteral();
- }
- }
- return null;
- }
- private void SniffTerminator(string term)
- {
- int ch = ReadChar();
- int i = 0;
- int n = term.Length;
- while (i < n && ch != EOF)
- {
- if (term[i] == ch)
- {
- i++;
- if (i == n) break;
- }
- else
- {
- i = 0; // reset.
- }
- ch = ReadChar();
- }
- }
-
- internal Decoder SniffEncoding()
- {
- Decoder decoder = null;
- if (SniffPattern("");
- }
- }
- if (decoder == null)
- {
- return SniffMeta();
- }
- return null;
- }
-
- internal Decoder SniffMeta()
- {
- int i = ReadChar();
- while (i != EOF)
- {
- char ch = (char)i;
- if (ch == '<')
- {
- string name = SniffName();
- if (name != null && StringUtilities.EqualsIgnoreCase(name, "meta"))
- {
- string httpequiv = null;
- string content = null;
- while (true)
- {
- string value = SniffAttribute(out name);
- if (name == null)
- break;
-
- if (StringUtilities.EqualsIgnoreCase(name, "http-equiv"))
- {
- httpequiv = value;
- }
- else if (StringUtilities.EqualsIgnoreCase(name, "content"))
- {
- content = value;
- }
- }
-
- if (httpequiv != null && StringUtilities.EqualsIgnoreCase(httpequiv, "content-type") && content != null)
- {
- int j = content.IndexOf("charset");
- if (j >= 0)
- {
- //charset=utf-8
- j = content.IndexOf("=", j);
- if (j >= 0)
+ string msg;
+ if (p.m_isInternal)
{
- j++;
- int k = content.IndexOf(";", j);
- if (k < 0) k = content.Length;
- string charset = content.Substring(j, k - j).Trim();
- try
- {
- Encoding e = Encoding.GetEncoding(charset);
- this.m_encoding = e;
- return e.GetDecoder();
- }
- catch (ArgumentException) { }
+ msg = string.Format(CultureInfo.InvariantCulture, "\nReferenced on line {0}, position {1} of internal entity '{2}'", p.m_line, p.LinePosition, p.m_name);
+ }
+ else {
+ msg = string.Format(CultureInfo.InvariantCulture, "\nReferenced on line {0}, position {1} of '{2}' entity at [{3}]", p.m_line, p.LinePosition, p.m_name, p.ResolvedUri.AbsolutePath);
}
- }
+ sb.Append(msg);
+ p = p.Parent;
}
- }
+
+ return sb.ToString();
}
- i = ReadChar();
- }
- return null;
- }
-
- internal string SniffName()
- {
- int c = PeekChar();
- if (c == EOF)
- return null;
- char ch = (char)c;
- int start = pos;
- while (pos < used - 1 && (char.IsLetterOrDigit(ch) || ch == '-' || ch == '_' || ch == ':'))
- ch = m_buffer[++pos];
-
- if (start == pos)
- return null;
-
- return new string(m_buffer, start, pos - start);
- }
-
- [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Kept for potential future usage.")]
- internal void SkipWhitespace()
- {
- char ch = (char)PeekChar();
- while (pos < used - 1 && (ch == ' ' || ch == '\r' || ch == '\n'))
- ch = m_buffer[++pos];
- }
-
- [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Kept for potential future usage.")]
- internal void SkipTo(char what)
- {
- char ch = (char)PeekChar();
- while (pos < used - 1 && (ch != what))
- ch = m_buffer[++pos];
- }
-
- [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Kept for potential future usage.")]
- internal string ParseAttribute()
- {
- SkipTo('=');
- if (pos < used)
- {
- pos++;
- SkipWhitespace();
- if (pos < used)
+ ///
+ /// Checks whether a token denotes a literal entity or not.
+ ///
+ /// The token to check.
+ /// true if the token is "CDATA", "SDATA" or "PI", otherwise false.
+ public static bool IsLiteralType(string token)
{
- char quote = m_buffer[pos];
- pos++;
- int start = pos;
- SkipTo(quote);
- if (pos < used)
- {
- string result = new string(m_buffer, start, pos - start);
- pos++;
+ return string.Equals(token, "CDATA", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(token, "SDATA", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(token, "PI", StringComparison.OrdinalIgnoreCase);
+ }
+
+ ///
+ /// Sets the entity to be a literal of the type specified.
+ ///
+ /// One of "CDATA", "SDATA" or "PI".
+ public void SetLiteralType(string token)
+ {
+ switch (token)
+ {
+ case "CDATA":
+ this.m_literalType = LiteralType.CDATA;
+ break;
+ case "SDATA":
+ this.m_literalType = LiteralType.SDATA;
+ break;
+ case "PI":
+ this.m_literalType = LiteralType.PI;
+ break;
+ }
+ }
+
+ #region IDisposable Members
+
+ ///
+ /// The finalizer for the Entity class.
+ ///
+ ~Entity()
+ {
+ Dispose(false);
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ ///
+ /// true if this method has been called by user code, false if it has been called through a finalizer.
+ protected virtual void Dispose(bool isDisposing)
+ {
+ if (isDisposing)
+ {
+ if (m_stm != null)
+ {
+ m_stm.Dispose();
+ m_stm = null;
+ }
+ }
+ }
+
+ #endregion
+ }
+
+ // This class decodes an HTML/XML stream correctly.
+ internal class HtmlStream : TextReader
+ {
+ private Stream stm;
+ private byte[] rawBuffer;
+ private int rawPos;
+ private int rawUsed;
+ private Encoding m_encoding;
+ private Decoder m_decoder;
+ private char[] m_buffer;
+ private int used;
+ private int pos;
+ private const int BUFSIZE = 16384;
+ private const int EOF = -1;
+
+ public HtmlStream(Stream stm, Encoding defaultEncoding)
+ {
+ if (defaultEncoding == null) defaultEncoding = Encoding.UTF8; // default is UTF8
+ if (!stm.CanSeek){
+ // Need to be able to seek to sniff correctly.
+ stm = CopyToMemoryStream(stm);
+ }
+ this.stm = stm;
+ rawBuffer = new Byte[BUFSIZE];
+ rawUsed = stm.Read(rawBuffer, 0, 4); // maximum byte order mark
+ this.m_buffer = new char[BUFSIZE];
+
+ // Check byte order marks
+ this.m_decoder = AutoDetectEncoding(rawBuffer, ref rawPos, rawUsed);
+ int bom = rawPos;
+ if (this.m_decoder == null)
+ {
+ this.m_decoder = defaultEncoding.GetDecoder();
+ rawUsed += stm.Read(rawBuffer, 4, BUFSIZE-4);
+ DecodeBlock();
+ // Now sniff to see if there is an XML declaration or HTML tag.
+ Decoder sd = SniffEncoding();
+ if (sd != null) {
+ this.m_decoder = sd;
+ }
+ }
+
+ // Reset to get ready for Read()
+ this.stm.Seek(0, SeekOrigin.Begin);
+ this.pos = this.used = 0;
+ // skip bom
+ if (bom>0){
+ stm.Read(this.rawBuffer, 0, bom);
+ }
+ this.rawPos = this.rawUsed = 0;
+
+ }
+
+ public Encoding Encoding
+ {
+ get
+ {
+ return this.m_encoding;
+ }
+ }
+
+ private static Stream CopyToMemoryStream(Stream s)
+ {
+ int size = 100000; // large heap is more efficient
+ byte[] copyBuff = new byte[size];
+ int len;
+ MemoryStream r = new MemoryStream();
+ while ((len = s.Read(copyBuff, 0, size)) > 0)
+ r.Write(copyBuff, 0, len);
+
+ r.Seek(0, SeekOrigin.Begin);
+ s.Dispose();
+ return r;
+ }
+
+ internal void DecodeBlock() {
+ // shift current chars to beginning.
+ if (pos > 0) {
+ if (pos < used) {
+ System.Array.Copy(m_buffer, pos, m_buffer, 0, used - pos);
+ }
+ used -= pos;
+ pos = 0;
+ }
+ int len = m_decoder.GetCharCount(rawBuffer, rawPos, rawUsed - rawPos);
+ int available = m_buffer.Length - used;
+ if (available < len) {
+ char[] newbuf = new char[m_buffer.Length + len];
+ System.Array.Copy(m_buffer, pos, newbuf, 0, used - pos);
+ m_buffer = newbuf;
+ }
+ used = pos + m_decoder.GetChars(rawBuffer, rawPos, rawUsed - rawPos, m_buffer, pos);
+ rawPos = rawUsed; // consumed the whole buffer!
+ }
+ internal static Decoder AutoDetectEncoding(byte[] buffer, ref int index, int length) {
+ if (4 <= (length - index)) {
+ uint w = (uint)buffer[index + 0] << 24 | (uint)buffer[index + 1] << 16 | (uint)buffer[index + 2] << 8 | (uint)buffer[index + 3];
+ // see if it's a 4-byte encoding
+ switch (w) {
+ case 0xfefffeff:
+ index += 4;
+ return new Ucs4DecoderBigEngian();
+
+ case 0xfffefffe:
+ index += 4;
+ return new Ucs4DecoderLittleEndian();
+
+ case 0x3c000000:
+ goto case 0xfefffeff;
+
+ case 0x0000003c:
+ goto case 0xfffefffe;
+ }
+ w >>= 8;
+ if (w == 0xefbbbf) {
+ index += 3;
+ return Encoding.UTF8.GetDecoder();
+ }
+ w >>= 8;
+ switch (w) {
+ case 0xfeff:
+ index += 2;
+ return UnicodeEncoding.BigEndianUnicode.GetDecoder();
+
+ case 0xfffe:
+ index += 2;
+ return new UnicodeEncoding(false, false).GetDecoder();
+
+ case 0x3c00:
+ goto case 0xfeff;
+
+ case 0x003c:
+ goto case 0xfffe;
+ }
+ }
+ return null;
+ }
+ private int ReadChar() {
+ // Read only up to end of current buffer then stop.
+ if (pos < used) return m_buffer[pos++];
+ return EOF;
+ }
+ private int PeekChar() {
+ int ch = ReadChar();
+ if (ch != EOF) {
+ pos--;
+ }
+ return ch;
+ }
+ private bool SniffPattern(string pattern) {
+ int ch = PeekChar();
+ if (ch != pattern[0]) return false;
+ for (int i = 0, n = pattern.Length; ch != EOF && i < n; i++) {
+ ch = ReadChar();
+ char m = pattern[i];
+ if (ch != m) {
+ return false;
+ }
+ }
+ return true;
+ }
+ private void SniffWhitespace() {
+ char ch = (char)PeekChar();
+ while (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
+ int i = pos;
+ ch = (char)ReadChar();
+ if (ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n')
+ pos = i;
+ }
+ }
+
+ private string SniffLiteral() {
+ int quoteChar = PeekChar();
+ if (quoteChar == '\'' || quoteChar == '"') {
+ ReadChar();// consume quote char
+ int i = this.pos;
+ int ch = ReadChar();
+ while (ch != EOF && ch != quoteChar) {
+ ch = ReadChar();
+ }
+ return (pos>i) ? new string(m_buffer, i, pos - i - 1) : "";
+ }
+ return null;
+ }
+ private string SniffAttribute(string name) {
+ SniffWhitespace();
+ string id = SniffName();
+ if (string.Equals(name, id, StringComparison.OrdinalIgnoreCase)) {
+ SniffWhitespace();
+ if (SniffPattern("=")) {
+ SniffWhitespace();
+ return SniffLiteral();
+ }
+ }
+ return null;
+ }
+ private string SniffAttribute(out string name) {
+ SniffWhitespace();
+ name = SniffName();
+ if (name != null){
+ SniffWhitespace();
+ if (SniffPattern("=")) {
+ SniffWhitespace();
+ return SniffLiteral();
+ }
+ }
+ return null;
+ }
+ private void SniffTerminator(string term) {
+ int ch = ReadChar();
+ int i = 0;
+ int n = term.Length;
+ while (i < n && ch != EOF) {
+ if (term[i] == ch) {
+ i++;
+ if (i == n) break;
+ } else {
+ i = 0; // reset.
+ }
+ ch = ReadChar();
+ }
+ }
+
+ internal Decoder SniffEncoding()
+ {
+ Decoder decoder = null;
+ if (SniffPattern("");
+ }
+ }
+ if (decoder == null) {
+ return SniffMeta();
+ }
+ return null;
+ }
+
+ internal Decoder SniffMeta()
+ {
+ int i = ReadChar();
+ while (i != EOF)
+ {
+ char ch = (char)i;
+ if (ch == '<')
+ {
+ string name = SniffName();
+ if (name != null && StringUtilities.EqualsIgnoreCase(name, "meta"))
+ {
+ string httpequiv = null;
+ string content = null;
+ while (true)
+ {
+ string value = SniffAttribute(out name);
+ if (name == null)
+ break;
+
+ if (StringUtilities.EqualsIgnoreCase(name, "http-equiv"))
+ {
+ httpequiv = value;
+ }
+ else if (StringUtilities.EqualsIgnoreCase(name, "content"))
+ {
+ content = value;
+ }
+ }
+
+ if (httpequiv != null && StringUtilities.EqualsIgnoreCase(httpequiv, "content-type") && content != null)
+ {
+ int j = content.IndexOf("charset");
+ if (j >= 0)
+ {
+ //charset=utf-8
+ j = content.IndexOf("=", j);
+ if (j >= 0)
+ {
+ j++;
+ int k = content.IndexOf(";", j);
+ if (k<0) k = content.Length;
+ string charset = content.Substring(j, k-j).Trim();
+ try
+ {
+ Encoding e = Encoding.GetEncoding(charset);
+ this.m_encoding = e;
+ return e.GetDecoder();
+ } catch (ArgumentException) {}
+ }
+ }
+ }
+ }
+ }
+ i = ReadChar();
+
+ }
+ return null;
+ }
+
+ internal string SniffName()
+ {
+ int c = PeekChar();
+ if (c == EOF)
+ return null;
+ char ch = (char)c;
+ int start = pos;
+ while (pos < used - 1 && (char.IsLetterOrDigit(ch) || ch == '-' || ch == '_' || ch == ':'))
+ ch = m_buffer[++pos];
+
+ if (start == pos)
+ return null;
+
+ return new string(m_buffer, start, pos - start);
+ }
+
+ [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Kept for potential future usage.")]
+ internal void SkipWhitespace()
+ {
+ char ch = (char)PeekChar();
+ while (pos < used - 1 && (ch == ' ' || ch == '\r' || ch == '\n'))
+ ch = m_buffer[++pos];
+ }
+
+ [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Kept for potential future usage.")]
+ internal void SkipTo(char what)
+ {
+ char ch = (char)PeekChar();
+ while (pos < used - 1 && (ch != what))
+ ch = m_buffer[++pos];
+ }
+
+ [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Kept for potential future usage.")]
+ internal string ParseAttribute()
+ {
+ SkipTo('=');
+ if (pos < used)
+ {
+ pos++;
+ SkipWhitespace();
+ if (pos < used) {
+ char quote = m_buffer[pos];
+ pos++;
+ int start = pos;
+ SkipTo(quote);
+ if (pos < used) {
+ string result = new string(m_buffer, start, pos - start);
+ pos++;
+ return result;
+ }
+ }
+ }
+ return null;
+ }
+ public override int Peek() {
+ int result = Read();
+ if (result != EOF) {
+ pos--;
+ }
return result;
- }
}
- }
- return null;
- }
- public override int Peek()
- {
- int result = Read();
- if (result != EOF)
- {
- pos--;
- }
- return result;
- }
- public override int Read()
- {
- if (pos == used)
- {
- rawUsed = stm.Read(rawBuffer, 0, rawBuffer.Length);
- rawPos = 0;
- if (rawUsed == 0) return EOF;
- DecodeBlock();
- }
- if (pos < used) return m_buffer[pos++];
- return -1;
- }
-
- public override int Read(char[] buffer, int start, int length)
- {
- if (pos == used)
- {
- rawUsed = stm.Read(rawBuffer, 0, rawBuffer.Length);
- rawPos = 0;
- if (rawUsed == 0) return -1;
- DecodeBlock();
- }
- if (pos < used)
- {
- length = Math.Min(used - pos, length);
- Array.Copy(this.m_buffer, pos, buffer, start, length);
- pos += length;
- return length;
- }
- return 0;
- }
-
- public override int ReadBlock(char[] data, int index, int count)
- {
- return Read(data, index, count);
- }
-
- // Read up to end of line, or full buffer, whichever comes first.
- [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Kept for potential future usage.")]
- public int ReadLine(char[] buffer, int start, int length)
- {
- int i = 0;
- int ch = ReadChar();
- while (ch != EOF)
- {
- buffer[i + start] = (char)ch;
- i++;
- if (i + start == length)
- break; // buffer is full
-
- if (ch == '\r')
+ public override int Read()
{
- if (PeekChar() == '\n')
- {
- ch = ReadChar();
- buffer[i + start] = (char)ch;
- i++;
- }
- break;
+ if (pos == used)
+ {
+ rawUsed = stm.Read(rawBuffer, 0, rawBuffer.Length);
+ rawPos = 0;
+ if (rawUsed == 0) return EOF;
+ DecodeBlock();
+ }
+ if (pos < used) return m_buffer[pos++];
+ return -1;
}
- else if (ch == '\n')
+
+ public override int Read(char[] buffer, int start, int length) {
+ if (pos == used) {
+ rawUsed = stm.Read(rawBuffer, 0, rawBuffer.Length);
+ rawPos = 0;
+ if (rawUsed == 0) return -1;
+ DecodeBlock();
+ }
+ if (pos < used) {
+ length = Math.Min(used - pos, length);
+ Array.Copy(this.m_buffer, pos, buffer, start, length);
+ pos += length;
+ return length;
+ }
+ return 0;
+ }
+
+ public override int ReadBlock(char[] data, int index, int count)
{
- break;
+ return Read(data, index, count);
+ }
+
+ // Read up to end of line, or full buffer, whichever comes first.
+ [SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Kept for potential future usage.")]
+ public int ReadLine(char[] buffer, int start, int length)
+ {
+ int i = 0;
+ int ch = ReadChar();
+ while (ch != EOF) {
+ buffer[i+start] = (char)ch;
+ i++;
+ if (i+start == length)
+ break; // buffer is full
+
+ if (ch == '\r' ) {
+ if (PeekChar() == '\n') {
+ ch = ReadChar();
+ buffer[i + start] = (char)ch;
+ i++;
+ }
+ break;
+ } else if (ch == '\n') {
+ break;
+ }
+ ch = ReadChar();
+ }
+ return i;
+ }
+
+ public override string ReadToEnd() {
+ char[] buffer = new char[100000]; // large block heap is more efficient
+ int len = 0;
+ StringBuilder sb = new StringBuilder();
+ while ((len = Read(buffer, 0, buffer.Length)) > 0) {
+ sb.Append(buffer, 0, len);
+ }
+ return sb.ToString();
+ }
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ if (disposing)
+ {
+ stm.Dispose();
+ }
}
- ch = ReadChar();
- }
- return i;
}
- public override string ReadToEnd()
- {
- char[] buffer = new char[100000]; // large block heap is more efficient
- int len = 0;
- StringBuilder sb = new StringBuilder();
- while ((len = Read(buffer, 0, buffer.Length)) > 0)
- {
- sb.Append(buffer, 0, len);
- }
- return sb.ToString();
+ internal abstract class Ucs4Decoder : Decoder {
+ internal byte[] temp = new byte[4];
+ internal int tempBytes = 0;
+ public override int GetCharCount(byte[] bytes, int index, int count) {
+ return (count + tempBytes) / 4;
+ }
+ internal abstract int GetFullChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex);
+ public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) {
+ int i = tempBytes;
+
+ if (tempBytes > 0) {
+ for (; i < 4; i++) {
+ temp[i] = bytes[byteIndex];
+ byteIndex++;
+ byteCount--;
+ }
+ i = 1;
+ GetFullChars(temp, 0, 4, chars, charIndex);
+ charIndex++;
+ } else
+ i = 0;
+ i = GetFullChars(bytes, byteIndex, byteCount, chars, charIndex) + i;
+
+ int j = (tempBytes + byteCount) % 4;
+ byteCount += byteIndex;
+ byteIndex = byteCount - j;
+ tempBytes = 0;
+
+ if (byteIndex >= 0)
+ for (; byteIndex < byteCount; byteIndex++) {
+ temp[tempBytes] = bytes[byteIndex];
+ tempBytes++;
+ }
+ return i;
+ }
+ internal static char UnicodeToUTF16(UInt32 code) {
+ byte lowerByte, higherByte;
+ lowerByte = (byte)(0xD7C0 + (code >> 10));
+ higherByte = (byte)(0xDC00 | code & 0x3ff);
+ return ((char)((higherByte << 8) | lowerByte));
+ }
}
- protected override void Dispose(bool disposing)
- {
- base.Dispose(disposing);
- if (disposing)
- {
- stm.Dispose();
- }
+
+ internal class Ucs4DecoderBigEngian : Ucs4Decoder {
+ internal override int GetFullChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) {
+ UInt32 code;
+ int i, j;
+ byteCount += byteIndex;
+ for (i = byteIndex, j = charIndex; i + 3 < byteCount; ) {
+ code = (UInt32)(((bytes[i + 3]) << 24) | (bytes[i + 2] << 16) | (bytes[i + 1] << 8) | (bytes[i]));
+ if (code > 0x10FFFF) {
+ throw new SgmlParseException(string.Format(CultureInfo.CurrentUICulture, "Invalid character 0x{0:x} in encoding", code));
+ } else if (code > 0xFFFF) {
+ chars[j] = UnicodeToUTF16(code);
+ j++;
+ } else {
+ if (code >= 0xD800 && code <= 0xDFFF) {
+ throw new SgmlParseException(string.Format(CultureInfo.CurrentUICulture, "Invalid character 0x{0:x} in encoding", code));
+ } else {
+ chars[j] = (char)code;
+ }
+ }
+ j++;
+ i += 4;
+ }
+ return j - charIndex;
+ }
}
- }
- internal abstract class Ucs4Decoder : Decoder
- {
- internal byte[] temp = new byte[4];
- internal int tempBytes = 0;
- public override int GetCharCount(byte[] bytes, int index, int count)
- {
- return (count + tempBytes) / 4;
- }
- internal abstract int GetFullChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex);
- public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
- {
- int i = tempBytes;
-
- if (tempBytes > 0)
- {
- for (; i < 4; i++)
- {
- temp[i] = bytes[byteIndex];
- byteIndex++;
- byteCount--;
+ internal class Ucs4DecoderLittleEndian : Ucs4Decoder {
+ internal override int GetFullChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) {
+ UInt32 code;
+ int i, j;
+ byteCount += byteIndex;
+ for (i = byteIndex, j = charIndex; i + 3 < byteCount; ) {
+ code = (UInt32)(((bytes[i]) << 24) | (bytes[i + 1] << 16) | (bytes[i + 2] << 8) | (bytes[i + 3]));
+ if (code > 0x10FFFF) {
+ throw new SgmlParseException(string.Format(CultureInfo.CurrentUICulture, "Invalid character 0x{0:x} in encoding", code));
+ } else if (code > 0xFFFF) {
+ chars[j] = UnicodeToUTF16(code);
+ j++;
+ } else {
+ if (code >= 0xD800 && code <= 0xDFFF) {
+ throw new SgmlParseException(string.Format(CultureInfo.CurrentUICulture, "Invalid character 0x{0:x} in encoding", code));
+ } else {
+ chars[j] = (char)code;
+ }
+ }
+ j++;
+ i += 4;
+ }
+ return j - charIndex;
}
- i = 1;
- GetFullChars(temp, 0, 4, chars, charIndex);
- charIndex++;
- }
- else
- i = 0;
- i = GetFullChars(bytes, byteIndex, byteCount, chars, charIndex) + i;
-
- int j = (tempBytes + byteCount) % 4;
- byteCount += byteIndex;
- byteIndex = byteCount - j;
- tempBytes = 0;
-
- if (byteIndex >= 0)
- for (; byteIndex < byteCount; byteIndex++)
- {
- temp[tempBytes] = bytes[byteIndex];
- tempBytes++;
- }
- return i;
- }
- internal static char UnicodeToUTF16(UInt32 code)
- {
- byte lowerByte, higherByte;
- lowerByte = (byte)(0xD7C0 + (code >> 10));
- higherByte = (byte)(0xDC00 | code & 0x3ff);
- return ((char)((higherByte << 8) | lowerByte));
- }
- }
-
- internal class Ucs4DecoderBigEngian : Ucs4Decoder
- {
- internal override int GetFullChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
- {
- UInt32 code;
- int i, j;
- byteCount += byteIndex;
- for (i = byteIndex, j = charIndex; i + 3 < byteCount; )
- {
- code = (UInt32)(((bytes[i + 3]) << 24) | (bytes[i + 2] << 16) | (bytes[i + 1] << 8) | (bytes[i]));
- if (code > 0x10FFFF)
- {
- throw new SgmlParseException(string.Format(CultureInfo.CurrentUICulture, "Invalid character 0x{0:x} in encoding", code));
- }
- else if (code > 0xFFFF)
- {
- chars[j] = UnicodeToUTF16(code);
- j++;
- }
- else
- {
- if (code >= 0xD800 && code <= 0xDFFF)
- {
- throw new SgmlParseException(string.Format(CultureInfo.CurrentUICulture, "Invalid character 0x{0:x} in encoding", code));
- }
- else
- {
- chars[j] = (char)code;
- }
- }
- j++;
- i += 4;
- }
- return j - charIndex;
- }
- }
-
- internal class Ucs4DecoderLittleEndian : Ucs4Decoder
- {
- internal override int GetFullChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
- {
- UInt32 code;
- int i, j;
- byteCount += byteIndex;
- for (i = byteIndex, j = charIndex; i + 3 < byteCount; )
- {
- code = (UInt32)(((bytes[i]) << 24) | (bytes[i + 1] << 16) | (bytes[i + 2] << 8) | (bytes[i + 3]));
- if (code > 0x10FFFF)
- {
- throw new SgmlParseException(string.Format(CultureInfo.CurrentUICulture, "Invalid character 0x{0:x} in encoding", code));
- }
- else if (code > 0xFFFF)
- {
- chars[j] = UnicodeToUTF16(code);
- j++;
- }
- else
- {
- if (code >= 0xD800 && code <= 0xDFFF)
- {
- throw new SgmlParseException(string.Format(CultureInfo.CurrentUICulture, "Invalid character 0x{0:x} in encoding", code));
- }
- else
- {
- chars[j] = (char)code;
- }
- }
- j++;
- i += 4;
- }
- return j - charIndex;
- }
- }
-
- ///
- /// An element declaration in a DTD.
- ///
- public class ElementDecl
- {
- private string m_name;
- private bool m_startTagOptional;
- private bool m_endTagOptional;
- private ContentModel m_contentModel;
- private string[] m_inclusions;
- private string[] m_exclusions;
- private Dictionary m_attList;
-
- ///
- /// Initialises a new element declaration instance.
- ///
- /// The name of the element.
- /// Whether the start tag is optional.
- /// Whether the end tag is optional.
- /// The of the element.
- ///
- ///
- public ElementDecl(string name, bool sto, bool eto, ContentModel cm, string[] inclusions, string[] exclusions)
- {
- m_name = name;
- m_startTagOptional = sto;
- m_endTagOptional = eto;
- m_contentModel = cm;
- m_inclusions = inclusions;
- m_exclusions = exclusions;
}
///
- /// The element name.
+ /// An element declaration in a DTD.
///
- public string Name
+ public class ElementDecl
{
- get
- {
- return m_name;
- }
- }
+ private string m_name;
+ private bool m_startTagOptional;
+ private bool m_endTagOptional;
+ private ContentModel m_contentModel;
+ private string[] m_inclusions;
+ private string[] m_exclusions;
+ private Dictionary m_attList;
- ///
- /// The of the element declaration.
- ///
- public ContentModel ContentModel
- {
- get
- {
- return m_contentModel;
- }
- }
-
- ///
- /// Whether the end tag of the element is optional.
- ///
- /// true if the end tag of the element is optional, otherwise false.
- public bool EndTagOptional
- {
- get
- {
- return m_endTagOptional;
- }
- }
-
- ///
- /// Whether the start tag of the element is optional.
- ///
- /// true if the start tag of the element is optional, otherwise false.
- public bool StartTagOptional
- {
- get
- {
- return m_startTagOptional;
- }
- }
-
- ///
- /// Finds the attribute definition with the specified name.
- ///
- /// The name of the to find.
- /// The with the specified name.
- /// If the attribute list has not yet been initialised.
- public AttDef FindAttribute(string name)
- {
- if (m_attList == null)
- throw new InvalidOperationException("The attribute list for the element declaration has not been initialised.");
-
- AttDef a;
- m_attList.TryGetValue(name.ToUpperInvariant(), out a);
- return a;
- }
-
- ///
- /// Adds attribute definitions to the element declaration.
- ///
- /// The list of attribute definitions to add.
- public void AddAttDefs(Dictionary list)
- {
- if (list == null)
- throw new ArgumentNullException("list");
-
- if (m_attList == null)
- {
- m_attList = list;
- }
- else
- {
- foreach (AttDef a in list.Values)
+ ///
+ /// Initialises a new element declaration instance.
+ ///
+ /// The name of the element.
+ /// Whether the start tag is optional.
+ /// Whether the end tag is optional.
+ /// The of the element.
+ ///
+ ///
+ public ElementDecl(string name, bool sto, bool eto, ContentModel cm, string[] inclusions, string[] exclusions)
{
- if (!m_attList.ContainsKey(a.Name))
- {
- m_attList.Add(a.Name, a);
- }
+ m_name = name;
+ m_startTagOptional = sto;
+ m_endTagOptional = eto;
+ m_contentModel = cm;
+ m_inclusions = inclusions;
+ m_exclusions = exclusions;
+ }
+
+ ///
+ /// The element name.
+ ///
+ public string Name
+ {
+ get
+ {
+ return m_name;
+ }
+ }
+
+ ///
+ /// The of the element declaration.
+ ///
+ public ContentModel ContentModel
+ {
+ get
+ {
+ return m_contentModel;
+ }
+ }
+
+ ///
+ /// Whether the end tag of the element is optional.
+ ///
+ /// true if the end tag of the element is optional, otherwise false.
+ public bool EndTagOptional
+ {
+ get
+ {
+ return m_endTagOptional;
+ }
+ }
+
+ ///
+ /// Whether the start tag of the element is optional.
+ ///
+ /// true if the start tag of the element is optional, otherwise false.
+ public bool StartTagOptional
+ {
+ get
+ {
+ return m_startTagOptional;
+ }
+ }
+
+ ///
+ /// Finds the attribute definition with the specified name.
+ ///
+ /// The name of the to find.
+ /// The with the specified name.
+ /// If the attribute list has not yet been initialised.
+ public AttDef FindAttribute(string name)
+ {
+ if (m_attList == null)
+ throw new InvalidOperationException("The attribute list for the element declaration has not been initialised.");
+
+ AttDef a;
+ m_attList.TryGetValue(name.ToUpperInvariant(), out a);
+ return a;
+ }
+
+ ///
+ /// Adds attribute definitions to the element declaration.
+ ///
+ /// The list of attribute definitions to add.
+ public void AddAttDefs(Dictionary list)
+ {
+ if (list == null)
+ throw new ArgumentNullException("list");
+
+ if (m_attList == null)
+ {
+ m_attList = list;
+ }
+ else
+ {
+ foreach (AttDef a in list.Values)
+ {
+ if (!m_attList.ContainsKey(a.Name))
+ {
+ m_attList.Add(a.Name, a);
+ }
+ }
+ }
+ }
+
+ ///
+ /// Tests whether this element can contain another specified element.
+ ///
+ /// The name of the element to check for.
+ /// The DTD to use to do the check.
+ /// True if the specified element can be contained by this element.
+ public bool CanContain(string name, SgmlDtd dtd)
+ {
+ // return true if this element is allowed to contain the given element.
+ if (m_exclusions != null)
+ {
+ foreach (string s in m_exclusions)
+ {
+ if (string.Equals(s, name, StringComparison.OrdinalIgnoreCase))
+ return false;
+ }
+ }
+
+ if (m_inclusions != null)
+ {
+ foreach (string s in m_inclusions)
+ {
+ if (string.Equals(s, name, StringComparison.OrdinalIgnoreCase))
+ return true;
+ }
+ }
+ return m_contentModel.CanContain(name, dtd);
}
- }
}
///
- /// Tests whether this element can contain another specified element.
+ /// Where nested subelements cannot occur within an element, its contents can be declared to consist of one of the types of declared content contained in this enumeration.
///
- /// The name of the element to check for.
- /// The DTD to use to do the check.
- /// True if the specified element can be contained by this element.
- public bool CanContain(string name, SgmlDtd dtd)
+ public enum DeclaredContent
{
- // return true if this element is allowed to contain the given element.
- if (m_exclusions != null)
- {
- foreach (string s in m_exclusions)
+ ///
+ /// Not defined.
+ ///
+ Default,
+
+ ///
+ /// Character data (CDATA), which contains only valid SGML characters.
+ ///
+ [SuppressMessage("Microsoft.Naming", "CA1705", Justification = "This capitalisation is appropriate since the value it represents has all upper-case capitalisation.")]
+ CDATA,
+
+ ///
+ /// Replaceable character data (RCDATA), which can contain text, character references and/or general entity references that resolve to character data.
+ ///
+ [SuppressMessage("Microsoft.Naming", "CA1705", Justification = "This capitalisation is appropriate since the value it represents has all upper-case capitalisation.")]
+ RCDATA,
+
+ ///
+ /// Empty element (EMPTY), i.e. having no contents, or contents that can be generated by the program.
+ ///
+ [SuppressMessage("Microsoft.Naming", "CA1705", Justification = "This capitalisation is appropriate since the value it represents has all upper-case capitalisation.")]
+ EMPTY
+ }
+
+ ///
+ /// Defines the content model for an element.
+ ///
+ public class ContentModel
+ {
+ private DeclaredContent m_declaredContent;
+ private int m_currentDepth;
+ private Group m_model;
+
+ ///
+ /// Initialises a new instance of the class.
+ ///
+ public ContentModel()
{
- if (string.Equals(s, name, StringComparison.OrdinalIgnoreCase))
+ m_model = new Group(null);
+ }
+
+ ///
+ /// The number of groups on the stack.
+ ///
+ public int CurrentDepth
+ {
+ get
+ {
+ return m_currentDepth;
+ }
+ }
+
+ ///
+ /// The allowed child content, specifying if nested children are not allowed and if so, what content is allowed.
+ ///
+ public DeclaredContent DeclaredContent
+ {
+ get
+ {
+ return m_declaredContent;
+ }
+ }
+
+ ///
+ /// Begins processing of a nested model group.
+ ///
+ public void PushGroup()
+ {
+ m_model = new Group(m_model);
+ m_currentDepth++;
+ }
+
+ ///
+ /// Finishes processing of a nested model group.
+ ///
+ /// The current depth of the group nesting, or -1 if there are no more groups to pop.
+ public int PopGroup()
+ {
+ if (m_currentDepth == 0)
+ return -1;
+
+ m_currentDepth--;
+ m_model.Parent.AddGroup(m_model);
+ m_model = m_model.Parent;
+ return m_currentDepth;
+ }
+
+ ///
+ /// Adds a new symbol to the current group's members.
+ ///
+ /// The symbol to add.
+ public void AddSymbol(string sym)
+ {
+ m_model.AddSymbol(sym);
+ }
+
+ ///
+ /// Adds a connector onto the member list for the current group.
+ ///
+ /// The connector character to add.
+ ///
+ /// If the content is not mixed and has no members yet, or if the group type has been set and the
+ /// connector does not match the group type.
+ ///
+ public void AddConnector(char c)
+ {
+ m_model.AddConnector(c);
+ }
+
+ ///
+ /// Adds an occurrence character for the current model group, setting it's value.
+ ///
+ /// The occurrence character.
+ public void AddOccurrence(char c)
+ {
+ m_model.AddOccurrence(c);
+ }
+
+ ///
+ /// Sets the contained content for the content model.
+ ///
+ /// The text specified the permissible declared child content.
+ public void SetDeclaredContent(string dc)
+ {
+ // TODO: Validate that this can never combine with nexted groups?
+ switch (dc)
+ {
+ case "EMPTY":
+ this.m_declaredContent = DeclaredContent.EMPTY;
+ break;
+ case "RCDATA":
+ this.m_declaredContent = DeclaredContent.RCDATA;
+ break;
+ case "CDATA":
+ this.m_declaredContent = DeclaredContent.CDATA;
+ break;
+ default:
+ throw new SgmlParseException(string.Format(CultureInfo.CurrentUICulture, "Declared content type '{0}' is not supported", dc));
+ }
+ }
+
+ ///
+ /// Checks whether an element using this group can contain a specified element.
+ ///
+ /// The name of the element to look for.
+ /// The DTD to use during the checking.
+ /// true if an element using this group can contain the element, otherwise false.
+ public bool CanContain(string name, SgmlDtd dtd)
+ {
+ if (m_declaredContent != DeclaredContent.Default)
+ return false; // empty or text only node.
+
+ return m_model.CanContain(name, dtd);
+ }
+ }
+
+ ///
+ /// The type of the content model group, defining the order in which child elements can occur.
+ ///
+ public enum GroupType
+ {
+ ///
+ /// No model group.
+ ///
+ None,
+
+ ///
+ /// All elements must occur, in any order.
+ ///
+ And,
+
+ ///
+ /// One (and only one) must occur.
+ ///
+ Or,
+
+ ///
+ /// All element must occur, in the specified order.
+ ///
+ Sequence
+ };
+
+ ///
+ /// Qualifies the occurrence of a child element within a content model group.
+ ///
+ public enum Occurrence
+ {
+ ///
+ /// The element is required and must occur only once.
+ ///
+ Required,
+
+ ///
+ /// The element is optional and must occur once at most.
+ ///
+ Optional,
+
+ ///
+ /// The element is optional and can be repeated.
+ ///
+ ZeroOrMore,
+
+ ///
+ /// The element must occur at least once or more times.
+ ///
+ OneOrMore
+ }
+
+ ///
+ /// Defines a group of elements nested within another element.
+ ///
+ public class Group
+ {
+ private Group m_parent;
+ private List