BrowserCapabilitiesCodeGenerator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / xsp / System / Web / Configuration / BrowserCapabilitiesCodeGenerator.cs / 3 / BrowserCapabilitiesCodeGenerator.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

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.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.CSharp; 

    [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; 
                    } 

                    _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 { 
                ServiceController controller = new ServiceController("W3SVC"); 
                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;
        }

        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) {
                        string noPathFileName = String.Empty; 
                        int lastSlash = fileName.LastIndexOf("\\", StringComparison.Ordinal);
                        if(lastSlash > -1) {
                            noPathFileName = fileName.Substring(lastSlash);
                        } 
                        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);
        } 
 
        internal void ProcessCustomBrowserFiles(bool useVirtualPath, string virtualDir) {
            //get all custom browser files and put them in the "tree" 
            DirectoryInfo browserDirInfo = null;
            DirectoryInfo[] browserSubDirectories = 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));
            } 
 
            browserSubDirectories = browserDirInfo.GetDirectories();
            for (int i = 0; i < browserSubDirectories.Length; i++) { 
                /* Recursively Into Subdirectories */
                FileInfo[] browserFiles = browserSubDirectories[i].GetFiles("*.browser", SearchOption.AllDirectories);

                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) { 
                            string noPathFileName = String.Empty;
                            int lastSlash = fileName.LastIndexOf("\\", StringComparison.Ordinal);
                            if (lastSlash > -1) {
                                noPathFileName = fileName.Substring(lastSlash); 
                            }
                            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);
        } 

        //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);
 
            //
            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 = RuntimeConfig.GetAppConfig().Compilation; 
 
            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);
 
            //
            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);
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

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.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.CSharp; 

    [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; 
                    } 

                    _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 { 
                ServiceController controller = new ServiceController("W3SVC"); 
                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;
        }

        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) {
                        string noPathFileName = String.Empty; 
                        int lastSlash = fileName.LastIndexOf("\\", StringComparison.Ordinal);
                        if(lastSlash > -1) {
                            noPathFileName = fileName.Substring(lastSlash);
                        } 
                        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);
        } 
 
        internal void ProcessCustomBrowserFiles(bool useVirtualPath, string virtualDir) {
            //get all custom browser files and put them in the "tree" 
            DirectoryInfo browserDirInfo = null;
            DirectoryInfo[] browserSubDirectories = 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));
            } 
 
            browserSubDirectories = browserDirInfo.GetDirectories();
            for (int i = 0; i < browserSubDirectories.Length; i++) { 
                /* Recursively Into Subdirectories */
                FileInfo[] browserFiles = browserSubDirectories[i].GetFiles("*.browser", SearchOption.AllDirectories);

                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) { 
                            string noPathFileName = String.Empty;
                            int lastSlash = fileName.LastIndexOf("\\", StringComparison.Ordinal);
                            if (lastSlash > -1) {
                                noPathFileName = fileName.Substring(lastSlash); 
                            }
                            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);
        } 

        //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);
 
            //
            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 = RuntimeConfig.GetAppConfig().Compilation; 
 
            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);
 
            //
            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);
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK