blob: da489db61f8e23dacdca30210b569a64f3447034 [file] [log] [blame]
/***************************************************************************
Copyright (c) Microsoft Corporation 2012-2015.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
Published at http://OpenXmlDeveloper.org
Resource Center and Documentation: http://openxmldeveloper.org/wiki/w/wiki/powertools-for-open-xml.aspx
***************************************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
namespace OpenXmlPowerTools.HtmlToWml.CSS
{
public class CssAttribute
{
private string m_operand;
private CssAttributeOperator? m_op = null;
private string m_val;
public string Operand
{
get {
return m_operand;
}
set {
m_operand = value;
}
}
public CssAttributeOperator? Operator
{
get {
return m_op;
}
set {
m_op = value;
}
}
public string CssOperatorString
{
get {
if (this.m_op.HasValue)
{
return this.m_op.Value.ToString();
}
else
{
return null;
}
}
set {
this.m_op = (CssAttributeOperator)Enum.Parse(typeof(CssAttributeOperator), value);
}
}
public string Value
{
get {
return m_val;
}
set {
m_val = value;
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("[{0}", m_operand);
if (m_op.HasValue)
{
switch (m_op.Value)
{
case CssAttributeOperator.Equals:
sb.Append("=");
break;
case CssAttributeOperator.InList:
sb.Append("~=");
break;
case CssAttributeOperator.Hyphenated:
sb.Append("|=");
break;
case CssAttributeOperator.BeginsWith:
sb.Append("$=");
break;
case CssAttributeOperator.EndsWith:
sb.Append("^=");
break;
case CssAttributeOperator.Contains:
sb.Append("*=");
break;
}
sb.Append(m_val);
}
sb.Append("]");
return sb.ToString();
}
}
public enum CssAttributeOperator
{
Equals,
InList,
Hyphenated,
EndsWith,
BeginsWith,
Contains,
}
public enum CssCombinator
{
ChildOf,
PrecededImmediatelyBy,
PrecededBy,
}
public class CssDocument : ItfRuleSetContainer
{
private List<CssDirective> m_dirs = new List<CssDirective>();
private List<CssRuleSet> m_rulesets = new List<CssRuleSet>();
public List<CssDirective> Directives
{
get {
return m_dirs;
}
set {
m_dirs = value;
}
}
public List<CssRuleSet> RuleSets
{
get {
return m_rulesets;
}
set {
m_rulesets = value;
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
foreach (CssDirective cssDir in m_dirs)
{
sb.AppendFormat("{0}" + Environment.NewLine, cssDir.ToString());
}
if (sb.Length > 0)
{
sb.Append(Environment.NewLine);
}
foreach (CssRuleSet rules in m_rulesets)
{
sb.AppendFormat("{0}" + Environment.NewLine,
rules.ToString());
}
return sb.ToString();
}
}
public class CssDeclaration
{
private string m_name;
private CssExpression m_expression;
private bool m_important;
public string Name
{
get {
return m_name;
}
set {
m_name = value;
}
}
public bool Important
{
get {
return m_important;
}
set {
m_important = value;
}
}
public CssExpression Expression
{
get {
return m_expression;
}
set {
m_expression = value;
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}: {1}{2}",
m_name,
m_expression.ToString(),
m_important ? " !important" : "");
return sb.ToString();
}
}
public class CssDirective : ItfDeclarationContainer, ItfRuleSetContainer
{
private CssDirectiveType m_type;
private string m_name;
private CssExpression m_expression;
private List<CssMedium> m_mediums = new List<CssMedium>();
private List<CssDirective> m_directives = new List<CssDirective>();
private List<CssRuleSet> m_rulesets = new List<CssRuleSet>();
private List<CssDeclaration> m_declarations = new List<CssDeclaration>();
public CssDirectiveType Type
{
get {
return this.m_type;
}
set {
this.m_type = value;
}
}
public string Name
{
get {
return this.m_name;
}
set {
this.m_name = value;
}
}
public CssExpression Expression
{
get {
return this.m_expression;
}
set {
this.m_expression = value;
}
}
public List<CssMedium> Mediums
{
get {
return this.m_mediums;
}
set {
this.m_mediums = value;
}
}
public List<CssDirective> Directives
{
get {
return this.m_directives;
}
set {
this.m_directives = value;
}
}
public List<CssRuleSet> RuleSets
{
get {
return this.m_rulesets;
}
set {
this.m_rulesets = value;
}
}
public List<CssDeclaration> Declarations
{
get {
return this.m_declarations;
}
set {
this.m_declarations = value;
}
}
public override string ToString()
{
return ToString(0);
}
public string ToString(int indentLevel)
{
string start = "".PadRight(indentLevel, '\t');
switch (m_type)
{
case CssDirectiveType.Charset:
return ToCharSetString(start);
case CssDirectiveType.Page:
return ToPageString(start);
case CssDirectiveType.Media:
return ToMediaString(indentLevel);
case CssDirectiveType.Import:
return ToImportString();
case CssDirectiveType.FontFace:
return ToFontFaceString(start);
}
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0} ", m_name);
if (m_expression != null)
{
sb.AppendFormat("{0} ", m_expression);
}
bool first = true;
foreach (CssMedium med in m_mediums)
{
if (first)
{
first = false;
sb.Append(" ");
}
else
{
sb.Append(", ");
}
sb.Append(med.ToString());
}
bool HasBlock = (this.m_declarations.Count > 0 || this.m_directives.Count > 0 || this.m_rulesets.Count > 0);
if (!HasBlock)
{
sb.Append(";");
return sb.ToString();
}
sb.Append(" {" + Environment.NewLine + start);
foreach (CssDirective dir in m_directives)
{
sb.AppendFormat("{0}" + Environment.NewLine, dir.ToCharSetString(start + "\t"));
}
foreach (CssRuleSet rules in m_rulesets)
{
sb.AppendFormat("{0}" + Environment.NewLine, rules.ToString(indentLevel + 1));
}
first = true;
foreach (CssDeclaration decl in m_declarations)
{
if (first)
{
first = false;
}
else
{
sb.Append(";");
}
sb.Append(Environment.NewLine + "\t" + start);
sb.Append(decl.ToString());
}
sb.Append(Environment.NewLine + "}");
return sb.ToString();
}
private string ToFontFaceString(string start)
{
StringBuilder sb = new StringBuilder();
sb.Append("@font-face {");
bool first = true;
foreach (CssDeclaration decl in m_declarations)
{
if (first)
{
first = false;
}
else
{
sb.Append(";");
}
sb.Append(Environment.NewLine + "\t" + start);
sb.Append(decl.ToString());
}
sb.Append(Environment.NewLine + "}");
return sb.ToString();
}
private string ToImportString()
{
StringBuilder sb = new StringBuilder();
sb.Append("@import ");
if (m_expression != null)
{
sb.AppendFormat("{0} ", m_expression);
}
bool first = true;
foreach (CssMedium med in m_mediums)
{
if (first)
{
first = false;
sb.Append(" ");
}
else
{
sb.Append(", ");
}
sb.Append(med.ToString());
}
sb.Append(";");
return sb.ToString();
}
private string ToMediaString(int indentLevel)
{
StringBuilder sb = new StringBuilder();
sb.Append("@media");
bool first = true;
foreach (CssMedium medium in m_mediums)
{
if (first)
{
first = false;
sb.Append(" ");
}
else
{
sb.Append(", ");
}
sb.Append(medium.ToString());
}
sb.Append(" {" + Environment.NewLine);
foreach (CssRuleSet ruleset in m_rulesets)
{
sb.AppendFormat("{0}" + Environment.NewLine, ruleset.ToString(indentLevel + 1));
}
sb.Append("}");
return sb.ToString();
}
private string ToPageString(string start)
{
StringBuilder sb = new StringBuilder();
sb.Append("@page ");
if (m_expression != null)
{
sb.AppendFormat("{0} ", m_expression);
}
sb.Append("{" + Environment.NewLine);
bool first = true;
foreach (CssDeclaration decl in m_declarations)
{
if (first)
{
first = false;
}
else
{
sb.Append(";");
}
sb.Append(Environment.NewLine + "\t" + start);
sb.Append(decl.ToString());
}
sb.Append("}");
return sb.ToString();
}
private string ToCharSetString(string start)
{
return string.Format("{2}{0} {1}",
m_name,
m_expression.ToString(),
start);
}
}
public enum CssDirectiveType
{
Media,
Import,
Charset,
Page,
FontFace,
Namespace,
Other,
}
public class CssExpression
{
private List<CssTerm> m_terms = new List<CssTerm>();
public List<CssTerm> Terms
{
get {
return m_terms;
}
set {
m_terms = value;
}
}
public bool IsNotAuto
{
get
{
return (this != null && this.ToString() != "auto");
}
}
public bool IsAuto
{
get
{
return (this != null && this.ToString() == "auto");
}
}
public bool IsNotNormal
{
get
{
return (this != null && this.ToString() != "normal");
}
}
public bool IsNormal
{
get
{
return (this != null && this.ToString() == "normal");
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
bool first = true;
foreach (CssTerm term in m_terms)
{
if (first)
{
first = false;
}
else
{
sb.AppendFormat("{0} ",
term.Separator.HasValue ? term.Separator.Value.ToString() : "");
}
sb.Append(term.ToString());
}
return sb.ToString();
}
public static implicit operator string(CssExpression e)
{
return e.ToString();
}
public static explicit operator double(CssExpression e)
{
return double.Parse(e.Terms.First().Value, CultureInfo.InvariantCulture);
}
public static explicit operator Emu(CssExpression e)
{
return Emu.PointsToEmus(double.Parse(e.Terms.First().Value, CultureInfo.InvariantCulture));
}
// will only be called on expression that is in terms of points
public static explicit operator TPoint(CssExpression e)
{
return new TPoint(double.Parse(e.Terms.First().Value, CultureInfo.InvariantCulture));
}
// will only be called on expression that is in terms of points
public static explicit operator Twip(CssExpression length)
{
if (length.Terms.Count() == 1)
{
CssTerm term = length.Terms.First();
if (term.Unit == CssUnit.PT)
{
double ptValue;
if (double.TryParse(term.Value.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture, out ptValue))
{
if (term.Sign == '-')
ptValue = -ptValue;
return new Twip((long)(ptValue * 20));
}
}
}
return 0;
}
}
public class CssFunction
{
private string m_name;
private CssExpression m_expression;
public string Name
{
get {
return m_name;
}
set {
m_name = value;
}
}
public CssExpression Expression
{
get {
return m_expression;
}
set {
m_expression = value;
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}(", m_name);
if (m_expression != null)
{
bool first = true;
foreach (CssTerm t in m_expression.Terms)
{
if (first)
{
first = false;
}
else if (!t.Value.EndsWith("="))
{
sb.Append(", ");
}
bool quote = false;
if (t.Type == CssTermType.String && !t.Value.EndsWith("="))
{
quote = true;
}
if (quote)
{
sb.Append("'");
}
sb.Append(t.ToString());
if (quote)
{
sb.Append("'");
}
}
}
sb.Append(")");
return sb.ToString();
}
}
public interface ItfDeclarationContainer
{
List<CssDeclaration> Declarations { get; set; }
}
public interface ItfRuleSetContainer
{
List<CssRuleSet> RuleSets { get; set; }
}
public interface ItfSelectorContainer
{
List<CssSelector> Selectors { get; set; }
}
public enum CssMedium
{
all,
aural,
braille,
embossed,
handheld,
print,
projection,
screen,
tty,
tv
}
public class CssPropertyValue
{
private CssValueType m_type;
private CssUnit m_unit;
private string m_value;
public CssValueType Type
{
get {
return this.m_type;
}
set {
this.m_type = value;
}
}
public CssUnit Unit
{
get {
return this.m_unit;
}
set {
this.m_unit = value;
}
}
public string Value
{
get {
return this.m_value;
}
set {
this.m_value = value;
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder(m_value);
if (m_type == CssValueType.Unit)
{
sb.Append(m_unit.ToString().ToLower());
}
sb.Append(" [");
sb.Append(m_type.ToString());
sb.Append("]");
return sb.ToString();
}
public bool IsColor
{
get
{
if (((m_type == CssValueType.Hex)
|| (m_type == CssValueType.String && m_value.StartsWith("#")))
&& (m_value.Length == 6 || (m_value.Length == 7 && m_value.StartsWith("#"))))
{
bool hex = true;
foreach (char c in m_value)
{
if (!char.IsDigit(c)
&& c != '#'
&& c != 'a'
&& c != 'A'
&& c != 'b'
&& c != 'B'
&& c != 'c'
&& c != 'C'
&& c != 'd'
&& c != 'D'
&& c != 'e'
&& c != 'E'
&& c != 'f'
&& c != 'F'
)
{
return false;
}
}
return hex;
}
else if (m_type == CssValueType.String)
{
bool number = true;
foreach (char c in m_value)
{
if (!char.IsDigit(c))
{
number = false;
break;
}
}
if (number) { return false; }
try
{
KnownColor kc = (KnownColor)Enum.Parse(typeof(KnownColor), m_value, true);
return true;
}
catch { }
}
return false;
}
}
public Color ToColor()
{
string hex = "000000";
if (m_type == CssValueType.Hex)
{
if (m_value.Length == 7 && m_value.StartsWith("#"))
{
hex = m_value.Substring(1);
}
else if (m_value.Length == 6)
{
hex = m_value;
}
}
else
{
try
{
KnownColor kc = (KnownColor)Enum.Parse(typeof(KnownColor), m_value, true);
Color c = Color.FromKnownColor(kc);
return c;
}
catch { }
}
int r = ConvertFromHex(hex.Substring(0, 2));
int g = ConvertFromHex(hex.Substring(2, 2));
int b = ConvertFromHex(hex.Substring(4));
return Color.FromArgb(r, g, b);
}
private int ConvertFromHex(string input)
{
int val;
int result = 0;
for (int i = 0; i < input.Length; i++)
{
string chunk = input.Substring(i, 1).ToUpper();
switch (chunk)
{
case "A":
val = 10;
break;
case "B":
val = 11;
break;
case "C":
val = 12;
break;
case "D":
val = 13;
break;
case "E":
val = 14;
break;
case "F":
val = 15;
break;
default:
val = int.Parse(chunk);
break;
}
if (i == 0)
{
result += val * 16;
}
else
{
result += val;
}
}
return result;
}
}
public class CssRuleSet : ItfDeclarationContainer
{
private List<CssSelector> m_selectors = new List<CssSelector>();
private List<CssDeclaration> m_declarations = new List<CssDeclaration>();
public List<CssSelector> Selectors
{
get {
return m_selectors;
}
set {
m_selectors = value;
}
}
public List<CssDeclaration> Declarations
{
get {
return m_declarations;
}
set {
m_declarations = value;
}
}
public override string ToString()
{
return ToString(0);
}
public string ToString(int indentLevel)
{
string start = "";
for (int i = 0; i < indentLevel; i++)
{
start += "\t";
}
StringBuilder sb = new StringBuilder();
bool first = true;
foreach (CssSelector sel in m_selectors)
{
if (first)
{
first = false;
sb.Append(start);
}
else
{
sb.Append(", ");
}
sb.Append(sel.ToString());
}
sb.Append(" {" + Environment.NewLine);
sb.Append(start);
foreach (CssDeclaration dec in m_declarations)
{
sb.AppendFormat("\t{0};" + Environment.NewLine + "{1}", dec.ToString(), start);
}
sb.Append("}");
return sb.ToString();
}
}
public class CssSelector
{
private List<CssSimpleSelector> m_simpleSelectors = new List<CssSimpleSelector>();
public List<CssSimpleSelector> SimpleSelectors
{
get {
return m_simpleSelectors;
}
set {
m_simpleSelectors = value;
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
bool first = true;
foreach (CssSimpleSelector ss in m_simpleSelectors)
{
if (first)
{
first = false;
}
else
{
sb.Append(" ");
}
sb.Append(ss.ToString());
}
return sb.ToString();
}
}
public class CssSimpleSelector
{
private CssCombinator? m_combinator = null;
private string m_elementname;
private string m_id;
private string m_cls;
private CssAttribute m_attribute;
private string m_pseudo;
private CssFunction m_function;
private CssSimpleSelector m_child;
public CssCombinator? Combinator
{
get {
return m_combinator;
}
set {
m_combinator = value;
}
}
public string CombinatorString
{
get {
if (this.m_combinator.HasValue)
{
return m_combinator.ToString();
}
else
{
return null;
}
}
set {
this.m_combinator = (CssCombinator)Enum.Parse(typeof(CssCombinator), value);
}
}
public string ElementName
{
get {
return m_elementname;
}
set {
m_elementname = value;
}
}
public string ID
{
get {
return m_id;
}
set {
m_id = value;
}
}
public string Class
{
get {
return m_cls;
}
set {
m_cls = value;
}
}
public string Pseudo
{
get {
return m_pseudo;
}
set {
m_pseudo = value;
}
}
public CssAttribute Attribute
{
get {
return m_attribute;
}
set {
m_attribute = value;
}
}
public CssFunction Function
{
get {
return m_function;
}
set {
m_function = value;
}
}
public CssSimpleSelector Child
{
get {
return m_child;
}
set {
m_child = value;
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
if (m_combinator.HasValue)
{
switch (m_combinator.Value)
{
case OpenXmlPowerTools.HtmlToWml.CSS.CssCombinator.PrecededImmediatelyBy:
sb.Append(" + ");
break;
case OpenXmlPowerTools.HtmlToWml.CSS.CssCombinator.ChildOf:
sb.Append(" > ");
break;
case OpenXmlPowerTools.HtmlToWml.CSS.CssCombinator.PrecededBy:
sb.Append(" ~ ");
break;
}
}
if (m_elementname != null)
{
sb.Append(m_elementname);
}
if (m_id != null)
{
sb.AppendFormat("#{0}", m_id);
}
if (m_cls != null)
{
sb.AppendFormat(".{0}", m_cls);
}
if (m_pseudo != null)
{
sb.AppendFormat(":{0}", m_pseudo);
}
if (m_attribute != null)
{
sb.Append(m_attribute.ToString());
}
if (m_function != null)
{
sb.Append(m_function.ToString());
}
if (m_child != null)
{
if (m_child.ElementName != null)
{
sb.Append(" ");
}
sb.Append(m_child.ToString());
}
return sb.ToString();
}
}
public class CssTag
{
private CssTagType m_tagtype;
private string m_name;
private string m_cls;
private string m_pseudo;
private string m_id;
private char m_parentrel = '\0';
private CssTag m_subtag;
private List<string> m_attribs = new List<string>();
public CssTagType TagType
{
get {
return m_tagtype;
}
set {
m_tagtype = value;
}
}
public bool IsIDSelector
{
get {
return m_id != null;
}
}
public bool HasName
{
get {
return m_name != null;
}
}
public bool HasClass
{
get {
return m_cls != null;
}
}
public bool HasPseudoClass
{
get {
return m_pseudo != null;
}
}
public string Name
{
get {
return m_name;
}
set {
m_name = value;
}
}
public string Class
{
get {
return m_cls;
}
set {
m_cls = value;
}
}
public string Pseudo
{
get {
return m_pseudo;
}
set {
m_pseudo = value;
}
}
public string Id
{
get {
return m_id;
}
set {
m_id = value;
}
}
public char ParentRelationship
{
get {
return m_parentrel;
}
set {
m_parentrel = value;
}
}
public CssTag SubTag
{
get {
return m_subtag;
}
set {
m_subtag = value;
}
}
public List<string> Attributes
{
get {
return m_attribs;
}
set {
m_attribs = value;
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder(ToShortString());
if (m_subtag != null)
{
sb.Append(" ");
sb.Append(m_subtag.ToString());
}
return sb.ToString();
}
public string ToShortString()
{
StringBuilder sb = new StringBuilder();
if (m_parentrel != '\0')
{
sb.AppendFormat("{0} ", m_parentrel.ToString());
}
if (HasName)
{
sb.Append(m_name);
}
foreach (string atr in m_attribs)
{
sb.AppendFormat("[{0}]", atr);
}
if (HasClass)
{
sb.Append(".");
sb.Append(m_cls);
}
if (IsIDSelector)
{
sb.Append("#");
sb.Append(m_id);
}
if (HasPseudoClass)
{
sb.Append(":");
sb.Append(m_pseudo);
}
return sb.ToString();
}
}
[Flags]
public enum CssTagType
{
Named = 1,
Classed = 2,
IDed = 4,
Pseudoed = 8,
Directive = 16
}
public class CssTerm
{
private char? m_separator;
private char? m_sign;
private CssTermType m_type;
private string m_val;
private CssUnit? m_unit;
private CssFunction m_function;
public char? Separator
{
get {
return m_separator;
}
set {
m_separator = value;
}
}
public string SeparatorChar
{
get {
return m_separator.HasValue ? this.m_separator.Value.ToString() : null;
}
set {
m_separator = !string.IsNullOrEmpty(value) ? value[0] : '\0';
}
}
public char? Sign
{
get {
return m_sign;
}
set {
m_sign = value;
}
}
public string SignChar
{
get {
return this.m_sign.HasValue ? this.m_sign.Value.ToString() : null;
}
set {
this.m_sign = !string.IsNullOrEmpty(value) ? value[0] : '\0';
}
}
public CssTermType Type
{
get {
return m_type;
}
set {
m_type = value;
}
}
public string Value
{
get {
return m_val;
}
set {
m_val = value;
}
}
public CssUnit? Unit
{
get {
return m_unit;
}
set {
m_unit = value;
}
}
public string UnitString
{
get {
if (this.m_unit.HasValue)
{
return this.m_unit.ToString();
}
else
{
return null;
}
}
set {
this.m_unit = (CssUnit)Enum.Parse(typeof(CssUnit), value);
}
}
public CssFunction Function
{
get {
return m_function;
}
set {
m_function = value;
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
if (m_type == CssTermType.Function)
{
sb.Append(m_function.ToString());
}
else if (m_type == CssTermType.Url)
{
sb.AppendFormat("url('{0}')", m_val);
}
else if (m_type == CssTermType.Unicode)
{
sb.AppendFormat("U\\{0}", m_val.ToUpper());
}
else if (m_type == CssTermType.Hex)
{
sb.Append(m_val.ToUpper());
}
else
{
if (m_sign.HasValue)
{
sb.Append(m_sign.Value);
}
sb.Append(m_val);
if (m_unit.HasValue)
{
if (m_unit.Value == OpenXmlPowerTools.HtmlToWml.CSS.CssUnit.Percent)
{
sb.Append("%");
}
else
{
sb.Append(CssUnitOutput.ToString(m_unit.Value));
}
}
}
return sb.ToString();
}
public bool IsColor
{
get
{
if (((m_type == CssTermType.Hex)
|| (m_type == CssTermType.String && m_val.StartsWith("#")))
&& (m_val.Length == 6 || m_val.Length == 3 || ((m_val.Length == 7 || m_val.Length == 4)
&& m_val.StartsWith("#"))))
{
bool hex = true;
foreach (char c in m_val)
{
if (!char.IsDigit(c)
&& c != '#'
&& c != 'a'
&& c != 'A'
&& c != 'b'
&& c != 'B'
&& c != 'c'
&& c != 'C'
&& c != 'd'
&& c != 'D'
&& c != 'e'
&& c != 'E'
&& c != 'f'
&& c != 'F'
)
{
return false;
}
}
return hex;
}
else if (m_type == CssTermType.String)
{
bool number = true;
foreach (char c in m_val)
{
if (!char.IsDigit(c))
{
number = false;
break;
}
}
if (number) {
return false;
}
KnownColor kc;
if (Enum.TryParse(m_val, true, out kc))
{
return true;
}
}
else if (m_type == CssTermType.Function)
{
if ((m_function.Name.ToLower().Equals("rgb") && m_function.Expression.Terms.Count == 3)
|| (m_function.Name.ToLower().Equals("rgba") && m_function.Expression.Terms.Count == 4)
)
{
for (int i = 0; i < m_function.Expression.Terms.Count; i++)
{
if (m_function.Expression.Terms[i].Type != CssTermType.Number)
{
return false;
}
}
return true;
}
else if ((m_function.Name.ToLower().Equals("hsl") && m_function.Expression.Terms.Count == 3)
|| (m_function.Name.ToLower().Equals("hsla") && m_function.Expression.Terms.Count == 4)
)
{
for (int i = 0; i < m_function.Expression.Terms.Count; i++)
{
if (m_function.Expression.Terms[i].Type != CssTermType.Number)
{
return false;
}
}
return true;
}
}
return false;
}
}
private int GetRGBValue(CssTerm t)
{
try
{
if (t.Unit.HasValue && t.Unit.Value == OpenXmlPowerTools.HtmlToWml.CSS.CssUnit.Percent)
{
return (int)(255f * float.Parse(t.Value) / 100f);
}
return int.Parse(t.Value);
}
catch { }
return 0;
}
private int GetHueValue(CssTerm t)
{
try
{
return (int)(float.Parse(t.Value) * 255f / 360f);
}
catch { }
return 0;
}
public Color ToColor()
{
string hex = "000000";
if (m_type == CssTermType.Hex)
{
if ((m_val.Length == 7 || m_val.Length == 4) && m_val.StartsWith("#"))
{
hex = m_val.Substring(1);
}
else if (m_val.Length == 6 || m_val.Length == 3)
{
hex = m_val;
}
}
else if (m_type == CssTermType.Function)
{
if ((m_function.Name.ToLower().Equals("rgb") && m_function.Expression.Terms.Count == 3)
|| (m_function.Name.ToLower().Equals("rgba") && m_function.Expression.Terms.Count == 4)
)
{
int fr = 0, fg = 0, fb = 0;
for (int i = 0; i < m_function.Expression.Terms.Count; i++)
{
if (m_function.Expression.Terms[i].Type != CssTermType.Number)
{
return Color.Black;
}
switch (i)
{
case 0: fr = GetRGBValue(m_function.Expression.Terms[i]);
break;
case 1: fg = GetRGBValue(m_function.Expression.Terms[i]);
break;
case 2: fb = GetRGBValue(m_function.Expression.Terms[i]);
break;
}
}
return Color.FromArgb(fr, fg, fb);
}
else if ((m_function.Name.ToLower().Equals("hsl") && m_function.Expression.Terms.Count == 3)
|| (m_function.Name.Equals("hsla") && m_function.Expression.Terms.Count == 4)
)
{
int h = 0, s = 0, v = 0;
for (int i = 0; i < m_function.Expression.Terms.Count; i++)
{
if (m_function.Expression.Terms[i].Type != CssTermType.Number) { return Color.Black; }
switch (i)
{
case 0: h = GetHueValue(m_function.Expression.Terms[i]);
break;
case 1: s = GetRGBValue(m_function.Expression.Terms[i]);
break;
case 2: v = GetRGBValue(m_function.Expression.Terms[i]);
break;
}
}
HueSatVal hsv = new HueSatVal(h, s, v);
return hsv.Color;
}
}
else
{
try
{
KnownColor kc = (KnownColor)Enum.Parse(typeof(KnownColor), m_val, true);
Color c = Color.FromKnownColor(kc);
return c;
}
catch { }
}
if (hex.Length == 3)
{
string temp = "";
foreach (char c in hex)
{
temp += c.ToString() + c.ToString();
}
hex = temp;
}
int r = ConvertFromHex(hex.Substring(0, 2));
int g = ConvertFromHex(hex.Substring(2, 2));
int b = ConvertFromHex(hex.Substring(4));
return Color.FromArgb(r, g, b);
}
private int ConvertFromHex(string input)
{
int val;
int result = 0;
for (int i = 0; i < input.Length; i++)
{
string chunk = input.Substring(i, 1).ToUpper();
switch (chunk)
{
case "A":
val = 10;
break;
case "B":
val = 11;
break;
case "C":
val = 12;
break;
case "D":
val = 13;
break;
case "E":
val = 14;
break;
case "F":
val = 15;
break;
default:
val = int.Parse(chunk);
break;
}
if (i == 0)
{
result += val * 16;
}
else
{
result += val;
}
}
return result;
}
}
public enum CssTermType
{
Number,
Function,
String,
Url,
Unicode,
Hex
}
public enum CssUnit
{
None,
Percent,
EM,
EX,
PX,
GD,
REM,
VW,
VH,
VM,
CH,
MM,
CM,
IN,
PT,
PC,
DEG,
GRAD,
RAD,
TURN,
MS,
S,
Hz,
kHz,
}
public static class CssUnitOutput
{
public static string ToString(CssUnit u)
{
if (u == CssUnit.Percent)
{
return "%";
}
else if (u == CssUnit.Hz || u == CssUnit.kHz)
{
return u.ToString();
}
else if (u == CssUnit.None)
{
return "";
}
return u.ToString().ToLower();
}
}
public enum CssValueType
{
String,
Hex,
Unit,
Percent,
Url,
Function
}
public class CssParser
{
private List<string> m_errors = new List<string>();
private CssDocument m_doc;
public CssDocument ParseText(string content)
{
MemoryStream mem = new MemoryStream();
byte[] bytes = ASCIIEncoding.ASCII.GetBytes(content);
mem.Write(bytes, 0, bytes.Length);
try
{
return ParseStream(mem);
}
catch (OpenXmlPowerToolsException e)
{
string msg = e.Message + ". CSS => " + content;
throw new OpenXmlPowerToolsException(msg);
}
}
// following method should be private, as it does not properly re-throw OpenXmlPowerToolsException
private CssDocument ParseStream(Stream stream)
{
Scanner scanner = new Scanner(stream);
Parser parser = new Parser(scanner);
parser.Parse();
m_doc = parser.CssDoc;
return m_doc;
}
public CssDocument CSSDocument
{
get { return m_doc; }
}
public List<string> Errors
{
get { return m_errors; }
}
}
// Hue Sat and Val values from 0 - 255.
internal struct HueSatVal
{
private int m_hue;
private int m_sat;
private int m_val;
public HueSatVal(int h, int s, int v)
{
m_hue = h;
m_sat = s;
m_val = v;
}
public HueSatVal(Color color)
{
m_hue = 0;
m_sat = 0;
m_val = 0;
ConvertFromRGB(color);
}
public int Hue
{
get {
return m_hue;
}
set {
m_hue = value;
}
}
public int Saturation
{
get {
return m_sat;
}
set {
m_sat = value;
}
}
public int Value
{
get {
return m_val;
}
set {
m_val = value;
}
}
public Color Color
{
get {
return ConvertToRGB();
}
set {
ConvertFromRGB(value);
}
}
private void ConvertFromRGB(Color color)
{
double min; double max; double delta;
double r = (double)color.R / 255.0d;
double g = (double)color.G / 255.0d;
double b = (double)color.B / 255.0d;
double h; double s; double v;
min = Math.Min(Math.Min(r, g), b);
max = Math.Max(Math.Max(r, g), b);
v = max;
delta = max - min;
if (max == 0 || delta == 0)
{
s = 0;
h = 0;
}
else
{
s = delta / max;
if (r == max)
{
h = (60D * ((g - b) / delta)) % 360.0d;
}
else if (g == max)
{
h = 60D * ((b - r) / delta) + 120.0d;
}
else
{
h = 60D * ((r - g) / delta) + 240.0d;
}
}
if (h < 0)
{
h += 360.0d;
}
Hue = (int)(h / 360.0d * 255.0d);
Saturation = (int)(s * 255.0d);
Value = (int)(v * 255.0d);
}
private Color ConvertToRGB()
{
double h;
double s;
double v;
double r = 0;
double g = 0;
double b = 0;
h = ((double)Hue / 255.0d * 360.0d) % 360.0d;
s = (double)Saturation / 255.0d;
v = (double)Value / 255.0d;
if (s == 0)
{
r = v;
g = v;
b = v;
}
else
{
double p;
double q;
double t;
double fractionalPart;
int sectorNumber;
double sectorPos;
sectorPos = h / 60.0d;
sectorNumber = (int)(Math.Floor(sectorPos));
fractionalPart = sectorPos - sectorNumber;
p = v * (1.0d - s);
q = v * (1.0d - (s * fractionalPart));
t = v * (1.0d - (s * (1.0d - fractionalPart)));
switch (sectorNumber)
{
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
case 5:
r = v;
g = p;
b = q;
break;
}
}
return Color.FromArgb((int)(r * 255.0d), (int)(g * 255.0d), (int)(b * 255.0d));
}
public static bool operator !=(HueSatVal left, HueSatVal right)
{
return !(left == right);
}
public static bool operator ==(HueSatVal left, HueSatVal right)
{
return (left.Hue == right.Hue && left.Value == right.Value && left.Saturation == right.Saturation);
}
public override bool Equals(object obj)
{
return this == (HueSatVal)obj;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
public class Parser
{
public const int c_EOF = 0;
public const int c_ident = 1;
public const int c_newline = 2;
public const int c_digit = 3;
public const int c_whitespace = 4;
public const int c_maxT = 49;
const bool T = true;
const bool x = false;
const int minErrDist = 2;
public Scanner m_scanner;
public Errors m_errors;
public CssToken m_lastRecognizedToken;
public CssToken m_lookaheadToken;
int errDist = minErrDist;
public CssDocument CssDoc;
bool IsInHex(string value)
{
if (value.Length == 7)
{
return false;
}
if (value.Length + m_lookaheadToken.m_tokenValue.Length > 7)
{
return false;
}
var hexes = new List<string>
{
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "a", "b", "c", "d", "e", "f"
};
foreach (char c in m_lookaheadToken.m_tokenValue)
{
if (!hexes.Contains(c.ToString()))
{
return false;
}
}
return true;
}
bool IsUnitOfLength()
{
if (m_lookaheadToken.m_tokenKind != 1)
{
return false;
}
System.Collections.Generic.List<string> units = new System.Collections.Generic.List<string>(
new string[]
{
"em", "ex", "px", "gd", "rem", "vw", "vh", "vm", "ch", "mm", "cm", "in", "pt", "pc", "deg", "grad", "rad", "turn", "ms", "s", "hz", "khz"
});
return units.Contains(m_lookaheadToken.m_tokenValue.ToLower());
}
bool IsNumber()
{
if (m_lookaheadToken.m_tokenValue.Length > 0)
{
return char.IsDigit(m_lookaheadToken.m_tokenValue[0]);
}
return false;
}
public Parser(Scanner scanner)
{
this.m_scanner = scanner;
m_errors = new Errors();
}
void SyntaxErr(int n)
{
if (errDist >= minErrDist)
m_errors.SyntaxError(m_lookaheadToken.m_tokenLine, m_lookaheadToken.m_tokenColumn, n);
errDist = 0;
}
public void SemanticErr(string msg)
{
if (errDist >= minErrDist)
m_errors.SemanticError(m_lastRecognizedToken.m_tokenLine, m_lastRecognizedToken.m_tokenColumn, msg);
errDist = 0;
}
void Get()
{
for (;;)
{
m_lastRecognizedToken = m_lookaheadToken;
m_lookaheadToken = m_scanner.Scan();
if (m_lookaheadToken.m_tokenKind <= c_maxT)
{
++errDist;
break;
}
m_lookaheadToken = m_lastRecognizedToken;
}
}
void Expect(int n)
{
if (m_lookaheadToken.m_tokenKind == n)
Get();
else
{
SyntaxErr(n);
}
}
bool StartOf(int s)
{
return set[s, m_lookaheadToken.m_tokenKind];
}
void ExpectWeak(int n, int follow)
{
if (m_lookaheadToken.m_tokenKind == n)
Get();
else
{
SyntaxErr(n);
while (!StartOf(follow))
Get();
}
}
bool WeakSeparator(int n, int syFol, int repFol)
{
int kind = m_lookaheadToken.m_tokenKind;
if (kind == n)
{
Get();
return true;
}
else if (StartOf(repFol))
{
return false;
}
else
{
SyntaxErr(n);
while (!(set[syFol, kind] || set[repFol, kind] || set[0, kind]))
{
Get();
kind = m_lookaheadToken.m_tokenKind;
}
return StartOf(syFol);
}
}
void Css3()
{
CssDoc = new CssDocument();
CssRuleSet rset = null;
CssDirective dir = null;
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
while (m_lookaheadToken.m_tokenKind == 5 || m_lookaheadToken.m_tokenKind == 6)
{
if (m_lookaheadToken.m_tokenKind == 5)
{
Get();
}
else
{
Get();
}
}
while (StartOf(1))
{
if (StartOf(2))
{
RuleSet(out rset);
CssDoc.RuleSets.Add(rset);
}
else
{
Directive(out dir);
CssDoc.Directives.Add(dir);
}
while (m_lookaheadToken.m_tokenKind == 5 || m_lookaheadToken.m_tokenKind == 6)
{
if (m_lookaheadToken.m_tokenKind == 5)
{
Get();
}
else
{
Get();
}
}
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
}
void RuleSet(out CssRuleSet rset)
{
rset = new CssRuleSet();
CssSelector sel = null;
CssDeclaration dec = null;
Selector(out sel);
rset.Selectors.Add(sel);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
while (m_lookaheadToken.m_tokenKind == 25)
{
Get();
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
Selector(out sel);
rset.Selectors.Add(sel);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
Expect(26);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
if (StartOf(3))
{
Declaration(out dec);
rset.Declarations.Add(dec);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
while (m_lookaheadToken.m_tokenKind == 27)
{
Get();
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
if (m_lookaheadToken.m_tokenValue.Equals("}"))
{
Get();
return;
}
Declaration(out dec);
rset.Declarations.Add(dec);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
if (m_lookaheadToken.m_tokenKind == 27)
{
Get();
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
}
Expect(28);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
void Directive(out CssDirective dir)
{
dir = new CssDirective();
CssDeclaration dec = null;
CssRuleSet rset = null;
CssExpression exp = null;
CssDirective dr = null;
string ident = null;
CssMedium m;
Expect(23);
dir.Name = "@";
if (m_lookaheadToken.m_tokenKind == 24)
{
Get();
dir.Name += "-";
}
Identity(out ident);
dir.Name += ident;
switch (dir.Name.ToLower())
{
case "@media":
dir.Type = CssDirectiveType.Media;
break;
case "@import":
dir.Type = CssDirectiveType.Import;
break;
case "@charset":
dir.Type = CssDirectiveType.Charset;
break;
case "@page":
dir.Type = CssDirectiveType.Page;
break;
case "@font-face":
dir.Type = CssDirectiveType.FontFace;
break;
case "@namespace":
dir.Type = CssDirectiveType.Namespace;
break;
default:
dir.Type = CssDirectiveType.Other;
break;
}
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
if (StartOf(4))
{
if (StartOf(5))
{
Medium(out m);
dir.Mediums.Add(m);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
while (m_lookaheadToken.m_tokenKind == 25)
{
Get();
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
Medium(out m);
dir.Mediums.Add(m);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
}
else
{
Exprsn(out exp);
dir.Expression = exp;
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
}
if (m_lookaheadToken.m_tokenKind == 26)
{
Get();
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
if (StartOf(6))
{
while (StartOf(1))
{
if (dir.Type == CssDirectiveType.Page || dir.Type == CssDirectiveType.FontFace)
{
Declaration(out dec);
dir.Declarations.Add(dec);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
while (m_lookaheadToken.m_tokenKind == 27)
{
Get();
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
if (m_lookaheadToken.m_tokenValue.Equals("}"))
{
Get();
return;
}
Declaration(out dec);
dir.Declarations.Add(dec);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
if (m_lookaheadToken.m_tokenKind == 27)
{
Get();
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
}
else if (StartOf(2))
{
RuleSet(out rset);
dir.RuleSets.Add(rset);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
else
{
Directive(out dr);
dir.Directives.Add(dr);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
}
}
Expect(28);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
else if (m_lookaheadToken.m_tokenKind == 27)
{
Get();
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
else SyntaxErr(50);
}
void QuotedString(out string qs)
{
qs = "";
if (m_lookaheadToken.m_tokenKind == 7)
{
Get();
while (StartOf(7))
{
Get();
qs += m_lastRecognizedToken.m_tokenValue;
if (m_lookaheadToken.m_tokenValue.Equals("'") && !m_lastRecognizedToken.m_tokenValue.Equals("\\"))
{
break;
}
}
Expect(7);
}
else if (m_lookaheadToken.m_tokenKind == 8)
{
Get();
while (StartOf(8))
{
Get();
qs += m_lastRecognizedToken.m_tokenValue;
if (m_lookaheadToken.m_tokenValue.Equals("\"") && !m_lastRecognizedToken.m_tokenValue.Equals("\\"))
{
break;
}
}
Expect(8);
}
else SyntaxErr(51);
}
void URI(out string url)
{
url = "";
Expect(9);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
if (m_lookaheadToken.m_tokenKind == 10)
{
Get();
}
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
if (m_lookaheadToken.m_tokenKind == 7 || m_lookaheadToken.m_tokenKind == 8)
{
QuotedString(out url);
}
else if (StartOf(9))
{
while (StartOf(10))
{
Get();
url += m_lastRecognizedToken.m_tokenValue;
if (m_lookaheadToken.m_tokenValue.Equals(")"))
{
break;
}
}
}
else SyntaxErr(52);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
if (m_lookaheadToken.m_tokenKind == 11)
{
Get();
}
}
void Medium(out CssMedium m)
{
m = CssMedium.all;
switch (m_lookaheadToken.m_tokenKind)
{
case 12:
{
Get();
m = CssMedium.all;
break;
}
case 13:
{
Get();
m = CssMedium.aural;
break;
}
case 14:
{
Get();
m = CssMedium.braille;
break;
}
case 15:
{
Get();
m = CssMedium.embossed;
break;
}
case 16:
{
Get();
m = CssMedium.handheld;
break;
}
case 17:
{
Get();
m = CssMedium.print;
break;
}
case 18:
{
Get();
m = CssMedium.projection;
break;
}
case 19:
{
Get();
m = CssMedium.screen;
break;
}
case 20:
{
Get();
m = CssMedium.tty;
break;
}
case 21:
{
Get();
m = CssMedium.tv;
break;
}
default: SyntaxErr(53); break;
}
}
void Identity(out string ident)
{
ident = "";
switch (m_lookaheadToken.m_tokenKind)
{
case 1:
{
Get();
break;
}
case 22:
{
Get();
break;
}
case 9:
{
Get();
break;
}
case 12:
{
Get();
break;
}
case 13:
{
Get();
break;
}
case 14:
{
Get();
break;
}
case 15:
{
Get();
break;
}
case 16:
{
Get();
break;
}
case 17:
{
Get();
break;
}
case 18:
{
Get();
break;
}
case 19:
{
Get();
break;
}
case 20:
{
Get();
break;
}
case 21:
{
Get();
break;
}
default: SyntaxErr(54); break;
}
ident += m_lastRecognizedToken.m_tokenValue;
}
void Exprsn(out CssExpression exp)
{
exp = new CssExpression();
char? sep = null;
CssTerm trm = null;
Term(out trm);
exp.Terms.Add(trm);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
while (StartOf(11))
{
if (m_lookaheadToken.m_tokenKind == 25 || m_lookaheadToken.m_tokenKind == 46)
{
if (m_lookaheadToken.m_tokenKind == 46)
{
Get();
sep = '/';
}
else
{
Get();
sep = ',';
}
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
Term(out trm);
if (sep.HasValue)
{
trm.Separator = sep.Value;
}
exp.Terms.Add(trm);
sep = null;
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
}
void Declaration(out CssDeclaration dec)
{
dec = new CssDeclaration();
CssExpression exp = null;
string ident = "";
if (m_lookaheadToken.m_tokenKind == 24)
{
Get();
dec.Name += "-";
}
Identity(out ident);
dec.Name += ident;
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
Expect(43);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
Exprsn(out exp);
dec.Expression = exp;
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
if (m_lookaheadToken.m_tokenKind == 44)
{
Get();
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
Expect(45);
dec.Important = true;
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
}
void Selector(out CssSelector sel)
{
sel = new CssSelector();
CssSimpleSelector ss = null;
CssCombinator? cb = null;
SimpleSelector(out ss);
sel.SimpleSelectors.Add(ss);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
while (StartOf(12))
{
if (m_lookaheadToken.m_tokenKind == 29 || m_lookaheadToken.m_tokenKind == 30 || m_lookaheadToken.m_tokenKind == 31)
{
if (m_lookaheadToken.m_tokenKind == 29)
{
Get();
cb = CssCombinator.PrecededImmediatelyBy;
}
else if (m_lookaheadToken.m_tokenKind == 30)
{
Get();
cb = CssCombinator.ChildOf;
}
else
{
Get();
cb = CssCombinator.PrecededBy;
}
}
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
SimpleSelector(out ss);
if (cb.HasValue)
{
ss.Combinator = cb.Value;
}
sel.SimpleSelectors.Add(ss);
cb = null;
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
}
void SimpleSelector(out CssSimpleSelector ss)
{
ss = new CssSimpleSelector();
ss.ElementName = "";
string psd = null;
OpenXmlPowerTools.HtmlToWml.CSS.CssAttribute atb = null;
CssSimpleSelector parent = ss;
string ident = null;
if (StartOf(3))
{
if (m_lookaheadToken.m_tokenKind == 24)
{
Get();
ss.ElementName += "-";
}
Identity(out ident);
ss.ElementName += ident;
}
else if (m_lookaheadToken.m_tokenKind == 32)
{
Get();
ss.ElementName = "*";
}
else if (StartOf(13))
{
if (m_lookaheadToken.m_tokenKind == 33)
{
Get();
if (m_lookaheadToken.m_tokenKind == 24)
{
Get();
ss.ID = "-";
}
Identity(out ident);
if (ss.ID == null)
{
ss.ID = ident;
}
else
{
ss.ID += ident;
}
}
else if (m_lookaheadToken.m_tokenKind == 34)
{
Get();
ss.Class = "";
if (m_lookaheadToken.m_tokenKind == 24)
{
Get();
ss.Class += "-";
}
Identity(out ident);
ss.Class += ident;
}
else if (m_lookaheadToken.m_tokenKind == 35)
{
Attrib(out atb);
ss.Attribute = atb;
}
else
{
Pseudo(out psd);
ss.Pseudo = psd;
}
}
else SyntaxErr(55);
while (StartOf(13))
{
CssSimpleSelector child = new CssSimpleSelector();
if (m_lookaheadToken.m_tokenKind == 33)
{
Get();
if (m_lookaheadToken.m_tokenKind == 24)
{
Get();
child.ID = "-";
}
Identity(out ident);
if (child.ID == null)
{
child.ID = ident;
}
else
{
child.ID += "-";
}
}
else if (m_lookaheadToken.m_tokenKind == 34)
{
Get();
child.Class = "";
if (m_lookaheadToken.m_tokenKind == 24)
{
Get();
child.Class += "-";
}
Identity(out ident);
child.Class += ident;
}
else if (m_lookaheadToken.m_tokenKind == 35)
{
Attrib(out atb);
child.Attribute = atb;
}
else
{
Pseudo(out psd);
child.Pseudo = psd;
}
parent.Child = child;
parent = child;
}
}
void Attrib(out OpenXmlPowerTools.HtmlToWml.CSS.CssAttribute atb)
{
atb = new OpenXmlPowerTools.HtmlToWml.CSS.CssAttribute();
atb.Value = "";
string quote = null;
string ident = null;
Expect(35);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
Identity(out ident);
atb.Operand = ident;
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
if (StartOf(14))
{
switch (m_lookaheadToken.m_tokenKind)
{
case 36:
{
Get();
atb.Operator = CssAttributeOperator.Equals;
break;
}
case 37:
{
Get();
atb.Operator = CssAttributeOperator.InList;
break;
}
case 38:
{
Get();
atb.Operator = CssAttributeOperator.Hyphenated;
break;
}
case 39:
{
Get();
atb.Operator = CssAttributeOperator.EndsWith;
break;
}
case 40:
{
Get();
atb.Operator = CssAttributeOperator.BeginsWith;
break;
}
case 41:
{
Get();
atb.Operator = CssAttributeOperator.Contains;
break;
}
}
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
if (StartOf(3))
{
if (m_lookaheadToken.m_tokenKind == 24)
{
Get();
atb.Value += "-";
}
Identity(out ident);
atb.Value += ident;
}
else if (m_lookaheadToken.m_tokenKind == 7 || m_lookaheadToken.m_tokenKind == 8)
{
QuotedString(out quote);
atb.Value = quote;
}
else SyntaxErr(56);
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
}
Expect(42);
}
void Pseudo(out string pseudo)
{
pseudo = "";
CssExpression exp = null;
string ident = null;
Expect(43);
if (m_lookaheadToken.m_tokenKind == 43)
{
Get();
}
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
if (m_lookaheadToken.m_tokenKind == 24)
{
Get();
pseudo += "-";
}
Identity(out ident);
pseudo += ident;
if (m_lookaheadToken.m_tokenKind == 10)
{
Get();
pseudo += m_lastRecognizedToken.m_tokenValue;
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
Exprsn(out exp);
pseudo += exp.ToString();
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
Expect(11);
pseudo += m_lastRecognizedToken.m_tokenValue;
}
}
void Term(out CssTerm trm)
{
trm = new CssTerm();
string val = "";
CssExpression exp = null;
string ident = null;
if (m_lookaheadToken.m_tokenKind == 7 || m_lookaheadToken.m_tokenKind == 8)
{
QuotedString(out val);
trm.Value = val; trm.Type = CssTermType.String;
}
else if (m_lookaheadToken.m_tokenKind == 9)
{
URI(out val);
trm.Value = val;
trm.Type = CssTermType.Url;
}
else if (m_lookaheadToken.m_tokenKind == 47)
{
Get();
Identity(out ident);
trm.Value = "U\\" + ident;
trm.Type = CssTermType.Unicode;
}
else if (m_lookaheadToken.m_tokenKind == 33)
{
HexValue(out val);
trm.Value = val;
trm.Type = CssTermType.Hex;
}
else if (StartOf(15))
{
bool minus = false;
if (m_lookaheadToken.m_tokenKind == 24)
{
Get();
minus = true;
}
if (StartOf(16))
{
Identity(out ident);
trm.Value = ident;
trm.Type = CssTermType.String;
if (minus)
{
trm.Value = "-" + trm.Value;
}
if (StartOf(17))
{
while (m_lookaheadToken.m_tokenKind == 34 || m_lookaheadToken.m_tokenKind == 36 || m_lookaheadToken.m_tokenKind == 43)
{
if (m_lookaheadToken.m_tokenKind == 43)
{
Get();
trm.Value += m_lastRecognizedToken.m_tokenValue;
if (StartOf(18))
{
if (m_lookaheadToken.m_tokenKind == 43)
{
Get();
trm.Value += m_lastRecognizedToken.m_tokenValue;
}
if (m_lookaheadToken.m_tokenKind == 24)
{
Get();
trm.Value += m_lastRecognizedToken.m_tokenValue;
}
Identity(out ident);
trm.Value += ident;
}
else if (m_lookaheadToken.m_tokenKind == 33)
{
HexValue(out val);
trm.Value += val;
}
else if (StartOf(19))
{
while (m_lookaheadToken.m_tokenKind == 3)
{
Get();
trm.Value += m_lastRecognizedToken.m_tokenValue;
}
if (m_lookaheadToken.m_tokenKind == 34)
{
Get();
trm.Value += ".";
while (m_lookaheadToken.m_tokenKind == 3)
{
Get();
trm.Value += m_lastRecognizedToken.m_tokenValue;
}
}
}
else SyntaxErr(57);
}
else if (m_lookaheadToken.m_tokenKind == 34)
{
Get();
trm.Value += m_lastRecognizedToken.m_tokenValue;
if (m_lookaheadToken.m_tokenKind == 24)
{
Get();
trm.Value += m_lastRecognizedToken.m_tokenValue;
}
Identity(out ident);
trm.Value += ident;
}
else
{
Get();
trm.Value += m_lastRecognizedToken.m_tokenValue;
if (m_lookaheadToken.m_tokenKind == 24)
{
Get();
trm.Value += m_lastRecognizedToken.m_tokenValue;
}
if (StartOf(16))
{
Identity(out ident);
trm.Value += ident;
}
else if (StartOf(19))
{
while (m_lookaheadToken.m_tokenKind == 3)
{
Get();
trm.Value += m_lastRecognizedToken.m_tokenValue;
}
}
else SyntaxErr(58);
}
}
}
if (m_lookaheadToken.m_tokenKind == 10)
{
Get();
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
Exprsn(out exp);
CssFunction func = new CssFunction();
func.Name = trm.Value;
func.Expression = exp;
trm.Value = null;
trm.Function = func;
trm.Type = CssTermType.Function;
while (m_lookaheadToken.m_tokenKind == 4)
{
Get();
}
Expect(11);
}
}
else if (StartOf(15))
{
if (m_lookaheadToken.m_tokenKind == 29)
{
Get();
trm.Sign = '+';
}
if (minus) { trm.Sign = '-'; }
while (m_lookaheadToken.m_tokenKind == 3)
{
Get();
val += m_lastRecognizedToken.m_tokenValue;
}
if (m_lookaheadToken.m_tokenKind == 34)
{
Get();
val += m_lastRecognizedToken.m_tokenValue;
while (m_lookaheadToken.m_tokenKind == 3)
{
Get();
val += m_lastRecognizedToken.m_tokenValue;
}
}
if (StartOf(20))
{
if (m_lookaheadToken.m_tokenValue.ToLower().Equals("n"))
{
Expect(22);
val += m_lastRecognizedToken.m_tokenValue;
if (m_lookaheadToken.m_tokenKind == 24 || m_lookaheadToken.m_tokenKind == 29)
{
if (m_lookaheadToken.m_tokenKind == 29)
{
Get();
val += m_lastRecognizedToken.m_tokenValue;
}
else
{
Get();
val += m_lastRecognizedToken.m_tokenValue;
}
Expect(3);
val += m_lastRecognizedToken.m_tokenValue;
while (m_lookaheadToken.m_tokenKind == 3)
{
Get();
val += m_lastRecognizedToken.m_tokenValue;
}
}
}
else if (m_lookaheadToken.m_tokenKind == 48)
{
Get();
trm.Unit = CssUnit.Percent;
}
else
{
if (IsUnitOfLength())
{
Identity(out ident);
try
{
trm.Unit = (CssUnit)Enum.Parse(typeof(CssUnit), ident, true);
}
catch
{
m_errors.SemanticError(m_lastRecognizedToken.m_tokenLine, m_lastRecognizedToken.m_tokenColumn, string.Format("Unrecognized unit '{0}'", ident));
}
}
}
}
trm.Value = val; trm.Type = CssTermType.Number;
}
else SyntaxErr(59);
}
else SyntaxErr(60);
}
void HexValue(out string val)
{
val = "";
bool found = false;
Expect(33);
val += m_lastRecognizedToken.m_tokenValue;
if (StartOf(19))
{
while (m_lookaheadToken.m_tokenKind == 3)
{
Get();
val += m_lastRecognizedToken.m_tokenValue;
}
}
else if (IsInHex(val))
{
Expect(1);
val += m_lastRecognizedToken.m_tokenValue; found = true;
}
else SyntaxErr(61);
if (!found && IsInHex(val))
{
Expect(1);
val += m_lastRecognizedToken.m_tokenValue;
}
}
public void Parse()
{
m_lookaheadToken = new CssToken();
m_lookaheadToken.m_tokenValue = "";
Get();
Css3();
Expect(0);
}
static readonly bool[,] set = {
{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
{x,T,x,x, x,x,x,x, x,T,x,x, T,T,T,T, T,T,T,T, T,T,T,T, T,x,x,x, x,x,x,x, T,T,T,T, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x},
{x,T,x,x, x,x,x,x, x,T,x,x, T,T,T,T, T,T,T,T, T,T,T,x, T,x,x,x, x,x,x,x, T,T,T,T, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x},
{x,T,x,x, x,x,x,x, x,T,x,x, T,T,T,T, T,T,T,T, T,T,T,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
{x,T,x,T, T,x,x,T, T,T,x,x, T,T,T,T, T,T,T,T, T,T,T,x, T,T,T,T, x,T,x,x, x,T,T,x, x,x,x,x, x,x,x,x, x,x,T,T, T,x,x},
{x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, T,T,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
{x,T,x,x, x,x,x,x, x,T,x,x, T,T,T,T, T,T,T,T, T,T,T,T, T,x,x,x, T,x,x,x, T,T,T,T, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x},
{x,T,T,T, T,T,T,x, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x},
{x,T,T,T, T,T,T,T, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x},
{x,T,T,T, T,T,T,T, T,T,x,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x},
{x,T,T,T, x,T,T,x, x,T,x,x, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x},
{x,T,x,T, T,x,x,T, T,T,x,x, T,T,T,T, T,T,T,T, T,T,T,x, T,T,x,x, x,T,x,x, x,T,T,x, x,x,x,x, x,x,x,x, x,x,T,T, T,x,x},
{x,T,x,x, T,x,x,x, x,T,x,x, T,T,T,T, T,T,T,T, T,T,T,x, T,x,x,x, x,T,T,T, T,T,T,T, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x},
{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x},
{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, T,T,x,x, x,x,x,x, x,x,x},
{x,T,x,T, T,x,x,T, T,T,x,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x,x, T,T,T,T, x,x,x,x, x,x,x,T, T,x,T,T, T,x,x},
{x,T,x,x, x,x,x,x, x,T,x,x, T,T,T,T, T,T,T,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
{x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, T,x,x,x, x,x,x,T, x,x,x,x, x,x,x},
{x,T,x,x, x,x,x,x, x,T,x,x, T,T,T,T, T,T,T,T, T,T,T,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x},
{x,T,x,T, T,x,x,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x,x, T,T,T,T, T,x,x,x, x,x,x,T, T,x,T,T, T,x,x},
{x,T,x,x, x,x,x,x, x,T,x,x, T,T,T,T, T,T,T,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x}
};
}
public class Errors
{
public int numberOfErrorsDetected = 0;
public string errMsgFormat = "CssParser error: line {0} col {1}: {2}";
public virtual void SyntaxError(int line, int col, int n)
{
string s;
switch (n)
{
case 0: s = "EOF expected";
break;
case 1: s = "identifier expected";
break;
case 2: s = "newline expected";
break;
case 3: s = "digit expected";
break;
case 4: s = "whitespace expected";
break;
case 5: s = "\"<!--\" expected";
break;
case 6: s = "\"-->\" expected";
break;
case 7: s = "\"\'\" expected";
break;
case 8: s = "\"\"\" expected";
break;
case 9: s = "\"url\" expected";
break;
case 10: s = "\"(\" expected";
break;
case 11: s = "\")\" expected";
break;
case 12: s = "\"all\" expected";
break;
case 13: s = "\"aural\" expected";
break;
case 14: s = "\"braille\" expected";
break;
case 15: s = "\"embossed\" expected";
break;
case 16: s = "\"handheld\" expected";
break;
case 17: s = "\"print\" expected";
break;
case 18: s = "\"projection\" expected";
break;
case 19: s = "\"screen\" expected";
break;
case 20: s = "\"tty\" expected";
break;
case 21: s = "\"tv\" expected";
break;
case 22: s = "\"n\" expected";
break;
case 23: s = "\"@\" expected";
break;
case 24: s = "\"-\" expected";
break;
case 25: s = "\",\" expected";
break;
case 26: s = "\"{\" expected";
break;
case 27: s = "\";\" expected";
break;
case 28: s = "\"}\" expected";
break;
case 29: s = "\"+\" expected";
break;
case 30: s = "\">\" expected";
break;
case 31: s = "\"~\" expected";
break;
case 32: s = "\"*\" expected";
break;
case 33: s = "\"#\" expected";
break;
case 34: s = "\".\" expected";
break;
case 35: s = "\"[\" expected";
break;
case 36: s = "\"=\" expected";
break;
case 37: s = "\"~=\" expected";
break;
case 38: s = "\"|=\" expected";
break;
case 39: s = "\"$=\" expected";
break;
case 40: s = "\"^=\" expected";
break;
case 41: s = "\"*=\" expected";
break;
case 42: s = "\"]\" expected";
break;
case 43: s = "\":\" expected";
break;
case 44: s = "\"!\" expected";
break;
case 45: s = "\"important\" expected";
break;
case 46: s = "\"/\" expected";
break;
case 47: s = "\"U\\\\\" expected";
break;
case 48: s = "\"%\" expected";
break;
case 49: s = "??? expected";
break;
case 50: s = "invalid directive";
break;
case 51: s = "invalid QuotedString";
break;
case 52: s = "invalid URI";
break;
case 53: s = "invalid medium";
break;
case 54: s = "invalid identity";
break;
case 55: s = "invalid simpleselector";
break;
case 56: s = "invalid attrib";
break;
case 57: s = "invalid term";
break;
case 58: s = "invalid term";
break;
case 59: s = "invalid term";
break;
case 60: s = "invalid term";
break;
case 61: s = "invalid HexValue";
break;
default: s = "error " + n;
break;
}
var errorString = string.Format(errMsgFormat, line, col, s);
throw new OpenXmlPowerToolsException(errorString);
}
public virtual void SemanticError(int line, int col, string s)
{
var errorString = string.Format(errMsgFormat, line, col, s);
throw new OpenXmlPowerToolsException(errorString);
}
public virtual void SemanticError(string s)
{
throw new OpenXmlPowerToolsException(s);
}
public virtual void Warning(int line, int col, string s)
{
var errorString = string.Format(errMsgFormat, line, col, s);
throw new OpenXmlPowerToolsException(errorString);
}
public virtual void Warning(string s)
{
throw new OpenXmlPowerToolsException(s);
}
}
public class FatalError : Exception
{
public FatalError(string m) : base(m) { }
}
public class CssToken
{
public int m_tokenKind;
public int m_tokenPositionInBytes;
public int m_tokenPositionInCharacters;
public int m_tokenColumn;
public int m_tokenLine;
public string m_tokenValue;
public CssToken m_nextToken;
}
public class CssBuffer
{
public const int EOF = char.MaxValue + 1;
const int MIN_BUFFER_LENGTH = 1024;
const int MAX_BUFFER_LENGTH = MIN_BUFFER_LENGTH * 64;
byte[] m_inputBuffer;
int m_bufferStart;
int m_bufferLength;
int m_inputStreamLength;
int m_currentPositionInBuffer;
Stream m_inputStream;
bool m_isUserStream;
public CssBuffer(Stream s, bool isUserStream)
{
m_inputStream = s; this.m_isUserStream = isUserStream;
if (m_inputStream.CanSeek)
{
m_inputStreamLength = (int)m_inputStream.Length;
m_bufferLength = Math.Min(m_inputStreamLength, MAX_BUFFER_LENGTH);
m_bufferStart = Int32.MaxValue;
}
else
{
m_inputStreamLength = m_bufferLength = m_bufferStart = 0;
}
m_inputBuffer = new byte[(m_bufferLength > 0) ? m_bufferLength : MIN_BUFFER_LENGTH];
if (m_inputStreamLength > 0)
Pos = 0;
else
m_currentPositionInBuffer = 0;
if (m_bufferLength == m_inputStreamLength && m_inputStream.CanSeek)
Close();
}
protected CssBuffer(CssBuffer b)
{
m_inputBuffer = b.m_inputBuffer;
m_bufferStart = b.m_bufferStart;
m_bufferLength = b.m_bufferLength;
m_inputStreamLength = b.m_inputStreamLength;
m_currentPositionInBuffer = b.m_currentPositionInBuffer;
m_inputStream = b.m_inputStream;
b.m_inputStream = null;
m_isUserStream = b.m_isUserStream;
}
~CssBuffer() { Close(); }
protected void Close()
{
if (!m_isUserStream && m_inputStream != null)
{
m_inputStream.Close();
m_inputStream = null;
}
}
public virtual int Read()
{
if (m_currentPositionInBuffer < m_bufferLength)
{
return m_inputBuffer[m_currentPositionInBuffer++];
}
else if (Pos < m_inputStreamLength)
{
Pos = Pos;
return m_inputBuffer[m_currentPositionInBuffer++];
}
else if (m_inputStream != null && !m_inputStream.CanSeek && ReadNextStreamChunk() > 0)
{
return m_inputBuffer[m_currentPositionInBuffer++];
}
else
{
return EOF;
}
}
public int Peek()
{
int curPos = Pos;
int ch = Read();
Pos = curPos;
return ch;
}
public string GetString(int beg, int end)
{
int len = 0;
char[] buf = new char[end - beg];
int oldPos = Pos;
Pos = beg;
while (Pos < end)
buf[len++] = (char)Read();
Pos = oldPos;
return new String(buf, 0, len);
}
public int Pos
{
get { return m_currentPositionInBuffer + m_bufferStart; }
set
{
if (value >= m_inputStreamLength && m_inputStream != null && !m_inputStream.CanSeek)
{
while (value >= m_inputStreamLength && ReadNextStreamChunk() > 0) ;
}
if (value < 0 || value > m_inputStreamLength)
{
throw new FatalError("buffer out of bounds access, position: " + value);
}
if (value >= m_bufferStart && value < m_bufferStart + m_bufferLength)
{
m_currentPositionInBuffer = value - m_bufferStart;
}
else if (m_inputStream != null)
{
m_inputStream.Seek(value, SeekOrigin.Begin);
m_bufferLength = m_inputStream.Read(m_inputBuffer, 0, m_inputBuffer.Length);
m_bufferStart = value; m_currentPositionInBuffer = 0;
}
else
{
m_currentPositionInBuffer = m_inputStreamLength - m_bufferStart;
}
}
}
private int ReadNextStreamChunk()
{
int free = m_inputBuffer.Length - m_bufferLength;
if (free == 0)
{
byte[] newBuf = new byte[m_bufferLength * 2];
Array.Copy(m_inputBuffer, newBuf, m_bufferLength);
m_inputBuffer = newBuf;
free = m_bufferLength;
}
int read = m_inputStream.Read(m_inputBuffer, m_bufferLength, free);
if (read > 0)
{
m_inputStreamLength = m_bufferLength = (m_bufferLength + read);
return read;
}
return 0;
}
}
public class UTF8Buffer : CssBuffer
{
public UTF8Buffer(CssBuffer b) : base(b) { }
public override int Read()
{
int ch;
do
{
ch = base.Read();
} while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EOF));
if (ch < 128 || ch == EOF)
{
// nothing to do
}
else if ((ch & 0xF0) == 0xF0)
{
int c1 = ch & 0x07;
ch = base.Read();
int c2 = ch & 0x3F;
ch = base.Read();
int c3 = ch & 0x3F;
ch = base.Read();
int c4 = ch & 0x3F;
ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4;
}
else if ((ch & 0xE0) == 0xE0)
{
int c1 = ch & 0x0F;
ch = base.Read();
int c2 = ch & 0x3F;
ch = base.Read();
int c3 = ch & 0x3F;
ch = (((c1 << 6) | c2) << 6) | c3;
}
else if ((ch & 0xC0) == 0xC0)
{
int c1 = ch & 0x1F;
ch = base.Read();
int c2 = ch & 0x3F;
ch = (c1 << 6) | c2;
}
return ch;
}
}
public class Scanner
{
const char END_OF_LINE = '\n';
const int c_eof = 0;
const int c_maxT = 49;
const int c_noSym = 49;
const int c_maxTokenLength = 128;
public CssBuffer m_scannerBuffer;
CssToken m_currentToken;
int m_currentInputCharacter;
int m_currentCharacterBytePosition;
int m_unicodeCharacterPosition;
int m_columnNumberOfCurrentCharacter;
int m_lineNumberOfCurrentCharacter;
int m_eolInComment;
static readonly Hashtable s_start;
CssToken m_tokensAlreadyPeeked;
CssToken m_currentPeekToken;
char[] m_textOfCurrentToken = new char[c_maxTokenLength];
int m_lengthOfCurrentToken;
static Scanner()
{
s_start = new Hashtable(128);
for (int i = 65; i <= 84; ++i)
s_start[i] = 1;
for (int i = 86; i <= 90; ++i)
s_start[i] = 1;
for (int i = 95; i <= 95; ++i)
s_start[i] = 1;
for (int i = 97; i <= 122; ++i)
s_start[i] = 1;
for (int i = 10; i <= 10; ++i)
s_start[i] = 2;
for (int i = 13; i <= 13; ++i)
s_start[i] = 2;
for (int i = 48; i <= 57; ++i)
s_start[i] = 3;
for (int i = 9; i <= 9; ++i)
s_start[i] = 4;
for (int i = 11; i <= 12; ++i)
s_start[i] = 4;
for (int i = 32; i <= 32; ++i)
s_start[i] = 4;
s_start[60] = 5;
s_start[45] = 40;
s_start[39] = 11;
s_start[34] = 12;
s_start[40] = 13;
s_start[41] = 14;
s_start[64] = 15;
s_start[44] = 16;
s_start[123] = 17;
s_start[59] = 18;
s_start[125] = 19;
s_start[43] = 20;
s_start[62] = 21;
s_start[126] = 41;
s_start[42] = 42;
s_start[35] = 22;
s_start[46] = 23;
s_start[91] = 24;
s_start[61] = 25;
s_start[124] = 27;
s_start[36] = 29;
s_start[94] = 31;
s_start[93] = 34;
s_start[58] = 35;
s_start[33] = 36;
s_start[47] = 37;
s_start[85] = 43;
s_start[37] = 39;
s_start[CssBuffer.EOF] = -1;
}
public Scanner(string fileName)
{
try
{
Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
m_scannerBuffer = new CssBuffer(stream, false);
Init();
}
catch (IOException)
{
throw new FatalError("Cannot open file " + fileName);
}
}
public Scanner(Stream s)
{
m_scannerBuffer = new CssBuffer(s, true);
Init();
}
void Init()
{
m_currentCharacterBytePosition = -1;
m_lineNumberOfCurrentCharacter = 1;
m_columnNumberOfCurrentCharacter = 0;
m_unicodeCharacterPosition = -1;
m_eolInComment = 0;
NextCh();
if (m_currentInputCharacter == 0xEF)
{
NextCh();
int ch1 = m_currentInputCharacter;
NextCh();
int ch2 = m_currentInputCharacter;
if (ch1 != 0xBB || ch2 != 0xBF)
{
throw new FatalError(String.Format("illegal byte order mark: EF {0,2:X} {1,2:X}", ch1, ch2));
}
m_scannerBuffer = new UTF8Buffer(m_scannerBuffer);
m_columnNumberOfCurrentCharacter = 0;
m_unicodeCharacterPosition = -1;
NextCh();
}
m_currentPeekToken = m_tokensAlreadyPeeked = new CssToken();
}
void NextCh()
{
if (m_eolInComment > 0)
{
m_currentInputCharacter = END_OF_LINE;
m_eolInComment--;
}
else
{
m_currentCharacterBytePosition = m_scannerBuffer.Pos;
m_currentInputCharacter = m_scannerBuffer.Read();
m_columnNumberOfCurrentCharacter++;
m_unicodeCharacterPosition++;
if (m_currentInputCharacter == '\r' && m_scannerBuffer.Peek() != '\n')
m_currentInputCharacter = END_OF_LINE;
if (m_currentInputCharacter == END_OF_LINE)
{
m_lineNumberOfCurrentCharacter++; m_columnNumberOfCurrentCharacter = 0;
}
}
}
void AddCh()
{
if (m_lengthOfCurrentToken >= m_textOfCurrentToken.Length)
{
char[] newBuf = new char[2 * m_textOfCurrentToken.Length];
Array.Copy(m_textOfCurrentToken, 0, newBuf, 0, m_textOfCurrentToken.Length);
m_textOfCurrentToken = newBuf;
}
if (m_currentInputCharacter != CssBuffer.EOF)
{
m_textOfCurrentToken[m_lengthOfCurrentToken++] = (char)m_currentInputCharacter;
NextCh();
}
}
bool Comment0()
{
int level = 1, pos0 = m_currentCharacterBytePosition, line0 = m_lineNumberOfCurrentCharacter, col0 = m_columnNumberOfCurrentCharacter, charPos0 = m_unicodeCharacterPosition;
NextCh();
if (m_currentInputCharacter == '*')
{
NextCh();
for (;;)
{
if (m_currentInputCharacter == '*')
{
NextCh();
if (m_currentInputCharacter == '/')
{
level--;
if (level == 0)
{
m_eolInComment = m_lineNumberOfCurrentCharacter - line0;
NextCh();
return true;
}
NextCh();
}
}
else if (m_currentInputCharacter == CssBuffer.EOF)
return false;
else
NextCh();
}
}
else
{
m_scannerBuffer.Pos = pos0;
NextCh();
m_lineNumberOfCurrentCharacter = line0;
m_columnNumberOfCurrentCharacter = col0;
m_unicodeCharacterPosition = charPos0;
}
return false;
}
void CheckLiteral()
{
switch (m_currentToken.m_tokenValue)
{
case "url":
m_currentToken.m_tokenKind = 9;
break;
case "all":
m_currentToken.m_tokenKind = 12;
break;
case "aural":
m_currentToken.m_tokenKind = 13;
break;
case "braille":
m_currentToken.m_tokenKind = 14;
break;
case "embossed":
m_currentToken.m_tokenKind = 15;
break;
case "handheld":
m_currentToken.m_tokenKind = 16;
break;
case "print":
m_currentToken.m_tokenKind = 17;
break;
case "projection":
m_currentToken.m_tokenKind = 18;
break;
case "screen":
m_currentToken.m_tokenKind = 19;
break;
case "tty":
m_currentToken.m_tokenKind = 20;
break;
case "tv":
m_currentToken.m_tokenKind = 21;
break;
case "n":
m_currentToken.m_tokenKind = 22;
break;
case "important":
m_currentToken.m_tokenKind = 45;
break;
default:
break;
}
}
CssToken NextToken()
{
while (m_currentInputCharacter == ' ' || m_currentInputCharacter == 10 || m_currentInputCharacter == 13)
NextCh();
if (m_currentInputCharacter == '/' && Comment0())
return NextToken();
int recKind = c_noSym;
int recEnd = m_currentCharacterBytePosition;
m_currentToken = new CssToken();
m_currentToken.m_tokenPositionInBytes = m_currentCharacterBytePosition;
m_currentToken.m_tokenColumn = m_columnNumberOfCurrentCharacter;
m_currentToken.m_tokenLine = m_lineNumberOfCurrentCharacter;
m_currentToken.m_tokenPositionInCharacters = m_unicodeCharacterPosition;
int state;
if (s_start.ContainsKey(m_currentInputCharacter))
{
state = (int)s_start[m_currentInputCharacter];
}
else {
state = 0;
}
m_lengthOfCurrentToken = 0;
AddCh();
switch (state)
{
case -1: {
m_currentToken.m_tokenKind = c_eof;
break;
}
case 0:
{
if (recKind != c_noSym)
{
m_lengthOfCurrentToken = recEnd - m_currentToken.m_tokenPositionInBytes;
SetScannerBehindT();
}
m_currentToken.m_tokenKind = recKind;
break;
}
case 1:
recEnd = m_currentCharacterBytePosition; recKind = 1;
if (m_currentInputCharacter == '-' || m_currentInputCharacter >= '0' && m_currentInputCharacter <= '9' || m_currentInputCharacter >= 'A' && m_currentInputCharacter <= 'Z' || m_currentInputCharacter == '_' || m_currentInputCharacter >= 'a' && m_currentInputCharacter <= 'z')
{
AddCh();
goto case 1;
}
else
{
m_currentToken.m_tokenKind = 1; m_currentToken.m_tokenValue = new String(m_textOfCurrentToken, 0, m_lengthOfCurrentToken);
CheckLiteral();
return m_currentToken;
}
case 2:
{
m_currentToken.m_tokenKind = 2;
break;
}
case 3:
{
m_currentToken.m_tokenKind = 3;
break;
}
case 4:
{
m_currentToken.m_tokenKind = 4;
break;
}
case 5:
if (m_currentInputCharacter == '!')
{
AddCh();
goto case 6;
}
else
{
goto case 0;
}
case 6:
if (m_currentInputCharacter == '-')
{
AddCh();
goto case 7;
}
else {
goto case 0;
}
case 7:
if (m_currentInputCharacter == '-')
{
AddCh();
goto case 8;
}
else
{
goto case 0;
}
case 8:
{
m_currentToken.m_tokenKind = 5;
break;
}
case 9:
if (m_currentInputCharacter == '>')
{
AddCh();
goto case 10;
}
else
{
goto case 0;
}
case 10:
{
m_currentToken.m_tokenKind = 6;
break;
}
case 11:
{
m_currentToken.m_tokenKind = 7;
break;
}
case 12:
{
m_currentToken.m_tokenKind = 8;
break;
}
case 13:
{
m_currentToken.m_tokenKind = 10;
break;
}
case 14:
{
m_currentToken.m_tokenKind = 11;
break;
}
case 15:
{
m_currentToken.m_tokenKind = 23;
break;
}
case 16:
{
m_currentToken.m_tokenKind = 25;
break;
}
case 17:
{
m_currentToken.m_tokenKind = 26;
break;
}
case 18:
{
m_currentToken.m_tokenKind = 27;
break;
}
case 19:
{
m_currentToken.m_tokenKind = 28;
break;
}
case 20:
{
m_currentToken.m_tokenKind = 29;
break;
}
case 21:
{
m_currentToken.m_tokenKind = 30;
break;
}
case 22:
{
m_currentToken.m_tokenKind = 33;
break;
}
case 23:
{
m_currentToken.m_tokenKind = 34;
break;
}
case 24:
{
m_currentToken.m_tokenKind = 35;
break;
}
case 25:
{
m_currentToken.m_tokenKind = 36;
break;
}
case 26:
{
m_currentToken.m_tokenKind = 37;
break;
}
case 27:
if (m_currentInputCharacter == '=')
{
AddCh();
goto case 28;
}
else {
goto case 0;
}
case 28:
{
m_currentToken.m_tokenKind = 38;
break;
}
case 29:
if (m_currentInputCharacter == '=')
{
AddCh();
goto case 30;
}
else {
goto case 0;
}
case 30:
{
m_currentToken.m_tokenKind = 39;
break;
}
case 31:
if (m_currentInputCharacter == '=')
{
AddCh();
goto case 32;
}
else
{
goto case 0;
}
case 32:
{
m_currentToken.m_tokenKind = 40;
break;
}
case 33:
{
m_currentToken.m_tokenKind = 41;
break;
}
case 34:
{
m_currentToken.m_tokenKind = 42;
break;
}
case 35:
{
m_currentToken.m_tokenKind = 43;
break;
}
case 36:
{
m_currentToken.m_tokenKind = 44;
break;
}
case 37:
{
m_currentToken.m_tokenKind = 46;
break;
}
case 38:
{
m_currentToken.m_tokenKind = 47;
break;
}
case 39:
{
m_currentToken.m_tokenKind = 48;
break;
}
case 40:
recEnd = m_currentCharacterBytePosition;
recKind = 24;
if (m_currentInputCharacter == '-')
{
AddCh();
goto case 9;
}
else
{
m_currentToken.m_tokenKind = 24;
break;
}
case 41:
recEnd = m_currentCharacterBytePosition;
recKind = 31;
if (m_currentInputCharacter == '=')
{
AddCh();
goto case 26;
}
else
{
m_currentToken.m_tokenKind = 31;
break;
}
case 42:
recEnd = m_currentCharacterBytePosition;
recKind = 32;
if (m_currentInputCharacter == '=')
{
AddCh();
goto case 33;
}
else
{
m_currentToken.m_tokenKind = 32;
break;
}
case 43:
recEnd = m_currentCharacterBytePosition; recKind = 1;
if (m_currentInputCharacter == '-' || m_currentInputCharacter >= '0' && m_currentInputCharacter <= '9' || m_currentInputCharacter >= 'A' && m_currentInputCharacter <= 'Z' || m_currentInputCharacter == '_' || m_currentInputCharacter >= 'a' && m_currentInputCharacter <= 'z')
{
AddCh();
goto case 1;
}
else if (m_currentInputCharacter == 92)
{
AddCh();
goto case 38;
}
else
{
m_currentToken.m_tokenKind = 1;
m_currentToken.m_tokenValue = new String(m_textOfCurrentToken, 0, m_lengthOfCurrentToken);
CheckLiteral();
return m_currentToken;
}
}
m_currentToken.m_tokenValue = new String(m_textOfCurrentToken, 0, m_lengthOfCurrentToken);
return m_currentToken;
}
private void SetScannerBehindT()
{
m_scannerBuffer.Pos = m_currentToken.m_tokenPositionInBytes;
NextCh();
m_lineNumberOfCurrentCharacter = m_currentToken.m_tokenLine; m_columnNumberOfCurrentCharacter = m_currentToken.m_tokenColumn; m_unicodeCharacterPosition = m_currentToken.m_tokenPositionInCharacters;
for (int i = 0; i < m_lengthOfCurrentToken; i++) NextCh();
}
public CssToken Scan()
{
if (m_tokensAlreadyPeeked.m_nextToken == null)
{
return NextToken();
}
else
{
m_currentPeekToken = m_tokensAlreadyPeeked = m_tokensAlreadyPeeked.m_nextToken;
return m_tokensAlreadyPeeked;
}
}
public CssToken Peek()
{
do
{
if (m_currentPeekToken.m_nextToken == null)
{
m_currentPeekToken.m_nextToken = NextToken();
}
m_currentPeekToken = m_currentPeekToken.m_nextToken;
} while (m_currentPeekToken.m_tokenKind > c_maxT);
return m_currentPeekToken;
}
public void ResetPeek()
{
m_currentPeekToken = m_tokensAlreadyPeeked;
}
}
}