//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // [....] //------------------------------------------------------------------------------ namespace System.Xml.Xsl.XsltOld { using Res = System.Xml.Utils.Res; using System; using System.Diagnostics; using System.Globalization; using System.Xml; using System.Xml.XPath; using System.Xml.Xsl.Runtime; using MS.Internal.Xml.XPath; using System.Xml.Xsl.XsltOld.Debugger; using System.Text; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.IO; using System.CodeDom; using System.CodeDom.Compiler; using System.Reflection; using System.Security; using System.Security.Policy; using System.Security.Permissions; using Keywords = System.Xml.Xsl.Xslt.KeywordsTable; using System.Runtime.Versioning; internal class Sort { internal int select; internal string lang; internal XmlDataType dataType; internal XmlSortOrder order; internal XmlCaseOrder caseOrder; public Sort(int sortkey, String xmllang, XmlDataType datatype, XmlSortOrder xmlorder, XmlCaseOrder xmlcaseorder) { select = sortkey; lang = xmllang; dataType = datatype; order = xmlorder; caseOrder = xmlcaseorder; } } internal enum ScriptingLanguage { JScript, #if !FEATURE_PAL // visualbasic VisualBasic, #endif // !FEATURE_PAL CSharp } internal class Compiler { internal const int InvalidQueryKey = -1; internal const double RootPriority = 0.5; // cached StringBuilder for AVT parseing internal StringBuilder AvtStringBuilder = new StringBuilder(); private int stylesheetid; // Root stylesheet has id=0. We are using this in CompileImports to compile BuiltIns private InputScope rootScope; // // Object members private XmlResolver xmlResolver; // // Template being currently compiled private TemplateBaseAction currentTemplate; private XmlQualifiedName currentMode; private Hashtable globalNamespaceAliasTable; // // Current import stack private Stack stylesheets; private HybridDictionary documentURIs = new HybridDictionary(); // import/include documents, who is here has its URI in this.documentURIs private NavigatorInput input; // Atom table & InputScopeManager - cached top of the this.input stack private Keywords atoms; private InputScopeManager scopeManager; // // Compiled stylesheet state internal Stylesheet stylesheet; internal Stylesheet rootStylesheet; private RootAction rootAction; private List queryStore; private QueryBuilder queryBuilder = new QueryBuilder(); private int rtfCount = 0; // Used to load Built In templates public bool AllowBuiltInMode; public static XmlQualifiedName BuiltInMode = new XmlQualifiedName("*", string.Empty); internal Keywords Atoms { get { Debug.Assert(this.atoms != null); return this.atoms; } } internal int Stylesheetid { get{ return this.stylesheetid; } set { this.stylesheetid = value; } } internal NavigatorInput Document { get { return this.input; } } internal NavigatorInput Input { get { return this.input; } } internal bool Advance() { Debug.Assert(Document != null); return Document.Advance(); } internal bool Recurse() { Debug.Assert(Document != null); return Document.Recurse(); } internal bool ToParent() { Debug.Assert(Document != null); return Document.ToParent(); } internal Stylesheet CompiledStylesheet { get { return this.stylesheet; } } internal RootAction RootAction { get { return this.rootAction; } set { Debug.Assert(this.rootAction == null); this.rootAction = value; Debug.Assert(this.currentTemplate == null); this.currentTemplate = this.rootAction; } } internal List QueryStore { get { return this.queryStore; } } public virtual IXsltDebugger Debugger { get { return null; } } internal string GetUnicRtfId() { this.rtfCount++; return this.rtfCount.ToString(CultureInfo.InvariantCulture); } // // The World of Compile // internal void Compile(NavigatorInput input, XmlResolver xmlResolver, Evidence evidence) { #if !FEATURE_MONO_CAS evidence = null; #endif Debug.Assert(input != null); Debug.Assert(xmlResolver != null); // Debug.Assert(evidence != null); -- default evidence is null now Debug.Assert(this.input == null && this.atoms == null); this.xmlResolver = xmlResolver; PushInputDocument(input); this.rootScope = this.scopeManager.PushScope(); this.queryStore = new List(); try { this.rootStylesheet = new Stylesheet(); PushStylesheet(this.rootStylesheet); Debug.Assert(this.input != null && this.atoms != null); try { this.CreateRootAction(); } catch (XsltCompileException) { throw; } catch (Exception e) { throw new XsltCompileException(e, this.Input.BaseURI, this.Input.LineNumber, this.Input.LinePosition); } this.stylesheet.ProcessTemplates(); this.rootAction.PorcessAttributeSets(this.rootStylesheet); this.stylesheet.SortWhiteSpace(); #if !DISABLE_XSLT_SCRIPT CompileScript(evidence); #endif if (evidence != null) { this.rootAction.permissions = SecurityManager.GetStandardSandbox(evidence); } if (this.globalNamespaceAliasTable != null) { this.stylesheet.ReplaceNamespaceAlias(this); this.rootAction.ReplaceNamespaceAlias(this); } } finally { PopInputDocument(); } Debug.Assert(this.rootAction != null); Debug.Assert(this.stylesheet != null); Debug.Assert(this.queryStore != null); Debug.Assert(this.input == null && this.atoms == null); } // // Input scope compiler's support // internal bool ForwardCompatibility { get { return this.scopeManager.CurrentScope.ForwardCompatibility; } set { this.scopeManager.CurrentScope.ForwardCompatibility = value; } } internal bool CanHaveApplyImports { get { return this.scopeManager.CurrentScope.CanHaveApplyImports; } set { this.scopeManager.CurrentScope.CanHaveApplyImports = value; } } internal void InsertExtensionNamespace(string value) { string[] nsList = ResolvePrefixes(value); if (nsList != null) { scopeManager.InsertExtensionNamespaces(nsList); } } internal void InsertExcludedNamespace(string value) { string[] nsList = ResolvePrefixes(value); if (nsList != null) { scopeManager.InsertExcludedNamespaces(nsList); } } internal void InsertExtensionNamespace() { InsertExtensionNamespace(Input.Navigator.GetAttribute(Input.Atoms.ExtensionElementPrefixes, Input.Atoms.UriXsl)); } internal void InsertExcludedNamespace() { InsertExcludedNamespace(Input.Navigator.GetAttribute(Input.Atoms.ExcludeResultPrefixes, Input.Atoms.UriXsl)); } internal bool IsExtensionNamespace(String nspace) { return this.scopeManager.IsExtensionNamespace(nspace); } internal bool IsExcludedNamespace(String nspace) { return this.scopeManager.IsExcludedNamespace(nspace); } internal void PushLiteralScope() { PushNamespaceScope(); string value = Input.Navigator.GetAttribute(Atoms.Version, Atoms.UriXsl); if (value.Length != 0) { ForwardCompatibility = (value != "1.0"); } } internal void PushNamespaceScope() { this.scopeManager.PushScope(); NavigatorInput input = Input; if (input.MoveToFirstNamespace()) { do { this.scopeManager.PushNamespace(input.LocalName, input.Value); } while(input.MoveToNextNamespace()); input.ToParent(); } } protected InputScopeManager ScopeManager { get { return this.scopeManager; } } internal virtual void PopScope() { this.currentTemplate.ReleaseVariableSlots(this.scopeManager.CurrentScope.GetVeriablesCount()); this.scopeManager.PopScope(); } internal InputScopeManager CloneScopeManager() { return this.scopeManager.Clone(); } // // Variable support // internal int InsertVariable(VariableAction variable) { InputScope varScope; if (variable.IsGlobal) { Debug.Assert(this.rootAction != null); varScope = this.rootScope; } else { Debug.Assert(this.currentTemplate != null); Debug.Assert(variable.VarType == VariableType.LocalVariable || variable.VarType == VariableType.LocalParameter || variable.VarType == VariableType.WithParameter); varScope = this.scopeManager.VariableScope; } VariableAction oldVar = varScope.ResolveVariable(variable.Name); if (oldVar != null) { // Other variable with this name is visible in this scope if (oldVar.IsGlobal) { if (variable.IsGlobal) { // Global Vars replace each other base on import presidens odred if (variable.Stylesheetid == oldVar.Stylesheetid) { // Both vars are in the same stylesheet throw XsltException.Create(Res.Xslt_DupVarName, variable.NameStr); } else if (variable.Stylesheetid < oldVar.Stylesheetid) { // newly defined var is more importent varScope.InsertVariable(variable); return oldVar.VarKey; } else { // we egnore new variable return InvalidQueryKey; // We didn't add this var, so doesn't matter what VarKey we return; } } else { // local variable can shadow global } } else { // Local variable never can be "shadowed" throw XsltException.Create(Res.Xslt_DupVarName, variable.NameStr); } } varScope.InsertVariable(variable); return this.currentTemplate.AllocateVariableSlot(); } internal void AddNamespaceAlias(String StylesheetURI, NamespaceInfo AliasInfo){ if (this.globalNamespaceAliasTable == null) { this.globalNamespaceAliasTable = new Hashtable(); } NamespaceInfo duplicate = this.globalNamespaceAliasTable[StylesheetURI] as NamespaceInfo; if (duplicate == null || AliasInfo.stylesheetId <= duplicate.stylesheetId) { this.globalNamespaceAliasTable[StylesheetURI] = AliasInfo; } } internal bool IsNamespaceAlias(String StylesheetURI){ if (this.globalNamespaceAliasTable == null) { return false; } return this.globalNamespaceAliasTable.Contains(StylesheetURI); } internal NamespaceInfo FindNamespaceAlias(String StylesheetURI) { if (this.globalNamespaceAliasTable != null) { return (NamespaceInfo)this.globalNamespaceAliasTable[StylesheetURI]; } return null; } internal String ResolveXmlNamespace(String prefix) { return this.scopeManager.ResolveXmlNamespace(prefix); } internal String ResolveXPathNamespace(String prefix) { return this.scopeManager.ResolveXPathNamespace(prefix); } internal String DefaultNamespace { get{ return this.scopeManager.DefaultNamespace; } } internal void InsertKey(XmlQualifiedName name, int MatchKey, int UseKey) { this.rootAction.InsertKey(name, MatchKey, UseKey); } internal void AddDecimalFormat(XmlQualifiedName name, DecimalFormat formatinfo) { this.rootAction.AddDecimalFormat(name, formatinfo); } // // Attribute parsing support // // This function is for processing optional attributes only. In case of error // the value is ignored iff forwards-compatible mode is on. private string[] ResolvePrefixes(string tokens) { if (tokens == null || tokens.Length == 0) { return null; } string[] nsList = XmlConvert.SplitString(tokens); try { for (int idx = 0; idx < nsList.Length; idx++) { string prefix = nsList[idx]; nsList[idx] = scopeManager.ResolveXmlNamespace(prefix == "#default" ? string.Empty : prefix); } } catch (XsltException) { // The only exception here might be Res.Xslt_InvalidPrefix if (!ForwardCompatibility) { // Rethrow the exception if we're not in forwards-compatible mode throw; } // Ignore the whole list in forwards-compatible mode return null; } return nsList; } internal bool GetYesNo(string value) { Debug.Assert(value != null); Debug.Assert((object)value == (object)Input.Value); // this is always true. Why we passing value to this function. if (value == "yes") { return true; } if (value == "no") { return false; } throw XsltException.Create(Res.Xslt_InvalidAttrValue, Input.LocalName, value); } internal string GetSingleAttribute(string attributeAtom) { NavigatorInput input = Input; string element = input.LocalName; string value = null; if (input.MoveToFirstAttribute()) { do { string nspace = input.NamespaceURI; string name = input.LocalName; if (nspace.Length != 0) continue; if (Ref.Equal(name, attributeAtom)) { value = input.Value; } else { if (! this.ForwardCompatibility) { throw XsltException.Create(Res.Xslt_InvalidAttribute, name, element); } } } while (input.MoveToNextAttribute()); input.ToParent(); } if (value == null) { throw XsltException.Create(Res.Xslt_MissingAttribute, attributeAtom); } return value; } internal XmlQualifiedName CreateXPathQName(string qname) { string prefix, local; PrefixQName.ParseQualifiedName(qname, out prefix, out local); return new XmlQualifiedName(local, this.scopeManager.ResolveXPathNamespace(prefix)); } internal XmlQualifiedName CreateXmlQName(string qname) { string prefix, local; PrefixQName.ParseQualifiedName(qname, out prefix, out local); return new XmlQualifiedName(local, this.scopeManager.ResolveXmlNamespace(prefix)); } // // Input documents management // internal static XPathDocument LoadDocument(XmlTextReaderImpl reader) { reader.EntityHandling = EntityHandling.ExpandEntities; reader.XmlValidatingReaderCompatibilityMode = true; try { return new XPathDocument(reader, XmlSpace.Preserve); } finally { reader.Close(); } } private void AddDocumentURI(string href) { Debug.Assert(!this.documentURIs.Contains(href), "Circular references must be checked while processing xsl:include and xsl:import"); this.documentURIs.Add(href, null); } private void RemoveDocumentURI(string href) { Debug.Assert(this.documentURIs.Contains(href), "Attempt to remove href that was not added"); this.documentURIs.Remove(href); } internal bool IsCircularReference(string href) { return this.documentURIs.Contains(href); } [ResourceConsumption(ResourceScope.Machine)] [ResourceExposure(ResourceScope.Machine)] internal Uri ResolveUri(string relativeUri) { Debug.Assert(this.xmlResolver != null); string baseUri = this.Input.BaseURI; Uri uri = this.xmlResolver.ResolveUri((baseUri.Length != 0) ? this.xmlResolver.ResolveUri(null, baseUri) : null, relativeUri); if (uri == null) { throw XsltException.Create(Res.Xslt_CantResolve, relativeUri); } return uri; } internal NavigatorInput ResolveDocument(Uri absoluteUri) { Debug.Assert(this.xmlResolver != null); object input = this.xmlResolver.GetEntity(absoluteUri, null, null); string resolved = absoluteUri.ToString(); if (input is Stream) { XmlTextReaderImpl tr = new XmlTextReaderImpl(resolved, (Stream) input); { tr.XmlResolver = this.xmlResolver; } // reader is closed by Compiler.LoadDocument() return new NavigatorInput(Compiler.LoadDocument(tr).CreateNavigator(), resolved, rootScope); } else if (input is XPathNavigator) { return new NavigatorInput((XPathNavigator) input, resolved, rootScope); } else { throw XsltException.Create(Res.Xslt_CantResolve, resolved); } } internal void PushInputDocument(NavigatorInput newInput) { Debug.Assert(newInput != null); string inputUri = newInput.Href; AddDocumentURI(inputUri); newInput.Next = this.input; this.input = newInput; this.atoms = this.input.Atoms; this.scopeManager = this.input.InputScopeManager; } internal void PopInputDocument() { Debug.Assert(this.input != null); Debug.Assert(this.input.Atoms == this.atoms); NavigatorInput lastInput = this.input; this.input = lastInput.Next; lastInput.Next = null; if (this.input != null) { this.atoms = this.input.Atoms; this.scopeManager = this.input.InputScopeManager; } else { this.atoms = null; this.scopeManager = null; } RemoveDocumentURI(lastInput.Href); lastInput.Close(); } // // Stylesheet management // internal void PushStylesheet(Stylesheet stylesheet) { if (this.stylesheets == null) { this.stylesheets = new Stack(); } Debug.Assert(this.stylesheets != null); this.stylesheets.Push(stylesheet); this.stylesheet = stylesheet; } internal Stylesheet PopStylesheet() { Debug.Assert(this.stylesheet == this.stylesheets.Peek()); Stylesheet stylesheet = (Stylesheet) this.stylesheets.Pop(); this.stylesheet = (Stylesheet) this.stylesheets.Peek(); return stylesheet; } // // Attribute-Set management // internal void AddAttributeSet(AttributeSetAction attributeSet) { Debug.Assert(this.stylesheet == this.stylesheets.Peek()); this.stylesheet.AddAttributeSet(attributeSet); } // // Template management // internal void AddTemplate(TemplateAction template) { Debug.Assert(this.stylesheet == this.stylesheets.Peek()); this.stylesheet.AddTemplate(template); } internal void BeginTemplate(TemplateAction template) { Debug.Assert(this.currentTemplate != null); this.currentTemplate = template; this.currentMode = template.Mode; this.CanHaveApplyImports = template.MatchKey != Compiler.InvalidQueryKey; } internal void EndTemplate() { Debug.Assert(this.currentTemplate != null); this.currentTemplate = this.rootAction; } internal XmlQualifiedName CurrentMode { get { return this.currentMode; } } // // Query management // internal int AddQuery(string xpathQuery) { return AddQuery(xpathQuery, /*allowVars:*/true, /*allowKey*/true, false); } internal int AddQuery(string xpathQuery, bool allowVar, bool allowKey, bool isPattern) { Debug.Assert(this.queryStore != null); CompiledXpathExpr expr; try { expr = new CompiledXpathExpr( (isPattern ? this.queryBuilder.BuildPatternQuery(xpathQuery, allowVar, allowKey) : this.queryBuilder.Build( xpathQuery, allowVar, allowKey) ), xpathQuery, false ); } catch (XPathException e) { if (! ForwardCompatibility) { throw XsltException.Create(Res.Xslt_InvalidXPath, new string[] { xpathQuery }, e); } expr = new ErrorXPathExpression(xpathQuery, this.Input.BaseURI, this.Input.LineNumber, this.Input.LinePosition); } this.queryStore.Add(new TheQuery(expr, this.scopeManager)); return this.queryStore.Count - 1; } internal int AddStringQuery(string xpathQuery) { string modifiedQuery = XmlCharType.Instance.IsOnlyWhitespace(xpathQuery) ? xpathQuery : "string(" + xpathQuery + ")"; return AddQuery(modifiedQuery); } internal int AddBooleanQuery(string xpathQuery) { string modifiedQuery = XmlCharType.Instance.IsOnlyWhitespace(xpathQuery) ? xpathQuery : "boolean(" + xpathQuery + ")"; return AddQuery(modifiedQuery); } // // Script support // Hashtable[] _typeDeclsByLang = new Hashtable[] { new Hashtable(), new Hashtable(), new Hashtable() }; ArrayList scriptFiles = new ArrayList(); // Namespaces we always import when compiling private static string[] _defaultNamespaces = new string[] { "System", "System.Collections", "System.Text", "System.Text.RegularExpressions", "System.Xml", "System.Xml.Xsl", "System.Xml.XPath", }; private static int scriptClassCounter = 0; private static string GenerateUniqueClassName() { return "ScriptClass_" + System.Threading.Interlocked.Increment(ref scriptClassCounter); } #if !DISABLE_XSLT_SCRIPT internal void AddScript(string source, ScriptingLanguage lang, string ns, string fileName, int lineNumber) { ValidateExtensionNamespace(ns); for (ScriptingLanguage langTmp = ScriptingLanguage.JScript; langTmp <= ScriptingLanguage.CSharp; langTmp ++) { Hashtable typeDecls = _typeDeclsByLang[(int)langTmp]; if (lang == langTmp) { CodeTypeDeclaration scriptClass = (CodeTypeDeclaration)typeDecls[ns]; if (scriptClass == null) { scriptClass = new CodeTypeDeclaration(GenerateUniqueClassName()); scriptClass.TypeAttributes = TypeAttributes.Public; typeDecls.Add(ns, scriptClass); } CodeSnippetTypeMember scriptSnippet = new CodeSnippetTypeMember(source); if (lineNumber > 0) { scriptSnippet.LinePragma = new CodeLinePragma(fileName, lineNumber); scriptFiles.Add(fileName); } scriptClass.Members.Add(scriptSnippet); } else if (typeDecls.Contains(ns)) { throw XsltException.Create(Res.Xslt_ScriptMixedLanguages, ns); } } } #endif private static void ValidateExtensionNamespace(string nsUri) { if (nsUri.Length == 0 || nsUri == XmlReservedNs.NsXslt) { throw XsltException.Create(Res.Xslt_InvalidExtensionNamespace); } XmlConvert.ToUri(nsUri); } #if !DISABLE_XSLT_SCRIPT private void FixCompilerError(CompilerError e) { foreach(string scriptFile in this.scriptFiles) { if (e.FileName == scriptFile) { return; // Yes! this error is in our code sippet. } } e.FileName = string.Empty; } CodeDomProvider ChooseCodeDomProvider(ScriptingLanguage lang) { return ( lang == ScriptingLanguage.JScript ? (CodeDomProvider) Activator.CreateInstance(Type.GetType("Microsoft.JScript.JScriptCodeProvider, " + AssemblyRef.MicrosoftJScript), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, null, null) : #if !FEATURE_PAL // visualbasic lang == ScriptingLanguage.VisualBasic ? (CodeDomProvider) new Microsoft.VisualBasic.VBCodeProvider() : #endif /*CSharp | default */ (CodeDomProvider) new Microsoft.CSharp.CSharpCodeProvider() ); } private void CompileScript(Evidence evidence) { for (ScriptingLanguage lang = ScriptingLanguage.JScript; lang <= ScriptingLanguage.CSharp; lang ++) { int idx = (int)lang; if (_typeDeclsByLang[idx].Count > 0) { CompileAssembly(lang, _typeDeclsByLang[idx], lang.ToString(), evidence); } } } [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] // SxS: This method does not take any resource name and does not expose any resources to the caller. // It's OK to suppress the SxS warning. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] [ResourceExposure(ResourceScope.None)] private void CompileAssembly(ScriptingLanguage lang, Hashtable typeDecls, string nsName, Evidence evidence) { nsName = "Microsoft.Xslt.CompiledScripts." + nsName; CodeNamespace msXslt = new CodeNamespace(nsName); // Add all the default namespaces foreach(string ns in _defaultNamespaces) { msXslt.Imports.Add(new CodeNamespaceImport(ns)); } #if !FEATURE_PAL // visualbasic if (lang == ScriptingLanguage.VisualBasic) { msXslt.Imports.Add(new CodeNamespaceImport("Microsoft.VisualBasic")); } #endif //!FEATURE_PAL foreach(CodeTypeDeclaration scriptClass in typeDecls.Values) { msXslt.Types.Add(scriptClass); } CodeCompileUnit unit = new CodeCompileUnit(); { unit.Namespaces.Add(msXslt); // This settings have sense for Visual Basic only. // We can consider in future to allow user set them in attribute. unit.UserData["AllowLateBound"] = true; // Allow variables to be undeclared unit.UserData["RequireVariableDeclaration"] = false; // Allow variables to be declared untyped } // We want the assemblies generated for scripts to stick to the old security model unit.AssemblyCustomAttributes.Add( new CodeAttributeDeclaration( new CodeTypeReference(typeof(System.Security.SecurityRulesAttribute)), new CodeAttributeArgument( new CodeFieldReferenceExpression( new CodeTypeReferenceExpression(typeof(System.Security.SecurityRuleSet)), "Level1")))); CompilerParameters compilParams = new CompilerParameters(); { try { new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Assert(); try { compilParams.GenerateInMemory = true; #pragma warning disable 618 compilParams.Evidence = evidence; #pragma warning restore 618 compilParams.ReferencedAssemblies.Add(typeof(XPathNavigator).Module.FullyQualifiedName); compilParams.ReferencedAssemblies.Add("system.dll"); #if !FEATURE_PAL // visualbasic if (lang == ScriptingLanguage.VisualBasic) { compilParams.ReferencedAssemblies.Add("microsoft.visualbasic.dll"); } #endif // !FEATURE_PAL } finally { CodeAccessPermission.RevertAssert(); } } catch { throw; } } CompilerResults results = ChooseCodeDomProvider(lang).CompileAssemblyFromDom(compilParams, unit); if (results.Errors.HasErrors) { StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); foreach (CompilerError e in results.Errors) { FixCompilerError(e); stringWriter.WriteLine(e.ToString()); } throw XsltException.Create(Res.Xslt_ScriptCompileErrors, stringWriter.ToString()); } Assembly assembly = results.CompiledAssembly; foreach(DictionaryEntry entry in typeDecls) { string ns = (string)entry.Key; CodeTypeDeclaration scriptClass = (CodeTypeDeclaration)entry.Value; this.stylesheet.ScriptObjectTypes.Add(ns, assembly.GetType(nsName + "." + scriptClass.Name)); } } #endif public string GetNsAlias(ref string prefix) { Debug.Assert( Ref.Equal(this.input.LocalName, this.input.Atoms.StylesheetPrefix) || Ref.Equal(this.input.LocalName, this.input.Atoms.ResultPrefix) ); if (prefix == "#default") { prefix = string.Empty; return this.DefaultNamespace; } else { if (! PrefixQName.ValidatePrefix(prefix)) { throw XsltException.Create(Res.Xslt_InvalidAttrValue, this.input.LocalName, prefix); } return this.ResolveXPathNamespace(prefix); } } // AVT's compilation. // CompileAvt() returns ArrayList of TextEvent & AvtEvent private static void getTextLex(string avt, ref int start, StringBuilder lex) { Debug.Assert(avt.Length != start, "Empty string not supposed here"); Debug.Assert(lex.Length == 0 , "Builder shoud to be reset here"); int avtLength = avt.Length; int i; for (i = start; i < avtLength; i ++) { char ch = avt[i]; if (ch == '{') { if (i + 1 < avtLength && avt[i + 1] == '{') { // "{{" i ++; } else { break; } } else if (ch == '}') { if (i + 1 < avtLength && avt[i + 1] == '}') { // "}}" i ++; } else { throw XsltException.Create(Res.Xslt_SingleRightAvt, avt); } } lex.Append(ch); } start = i; } private static void getXPathLex(string avt, ref int start, StringBuilder lex) { // AVT parser states const int InExp = 0; // Inside AVT expression const int InLiteralA = 1; // Inside literal in expression, apostrophe delimited const int InLiteralQ = 2; // Inside literal in expression, quote delimited Debug.Assert(avt.Length != start, "Empty string not supposed here"); Debug.Assert(lex.Length == 0 , "Builder shoud to be reset here"); Debug.Assert(avt[start] == '{' , "We calling getXPathLex() only after we realy meet {"); int avtLength = avt.Length; int state = InExp; for (int i = start + 1; i < avtLength; i ++) { char ch = avt[i]; switch(state) { case InExp : switch (ch) { case '{' : throw XsltException.Create(Res.Xslt_NestedAvt, avt); case '}' : i ++; // include '}' if (i == start + 2) { // empty XPathExpresion throw XsltException.Create(Res.Xslt_EmptyAvtExpr, avt); } lex.Append(avt, start + 1, i - start - 2); // avt without {} start = i; return; case '\'' : state = InLiteralA; break; case '"' : state = InLiteralQ; break; } break; case InLiteralA : if (ch == '\'') { state = InExp; } break; case InLiteralQ : if (ch == '"') { state = InExp; } break; } } // if we meet end of string before } we have an error throw XsltException.Create(state == InExp ? Res.Xslt_OpenBracesAvt : Res.Xslt_OpenLiteralAvt, avt); } private static bool GetNextAvtLex(string avt, ref int start, StringBuilder lex, out bool isAvt) { Debug.Assert(start <= avt.Length); #if DEBUG int saveStart = start; #endif isAvt = false; if (start == avt.Length) { return false; } lex.Length = 0; getTextLex(avt, ref start, lex); if (lex.Length == 0) { isAvt = true; getXPathLex(avt, ref start, lex); } #if DEBUG Debug.Assert(saveStart < start, "We have to read something. Otherwise it's dead loop."); #endif return true; } internal ArrayList CompileAvt(string avtText, out bool constant) { Debug.Assert(avtText != null); ArrayList list = new ArrayList(); constant = true; /* Parse input.Value as AVT */ { int pos = 0; bool isAvt; while (GetNextAvtLex(avtText, ref pos, this.AvtStringBuilder, out isAvt)) { string lex = this.AvtStringBuilder.ToString(); if (isAvt) { list.Add(new AvtEvent(this.AddStringQuery(lex))); constant = false; } else { list.Add(new TextEvent(lex)); } } } Debug.Assert(!constant || list.Count <= 1, "We can't have more then 1 text event if now {avt} found"); return list; } internal ArrayList CompileAvt(string avtText) { bool constant; return CompileAvt(avtText, out constant); } // Compiler is a class factory for some actions: // CompilerDbg override all this methods: public virtual ApplyImportsAction CreateApplyImportsAction() { ApplyImportsAction action = new ApplyImportsAction(); action.Compile(this); return action; } public virtual ApplyTemplatesAction CreateApplyTemplatesAction() { ApplyTemplatesAction action = new ApplyTemplatesAction(); action.Compile(this); return action; } public virtual AttributeAction CreateAttributeAction() { AttributeAction action = new AttributeAction(); action.Compile(this); return action; } public virtual AttributeSetAction CreateAttributeSetAction() { AttributeSetAction action = new AttributeSetAction(); action.Compile(this); return action; } public virtual CallTemplateAction CreateCallTemplateAction() { CallTemplateAction action = new CallTemplateAction(); action.Compile(this); return action; } public virtual ChooseAction CreateChooseAction() {//!!! don't need to be here ChooseAction action = new ChooseAction(); action.Compile(this); return action; } public virtual CommentAction CreateCommentAction() { CommentAction action = new CommentAction(); action.Compile(this); return action; } public virtual CopyAction CreateCopyAction() { CopyAction action = new CopyAction(); action.Compile(this); return action; } public virtual CopyOfAction CreateCopyOfAction() { CopyOfAction action = new CopyOfAction(); action.Compile(this); return action; } public virtual ElementAction CreateElementAction() { ElementAction action = new ElementAction(); action.Compile(this); return action; } public virtual ForEachAction CreateForEachAction() { ForEachAction action = new ForEachAction(); action.Compile(this); return action; } public virtual IfAction CreateIfAction(IfAction.ConditionType type) { IfAction action = new IfAction(type); action.Compile(this); return action; } public virtual MessageAction CreateMessageAction() { MessageAction action = new MessageAction(); action.Compile(this); return action; } public virtual NewInstructionAction CreateNewInstructionAction() { NewInstructionAction action = new NewInstructionAction(); action.Compile(this); return action; } public virtual NumberAction CreateNumberAction() { NumberAction action = new NumberAction(); action.Compile(this); return action; } public virtual ProcessingInstructionAction CreateProcessingInstructionAction() { ProcessingInstructionAction action = new ProcessingInstructionAction(); action.Compile(this); return action; } public virtual void CreateRootAction() { this.RootAction = new RootAction(); this.RootAction.Compile(this); } public virtual SortAction CreateSortAction() { SortAction action = new SortAction(); action.Compile(this); return action; } public virtual TemplateAction CreateTemplateAction() { TemplateAction action = new TemplateAction(); action.Compile(this); return action; } public virtual TemplateAction CreateSingleTemplateAction() { TemplateAction action = new TemplateAction(); action.CompileSingle(this); return action; } public virtual TextAction CreateTextAction() { TextAction action = new TextAction(); action.Compile(this); return action; } public virtual UseAttributeSetsAction CreateUseAttributeSetsAction() { UseAttributeSetsAction action = new UseAttributeSetsAction(); action.Compile(this); return action; } public virtual ValueOfAction CreateValueOfAction() { ValueOfAction action = new ValueOfAction(); action.Compile(this); return action; } public virtual VariableAction CreateVariableAction(VariableType type) { VariableAction action = new VariableAction(type); action.Compile(this); if (action.VarKey != InvalidQueryKey) { return action; } else { return null; } } public virtual WithParamAction CreateWithParamAction() { WithParamAction action = new WithParamAction(); action.Compile(this); return action; } // Compiler is a class factory for some events: // CompilerDbg override all this methods: public virtual BeginEvent CreateBeginEvent() { return new BeginEvent(this); } public virtual TextEvent CreateTextEvent() { return new TextEvent(this); } public XsltException UnexpectedKeyword() { XPathNavigator nav = this.Input.Navigator.Clone(); string thisName = nav.Name; nav.MoveToParent(); string parentName = nav.Name; return XsltException.Create(Res.Xslt_UnexpectedKeyword, thisName, parentName); } internal class ErrorXPathExpression : CompiledXpathExpr { private string baseUri; private int lineNumber, linePosition; public ErrorXPathExpression(string expression, string baseUri, int lineNumber, int linePosition) : base(null, expression, false) { this.baseUri = baseUri; this.lineNumber = lineNumber; this.linePosition = linePosition; } public override XPathExpression Clone() { return this; } public override void CheckErrors() { throw new XsltException(Res.Xslt_InvalidXPath, new string[] { Expression }, baseUri, linePosition, lineNumber, null); } } } }