File: System\Xml\Xsl\XsltOld\OutputScopeManager.cs
Web Access
Project: src\src\libraries\System.Private.Xml\src\System.Private.Xml.csproj (System.Private.Xml)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Diagnostics;
using System.Globalization;
using System.Xml;
 
namespace System.Xml.Xsl.XsltOld
{
    internal sealed class OutputScopeManager
    {
        private const int STACK_INCREMENT = 10;
 
        private readonly HWStack _elementScopesStack;
        private string _defaultNS;
        private readonly OutKeywords _atoms;
        private readonly XmlNameTable _nameTable;
        private int _prefixIndex;
 
        internal string DefaultNamespace
        {
            get { return _defaultNS; }
        }
 
        internal OutputScope CurrentElementScope
        {
            get
            {
                Debug.Assert(_elementScopesStack.Peek() != null); // We adding rootElementScope to garantee this
                return (OutputScope)_elementScopesStack.Peek()!;
            }
        }
 
        internal XmlSpace XmlSpace
        {
            get { return CurrentElementScope.Space; }
        }
 
        internal string XmlLang
        {
            get { return CurrentElementScope.Lang; }
        }
 
        internal OutputScopeManager(XmlNameTable nameTable, OutKeywords atoms)
        {
            Debug.Assert(nameTable != null);
            Debug.Assert(atoms != null);
 
            _elementScopesStack = new HWStack(STACK_INCREMENT);
            _nameTable = nameTable;
            _atoms = atoms;
            _defaultNS = _atoms.Empty;
 
            // We always adding rootElementScope to garantee that CurrentElementScope != null
            // This context is active between PI and first element for example
            OutputScope rootElementScope = (OutputScope)_elementScopesStack.Push();
            if (rootElementScope == null)
            {
                rootElementScope = new OutputScope();
                _elementScopesStack.AddToTop(rootElementScope);
            }
            rootElementScope.Init(string.Empty, string.Empty, string.Empty, /*space:*/XmlSpace.None, /*lang:*/string.Empty, /*mixed:*/false);
        }
 
        internal void PushNamespace(string prefix, string nspace)
        {
            Debug.Assert(prefix != null);
            Debug.Assert(nspace != null);
            CurrentElementScope.AddNamespace(prefix, nspace, _defaultNS);
 
            if (string.IsNullOrEmpty(prefix))
            {
                _defaultNS = nspace;
            }
        }
 
        internal void PushScope(string name, string nspace, string prefix)
        {
            Debug.Assert(name != null);
            Debug.Assert(nspace != null);
            Debug.Assert(prefix != null);
            OutputScope parentScope = CurrentElementScope;
            OutputScope elementScope = (OutputScope)_elementScopesStack.Push();
 
            if (elementScope == null)
            {
                elementScope = new OutputScope();
                _elementScopesStack.AddToTop(elementScope);
            }
 
            Debug.Assert(elementScope != null);
            elementScope.Init(name, nspace, prefix, parentScope.Space, parentScope.Lang, parentScope.Mixed);
        }
 
        internal void PopScope()
        {
            OutputScope? elementScope = (OutputScope?)_elementScopesStack.Pop();
 
            Debug.Assert(elementScope != null); // We're adding rootElementScope to guarantee this
 
            for (NamespaceDecl? scope = elementScope.Scopes; scope != null; scope = scope.Next)
            {
                _defaultNS = scope.PrevDefaultNsUri;
            }
        }
 
        internal string? ResolveNamespace(string prefix)
        {
            return ResolveNamespace(prefix, out _);
        }
 
        internal string? ResolveNamespace(string prefix, out bool thisScope)
        {
            Debug.Assert(prefix != null);
            thisScope = true;
 
            if (string.IsNullOrEmpty(prefix))
            {
                return _defaultNS;
            }
            else
            {
                if (Ref.Equal(prefix, _atoms.Xml))
                {
                    return _atoms.XmlNamespace;
                }
                else if (Ref.Equal(prefix, _atoms.Xmlns))
                {
                    return _atoms.XmlnsNamespace;
                }
 
                for (int i = _elementScopesStack.Length - 1; i >= 0; i--)
                {
                    Debug.Assert(_elementScopesStack[i] is OutputScope);
                    OutputScope elementScope = (OutputScope)_elementScopesStack[i];
 
                    string? nspace = elementScope.ResolveAtom(prefix);
                    if (nspace != null)
                    {
                        thisScope = (i == _elementScopesStack.Length - 1);
                        return nspace;
                    }
                }
            }
 
            return null;
        }
 
        internal bool FindPrefix(string nspace, out string? prefix)
        {
            Debug.Assert(nspace != null);
            for (int i = _elementScopesStack.Length - 1; 0 <= i; i--)
            {
                Debug.Assert(_elementScopesStack[i] is OutputScope);
 
                OutputScope elementScope = (OutputScope)_elementScopesStack[i];
                string? pfx;
                if (elementScope.FindPrefix(nspace, out pfx))
                {
                    string? testNspace = ResolveNamespace(pfx);
                    if (testNspace != null && Ref.Equal(testNspace, nspace))
                    {
                        prefix = pfx;
                        return true;
                    }
                    else
                    {
                        break;
                    }
                }
            }
            prefix = null;
            return false;
        }
 
        internal string GeneratePrefix(string format)
        {
            string prefix;
 
            do
            {
                prefix = string.Format(CultureInfo.InvariantCulture, format, _prefixIndex++);
            } while (_nameTable.Get(prefix) != null);
 
            return _nameTable.Add(prefix);
        }
    }
}