TemplateParser.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / xsp / System / Web / UI / TemplateParser.cs / 1471291 / TemplateParser.cs

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

/* 
 * Implements the ASP.NET template parser 
 *
 * Copyright (c) 1998 Microsoft Corporation 
 */

// Turn this on to do regex profiling
//#define PROFILE_REGEX 

namespace System.Web.UI { 
using System.Runtime.Serialization.Formatters; 
using System.Text;
using System.Runtime.InteropServices; 
using System.Runtime.Serialization;
using System;
using System.IO;
using System.Collections; 
using System.Collections.Generic;
using System.Collections.Specialized; 
using System.Threading; 
using System.Reflection;
using System.Globalization; 
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Web.Caching; 
using System.Web.Util;
using System.Web.Hosting; 
using System.Web.Compilation; 
using HttpException = System.Web.HttpException;
using System.Text.RegularExpressions; 
using System.Security.Permissions;
using System.Web.Configuration;

 
/// 
///  
///    [To be supplied.] 
/// 
public abstract class TemplateParser : BaseParser, IAssemblyDependencyParser { 

    internal const string CodeFileBaseClassAttributeName = "codefilebaseclass";

    // The  config section 
    private CompilationSection _compConfig;
    internal CompilationSection CompConfig { 
        get { return _compConfig; } 
    }
 
    // The  config section
    private PagesSection _pagesConfig;
    internal PagesSection PagesConfig {
        get { return _pagesConfig; } 
    }
 
    // const masks into the BitVector32 
    private const int isServerTag                   = 0x00000001;
    private const int inScriptTag                   = 0x00000002; 
    private const int ignoreScriptTag               = 0x00000004;
    private const int ignoreNextSpaceString         = 0x00000008;
    internal const int requiresCompilation          = 0x00000010;   // Has constructs that require compilation
    private const int ignoreControlProperties       = 0x00000020; 
    internal const int aspCompatMode                = 0x00000040;
    private const int hasCodeBehind                 = 0x00000080; 
    private const int inDesigner                    = 0x00000100; 
    private const int ignoreParseErrors             = 0x00000200;
    private const int mainDirectiveSpecified        = 0x00000400; 
    private const int mainDirectiveHandled          = 0x00000800;
    private const int useExplicit                   = 0x00001000;
    private const int hasDebugAttribute             = 0x00002000;
    private const int debug                         = 0x00004000; 
    private const int noLinePragmas                 = 0x00008000;
    private const int strict                        = 0x00010000; 
    internal const int noAutoEventWireup            = 0x00020000; 
    private const int attemptedImplicitResources    = 0x00040000;
    internal const int buffer                       = 0x00080000; 
    internal const int requiresSessionState         = 0x00100000;
    internal const int readOnlySessionState         = 0x00200000;
    internal const int validateRequest              = 0x00400000;
    internal const int asyncMode                    = 0x00800000; 
    private const int throwOnFirstParseError        = 0x01000000;
    private const int ignoreParserFilter            = 0x02000000; 
    internal const int calledFromParseControlFlag   = 0x04000000; 
    #pragma warning disable 0649
    internal SimpleBitVector32 flags; 
    #pragma warning restore 0649

    private MainTagNameToTypeMapper _typeMapper;
    internal MainTagNameToTypeMapper TypeMapper { get { return _typeMapper; } } 

    internal ICollection UserControlRegisterEntries { get { return TypeMapper.UserControlRegisterEntries; } } 
    internal List TagRegisterEntries { get { return TypeMapper.TagRegisterEntries; } } 

    private Stack _builderStack; // Stack of BuilderStackEntry's 
    internal Stack BuilderStack {
        get {
            EnsureRootBuilderCreated();
            return _builderStack; 
        }
    } 
 
    private string _id;
    private StringSet _idList; 
    private Stack _idListStack;
    private ScriptBlockData _currentScript;
    private StringBuilder _literalBuilder;
 
    // The line number in file currently being parsed
    internal int _lineNumber; 
 
    // The line number at which the current script block started
    private int _scriptStartLineNumber; 

    // String that contains the data to be parsed
    private string _text;
    internal string Text { 
        get { return _text; }
        set { _text = value; } 
    } 

    // The class from which to inherit if we are compiling a class 
    private Type _baseType;
    internal Type BaseType {
        get { return _baseType; }
        set { _baseType = value; } 
    }
 
    // The namespace and name of the class from which to inherit.  Only used with code separation, 
    // since we don't have the live Type in that case (not yet compiled)
    private string _baseTypeNamespace; 
    internal string BaseTypeNamespace { get { return _baseTypeNamespace; } }
    private string _baseTypeName;
    internal string BaseTypeName { get { return _baseTypeName; } }
 
    internal bool IgnoreControlProperties {
        get { return flags[ignoreControlProperties]; } 
        set { flags[ignoreControlProperties] = value; } 
    }
 
    // Indicates whether the parser should throw on the first error.
    internal bool ThrowOnFirstParseError {
        get { return flags[throwOnFirstParseError]; }
        set { flags[throwOnFirstParseError] = value; } 
    }
 
    // The interfaces that we implement (ArrayList of Type objects) 
    private ArrayList _implementedInterfaces;
    internal ArrayList ImplementedInterfaces { get { return _implementedInterfaces; } } 

    internal bool HasCodeBehind { get { return flags[hasCodeBehind]; } }

    internal abstract Type DefaultBaseType { get; } 

    internal PageParserFilter _pageParserFilter; 
 
    private IImplicitResourceProvider _implicitResourceProvider;
 
    // The FInDesigner property gets used by control builders so that
    // they can behave differently if needed.
    internal virtual bool FInDesigner {
        get { return flags[inDesigner]; } 
        set { flags[inDesigner] = value; }
    } 
 
    // When this is set, we ignore parse errors and keep on processing the page as
    // well as possible.  This is used for the Venus CBM scenario 
    internal virtual bool IgnoreParseErrors {
        get { return flags[ignoreParseErrors]; }
        set { flags[ignoreParseErrors] = value; }
    } 

    // When true, it is not legal to have any constructs that require compilation 
    private CompilationMode _compilationMode; 
    internal CompilationMode CompilationMode {
        get { 
            // When precompiling for deployment, always compile everything (VSWhidbey 266509)
            if (BuildManager.PrecompilingForDeployment)
                return CompilationMode.Always;
 
            return _compilationMode;
        } 
        set { 
            if (value == CompilationMode.Never && flags[requiresCompilation]) {
                ProcessError(SR.GetString(SR.Compilmode_not_allowed)); 
            }

            _compilationMode = value;
        } 
    }
 
    private ParserErrorCollection _parserErrors; 
    private ParserErrorCollection ParserErrors {
        get { 
            if (_parserErrors == null) {
                _parserErrors = new ParserErrorCollection();
            }
 
            return _parserErrors;
        } 
    } 

    private bool HasParserErrors { 
        get { return _parserErrors != null && _parserErrors.Count > 0; }
    }

    // Method to report parser errors. 
    protected void ProcessError(string message) {
        // Ignore the errors if in that mode. 
        if (IgnoreParseErrors) { 
            return;
        } 

        // Rethrow as innerexception if in that mode.
        if (ThrowOnFirstParseError) {
            throw new HttpException(message); 
        }
 
        // otherwise add to the error collection with proper info. 
        ParserError parseError = new ParserError(message, CurrentVirtualPath, _lineNumber);
        ParserErrors.Add(parseError); 

        // If there is a CBM callback, inform it of the error
        BuildManager.ReportParseError(parseError);
    } 

    // Method to report exception, this is called when external exceptions are caught in the parser. 
    protected void ProcessException(Exception ex) { 
        // Ignore the errors if in that mode.
        if (IgnoreParseErrors) { 
            return;
        }

        // Rethrow as innerexception if in that mode or it is a compile exception. 
        if (ThrowOnFirstParseError || ex is HttpCompileException) {
            if (ex is HttpParseException) 
                throw ex; 
            throw new HttpParseException(ex.Message, ex);
        } 

        // If it is already a parser exception remember the location corresponding to
        // the original error.
        ParserError parseError; 

        HttpParseException hpe = ex as HttpParseException; 
        if (hpe != null) { 
            parseError = new ParserError(hpe.Message, hpe.VirtualPath, hpe.Line);
        } 
        else {
            parseError = new ParserError(ex.Message, CurrentVirtualPath, _lineNumber);
        }
 
        // Remember the original exception.
        parseError.Exception = ex; 
 
        ParserErrors.Add(parseError);
 
        // If there is a CBM callback, inform it of the error only if the HttpParseException comes
        // from the current virtualpath. Since if the exception is thrown from parsing another file,
        // it would have been reported already.
        if (hpe == null || CurrentVirtualPath.Equals(hpe.VirtualPathObject)) { 
            BuildManager.ReportParseError(parseError);
        } 
    } 

    // When true, there are construct that require compilation 
    internal virtual bool RequiresCompilation {
        get {
            // By default, require compilation.  The Page parser overrides this
            // and can allow no-compile pages depending on the page contents 
            return true;
        } 
    } 

    internal virtual bool IsCodeAllowed { 
        get {
            // If it's a no-compile page, code is not allowed
            if (CompilationMode == CompilationMode.Never)
                return false; 

            // Likewise, check if the PageParserFilter allows code 
            if (_pageParserFilter != null && !_pageParserFilter.AllowCode) 
                return false;
 
            return true;
        }
    }
 
    internal void EnsureCodeAllowed() {
 
        // If it's a no-compile page, fail since there is code on it. 
        // Likewise if the PageParserFilter returns IsCodeAllowed == false
        if (!IsCodeAllowed) { 
            ProcessError(SR.GetString(SR.Code_not_allowed));
        }

        // Remember the fact that this page MUST be compiled 
        flags[requiresCompilation] = true;
    } 
 
    // This is called whenever we parse an attribute that requires compilation
    internal void OnFoundAttributeRequiringCompilation(string attribName) { 

        // If compilation is not alowed, fail
        if (!IsCodeAllowed) {
            ProcessError(SR.GetString(SR.Attrib_not_allowed, attribName)); 
        }
 
        // Remember the fact that this page MUST be compiled 
        flags[requiresCompilation] = true;
    } 

    // This is called whenever we parse a directive that requires compilation
    internal void OnFoundDirectiveRequiringCompilation(string directiveName) {
 
        // If compilation is not alowed, fail
        if (!IsCodeAllowed) { 
            ProcessError(SR.GetString(SR.Directive_not_allowed, directiveName)); 
        }
 
        // Remember the fact that this page MUST be compiled
        flags[requiresCompilation] = true;
    }
 
    // This is called whenever we parse an event attribute on a tag
    internal void OnFoundEventHandler(string directiveName) { 
 
        // If compilation is not alowed, fail
        if (!IsCodeAllowed) { 
            ProcessError(SR.GetString(SR.Event_not_allowed, directiveName));
        }

        // Remember the fact that this page MUST be compiled 
        flags[requiresCompilation] = true;
    } 
 
    private IDesignerHost _designerHost;
    private ITypeResolutionService _typeResolutionService; 
    internal IDesignerHost DesignerHost {
        get {
            Debug.Assert(FInDesigner, "DesignerHost should be accessed only when FInDesigner == true");
            return _designerHost; 
        }
        set { 
            Debug.Assert(FInDesigner, "DesignerHost should be accessed only when FInDesigner == true"); 
            _designerHost = value;
 
            _typeResolutionService = null;
            if (_designerHost != null) {
                _typeResolutionService = (ITypeResolutionService)_designerHost.GetService(typeof(ITypeResolutionService));
                if (_typeResolutionService == null) { 
                    throw new ArgumentException(SR.GetString(SR.TypeResService_Needed));
                } 
            } 
        }
    } 

    // true if we're parsing global.asax
    internal virtual bool FApplicationFile { get { return false; } }
 
    // The global delegate to use for the DataBind event on controls when
    // the parser is run in design-mode. 
    private EventHandler _designTimeDataBindHandler; 
    internal EventHandler DesignTimeDataBindHandler {
        get { return _designTimeDataBindHandler; } 
        set { _designTimeDataBindHandler = value; }
    }

    // Used to detect circular references 
    private StringSet _circularReferenceChecker;
 
    // The set of assemblies that the build system is telling us we will be linked with 
    private ICollection _referencedAssemblies;
 
    // The set of assemblies that this file is explicitly asking for
    private AssemblySet _assemblyDependencies;
    internal AssemblySet AssemblyDependencies {
        get { return _assemblyDependencies; } 
    }
 
    // The list of virtual paths to source files we are dependent on 
    private StringSet _sourceDependencies;
    internal StringSet SourceDependencies { 
        get { return _sourceDependencies; }
    }

    // The collection of  tags with scope=session 
    internal HttpStaticObjectsCollection _sessionObjects;
    internal HttpStaticObjectsCollection SessionObjects { 
        get { return _sessionObjects; } 
    }
 
    // The collection of  tags with scope=application
    internal HttpStaticObjectsCollection _applicationObjects;
    internal HttpStaticObjectsCollection ApplicationObjects {
        get { return _applicationObjects; } 
    }
 
    // data that was obtained from parsing the input file 

    private RootBuilder _rootBuilder; 
    internal RootBuilder RootBuilder {
        get {
            EnsureRootBuilderCreated();
            return _rootBuilder; 
        }
    } 
 
    // Main directive attributes coming from config
    internal IDictionary _mainDirectiveConfigSettings; 

    // 
    private Hashtable _namespaceEntries;
    internal Hashtable NamespaceEntries { get { return _namespaceEntries; } } 

    private CompilerType _compilerType; 
    internal CompilerType CompilerType { get { return _compilerType; } } 

    // the server side scripts (list of ScriptBlockData's) 
    private ArrayList _scriptList;
    internal ArrayList ScriptList { get { return _scriptList; } }

    // the hash code which determines the set of controls on the page 
    private HashCodeCombiner _typeHashCode = new HashCodeCombiner();
    internal int TypeHashCode { get { return _typeHashCode.CombinedHash32; } } 
 
    // The  tags local to the page.  Entries are ObjectTagBuilder's.
    private ArrayList _pageObjectList; 
    internal ArrayList PageObjectList { get { return _pageObjectList; } }


    // Data parsed from the directives 

    internal CompilerParameters CompilParams { get { return _compilerType.CompilerParameters; } } 
 
    internal bool FExplicit { get { return flags[useExplicit]; } }
 
    internal bool FLinePragmas { get { return !flags[noLinePragmas]; } }

    private int _warningLevel=-1;
    private string _compilerOptions; 

    internal bool FStrict { get { return flags[strict]; } } 
 
    // File that we must be compiled with, aka code besides (optional)
    private VirtualPath _codeFileVirtualPath; 
    internal VirtualPath CodeFileVirtualPath { get { return _codeFileVirtualPath; } }

    // Name that the user wants to give to the generated class
    private string _generatedClassName; 
    internal string GeneratedClassName { get { return _generatedClassName; } }
 
    // Name that the user wants to give to the generated namespace 
    private string _generatedNamespace = null;
    internal string GeneratedNamespace { 
        get {
            // If no namespace was specified, use "ASP"
            if (_generatedNamespace == null)
                return BaseCodeDomTreeGenerator.defaultNamespace; 

            return _generatedNamespace; 
        } 
    }
 

    /// 
    /// Parse the input into a Control. This is used to parse in a control dynamically from some
    /// textual content. 
    /// 
    internal static Control ParseControl(string content, VirtualPath virtualPath, bool ignoreFilter) { 
        if (content == null) { 
            return null;
        } 

        ITemplate t = ParseTemplate(content, virtualPath, ignoreFilter);

        // Create a parent control to hold the controls we parsed 
        Control c = new Control();
        t.InstantiateIn(c); 
 
        return c;
    } 

    private static ITemplate ParseTemplate(string content, VirtualPath virtualPath, bool ignoreFilter) {
        TemplateParser parser = new UserControlParser();
        return parser.ParseTemplateInternal(content, virtualPath, ignoreFilter); 
    }
 
    private ITemplate ParseTemplateInternal(string content, VirtualPath virtualPath, bool ignoreFilter) { 

        // Use the passed in virtualPath, since we need to have one, and the content string 
        // itself doesn't have one.
        CurrentVirtualPath = virtualPath;
        CompilationMode = CompilationMode.Never;
        _text = content; 

        // Ignore the PageParserFilter when processing ParserControl/ParseTemplate (VSWhidbey 361509) 
        // Allow the ignore action to be controlled by a parameter (DevDiv 38679) 
        flags[ignoreParserFilter] = ignoreFilter;
        flags[calledFromParseControlFlag] = true; 

        Parse();

        Debug.Assert(RootBuilder != null); 
        return RootBuilder;
    } 
 
    /*
     * Do some initialization before the parsing 
     */
    internal virtual void PrepareParse() {
        if (_circularReferenceChecker == null)
            _circularReferenceChecker = new CaseInsensitiveStringSet(); 

        _baseType = DefaultBaseType; 
 
        // Initialize the main directive
        _mainDirectiveConfigSettings = CreateEmptyAttributeBag(); 

        // Get the config sections we care about
        if (!FInDesigner) {
            _compConfig = MTConfigUtil.GetCompilationConfig(CurrentVirtualPath); 
            _pagesConfig = MTConfigUtil.GetPagesConfig(CurrentVirtualPath);
        } 
 
        // Get default settings from config
        ProcessConfigSettings(); 

        // Initialize the type mapper
        // This must follow processing of config, so it can use the results
        _typeMapper = new MainTagNameToTypeMapper(this as BaseTemplateParser); 

        // Register the  tag 
        _typeMapper.RegisterTag("object", typeof(System.Web.UI.ObjectTag)); 

        _sourceDependencies = new CaseInsensitiveStringSet(); 

        // Create and seed the stack of ID lists.
        _idListStack = new Stack();
        _idList = new CaseInsensitiveStringSet(); 

        _scriptList = new ArrayList(); 
    } 

    private void EnsureRootBuilderCreated() { 

        // Create it on demand
        if (_rootBuilder != null)
            return; 

        if (BaseType == DefaultBaseType) { 
            // If the base type is the default, no need to look up the attribute 
            _rootBuilder = CreateDefaultFileLevelBuilder();
        } 
        else {
            // Look for a custom attribute
            Type fileLevelBuilderType = GetFileLevelControlBuilderType();
 
            if (fileLevelBuilderType == null) {
                // No custom type: use the default 
                _rootBuilder = CreateDefaultFileLevelBuilder(); 
            }
            else { 
                // Create the custom file level builder
                _rootBuilder = (RootBuilder) HttpRuntime.CreateNonPublicInstance(
                    fileLevelBuilderType);
            } 
        }
 
        _rootBuilder.Line = 1; 
        _rootBuilder.Init(this, null, null, null, null, null);
        _rootBuilder.SetTypeMapper(TypeMapper); 

        _rootBuilder.VirtualPath = CurrentVirtualPath;

        // Create and seed the stack of builders. 
        _builderStack = new Stack();
        _builderStack.Push(new BuilderStackEntry(RootBuilder, null, null, 0, null, 0)); 
    } 

    internal virtual Type DefaultFileLevelBuilderType { 
        get {
            return typeof(RootBuilder);
        }
    } 

    internal virtual RootBuilder CreateDefaultFileLevelBuilder() { 
 
        // By default, create a RootBuilder
        return new RootBuilder(); 
    }

    private Type GetFileLevelControlBuilderType() {
        // Check whether the control's class exposes a custom file level builder type 
        FileLevelControlBuilderAttribute cba = null;
        object[] attrs = BaseType.GetCustomAttributes( 
            typeof(FileLevelControlBuilderAttribute), /*inherit*/ true); 
        if ((attrs != null) && (attrs.Length > 0)) {
            Debug.Assert(attrs[0] is FileLevelControlBuilderAttribute); 
            cba = (FileLevelControlBuilderAttribute)attrs[0];
        }

        if (cba == null) 
            return null;
 
        // Make sure the type has the correct base class 
        Util.CheckAssignableType(DefaultFileLevelBuilderType, cba.BuilderType);
 
        return cba.BuilderType;
    }

    // Get default settings from config 
    internal virtual void ProcessConfigSettings() {
        if (_compConfig != null) { 
            flags[useExplicit] = _compConfig.Explicit; 
            flags[strict] = _compConfig.Strict;
        } 

        if (PagesConfig != null) {
            _namespaceEntries = PagesConfig.Namespaces.NamespaceEntries;
 
            // Clone it so we don't modify the config settings
            if (_namespaceEntries != null) 
                _namespaceEntries = (Hashtable) _namespaceEntries.Clone(); 

            if (!flags[ignoreParserFilter]) { 
                // Check if a filter is registered, and if so initialize it
                _pageParserFilter = PageParserFilter.Create(PagesConfig, CurrentVirtualPath, this);
            }
        } 
    }
 
    internal void Parse(ICollection referencedAssemblies, VirtualPath virtualPath) { 

        _referencedAssemblies = referencedAssemblies; 
        CurrentVirtualPath = virtualPath;

        Parse();
    } 

    /* 
     * Parse the input 
     */
    internal void Parse() { 

        // Always set the culture to Invariant when parsing (ASURT 99071)
        Thread currentThread = Thread.CurrentThread;
        CultureInfo prevCulture = currentThread.CurrentCulture; 
        System.Web.Util.Debug.Trace("Culture", "Before parsing, culture is " + prevCulture.DisplayName);
        currentThread.CurrentCulture = CultureInfo.InvariantCulture; 
 
        try {
            try { 
                // Do some initialization before the parsing
                PrepareParse();
                ParseInternal();
                HandlePostParse(); 
            }
            finally { 
                // Restore the previous culture 
                System.Web.Util.Debug.Trace("Culture", "After parsing, culture is " + currentThread.CurrentCulture.DisplayName);
                currentThread.CurrentCulture = prevCulture; 
                System.Web.Util.Debug.Trace("Culture", "Restored culture to " + prevCulture.DisplayName);
            }
        }
        catch { throw; }    // Prevent Exception Filter Security Issue (ASURT 122835) 
    }
 
    internal virtual void ParseInternal() { 
        // Parse either the file or string
        if (_text != null) { 
            ParseString(_text, CurrentVirtualPath, Encoding.UTF8);
        }
        else {
            AddSourceDependency(CurrentVirtualPath); 
            ParseFile(null /*physicalPath*/, CurrentVirtualPath.VirtualPathString);
        } 
    } 

    internal TemplateParser() { 
        ThrowOnFirstParseError = true;
    }

    /* 
     * Parse the contents of the input file
     */ 
 
    protected void ParseFile(string physicalPath, string virtualPath) {
        ParseFile(physicalPath, VirtualPath.Create(virtualPath)); 
    }

    internal void ParseFile(string physicalPath, VirtualPath virtualPath) {
 
        // Determine the file used for the circular references checker.  Normally,
        // we use the virtualPath, but we use the physical path if it specified, 
        // as is the case for  
        string fileToReferenceCheck = physicalPath != null ? physicalPath : virtualPath.VirtualPathString;
 
        // Check for circular references of include files
        if (_circularReferenceChecker.Contains(fileToReferenceCheck)) {
            ProcessError(SR.GetString(SR.Circular_include));
 
            return;
        } 
 
        // Add the current file to the circular references checker.
        _circularReferenceChecker.Add(fileToReferenceCheck); 

        try {
            // Open a TextReader either from the physical or virtual path
            StreamReader reader; 
            if (physicalPath != null) {
                using (reader = Util.ReaderFromFile(physicalPath, CurrentVirtualPath)) { 
                    ParseReader(reader, virtualPath); 
                }
            } 
            else {
                // Open a TextReader for the virtualPath we're parsing
                using (Stream stream = virtualPath.OpenFile()) {
                    reader = Util.ReaderFromStream(stream, CurrentVirtualPath); 
                    ParseReader(reader, virtualPath);
                } 
            } 
        }
        finally { 
            // Remove the current file from the circular references checker
            _circularReferenceChecker.Remove(fileToReferenceCheck);
        }
    } 

    /* 
     * Parse the contents of the TextReader 
     */
    private void ParseReader(StreamReader reader, VirtualPath virtualPath) { 
        string s = reader.ReadToEnd();

        // Save the text of the input file in case it's trivial
        _text = s; 

        ParseString(s, virtualPath, reader.CurrentEncoding); 
    } 

    private void AddLiteral(string literal) { 

        if (_literalBuilder == null)
            _literalBuilder = new StringBuilder();
 
        _literalBuilder.Append(literal);
    } 
 
    private string GetLiteral() {
        if (_literalBuilder == null) 
            return null;

        return _literalBuilder.ToString();
    } 

    /* 
     * Update the hash code of the Type we're creating by xor'ing it with 
     * a string.
     */ 
    internal void UpdateTypeHashCode(string text) {
        _typeHashCode.AddObject(text);
    }
 
    /*
     * Parse the contents of the string, and catch exceptions 
     */ 
    internal void ParseString(string text, VirtualPath virtualPath, Encoding fileEncoding) {
 
        System.Web.Util.Debug.Trace("Template", "Starting parse at " + DateTime.Now);

        // Save the previous base dirs and line number
        VirtualPath prevVirtualPath = CurrentVirtualPath; 
        int prevLineNumber = _lineNumber;
 
        // Set the new current base dirs and line number 
        CurrentVirtualPath = virtualPath;
        _lineNumber = 1; 

        // Always ignore the spaces at the beginning of a string
        flags[ignoreNextSpaceString] = true;
 
        try {
            ParseStringInternal(text, fileEncoding); 
 
            // If there are parser errors caught in the parser
            if (HasParserErrors) { 
                ParserError firstError = ParserErrors[0];

                Exception originalException = firstError.Exception;
 
                // Use the first error as the inner exception if not already caught one.
                if (originalException == null) { 
                    originalException = new HttpException(firstError.ErrorText); 
                }
 
                // Make it a HttpParseException with proper info.
                HttpParseException ex = new HttpParseException(firstError.ErrorText,
                    originalException, firstError.VirtualPath, Text, firstError.Line);
 
                // Add the rest of the errors
                for (int i = 1; i < ParserErrors.Count; i++) { 
                    ex.ParserErrors.Add(ParserErrors[i]); 
                }
 
                // throw the new exception
                throw ex;
            }
 
            // Make sure that if any code calls ProcessError/ProcessException after this point,
            // it throws the error right away, since we won't look at ParserErrors/_firstParseException 
            // anymore 
            ThrowOnFirstParseError = true;
        } 
        catch (Exception e) {
            ErrorFormatter errorFormatter = null;

            PerfCounters.IncrementCounter(AppPerfCounter.ERRORS_PRE_PROCESSING); 
            PerfCounters.IncrementCounter(AppPerfCounter.ERRORS_TOTAL);
 
            // Check if the exception has a formatter 
            errorFormatter = HttpException.GetErrorFormatter(e);
 
            // If it doesn't, throw a parse exception
            if (errorFormatter == null) {

                throw new HttpParseException(e.Message, e, 
                    CurrentVirtualPath, text, _lineNumber);
            } 
            else { 
                // Otherwise, just rethrow it
                throw; 
            }
        }
        finally {
            // Restore the previous base dirs and line number 
            CurrentVirtualPath = prevVirtualPath;
            _lineNumber = prevLineNumber; 
        } 

        System.Web.Util.Debug.Trace("Template", "Ending parse at " + DateTime.Now); 
    }

#if PROFILE_REGEX
    private Match RunTagRegex(string text, int textPos) { 
        int i=1;
        if (i==0) 
            throw new HttpException("Bogus exception just to prevent method inlining"); 

        return TagRegex.Match(text, textPos); 
    }

    private Match RunDirectiveRegex(string text, int textPos) {
        int i=1; 
        if (i==0)
            throw new HttpException("Bogus exception just to prevent method inlining"); 
 
        return directiveRegex.Match(text, textPos);
    } 

    private Match RunEndTagRegex(string text, int textPos) {
        int i=1;
        if (i==0) 
            throw new HttpException("Bogus exception just to prevent method inlining");
 
        return endtagRegex.Match(text, textPos); 
    }
 
    private Match RunCodeBlockRegex(string text, int textPos) {
        int i=1;
        if (i==0)
            throw new HttpException("Bogus exception just to prevent method inlining"); 

        return aspCodeRegex.Match(text, textPos); 
    } 

    private Match RunExprCodeBlockRegex(string text, int textPos) { 
        int i=1;
        if (i==0)
            throw new HttpException("Bogus exception just to prevent method inlining");
 
        return aspExprRegex.Match(text, textPos);
    } 
 
    private Match RunCommentRegex(string text, int textPos) {
        int i=1; 
        if (i==0)
            throw new HttpException("Bogus exception just to prevent method inlining");

        return commentRegex.Match(text, textPos); 
    }
 
    private Match RunIncludeRegex(string text, int textPos) { 
        int i=1;
        if (i==0) 
            throw new HttpException("Bogus exception just to prevent method inlining");

        return includeRegex.Match(text, textPos);
    } 

    private Match RunTextRegex(string text, int textPos) { 
        int i=1; 
        if (i==0)
            throw new HttpException("Bogus exception just to prevent method inlining"); 

        return textRegex.Match(text, textPos);
    }
#endif // PROFILE_REGEX 

    /* 
     * Parse the contents of the string 
     */
    private void ParseStringInternal(string text, Encoding fileEncoding) { 
        int textPos = 0;

        // Find the last '>' in the input string
        int lastGTIndex = text.LastIndexOf('>'); 

        Regex tagRegex = TagRegex; 
 
        for (;;) {
            Match match; 

            // 1: scan for text up to the next tag.

#if PROFILE_REGEX 
            if ((match = RunTextRegex(text, textPos)).Success)
#else 
            if ((match = textRegex.Match(text, textPos)).Success) 
#endif
            { 
                // Append the text to the literal builder
                AddLiteral(match.ToString());

                _lineNumber += Util.LineCount(text, textPos, 
                                         match.Index + match.Length);
                textPos = match.Index + match.Length; 
            } 

            // we might be done now 

            if (textPos == text.Length)
                break;
 
            // 2: handle constructs that start with <
 
            // This later gets set to true if we match a regex, but do not 
            // process the match
            bool fMatchedButNotProcessed = false; 

            // Check to see if it's a directive (i.e. <%@ %> block)

            if (!flags[inScriptTag] && 
#if PROFILE_REGEX
                (match = RunDirectiveRegex(text, textPos)).Success) 
#else 
                (match = directiveRegex.Match(text, textPos)).Success)
#endif 
            {
                ProcessLiteral();

                // Get all the directives into a bag 
                ParsedAttributeCollection directive;
                string duplicateAttribute; 
                string directiveName = ProcessAttributes(match, out directive, true, out duplicateAttribute); 

                try { 
                    // If there is a parser filter, give it a chance to look at the directive
                    PreprocessDirective(directiveName, directive);

                    ProcessDirective(directiveName, directive); 
                }
                catch(Exception e) { 
                    ProcessException(e); 
                }
 
                // If we just found the main directive, and it uses a codeFile, check if we need to create
                // a modified version of the file (used for updatable deployment precompilation)
                if (directiveName.Length == 0 && _codeFileVirtualPath != null) {
                    CreateModifiedMainDirectiveFileIfNeeded(text, match, directive, fileEncoding); 
                }
 
                // Always ignore the spaces after a directive 
                flags[ignoreNextSpaceString] = true;
            } 

            // Check to see if it's a server side include
            // e.g. 
 
#if PROFILE_REGEX
            else if ((match = RunIncludeRegex(text, textPos)).Success) 
#else 
            else if ((match = includeRegex.Match(text, textPos)).Success)
#endif 
            {
                try {
                    ProcessServerInclude(match);
                } 
                catch(Exception ex) {
                    ProcessException(ex); 
                } 
            }
 
            // Check to see if it's a comment <%-- --%> block

#if PROFILE_REGEX
            else if ((match = RunCommentRegex(text, textPos)).Success) 
#else
            else if ((match = commentRegex.Match(text, textPos)).Success) 
#endif 
            {
                // Just skip it 
            }

            // Check to see if it's an expression code block (i.e. <%= ... %> block)
 
            else if (!flags[inScriptTag] &&
#if PROFILE_REGEX 
                     (match = RunExprCodeBlockRegex(text, textPos)).Success) 
#else
                     (match = aspExprRegex.Match(text, textPos)).Success) 
#endif
            {
                ProcessCodeBlock(match, CodeBlockType.Expression, text);
            } 

            // Check to see if it's an encoded expression code block (i.e. <%: ... %> block) 
 
            else if (!flags[inScriptTag] && (match = aspEncodedExprRegex.Match(text, textPos)).Success) {
                ProcessCodeBlock(match, CodeBlockType.EncodedExpression, text); 
            }

            // Check to see if it's a databinding expression block (i.e. <%# ... %> block)
            // This does not include <%# %> blocks used as values for 
            // attributes of server tags.
 
            else if (!flags[inScriptTag] && 
                     (match = databindExprRegex.Match(text, textPos)).Success) {
                ProcessCodeBlock(match, CodeBlockType.DataBinding, text); 
            }

            // Check to see if it's a code block (<% ... %>)
 
            else if (!flags[inScriptTag] &&
#if PROFILE_REGEX 
                     (match = RunCodeBlockRegex(text, textPos)).Success) 
#else
                     (match = aspCodeRegex.Match(text, textPos)).Success) 
#endif
            {
                string code = match.Groups["code"].Value.Trim();
                if (code.StartsWith("$", StringComparison.Ordinal)) { 
                    ProcessError(SR.GetString(SR.ExpressionBuilder_LiteralExpressionsNotAllowed, match.ToString(), code));
                } 
                else { 
                    ProcessCodeBlock(match, CodeBlockType.Code, text);
                } 
            }

            // Check to see if it's a tag.  Don't run the tag regex if there is no '>' after the
            // current position, since we know it cannot match, and it can take an exponential 
            // amount of time to run (VSWhidbey 141878,358072)
 
            else if (!flags[inScriptTag] && 
#if PROFILE_REGEX
                     (match = RunTagRegex(text, textPos)).Success) 
#else
                     lastGTIndex > textPos && (match = tagRegex.Match(text, textPos)).Success)
#endif
            { 
                try {
                    if (!ProcessBeginTag(match, text)) 
                        fMatchedButNotProcessed = true; 
                }
                catch (Exception ex) { 
                    ProcessException(ex);
                }
            }
 
            // Check to see if it's an end tag
 
#if PROFILE_REGEX 
            else if ((match = RunEndTagRegex(text, textPos)).Success)
#else 
            else if ((match = endtagRegex.Match(text, textPos)).Success)
#endif
            {
                if (!ProcessEndTag(match)) 
                    fMatchedButNotProcessed = true;
            } 
 
            // Did we process the block that started with a '<'?
            if (match == null || !match.Success || fMatchedButNotProcessed) { 
                // If we could not match the '<' at all, check for some
                // specific syntax errors
                if (!fMatchedButNotProcessed && !flags[inScriptTag])
                    DetectSpecialServerTagError(text, textPos); 

                // Skip the '<' 
                textPos++; 
                AddLiteral("<");
            } 
            else {
                _lineNumber += Util.LineCount(text, textPos,
                                         match.Index + match.Length);
                textPos = match.Index + match.Length; 
            }
 
            // we might be done now 
            if (textPos == text.Length)
                break; 
        }

        if (flags[inScriptTag] && !IgnoreParseErrors) {
            // Change the line number to where the script tag started to get 
            // the correct error message (ASURT 13698).
            _lineNumber = _scriptStartLineNumber; 
 
            ProcessError(SR.GetString(SR.Unexpected_eof_looking_for_tag, "script"));
            return; 
        }

        // Process the final literal (if any)
        ProcessLiteral(); 
    }
 
    // Used for updatable deployment precompilation 
    void CreateModifiedMainDirectiveFileIfNeeded(string text, Match match,
            ParsedAttributeCollection mainDirective, Encoding fileEncoding) { 

        TextWriter precompTargetWriter = BuildManager.GetUpdatableDeploymentTargetWriter(CurrentVirtualPath, fileEncoding);

        // If we're not precompiling for deployment, there is nothing to do here 
        if (precompTargetWriter == null)
            return; 
 
        using (precompTargetWriter) {
 
            // Write out everything up to the main directive
            precompTargetWriter.Write(text.Substring(0, match.Index));

            precompTargetWriter.Write("<%@ " + DefaultDirectiveName); 

            // Go through all the attributes on the main directive 
            foreach (DictionaryEntry entry in mainDirective) { 

                string attribName = (string) entry.Key; 
                string attribValue = (string) entry.Value;

                // Remove the codefile and CodeFileBaseClass attributes
                if (StringUtil.EqualsIgnoreCase(attribName, "codefile")) continue; 
                if (StringUtil.EqualsIgnoreCase(attribName, CodeFileBaseClassAttributeName)) continue;
 
                // Write out a special token for the inherits attribute.  It will later be replaced by 
                // the full type later in the precompilation.  We can't do it here because we don't know
                // the assembly name yet (VSWhidbey 467936) 
                if (StringUtil.EqualsIgnoreCase(attribName, "inherits")) {
                    attribValue = BuildManager.UpdatableInheritReplacementToken;
                }
 
                precompTargetWriter.Write(" ");
                precompTargetWriter.Write(attribName); 
                precompTargetWriter.Write("=\""); 
                precompTargetWriter.Write(attribValue);
                precompTargetWriter.Write("\""); 
            }

            precompTargetWriter.Write(" %>");
 
            // Write out everything after the main directive
            precompTargetWriter.Write(text.Substring(match.Index+match.Length)); 
        } 
    }
 
    /*
     * Do what needs to be done before returning after the parsing is complete
     */
    internal virtual void HandlePostParse() { 

        // If there was no main directive in the page, process settings that may have come from config 
        if (!flags[mainDirectiveHandled]) { 
            ProcessMainDirective(_mainDirectiveConfigSettings);
            flags[mainDirectiveHandled] = true; 
        }

        // We need to check the PageParserFilter here to handle the case where the base was specified
        // in web.config, and was *not* overridden with an 'inherits' attribute. 
        if (_pageParserFilter != null) {
            if (!_pageParserFilter.AllowBaseType(BaseType)) { 
                throw new HttpException( 
                    SR.GetString(SR.Base_type_not_allowed, BaseType.FullName));
            } 
        }

        // If there is more than one builder on the stack, some tag was
        // not correctly closed, which is an error. 
        if (BuilderStack.Count > 1) {
            BuilderStackEntry entry = (BuilderStackEntry) _builderStack.Peek(); 
 
            string message = SR.GetString(SR.Unexpected_eof_looking_for_tag, entry._tagName);
            ProcessException(new HttpParseException(message, null, entry.VirtualPath, entry._inputText, entry.Line)); 

            return;
        }
 
        // If no language was specified in the page
        if (_compilerType == null) { 
 
            if (!FInDesigner) {
                // Get a default from config 
                _compilerType = CompilationUtil.GetDefaultLanguageCompilerInfo(
                    _compConfig, CurrentVirtualPath);
            }
            else { 
                // Get default from code
                _compilerType = CompilationUtil.GetCodeDefaultLanguageCompilerInfo(); 
            } 
        }
 
        CompilerParameters compilParams = _compilerType.CompilerParameters;

        // Override certain settings if they were specified on the page
        if (flags[hasDebugAttribute]) 
            compilParams.IncludeDebugInformation = flags[debug];
 
        // Debugging requires medium trust level 
        if (compilParams.IncludeDebugInformation)
            HttpRuntime.CheckAspNetHostingPermission(AspNetHostingPermissionLevel.Medium, SR.Debugging_not_supported_in_low_trust); 

        // If warningLevel was specified in the page, use it
        if (_warningLevel >= 0) {
            compilParams.WarningLevel = _warningLevel; 
            compilParams.TreatWarningsAsErrors = (_warningLevel>0);
        } 
        if (_compilerOptions != null) 
            compilParams.CompilerOptions = _compilerOptions;
 
        // Tell the filter (if any) that the parsing is complete
        if (_pageParserFilter != null)
            _pageParserFilter.ParseComplete(RootBuilder);
    } 

    /* 
     * Process all the text in the literal StringBuilder, and reset it 
     */
    private void ProcessLiteral() { 
        // Debug.Trace("Template", "Literal text: \"" + _literalBuilder.ToString() + "\"");

        // Get the current literal string
        string literal = GetLiteral(); 

        // Nothing to do if it's empty 
        if (String.IsNullOrEmpty(literal)) { 
            flags[ignoreNextSpaceString] = false;
            return; 
        }

        // In global.asax, we don't allow random rendering content
        if (FApplicationFile) { 
            // Make sure the literal is just white spaces
            int iFirstNonWhiteSpace = Util.FirstNonWhiteSpaceIndex(literal); 
 
            // Only move the line number if not ignore parser error, otherwise the linenumber
            // of other valid elements will be off. 
            if (iFirstNonWhiteSpace >= 0 && !IgnoreParseErrors) {
                // Move the line number back to the first non-whitespace
                _lineNumber -= Util.LineCount(literal, iFirstNonWhiteSpace, literal.Length);
 
                ProcessError(SR.GetString(SR.Invalid_app_file_content));
            } 
        } 
        else {
 
            // Check if we should ignore the string (ASURT 8186)
            bool fIgnoreThisLiteral = false;
            if (flags[ignoreNextSpaceString]) {
                flags[ignoreNextSpaceString] = false; 

                if (Util.IsWhiteSpaceString(literal)) 
                    fIgnoreThisLiteral = true; 
            }
 
            if (!fIgnoreThisLiteral) {

                // Process the settings that may come from config when the first non-trivial literal is parsed. VS Whidbey 141882
                if (!flags[mainDirectiveHandled]) { 
                    ProcessMainDirective(_mainDirectiveConfigSettings);
                    flags[mainDirectiveHandled] = true; 
                } 

                // Add it to the top builder 
                ControlBuilder builder = ((BuilderStackEntry) BuilderStack.Peek())._builder;
                try {
                    builder.AppendLiteralString(literal);
                } 
                catch (Exception e) {
                    if (!IgnoreParseErrors) { 
                        // If there was an error during the parsing of the literal, move 
                        // the line number back to the beginning of the literal
                        int iFirstNonWhiteSpace = Util.FirstNonWhiteSpaceIndex(literal); 
                        if (iFirstNonWhiteSpace < 0) iFirstNonWhiteSpace = 0;
                        _lineNumber -= Util.LineCount(literal, iFirstNonWhiteSpace, literal.Length);

                        ProcessException(e); 
                    }
                } 
 
                // Update the hash code with a fixed string, to mark that there is
                // a literal, but allow it to change without affecting the hash. 
                UpdateTypeHashCode("string");
            }
        }
 
        // Reset the StringBuilder for the next literal
        _literalBuilder = null; 
    } 

    /* 
     * Process a server side SCRIPT tag
     */
    private void ProcessServerScript() {
        // Get the contents of the script tag 
        string script = GetLiteral();
 
        // Nothing to do if it's empty. 
        // Unless we're in GenerateCodeCompileUnit mode, in which case
        // we want the empty block (VSWhidbey 112777) 
        if (String.IsNullOrEmpty(script)) {
            if (!IgnoreParseErrors)
                return;
 
            script = String.Empty;
        } 
 
        // Add this script to the script builder, unless we're
        // supposed to ignore it 
        if (!flags[ignoreScriptTag]) {

            // First, give the PageParserFilter a chance to handle the code block
            if (!PageParserFilterProcessedCodeBlock(CodeConstructType.ScriptTag, script, _currentScript.Line)) { 
                // Make sure it's legal to have code in this page
                EnsureCodeAllowed(); 
 
                _currentScript.Script = script;
                _scriptList.Add(_currentScript); 
                _currentScript = null;
            }
        }
        // Reset the StringBuilder for the next literal 
        _literalBuilder = null;
    } 
 
    internal virtual void CheckObjectTagScope(ref ObjectTagScope scope) {
 
        // Map the default scope to Page
        if (scope == ObjectTagScope.Default)
            scope = ObjectTagScope.Page;
 
        // Check for invalid scopes
        if (scope != ObjectTagScope.Page) { 
            throw new HttpException( 
                SR.GetString(SR.App_session_only_valid_in_global_asax));
        } 
    }

    /*
     * Process an Object tag, depending on its scope 
     */
    private void ProcessObjectTag(ObjectTagBuilder objectBuilder) { 
 
        ObjectTagScope scope = objectBuilder.Scope;
        CheckObjectTagScope(ref scope); 

        // Page and AppInstance are treated identically
        if (scope == ObjectTagScope.Page ||
            scope == ObjectTagScope.AppInstance) { 
            if (_pageObjectList == null)
                _pageObjectList = new ArrayList(); 
 
            _pageObjectList.Add(objectBuilder);
        } 
        else if (scope == ObjectTagScope.Session) {
            if (_sessionObjects == null)
                _sessionObjects = new HttpStaticObjectsCollection();
 
            _sessionObjects.Add(objectBuilder.ID,
                objectBuilder.ObjectType, 
                objectBuilder.LateBound); 
        }
        else if (scope == ObjectTagScope.Application) { 
            if (_applicationObjects == null)
                _applicationObjects = new HttpStaticObjectsCollection();

            _applicationObjects.Add(objectBuilder.ID, 
                objectBuilder.ObjectType,
                objectBuilder.LateBound); 
        } 
        else {
            Debug.Assert(false, "Unexpected scope!"); 
        }
    }

    /* 
     * Add a child builder to a builder
     */ 
    private void AppendSubBuilder(ControlBuilder builder, ControlBuilder subBuilder) { 
        // Check if it's an object tag
        if (subBuilder is ObjectTagBuilder) { 
            ProcessObjectTag((ObjectTagBuilder) subBuilder);
            return;
        }
 
        builder.AppendSubBuilder(subBuilder);
    } 
 
    /*
     * Process an opening tag (possibly self-closed) 
     */
    // Used to generate unique id's
    private int _controlCount;
    private bool ProcessBeginTag(Match match, string inputText) { 
        string tagName = match.Groups["tagname"].Value;
 
        // Get all the attributes into a bag 
        ParsedAttributeCollection attribs;
        string duplicateAttribute; 
        ProcessAttributes(match, out attribs, false /*fDirective*/, out duplicateAttribute);

        // Check if the tag is self closed
        bool fSelfClosed = match.Groups["empty"].Success; 

        // Is it a server side script tag? 
        if (StringUtil.EqualsIgnoreCase(tagName, "script") && flags[isServerTag]) { 
            ProcessScriptTag(match, inputText, attribs, fSelfClosed);
            return true; 
        }

        // Process the settings that may come from config when the first non-trivial tag is parsed.  VS Whidbey 141882
        if (!flags[mainDirectiveHandled]) { 
            ProcessMainDirective(_mainDirectiveConfigSettings);
            flags[mainDirectiveHandled] = true; 
        } 

        ControlBuilder parentBuilder = null; 
        ControlBuilder subBuilder = null;
        Type childType = null;

        // This could be a property of an object that is filterable 
        string realTagName;
        string filter = Util.ParsePropertyDeviceFilter(tagName, out realTagName); 
 
        // Check if the parent builder wants to create a subcontrol for this tag.
        if (BuilderStack.Count > 1) { 

            parentBuilder = ((BuilderStackEntry) _builderStack.Peek())._builder;

            // If the parent builder is a StringPropertyBuilder, we want to treat everything 
            // in it as a literal, so we always return false here (VSWhidbey 285429)
            if (parentBuilder is StringPropertyBuilder) 
                return false; 

            subBuilder = parentBuilder.CreateChildBuilder(filter, realTagName, attribs, 
                this, parentBuilder, _id, _lineNumber, CurrentVirtualPath, ref childType, false);
        }

        // If not, use the root builder if runat=server is there. 
        if (subBuilder == null && flags[isServerTag]) {
            subBuilder = RootBuilder.CreateChildBuilder(filter, realTagName, attribs, 
                this, parentBuilder, _id, _lineNumber, CurrentVirtualPath, ref childType, false); 
        }
 
        // In case we find that the top stack item has the same name as the
        // current tag, we increase a count on the stack item.  This way, we
        // know that we need to ignore the corresponding closing tag (ASURT 50795)
        if (subBuilder == null && _builderStack.Count > 1 && !fSelfClosed) { 
            BuilderStackEntry stackEntry = (BuilderStackEntry) _builderStack.Peek();
            if (StringUtil.EqualsIgnoreCase(tagName, stackEntry._tagName)) 
                stackEntry._repeatCount++; 
        }
 
        // We could not get the type of a server control from that tag
        if (subBuilder == null) {
            // If it wasn't marked as runat=server, ignore
            if (!flags[isServerTag] || IgnoreParseErrors) 
                return false;
 
            // If it was marked as runat=server, fail 
            ProcessError(SR.GetString(SR.Unknown_server_tag, tagName));
            return true; 
        }

        // We have a server control
 
        // If we have a control type filter, make sure the child control is allowed
        if (_pageParserFilter != null) { 
            Debug.Assert(childType != null); 

            if (!_pageParserFilter.AllowControlInternal(childType, subBuilder)) { 
                ProcessError(SR.GetString(SR.Control_type_not_allowed, childType.FullName));
                return true;
            }
        } 

        // Make sure it doesn't have duplicated attributes 
        if (duplicateAttribute != null) { 
            ProcessError(SR.GetString(SR.Duplicate_attr_in_tag, duplicateAttribute));
        } 

        // Get the id from the builder.  Note that it may be null even if _id was not initially null,
        // if the builder is not for a Control (VSWhidbey 406302)
        _id = subBuilder.ID; 

        // If it has an id, enforce validity and uniqueness 
        if (_id != null) { 
            if (!System.CodeDom.Compiler.CodeGenerator.IsValidLanguageIndependentIdentifier(_id)) {
                ProcessError(SR.GetString(SR.Invalid_identifier, _id)); 
                return true;
            }

            if (_idList.Contains(_id)) { 
                ProcessError(SR.GetString(SR.Id_already_used, _id));
                return true; 
            } 

            _idList.Add(_id); 
        }
        else if (flags[isServerTag]) {
            // Make sure that cached controls always have a fixed id to prevent
            // unpredictable behavior (ASURT 83402) 
            PartialCachingAttribute cacheAttrib = (PartialCachingAttribute)
                TypeDescriptor.GetAttributes(childType)[typeof(PartialCachingAttribute)]; 
 
            // If we are parsing a theme file, the controls do not have an ID,
            // and we should not be adding one. (Dev10 bug 660310) 
            if (!(subBuilder.Parser is PageThemeParser) && cacheAttrib != null) {
                _id = "_ctrl_" + _controlCount.ToString(NumberFormatInfo.InvariantInfo);
                subBuilder.ID = _id;
                _controlCount++; 
                // Controls can't be filtered, so use the default filter
                subBuilder.PreprocessAttribute(String.Empty, "id", _id, false /*mainDirectiveMode*/); 
            } 
        }
 

        // Take care of the previous literal string
        ProcessLiteral();
 
        if (childType != null) {
            // Update the hash code with the name of the control's type 
            UpdateTypeHashCode(childType.FullName); 
        }
 
        // If the server control has a body, and if it didn't self-close
        // (i.e. wasn't terminated with "/>"), put it on the stack of controls.
        if (!fSelfClosed && subBuilder.HasBody()) {
 
            // If it's a template, push a new ID list (ASURT 72773)
            if (subBuilder is TemplateBuilder && ((TemplateBuilder)subBuilder).AllowMultipleInstances) { 
                _idListStack.Push(_idList); 
                _idList = new CaseInsensitiveStringSet();
            } 

            _builderStack.Push(new BuilderStackEntry(subBuilder, tagName,
                               CurrentVirtualPathString, _lineNumber,
                               inputText, match.Index + match.Length)); 
        }
        else { 
            // Append the sub builder to the current builder 
            parentBuilder = ((BuilderStackEntry) _builderStack.Peek())._builder;
            AppendSubBuilder(parentBuilder, subBuilder); 

            // Tell the builder that we're done parsing its control
            subBuilder.CloseControl();
        } 

        return true; 
    } 

    /* 
     * Process a 
            if (!StringUtil.EqualsIgnoreCase(tagName, "script")) 
                return false; 

            ProcessServerScript(); 

            flags[inScriptTag] = false;
            flags[ignoreScriptTag] = false;
 
            return true;
        } 
 
        // See if anyone on the stack cares about termination.
        return MaybeTerminateControl(tagName, match.Index); 
    }

    internal bool IsExpressionBuilderValue(string val) {
        return ControlBuilder.expressionBuilderRegex.Match(val, 0).Success; 
    }
 
 
    internal abstract string DefaultDirectiveName { get; }
 
    // If there is a parser filter, give it a chance to look at the directive
    internal void PreprocessDirective(string directiveName, IDictionary directive) {

        // No parser filter: done 
        if (_pageParserFilter == null)
            return; 
 
        if (directiveName.Length == 0)
            directiveName = DefaultDirectiveName; 

        _pageParserFilter.PreprocessDirective(directiveName, directive);
    }
 
    /*
     * Process a <%@ %> block 
     */ 
    internal virtual void ProcessDirective(string directiveName, IDictionary directive) {
 
        // Check for the main directive, which is "page" for an aspx,
        // and "application" for global.asax
        if (directiveName.Length == 0) {
 
            if (FInDesigner) {
                return; 
            } 

            // Make sure the main directive was not already specified 
            if (flags[mainDirectiveSpecified]) {
                ProcessError(SR.GetString(SR.Only_one_directive_allowed, DefaultDirectiveName));

                return; 
            }
 
            // If there are some config settings that were not overriden, add them to the list 
            if (_mainDirectiveConfigSettings != null) {
                // Go through all the config attributes 
                foreach (DictionaryEntry entry in _mainDirectiveConfigSettings) {

                    // If it was overridden, ignore the config setting
                    if (directive.Contains(entry.Key)) 
                        continue;
 
                    // Add it to the list 
                    directive[entry.Key] = entry.Value;
                } 
            }

            ProcessMainDirective(directive);
 
            flags[mainDirectiveSpecified] = true;
            flags[mainDirectiveHandled] = true; 
        } 
        else if (StringUtil.EqualsIgnoreCase(directiveName, "assembly")) {
            // Assembly directive 

            // Even though this only makes sense for compiled pages, Sharepoint needs us to
            // ignore instead of throw when the page in non-compiled.
 
            // Remove the attributes as we get them from the dictionary
            string assemblyName = Util.GetAndRemoveNonEmptyAttribute(directive, "name"); 
            VirtualPath src = Util.GetAndRemoveVirtualPathAttribute(directive, "src"); 

            // If there are some attributes left, fail 
            Util.CheckUnknownDirectiveAttributes(directiveName, directive);

            if (assemblyName != null && src != null) {
                ProcessError(SR.GetString(SR.Attributes_mutually_exclusive, "Name", "Src")); 
            }
 
            if (assemblyName != null) { 
                AddAssemblyDependency(assemblyName);
            } 
            // Is it a source file that needs to be compiled on the fly
            else if (src != null) {
                ImportSourceFile(src);
            } 
            else {
                ProcessError(SR.GetString(SR.Missing_attr, "name")); 
            } 
        }
        else if (StringUtil.EqualsIgnoreCase(directiveName, "import")) { 

            // Import directive

            ProcessImportDirective(directiveName, directive); 
        }
        else if (StringUtil.EqualsIgnoreCase(directiveName, "implements")) { 
            // 'implements' directive 

            // We must compile the page if it asks to implement an interface 
            OnFoundDirectiveRequiringCompilation(directiveName);

            // Remove the attributes as we get them from the dictionary
            string interfaceName = Util.GetAndRemoveRequiredAttribute(directive, "interface"); 

            // If there are some attributes left, fail 
            Util.CheckUnknownDirectiveAttributes(directiveName, directive); 

            Type interfaceType = GetType(interfaceName); 

            // Make sure that it's an interface
            if (!interfaceType.IsInterface) {
                ProcessError(SR.GetString(SR.Invalid_type_to_implement, interfaceName)); 

                return; 
            } 

            // Add the interface type to the list 
            if (_implementedInterfaces == null) {
                _implementedInterfaces = new ArrayList();
            }
            _implementedInterfaces.Add(interfaceType); 
        }
        else if (!FInDesigner) { 
            ProcessError(SR.GetString(SR.Unknown_directive, directiveName)); 
        }
    } 

    internal virtual void ProcessMainDirective(IDictionary mainDirective) {

        // Used to store some temporary data resulting from the parsing of the directive 
        IDictionary parseData = new HybridDictionary();
 
        // Keep track of unknown attributes 
        ParsedAttributeCollection unknownAttributes = null;
 
        // Go through all the attributes on the directive
        foreach (DictionaryEntry entry in mainDirective) {

            string attribName = (string)entry.Key; 

            // Parse out the device name, if any 
            string deviceName = Util.ParsePropertyDeviceFilter(attribName, out attribName); 

            try { 
                // Try to process the attribute, and if not, keep track of it in the 'unknown' list
                if (!ProcessMainDirectiveAttribute(deviceName, attribName, (string)entry.Value, parseData)) {
                    if (unknownAttributes == null) {
                        unknownAttributes = CreateEmptyAttributeBag(); 
                    }
 
                    unknownAttributes.AddFilteredAttribute(deviceName, attribName, (string)entry.Value); 
                }
            } 
            catch (Exception e) {
                ProcessException(e);
            }
        } 

        // Allow some postprocessing to happen, in case attributes have dependencies 
        // on each other (e.g. mutually exclusive attributes). 
        PostProcessMainDirectiveAttributes(parseData);
 
        // We should always set the control type of the root builder regardless of unknown attributes
        RootBuilder.SetControlType(BaseType);

        // If we didn't have any unknown attributes, we're done 
        if (unknownAttributes == null)
            return; 
 
        RootBuilder.ProcessImplicitResources(unknownAttributes);
 
        // Process all the unknown attributes
        foreach (FilteredAttributeDictionary filteredAttributes in unknownAttributes.GetFilteredAttributeDictionaries()) {
            string filter = filteredAttributes.Filter;
 
            foreach (DictionaryEntry attribute in filteredAttributes) {
                string attribName = (string)attribute.Key; 
                ProcessUnknownMainDirectiveAttribute(filter, attribName, (string) attribute.Value); 
            }
        } 
    }

    internal virtual bool ProcessMainDirectiveAttribute(string deviceName, string name,
        string value, IDictionary parseData) { 

        switch (name) { 
        // Ignore description and codebehind attributes 
        case "description":
        case "codebehind": 
            break;

        case "debug":
            flags[debug] = Util.GetBooleanAttribute(name, value); 
            if (flags[debug] && !HttpRuntime.HasAspNetHostingPermission(AspNetHostingPermissionLevel.Medium)) {
                throw new HttpException(SR.GetString(SR.Insufficient_trust_for_attribute, "debug")); 
            } 

            flags[hasDebugAttribute] = true; 
            break;

        case "linepragmas":
            flags[noLinePragmas] = !Util.GetBooleanAttribute(name, value); 
            break;
 
        case "warninglevel": 
            _warningLevel = Util.GetNonNegativeIntegerAttribute(name, value);
            break; 

        case "compileroptions":
            // This only makes sense for compiled pages
            OnFoundAttributeRequiringCompilation(name); 

            string compilerOptions = value.Trim(); 
 
            CompilationUtil.CheckCompilerOptionsAllowed(compilerOptions, false /*config*/, null, 0);
 
            _compilerOptions = compilerOptions;
            break;

        // These two really only make sense in VB 
        case "explicit":
            flags[useExplicit] = Util.GetBooleanAttribute(name, value); 
            break; 
        case "strict":
            flags[strict] = Util.GetBooleanAttribute(name, value); 
            break;

        case "language":
            ValidateBuiltInAttribute(deviceName, name, value); 
            string language = Util.GetNonEmptyAttribute(name, value);
            ProcessLanguageAttribute(language); 
            break; 

        // A "src" attribute is equivalent to an imported source file 
        case "src":
            // This only makes sense for compiled pages
            OnFoundAttributeRequiringCompilation(name);
 
            // Remember the src assembly for post processing
            parseData[name] = Util.GetNonEmptyAttribute(name, value); 
            break; 

        case "inherits": 
            // Remember the base class for post processing
            parseData[name] = Util.GetNonEmptyAttribute(name, value);
            break;
 
        case "classname":
 
            // Even though this only makes sense for compiled pages, Sharepoint needs us to 
            // ignore instead of throw when the page in non-compiled.
 
            _generatedClassName = Util.GetNonEmptyFullClassNameAttribute(name, value,
                ref _generatedNamespace);
            break;
 
        case "codefile":
            // This only makes sense for compiled pages 
            OnFoundAttributeRequiringCompilation(name); 

            try { 
                ProcessCodeFile(VirtualPath.Create(Util.GetNonEmptyAttribute(name, value)));
            }
            catch (Exception ex) {
                ProcessException(ex); 
            }
            break; 
 
        default:
            // We didn't handle the attribute 
            return false;
        }

        // The attribute was handled 

        // Make sure no device filter or resource expression was specified 
        ValidateBuiltInAttribute(deviceName, name, value); 

        return true; 
    }

    // Throw an exception if there is a device filter or resource expression
    internal void ValidateBuiltInAttribute(string deviceName, string name, string value) { 
        Debug.Assert(deviceName != null);
 
        if (IsExpressionBuilderValue(value)) { 
            ProcessError(SR.GetString(SR.Illegal_Resource_Builder, name));
        } 

        if (deviceName.Length > 0) {
            ProcessError(SR.GetString(SR.Illegal_Device, name));
        } 
    }
 
    internal virtual void ProcessUnknownMainDirectiveAttribute(string filter, string attribName, string value) { 
        // By default, it is not legal to have unknown attributes.  But derived parser
        // classes can change this behavior 
        ProcessError(SR.GetString(SR.Attr_not_supported_in_directive,
                attribName, DefaultDirectiveName));
    }
 
    internal virtual void PostProcessMainDirectiveAttributes(IDictionary parseData) {
 
        // Post process the src and inherits attributes 

        string src = (string) parseData["src"]; 
        Assembly assembly = null;
        if (src != null) {
            try {
                assembly = ImportSourceFile(VirtualPath.Create(src)); 
            }
            catch (Exception ex) { 
                ProcessException(ex); 
            }
        } 

        // Was a code file base type specified in the directive
        string codeFileBaseTypeName = (string)parseData[CodeFileBaseClassAttributeName];
 
        // If so, there must also be a CodeFile attribute
        if (codeFileBaseTypeName != null && _codeFileVirtualPath == null) { 
            throw new HttpException(SR.GetString(SR.CodeFileBaseClass_Without_Codefile)); 
        }
 
        // Was a base type specified in the directive
        string baseTypeName = (string) parseData["inherits"];
        if (baseTypeName != null) {
            try { 
                ProcessInheritsAttribute(baseTypeName, codeFileBaseTypeName, src, assembly);
            } 
            catch (Exception ex) { 
                ProcessException(ex);
            } 
        }
        else {
            if (_codeFileVirtualPath != null) {
                throw new HttpException(SR.GetString(SR.Codefile_without_inherits)); 
            }
        } 
    } 

    private void ProcessInheritsAttribute(string baseTypeName, string codeFileBaseTypeName, 
        string src, Assembly assembly) {

        // If a code file is used, then the inherits attribute points to the class in that file,
        // which is not yet compiled.  In that case, we cannot get the Type, so we just keep 
        // track of the class name (and namespace)
        if (_codeFileVirtualPath != null) { 
            _baseTypeName = Util.GetNonEmptyFullClassNameAttribute("inherits", baseTypeName, 
                ref _baseTypeNamespace);
 
            // Now set baseTypeName to codeFileBaseTypeName, so that if it was set, it will
            // be used as the BaseType during parsing (DevDiv 43024)
            baseTypeName = codeFileBaseTypeName;
 
            if (baseTypeName == null)
                return; 
        } 

        Type baseType = null; 
        if (assembly != null)
            baseType = assembly.GetType(baseTypeName, false /* throwOnError */, true /* caseInsensitive */);
        else {
            try { 
                baseType = GetType(baseTypeName);
            } 
            catch { 
                // We couldn't load the inherits type.  If the classname attribute has a
                // namespace, check if the inherits type exists in there (VSWhidbey 297056) 

                // If the classname attribute doesn't have a namespace, give up
                if (_generatedNamespace == null)
                    throw; 

                // If the inherits attribute already had a namespace, don't try this 
                if (baseTypeName.IndexOf('.') >= 0) 
                    throw;
 
                try {
                    // Try loading the inherit using the classname's namespace
                    string baseTypeNameWithNS = _generatedNamespace + "." + baseTypeName;
                    baseType = GetType(baseTypeNameWithNS); 
                }
                catch {} 
 
                // If that failed too, rethrow the original exception
                if (baseType == null) 
                    throw;
            }
        }
 
        // Make sure we successfully got the Type of the base class
        if (baseType == null) { 
            Debug.Assert(assembly != null, "assembly != null"); 
            ProcessError(SR.GetString(SR.Non_existent_base_type, baseTypeName, src));
 
            return;
        }

        // Make sure the base type extends the DefaultBaseType (Page or UserControl) 
        if (!DefaultBaseType.IsAssignableFrom(baseType)) {
            ProcessError(SR.GetString(SR.Invalid_type_to_inherit_from, baseTypeName, 
                    _baseType.FullName)); 

            return; 
        }

        // If we have a control type filter, make sure the base type is allowed
        if (_pageParserFilter != null) { 

            if (!_pageParserFilter.AllowBaseType(baseType)) { 
                throw new HttpException( 
                    SR.GetString(SR.Base_type_not_allowed, baseType.FullName));
            } 
        }

        _baseType = baseType;
 
        // Now that we have the base type, we can create the RootBuilder
        Debug.Assert(_rootBuilder == null); 
        EnsureRootBuilderCreated(); 

        // Make sure we link with the assembly of the base type (ASURT 101778) 
        AddTypeDependency(_baseType);

        // Remember the fact that the page uses codebehind
        flags[hasCodeBehind] = true; 
    }
 
    private void ProcessImportDirective(string directiveName, IDictionary directive) { 

        // Even though this only makes sense for compiled pages, Sharepoint needs us to 
        // ignore instead of throw when the page in non-compiled.

        // Remove the attributes as we get them from the dictionary
        string ns = Util.GetAndRemoveNonEmptyNoSpaceAttribute(directive, "namespace"); 

        if (ns == null) 
            ProcessError(SR.GetString(SR.Missing_attr, "namespace")); 
        else
            AddImportEntry(ns); 

        // If there are some attributes left, fail
        Util.CheckUnknownDirectiveAttributes(directiveName, directive);
    } 

    /* 
     * Process a language attribute, as can appear in the Page directive and in 
     * 
                        
                    
                    

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