The Labs \ Source Viewer \ SSCLI \ System.Xml.Xsl.Xslt \ Scripts

  1. //------------------------------------------------------------------------------
  2. // <copyright file="Scripts.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. // <spec>http://devdiv/Documents/Whidbey/CLR/CurrentSpecs/BCL/CodeDom%20Activation.doc</spec>
  15. //------------------------------------------------------------------------------
  16. using System.CodeDom;
  17. using System.CodeDom.Compiler;
  18. using System.Collections.Generic;
  19. using System.Collections.Specialized;
  20. using System.Configuration;
  21. using System.Diagnostics;
  22. using System.Reflection;
  23. using System.Runtime.InteropServices;
  24. using System.Threading;
  25. using System.Xml.Xsl.IlGen;
  26. using System.Xml.Xsl.Runtime;
  27. using System.Security.Permissions;
  28. namespace System.Xml.Xsl.Xslt
  29. {
  30.     using Res = System.Xml.Utils.Res;
  31.    
  32.     internal class ScriptClass
  33.     {
  34.         public string ns;
  35.         public CompilerInfo compilerInfo;
  36.         public StringCollection refAssemblies = new StringCollection();
  37.         public StringCollection nsImports = new StringCollection();
  38.         public StringCollection scriptFiles = new StringCollection();
  39.         public CodeTypeDeclaration typeDecl;
  40.        
  41.         // These three fields are used to report a compile error when its position is outside
  42.         // of all user code snippets in the generated temporary file
  43.         public string endFileName;
  44.         public int endLine;
  45.         public int endPos;
  46.        
  47.         public ScriptClass(string ns, CompilerInfo compilerInfo)
  48.         {
  49.             this.ns = ns;
  50.             this.compilerInfo = compilerInfo;
  51.             this.typeDecl = new CodeTypeDeclaration(GenerateUniqueClassName());
  52.         }
  53.        
  54.         private static long scriptClassCounter = 0;
  55.        
  56.         private static string GenerateUniqueClassName()
  57.         {
  58.             return "Script" + Interlocked.Increment(ref scriptClassCounter);
  59.         }
  60.        
  61.         public void AddScriptBlock(string source, string uriString, int lineNumber, int endLine, int endPos)
  62.         {
  63.             CodeSnippetTypeMember scriptSnippet = new CodeSnippetTypeMember(source);
  64.             string fileName = SourceLineInfo.GetFileName(uriString);
  65.             if (lineNumber > 0) {
  66.                 scriptSnippet.LinePragma = new CodeLinePragma(fileName, lineNumber);
  67.                 scriptFiles.Add(fileName);
  68.             }
  69.             typeDecl.Members.Add(scriptSnippet);
  70.            
  71.             this.endFileName = fileName;
  72.             this.endLine = endLine;
  73.             this.endPos = endPos;
  74.         }
  75.        
  76.         // The position of a compile error may be outside of all user code snippets (for example, in case of
  77.         // unclosed '{'). In that case filename would be the name of the temporary file, and not the name
  78.         // of the stylesheet file. Exposing the path of the temporary file is considered to be a security issue,
  79.         // so here we check that filename is amongst user files
  80.         public void FixFileName(CompilerError e)
  81.         {
  82.             string fileName = e.FileName;
  83.             foreach (string scriptFile in scriptFiles) {
  84.                 if (fileName.Equals(scriptFile, StringComparison.OrdinalIgnoreCase)) {
  85.                     // The error position is within one of user stylesheets, its filename may be reported
  86.                     e.FileName = scriptFile;
  87.                     return;
  88.                 }
  89.             }
  90.            
  91.             // Error is outside user files, we should hide filename for security reasons.
  92.             // Return filename and position of the end of the last script block for the given class.
  93.             e.FileName = this.endFileName;
  94.             e.Line = this.endLine;
  95.             e.Column = this.endPos;
  96.         }
  97.        
  98.         public CompilerError CreateCompileExceptionError(Exception e)
  99.         {
  100.                 /*[XT_041]*/            string errorText = XslTransformException.CreateMessage(Res.Xslt_ScriptCompileException, e.Message);
  101.                 /*errorNumber:*/            return new CompilerError(this.endFileName, this.endLine, this.endPos, string.Empty, errorText);
  102.         }
  103.     }
  104.    
  105.     internal class Scripts
  106.     {
  107.         private Compiler compiler;
  108.         private List<ScriptClass> scriptClasses = new List<ScriptClass>();
  109.         private Dictionary<string, Type> nsToType = new Dictionary<string, Type>();
  110.         private XmlExtensionFunctionTable extFuncs = new XmlExtensionFunctionTable();
  111.        
  112.         public Scripts(Compiler compiler)
  113.         {
  114.             this.compiler = compiler;
  115.         }
  116.        
  117.         public Dictionary<string, Type> ScriptClasses {
  118.             get { return nsToType; }
  119.         }
  120.        
  121.         public XmlExtensionFunction ResolveFunction(string name, string ns, int numArgs, IErrorHelper errorHelper)
  122.         {
  123.             Type type;
  124.             if (nsToType.TryGetValue(ns, out type)) {
  125.                 try {
  126.                     return extFuncs.Bind(name, ns, numArgs, type, XmlQueryRuntime.EarlyBoundFlags);
  127.                 }
  128.                 catch (XslTransformException e) {
  129.                     errorHelper.ReportError(e.Message);
  130.                 }
  131.             }
  132.             return null;
  133.         }
  134.        
  135.         public ScriptClass GetScriptClass(string ns, string language, IErrorHelper errorHelper)
  136.         {
  137.             CompilerInfo compilerInfo;
  138.             try {
  139.                 compilerInfo = CodeDomProvider.GetCompilerInfo(language);
  140.                 Debug.Assert(compilerInfo != null);
  141.             }
  142.             catch (ConfigurationException) {
  143.                 // There is no CodeDom provider defined for this language
  144.                     /*[XT_010]*/                errorHelper.ReportError(Res.Xslt_ScriptInvalidLanguage, language);
  145.                 return null;
  146.             }
  147.            
  148.             foreach (ScriptClass scriptClass in scriptClasses) {
  149.                 if (ns == scriptClass.ns) {
  150.                     if (!compilerInfo.Equals(scriptClass.compilerInfo)) {
  151.                             /*[XT_011]*/                        errorHelper.ReportError(Res.Xslt_ScriptMixedLanguages, ns);
  152.                         return null;
  153.                     }
  154.                     return scriptClass;
  155.                 }
  156.             }
  157.            
  158.             ScriptClass newScriptClass = new ScriptClass(ns, compilerInfo);
  159.             newScriptClass.typeDecl.TypeAttributes = TypeAttributes.Public;
  160.             scriptClasses.Add(newScriptClass);
  161.             return newScriptClass;
  162.         }
  163.        
  164.         // ------------- CompileScripts() -----------
  165.        
  166.         public void CompileScripts()
  167.         {
  168.             for (int i = 0; i < scriptClasses.Count; i++) {
  169.                 ScriptClass script = scriptClasses[i];
  170.                 Type clrType = CompileClass(script);
  171.                 if (clrType != null) {
  172.                     nsToType.Add(script.ns, clrType);
  173.                 }
  174.             }
  175.         }
  176.        
  177.         // Namespaces we always import when compiling
  178.         private static string[] defaultNamespaces = new string[] {"System", "System.Collections", "System.Text", "System.Text.RegularExpressions", "System.Xml", "System.Xml.Xsl", "System.Xml.XPath"};
  179.        
  180.         [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
  181.         private Type CompileClass(ScriptClass script)
  182.         {
  183.             TempFileCollection allTempFiles = compiler.CompilerResults.TempFiles;
  184.             CompilerErrorCollection allErrors = compiler.CompilerResults.Errors;
  185.             CodeDomProvider provider;
  186.             bool isVB = false;
  187.            
  188.             try {
  189.                 provider = script.compilerInfo.CreateProvider();
  190.             }
  191.             catch (ConfigurationException e) {
  192.                 // The CodeDom provider type could not be located, or some error in machine.config
  193.                 allErrors.Add(script.CreateCompileExceptionError(e));
  194.                 return null;
  195.             }
  196.            
  197.             CodeNamespace scriptNs = new CodeNamespace("System.Xml.Xsl.CompiledQuery");
  198.            
  199.             // Add #using directives
  200.             foreach (string ns in defaultNamespaces) {
  201.                 scriptNs.Imports.Add(new CodeNamespaceImport(ns));
  202.             }
  203.             if (isVB) {
  204.                 scriptNs.Imports.Add(new CodeNamespaceImport("Microsoft.VisualBasic"));
  205.             }
  206.             foreach (string ns in script.nsImports) {
  207.                 scriptNs.Imports.Add(new CodeNamespaceImport(ns));
  208.             }
  209.            
  210.             scriptNs.Types.Add(script.typeDecl);
  211.            
  212.             CodeCompileUnit unit = new CodeCompileUnit();
  213.             {
  214.                 unit.Namespaces.Add(scriptNs);
  215.                 unit.UserData["AllowLateBound"] = true;
  216.                 // Allow variables to be undeclared
  217.                 unit.UserData["RequireVariableDeclaration"] = false;
  218.                 // Allow variables to be declared untyped
  219.                 unit.AssemblyCustomAttributes.Add(new CodeAttributeDeclaration("System.Security.SecurityTransparentAttribute"));
  220.             }
  221.            
  222.             CompilerParameters compilParams = new CompilerParameters();
  223.            
  224.             compilParams.ReferencedAssemblies.Add(typeof(System.Xml.Res).Assembly.Location);
  225.             compilParams.ReferencedAssemblies.Add("System.dll");
  226.             if (isVB) {
  227.                 compilParams.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll");
  228.             }
  229.             foreach (string name in script.refAssemblies) {
  230.                 compilParams.ReferencedAssemblies.Add(name);
  231.             }
  232.            
  233.             XsltSettings settings = compiler.Settings;
  234.             compilParams.WarningLevel = settings.WarningLevel >= 0 ? settings.WarningLevel : 4;
  235.             compilParams.TreatWarningsAsErrors = settings.TreatWarningsAsErrors;
  236.             compilParams.IncludeDebugInformation = settings.IncludeDebugInformation;
  237.             compilParams.CompilerOptions = script.compilerInfo.CreateDefaultCompilerParameters().CompilerOptions;
  238.            
  239.             bool keepFiles = (settings.IncludeDebugInformation || XmlILTrace.IsEnabled) && !settings.CheckOnly;
  240.            
  241.             compilParams.GenerateInMemory = settings.CheckOnly;
  242.            
  243.             // We need only .dll and .pdb, but there is no way to specify that
  244.             compilParams.TempFiles.KeepFiles = keepFiles;
  245.            
  246.             CompilerResults results;
  247.            
  248.             try {
  249.                 results = provider.CompileAssemblyFromDom(compilParams, unit);
  250.             }
  251.             catch (ExternalException e) {
  252.                 // Compiler might have created temporary files
  253.                 results = new CompilerResults(compilParams.TempFiles);
  254.                 results.Errors.Add(script.CreateCompileExceptionError(e));
  255.             }
  256.            
  257.             if (!settings.CheckOnly) {
  258.                 foreach (string fileName in results.TempFiles) {
  259.                     allTempFiles.AddFile(fileName, allTempFiles.KeepFiles);
  260.                 }
  261.             }
  262.             foreach (CompilerError e in results.Errors) {
  263.                 script.FixFileName(e);
  264.             }
  265.             allErrors.AddRange(results.Errors);
  266.             if (results.Errors.HasErrors) {
  267.                 return null;
  268.             }
  269.             return results.CompiledAssembly.GetType("System.Xml.Xsl.CompiledQuery." + script.typeDecl.Name);
  270.         }
  271.     }
  272. }

Developer Fusion