diff options
Diffstat (limited to 'src/mscorlib/src/System/CfgParser.cs')
-rw-r--r-- | src/mscorlib/src/System/CfgParser.cs | 574 |
1 files changed, 574 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/CfgParser.cs b/src/mscorlib/src/System/CfgParser.cs new file mode 100644 index 0000000000..ef368a9020 --- /dev/null +++ b/src/mscorlib/src/System/CfgParser.cs @@ -0,0 +1,574 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*============================================================ + ** + ** + ** + ** Purpose: XMLParser and Tree builder internal to BCL + ** + ** + ===========================================================*/ + +namespace System +{ + using System.Runtime.InteropServices; + using System.Collections; + using System.Collections.Generic; + using System.Runtime.CompilerServices; + using System.Security.Permissions; + using System.Security; + using System.Globalization; + using System.IO; + using System.Runtime.Versioning; + using System.Diagnostics.Contracts; + + [Serializable] + internal enum ConfigEvents + { + StartDocument = 0, + StartDTD = StartDocument + 1, + EndDTD = StartDTD + 1, + StartDTDSubset = EndDTD + 1, + EndDTDSubset = StartDTDSubset + 1, + EndProlog = EndDTDSubset + 1, + StartEntity = EndProlog + 1, + EndEntity = StartEntity + 1, + EndDocument = EndEntity + 1, + DataAvailable = EndDocument + 1, + LastEvent = DataAvailable + } + + [Serializable] + internal enum ConfigNodeType + { + Element = 1, + Attribute = Element + 1, + Pi = Attribute + 1, + XmlDecl = Pi + 1, + DocType = XmlDecl + 1, + DTDAttribute = DocType + 1, + EntityDecl = DTDAttribute + 1, + ElementDecl = EntityDecl + 1, + AttlistDecl = ElementDecl + 1, + Notation = AttlistDecl + 1, + Group = Notation + 1, + IncludeSect = Group + 1, + PCData = IncludeSect + 1, + CData = PCData + 1, + IgnoreSect = CData + 1, + Comment = IgnoreSect + 1, + EntityRef = Comment + 1, + Whitespace = EntityRef + 1, + Name = Whitespace + 1, + NMToken = Name + 1, + String = NMToken + 1, + Peref = String + 1, + Model = Peref + 1, + ATTDef = Model + 1, + ATTType = ATTDef + 1, + ATTPresence = ATTType + 1, + DTDSubset = ATTPresence + 1, + LastNodeType = DTDSubset + 1 + } + + [Serializable] + internal enum ConfigNodeSubType + { + Version = (int)ConfigNodeType.LastNodeType, + Encoding = Version + 1, + Standalone = Encoding + 1, + NS = Standalone + 1, + XMLSpace = NS + 1, + XMLLang = XMLSpace + 1, + System = XMLLang + 1, + Public = System + 1, + NData = Public + 1, + AtCData = NData + 1, + AtId = AtCData + 1, + AtIdref = AtId + 1, + AtIdrefs = AtIdref + 1, + AtEntity = AtIdrefs + 1, + AtEntities = AtEntity + 1, + AtNmToken = AtEntities + 1, + AtNmTokens = AtNmToken + 1, + AtNotation = AtNmTokens + 1, + AtRequired = AtNotation + 1, + AtImplied = AtRequired + 1, + AtFixed = AtImplied + 1, + PentityDecl = AtFixed + 1, + Empty = PentityDecl + 1, + Any = Empty + 1, + Mixed = Any + 1, + Sequence = Mixed + 1, + Choice = Sequence + 1, + Star = Choice + 1, + Plus = Star + 1, + Questionmark = Plus + 1, + LastSubNodeType = Questionmark + 1 + } + + internal abstract class BaseConfigHandler + { + // These delegates must be at the very start of the object + // This is necessary because unmanaged code takes a dependency on this layout + // Any changes made to this must be reflected in ConfigHelper.h in ConfigFactory class + protected Delegate[] eventCallbacks; + public BaseConfigHandler() + { + InitializeCallbacks(); + } + private void InitializeCallbacks() + { + if (eventCallbacks == null) + { + eventCallbacks = new Delegate[6]; + eventCallbacks[0] = new NotifyEventCallback(this.NotifyEvent); + eventCallbacks[1] = new BeginChildrenCallback(this.BeginChildren); + eventCallbacks[2] = new EndChildrenCallback(this.EndChildren); + eventCallbacks[3] = new ErrorCallback(this.Error); + eventCallbacks[4] = new CreateNodeCallback(this.CreateNode); + eventCallbacks[5] = new CreateAttributeCallback(this.CreateAttribute); + } + } + + private delegate void NotifyEventCallback(ConfigEvents nEvent); + public abstract void NotifyEvent(ConfigEvents nEvent); + + private delegate void BeginChildrenCallback(int size, + ConfigNodeSubType subType, + ConfigNodeType nType, + int terminal, + [MarshalAs(UnmanagedType.LPWStr)] String text, + int textLength, + int prefixLength); + public abstract void BeginChildren(int size, + ConfigNodeSubType subType, + ConfigNodeType nType, + int terminal, + [MarshalAs(UnmanagedType.LPWStr)] String text, + int textLength, + int prefixLength); + + private delegate void EndChildrenCallback(int fEmpty, + int size, + ConfigNodeSubType subType, + ConfigNodeType nType, + int terminal, + [MarshalAs(UnmanagedType.LPWStr)] String text, + int textLength, + int prefixLength); + public abstract void EndChildren(int fEmpty, + int size, + ConfigNodeSubType subType, + ConfigNodeType nType, + int terminal, + [MarshalAs(UnmanagedType.LPWStr)] String text, + int textLength, + int prefixLength); + + private delegate void ErrorCallback(int size, + ConfigNodeSubType subType, + ConfigNodeType nType, + int terminal, + [MarshalAs(UnmanagedType.LPWStr)]String text, + int textLength, + int prefixLength); + public abstract void Error(int size, + ConfigNodeSubType subType, + ConfigNodeType nType, + int terminal, + [MarshalAs(UnmanagedType.LPWStr)]String text, + int textLength, + int prefixLength); + + private delegate void CreateNodeCallback(int size, + ConfigNodeSubType subType, + ConfigNodeType nType, + int terminal, + [MarshalAs(UnmanagedType.LPWStr)]String text, + int textLength, + int prefixLength); + public abstract void CreateNode(int size, + ConfigNodeSubType subType, + ConfigNodeType nType, + int terminal, + [MarshalAs(UnmanagedType.LPWStr)]String text, + int textLength, + int prefixLength); + + private delegate void CreateAttributeCallback(int size, + ConfigNodeSubType subType, + ConfigNodeType nType, + int terminal, + [MarshalAs(UnmanagedType.LPWStr)]String text, + int textLength, + int prefixLength); + public abstract void CreateAttribute(int size, + ConfigNodeSubType subType, + ConfigNodeType nType, + int terminal, + [MarshalAs(UnmanagedType.LPWStr)]String text, + int textLength, + int prefixLength); + + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern void RunParser(String fileName); + } + + // Class used to build a DOM like tree of parsed XML + internal class ConfigTreeParser : BaseConfigHandler + { + ConfigNode rootNode = null; + ConfigNode currentNode = null; + String fileName = null; + int attributeEntry; + String key = null; + String [] treeRootPath = null; // element to start tree + bool parsing = false; + int depth = 0; + int pathDepth = 0; + int searchDepth = 0; + bool bNoSearchPath = false; + + // Track state for error message formatting + String lastProcessed = null; + bool lastProcessedEndElement; + + + // NOTE: This parser takes a path eg. /configuration/system.runtime.remoting + // and will return a node which matches this. + internal ConfigNode Parse(String fileName, String configPath) + { + return Parse(fileName, configPath, false); + } + + [System.Security.SecuritySafeCritical] // auto-generated + internal ConfigNode Parse(String fileName, String configPath, bool skipSecurityStuff) + { + if (fileName == null) + throw new ArgumentNullException("fileName"); + Contract.EndContractBlock(); + this.fileName = fileName; + if (configPath[0] == '/'){ + treeRootPath = configPath.Substring(1).Split('/'); + pathDepth = treeRootPath.Length - 1; + bNoSearchPath = false; + } + else{ + treeRootPath = new String[1]; + treeRootPath[0] = configPath; + bNoSearchPath = true; + } + + if (!skipSecurityStuff) { + (new FileIOPermission( FileIOPermissionAccess.Read, System.IO.Path.GetFullPathInternal( fileName ) )).Demand(); + } +#pragma warning disable 618 + (new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)).Assert(); +#pragma warning restore 618 + + try + { + RunParser(fileName); + } + catch(FileNotFoundException) { + throw; // Pass these through unadulterated. + } + catch(DirectoryNotFoundException) { + throw; // Pass these through unadulterated. + } + catch(UnauthorizedAccessException) { + throw; + } + catch(FileLoadException) { + throw; + } + catch(Exception inner) { + String message = GetInvalidSyntaxMessage(); + // Neither Exception nor ApplicationException are the "right" exceptions here. + // Desktop throws ApplicationException for backwards compatibility. + // On Silverlight we don't have ApplicationException, so fall back to Exception. +#if FEATURE_CORECLR + throw new Exception(message, inner); +#else + throw new ApplicationException(message, inner); +#endif + } + return rootNode; + } + + public override void NotifyEvent(ConfigEvents nEvent) + { + BCLDebug.Trace("REMOTE", "NotifyEvent "+((Enum)nEvent).ToString()+"\n"); + } + + public override void BeginChildren(int size, + ConfigNodeSubType subType, + ConfigNodeType nType, + int terminal, + [MarshalAs(UnmanagedType.LPWStr)] String text, + int textLength, + int prefixLength) + { + //Trace("BeginChildren",size,subType,nType,terminal,text,textLength,prefixLength,0); + if (!parsing && + (!bNoSearchPath + && depth == (searchDepth + 1) + && String.Compare(text, treeRootPath[searchDepth], StringComparison.Ordinal) == 0)) + { + searchDepth++; + } + } + + public override void EndChildren(int fEmpty, + int size, + ConfigNodeSubType subType, + ConfigNodeType nType, + int terminal, + [MarshalAs(UnmanagedType.LPWStr)] String text, + int textLength, + int prefixLength) + { + lastProcessed = text; + lastProcessedEndElement = true; + if (parsing) + { + //Trace("EndChildren",size,subType,nType,terminal,text,textLength,prefixLength,fEmpty); + + if (currentNode == rootNode) + { + // End of section of tree which is parsed + parsing = false; + } + + currentNode = currentNode.Parent; + } + else if (nType == ConfigNodeType.Element){ + if(depth == searchDepth && String.Compare(text, treeRootPath[searchDepth - 1], StringComparison.Ordinal) == 0) + { + searchDepth--; + depth--; + } + else + depth--; + } + } + + public override void Error(int size, + ConfigNodeSubType subType, + ConfigNodeType nType, + int terminal, + [MarshalAs(UnmanagedType.LPWStr)]String text, + int textLength, + int prefixLength) + { + //Trace("Error",size,subType,nType,terminal,text,textLength,prefixLength,0); + } + + public override void CreateNode(int size, + ConfigNodeSubType subType, + ConfigNodeType nType, + int terminal, + [MarshalAs(UnmanagedType.LPWStr)]String text, + int textLength, + int prefixLength) + { + //Trace("CreateNode",size,subType,nType,terminal,text,textLength,prefixLength,0); + + if (nType == ConfigNodeType.Element) + { + // New Node + lastProcessed = text; + lastProcessedEndElement = false; + + if (parsing + || (bNoSearchPath && + String.Compare(text, treeRootPath[0], StringComparison.OrdinalIgnoreCase) == 0) + || (depth == searchDepth && searchDepth == pathDepth && + String.Compare(text, treeRootPath[pathDepth], StringComparison.OrdinalIgnoreCase) == 0 )) + { + parsing = true; + + ConfigNode parentNode = currentNode; + currentNode = new ConfigNode(text, parentNode); + if (rootNode == null) + rootNode = currentNode; + else + parentNode.AddChild(currentNode); + } + else + depth++; + } + else if (nType == ConfigNodeType.PCData) + { + // Data node + if (currentNode != null) + { + currentNode.Value = text; + } + } + } + + public override void CreateAttribute(int size, + ConfigNodeSubType subType, + ConfigNodeType nType, + int terminal, + [MarshalAs(UnmanagedType.LPWStr)]String text, + int textLength, + int prefixLength) + { + //Trace("CreateAttribute",size,subType,nType,terminal,text,textLength,prefixLength,0); + if (parsing) + { + // if the value of the attribute is null, the parser doesn't come back, so need to store the attribute when the + // attribute name is encountered + if (nType == ConfigNodeType.Attribute) + { + attributeEntry = currentNode.AddAttribute(text, ""); + key = text; + } + else if (nType == ConfigNodeType.PCData) + { + currentNode.ReplaceAttribute(attributeEntry, key, text); + } + else + { + String message = GetInvalidSyntaxMessage(); + // Neither Exception nor ApplicationException are the "right" exceptions here. + // Desktop throws ApplicationException for backwards compatibility. + // On Silverlight we don't have ApplicationException, so fall back to Exception. +#if FEATURE_CORECLR + throw new Exception(message); +#else + throw new ApplicationException(message); +#endif + } + } + } + +#if _DEBUG + [System.Diagnostics.Conditional("_LOGGING")] + private void Trace(String name, + int size, + ConfigNodeSubType subType, + ConfigNodeType nType, + int terminal, + [MarshalAs(UnmanagedType.LPWStr)]String text, + int textLength, + int prefixLength, int fEmpty) + { + + BCLDebug.Trace("REMOTE","Node "+name); + BCLDebug.Trace("REMOTE","text "+text); + BCLDebug.Trace("REMOTE","textLength "+textLength); + BCLDebug.Trace("REMOTE","size "+size); + BCLDebug.Trace("REMOTE","subType "+((Enum)subType).ToString()); + BCLDebug.Trace("REMOTE","nType "+((Enum)nType).ToString()); + BCLDebug.Trace("REMOTE","terminal "+terminal); + BCLDebug.Trace("REMOTE","prefixLength "+prefixLength); + BCLDebug.Trace("REMOTE","fEmpty "+fEmpty+"\n"); + } +#endif + + private String GetInvalidSyntaxMessage() + { + String lastProcessedTag = null; + + if (lastProcessed != null) + lastProcessedTag = (lastProcessedEndElement ? "</" : "<") + lastProcessed + ">"; + + return Environment.GetResourceString("XML_Syntax_InvalidSyntaxInFile", fileName, lastProcessedTag); + } + } + + // Node in Tree produced by ConfigTreeParser + internal class ConfigNode + { + String m_name = null; + String m_value = null; + ConfigNode m_parent = null; + List<ConfigNode> m_children = new List<ConfigNode>(5); + List<DictionaryEntry> m_attributes = new List<DictionaryEntry>(5); + + internal ConfigNode(String name, ConfigNode parent) + { + m_name = name; + m_parent = parent; + } + + internal String Name + { + get {return m_name;} + } + + internal String Value + { + get {return m_value;} + set {m_value = value;} + } + + internal ConfigNode Parent + { + get {return m_parent;} + } + + internal List<ConfigNode> Children + { + get {return m_children;} + } + + internal List<DictionaryEntry> Attributes + { + get {return m_attributes;} + } + + internal void AddChild(ConfigNode child) + { + child.m_parent = this; + m_children.Add(child); + } + + internal int AddAttribute(String key, String value) + { + m_attributes.Add(new DictionaryEntry(key, value)); + return m_attributes.Count-1; + } + + internal void ReplaceAttribute(int index, String key, String value) + { + m_attributes[index] = new DictionaryEntry(key, value); + } + +#if _DEBUG + [System.Diagnostics.Conditional("_LOGGING")] + internal void Trace() + { + BCLDebug.Trace("REMOTE","************ConfigNode************"); + BCLDebug.Trace("REMOTE","Name = "+m_name); + if (m_value != null) + BCLDebug.Trace("REMOTE","Value = "+m_value); + if (m_parent != null) + BCLDebug.Trace("REMOTE","Parent = "+m_parent.Name); + for (int i=0; i<m_attributes.Count; i++) + { + DictionaryEntry de = (DictionaryEntry)m_attributes[i]; + BCLDebug.Trace("REMOTE","Key = "+de.Key+" Value = "+de.Value); + } + + for (int i=0; i<m_children.Count; i++) + { + ((ConfigNode)m_children[i]).Trace(); + } + } +#endif + } +} + + + + + + |