BrowserCapabilitiesCodeGenerator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / xsp / System / Web / Configuration / BrowserCapabilitiesCodeGenerator.cs / 1305376 / 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.Linq;
    using System.Reflection; 
    using System.Security;
    using System.Security.Permissions;
    using System.Text;
    using System.Text.RegularExpressions; 
    using System.Web;
    using System.Web.Compilation; 
    using System.Web.Configuration; 
    using System.Web.Hosting;
    using System.Web.UI; 
    using System.Web.Util;
    using System.Xml;
    using System.Xml.Schema;
 
    using Microsoft.Build.Utilities;
    using Microsoft.CSharp; 
 
    [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
    [PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)] 
    public class BrowserCapabilitiesCodeGenerator {
        private static readonly string _browsersDirectory;
        private static readonly string _publicKeyTokenFile;
 
        private static object _staticLock = new object();
 
        private BrowserTree _browserTree; 
        private BrowserTree _defaultTree;
        private BrowserDefinitionCollection _browserDefinitionCollection; 

        internal const string browserCapsVariable = "browserCaps";
        internal const string IgnoreApplicationBrowserVariableName = "ignoreApplicationBrowsers";
        private const string _factoryTypeName = "BrowserCapabilitiesFactory"; 
        private const string _headerDictionaryVarName = "_headerDictionary";
        private const string _disableOptimizedCacheKeyMethodName = "DisableOptimizedCacheKey"; 
        private const string _matchedHeadersMethodName = "PopulateMatchedHeaders"; 
        private const string _browserElementsMethodName = "PopulateBrowserElements";
        private const string _dictionaryRefName = "dictionary"; 
        private const string _regexWorkerRefName = "regexWorker";
        private const string _headersRefName = "headers";
        private const string _resultVarName = "result";
        private const string _processRegexMethod = "ProcessRegex"; 
        private static readonly string _strongNameKeyFileName = browserCapsVariable + ".snk";
        private static readonly string _publicKeyTokenFileName = browserCapsVariable + ".token"; 
        private static bool _publicKeyTokenLoaded; 
        private static string _publicKeyToken;
 
        private CodeVariableReferenceExpression _dictionaryRefExpr = new CodeVariableReferenceExpression(_dictionaryRefName);
        private CodeVariableReferenceExpression _regexWorkerRefExpr = new CodeVariableReferenceExpression(_regexWorkerRefName);
        private CodeVariableReferenceExpression _headersRefExpr = new CodeVariableReferenceExpression(_headersRefName);
        private CodeVariableReferenceExpression _browserCapsRefExpr = new CodeVariableReferenceExpression(browserCapsVariable); 

        private ArrayList _browserFileList; 
 
        private ArrayList _customBrowserFileLists;
        private ArrayList _customTreeList; 
        private ArrayList _customTreeNames;
        private ArrayList _customBrowserDefinitionCollections;

        private CaseInsensitiveStringSet _headers; 

        static BrowserCapabilitiesCodeGenerator() { 
#if !PLATFORM_UNIX // File system paths must account for UNIX 
            _browsersDirectory = HttpRuntime.ClrInstallDirectoryInternal + "\\config\\browsers";
            _publicKeyTokenFile = _browsersDirectory + "\\" + _publicKeyTokenFileName; 
#else // !PLATFORM_UNIX
            _browsersDirectory = HttpRuntime.ClrInstallDirectoryInternal + "/config/browsers";
            _publicKeyTokenFile = _browsersDirectory + "/" + _publicKeyTokenFileName;
 
#endif // !PLATFORM_UNIX
        } 
 
        public BrowserCapabilitiesCodeGenerator() {
            _headers = new CaseInsensitiveStringSet(); 
        }

        internal BrowserTree BrowserTree {
            get { 
                return _browserTree;
            } 
        } 

        internal BrowserTree DefaultTree { 
            get {
                return _defaultTree;
            }
        } 

        internal ArrayList CustomTreeList { 
            get { 
                return _customTreeList;
            } 
        }

        internal ArrayList CustomTreeNames {
            get { 
                return _customTreeNames;
            } 
        } 

        internal static string BrowserCapAssemblyPublicKeyToken { 
            get {
                if (_publicKeyTokenLoaded) {
                    return _publicKeyToken;
                } 

                lock (_staticLock) { 
                    if (_publicKeyTokenLoaded) { 
                        return _publicKeyToken;
                    } 

                    string publicKeyTokenFile;
                    if (MultiTargetingUtil.IsTargetFramework40OrAbove) {
                        publicKeyTokenFile = _publicKeyTokenFile; 
                    }
                    else { 
                        // If we are targeting pre-4.0, we should be using version 2.0 of the assembly 
                        // ASP.BrowserCapsFactory, so we need to read the token file from the 2.0 path.
                        // (Dev10 bug 795509) 
                        string subPath = @"config\browsers\" + _publicKeyTokenFileName;
                        publicKeyTokenFile = ToolLocationHelper.GetPathToDotNetFrameworkFile(subPath, TargetDotNetFrameworkVersion.Version20);
                    }
                    _publicKeyToken = LoadPublicKeyTokenFromFile(publicKeyTokenFile); 
                    _publicKeyTokenLoaded = true;
 
                    return _publicKeyToken; 
                }
            } 
        }

        internal virtual bool GenerateOverrides { get { return true; } }
 
        internal virtual string TypeName {
            get { 
                return _factoryTypeName; 
            }
        } 

        internal void AddFile(string filePath) {
            if (_browserFileList == null)
                _browserFileList = new ArrayList(); 

            _browserFileList.Add(filePath); 
        } 

        internal void AddCustomFile(string filePath) { 
            if (_customBrowserFileLists == null) {
                _customBrowserFileLists = new ArrayList();
            }
 
            _customBrowserFileLists.Add(filePath);
        } 
 
        //parse the config info and create BrowserTree
        //then generate code for, compile, and gac the object 
        [SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
        public virtual void Create() {
            DirectoryInfo browserDirInfo = new DirectoryInfo(_browsersDirectory);
            //get all the browser files and put them in the "tree" 
            FileInfo[] browserFiles = browserDirInfo.GetFiles("*.browser");
 
            if (browserFiles == null || browserFiles.Length == 0) { 
                return;
            } 

            foreach(FileInfo browserFile in browserFiles) {
                AddFile(browserFile.FullName);
            } 

            // First parse the browser files. 
            ProcessBrowserFiles(); 

            // Then parse custom browser files. 
            ProcessCustomBrowserFiles();

            // Uninstall previously installed generated assembly.
            Uninstall(); 

            //generate the source code, compile it, and gac it 
            GenerateAssembly(); 

            // Restart w3svc service 
            RestartW3SVCIfNecessary();
        }

        internal bool UninstallInternal() { 
            // Remove existing strong name public token file
            if (File.Exists(_publicKeyTokenFile)) { 
                File.Delete(_publicKeyTokenFile); 
            }
 
            // Removing existing copy from GAC
            GacUtil gacutil = new GacUtil();
            bool assemblyRemoved = gacutil.GacUnInstall("ASP.BrowserCapsFactory, Version=" + ThisAssembly.Version + ", Culture=neutral");
            if (!assemblyRemoved) { 
                return false;
            } 
 
            return true;
        } 

        [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
        public bool Uninstall() {
            // Restart w3svc service 
            RestartW3SVCIfNecessary();
 
            if (!UninstallInternal()) { 
                return false;
            } 

            // Restart w3svc service again so applications get a fresh copy.
            RestartW3SVCIfNecessary();
 
            return true;
        } 
 
        private void RestartW3SVCIfNecessary() {
#if !FEATURE_PAL 
            try {
                // Dev10 bug 734918
                // We should not fail when the w3svc service is not installed.
                ServiceController[] services = ServiceController.GetServices(); 
                ServiceController controller = services.SingleOrDefault(s => String.Equals(s.ServiceName, "W3SVC", StringComparison.OrdinalIgnoreCase));
                if (controller == null) { 
                    return; 
                }
 
                ServiceControllerStatus status = controller.Status;

                // Stop the service if it's not currently stopped or pending.
                if (!status.Equals(ServiceControllerStatus.Stopped) && 
                    !status.Equals(ServiceControllerStatus.StopPending) &&
                    !status.Equals(ServiceControllerStatus.StartPending)) { 
                    controller.Stop(); 

                    // Give it 5 minutes to stop 
                    controller.WaitForStatus(ServiceControllerStatus.Stopped, new TimeSpan(0, 5, 0));
                    controller.Start();

                    // If the service was paused, pause it. 
                    if (status.Equals(ServiceControllerStatus.Paused) || status.Equals(ServiceControllerStatus.PausePending)) {
                        controller.Pause(); 
                    } 
                }
            } 
            catch (Exception ex) {
                throw new InvalidOperationException(SR.GetString(SR.Browser_W3SVC_Failure_Helper_Text, ex));
            }
#endif // !FEATURE_PAL 
        }
 
        internal void ProcessBrowserFiles() { 
            ProcessBrowserFiles(false, String.Empty);
        } 

        private string NoPathFileName(string fullPath) {
            int lastSlash = fullPath.LastIndexOf("\\", StringComparison.Ordinal);
            if(lastSlash > -1) { 
                return fullPath.Substring(lastSlash + 1);
            } 
            return fullPath; 
        }
 
        internal virtual void ProcessBrowserNode(XmlNode node, BrowserTree browserTree) {

            BrowserDefinition browserInfo = null;
 
            if (node.Name == "gateway") {
                browserInfo = new GatewayDefinition(node); 
            } 
            else if (node.Name == "browser") {
                browserInfo = new BrowserDefinition(node); 
            }
            else {
                Debug.Assert(node.Name == "defaultBrowser");
                browserInfo = new BrowserDefinition(node, true); 
            }
 
            BrowserDefinition oldNode = (BrowserDefinition)browserTree[browserInfo.Name]; 

            if (oldNode != null) { 
                if (browserInfo.IsRefID) {
                    oldNode.MergeWithDefinition(browserInfo);
                }
                else { 
                    throw new ConfigurationErrorsException(SR.GetString(SR.Duplicate_browser_id, browserInfo.ID), node);
                } 
            } 
            else {
                browserTree[browserInfo.Name] = browserInfo; 
            }
        }

        private void NormalizeAndValidateTree(BrowserTree browserTree, bool isDefaultBrowser) { 
            NormalizeAndValidateTree(browserTree, isDefaultBrowser, false);
        } 
 
        private void NormalizeAndValidateTree(BrowserTree browserTree, bool isDefaultBrowser, bool isCustomBrowser) {
            //normalize the tree 
            foreach (DictionaryEntry entry in browserTree) {
                BrowserDefinition bd = (BrowserDefinition)entry.Value;
                string parentName = bd.ParentName;
                BrowserDefinition parentBrowser = null; 

                if (IsRootNode(bd.Name)) { 
                    continue; 
                }
 
                if (parentName.Length > 0) {
                    parentBrowser = (BrowserDefinition)browserTree[parentName];
                }
 
                if (parentBrowser != null) {
                    if (bd.IsRefID) { 
                        if (bd is GatewayDefinition) { 
                            parentBrowser.RefGateways.Add(bd);
                        } 
                        else {
                            parentBrowser.RefBrowsers.Add(bd);
                        }
                    } 
                    else if (bd is GatewayDefinition) {
                        parentBrowser.Gateways.Add(bd); 
                    } 
                    else {
                        parentBrowser.Browsers.Add(bd); 
                    }
                }
                else {
                    if (isCustomBrowser) { 
                        throw new ConfigurationErrorsException(SR.GetString(SR.Browser_parentID_Not_Found, bd.ParentID), bd.XmlNode);
                    } 
                    else { 
                        HandleUnRecognizedParentElement(bd, isDefaultBrowser);
                    } 
                }
            }

            //validate the tree 
            //loop check
            foreach (DictionaryEntry entry in browserTree) { 
                BrowserDefinition bd = (BrowserDefinition)entry.Value; 
                Hashtable loopCheck = new Hashtable();
                BrowserDefinition currentBrowser = bd; 
                string currentId = currentBrowser.Name;
                while (!IsRootNode(currentId)) {
                    if (loopCheck[currentId] != null) {
                        throw new ConfigurationErrorsException(SR.GetString(SR.Browser_Circular_Reference, currentId), currentBrowser.XmlNode); 
                    }
                    loopCheck[currentId] = currentId; 
                    currentBrowser = (BrowserDefinition)browserTree[currentBrowser.ParentName]; 
                    //in app-level, parent can exist in machine level
                    if (currentBrowser == null) { 
                        break;
                    }

                    currentId = currentBrowser.Name; 
                }
            } 
        } 

        private void SetCustomTreeRoots(BrowserTree browserTree, int index) { 
            foreach (DictionaryEntry entry in browserTree) {
                BrowserDefinition bd = (BrowserDefinition)entry.Value;
                if (bd.ParentName == null) {
                    _customTreeNames[index] = bd.Name; 
                    break;
                } 
            } 
        }
 
        // Now that we support adding custom browser hierarchies, root nodes other than Default are permitted.
        private bool IsRootNode(string nodeName) {
            if (String.Compare(nodeName, "Default", StringComparison.OrdinalIgnoreCase) == 0)
                return true; 

            foreach (string treeRootName in _customTreeNames) { 
                if (String.Compare(nodeName, treeRootName, StringComparison.OrdinalIgnoreCase) == 0) { 
                    return true;
                } 
            }

            return false;
        } 

        protected void ProcessBrowserFiles(bool useVirtualPath, string virtualDir) { 
            _browserTree = new BrowserTree(); 
            _defaultTree = new BrowserTree();
            _customTreeNames = new ArrayList(); 

            if (_browserFileList == null) {
                _browserFileList = new ArrayList();
            } 

            _browserFileList.Sort(); 
//#if OPTIMIZE_FOR_DESKTOP_BROWSER 
            string mozillaFile = null;
            string ieFile = null; 
            string operaFile = null;

            // DevDivBugs 180962
            // IE, Mozilla and Opera are first-class browsers. Their User-Agent profiles need to be compared to the UA profile 
            // of the HTTP request before other browsers. We put them to the head of the list so that the generated browser capabilities
            // code will try to match them before other browsers. 
            foreach (String filePath in _browserFileList) { 
                if (filePath.EndsWith("ie.browser", StringComparison.OrdinalIgnoreCase)) {
                    ieFile = filePath; 
                }
                else if (filePath.EndsWith("mozilla.browser", StringComparison.OrdinalIgnoreCase)) {
                    mozillaFile = filePath;
                } 
                else if (filePath.EndsWith("opera.browser", StringComparison.OrdinalIgnoreCase)) {
                    operaFile = filePath; 
                    break; 
                }
            } 

            if (ieFile != null) {
                _browserFileList.Remove(ieFile);
                _browserFileList.Insert(0, ieFile); 
            }
 
            if (mozillaFile != null) { 
                _browserFileList.Remove(mozillaFile);
                _browserFileList.Insert(1, mozillaFile); 
            }

            if (operaFile != null) {
                _browserFileList.Remove(operaFile); 
                _browserFileList.Insert(2, operaFile);
            } 
//#endif 
            foreach (string fileName in _browserFileList) {
                XmlDocument doc = new ConfigXmlDocument(); 
                try {
                    doc.Load(fileName);

                    XmlNode rootNode = doc.DocumentElement; 
                    if(rootNode.Name != "browsers") {
                        if(useVirtualPath) { 
                            throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, 1); 
                        }
                        else { 
                            throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, fileName, null /*sourceCode*/, 1);
                        }
                    }
 
                    foreach (XmlNode node in rootNode.ChildNodes) {
                        if (node.NodeType != XmlNodeType.Element) 
                            continue; 
                        if (node.Name == "browser" || node.Name == "gateway") {
                            ProcessBrowserNode(node, _browserTree); 
                        }
                        else if (node.Name == "defaultBrowser") {
                            ProcessBrowserNode(node, _defaultTree);
                        } 
                        else {
                            HandlerBase.ThrowUnrecognizedElement(node); 
                        } 
                    }
                } 
                catch (XmlException e) {
                    if(useVirtualPath) {
                        throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber);
                    } 
                    else {
                        throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber); 
                    } 
                }
                catch (XmlSchemaException e) { 
                    if(useVirtualPath) {
                        throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber);
                    }
                    else { 
                        throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber);
                    } 
                } 
            }
            NormalizeAndValidateTree(_browserTree, false); 
            NormalizeAndValidateTree(_defaultTree, true);

            BrowserDefinition defaultBrowser = (BrowserDefinition)_browserTree["Default"];
 
            if (defaultBrowser != null) {
                AddBrowserToCollectionRecursive(defaultBrowser, 0); 
            } 
        }
 
        internal void ProcessCustomBrowserFiles() {
            ProcessCustomBrowserFiles(false, String.Empty);
        }
 
        internal void ProcessCustomBrowserFiles(bool useVirtualPath, string virtualDir) {
            //get all custom browser files and put them in the "tree" 
            DirectoryInfo browserDirInfo = null; 
            DirectoryInfo[] browserSubDirectories = null;
            DirectoryInfo[] allBrowserSubDirectories = null; 
            ArrayList customBrowserFileNames;
            _customTreeList = new ArrayList();
            _customBrowserFileLists = new ArrayList();
            _customBrowserDefinitionCollections = new ArrayList(); 

            /* Machine Level Custom Browsers */ 
            if (useVirtualPath == false) { 
                browserDirInfo = new DirectoryInfo(_browsersDirectory);
            } 
            /* Application Level Custom Browsers */
            else {
                browserDirInfo = new DirectoryInfo(HostingEnvironment.MapPathInternal(virtualDir));
            } 

            allBrowserSubDirectories = browserDirInfo.GetDirectories(); 
 
            int j = 0;
            int length = allBrowserSubDirectories.Length; 
            browserSubDirectories = new DirectoryInfo[length];
            for (int i = 0; i < length; i++) {
                if ((allBrowserSubDirectories[i].Attributes & FileAttributes.Hidden) != FileAttributes.Hidden) {
                    browserSubDirectories[j] = allBrowserSubDirectories[i]; 
                    j++;
                } 
            } 
            Array.Resize(ref browserSubDirectories, j);
 
            for (int i = 0; i < browserSubDirectories.Length; i++) {
                /* Recursively Into Subdirectories */
                FileInfo[] browserFiles = GetFilesNotHidden(browserSubDirectories[i], browserDirInfo);
 
                if (browserFiles == null || browserFiles.Length == 0) {
                    continue; 
                } 
                BrowserTree customTree = new BrowserTree();
                _customTreeList.Add(customTree); 
                _customTreeNames.Add(browserSubDirectories[i].Name);
                customBrowserFileNames = new ArrayList();

                foreach (FileInfo browserFile in browserFiles) { 
                    customBrowserFileNames.Add(browserFile.FullName);
                } 
                _customBrowserFileLists.Add(customBrowserFileNames); 
            }
            for (int i = 0; i < _customBrowserFileLists.Count; i++) { 
                ArrayList fileNames = (ArrayList)_customBrowserFileLists[i];
                foreach (string fileName in fileNames) {
                    XmlDocument doc = new ConfigXmlDocument();
                    try { 
                        doc.Load(fileName);
 
                        XmlNode rootNode = doc.DocumentElement; 
                        if (rootNode.Name != "browsers") {
                            if (useVirtualPath) { 
                                throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, 1);
                            }
                            else {
                                throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, fileName, null /*sourceCode*/, 1); 
                            }
                        } 
                        foreach (XmlNode node in rootNode.ChildNodes) { 
                            if (node.NodeType != XmlNodeType.Element) {
                                continue; 
                            }
                            if (node.Name == "browser" || node.Name == "gateway") {
                                ProcessBrowserNode(node, (BrowserTree)_customTreeList[i]);
                            } 
                            else {
                                HandlerBase.ThrowUnrecognizedElement(node); 
                            } 
                        }
                    } 
                    catch (XmlException e) {
                        if (useVirtualPath) {
                            throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber);
                        } 
                        else {
                            throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber); 
                        } 
                    }
                    catch (XmlSchemaException e) { 
                        if (useVirtualPath) {
                            throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber);
                        }
                        else { 
                            throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber);
                        } 
                    } 
                }
                SetCustomTreeRoots((BrowserTree)_customTreeList[i], i); 
                NormalizeAndValidateTree((BrowserTree)_customTreeList[i], false, true);
                _customBrowserDefinitionCollections.Add(new BrowserDefinitionCollection());
                AddCustomBrowserToCollectionRecursive((BrowserDefinition)(((BrowserTree)_customTreeList[i])[_customTreeNames[i]]), 0, i);
            } 
        }
 
        internal void AddCustomBrowserToCollectionRecursive(BrowserDefinition bd, int depth, int index) { 
            if(_customBrowserDefinitionCollections[index] == null) {
                _customBrowserDefinitionCollections[index] = new BrowserDefinitionCollection(); 
            }
            bd.Depth = depth;
            bd.IsDeviceNode = true;
            ((BrowserDefinitionCollection)_customBrowserDefinitionCollections[index]).Add(bd); 

            foreach (BrowserDefinition childBrowser in bd.Browsers) { 
                AddCustomBrowserToCollectionRecursive(childBrowser, depth + 1, index); 
            }
        } 

        internal void AddBrowserToCollectionRecursive(BrowserDefinition bd, int depth) {
            if (_browserDefinitionCollection == null) {
                _browserDefinitionCollection = new BrowserDefinitionCollection(); 
            }
 
            bd.Depth = depth; 
            bd.IsDeviceNode = true;
            _browserDefinitionCollection.Add(bd); 

            foreach(BrowserDefinition childBrowser in bd.Browsers) {
                AddBrowserToCollectionRecursive(childBrowser, depth + 1);
            } 
        }
 
        internal virtual void HandleUnRecognizedParentElement(BrowserDefinition bd, bool isDefault) { 
            throw new ConfigurationErrorsException(SR.GetString(SR.Browser_parentID_Not_Found, bd.ParentID), bd.XmlNode);
        } 

        private static FileInfo[] GetFilesNotHidden(DirectoryInfo rootDirectory, DirectoryInfo browserDirInfo) {
            ArrayList fileList = new ArrayList();
            FileInfo[] files; 
            DirectoryInfo[] subDirectories = rootDirectory.GetDirectories("*", SearchOption.AllDirectories);
 
            files = rootDirectory.GetFiles("*.browser", SearchOption.TopDirectoryOnly); 
            fileList.AddRange(files);
            for (int i = 0; i < subDirectories.Length; i++) { 
                if ((HasHiddenParent(subDirectories[i], browserDirInfo) == false)) {
                    files = subDirectories[i].GetFiles("*.browser", SearchOption.TopDirectoryOnly);
                    fileList.AddRange(files);
                } 
            }
            return ((FileInfo [])fileList.ToArray(typeof(FileInfo))); 
        } 

        private static bool HasHiddenParent(DirectoryInfo directory, DirectoryInfo browserDirInfo) { 
            while(!String.Equals(directory.Parent.Name, browserDirInfo.Name)) {
                if ((directory.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) {
                    return true;
                } 
                directory = directory.Parent;
            } 
            return false; 
        }
 
        //generate the code from the parsed BrowserDefinitionTree
        //compile it, and install it in the gac
        private void GenerateAssembly() {
            Debug.Assert(_browserTree != null); 
            BrowserDefinition root = (BrowserDefinition)_browserTree["Default"];
            BrowserDefinition defaultRoot = (BrowserDefinition)_defaultTree["Default"]; 
            ArrayList customTreeRoots = new ArrayList(); 
            for (int i = 0; i < _customTreeNames.Count; i++) {
                customTreeRoots.Add((BrowserDefinition)(((BrowserTree)_customTreeList[i])[_customTreeNames[i]])); 
            }

            //create a CodeCompileUnit
            //add a CodeNamespace object to the CodeCompileUnit 
            //add a CodeTypeDeclaration to the CodeNamespace
            //add all the members of the type/class to the CodeTypeDeclaration 
            //use a CodeGenerator to generate code from the CodeCompileUnit 
            //a CodeDomProvider can provide a CodeGenerator
 
            //translate the BrowserDefinition tree to code
            CSharpCodeProvider cscp = new CSharpCodeProvider();

            // namespace System.Web.BrowserCapsFactory 
            CodeCompileUnit ccu = new CodeCompileUnit();
 
            //add strong-name key pair for 
            CodeAttributeDeclaration declaration = new CodeAttributeDeclaration(
                "System.Reflection.AssemblyKeyFile", 
                new CodeAttributeArgument[] {
                    new CodeAttributeArgument(new CodePrimitiveExpression(_strongNameKeyFileName))});

            CodeAttributeDeclaration aptca = new CodeAttributeDeclaration( 
                "System.Security.AllowPartiallyTrustedCallers");
            ccu.AssemblyCustomAttributes.Add(aptca); 
 
            ccu.AssemblyCustomAttributes.Add(declaration);
            //add version number for it so it can distinguished in future versions 
            declaration = new CodeAttributeDeclaration(
                "System.Reflection.AssemblyVersion",
                new CodeAttributeArgument[] {
                    new CodeAttributeArgument(new CodePrimitiveExpression(ThisAssembly.Version))}); 
            ccu.AssemblyCustomAttributes.Add(declaration);
 
            CodeNamespace cnamespace = new CodeNamespace("ASP"); 
            //GEN: using System;
            cnamespace.Imports.Add(new CodeNamespaceImport("System")); 
            //GEN: using System.Web;
            cnamespace.Imports.Add(new CodeNamespaceImport("System.Web"));
            //GEN: using System.Web.Configuration;
            cnamespace.Imports.Add(new CodeNamespaceImport("System.Web.Configuration")); 
            //GEN: using System.Reflection;
            cnamespace.Imports.Add(new CodeNamespaceImport("System.Reflection")); 
            //GEN: class BrowserCapabilitiesFactory 
            ccu.Namespaces.Add(cnamespace);
 
            CodeTypeDeclaration factoryType = new CodeTypeDeclaration("BrowserCapabilitiesFactory");
            factoryType.Attributes = MemberAttributes.Private;
            factoryType.IsClass = true;
            factoryType.Name = TypeName; 
            factoryType.BaseTypes.Add(new CodeTypeReference("System.Web.Configuration.BrowserCapabilitiesFactoryBase"));
            cnamespace.Types.Add(factoryType); 
 
            //GEN: protected override object ConfigureBrowserCapabilities(NameValueCollection headers, HttpBrowserCapabilities browserCaps)
            CodeMemberMethod method = new CodeMemberMethod(); 
            method.Attributes = MemberAttributes.Override | MemberAttributes.Public;
            method.ReturnType = new CodeTypeReference(typeof(void));
            method.Name = "ConfigureBrowserCapabilities";
 
            CodeParameterDeclarationExpression cpde = new CodeParameterDeclarationExpression(typeof(NameValueCollection), _headersRefName);
            method.Parameters.Add(cpde); 
            cpde = new CodeParameterDeclarationExpression(typeof(HttpBrowserCapabilities), browserCapsVariable); 
            method.Parameters.Add(cpde);
            factoryType.Members.Add(method); 

            GenerateSingleProcessCall(root, method);

            for (int i = 0; i < customTreeRoots.Count; i++) { 
                GenerateSingleProcessCall((BrowserDefinition)customTreeRoots[i], method);
            } 
 
            //GEN: if(this.IsBrowserUnknown(browserCaps) == false) return;
            CodeConditionStatement istatement = new CodeConditionStatement(); 

            CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "IsBrowserUnknown");
            cmie.Parameters.Add(_browserCapsRefExpr);
            istatement.Condition = new CodeBinaryOperatorExpression(cmie, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false)); 
            istatement.TrueStatements.Add(new CodeMethodReturnStatement());
            method.Statements.Add(istatement); 
 
            if(defaultRoot != null) {
                GenerateSingleProcessCall(defaultRoot, method, "Default"); 
            }

            for (int i = 0; i < customTreeRoots.Count; i++) {
                foreach (DictionaryEntry entry in (BrowserTree)_customTreeList[i]) { 
                    BrowserDefinition bd = entry.Value as BrowserDefinition;
                    Debug.Assert(bd != null); 
                    GenerateProcessMethod(bd, factoryType); 
                }
            } 

            //GenerateCallsToProcessMethods(root, method);
            foreach (DictionaryEntry entry in _browserTree) {
                BrowserDefinition bd = entry.Value as BrowserDefinition; 
                Debug.Assert(bd != null);
                GenerateProcessMethod(bd, factoryType); 
            } 

            foreach (DictionaryEntry entry in _defaultTree) { 
                BrowserDefinition bd = entry.Value as BrowserDefinition;
                Debug.Assert(bd != null);
                GenerateProcessMethod(bd, factoryType, "Default");
            } 

            GenerateOverrideMatchedHeaders(factoryType); 
            GenerateOverrideBrowserElements(factoryType); 

            //TODO: don't actually generate the code, just compile it in memory 
            TextWriter twriter = new StreamWriter(new FileStream(_browsersDirectory + "\\BrowserCapsFactory.cs", FileMode.Create));
            try {
                cscp.GenerateCodeFromCompileUnit(ccu, twriter, null);
            } 
            finally {
                if(twriter != null) 
                    twriter.Close(); 
            }
 
            CompilationSection compConfig = MTConfigUtil.GetCompilationAppConfig();

            bool debug = compConfig.Debug;
 
#if !PLATFORM_UNIX // File system paths must account for UNIX
            string strongNameFile = _browsersDirectory + "\\" + _strongNameKeyFileName; 
#else // !PLATFORM_UNIX 
            string strongNameFile = _browsersDirectory + "/" + _strongNameKeyFileName;
#endif // !PLATFORM_UNIX 

            // Generate strong name file
            StrongNameUtility.GenerateStrongNameFile(strongNameFile);
 
            //TODO: do not use interim file:  CompileAssemblyFromDom instead
            string[] referencedAssemblies = new string[2] { "System.dll", "System.Web.dll" }; 
            CompilerParameters compilerParameters = new CompilerParameters(referencedAssemblies, "ASP.BrowserCapsFactory", debug /* includeDebugInformation */ ); 
            compilerParameters.GenerateInMemory = false;
            compilerParameters.OutputAssembly = _browsersDirectory + "\\ASP.BrowserCapsFactory.dll"; 
            CompilerResults results = null;

            try {
                results = cscp.CompileAssemblyFromFile(compilerParameters, _browsersDirectory + "\\BrowserCapsFactory.cs"); 
            }
            finally { 
                if (File.Exists(strongNameFile)) { 
                    File.Delete(strongNameFile);
                } 
            }

            if (results.NativeCompilerReturnValue != 0 || results.Errors.HasErrors) {
                foreach (CompilerError error in results.Errors) { 
                    if (!error.IsWarning) {
                        throw new HttpCompileException(error.ErrorText); 
                    } 
                }
 
                throw new HttpCompileException(SR.GetString(SR.Browser_compile_error));
            }

            Assembly resultAssembly = results.CompiledAssembly; 

            GacUtil gacutil = new GacUtil(); 
            gacutil.GacInstall(resultAssembly.Location); 

            SavePublicKeyTokenFile(_publicKeyTokenFile, resultAssembly.GetName().GetPublicKeyToken()); 
        }

        private void SavePublicKeyTokenFile(string filename, byte[] publicKeyToken) {
            using (FileStream pktStream = new FileStream(filename, FileMode.Create, FileAccess.Write)) { 
                using (StreamWriter pktWriter = new StreamWriter(pktStream)) {
                    foreach (byte b in publicKeyToken) { 
                        pktWriter.Write("{0:X2}", b); 
                    }
                } 
            }
        }

        private static string LoadPublicKeyTokenFromFile(string filename) { 
            IStackWalk fileReadAccess = InternalSecurityPermissions.FileReadAccess(filename);
            Debug.Assert(fileReadAccess != null); 
            fileReadAccess.Assert(); 
            if (!File.Exists(filename)) {
                return null; 
            }

            try {
                using (FileStream pktStream = new FileStream(filename, FileMode.Open, FileAccess.Read)) { 
                    using (StreamReader pktReader = new StreamReader(pktStream)) {
                        return pktReader.ReadLine(); 
                    } 
                }
            } 
            catch (IOException) {
                if (HttpRuntime.HasFilePermission(filename)) {
                    throw;
                } 

                // Don't throw exception if we don't have permission to the file. 
                return null; 
            }
            finally { 
                CodeAccessPermission.RevertAssert();
            }
        }
 
        internal void GenerateOverrideBrowserElements(CodeTypeDeclaration typeDeclaration) {
 
            // Don't generate the property if there's nothing to override. 
            if (_browserDefinitionCollection == null) {
                return; 
            }

            // GEN:
            // protected override void PopulateBrowserElements(IDictionary dictionary) { 
            //     dictionary["Default"] = new Triplet(null, "default description", 0 /*depth_of_node */);
            //     dictionary["Up"] = new Triplet("Default", "up Description", 1 /*depth_of_node */); 
            // } 
            CodeMemberMethod method = new CodeMemberMethod();
            method.Name = _browserElementsMethodName; 
            method.Attributes = MemberAttributes.Override | MemberAttributes.Family;
            method.ReturnType = new CodeTypeReference(typeof(void));
            CodeParameterDeclarationExpression parameter =
                new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IDictionary)), _dictionaryRefName); 

            method.Parameters.Add(parameter); 
            typeDeclaration.Members.Add(method); 

            CodeMethodReferenceExpression baseMethod = new CodeMethodReferenceExpression(new CodeBaseReferenceExpression(), _browserElementsMethodName); 
            CodeMethodInvokeExpression baseInvoke = new CodeMethodInvokeExpression(baseMethod, new CodeExpression[] { _dictionaryRefExpr });
            method.Statements.Add(baseInvoke);

            foreach(BrowserDefinition bd in _browserDefinitionCollection) { 
                if (!bd.IsDeviceNode)
                    continue; 
 
                Debug.Assert(!(bd is GatewayDefinition));
 
                CodeAssignStatement cas = new CodeAssignStatement();
                cas.Left = new CodeIndexerExpression(_dictionaryRefExpr, new CodeExpression[] {
                                                                             new CodePrimitiveExpression(bd.ID)
                                                                          }); 
                cas.Right = new CodeObjectCreateExpression(typeof(Triplet),
                    new CodeExpression[] { 
                        new CodePrimitiveExpression(bd.ParentName), 
                        new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "Empty"),
                        new CodePrimitiveExpression(bd.Depth)}); 

                method.Statements.Add(cas);
            }
 
            for (int i = 0; i < _customTreeNames.Count; i++) {
                foreach (BrowserDefinition bd in (BrowserDefinitionCollection)_customBrowserDefinitionCollections[i]) { 
                    if (!bd.IsDeviceNode) 
                        continue;
 
                    Debug.Assert(!(bd is GatewayDefinition));

                    CodeAssignStatement cas = new CodeAssignStatement();
                    cas.Left = new CodeIndexerExpression(_dictionaryRefExpr, new CodeExpression[] { 
                                                                             new CodePrimitiveExpression(bd.ID)
                                                                           }); 
                    cas.Right = new CodeObjectCreateExpression(typeof(Triplet), 
                        new CodeExpression[] {
                        new CodePrimitiveExpression(bd.ParentName), 
                        new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "Empty"),
                        new CodePrimitiveExpression(bd.Depth)});

                    method.Statements.Add(cas); 
                }
            } 
        } 

        internal void GenerateOverrideMatchedHeaders(CodeTypeDeclaration typeDeclaration) { 
            // GEN:
            // protected override void PopulateMatchedHeaders(IDictionary dictionary) {
            //     base.PopulateMatchedHeaders(dictionary);
            // 
            //     dictionary["header0"] = null;
            //     dictionary["header1"] = null; 
            // } 
            CodeMemberMethod method = new CodeMemberMethod();
            method.Name = _matchedHeadersMethodName; 
            method.Attributes = MemberAttributes.Override | MemberAttributes.Family;
            method.ReturnType = new CodeTypeReference(typeof(void));
            CodeParameterDeclarationExpression parameter =
                new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IDictionary)), _dictionaryRefName); 

            method.Parameters.Add(parameter); 
            typeDeclaration.Members.Add(method); 

            CodeMethodReferenceExpression baseMethod = new CodeMethodReferenceExpression(new CodeBaseReferenceExpression(), _matchedHeadersMethodName); 
            CodeMethodInvokeExpression baseInvoke = new CodeMethodInvokeExpression(baseMethod, new CodeExpression[] { _dictionaryRefExpr });
            method.Statements.Add(baseInvoke);

            foreach(String header in _headers) { 
                CodeAssignStatement cas = new CodeAssignStatement();
                cas.Left = new CodeIndexerExpression(_dictionaryRefExpr, new CodeExpression[] { 
                                                                             new CodePrimitiveExpression(header) 
                                                                          });
                cas.Right = new CodePrimitiveExpression(null); 

                method.Statements.Add(cas);
            }
        } 

        internal void GenerateProcessMethod(BrowserDefinition bd, CodeTypeDeclaration ctd) { 
            GenerateProcessMethod(bd, ctd, String.Empty); 
        }
 
        //generate the xxxProcess method for an individual BrowserDefinition
        internal void GenerateProcessMethod(BrowserDefinition bd, CodeTypeDeclaration ctd, string prefix) {
            //GEN: internal bool XxxProcess(NameValueCollection headers, HttpBrowserCapabilities browserCaps)
            CodeMemberMethod cmm = new CodeMemberMethod(); 
            cmm.Name = prefix + bd.Name + "Process";
            cmm.ReturnType = new CodeTypeReference(typeof(bool)); 
            cmm.Attributes = MemberAttributes.Private; 
            CodeParameterDeclarationExpression cpde = new CodeParameterDeclarationExpression(typeof(NameValueCollection), _headersRefName);
            cmm.Parameters.Add(cpde); 
            cpde = new CodeParameterDeclarationExpression(typeof(HttpBrowserCapabilities), browserCapsVariable);
            cmm.Parameters.Add(cpde);

            bool regexWorkerGenerated = false; 

            GenerateIdentificationCode(bd, cmm, ref regexWorkerGenerated); 
            GenerateCapturesCode(bd, cmm, ref regexWorkerGenerated); 
            GenerateSetCapabilitiesCode(bd, cmm, ref regexWorkerGenerated);
            GenerateSetAdaptersCode(bd, cmm); 

            // Only add the browser node to the browser collection if it represents a device.
            if (bd.IsDeviceNode) {
                Debug.Assert(!(bd is GatewayDefinition)); 

                //GEN: browserCaps.AddBrowser("xxx"); 
                CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression(browserCapsVariable), "AddBrowser"); 
                cmie.Parameters.Add(new CodePrimitiveExpression(bd.ID));
                cmm.Statements.Add(cmie); 
            }

            // Generate ref gateway elements
            foreach (BrowserDefinition b in bd.RefGateways) { 
                AddComment("ref gateways, parent=" + bd.ID, cmm);
                GenerateSingleProcessCall(b, cmm); 
            } 

            if ((GenerateOverrides) && (prefix.Length == 0)) { 
                //Gen: protected virtual void XxxProcessGateways(NameValueCollection headers, HttpBrowserCapabilities browserCaps) ;
                string methodName = prefix + bd.Name + "ProcessGateways";
                GenerateChildProcessMethod(methodName, ctd, false);
 
                //Gen: XxxProcessGateways(headers,  browserCaps) ;
                GenerateChildProcessInvokeExpression(methodName, cmm, false); 
            } 

            foreach(BrowserDefinition b in bd.Gateways) { 
                AddComment("gateway, parent=" + bd.ID, cmm);
                GenerateSingleProcessCall(b, cmm);
            }
 
            if (GenerateOverrides) {
                //GEN: bool ignoreApplicationBrowsers = true | false; //bd.Browsers.Count != 0 
                CodeVariableDeclarationStatement cvds = new CodeVariableDeclarationStatement(typeof(bool), 
                    IgnoreApplicationBrowserVariableName, new CodePrimitiveExpression(bd.Browsers.Count != 0));
                cmm.Statements.Add(cvds); 
            }

            if (bd.Browsers.Count > 0) {
                CodeStatementCollection statements = cmm.Statements; 
                AddComment("browser, parent=" + bd.ID, cmm);
                foreach (BrowserDefinition b in bd.Browsers) { 
                    statements = GenerateTrackedSingleProcessCall(statements, b, cmm, prefix); 
                }
 
                if (GenerateOverrides) {
                    //GEN: ignoreApplicationBrowsers = false;
                    CodeAssignStatement codeAssignStmt = new CodeAssignStatement();
                    codeAssignStmt.Left = new CodeVariableReferenceExpression(IgnoreApplicationBrowserVariableName); 
                    codeAssignStmt.Right = new CodePrimitiveExpression(false);
                    statements.Add(codeAssignStmt); 
                } 
            }
 
            // Generate ref browser
            foreach (BrowserDefinition b in bd.RefBrowsers) {
                AddComment("ref browsers, parent=" + bd.ID, cmm);
                if (b.IsDefaultBrowser) { 
                    GenerateSingleProcessCall(b, cmm, "Default");
                } 
                else { 
                    GenerateSingleProcessCall(b, cmm);
                } 
            }

            if (GenerateOverrides) {
                //Gen: protected virtual void XxxProcessBrowsers(bool ignoreApplicationBrowsers, NameValueCollection headers, HttpBrowserCapabilities browserCaps) ; 
                string methodName = prefix + bd.Name + "ProcessBrowsers";
                GenerateChildProcessMethod(methodName, ctd, true); 
 
                //Gen: XxxProcessBrowsers(ignoreApplicationBrowsers, headers, browserCaps);
                GenerateChildProcessInvokeExpression(methodName, cmm, true); 
            }

            //GEN: return true;
            CodeMethodReturnStatement cmrs = new CodeMethodReturnStatement(new CodePrimitiveExpression(true)); 
            cmm.Statements.Add(cmrs);
 
            ctd.Members.Add(cmm); 
        }
 
        private void GenerateChildProcessInvokeExpression(string methodName, CodeMemberMethod cmm, bool generateTracker) {
            //Gen: XxxProcessBrowsers(ignoreApplicationBrowsers, headers, browserCaps) ;
            CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), methodName);
 
            if (generateTracker) {
                expr.Parameters.Add(new CodeVariableReferenceExpression(IgnoreApplicationBrowserVariableName)); 
            } 
            expr.Parameters.Add(new CodeVariableReferenceExpression(_headersRefName));
            expr.Parameters.Add(new CodeVariableReferenceExpression(browserCapsVariable)); 

            cmm.Statements.Add(expr);
        }
 
        private void GenerateChildProcessMethod(string methodName, CodeTypeDeclaration ctd, bool generateTracker) {
            //Gen: protected virtual void XxxProcessBrowsers(bool ignoreApplicationBrowsers, NameValueCollection headers, HttpBrowserCapabilities browserCaps) ; 
            CodeMemberMethod cmm= new CodeMemberMethod(); 
            cmm.Name = methodName;
            cmm.ReturnType = new CodeTypeReference(typeof(void)); 
            cmm.Attributes = MemberAttributes.Family;
            CodeParameterDeclarationExpression cpde = null;

            if (generateTracker) { 
                cpde = new CodeParameterDeclarationExpression(typeof(bool), IgnoreApplicationBrowserVariableName);
                cmm.Parameters.Add(cpde); 
            } 

            cpde = new CodeParameterDeclarationExpression(typeof(NameValueCollection), _headersRefName); 
            cmm.Parameters.Add(cpde);
            cpde = new CodeParameterDeclarationExpression(typeof(HttpBrowserCapabilities), browserCapsVariable);
            cmm.Parameters.Add(cpde);
 
            ctd.Members.Add(cmm);
        } 
 
        private void GenerateRegexWorkerIfNecessary(CodeMemberMethod cmm, ref bool regexWorkerGenerated) {
            if (regexWorkerGenerated) { 
                return;
            }

            regexWorkerGenerated = true; 

            //GEN: RegexWorker regexWorker; 
            cmm.Statements.Add(new CodeVariableDeclarationStatement("RegexWorker", _regexWorkerRefName)); 

            //GEN: regexWorker = new RegexWorker(browserCaps); 
            cmm.Statements.Add(new CodeAssignStatement(_regexWorkerRefExpr, new CodeObjectCreateExpression("RegexWorker", _browserCapsRefExpr)));
        }

        private void ReturnIfHeaderValueEmpty(CodeMemberMethod cmm, CodeVariableReferenceExpression varExpr) { 
            //  GEN: if(String.IsNullOrEmpty(varExpr)) {
            //  GEN:     return false; 
            //  GEN: } 
            CodeConditionStatement emptyCheckStmt = new CodeConditionStatement();
            CodeMethodReferenceExpression emptyCheckMethod = new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "IsNullOrEmpty"); 
            CodeMethodInvokeExpression emptyCheckExpr = new CodeMethodInvokeExpression(emptyCheckMethod, varExpr);

            emptyCheckStmt.Condition = emptyCheckExpr;
            emptyCheckStmt.TrueStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(false))); 
            cmm.Statements.Add(emptyCheckStmt);
        } 
 
        //generate part of the xxxProcess method for handling determining if the requesting
        //browser meets the regexes for this browser 
        private void GenerateIdentificationCode(BrowserDefinition bd, CodeMemberMethod cmm, ref bool regexWorkerGenerated) {

            //GEN: IDictionary dictionary;
            cmm.Statements.Add(new CodeVariableDeclarationStatement(typeof(IDictionary), _dictionaryRefName)); 

            //GEN: dictionary = browserCaps.Capabilities; 
            CodeAssignStatement assign = new CodeAssignStatement( 
                _dictionaryRefExpr,
                new CodePropertyReferenceExpression(_browserCapsRefExpr, "Capabilities") 
                );
            cmm.Statements.Add(assign);

            bool disableOptimizedKey = false; 
            CodeVariableReferenceExpression result = null;
            CodeVariableReferenceExpression headerValue = null; 
 
            if(bd.IdHeaderChecks.Count > 0) {
                AddComment("Identification: check header matches", cmm); 
                for (int i = 0; i < bd.IdHeaderChecks.Count; i++) {
                    string matchedString = ((CheckPair)bd.IdHeaderChecks[i]).MatchString;

                    // Skip matching ".*" 
                    if (matchedString.Equals(".*")) {
                        continue; 
                    } 

                    if (headerValue == null) { 
                        headerValue = GenerateVarReference(cmm, typeof(string), "headerValue");
                    }

                    CodeAssignStatement valueAssignment = new CodeAssignStatement(); 
                    cmm.Statements.Add(valueAssignment);
                    valueAssignment.Left = headerValue; 
 
                    if (((CheckPair)bd.IdHeaderChecks[i]).Header.Equals("User-Agent")) {
                        _headers.Add(String.Empty); 

                        // GEN: headerValue = ((string)(browserCaps[String.Empty]));
                        valueAssignment.Right = new CodeCastExpression(typeof(string),
                                                new CodeIndexerExpression( 
                                                    new CodeVariableReferenceExpression(browserCapsVariable),
                                                    new CodeExpression[] { 
                                                        new CodePropertyReferenceExpression( 
                                                        new CodeTypeReferenceExpression(typeof(String)), "Empty") }));
                    } 
                    else {
                        string header = ((CheckPair)bd.IdHeaderChecks[i]).Header;
                        _headers.Add(header);
 
                        //GEN: headerValue = ((String)headers["xxx"]);
                        valueAssignment.Right = new CodeCastExpression(typeof(string), 
                                                   new CodeIndexerExpression( 
                                                       _headersRefExpr,
                                                       new CodeExpression[] { new CodePrimitiveExpression(header) } 
                                                       )
                                                   );

                        disableOptimizedKey = true; 
                    }
 
                    // Don't need to use Regex if matching . only. 
                    if (matchedString.Equals(".")) {
 
                        // Simply return if the header exists.
                        ReturnIfHeaderValueEmpty(cmm, headerValue);

                        continue; 
                    }
 
                    if (result == null) { 
                        result = GenerateVarReference(cmm, typeof(bool), _resultVarName);
                    } 

                    GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated);
                    CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod);
 
                    cmie.Parameters.Add(headerValue);
                    cmie.Parameters.Add(new CodePrimitiveExpression(matchedString)); 
 
                    //GEN: result = regexWorker.ProcessRegex(headerValue, {matchedString});
                    assign = new CodeAssignStatement(); 
                    assign.Left = result;
                    assign.Right = cmie;
                    cmm.Statements.Add(assign);
 
                    //GEN: if(result == false) {
                    //GEN:     return false; 
                    //GEN: } 
                    CodeConditionStatement istatement = new CodeConditionStatement();
                    if(((CheckPair)bd.IdHeaderChecks[i]).NonMatch) { 
                        istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(true));
                    }
                    else {
                        istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false)); 
                    }
                    istatement.TrueStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(false))); 
                    cmm.Statements.Add(istatement); 
                }
            } 

            if (bd.IdCapabilityChecks.Count > 0) {
                AddComment("Identification: check capability matches", cmm);
                for (int i = 0; i < bd.IdCapabilityChecks.Count; i++) { 
                    string matchedString = ((CheckPair)bd.IdCapabilityChecks[i]).MatchString;
 
                    // Skip matching ".*" 
                    if (matchedString.Equals(".*")) {
                        continue; 
                    }

                    if (headerValue == null) {
                        headerValue = GenerateVarReference(cmm, typeof(string), "headerValue"); 
                    }
 
                    CodeAssignStatement valueAssignment = new CodeAssignStatement(); 
                    cmm.Statements.Add(valueAssignment);
                    valueAssignment.Left = headerValue; 
                    valueAssignment.Right = (new CodeCastExpression(typeof(string),
                                                               new CodeIndexerExpression(
                                                                   _dictionaryRefExpr,
                                                                   new CodeExpression[] { 
                                                                       new CodePrimitiveExpression(((CheckPair)bd.IdCapabilityChecks[i]).Header)
                                                                   } 
                                                                   ) 
                                                               ));
 
                    // Don't need to use Regex if matching . only.
                    if (matchedString.Equals(".")) {
                        continue;
                    } 

                    if (result == null) { 
                        result = GenerateVarReference(cmm, typeof(bool), _resultVarName); 
                    }
 
                    GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated);
                    //GEN: result = regexWorker.ProcessRegex((string)dictionary["xxxCapability"], "xxxRegexString");
                    CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod);
 
                    cmie.Parameters.Add(headerValue);
                    cmie.Parameters.Add(new CodePrimitiveExpression(matchedString)); 
                    assign = new CodeAssignStatement(); 
                    assign.Left = result;
                    assign.Right = cmie; 
                    cmm.Statements.Add(assign);

                    //GEN: if(result == false) {
                    //GEN:      return false; 
                    //GEN: }
                    CodeConditionStatement istatement = new CodeConditionStatement(); 
                    if (((CheckPair)bd.IdCapabilityChecks[i]).NonMatch) { 
                        istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(true));
                    } 
                    else {
                        istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false));
                    }
                    istatement.TrueStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(false))); 
                    cmm.Statements.Add(istatement);
                } 
            } 

            //GEN: browserCaps.DisableOptimizedCacheKey(); 
            if (disableOptimizedKey) {
                CodeMethodInvokeExpression cme = new CodeMethodInvokeExpression(_browserCapsRefExpr, _disableOptimizedCacheKeyMethodName);
                cmm.Statements.Add(cme);
            } 
        }
 
        private CodeVariableReferenceExpression GenerateVarReference(CodeMemberMethod cmm, Type varType, string varName) { 
            //GEN: {varType} {varName};
            cmm.Statements.Add(new CodeVariableDeclarationStatement(varType, varName)); 
            return new CodeVariableReferenceExpression(varName);
        }

        //generate part of the xxxProcess method for running and storing the capture regexes 
        private void GenerateCapturesCode(BrowserDefinition bd, CodeMemberMethod cmm, ref bool regexWorkerGenerated) {
            if ((bd.CaptureHeaderChecks.Count == 0) && (bd.CaptureCapabilityChecks.Count == 0)) { 
                return; 
            }
 
            if(bd.CaptureHeaderChecks.Count > 0) {
                AddComment("Capture: header values", cmm);
                for(int i = 0; i < bd.CaptureHeaderChecks.Count; i++) {
 
                    string matchedString = ((CheckPair)bd.CaptureHeaderChecks[i]).MatchString;
                    if (matchedString.Equals(".*")) { 
                        continue; 
                    }
 
                    GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated);
                    CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod);

                    if (((CheckPair)bd.CaptureHeaderChecks[i]).Header.Equals("User-Agent")) { 
                        _headers.Add(String.Empty);
                        cmie.Parameters.Add(new CodeCastExpression(typeof(string), 
                            new CodeIndexerExpression(new CodeVariableReferenceExpression(browserCapsVariable), new CodeExpression[] { 
                                new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "Empty") })));
                    } 
                    else {
                        string header = ((CheckPair)bd.CaptureHeaderChecks[i]).Header;
                        _headers.Add(header);
 
                        //GEN: regexWorker.ProcessRegex((string)headers["xxx"], "xxxRegexString");
                        cmie.Parameters.Add( 
                            new CodeCastExpression(typeof(string), 
                                                   new CodeIndexerExpression(
                                                       _headersRefExpr, 
                                                       new CodeExpression[] { new CodePrimitiveExpression(header) }
                                                       )
                                                   )
                            ); 
                    }
 
                    cmie.Parameters.Add(new CodePrimitiveExpression(matchedString)); 
                    cmm.Statements.Add(cmie);
                } 
            }

            if (bd.CaptureCapabilityChecks.Count > 0) {
                AddComment("Capture: capability values", cmm); 
                for(int i = 0; i < bd.CaptureCapabilityChecks.Count; i++) {
 
                    string matchedString = ((CheckPair)bd.CaptureCapabilityChecks[i]).MatchString; 
                    if (matchedString.Equals(".*")) {
                        continue; 
                    }

                    GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated);
                    //GEN: regexWorker.ProcessRegex((string)dictionary["xxxCapability"], "xxxRegexString"); 
                    CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod);
                    cmie.Parameters.Add( 
                        new CodeCastExpression(typeof(string), 
                                               new CodeIndexerExpression(
                                                   _dictionaryRefExpr, 
                                                   new CodeExpression[] { new CodePrimitiveExpression(((CheckPair)bd.CaptureCapabilityChecks[i]).Header) }
                                                   )
                                               )
                        ); 

                    cmie.Parameters.Add(new CodePrimitiveExpression(matchedString)); 
                    cmm.Statements.Add(cmie); 
                }
            } 
        }

        //generate part of the xxxProcess method for assigning capability values
        private void GenerateSetCapabilitiesCode(BrowserDefinition bd, CodeMemberMethod cmm, ref bool regexWorkerGenerated) { 
            //GEN: browserCaps[aaa] = "bbb";
            //GEN: browserCaps[xxx] = "yyy"; 
            NameValueCollection nvc = bd.Capabilities; 
            CodeAssignStatement assign;
 
            AddComment("Capabilities: set capabilities", cmm);
            foreach (string s in nvc.Keys) {
                string capsString = nvc[s];
                //GEN: dictionary["xxx"] = regexWorker["xxx"]; 
                assign = new CodeAssignStatement();
                assign.Left = new CodeIndexerExpression( 
                    _dictionaryRefExpr, 
                    new CodeExpression[] { new CodePrimitiveExpression(s) } );
 
                CodePrimitiveExpression capabilityExpr = new CodePrimitiveExpression(capsString);
                if (RegexWorker.RefPat.Match(capsString).Success) {

                    GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated); 
                    assign.Right = new CodeIndexerExpression(
                        _regexWorkerRefExpr, 
                        new CodeExpression[] {capabilityExpr}); 
                }
                else { 
                    assign.Right = capabilityExpr;
                }

                cmm.Statements.Add(assign); 
            }
        } 
 
        //generate part of the xxxProcess method for setting specific adapters for this browser
        internal void GenerateSetAdaptersCode(BrowserDefinition bd, CodeMemberMethod cmm) { 
            //GEN: browserCaps.Adapters[xxxControl] = yyyAdapter;
            foreach (DictionaryEntry entry in bd.Adapters) {
                string controlString = (string)entry.Key;
                string adapterString = (string)entry.Value; 
                CodePropertyReferenceExpression cpre = new CodePropertyReferenceExpression(_browserCapsRefExpr, "Adapters");
                CodeIndexerExpression indexerExpression = new CodeIndexerExpression( 
                    cpre, 
                    new CodeExpression[] { new CodePrimitiveExpression(controlString) }
                    ); 
                CodeAssignStatement assignAdapter = new CodeAssignStatement();
                assignAdapter.Left = indexerExpression;
                assignAdapter.Right = new CodePrimitiveExpression(adapterString);
                cmm.Statements.Add(assignAdapter); 
            }
 
            //GEN: browser.HtmlTextWriter = xxxHtmlTextWriter; 
            if(bd.HtmlTextWriterString != null) {
                CodeAssignStatement assignHtmlTextWriter = new CodeAssignStatement(); 
                assignHtmlTextWriter.Left = new CodePropertyReferenceExpression(_browserCapsRefExpr, "HtmlTextWriter");
                assignHtmlTextWriter.Right = new CodePrimitiveExpression(bd.HtmlTextWriterString);
                cmm.Statements.Add(assignHtmlTextWriter);
            } 
            return;
        } 
 
        internal void AddComment(string comment, CodeMemberMethod cmm) {
            cmm.Statements.Add(new CodeCommentStatement(comment)); 
        }

        internal CodeStatementCollection GenerateTrackedSingleProcessCall(CodeStatementCollection stmts, BrowserDefinition bd, CodeMemberMethod cmm) {
            return GenerateTrackedSingleProcessCall(stmts, bd, cmm, String.Empty); 
        }
 
        internal CodeStatementCollection GenerateTrackedSingleProcessCall(CodeStatementCollection stmts, BrowserDefinition bd, CodeMemberMethod cmm, string prefix) { 
            //GEN:  if (xProcess(headers, browserCaps)) {
            //      } 
            //      else {
            //          ...
            //      }
            CodeMethodInvokeExpression xProcess = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), prefix + bd.Name + "Process"); 
            xProcess.Parameters.Add(new CodeVariableReferenceExpression(_headersRefName));
            xProcess.Parameters.Add(new CodeVariableReferenceExpression(browserCapsVariable)); 
 
            CodeConditionStatement conditionStmt = new CodeConditionStatement();
            conditionStmt.Condition = xProcess; 

            stmts.Add(conditionStmt);

            return conditionStmt.FalseStatements; 
        }
 
        internal void GenerateSingleProcessCall(BrowserDefinition bd, CodeMemberMethod cmm) { 
            GenerateSingleProcessCall(bd, cmm, String.Empty);
        } 

        //generate code to call the xxxProcess for a given browser
        //and store the result in a local variable
        internal void GenerateSingleProcessCall(BrowserDefinition bd, CodeMemberMethod cmm, string prefix) { 
            //GEN: xProcess(headers, browserCaps);
            CodeMethodInvokeExpression xProcess = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), prefix + bd.Name + "Process"); 
            xProcess.Parameters.Add(new CodeVariableReferenceExpression(_headersRefName)); 
            xProcess.Parameters.Add(new CodeVariableReferenceExpression(browserCapsVariable));
            cmm.Statements.Add(xProcess); 
        }
    }
}

// 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.Linq;
    using System.Reflection; 
    using System.Security;
    using System.Security.Permissions;
    using System.Text;
    using System.Text.RegularExpressions; 
    using System.Web;
    using System.Web.Compilation; 
    using System.Web.Configuration; 
    using System.Web.Hosting;
    using System.Web.UI; 
    using System.Web.Util;
    using System.Xml;
    using System.Xml.Schema;
 
    using Microsoft.Build.Utilities;
    using Microsoft.CSharp; 
 
    [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
    [PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)] 
    public class BrowserCapabilitiesCodeGenerator {
        private static readonly string _browsersDirectory;
        private static readonly string _publicKeyTokenFile;
 
        private static object _staticLock = new object();
 
        private BrowserTree _browserTree; 
        private BrowserTree _defaultTree;
        private BrowserDefinitionCollection _browserDefinitionCollection; 

        internal const string browserCapsVariable = "browserCaps";
        internal const string IgnoreApplicationBrowserVariableName = "ignoreApplicationBrowsers";
        private const string _factoryTypeName = "BrowserCapabilitiesFactory"; 
        private const string _headerDictionaryVarName = "_headerDictionary";
        private const string _disableOptimizedCacheKeyMethodName = "DisableOptimizedCacheKey"; 
        private const string _matchedHeadersMethodName = "PopulateMatchedHeaders"; 
        private const string _browserElementsMethodName = "PopulateBrowserElements";
        private const string _dictionaryRefName = "dictionary"; 
        private const string _regexWorkerRefName = "regexWorker";
        private const string _headersRefName = "headers";
        private const string _resultVarName = "result";
        private const string _processRegexMethod = "ProcessRegex"; 
        private static readonly string _strongNameKeyFileName = browserCapsVariable + ".snk";
        private static readonly string _publicKeyTokenFileName = browserCapsVariable + ".token"; 
        private static bool _publicKeyTokenLoaded; 
        private static string _publicKeyToken;
 
        private CodeVariableReferenceExpression _dictionaryRefExpr = new CodeVariableReferenceExpression(_dictionaryRefName);
        private CodeVariableReferenceExpression _regexWorkerRefExpr = new CodeVariableReferenceExpression(_regexWorkerRefName);
        private CodeVariableReferenceExpression _headersRefExpr = new CodeVariableReferenceExpression(_headersRefName);
        private CodeVariableReferenceExpression _browserCapsRefExpr = new CodeVariableReferenceExpression(browserCapsVariable); 

        private ArrayList _browserFileList; 
 
        private ArrayList _customBrowserFileLists;
        private ArrayList _customTreeList; 
        private ArrayList _customTreeNames;
        private ArrayList _customBrowserDefinitionCollections;

        private CaseInsensitiveStringSet _headers; 

        static BrowserCapabilitiesCodeGenerator() { 
#if !PLATFORM_UNIX // File system paths must account for UNIX 
            _browsersDirectory = HttpRuntime.ClrInstallDirectoryInternal + "\\config\\browsers";
            _publicKeyTokenFile = _browsersDirectory + "\\" + _publicKeyTokenFileName; 
#else // !PLATFORM_UNIX
            _browsersDirectory = HttpRuntime.ClrInstallDirectoryInternal + "/config/browsers";
            _publicKeyTokenFile = _browsersDirectory + "/" + _publicKeyTokenFileName;
 
#endif // !PLATFORM_UNIX
        } 
 
        public BrowserCapabilitiesCodeGenerator() {
            _headers = new CaseInsensitiveStringSet(); 
        }

        internal BrowserTree BrowserTree {
            get { 
                return _browserTree;
            } 
        } 

        internal BrowserTree DefaultTree { 
            get {
                return _defaultTree;
            }
        } 

        internal ArrayList CustomTreeList { 
            get { 
                return _customTreeList;
            } 
        }

        internal ArrayList CustomTreeNames {
            get { 
                return _customTreeNames;
            } 
        } 

        internal static string BrowserCapAssemblyPublicKeyToken { 
            get {
                if (_publicKeyTokenLoaded) {
                    return _publicKeyToken;
                } 

                lock (_staticLock) { 
                    if (_publicKeyTokenLoaded) { 
                        return _publicKeyToken;
                    } 

                    string publicKeyTokenFile;
                    if (MultiTargetingUtil.IsTargetFramework40OrAbove) {
                        publicKeyTokenFile = _publicKeyTokenFile; 
                    }
                    else { 
                        // If we are targeting pre-4.0, we should be using version 2.0 of the assembly 
                        // ASP.BrowserCapsFactory, so we need to read the token file from the 2.0 path.
                        // (Dev10 bug 795509) 
                        string subPath = @"config\browsers\" + _publicKeyTokenFileName;
                        publicKeyTokenFile = ToolLocationHelper.GetPathToDotNetFrameworkFile(subPath, TargetDotNetFrameworkVersion.Version20);
                    }
                    _publicKeyToken = LoadPublicKeyTokenFromFile(publicKeyTokenFile); 
                    _publicKeyTokenLoaded = true;
 
                    return _publicKeyToken; 
                }
            } 
        }

        internal virtual bool GenerateOverrides { get { return true; } }
 
        internal virtual string TypeName {
            get { 
                return _factoryTypeName; 
            }
        } 

        internal void AddFile(string filePath) {
            if (_browserFileList == null)
                _browserFileList = new ArrayList(); 

            _browserFileList.Add(filePath); 
        } 

        internal void AddCustomFile(string filePath) { 
            if (_customBrowserFileLists == null) {
                _customBrowserFileLists = new ArrayList();
            }
 
            _customBrowserFileLists.Add(filePath);
        } 
 
        //parse the config info and create BrowserTree
        //then generate code for, compile, and gac the object 
        [SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
        public virtual void Create() {
            DirectoryInfo browserDirInfo = new DirectoryInfo(_browsersDirectory);
            //get all the browser files and put them in the "tree" 
            FileInfo[] browserFiles = browserDirInfo.GetFiles("*.browser");
 
            if (browserFiles == null || browserFiles.Length == 0) { 
                return;
            } 

            foreach(FileInfo browserFile in browserFiles) {
                AddFile(browserFile.FullName);
            } 

            // First parse the browser files. 
            ProcessBrowserFiles(); 

            // Then parse custom browser files. 
            ProcessCustomBrowserFiles();

            // Uninstall previously installed generated assembly.
            Uninstall(); 

            //generate the source code, compile it, and gac it 
            GenerateAssembly(); 

            // Restart w3svc service 
            RestartW3SVCIfNecessary();
        }

        internal bool UninstallInternal() { 
            // Remove existing strong name public token file
            if (File.Exists(_publicKeyTokenFile)) { 
                File.Delete(_publicKeyTokenFile); 
            }
 
            // Removing existing copy from GAC
            GacUtil gacutil = new GacUtil();
            bool assemblyRemoved = gacutil.GacUnInstall("ASP.BrowserCapsFactory, Version=" + ThisAssembly.Version + ", Culture=neutral");
            if (!assemblyRemoved) { 
                return false;
            } 
 
            return true;
        } 

        [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
        public bool Uninstall() {
            // Restart w3svc service 
            RestartW3SVCIfNecessary();
 
            if (!UninstallInternal()) { 
                return false;
            } 

            // Restart w3svc service again so applications get a fresh copy.
            RestartW3SVCIfNecessary();
 
            return true;
        } 
 
        private void RestartW3SVCIfNecessary() {
#if !FEATURE_PAL 
            try {
                // Dev10 bug 734918
                // We should not fail when the w3svc service is not installed.
                ServiceController[] services = ServiceController.GetServices(); 
                ServiceController controller = services.SingleOrDefault(s => String.Equals(s.ServiceName, "W3SVC", StringComparison.OrdinalIgnoreCase));
                if (controller == null) { 
                    return; 
                }
 
                ServiceControllerStatus status = controller.Status;

                // Stop the service if it's not currently stopped or pending.
                if (!status.Equals(ServiceControllerStatus.Stopped) && 
                    !status.Equals(ServiceControllerStatus.StopPending) &&
                    !status.Equals(ServiceControllerStatus.StartPending)) { 
                    controller.Stop(); 

                    // Give it 5 minutes to stop 
                    controller.WaitForStatus(ServiceControllerStatus.Stopped, new TimeSpan(0, 5, 0));
                    controller.Start();

                    // If the service was paused, pause it. 
                    if (status.Equals(ServiceControllerStatus.Paused) || status.Equals(ServiceControllerStatus.PausePending)) {
                        controller.Pause(); 
                    } 
                }
            } 
            catch (Exception ex) {
                throw new InvalidOperationException(SR.GetString(SR.Browser_W3SVC_Failure_Helper_Text, ex));
            }
#endif // !FEATURE_PAL 
        }
 
        internal void ProcessBrowserFiles() { 
            ProcessBrowserFiles(false, String.Empty);
        } 

        private string NoPathFileName(string fullPath) {
            int lastSlash = fullPath.LastIndexOf("\\", StringComparison.Ordinal);
            if(lastSlash > -1) { 
                return fullPath.Substring(lastSlash + 1);
            } 
            return fullPath; 
        }
 
        internal virtual void ProcessBrowserNode(XmlNode node, BrowserTree browserTree) {

            BrowserDefinition browserInfo = null;
 
            if (node.Name == "gateway") {
                browserInfo = new GatewayDefinition(node); 
            } 
            else if (node.Name == "browser") {
                browserInfo = new BrowserDefinition(node); 
            }
            else {
                Debug.Assert(node.Name == "defaultBrowser");
                browserInfo = new BrowserDefinition(node, true); 
            }
 
            BrowserDefinition oldNode = (BrowserDefinition)browserTree[browserInfo.Name]; 

            if (oldNode != null) { 
                if (browserInfo.IsRefID) {
                    oldNode.MergeWithDefinition(browserInfo);
                }
                else { 
                    throw new ConfigurationErrorsException(SR.GetString(SR.Duplicate_browser_id, browserInfo.ID), node);
                } 
            } 
            else {
                browserTree[browserInfo.Name] = browserInfo; 
            }
        }

        private void NormalizeAndValidateTree(BrowserTree browserTree, bool isDefaultBrowser) { 
            NormalizeAndValidateTree(browserTree, isDefaultBrowser, false);
        } 
 
        private void NormalizeAndValidateTree(BrowserTree browserTree, bool isDefaultBrowser, bool isCustomBrowser) {
            //normalize the tree 
            foreach (DictionaryEntry entry in browserTree) {
                BrowserDefinition bd = (BrowserDefinition)entry.Value;
                string parentName = bd.ParentName;
                BrowserDefinition parentBrowser = null; 

                if (IsRootNode(bd.Name)) { 
                    continue; 
                }
 
                if (parentName.Length > 0) {
                    parentBrowser = (BrowserDefinition)browserTree[parentName];
                }
 
                if (parentBrowser != null) {
                    if (bd.IsRefID) { 
                        if (bd is GatewayDefinition) { 
                            parentBrowser.RefGateways.Add(bd);
                        } 
                        else {
                            parentBrowser.RefBrowsers.Add(bd);
                        }
                    } 
                    else if (bd is GatewayDefinition) {
                        parentBrowser.Gateways.Add(bd); 
                    } 
                    else {
                        parentBrowser.Browsers.Add(bd); 
                    }
                }
                else {
                    if (isCustomBrowser) { 
                        throw new ConfigurationErrorsException(SR.GetString(SR.Browser_parentID_Not_Found, bd.ParentID), bd.XmlNode);
                    } 
                    else { 
                        HandleUnRecognizedParentElement(bd, isDefaultBrowser);
                    } 
                }
            }

            //validate the tree 
            //loop check
            foreach (DictionaryEntry entry in browserTree) { 
                BrowserDefinition bd = (BrowserDefinition)entry.Value; 
                Hashtable loopCheck = new Hashtable();
                BrowserDefinition currentBrowser = bd; 
                string currentId = currentBrowser.Name;
                while (!IsRootNode(currentId)) {
                    if (loopCheck[currentId] != null) {
                        throw new ConfigurationErrorsException(SR.GetString(SR.Browser_Circular_Reference, currentId), currentBrowser.XmlNode); 
                    }
                    loopCheck[currentId] = currentId; 
                    currentBrowser = (BrowserDefinition)browserTree[currentBrowser.ParentName]; 
                    //in app-level, parent can exist in machine level
                    if (currentBrowser == null) { 
                        break;
                    }

                    currentId = currentBrowser.Name; 
                }
            } 
        } 

        private void SetCustomTreeRoots(BrowserTree browserTree, int index) { 
            foreach (DictionaryEntry entry in browserTree) {
                BrowserDefinition bd = (BrowserDefinition)entry.Value;
                if (bd.ParentName == null) {
                    _customTreeNames[index] = bd.Name; 
                    break;
                } 
            } 
        }
 
        // Now that we support adding custom browser hierarchies, root nodes other than Default are permitted.
        private bool IsRootNode(string nodeName) {
            if (String.Compare(nodeName, "Default", StringComparison.OrdinalIgnoreCase) == 0)
                return true; 

            foreach (string treeRootName in _customTreeNames) { 
                if (String.Compare(nodeName, treeRootName, StringComparison.OrdinalIgnoreCase) == 0) { 
                    return true;
                } 
            }

            return false;
        } 

        protected void ProcessBrowserFiles(bool useVirtualPath, string virtualDir) { 
            _browserTree = new BrowserTree(); 
            _defaultTree = new BrowserTree();
            _customTreeNames = new ArrayList(); 

            if (_browserFileList == null) {
                _browserFileList = new ArrayList();
            } 

            _browserFileList.Sort(); 
//#if OPTIMIZE_FOR_DESKTOP_BROWSER 
            string mozillaFile = null;
            string ieFile = null; 
            string operaFile = null;

            // DevDivBugs 180962
            // IE, Mozilla and Opera are first-class browsers. Their User-Agent profiles need to be compared to the UA profile 
            // of the HTTP request before other browsers. We put them to the head of the list so that the generated browser capabilities
            // code will try to match them before other browsers. 
            foreach (String filePath in _browserFileList) { 
                if (filePath.EndsWith("ie.browser", StringComparison.OrdinalIgnoreCase)) {
                    ieFile = filePath; 
                }
                else if (filePath.EndsWith("mozilla.browser", StringComparison.OrdinalIgnoreCase)) {
                    mozillaFile = filePath;
                } 
                else if (filePath.EndsWith("opera.browser", StringComparison.OrdinalIgnoreCase)) {
                    operaFile = filePath; 
                    break; 
                }
            } 

            if (ieFile != null) {
                _browserFileList.Remove(ieFile);
                _browserFileList.Insert(0, ieFile); 
            }
 
            if (mozillaFile != null) { 
                _browserFileList.Remove(mozillaFile);
                _browserFileList.Insert(1, mozillaFile); 
            }

            if (operaFile != null) {
                _browserFileList.Remove(operaFile); 
                _browserFileList.Insert(2, operaFile);
            } 
//#endif 
            foreach (string fileName in _browserFileList) {
                XmlDocument doc = new ConfigXmlDocument(); 
                try {
                    doc.Load(fileName);

                    XmlNode rootNode = doc.DocumentElement; 
                    if(rootNode.Name != "browsers") {
                        if(useVirtualPath) { 
                            throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, 1); 
                        }
                        else { 
                            throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, fileName, null /*sourceCode*/, 1);
                        }
                    }
 
                    foreach (XmlNode node in rootNode.ChildNodes) {
                        if (node.NodeType != XmlNodeType.Element) 
                            continue; 
                        if (node.Name == "browser" || node.Name == "gateway") {
                            ProcessBrowserNode(node, _browserTree); 
                        }
                        else if (node.Name == "defaultBrowser") {
                            ProcessBrowserNode(node, _defaultTree);
                        } 
                        else {
                            HandlerBase.ThrowUnrecognizedElement(node); 
                        } 
                    }
                } 
                catch (XmlException e) {
                    if(useVirtualPath) {
                        throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber);
                    } 
                    else {
                        throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber); 
                    } 
                }
                catch (XmlSchemaException e) { 
                    if(useVirtualPath) {
                        throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber);
                    }
                    else { 
                        throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber);
                    } 
                } 
            }
            NormalizeAndValidateTree(_browserTree, false); 
            NormalizeAndValidateTree(_defaultTree, true);

            BrowserDefinition defaultBrowser = (BrowserDefinition)_browserTree["Default"];
 
            if (defaultBrowser != null) {
                AddBrowserToCollectionRecursive(defaultBrowser, 0); 
            } 
        }
 
        internal void ProcessCustomBrowserFiles() {
            ProcessCustomBrowserFiles(false, String.Empty);
        }
 
        internal void ProcessCustomBrowserFiles(bool useVirtualPath, string virtualDir) {
            //get all custom browser files and put them in the "tree" 
            DirectoryInfo browserDirInfo = null; 
            DirectoryInfo[] browserSubDirectories = null;
            DirectoryInfo[] allBrowserSubDirectories = null; 
            ArrayList customBrowserFileNames;
            _customTreeList = new ArrayList();
            _customBrowserFileLists = new ArrayList();
            _customBrowserDefinitionCollections = new ArrayList(); 

            /* Machine Level Custom Browsers */ 
            if (useVirtualPath == false) { 
                browserDirInfo = new DirectoryInfo(_browsersDirectory);
            } 
            /* Application Level Custom Browsers */
            else {
                browserDirInfo = new DirectoryInfo(HostingEnvironment.MapPathInternal(virtualDir));
            } 

            allBrowserSubDirectories = browserDirInfo.GetDirectories(); 
 
            int j = 0;
            int length = allBrowserSubDirectories.Length; 
            browserSubDirectories = new DirectoryInfo[length];
            for (int i = 0; i < length; i++) {
                if ((allBrowserSubDirectories[i].Attributes & FileAttributes.Hidden) != FileAttributes.Hidden) {
                    browserSubDirectories[j] = allBrowserSubDirectories[i]; 
                    j++;
                } 
            } 
            Array.Resize(ref browserSubDirectories, j);
 
            for (int i = 0; i < browserSubDirectories.Length; i++) {
                /* Recursively Into Subdirectories */
                FileInfo[] browserFiles = GetFilesNotHidden(browserSubDirectories[i], browserDirInfo);
 
                if (browserFiles == null || browserFiles.Length == 0) {
                    continue; 
                } 
                BrowserTree customTree = new BrowserTree();
                _customTreeList.Add(customTree); 
                _customTreeNames.Add(browserSubDirectories[i].Name);
                customBrowserFileNames = new ArrayList();

                foreach (FileInfo browserFile in browserFiles) { 
                    customBrowserFileNames.Add(browserFile.FullName);
                } 
                _customBrowserFileLists.Add(customBrowserFileNames); 
            }
            for (int i = 0; i < _customBrowserFileLists.Count; i++) { 
                ArrayList fileNames = (ArrayList)_customBrowserFileLists[i];
                foreach (string fileName in fileNames) {
                    XmlDocument doc = new ConfigXmlDocument();
                    try { 
                        doc.Load(fileName);
 
                        XmlNode rootNode = doc.DocumentElement; 
                        if (rootNode.Name != "browsers") {
                            if (useVirtualPath) { 
                                throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, 1);
                            }
                            else {
                                throw new HttpParseException(SR.GetString(SR.Invalid_browser_root), null /*innerException*/, fileName, null /*sourceCode*/, 1); 
                            }
                        } 
                        foreach (XmlNode node in rootNode.ChildNodes) { 
                            if (node.NodeType != XmlNodeType.Element) {
                                continue; 
                            }
                            if (node.Name == "browser" || node.Name == "gateway") {
                                ProcessBrowserNode(node, (BrowserTree)_customTreeList[i]);
                            } 
                            else {
                                HandlerBase.ThrowUnrecognizedElement(node); 
                            } 
                        }
                    } 
                    catch (XmlException e) {
                        if (useVirtualPath) {
                            throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber);
                        } 
                        else {
                            throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber); 
                        } 
                    }
                    catch (XmlSchemaException e) { 
                        if (useVirtualPath) {
                            throw new HttpParseException(e.Message, null /*innerException*/, virtualDir + "/" + NoPathFileName(fileName), null /*sourceCode*/, e.LineNumber);
                        }
                        else { 
                            throw new HttpParseException(e.Message, null /*innerException*/, fileName, null /*sourceCode*/, e.LineNumber);
                        } 
                    } 
                }
                SetCustomTreeRoots((BrowserTree)_customTreeList[i], i); 
                NormalizeAndValidateTree((BrowserTree)_customTreeList[i], false, true);
                _customBrowserDefinitionCollections.Add(new BrowserDefinitionCollection());
                AddCustomBrowserToCollectionRecursive((BrowserDefinition)(((BrowserTree)_customTreeList[i])[_customTreeNames[i]]), 0, i);
            } 
        }
 
        internal void AddCustomBrowserToCollectionRecursive(BrowserDefinition bd, int depth, int index) { 
            if(_customBrowserDefinitionCollections[index] == null) {
                _customBrowserDefinitionCollections[index] = new BrowserDefinitionCollection(); 
            }
            bd.Depth = depth;
            bd.IsDeviceNode = true;
            ((BrowserDefinitionCollection)_customBrowserDefinitionCollections[index]).Add(bd); 

            foreach (BrowserDefinition childBrowser in bd.Browsers) { 
                AddCustomBrowserToCollectionRecursive(childBrowser, depth + 1, index); 
            }
        } 

        internal void AddBrowserToCollectionRecursive(BrowserDefinition bd, int depth) {
            if (_browserDefinitionCollection == null) {
                _browserDefinitionCollection = new BrowserDefinitionCollection(); 
            }
 
            bd.Depth = depth; 
            bd.IsDeviceNode = true;
            _browserDefinitionCollection.Add(bd); 

            foreach(BrowserDefinition childBrowser in bd.Browsers) {
                AddBrowserToCollectionRecursive(childBrowser, depth + 1);
            } 
        }
 
        internal virtual void HandleUnRecognizedParentElement(BrowserDefinition bd, bool isDefault) { 
            throw new ConfigurationErrorsException(SR.GetString(SR.Browser_parentID_Not_Found, bd.ParentID), bd.XmlNode);
        } 

        private static FileInfo[] GetFilesNotHidden(DirectoryInfo rootDirectory, DirectoryInfo browserDirInfo) {
            ArrayList fileList = new ArrayList();
            FileInfo[] files; 
            DirectoryInfo[] subDirectories = rootDirectory.GetDirectories("*", SearchOption.AllDirectories);
 
            files = rootDirectory.GetFiles("*.browser", SearchOption.TopDirectoryOnly); 
            fileList.AddRange(files);
            for (int i = 0; i < subDirectories.Length; i++) { 
                if ((HasHiddenParent(subDirectories[i], browserDirInfo) == false)) {
                    files = subDirectories[i].GetFiles("*.browser", SearchOption.TopDirectoryOnly);
                    fileList.AddRange(files);
                } 
            }
            return ((FileInfo [])fileList.ToArray(typeof(FileInfo))); 
        } 

        private static bool HasHiddenParent(DirectoryInfo directory, DirectoryInfo browserDirInfo) { 
            while(!String.Equals(directory.Parent.Name, browserDirInfo.Name)) {
                if ((directory.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) {
                    return true;
                } 
                directory = directory.Parent;
            } 
            return false; 
        }
 
        //generate the code from the parsed BrowserDefinitionTree
        //compile it, and install it in the gac
        private void GenerateAssembly() {
            Debug.Assert(_browserTree != null); 
            BrowserDefinition root = (BrowserDefinition)_browserTree["Default"];
            BrowserDefinition defaultRoot = (BrowserDefinition)_defaultTree["Default"]; 
            ArrayList customTreeRoots = new ArrayList(); 
            for (int i = 0; i < _customTreeNames.Count; i++) {
                customTreeRoots.Add((BrowserDefinition)(((BrowserTree)_customTreeList[i])[_customTreeNames[i]])); 
            }

            //create a CodeCompileUnit
            //add a CodeNamespace object to the CodeCompileUnit 
            //add a CodeTypeDeclaration to the CodeNamespace
            //add all the members of the type/class to the CodeTypeDeclaration 
            //use a CodeGenerator to generate code from the CodeCompileUnit 
            //a CodeDomProvider can provide a CodeGenerator
 
            //translate the BrowserDefinition tree to code
            CSharpCodeProvider cscp = new CSharpCodeProvider();

            // namespace System.Web.BrowserCapsFactory 
            CodeCompileUnit ccu = new CodeCompileUnit();
 
            //add strong-name key pair for 
            CodeAttributeDeclaration declaration = new CodeAttributeDeclaration(
                "System.Reflection.AssemblyKeyFile", 
                new CodeAttributeArgument[] {
                    new CodeAttributeArgument(new CodePrimitiveExpression(_strongNameKeyFileName))});

            CodeAttributeDeclaration aptca = new CodeAttributeDeclaration( 
                "System.Security.AllowPartiallyTrustedCallers");
            ccu.AssemblyCustomAttributes.Add(aptca); 
 
            ccu.AssemblyCustomAttributes.Add(declaration);
            //add version number for it so it can distinguished in future versions 
            declaration = new CodeAttributeDeclaration(
                "System.Reflection.AssemblyVersion",
                new CodeAttributeArgument[] {
                    new CodeAttributeArgument(new CodePrimitiveExpression(ThisAssembly.Version))}); 
            ccu.AssemblyCustomAttributes.Add(declaration);
 
            CodeNamespace cnamespace = new CodeNamespace("ASP"); 
            //GEN: using System;
            cnamespace.Imports.Add(new CodeNamespaceImport("System")); 
            //GEN: using System.Web;
            cnamespace.Imports.Add(new CodeNamespaceImport("System.Web"));
            //GEN: using System.Web.Configuration;
            cnamespace.Imports.Add(new CodeNamespaceImport("System.Web.Configuration")); 
            //GEN: using System.Reflection;
            cnamespace.Imports.Add(new CodeNamespaceImport("System.Reflection")); 
            //GEN: class BrowserCapabilitiesFactory 
            ccu.Namespaces.Add(cnamespace);
 
            CodeTypeDeclaration factoryType = new CodeTypeDeclaration("BrowserCapabilitiesFactory");
            factoryType.Attributes = MemberAttributes.Private;
            factoryType.IsClass = true;
            factoryType.Name = TypeName; 
            factoryType.BaseTypes.Add(new CodeTypeReference("System.Web.Configuration.BrowserCapabilitiesFactoryBase"));
            cnamespace.Types.Add(factoryType); 
 
            //GEN: protected override object ConfigureBrowserCapabilities(NameValueCollection headers, HttpBrowserCapabilities browserCaps)
            CodeMemberMethod method = new CodeMemberMethod(); 
            method.Attributes = MemberAttributes.Override | MemberAttributes.Public;
            method.ReturnType = new CodeTypeReference(typeof(void));
            method.Name = "ConfigureBrowserCapabilities";
 
            CodeParameterDeclarationExpression cpde = new CodeParameterDeclarationExpression(typeof(NameValueCollection), _headersRefName);
            method.Parameters.Add(cpde); 
            cpde = new CodeParameterDeclarationExpression(typeof(HttpBrowserCapabilities), browserCapsVariable); 
            method.Parameters.Add(cpde);
            factoryType.Members.Add(method); 

            GenerateSingleProcessCall(root, method);

            for (int i = 0; i < customTreeRoots.Count; i++) { 
                GenerateSingleProcessCall((BrowserDefinition)customTreeRoots[i], method);
            } 
 
            //GEN: if(this.IsBrowserUnknown(browserCaps) == false) return;
            CodeConditionStatement istatement = new CodeConditionStatement(); 

            CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "IsBrowserUnknown");
            cmie.Parameters.Add(_browserCapsRefExpr);
            istatement.Condition = new CodeBinaryOperatorExpression(cmie, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false)); 
            istatement.TrueStatements.Add(new CodeMethodReturnStatement());
            method.Statements.Add(istatement); 
 
            if(defaultRoot != null) {
                GenerateSingleProcessCall(defaultRoot, method, "Default"); 
            }

            for (int i = 0; i < customTreeRoots.Count; i++) {
                foreach (DictionaryEntry entry in (BrowserTree)_customTreeList[i]) { 
                    BrowserDefinition bd = entry.Value as BrowserDefinition;
                    Debug.Assert(bd != null); 
                    GenerateProcessMethod(bd, factoryType); 
                }
            } 

            //GenerateCallsToProcessMethods(root, method);
            foreach (DictionaryEntry entry in _browserTree) {
                BrowserDefinition bd = entry.Value as BrowserDefinition; 
                Debug.Assert(bd != null);
                GenerateProcessMethod(bd, factoryType); 
            } 

            foreach (DictionaryEntry entry in _defaultTree) { 
                BrowserDefinition bd = entry.Value as BrowserDefinition;
                Debug.Assert(bd != null);
                GenerateProcessMethod(bd, factoryType, "Default");
            } 

            GenerateOverrideMatchedHeaders(factoryType); 
            GenerateOverrideBrowserElements(factoryType); 

            //TODO: don't actually generate the code, just compile it in memory 
            TextWriter twriter = new StreamWriter(new FileStream(_browsersDirectory + "\\BrowserCapsFactory.cs", FileMode.Create));
            try {
                cscp.GenerateCodeFromCompileUnit(ccu, twriter, null);
            } 
            finally {
                if(twriter != null) 
                    twriter.Close(); 
            }
 
            CompilationSection compConfig = MTConfigUtil.GetCompilationAppConfig();

            bool debug = compConfig.Debug;
 
#if !PLATFORM_UNIX // File system paths must account for UNIX
            string strongNameFile = _browsersDirectory + "\\" + _strongNameKeyFileName; 
#else // !PLATFORM_UNIX 
            string strongNameFile = _browsersDirectory + "/" + _strongNameKeyFileName;
#endif // !PLATFORM_UNIX 

            // Generate strong name file
            StrongNameUtility.GenerateStrongNameFile(strongNameFile);
 
            //TODO: do not use interim file:  CompileAssemblyFromDom instead
            string[] referencedAssemblies = new string[2] { "System.dll", "System.Web.dll" }; 
            CompilerParameters compilerParameters = new CompilerParameters(referencedAssemblies, "ASP.BrowserCapsFactory", debug /* includeDebugInformation */ ); 
            compilerParameters.GenerateInMemory = false;
            compilerParameters.OutputAssembly = _browsersDirectory + "\\ASP.BrowserCapsFactory.dll"; 
            CompilerResults results = null;

            try {
                results = cscp.CompileAssemblyFromFile(compilerParameters, _browsersDirectory + "\\BrowserCapsFactory.cs"); 
            }
            finally { 
                if (File.Exists(strongNameFile)) { 
                    File.Delete(strongNameFile);
                } 
            }

            if (results.NativeCompilerReturnValue != 0 || results.Errors.HasErrors) {
                foreach (CompilerError error in results.Errors) { 
                    if (!error.IsWarning) {
                        throw new HttpCompileException(error.ErrorText); 
                    } 
                }
 
                throw new HttpCompileException(SR.GetString(SR.Browser_compile_error));
            }

            Assembly resultAssembly = results.CompiledAssembly; 

            GacUtil gacutil = new GacUtil(); 
            gacutil.GacInstall(resultAssembly.Location); 

            SavePublicKeyTokenFile(_publicKeyTokenFile, resultAssembly.GetName().GetPublicKeyToken()); 
        }

        private void SavePublicKeyTokenFile(string filename, byte[] publicKeyToken) {
            using (FileStream pktStream = new FileStream(filename, FileMode.Create, FileAccess.Write)) { 
                using (StreamWriter pktWriter = new StreamWriter(pktStream)) {
                    foreach (byte b in publicKeyToken) { 
                        pktWriter.Write("{0:X2}", b); 
                    }
                } 
            }
        }

        private static string LoadPublicKeyTokenFromFile(string filename) { 
            IStackWalk fileReadAccess = InternalSecurityPermissions.FileReadAccess(filename);
            Debug.Assert(fileReadAccess != null); 
            fileReadAccess.Assert(); 
            if (!File.Exists(filename)) {
                return null; 
            }

            try {
                using (FileStream pktStream = new FileStream(filename, FileMode.Open, FileAccess.Read)) { 
                    using (StreamReader pktReader = new StreamReader(pktStream)) {
                        return pktReader.ReadLine(); 
                    } 
                }
            } 
            catch (IOException) {
                if (HttpRuntime.HasFilePermission(filename)) {
                    throw;
                } 

                // Don't throw exception if we don't have permission to the file. 
                return null; 
            }
            finally { 
                CodeAccessPermission.RevertAssert();
            }
        }
 
        internal void GenerateOverrideBrowserElements(CodeTypeDeclaration typeDeclaration) {
 
            // Don't generate the property if there's nothing to override. 
            if (_browserDefinitionCollection == null) {
                return; 
            }

            // GEN:
            // protected override void PopulateBrowserElements(IDictionary dictionary) { 
            //     dictionary["Default"] = new Triplet(null, "default description", 0 /*depth_of_node */);
            //     dictionary["Up"] = new Triplet("Default", "up Description", 1 /*depth_of_node */); 
            // } 
            CodeMemberMethod method = new CodeMemberMethod();
            method.Name = _browserElementsMethodName; 
            method.Attributes = MemberAttributes.Override | MemberAttributes.Family;
            method.ReturnType = new CodeTypeReference(typeof(void));
            CodeParameterDeclarationExpression parameter =
                new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IDictionary)), _dictionaryRefName); 

            method.Parameters.Add(parameter); 
            typeDeclaration.Members.Add(method); 

            CodeMethodReferenceExpression baseMethod = new CodeMethodReferenceExpression(new CodeBaseReferenceExpression(), _browserElementsMethodName); 
            CodeMethodInvokeExpression baseInvoke = new CodeMethodInvokeExpression(baseMethod, new CodeExpression[] { _dictionaryRefExpr });
            method.Statements.Add(baseInvoke);

            foreach(BrowserDefinition bd in _browserDefinitionCollection) { 
                if (!bd.IsDeviceNode)
                    continue; 
 
                Debug.Assert(!(bd is GatewayDefinition));
 
                CodeAssignStatement cas = new CodeAssignStatement();
                cas.Left = new CodeIndexerExpression(_dictionaryRefExpr, new CodeExpression[] {
                                                                             new CodePrimitiveExpression(bd.ID)
                                                                          }); 
                cas.Right = new CodeObjectCreateExpression(typeof(Triplet),
                    new CodeExpression[] { 
                        new CodePrimitiveExpression(bd.ParentName), 
                        new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "Empty"),
                        new CodePrimitiveExpression(bd.Depth)}); 

                method.Statements.Add(cas);
            }
 
            for (int i = 0; i < _customTreeNames.Count; i++) {
                foreach (BrowserDefinition bd in (BrowserDefinitionCollection)_customBrowserDefinitionCollections[i]) { 
                    if (!bd.IsDeviceNode) 
                        continue;
 
                    Debug.Assert(!(bd is GatewayDefinition));

                    CodeAssignStatement cas = new CodeAssignStatement();
                    cas.Left = new CodeIndexerExpression(_dictionaryRefExpr, new CodeExpression[] { 
                                                                             new CodePrimitiveExpression(bd.ID)
                                                                           }); 
                    cas.Right = new CodeObjectCreateExpression(typeof(Triplet), 
                        new CodeExpression[] {
                        new CodePrimitiveExpression(bd.ParentName), 
                        new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "Empty"),
                        new CodePrimitiveExpression(bd.Depth)});

                    method.Statements.Add(cas); 
                }
            } 
        } 

        internal void GenerateOverrideMatchedHeaders(CodeTypeDeclaration typeDeclaration) { 
            // GEN:
            // protected override void PopulateMatchedHeaders(IDictionary dictionary) {
            //     base.PopulateMatchedHeaders(dictionary);
            // 
            //     dictionary["header0"] = null;
            //     dictionary["header1"] = null; 
            // } 
            CodeMemberMethod method = new CodeMemberMethod();
            method.Name = _matchedHeadersMethodName; 
            method.Attributes = MemberAttributes.Override | MemberAttributes.Family;
            method.ReturnType = new CodeTypeReference(typeof(void));
            CodeParameterDeclarationExpression parameter =
                new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IDictionary)), _dictionaryRefName); 

            method.Parameters.Add(parameter); 
            typeDeclaration.Members.Add(method); 

            CodeMethodReferenceExpression baseMethod = new CodeMethodReferenceExpression(new CodeBaseReferenceExpression(), _matchedHeadersMethodName); 
            CodeMethodInvokeExpression baseInvoke = new CodeMethodInvokeExpression(baseMethod, new CodeExpression[] { _dictionaryRefExpr });
            method.Statements.Add(baseInvoke);

            foreach(String header in _headers) { 
                CodeAssignStatement cas = new CodeAssignStatement();
                cas.Left = new CodeIndexerExpression(_dictionaryRefExpr, new CodeExpression[] { 
                                                                             new CodePrimitiveExpression(header) 
                                                                          });
                cas.Right = new CodePrimitiveExpression(null); 

                method.Statements.Add(cas);
            }
        } 

        internal void GenerateProcessMethod(BrowserDefinition bd, CodeTypeDeclaration ctd) { 
            GenerateProcessMethod(bd, ctd, String.Empty); 
        }
 
        //generate the xxxProcess method for an individual BrowserDefinition
        internal void GenerateProcessMethod(BrowserDefinition bd, CodeTypeDeclaration ctd, string prefix) {
            //GEN: internal bool XxxProcess(NameValueCollection headers, HttpBrowserCapabilities browserCaps)
            CodeMemberMethod cmm = new CodeMemberMethod(); 
            cmm.Name = prefix + bd.Name + "Process";
            cmm.ReturnType = new CodeTypeReference(typeof(bool)); 
            cmm.Attributes = MemberAttributes.Private; 
            CodeParameterDeclarationExpression cpde = new CodeParameterDeclarationExpression(typeof(NameValueCollection), _headersRefName);
            cmm.Parameters.Add(cpde); 
            cpde = new CodeParameterDeclarationExpression(typeof(HttpBrowserCapabilities), browserCapsVariable);
            cmm.Parameters.Add(cpde);

            bool regexWorkerGenerated = false; 

            GenerateIdentificationCode(bd, cmm, ref regexWorkerGenerated); 
            GenerateCapturesCode(bd, cmm, ref regexWorkerGenerated); 
            GenerateSetCapabilitiesCode(bd, cmm, ref regexWorkerGenerated);
            GenerateSetAdaptersCode(bd, cmm); 

            // Only add the browser node to the browser collection if it represents a device.
            if (bd.IsDeviceNode) {
                Debug.Assert(!(bd is GatewayDefinition)); 

                //GEN: browserCaps.AddBrowser("xxx"); 
                CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression(browserCapsVariable), "AddBrowser"); 
                cmie.Parameters.Add(new CodePrimitiveExpression(bd.ID));
                cmm.Statements.Add(cmie); 
            }

            // Generate ref gateway elements
            foreach (BrowserDefinition b in bd.RefGateways) { 
                AddComment("ref gateways, parent=" + bd.ID, cmm);
                GenerateSingleProcessCall(b, cmm); 
            } 

            if ((GenerateOverrides) && (prefix.Length == 0)) { 
                //Gen: protected virtual void XxxProcessGateways(NameValueCollection headers, HttpBrowserCapabilities browserCaps) ;
                string methodName = prefix + bd.Name + "ProcessGateways";
                GenerateChildProcessMethod(methodName, ctd, false);
 
                //Gen: XxxProcessGateways(headers,  browserCaps) ;
                GenerateChildProcessInvokeExpression(methodName, cmm, false); 
            } 

            foreach(BrowserDefinition b in bd.Gateways) { 
                AddComment("gateway, parent=" + bd.ID, cmm);
                GenerateSingleProcessCall(b, cmm);
            }
 
            if (GenerateOverrides) {
                //GEN: bool ignoreApplicationBrowsers = true | false; //bd.Browsers.Count != 0 
                CodeVariableDeclarationStatement cvds = new CodeVariableDeclarationStatement(typeof(bool), 
                    IgnoreApplicationBrowserVariableName, new CodePrimitiveExpression(bd.Browsers.Count != 0));
                cmm.Statements.Add(cvds); 
            }

            if (bd.Browsers.Count > 0) {
                CodeStatementCollection statements = cmm.Statements; 
                AddComment("browser, parent=" + bd.ID, cmm);
                foreach (BrowserDefinition b in bd.Browsers) { 
                    statements = GenerateTrackedSingleProcessCall(statements, b, cmm, prefix); 
                }
 
                if (GenerateOverrides) {
                    //GEN: ignoreApplicationBrowsers = false;
                    CodeAssignStatement codeAssignStmt = new CodeAssignStatement();
                    codeAssignStmt.Left = new CodeVariableReferenceExpression(IgnoreApplicationBrowserVariableName); 
                    codeAssignStmt.Right = new CodePrimitiveExpression(false);
                    statements.Add(codeAssignStmt); 
                } 
            }
 
            // Generate ref browser
            foreach (BrowserDefinition b in bd.RefBrowsers) {
                AddComment("ref browsers, parent=" + bd.ID, cmm);
                if (b.IsDefaultBrowser) { 
                    GenerateSingleProcessCall(b, cmm, "Default");
                } 
                else { 
                    GenerateSingleProcessCall(b, cmm);
                } 
            }

            if (GenerateOverrides) {
                //Gen: protected virtual void XxxProcessBrowsers(bool ignoreApplicationBrowsers, NameValueCollection headers, HttpBrowserCapabilities browserCaps) ; 
                string methodName = prefix + bd.Name + "ProcessBrowsers";
                GenerateChildProcessMethod(methodName, ctd, true); 
 
                //Gen: XxxProcessBrowsers(ignoreApplicationBrowsers, headers, browserCaps);
                GenerateChildProcessInvokeExpression(methodName, cmm, true); 
            }

            //GEN: return true;
            CodeMethodReturnStatement cmrs = new CodeMethodReturnStatement(new CodePrimitiveExpression(true)); 
            cmm.Statements.Add(cmrs);
 
            ctd.Members.Add(cmm); 
        }
 
        private void GenerateChildProcessInvokeExpression(string methodName, CodeMemberMethod cmm, bool generateTracker) {
            //Gen: XxxProcessBrowsers(ignoreApplicationBrowsers, headers, browserCaps) ;
            CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), methodName);
 
            if (generateTracker) {
                expr.Parameters.Add(new CodeVariableReferenceExpression(IgnoreApplicationBrowserVariableName)); 
            } 
            expr.Parameters.Add(new CodeVariableReferenceExpression(_headersRefName));
            expr.Parameters.Add(new CodeVariableReferenceExpression(browserCapsVariable)); 

            cmm.Statements.Add(expr);
        }
 
        private void GenerateChildProcessMethod(string methodName, CodeTypeDeclaration ctd, bool generateTracker) {
            //Gen: protected virtual void XxxProcessBrowsers(bool ignoreApplicationBrowsers, NameValueCollection headers, HttpBrowserCapabilities browserCaps) ; 
            CodeMemberMethod cmm= new CodeMemberMethod(); 
            cmm.Name = methodName;
            cmm.ReturnType = new CodeTypeReference(typeof(void)); 
            cmm.Attributes = MemberAttributes.Family;
            CodeParameterDeclarationExpression cpde = null;

            if (generateTracker) { 
                cpde = new CodeParameterDeclarationExpression(typeof(bool), IgnoreApplicationBrowserVariableName);
                cmm.Parameters.Add(cpde); 
            } 

            cpde = new CodeParameterDeclarationExpression(typeof(NameValueCollection), _headersRefName); 
            cmm.Parameters.Add(cpde);
            cpde = new CodeParameterDeclarationExpression(typeof(HttpBrowserCapabilities), browserCapsVariable);
            cmm.Parameters.Add(cpde);
 
            ctd.Members.Add(cmm);
        } 
 
        private void GenerateRegexWorkerIfNecessary(CodeMemberMethod cmm, ref bool regexWorkerGenerated) {
            if (regexWorkerGenerated) { 
                return;
            }

            regexWorkerGenerated = true; 

            //GEN: RegexWorker regexWorker; 
            cmm.Statements.Add(new CodeVariableDeclarationStatement("RegexWorker", _regexWorkerRefName)); 

            //GEN: regexWorker = new RegexWorker(browserCaps); 
            cmm.Statements.Add(new CodeAssignStatement(_regexWorkerRefExpr, new CodeObjectCreateExpression("RegexWorker", _browserCapsRefExpr)));
        }

        private void ReturnIfHeaderValueEmpty(CodeMemberMethod cmm, CodeVariableReferenceExpression varExpr) { 
            //  GEN: if(String.IsNullOrEmpty(varExpr)) {
            //  GEN:     return false; 
            //  GEN: } 
            CodeConditionStatement emptyCheckStmt = new CodeConditionStatement();
            CodeMethodReferenceExpression emptyCheckMethod = new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "IsNullOrEmpty"); 
            CodeMethodInvokeExpression emptyCheckExpr = new CodeMethodInvokeExpression(emptyCheckMethod, varExpr);

            emptyCheckStmt.Condition = emptyCheckExpr;
            emptyCheckStmt.TrueStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(false))); 
            cmm.Statements.Add(emptyCheckStmt);
        } 
 
        //generate part of the xxxProcess method for handling determining if the requesting
        //browser meets the regexes for this browser 
        private void GenerateIdentificationCode(BrowserDefinition bd, CodeMemberMethod cmm, ref bool regexWorkerGenerated) {

            //GEN: IDictionary dictionary;
            cmm.Statements.Add(new CodeVariableDeclarationStatement(typeof(IDictionary), _dictionaryRefName)); 

            //GEN: dictionary = browserCaps.Capabilities; 
            CodeAssignStatement assign = new CodeAssignStatement( 
                _dictionaryRefExpr,
                new CodePropertyReferenceExpression(_browserCapsRefExpr, "Capabilities") 
                );
            cmm.Statements.Add(assign);

            bool disableOptimizedKey = false; 
            CodeVariableReferenceExpression result = null;
            CodeVariableReferenceExpression headerValue = null; 
 
            if(bd.IdHeaderChecks.Count > 0) {
                AddComment("Identification: check header matches", cmm); 
                for (int i = 0; i < bd.IdHeaderChecks.Count; i++) {
                    string matchedString = ((CheckPair)bd.IdHeaderChecks[i]).MatchString;

                    // Skip matching ".*" 
                    if (matchedString.Equals(".*")) {
                        continue; 
                    } 

                    if (headerValue == null) { 
                        headerValue = GenerateVarReference(cmm, typeof(string), "headerValue");
                    }

                    CodeAssignStatement valueAssignment = new CodeAssignStatement(); 
                    cmm.Statements.Add(valueAssignment);
                    valueAssignment.Left = headerValue; 
 
                    if (((CheckPair)bd.IdHeaderChecks[i]).Header.Equals("User-Agent")) {
                        _headers.Add(String.Empty); 

                        // GEN: headerValue = ((string)(browserCaps[String.Empty]));
                        valueAssignment.Right = new CodeCastExpression(typeof(string),
                                                new CodeIndexerExpression( 
                                                    new CodeVariableReferenceExpression(browserCapsVariable),
                                                    new CodeExpression[] { 
                                                        new CodePropertyReferenceExpression( 
                                                        new CodeTypeReferenceExpression(typeof(String)), "Empty") }));
                    } 
                    else {
                        string header = ((CheckPair)bd.IdHeaderChecks[i]).Header;
                        _headers.Add(header);
 
                        //GEN: headerValue = ((String)headers["xxx"]);
                        valueAssignment.Right = new CodeCastExpression(typeof(string), 
                                                   new CodeIndexerExpression( 
                                                       _headersRefExpr,
                                                       new CodeExpression[] { new CodePrimitiveExpression(header) } 
                                                       )
                                                   );

                        disableOptimizedKey = true; 
                    }
 
                    // Don't need to use Regex if matching . only. 
                    if (matchedString.Equals(".")) {
 
                        // Simply return if the header exists.
                        ReturnIfHeaderValueEmpty(cmm, headerValue);

                        continue; 
                    }
 
                    if (result == null) { 
                        result = GenerateVarReference(cmm, typeof(bool), _resultVarName);
                    } 

                    GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated);
                    CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod);
 
                    cmie.Parameters.Add(headerValue);
                    cmie.Parameters.Add(new CodePrimitiveExpression(matchedString)); 
 
                    //GEN: result = regexWorker.ProcessRegex(headerValue, {matchedString});
                    assign = new CodeAssignStatement(); 
                    assign.Left = result;
                    assign.Right = cmie;
                    cmm.Statements.Add(assign);
 
                    //GEN: if(result == false) {
                    //GEN:     return false; 
                    //GEN: } 
                    CodeConditionStatement istatement = new CodeConditionStatement();
                    if(((CheckPair)bd.IdHeaderChecks[i]).NonMatch) { 
                        istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(true));
                    }
                    else {
                        istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false)); 
                    }
                    istatement.TrueStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(false))); 
                    cmm.Statements.Add(istatement); 
                }
            } 

            if (bd.IdCapabilityChecks.Count > 0) {
                AddComment("Identification: check capability matches", cmm);
                for (int i = 0; i < bd.IdCapabilityChecks.Count; i++) { 
                    string matchedString = ((CheckPair)bd.IdCapabilityChecks[i]).MatchString;
 
                    // Skip matching ".*" 
                    if (matchedString.Equals(".*")) {
                        continue; 
                    }

                    if (headerValue == null) {
                        headerValue = GenerateVarReference(cmm, typeof(string), "headerValue"); 
                    }
 
                    CodeAssignStatement valueAssignment = new CodeAssignStatement(); 
                    cmm.Statements.Add(valueAssignment);
                    valueAssignment.Left = headerValue; 
                    valueAssignment.Right = (new CodeCastExpression(typeof(string),
                                                               new CodeIndexerExpression(
                                                                   _dictionaryRefExpr,
                                                                   new CodeExpression[] { 
                                                                       new CodePrimitiveExpression(((CheckPair)bd.IdCapabilityChecks[i]).Header)
                                                                   } 
                                                                   ) 
                                                               ));
 
                    // Don't need to use Regex if matching . only.
                    if (matchedString.Equals(".")) {
                        continue;
                    } 

                    if (result == null) { 
                        result = GenerateVarReference(cmm, typeof(bool), _resultVarName); 
                    }
 
                    GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated);
                    //GEN: result = regexWorker.ProcessRegex((string)dictionary["xxxCapability"], "xxxRegexString");
                    CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod);
 
                    cmie.Parameters.Add(headerValue);
                    cmie.Parameters.Add(new CodePrimitiveExpression(matchedString)); 
                    assign = new CodeAssignStatement(); 
                    assign.Left = result;
                    assign.Right = cmie; 
                    cmm.Statements.Add(assign);

                    //GEN: if(result == false) {
                    //GEN:      return false; 
                    //GEN: }
                    CodeConditionStatement istatement = new CodeConditionStatement(); 
                    if (((CheckPair)bd.IdCapabilityChecks[i]).NonMatch) { 
                        istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(true));
                    } 
                    else {
                        istatement.Condition = new CodeBinaryOperatorExpression(result, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false));
                    }
                    istatement.TrueStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(false))); 
                    cmm.Statements.Add(istatement);
                } 
            } 

            //GEN: browserCaps.DisableOptimizedCacheKey(); 
            if (disableOptimizedKey) {
                CodeMethodInvokeExpression cme = new CodeMethodInvokeExpression(_browserCapsRefExpr, _disableOptimizedCacheKeyMethodName);
                cmm.Statements.Add(cme);
            } 
        }
 
        private CodeVariableReferenceExpression GenerateVarReference(CodeMemberMethod cmm, Type varType, string varName) { 
            //GEN: {varType} {varName};
            cmm.Statements.Add(new CodeVariableDeclarationStatement(varType, varName)); 
            return new CodeVariableReferenceExpression(varName);
        }

        //generate part of the xxxProcess method for running and storing the capture regexes 
        private void GenerateCapturesCode(BrowserDefinition bd, CodeMemberMethod cmm, ref bool regexWorkerGenerated) {
            if ((bd.CaptureHeaderChecks.Count == 0) && (bd.CaptureCapabilityChecks.Count == 0)) { 
                return; 
            }
 
            if(bd.CaptureHeaderChecks.Count > 0) {
                AddComment("Capture: header values", cmm);
                for(int i = 0; i < bd.CaptureHeaderChecks.Count; i++) {
 
                    string matchedString = ((CheckPair)bd.CaptureHeaderChecks[i]).MatchString;
                    if (matchedString.Equals(".*")) { 
                        continue; 
                    }
 
                    GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated);
                    CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod);

                    if (((CheckPair)bd.CaptureHeaderChecks[i]).Header.Equals("User-Agent")) { 
                        _headers.Add(String.Empty);
                        cmie.Parameters.Add(new CodeCastExpression(typeof(string), 
                            new CodeIndexerExpression(new CodeVariableReferenceExpression(browserCapsVariable), new CodeExpression[] { 
                                new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof(String)), "Empty") })));
                    } 
                    else {
                        string header = ((CheckPair)bd.CaptureHeaderChecks[i]).Header;
                        _headers.Add(header);
 
                        //GEN: regexWorker.ProcessRegex((string)headers["xxx"], "xxxRegexString");
                        cmie.Parameters.Add( 
                            new CodeCastExpression(typeof(string), 
                                                   new CodeIndexerExpression(
                                                       _headersRefExpr, 
                                                       new CodeExpression[] { new CodePrimitiveExpression(header) }
                                                       )
                                                   )
                            ); 
                    }
 
                    cmie.Parameters.Add(new CodePrimitiveExpression(matchedString)); 
                    cmm.Statements.Add(cmie);
                } 
            }

            if (bd.CaptureCapabilityChecks.Count > 0) {
                AddComment("Capture: capability values", cmm); 
                for(int i = 0; i < bd.CaptureCapabilityChecks.Count; i++) {
 
                    string matchedString = ((CheckPair)bd.CaptureCapabilityChecks[i]).MatchString; 
                    if (matchedString.Equals(".*")) {
                        continue; 
                    }

                    GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated);
                    //GEN: regexWorker.ProcessRegex((string)dictionary["xxxCapability"], "xxxRegexString"); 
                    CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(_regexWorkerRefExpr, _processRegexMethod);
                    cmie.Parameters.Add( 
                        new CodeCastExpression(typeof(string), 
                                               new CodeIndexerExpression(
                                                   _dictionaryRefExpr, 
                                                   new CodeExpression[] { new CodePrimitiveExpression(((CheckPair)bd.CaptureCapabilityChecks[i]).Header) }
                                                   )
                                               )
                        ); 

                    cmie.Parameters.Add(new CodePrimitiveExpression(matchedString)); 
                    cmm.Statements.Add(cmie); 
                }
            } 
        }

        //generate part of the xxxProcess method for assigning capability values
        private void GenerateSetCapabilitiesCode(BrowserDefinition bd, CodeMemberMethod cmm, ref bool regexWorkerGenerated) { 
            //GEN: browserCaps[aaa] = "bbb";
            //GEN: browserCaps[xxx] = "yyy"; 
            NameValueCollection nvc = bd.Capabilities; 
            CodeAssignStatement assign;
 
            AddComment("Capabilities: set capabilities", cmm);
            foreach (string s in nvc.Keys) {
                string capsString = nvc[s];
                //GEN: dictionary["xxx"] = regexWorker["xxx"]; 
                assign = new CodeAssignStatement();
                assign.Left = new CodeIndexerExpression( 
                    _dictionaryRefExpr, 
                    new CodeExpression[] { new CodePrimitiveExpression(s) } );
 
                CodePrimitiveExpression capabilityExpr = new CodePrimitiveExpression(capsString);
                if (RegexWorker.RefPat.Match(capsString).Success) {

                    GenerateRegexWorkerIfNecessary(cmm, ref regexWorkerGenerated); 
                    assign.Right = new CodeIndexerExpression(
                        _regexWorkerRefExpr, 
                        new CodeExpression[] {capabilityExpr}); 
                }
                else { 
                    assign.Right = capabilityExpr;
                }

                cmm.Statements.Add(assign); 
            }
        } 
 
        //generate part of the xxxProcess method for setting specific adapters for this browser
        internal void GenerateSetAdaptersCode(BrowserDefinition bd, CodeMemberMethod cmm) { 
            //GEN: browserCaps.Adapters[xxxControl] = yyyAdapter;
            foreach (DictionaryEntry entry in bd.Adapters) {
                string controlString = (string)entry.Key;
                string adapterString = (string)entry.Value; 
                CodePropertyReferenceExpression cpre = new CodePropertyReferenceExpression(_browserCapsRefExpr, "Adapters");
                CodeIndexerExpression indexerExpression = new CodeIndexerExpression( 
                    cpre, 
                    new CodeExpression[] { new CodePrimitiveExpression(controlString) }
                    ); 
                CodeAssignStatement assignAdapter = new CodeAssignStatement();
                assignAdapter.Left = indexerExpression;
                assignAdapter.Right = new CodePrimitiveExpression(adapterString);
                cmm.Statements.Add(assignAdapter); 
            }
 
            //GEN: browser.HtmlTextWriter = xxxHtmlTextWriter; 
            if(bd.HtmlTextWriterString != null) {
                CodeAssignStatement assignHtmlTextWriter = new CodeAssignStatement(); 
                assignHtmlTextWriter.Left = new CodePropertyReferenceExpression(_browserCapsRefExpr, "HtmlTextWriter");
                assignHtmlTextWriter.Right = new CodePrimitiveExpression(bd.HtmlTextWriterString);
                cmm.Statements.Add(assignHtmlTextWriter);
            } 
            return;
        } 
 
        internal void AddComment(string comment, CodeMemberMethod cmm) {
            cmm.Statements.Add(new CodeCommentStatement(comment)); 
        }

        internal CodeStatementCollection GenerateTrackedSingleProcessCall(CodeStatementCollection stmts, BrowserDefinition bd, CodeMemberMethod cmm) {
            return GenerateTrackedSingleProcessCall(stmts, bd, cmm, String.Empty); 
        }
 
        internal CodeStatementCollection GenerateTrackedSingleProcessCall(CodeStatementCollection stmts, BrowserDefinition bd, CodeMemberMethod cmm, string prefix) { 
            //GEN:  if (xProcess(headers, browserCaps)) {
            //      } 
            //      else {
            //          ...
            //      }
            CodeMethodInvokeExpression xProcess = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), prefix + bd.Name + "Process"); 
            xProcess.Parameters.Add(new CodeVariableReferenceExpression(_headersRefName));
            xProcess.Parameters.Add(new CodeVariableReferenceExpression(browserCapsVariable)); 
 
            CodeConditionStatement conditionStmt = new CodeConditionStatement();
            conditionStmt.Condition = xProcess; 

            stmts.Add(conditionStmt);

            return conditionStmt.FalseStatements; 
        }
 
        internal void GenerateSingleProcessCall(BrowserDefinition bd, CodeMemberMethod cmm) { 
            GenerateSingleProcessCall(bd, cmm, String.Empty);
        } 

        //generate code to call the xxxProcess for a given browser
        //and store the result in a local variable
        internal void GenerateSingleProcessCall(BrowserDefinition bd, CodeMemberMethod cmm, string prefix) { 
            //GEN: xProcess(headers, browserCaps);
            CodeMethodInvokeExpression xProcess = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), prefix + bd.Name + "Process"); 
            xProcess.Parameters.Add(new CodeVariableReferenceExpression(_headersRefName)); 
            xProcess.Parameters.Add(new CodeVariableReferenceExpression(browserCapsVariable));
            cmm.Statements.Add(xProcess); 
        }
    }
}

// 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