|
//------------------------------------------------------------------------------
// <copyright file="BrowserCapabilitiesCodeGenerator.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Configuration {
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Configuration;
using System.Collections;
using System.Collections.Specialized;
using System.IO;
#if !FEATURE_PAL
using System.ServiceProcess;
#endif // !FEATURE_PAL
using System.Linq;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Compilation;
using System.Web.Configuration;
using System.Web.Hosting;
using System.Web.UI;
using System.Web.Util;
using System.Xml;
using System.Xml.Schema;
using Microsoft.Build.Utilities;
using Microsoft.CSharp;
using System.Diagnostics.CodeAnalysis;
[PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
[PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)]
public class BrowserCapabilitiesCodeGenerator {
private static readonly string _browsersDirectory;
private static readonly string _publicKeyTokenFile;
private static object _staticLock = new object();
private BrowserTree _browserTree;
private BrowserTree _defaultTree;
private BrowserDefinitionCollection _browserDefinitionCollection;
internal const string browserCapsVariable = "browserCaps";
internal const string IgnoreApplicationBrowserVariableName = "ignoreApplicationBrowsers";
private const string _factoryTypeName = "BrowserCapabilitiesFactory";
private const string _headerDictionaryVarName = "_headerDictionary";
private const string _disableOptimizedCacheKeyMethodName = "DisableOptimizedCacheKey";
private const string _matchedHeadersMethodName = "PopulateMatchedHeaders";
private const string _browserElementsMethodName = "PopulateBrowserElements";
private const string _dictionaryRefName = "dictionary";
private const string _regexWorkerRefName = "regexWorker";
private const string _headersRefName = "headers";
private const string _resultVarName = "result";
private const string _processRegexMethod = "ProcessRegex";
private static readonly string _strongNameKeyFileName = browserCapsVariable + ".snk";
private static readonly string _publicKeyTokenFileName = browserCapsVariable + ".token";
private static bool _publicKeyTokenLoaded;
private static string _publicKeyToken;
private CodeVariableReferenceExpression _dictionaryRefExpr = new CodeVariableReferenceExpression(_dictionaryRefName);
private CodeVariableReferenceExpression _regexWorkerRefExpr = new CodeVariableReferenceExpression(_regexWorkerRefName);
private CodeVariableReferenceExpression _headersRefExpr = new CodeVariableReferenceExpression(_headersRefName);
private CodeVariableReferenceExpression _browserCapsRefExpr = new CodeVariableReferenceExpression(browserCapsVariable);
private ArrayList _browserFileList;
private ArrayList _customBrowserFileLists;
private ArrayList _customTreeList;
private ArrayList _customTreeNames;
private ArrayList _customBrowserDefinitionCollections;
private CaseInsensitiveStringSet _headers;
static BrowserCapabilitiesCodeGenerator() {
#if !PLATFORM_UNIX // File system paths must account for UNIX
_browsersDirectory = HttpRuntime.ClrInstallDirectoryInternal + "\\config\\browsers";
_publicKeyTokenFile = _browsersDirectory + "\\" + _publicKeyTokenFileName;
#else // !PLATFORM_UNIX
_browsersDirectory = HttpRuntime.ClrInstallDirectoryInternal + "/config/browsers";
_publicKeyTokenFile = _browsersDirectory + "/" + _publicKeyTokenFileName;
#endif // !PLATFORM_UNIX
}
public BrowserCapabilitiesCodeGenerator() {
_headers = new CaseInsensitiveStringSet();
}
internal BrowserTree BrowserTree {
get {
return _browserTree;
}
}
internal BrowserTree DefaultTree {
get {
return _defaultTree;
}
}
internal ArrayList CustomTreeList {
get {
return _customTreeList;
}
}
internal ArrayList CustomTreeNames {
get {
return _customTreeNames;
}
}
internal static string BrowserCapAssemblyPublicKeyToken {
get {
if (_publicKeyTokenLoaded) {
return _publicKeyToken;
}
lock (_staticLock) {
if (_publicKeyTokenLoaded) {
return _publicKeyToken;
}
string publicKeyTokenFile;
if (MultiTargetingUtil.IsTargetFramework40OrAbove) {
publicKeyTokenFile = _publicKeyTokenFile;
}
else {
// If we are targeting pre-4.0, we should be using version 2.0 of the assembly
// ASP.BrowserCapsFactory, so we need to read the token file from the 2.0 path.
// (Dev10 bug 795509)
string subPath = @"config\browsers\" + _publicKeyTokenFileName;
publicKeyTokenFile = ToolLocationHelper.GetPathToDotNetFrameworkFile(subPath, TargetDotNetFrameworkVersion.Version20);
}
_publicKeyToken = LoadPublicKeyTokenFromFile(publicKeyTokenFile);
_publicKeyTokenLoaded = true;
return _publicKeyToken;
}
}
}
internal virtual bool GenerateOverrides { get { return true; } }
internal virtual string TypeName {
get {
return _factoryTypeName;
}
}
internal void AddFile(string filePath) {
if (_browserFileList == null)
_browserFileList = new ArrayList();
_browserFileList.Add(filePath);
}
internal void AddCustomFile(string filePath) {
if (_customBrowserFileLists == null) {
_customBrowserFileLists = new ArrayList();
}
_customBrowserFileLists.Add(filePath);
}
//parse the config info and create BrowserTree
//then generate code for, compile, and gac the object
[SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
public virtual void Create() {
DirectoryInfo browserDirInfo = new DirectoryInfo(_browsersDirectory);
//get all the browser files and put them in the "tree"
FileInfo[] browserFiles = browserDirInfo.GetFiles("*.browser");
if (browserFiles == null || browserFiles.Length == 0) {
return;
}
foreach(FileInfo browserFile in browserFiles) {
AddFile(browserFile.FullName);
}
// First parse the browser files.
ProcessBrowserFiles();
// Then parse custom browser files.
ProcessCustomBrowserFiles();
// Uninstall previously installed generated assembly.
Uninstall();
//generate the source code, compile it, and gac it
GenerateAssembly();
// Restart w3svc service
RestartW3SVCIfNecessary();
}
internal bool UninstallInternal() {
// Remove existing strong name public token file
if (File.Exists(_publicKeyTokenFile)) {
File.Delete(_publicKeyTokenFile);
}
// Removing existing copy from GAC
GacUtil gacutil = new GacUtil();
bool assemblyRemoved = gacutil.GacUnInstall("ASP.BrowserCapsFactory, Version=" + ThisAssembly.Version + ", Culture=neutral");
if (!assemblyRemoved) {
return false;
}
return true;
}
[SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
public bool Uninstall() {
// Restart w3svc service
RestartW3SVCIfNecessary();
if (!UninstallInternal()) {
return false;
}
// Restart w3svc service again so applications get a fresh copy.
RestartW3SVCIfNecessary();
return true;
}
private void RestartW3SVCIfNecessary() {
#if !FEATURE_PAL
try {
// Dev10 bug 734918
// We should not fail when the w3svc service is not installed.
ServiceController[] services = ServiceController.GetServices();
ServiceController controller = services.SingleOrDefault(s => String.Equals(s.ServiceName, "W3SVC", StringComparison.OrdinalIgnoreCase));
if (controller == null) {
return;
}
ServiceControllerStatus status = controller.Status;
// Stop the service if it's not currently stopped or pending.
if (!status.Equals(ServiceControllerStatus.Stopped) &&
!status.Equals(ServiceControllerStatus.StopPending) &&
!status.Equals(ServiceControllerStatus.StartPending)) {
controller.Stop();
// Give it 5 minutes to stop
controller.WaitForStatus(ServiceControllerStatus.Stopped, new TimeSpan(0, 5, 0));
controller.Start();
// If the service was paused, pause it.
if (status.Equals(ServiceControllerStatus.Paused) || status.Equals(ServiceControllerStatus.PausePending)) {
controller.Pause();
}
}
}
catch (Exception ex) {
throw new InvalidOperationException(SR.GetString(SR.Browser_W3SVC_Failure_Helper_Text, ex));
}
#endif // !FEATURE_PAL
}
internal void ProcessBrowserFiles() {
ProcessBrowserFiles(false, String.Empty);
}
private string NoPathFileName(string fullPath) {
int lastSlash = fullPath.LastIndexOf("\\", StringComparison.Ordinal);
if(lastSlash > -1) {
return fullPath.Substring(lastSlash + 1);
}
return fullPath;
}
internal virtual void ProcessBrowserNode(XmlNode node, BrowserTree browserTree) {
BrowserDefinition browserInfo = null;
if (node.Name == "gateway") {
browserInfo = new GatewayDefinition(node);
}
else if (node.Name == "browser") {
browserInfo = new BrowserDefinition(node);
}
else {
Debug.Assert(node.Name == "defaultBrowser");
browserInfo = new BrowserDefinition(node, true);
}
BrowserDefinition oldNode = (BrowserDefinition)browserTree[browserInfo.Name];
if (oldNode != null) {
if (browserInfo.IsRefID) {
oldNode.MergeWithDefinition(browserInfo);
}
else {
throw new ConfigurationErrorsException(SR.GetString(SR.Duplicate_browser_id, browserInfo.ID), node);
}
}
else {
browserTree[browserInfo.Name] = browserInfo;
}
}
private void NormalizeAndValidateTree(BrowserTree browserTree, bool isDefaultBrowser) {
NormalizeAndValidateTree(browserTree, isDefaultBrowser, false);
}
private void NormalizeAndValidateTree(BrowserTree browserTree, bool isDefaultBrowser, bool isCustomBrowser) {
//normalize the tree
foreach (DictionaryEntry entry in browserTree) {
BrowserDefinition bd = (BrowserDefinition)entry.Value;
string parentName = bd.ParentName;
BrowserDefinition parentBrowser = null;
if (IsRootNode(bd.Name)) {
continue;
}
if (parentName.Length > 0) {
parentBrowser = (BrowserDefinition)browserTree[parentName];
}
if (parentBrowser != null) {
if (bd.IsRefID) {
if (bd is GatewayDefinition) {
parentBrowser.RefGateways.Add(bd);
}
else {
parentBrowser.RefBrowsers.Add(bd);
}
}
else if (bd is GatewayDefinition) {
parentBrowser.Gateways.Add(bd);
}
else {
parentBrowser.Browsers.Add(bd);
}
}
else {
if (isCustomBrowser) {
throw new ConfigurationErrorsException(SR.GetString(SR.Browser_parentID_Not_Found, bd.ParentID), bd.XmlNode);
}
else {
HandleUnRecognizedParentElement(bd, isDefaultBrowser);
}
}
}
//validate the tree
//loop check
foreach (DictionaryEntry entry in browserTree) {
BrowserDefinition bd = (BrowserDefinition)entry.Value;
Hashtable loopCheck = new Hashtable();
BrowserDefinition currentBrowser = bd;
string currentId = currentBrowser.Name;
while (!IsRootNode(currentId)) {
if (loopCheck[currentId] != null) {
throw new ConfigurationErrorsException(SR.GetString(SR.Browser_Circular_Reference, currentId), currentBrowser.XmlNode);
}
loopCheck[currentId] = currentId;
currentBrowser = (BrowserDefinition)browserTree[currentBrowser.ParentName];
//in app-level, parent can exist in machine level
if (currentBrowser == null) {
break;
}
currentId = currentBrowser.Name;
}
}
}
private void SetCustomTreeRoots(BrowserTree browserTree, int index) {
foreach (DictionaryEntry entry in browserTree) {
BrowserDefinition bd = (BrowserDefinition)entry.Value;
if (bd.ParentName == null) {
_customTreeNames[index] = bd.Name;
break;
}
}
}
// Now that we support adding custom browser hierarchies, root nodes other than Default are permitted.
private bool IsRootNode(string nodeName) {
if (String.Compare(nodeName, "Default", StringComparison.OrdinalIgnoreCase) == 0)
return true;
foreach (string treeRootName in _customTreeNames) {
if (String.Compare(nodeName, treeRootName, StringComparison.OrdinalIgnoreCase) == 0) {
return true;
}
}
return false;
}
[SuppressMessage("Microsoft.Security.Xml", "CA3056:UseXmlReaderForLoad", Justification = "Developer-controlled .xml files in application directory are implicitly trusted by ASP.Net.")]
protected void ProcessBrowserFiles(bool useVirtualPath, string virtualDir) {
_browserTree = new BrowserTree();
_defaultTree = new BrowserTree();
_customTreeNames = new ArrayList();
if (_browserFileList == null) {
_browserFileList = new ArrayList();
}
_browserFileList.Sort();
//#if OPTIMIZE_FOR_DESKTOP_BROWSER
string mozillaFile = null;
string ieFile = null;
string operaFile = null;
// DevDivBugs 180962
// IE, Mozilla and Opera are first-class browsers. Their User-Agent profiles need to be compared to the UA profile
// of the HTTP request before other browsers. We put them to the head of the list so that the generated browser capabilities
// code will try to match them before other browsers.
foreach (String filePath in _browserFileList) {
if (filePath.EndsWith("ie.browser", StringComparison.OrdinalIgnoreCase)) {
ieFile = filePath;
}
else if (filePath.EndsWith("mozilla.browser", StringComparison.OrdinalIgnoreCase)) {
mozillaFile = filePath;
}
else if (filePath.EndsWith("opera.browser", StringComparison.OrdinalIgnoreCase)) {
operaFile = filePath;
break;
}
}
if (ieFile != null) {
_browserFileList.Remove(ieFile);
_browserFileList.Insert(0, ieFile);
}
if (mozillaFile != null) {
_browserFileList.Remove(mozillaFile);
_browserFileList.Insert(1, mozillaFile);
}
if (operaFile != null) {
_browserFileList.Remove(operaFile);
_browserFileList.Insert(2, operaFile);
}
//#endif
foreach (string fileName in _browserFileList) {
XmlDocument doc = new ConfigXmlDocument();
try {
doc.Load(fileName);
XmlNode rootNode = doc.DocumentElement;
if(rootNode.Name != "browsers") {
if(useVirtualPath) {
throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, 1);
}
else {
throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, fileName, null /*sourceCode*/, 1);
}
}
foreach (XmlNode node in rootNode.ChildNodes) {
if (node.NodeType != XmlNodeType.Element)
continue;
if (node.Name == "browser" || node.Name == "gateway") {
ProcessBrowserNode(node, _browserTree);
}
else if (node.Name == "defaultBrowser") {
ProcessBrowserNode(node, _defaultTree);
}
else {
HandlerBase.ThrowUnrecognizedElement(node);
}
}
}
catch (XmlException e) {
if(useVirtualPath) {
throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber);
}
else {
throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber);
}
}
catch (XmlSchemaException e) {
if(useVirtualPath) {
throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber);
}
else {
throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber);
}
}
}
NormalizeAndValidateTree(_browserTree, false);
NormalizeAndValidateTree(_defaultTree, true);
BrowserDefinition defaultBrowser = (BrowserDefinition)_browserTree["Default"];
if (defaultBrowser != null) {
AddBrowserToCollectionRecursive(defaultBrowser, 0);
}
}
internal void ProcessCustomBrowserFiles() {
ProcessCustomBrowserFiles(false, String.Empty);
}
[SuppressMessage("Microsoft.Security.Xml", "CA3056:UseXmlReaderForLoad", Justification = "Developer-controlled .xml files in application directory are implicitly trusted by ASP.Net.")]
internal void ProcessCustomBrowserFiles(bool useVirtualPath, string virtualDir) {
//get all custom browser files and put them in the "tree"
DirectoryInfo browserDirInfo = null;
DirectoryInfo[] browserSubDirectories = null;
DirectoryInfo[] allBrowserSubDirectories = null;
ArrayList customBrowserFileNames;
_customTreeList = new ArrayList();
_customBrowserFileLists = new ArrayList();
_customBrowserDefinitionCollections = new ArrayList();
/* Machine Level Custom Browsers */
if (useVirtualPath == false) {
browserDirInfo = new DirectoryInfo(_browsersDirectory);
}
/* Application Level Custom Browsers */
else {
browserDirInfo = new DirectoryInfo(HostingEnvironment.MapPathInternal(virtualDir));
}
allBrowserSubDirectories = browserDirInfo.GetDirectories();
int j = 0;
int length = allBrowserSubDirectories.Length;
browserSubDirectories = new DirectoryInfo[length];
for (int i = 0; i < length; i++) {
if ((allBrowserSubDirectories[i].Attributes & FileAttributes.Hidden) != FileAttributes.Hidden) {
browserSubDirectories[j] = allBrowserSubDirectories[i];
j++;
}
}
Array.Resize(ref browserSubDirectories, j);
for (int i = 0; i < browserSubDirectories.Length; i++) {
/* Recursively Into Subdirectories */
FileInfo[] browserFiles = GetFilesNotHidden(browserSubDirectories[i], browserDirInfo);
if (browserFiles == null || browserFiles.Length == 0) {
continue;
}
BrowserTree customTree = new BrowserTree();
_customTreeList.Add(customTree);
_customTreeNames.Add(browserSubDirectories[i].Name);
customBrowserFileNames = new ArrayList();
foreach (FileInfo browserFile in browserFiles) {
customBrowserFileNames.Add(browserFile.FullName);
}
_customBrowserFileLists.Add(customBrowserFileNames);
}
for (int i = 0; i < _customBrowserFileLists.Count; i++) {
ArrayList fileNames = (ArrayList)_customBrowserFileLists[i];
foreach (string fileName in fileNames) {
XmlDocument doc = new ConfigXmlDocument();
try {
doc.Load(fileName);
XmlNode rootNode = doc.DocumentElement;
if (rootNode.Name != "browsers") {
if (useVirtualPath) {
throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, 1);
}
else {
throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, fileName, null /*sourceCode*/, 1);
}
}
foreach (XmlNode node in rootNode.ChildNodes) {
if (node.NodeType != XmlNodeType.Element) {
continue;
}
if (node.Name == "browser" || node.Name == "gateway") {
ProcessBrowserNode(node, (BrowserTree)_customTreeList[i]);
}
else {
HandlerBase.ThrowUnrecognizedElement(node);
}
}
}
catch (XmlException e) {
if (useVirtualPath) {
throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber);
}
else {
throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber);
}
}
catch (XmlSchemaException e) {
if (useVirtualPath) {
throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber);
}
else {
throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber);
}
}
}
SetCustomTreeRoots((BrowserTree)_customTreeList[i], i);
NormalizeAndValidateTree((BrowserTree)_customTreeList[i], false, true);
_customBrowserDefinitionCollections.Add(new BrowserDefinitionCollection());
AddCustomBrowserToCollectionRecursive((BrowserDefinition)(((BrowserTree)_customTreeList[i])[_customTreeNames[i]]), 0, i);
}
}
internal void AddCustomBrowserToCollectionRecursive(BrowserDefinition bd, int depth, int index) {
if(_customBrowserDefinitionCollections[index] == null) {
_customBrowserDefinitionCollections[index] = new BrowserDefinitionCollection();
}
bd.Depth = depth;
bd.IsDeviceNode = true;
((BrowserDefinitionCollection)_customBrowserDefinitionCollections[index]).Add(bd);
foreach (BrowserDefinition childBrowser in bd.Browsers) {
AddCustomBrowserToCollectionRecursive(childBrowser, depth + 1, index);
}
}
internal void AddBrowserToCollectionRecursive(BrowserDefinition bd, int depth) {
if (_browserDefinitionCollection == null) {
_browserDefinitionCollection = new BrowserDefinitionCollection();
}
bd.Depth = depth;
bd.IsDeviceNode = true;
_browserDefinitionCollection.Add(bd);
foreach(BrowserDefinition childBrowser in bd.Browsers) {
AddBrowserToCollectionRecursive(childBrowser, depth + 1);
}
}
internal virtual void HandleUnRecognizedParentElement(BrowserDefinition bd, bool isDefault) {
throw new ConfigurationErrorsException(SR.GetString(SR.Browser_parentID_Not_Found, bd.ParentID), bd.XmlNode);
}
private static FileInfo[] GetFilesNotHidden(DirectoryInfo rootDirectory, DirectoryInfo browserDirInfo) {
ArrayList fileList = new ArrayList();
FileInfo[] files;
DirectoryInfo[] subDirectories = rootDirectory.GetDirectories("*", SearchOption.AllDirectories);
files = rootDirectory.GetFiles("*.browser", SearchOption.TopDirectoryOnly);
fileList.AddRange(files);
for (int i = 0; i < subDirectories.Length; i++) {
if ((HasHiddenParent(subDirectories[i], browserDirInfo) == false)) {
files = subDirectories[i].GetFiles("*.browser", SearchOption.TopDirectoryOnly);
fileList.AddRange(files);
}
}
return ((FileInfo [])fileList.ToArray(typeof(FileInfo)));
}
private static bool HasHiddenParent(DirectoryInfo directory, DirectoryInfo browserDirInfo) {
while(!String.Equals(directory.Parent.Name, browserDirInfo.Name)) {
if ((directory.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) {
return true;
}
directory = directory.Parent;
}
return false;
}
//generate the code from the parsed BrowserDefinitionTree
//compile it, and install it in the gac
private void GenerateAssembly() {
Debug.Assert(_browserTree != null);
BrowserDefinition root = (BrowserDefinition)_browserTree["Default"];
BrowserDefinition defaultRoot = (BrowserDefinition)_defaultTree["Default"];
ArrayList customTreeRoots = new ArrayList();
for (int i = 0; i < _customTreeNames.Count; i++) {
customTreeRoots.Add((BrowserDefinition)(((BrowserTree)_customTreeList[i])[_customTreeNames[i]]));
}
//create a CodeCompileUnit
//add a CodeNamespace object to the CodeCompileUnit
//add a CodeTypeDeclaration to the CodeNamespace
//add all the members of the type/class to the CodeTypeDeclaration
//use a CodeGenerator to generate code from the CodeCompileUnit
//a CodeDomProvider can provide a CodeGenerator
//translate the BrowserDefinition tree to code
CSharpCodeProvider cscp = new CSharpCodeProvider();
// namespace System.Web.BrowserCapsFactory
CodeCompileUnit ccu = new CodeCompileUnit();
//add strong-name key pair for
CodeAttributeDeclaration declaration = new CodeAttributeDeclaration(
"System.Reflection.AssemblyKeyFile",
new CodeAttributeArgument[] {
new CodeAttributeArgument(new CodePrimitiveExpression(_strongNameKeyFileName))});
CodeAttributeDeclaration aptca = new CodeAttributeDeclaration(
"System.Security.AllowPartiallyTrustedCallers");
ccu.AssemblyCustomAttributes.Add(aptca);
ccu.AssemblyCustomAttributes.Add(declaration);
//add version number for it so it can distinguished in future versions
declaration = new CodeAttributeDeclaration(
"System.Reflection.AssemblyVersion",
new CodeAttributeArgument[] {
new CodeAttributeArgument(new CodePrimitiveExpression(ThisAssembly.Version))});
ccu.AssemblyCustomAttributes.Add(declaration);
CodeNamespace cnamespace = new CodeNamespace("ASP");
//GEN: using System;
cnamespace.Imports.Add(new CodeNamespaceImport("System"));
//GEN: using System.Web;
cnamespace.Imports.Add(new CodeNamespaceImport("System.Web"));
//GEN: using System.Web.Configuration;
cnamespace.Imports.Add(new CodeNamespaceImport("System.Web.Configuration"));
//GEN: using System.Reflection;
cnamespace.Imports.Add(new CodeNamespaceImport("System.Reflection"));
//GEN: class BrowserCapabilitiesFactory
ccu.Namespaces.Add(cnamespace);
CodeTypeDeclaration factoryType = new CodeTypeDeclaration("BrowserCapabilitiesFactory");
factoryType.Attributes = MemberAttributes.Private;
factoryType.IsClass = true;
factoryType.Name = TypeName;
factoryType.BaseTypes.Add(new CodeTypeReference("System.Web.Configuration.BrowserCapabilitiesFactoryBase"));
cnamespace.Types.Add(factoryType);
//GEN: protected override object ConfigureBrowserCapabilities(NameValueCollection headers, HttpBrowserCapabilities browserCaps)
CodeMemberMethod method = new CodeMemberMethod();
method.Attributes = MemberAttributes.Override | MemberAttributes.Public;
method.ReturnType = new CodeTypeReference(typeof(void));
method.Name = "ConfigureBrowserCapabilities";
CodeParameterDeclarationExpression cpde = new CodeParameterDeclarationExpression(typeof(NameValueCollection), _headersRefName);
method.Parameters.Add(cpde);
cpde = new CodeParameterDeclarationExpression(typeof(HttpBrowserCapabilities), browserCapsVariable);
method.Parameters.Add(cpde);
factoryType.Members.Add(method);
GenerateSingleProcessCall(root, method);
for (int i = 0; i < customTreeRoots.Count; i++) {
GenerateSingleProcessCall((BrowserDefinition)customTreeRoots[i], method);
}
//GEN: if(this.IsBrowserUnknown(browserCaps) == false) return;
CodeConditionStatement istatement = new CodeConditionStatement();
CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "IsBrowserUnknown");
cmie.Parameters.Add(_browserCapsRefExpr);
istatement.Condition = new CodeBinaryOperatorExpression(cmie, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false));
istatement.TrueStatements.Add(new CodeMethodReturnStatement());
method.Statements.Add(istatement);
if(defaultRoot != null) {
GenerateSingleProcessCall(defaultRoot, method, "Default");
}
for (int i = 0; i < customTreeRoots.Count; i++) {
foreach (DictionaryEntry entry in (BrowserTree)_customTreeList[i]) {
BrowserDefinition bd = entry.Value as BrowserDefinition;
Debug.Assert(bd != null);
GenerateProcessMethod(bd, factoryType);
}
}
//GenerateCallsToProcessMethods(root, method);
foreach (DictionaryEntry entry in _browserTree) {
BrowserDefinition bd = entry.Value as BrowserDefinition;
Debug.Assert(bd != null);
GenerateProcessMethod(bd, factoryType);
}
foreach (DictionaryEntry entry in _defaultTree) {
BrowserDefinition bd = entry.Value as BrowserDefinition;
Debug.Assert(bd != null);
GenerateProcessMethod(bd, factoryType, "Default");
}
GenerateOverrideMatchedHeaders(factoryType);
GenerateOverrideBrowserElements(factoryType);
//TODO: don't actually generate the code, just compile it in memory
TextWriter twriter = new StreamWriter(new FileStream(_browsersDirectory + "\\BrowserCapsFactory.cs", FileMode.Create));
try {
cscp.GenerateCodeFromCompileUnit(ccu, twriter, null);
}
finally {
if(twriter != null)
twriter.Close();
}
CompilationSection compConfig = MTConfigUtil.GetCompilationAppConfig();
bool debug = compConfig.Debug;
#if !PLATFORM_UNIX // File system paths must account for UNIX
string strongNameFile = _browsersDirectory + "\\" + _strongNameKeyFileName;
#else // !PLATFORM_UNIX
string strongNameFile = _browsersDirectory + "/" + _strongNameKeyFileName;
#endif // !PLATFORM_UNIX
// Generate strong name file
StrongNameUtility.GenerateStrongNameFile(strongNameFile);
//TODO: do not use interim file: CompileAssemblyFromDom instead
string[] referencedAssemblies = new string[2] { "System.dll", "System.Web.dll" };
CompilerParameters compilerParameters = new CompilerParameters(referencedAssemblies, "ASP.BrowserCapsFactory", debug /* includeDebugInformation */ );
compilerParameters.GenerateInMemory = false;
compilerParameters.OutputAssembly = _browsersDirectory + "\\ASP.BrowserCapsFactory.dll";
CompilerResults results = null;
try {
results = cscp.CompileAssemblyFromFile(compilerParameters, _browsersDirectory + "\\BrowserCapsFactory.cs");
}
finally {
if (File.Exists(strongNameFile)) {
File.Delete(strongNameFile);
}
}
if (results.NativeCompilerReturnValue != 0 || results.Errors.HasErrors) {
foreach (CompilerError error in results.Errors) {
if (!error.IsWarning) {
throw new HttpCompileException(error.ErrorText);
}
}
throw new HttpCompileException(SR.GetString(SR.Browser_compile_error));
}
Assembly resultAssembly = results.CompiledAssembly;
GacUtil gacutil = new GacUtil();
gacutil.GacInstall(resultAssembly.Location);
SavePublicKeyTokenFile(_publicKeyTokenFile, resultAssembly.GetName().GetPublicKeyToken());
}
private void SavePublicKeyTokenFile(string filename, byte[] publicKeyToken) {
using (FileStream pktStream = new FileStream(filename, FileMode.Create, FileAccess.Write)) {
using (StreamWriter pktWriter = new StreamWriter(pktStream)) {
foreach (byte b in publicKeyToken) {
pktWriter.Write("{0:X2}", b);
}
}
}
}
private static string LoadPublicKeyTokenFromFile(string filename) {
IStackWalk fileReadAccess = InternalSecurityPermissions.FileReadAccess(filename);
Debug.Assert(fileReadAccess != null);
fileReadAccess.Assert();
if (!File.Exists(filename)) {
return null;
}
try {
using (FileStream pktStream = new FileStream(filename, FileMode.Open, FileAccess.Read)) {
using (StreamReader pktReader = new StreamReader(pktStream)) {
return pktReader.ReadLine();
}
}
}
catch (IOException) {
if (HttpRuntime.HasFilePermission(filename)) {
throw;
}
// Don't throw exception if we don't have permission to the file.
return null;
}
finally {
CodeAccessPermission.RevertAssert();
}
}
internal void GenerateOverrideBrowserElements(CodeTypeDeclaration typeDeclaration) {
// Don't generate the property if there's nothing to override.
if (_browserDefinitionCollection == null) {
return;
}
// GEN:
// protected override void PopulateBrowserElements(IDictionary dictionary) {
// dictionary["Default"] = new Triplet(null, "default description", 0 /*depth_of_node */);
// dictionary["Up"] = new Triplet("Default", "up Description", 1 /*depth_of_node */);
// }
CodeMemberMethod method = new CodeMemberMethod();
method.Name = _browserElementsMethodName;
method.Attributes = MemberAttributes.Override | MemberAttributes.Family;
method.ReturnType = new CodeTypeReference(typeof(void));
CodeParameterDeclarationExpression parameter =
new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IDictionary)), _dictionaryRefName);
method.Parameters.Add(parameter);
typeDeclaration.Members.Add(method);
CodeMethodReferenceExpression baseMethod = new CodeMethodReferenceExpression(new CodeBaseReferenceExpression(), _browserElementsMethodName);
CodeMethodInvokeExpression baseInvoke = new CodeMethodInvokeExpression(baseMethod, new CodeExpression[] { _dictionaryRefExpr });
method.Statements.Add(baseInvoke);
foreach(BrowserDefinition bd in _browserDefinitionCollection) {
if (!bd.IsDeviceNode)
continue;
Debug.Assert(!(bd is GatewayDefinition));
CodeAssignStatement cas = new CodeAssignStatement();
cas.Left = new CodeIndexerExpression(_dictionaryRefExpr, new CodeExpression[] {
new CodePrimitiveExpression(bd.ID)
});
cas.Right = new CodeObjectCreateExpression(typeof(Triplet),
new CodeExpression[] {
new CodePrimitiveExpression(bd.ParentName),
new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "Empty"),
new CodePrimitiveExpression(bd.Depth)});
method.Statements.Add(cas);
}
for (int i = 0; i < _customTreeNames.Count; i++) {
foreach (BrowserDefinition bd in (BrowserDefinitionCollection)_customBrowserDefinitionCollections[i]) {
if (!bd.IsDeviceNode)
continue;
Debug.Assert(!(bd is GatewayDefinition));
CodeAssignStatement cas = new CodeAssignStatement();
cas.Left = new CodeIndexerExpression(_dictionaryRefExpr, new CodeExpression[] {
new CodePrimitiveExpression(bd.ID)
});
cas.Right = new CodeObjectCreateExpression(typeof(Triplet),
new CodeExpression[] {
new CodePrimitiveExpression(bd.ParentName),
new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "Empty"),
new CodePrimitiveExpression(bd.Depth)});
method.Statements.Add(cas);
}
}
}
internal void GenerateOverrideMatchedHeaders(CodeTypeDeclaration typeDeclaration) {
// GEN:
// protected override void PopulateMatchedHeaders(IDictionary dictionary) {
// base.PopulateMatchedHeaders(dictionary);
//
// dictionary["header0"] = null;
// dictionary["header1"] = null;
// }
CodeMemberMethod method = new CodeMemberMethod();
method.Name = _matchedHeadersMethodName;
method.Attributes = MemberAttributes.Override | MemberAttributes.Family;
method.ReturnType = new CodeTypeReference(typeof(void));
CodeParameterDeclarationExpression parameter =
new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IDictionary)), _dictionaryRefName);
method.Parameters.Add(parameter);
typeDeclaration.Members.Add(method);
CodeMethodReferenceExpression baseMethod = new CodeMethodReferenceExpression(new CodeBaseReferenceExpression(), _matchedHeadersMethodName);
CodeMethodInvokeExpression baseInvoke = new CodeMethodInvokeExpression(baseMethod, new CodeExpression[] { _dictionaryRefExpr });
method.Statements.Add(baseInvoke);
foreach(String header in _headers) {
CodeAssignStatement cas = new CodeAssignStatement();
cas.Left = new CodeIndexerExpression(_dictionaryRefExpr, new CodeExpression[] {
new CodePrimitiveExpression(header)
});
cas.Right = new CodePrimitiveExpression(null);
method.Statements.Add(cas);
}
}
internal void GenerateProcessMethod(BrowserDefinition bd, CodeTypeDeclaration ctd) {
GenerateProcessMethod(bd, ctd, String.Empty);
}
//generate the xxxProcess method for an individual BrowserDefinition
internal void GenerateProcessMethod(BrowserDefinition bd, CodeTypeDeclaration ctd, string prefix) {
//GEN: internal bool XxxProcess(NameValueCollection headers, HttpBrowserCapabilities browserCaps)
CodeMemberMethod cmm = new CodeMemberMethod();
cmm.Name = prefix + bd.Name + "Process";
cmm.ReturnType = new CodeTypeReference(typeof(bool));
cmm.Attributes = MemberAttributes.Private;
CodeParameterDeclarationExpression cpde = new CodeParameterDeclarationExpression(typeof(NameValueCollection), _headersRefName);
cmm.Parameters.Add(cpde);
cpde = new CodeParameterDeclarationExpression(typeof(HttpBrowserCapabilities), browserCapsVariable);
cmm.Parameters.Add(cpde);
bool regexWorkerGenerated = false;
GenerateIdentificationCode(bd, cmm, ref regexWorkerGenerated);
GenerateCapturesCode(bd, cmm, ref regexWorkerGenerated);
GenerateSetCapabilitiesCode(bd, cmm, ref regexWorkerGenerated);
GenerateSetAdaptersCode(bd, cmm);
// Only add the browser node to the browser collection if it represents a device.
if (bd.IsDeviceNode) {
Debug.Assert(!(bd is GatewayDefinition));
//GEN: browserCaps.AddBrowser("xxx");
CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression(browserCapsVariable), "AddBrowser");
cmie.Parameters.Add(new CodePrimitiveExpression(bd.ID));
cmm.Statements.Add(cmie);
}
// Generate ref gateway elements
foreach (BrowserDefinition b in bd.RefGateways) {
AddComment("ref gateways, parent=" + bd.ID, cmm);
GenerateSingleProcessCall(b, cmm);
}
if ((GenerateOverrides) && (prefix.Length == 0)) {
//Gen: protected virtual void XxxProcessGateways(NameValueCollection headers, HttpBrowserCapabilities browserCaps) ;
string methodName = prefix + bd.Name + "ProcessGateways";
GenerateChildProcessMethod(methodName, ctd, false);
//Gen: XxxProcessGateways(headers, browserCaps) ;
GenerateChildProcessInvokeExpression(methodName, cmm, false);
}
foreach(BrowserDefinition b in bd.Gateways) {
AddComment("gateway, parent=" + bd.ID, cmm);
GenerateSingleProcessCall(b, cmm);
}
if (GenerateOverrides) {
//GEN: bool ignoreApplicationBrowsers = true | false; //bd.Browsers.Count != 0
CodeVariableDeclarationStatement cvds = new CodeVariableDeclarationStatement(typeof(bool),
IgnoreApplicationBrowserVariableName, new CodePrimitiveExpression(bd.Browsers.Count != 0));
cmm.Statements.Add(cvds);
}
if (bd.Browsers.Count > 0) {
CodeStatementCollection statements = cmm.Statements;
AddComment("browser, parent=" + bd.ID, cmm);
foreach (BrowserDefinition b in bd.Browsers) {
statements = GenerateTrackedSingleProcessCall(statements, b, cmm, prefix);
}
if (GenerateOverrides) {
//GEN: ignoreApplicationBrowsers = false;
CodeAssignStatement codeAssignStmt = new CodeAssignStatement();
codeAssignStmt.Left = new CodeVariableReferenceExpression(IgnoreApplicationBrowserVariableName);
codeAssignStmt.Right = new CodePrimitiveExpression(false);
statements.Add(codeAssignStmt);
}
}
// Generate ref browser
foreach (BrowserDefinition b in bd.RefBrowsers) {
AddComment("ref browsers, parent=" + bd.ID, cmm);
if (b.IsDefaultBrowser) {
GenerateSingleProcessCall(b, cmm, "Default");
}
else {
GenerateSingleProcessCall(b, cmm);
}
}
if (GenerateOverrides) {
//Gen: protected virtual void XxxProcessBrowsers(bool ignoreApplicationBrowsers, NameValueCollection headers, HttpBrowserCapabilities browserCaps) ;
string methodName = prefix + bd.Name + "ProcessBrowsers";
GenerateChildProcessMethod(methodName, ctd, true);
//Gen: XxxProcessBrowsers(ignoreApplicationBrowsers, headers, browserCaps);
GenerateChildProcessInvokeExpression(methodName, cmm, true);
}
//GEN: return true;
CodeMethodReturnStatement cmrs = new CodeMethodReturnStatement(new CodePrimitiveExpression(true));
cmm.Statements.Add(cmrs);
ctd.Members.Add(cmm);
}
private void GenerateChildProcessInvokeExpression(string methodName, CodeMemberMethod cmm, bool generateTracker) {
//Gen: XxxProcessBrowsers(ignoreApplicationBrowsers, headers, browserCaps) ;
CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), methodName);
if (generateTracker) {
expr.Parameters.Add(new CodeVariableReferenceExpression(IgnoreApplicationBrowserVariableName));
}
expr.Parameters.Add(new CodeVariableReferenceExpression(_headersRefName));
expr.Parameters.Add(new CodeVariableReferenceExpression(browserCapsVariable));
cmm.Statements.Add(expr);
}
private void GenerateChildProcessMethod(string methodName, CodeTypeDeclaration ctd, bool generateTracker) {
//Gen: protected virtual void XxxProcessBrowsers(bool ignoreApplicationBrowsers, NameValueCollection headers, HttpBrowserCapabilities browserCaps) ;
CodeMemberMethod cmm= new CodeMemberMethod();
cmm.Name = methodName;
cmm.ReturnType = new CodeTypeReference(typeof(void));
cmm.Attributes = MemberAttributes.Family;
CodeParameterDeclarationExpression cpde = null;
if (generateTracker) {
cpde = new CodeParameterDeclarationExpression(typeof(bool), IgnoreApplicationBrowserVariableName);
cmm.Parameters.Add(cpde);
}
cpde = new CodeParameterDeclarationExpression(typeof(NameValueCollection), _headersRefName);
cmm.Parameters.Add(cpde);
cpde = new CodeParameterDeclarationExpression(typeof(HttpBrowserCapabilities), browserCapsVariable);
cmm.Parameters.Add(cpde);
ctd.Members.Add(cmm);
}
private void GenerateRegexWorkerIfNecessary(CodeMemberMethod cmm, ref bool regexWorkerGenerated) {
if (regexWorkerGenerated) {
return;
}
regexWorkerGenerated = true;
//GEN: RegexWorker regexWorker;
cmm.Statements.Add(new CodeVariableDeclarationStatement("RegexWorker", _regexWorkerRefName));
//GEN: regexWorker = new RegexWorker(browserCaps);
cmm.Statements.Add(new CodeAssignStatement(_regexWorkerRefExpr, new CodeObjectCreateExpression("RegexWorker", _browserCapsRefExpr)));
}
private void ReturnIfHeaderValueEmpty(CodeMemberMethod cmm, CodeVariableReferenceExpression varExpr) {
// GEN: if(String.IsNullOrEmpty(varExpr)) {
// GEN: return false;
// GEN: }
CodeConditionStatement emptyCheckStmt = new CodeConditionStatement();
CodeMethodReferenceExpression emptyCheckMethod = new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "IsNullOrEmpty");
CodeMethodInvokeExpression emptyCheckExpr = new CodeMethodInvokeExpression(emptyCheckMethod, varExpr);
emptyCheckStmt.Condition = emptyCheckExpr;
emptyCheckStmt.TrueStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(false)));
cmm.Statements.Add(emptyCheckStmt);
}
//generate part of the xxxProcess method for handling determining if the requesting
//browser meets the regexes for this browser
private void GenerateIdentificationCode(BrowserDefinition bd, CodeMemberMethod cmm, ref bool regexWorkerGenerated) {
//GEN: IDictionary dictionary;
cmm.Statements.Add(new CodeVariableDeclarationStatement(typeof(IDictionary), _dictionaryRefName));
//GEN: dictionary = browserCaps.Capabilities;
CodeAssignStatement assign = new CodeAssignStatement(
_dictionaryRefExpr,
new CodePropertyReferenceExpression(_browserCapsRefExpr, "Capabilities")
);
cmm.Statements.Add(assign);
bool disableOptimizedKey = false;
CodeVariableReferenceExpression result = null;
CodeVariableReferenceExpression headerValue = null;
if(bd.IdHeaderChecks.Count > 0) {
AddComment("Identification: check header matches", cmm);
for (int i = 0; i < bd.IdHeaderChecks.Count; i++) {
string matchedString = ((CheckPair)bd.IdHeaderChecks[i]).MatchString;
// Skip matching ".*"
if (matchedString.Equals(".*")) {
continue;
}
if (headerValue == null) {
headerValue = GenerateVarReference(cmm, typeof(string), "headerValue");
}
CodeAssignStatement valueAssignment = new CodeAssignStatement();
cmm.Statements.Add(valueAssignment);
valueAssignment.Left = headerValue;
if (((CheckPair)bd.IdHeaderChecks[i]).Header.Equals("User-Agent")) {
_headers.Add(String.Empty);
// GEN: headerValue = ((string)(browserCaps[String.Empty]));
valueAssignment.Right = new CodeCastExpression(typeof(string),
new CodeIndexerExpression(
new CodeVariableReferenceExpression(browserCapsVariable),
new CodeExpression[] {
new CodePropertyReferenceExpression(
new CodeTypeReferenceExpression(typeof(String)), "Empty") }));
}
else {
string header = ((CheckPair)bd.IdHeaderChecks[i]).Header;
_headers.Add(header);
//GEN: headerValue = ((String)headers["xxx"]);
valueAssignment.Right = new CodeCastExpression(typeof(string),
new CodeIndexerExpression(
_headersRefExpr,
new CodeExpression[] { new CodePrimitiveExpression(header) }
)
);
disableOptimizedKey = true;
}
// Don't need to use Regex if matching . only.
if (matchedString.Equals(".")) {
// Simply return if the header exists.
ReturnIfHeaderValueEmpty(cmm, headerValue);
continue;
}
if (result == null) {
result = GenerateVarReference(cmm, typeof(bool), _resultVarName);
}
GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated);
CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod);
cmie.Parameters.Add(headerValue);
cmie.Parameters.Add(new CodePrimitiveExpression(matchedString));
//GEN: result = regexWorker.ProcessRegex(headerValue, {matchedString});
assign = new CodeAssignStatement();
assign.Left = result;
assign.Right = cmie;
cmm.Statements.Add(assign);
//GEN: if(result == false) {
//GEN: return false;
//GEN: }
CodeConditionStatement istatement = new CodeConditionStatement();
if(((CheckPair)bd.IdHeaderChecks[i]).NonMatch) {
istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(true));
}
else {
istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false));
}
istatement.TrueStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(false)));
cmm.Statements.Add(istatement);
}
}
if (bd.IdCapabilityChecks.Count > 0) {
AddComment("Identification: check capability matches", cmm);
for (int i = 0; i < bd.IdCapabilityChecks.Count; i++) {
string matchedString = ((CheckPair)bd.IdCapabilityChecks[i]).MatchString;
// Skip matching ".*"
if (matchedString.Equals(".*")) {
continue;
}
if (headerValue == null) {
headerValue = GenerateVarReference(cmm, typeof(string), "headerValue");
}
CodeAssignStatement valueAssignment = new CodeAssignStatement();
cmm.Statements.Add(valueAssignment);
valueAssignment.Left = headerValue;
valueAssignment.Right = (new CodeCastExpression(typeof(string),
new CodeIndexerExpression(
_dictionaryRefExpr,
new CodeExpression[] {
new CodePrimitiveExpression(((CheckPair)bd.IdCapabilityChecks[i]).Header)
}
)
));
// Don't need to use Regex if matching . only.
if (matchedString.Equals(".")) {
continue;
}
if (result == null) {
result = GenerateVarReference(cmm, typeof(bool), _resultVarName);
}
GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated);
//GEN: result = regexWorker.ProcessRegex((string)dictionary["xxxCapability"], "xxxRegexString");
CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod);
cmie.Parameters.Add(headerValue);
cmie.Parameters.Add(new CodePrimitiveExpression(matchedString));
assign = new CodeAssignStatement();
assign.Left = result;
assign.Right = cmie;
cmm.Statements.Add(assign);
//GEN: if(result == false) {
//GEN: return false;
//GEN: }
CodeConditionStatement istatement = new CodeConditionStatement();
if (((CheckPair)bd.IdCapabilityChecks[i]).NonMatch) {
istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(true));
}
else {
istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false));
}
istatement.TrueStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(false)));
cmm.Statements.Add(istatement);
}
}
//GEN: browserCaps.DisableOptimizedCacheKey();
if (disableOptimizedKey) {
CodeMethodInvokeExpression cme = new CodeMethodInvokeExpression(_browserCapsRefExpr, _disableOptimizedCacheKeyMethodName);
cmm.Statements.Add(cme);
}
}
private CodeVariableReferenceExpression GenerateVarReference(CodeMemberMethod cmm, Type varType, string varName) {
//GEN: {varType} {varName};
cmm.Statements.Add(new CodeVariableDeclarationStatement(varType, varName));
return new CodeVariableReferenceExpression(varName);
}
//generate part of the xxxProcess method for running and storing the capture regexes
private void GenerateCapturesCode(BrowserDefinition bd, CodeMemberMethod cmm, ref bool regexWorkerGenerated) {
if ((bd.CaptureHeaderChecks.Count == 0) && (bd.CaptureCapabilityChecks.Count == 0)) {
return;
}
if(bd.CaptureHeaderChecks.Count > 0) {
AddComment("Capture: header values", cmm);
for(int i = 0; i < bd.CaptureHeaderChecks.Count; i++) {
string matchedString = ((CheckPair)bd.CaptureHeaderChecks[i]).MatchString;
if (matchedString.Equals(".*")) {
continue;
}
GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated);
CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod);
if (((CheckPair)bd.CaptureHeaderChecks[i]).Header.Equals("User-Agent")) {
_headers.Add(String.Empty);
cmie.Parameters.Add(new CodeCastExpression(typeof(string),
new CodeIndexerExpression(new CodeVariableReferenceExpression(browserCapsVariable), new CodeExpression[] {
new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "Empty") })));
}
else {
string header = ((CheckPair)bd.CaptureHeaderChecks[i]).Header;
_headers.Add(header);
//GEN: regexWorker.ProcessRegex((string)headers["xxx"], "xxxRegexString");
cmie.Parameters.Add(
new CodeCastExpression(typeof(string),
new CodeIndexerExpression(
_headersRefExpr,
new CodeExpression[] { new CodePrimitiveExpression(header) }
)
)
);
}
cmie.Parameters.Add(new CodePrimitiveExpression(matchedString));
cmm.Statements.Add(cmie);
}
}
if (bd.CaptureCapabilityChecks.Count > 0) {
AddComment("Capture: capability values", cmm);
for(int i = 0; i < bd.CaptureCapabilityChecks.Count; i++) {
string matchedString = ((CheckPair)bd.CaptureCapabilityChecks[i]).MatchString;
if (matchedString.Equals(".*")) {
continue;
}
GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated);
//GEN: regexWorker.ProcessRegex((string)dictionary["xxxCapability"], "xxxRegexString");
CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod);
cmie.Parameters.Add(
new CodeCastExpression(typeof(string),
new CodeIndexerExpression(
_dictionaryRefExpr,
new CodeExpression[] { new CodePrimitiveExpression(((CheckPair)bd.CaptureCapabilityChecks[i]).Header) }
)
)
);
cmie.Parameters.Add(new CodePrimitiveExpression(matchedString));
cmm.Statements.Add(cmie);
}
}
}
//generate part of the xxxProcess method for assigning capability values
private void GenerateSetCapabilitiesCode(BrowserDefinition bd, CodeMemberMethod cmm, ref bool regexWorkerGenerated) {
//GEN: browserCaps[aaa] = "bbb";
//GEN: browserCaps[xxx] = "yyy";
NameValueCollection nvc = bd.Capabilities;
CodeAssignStatement assign;
AddComment("Capabilities: set capabilities", cmm);
foreach (string s in nvc.Keys) {
string capsString = nvc[s];
//GEN: dictionary["xxx"] = regexWorker["xxx"];
assign = new CodeAssignStatement();
assign.Left = new CodeIndexerExpression(
_dictionaryRefExpr,
new CodeExpression[] { new CodePrimitiveExpression(s) } );
CodePrimitiveExpression capabilityExpr = new CodePrimitiveExpression(capsString);
if (RegexWorker.RefPat.Match(capsString).Success) {
GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated);
assign.Right = new CodeIndexerExpression(
_regexWorkerRefExpr,
new CodeExpression[] {capabilityExpr});
}
else {
assign.Right = capabilityExpr;
}
cmm.Statements.Add(assign);
}
}
//generate part of the xxxProcess method for setting specific adapters for this browser
internal void GenerateSetAdaptersCode(BrowserDefinition bd, CodeMemberMethod cmm) {
//GEN: browserCaps.Adapters[xxxControl] = yyyAdapter;
foreach (DictionaryEntry entry in bd.Adapters) {
string controlString = (string)entry.Key;
string adapterString = (string)entry.Value;
CodePropertyReferenceExpression cpre = new CodePropertyReferenceExpression(_browserCapsRefExpr, "Adapters");
CodeIndexerExpression indexerExpression = new CodeIndexerExpression(
cpre,
new CodeExpression[] { new CodePrimitiveExpression(controlString) }
);
CodeAssignStatement assignAdapter = new CodeAssignStatement();
assignAdapter.Left = indexerExpression;
assignAdapter.Right = new CodePrimitiveExpression(adapterString);
cmm.Statements.Add(assignAdapter);
}
//GEN: browser.HtmlTextWriter = xxxHtmlTextWriter;
if(bd.HtmlTextWriterString != null) {
CodeAssignStatement assignHtmlTextWriter = new CodeAssignStatement();
assignHtmlTextWriter.Left = new CodePropertyReferenceExpression(_browserCapsRefExpr, "HtmlTextWriter");
assignHtmlTextWriter.Right = new CodePrimitiveExpression(bd.HtmlTextWriterString);
cmm.Statements.Add(assignHtmlTextWriter);
}
return;
}
internal void AddComment(string comment, CodeMemberMethod cmm) {
cmm.Statements.Add(new CodeCommentStatement(comment));
}
internal CodeStatementCollection GenerateTrackedSingleProcessCall(CodeStatementCollection stmts, BrowserDefinition bd, CodeMemberMethod cmm) {
return GenerateTrackedSingleProcessCall(stmts, bd, cmm, String.Empty);
}
internal CodeStatementCollection GenerateTrackedSingleProcessCall(CodeStatementCollection stmts, BrowserDefinition bd, CodeMemberMethod cmm, string prefix) {
//GEN: if (xProcess(headers, browserCaps)) {
// }
// else {
// ...
// }
CodeMethodInvokeExpression xProcess = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), prefix + bd.Name + "Process");
xProcess.Parameters.Add(new CodeVariableReferenceExpression(_headersRefName));
xProcess.Parameters.Add(new CodeVariableReferenceExpression(browserCapsVariable));
CodeConditionStatement conditionStmt = new CodeConditionStatement();
conditionStmt.Condition = xProcess;
stmts.Add(conditionStmt);
return conditionStmt.FalseStatements;
}
internal void GenerateSingleProcessCall(BrowserDefinition bd, CodeMemberMethod cmm) {
GenerateSingleProcessCall(bd, cmm, String.Empty);
}
//generate code to call the xxxProcess for a given browser
//and store the result in a local variable
internal void GenerateSingleProcessCall(BrowserDefinition bd, CodeMemberMethod cmm, string prefix) {
//GEN: xProcess(headers, browserCaps);
CodeMethodInvokeExpression xProcess = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), prefix + bd.Name + "Process");
xProcess.Parameters.Add(new CodeVariableReferenceExpression(_headersRefName));
xProcess.Parameters.Add(new CodeVariableReferenceExpression(browserCapsVariable));
cmm.Statements.Add(xProcess);
}
}
}
|