Пример #1
0
        internal XmlConfigurationProvider(string path, XmlDocumentDecryptor xmlDocumentDecryptor, bool optional)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentException(Resources.Error_InvalidFilePath, "path");
            }

            Optional = optional;
            Path     = path;

            _xmlDocumentDecryptor = xmlDocumentDecryptor ?? XmlDocumentDecryptor.Instance;
        }
Пример #2
0
        /// <summary>
        /// Read a stream of XML values into a key/value dictionary.
        /// </summary>
        /// <param name="stream">The stream of XML data.</param>
        /// <param name="decryptor">The <see cref="XmlDocumentDecryptor"/> to use to decrypt.</param>
        /// <returns>The <see cref="IDictionary{String, String}"/> which was read from the stream.</returns>
        public static IDictionary <string, string> Read(Stream stream, XmlDocumentDecryptor decryptor)
        {
            var data = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

            var readerSettings = new XmlReaderSettings()
            {
                CloseInput       = false, // caller will close the stream
                DtdProcessing    = DtdProcessing.Prohibit,
                IgnoreComments   = true,
                IgnoreWhitespace = true
            };

            using (var reader = decryptor.CreateDecryptingXmlReader(stream, readerSettings))
            {
                var prefixStack = new Stack <string>();

                SkipUntilRootElement(reader);

                // We process the root element individually since it doesn't contribute to prefix
                ProcessAttributes(reader, prefixStack, data, AddNamePrefix);
                ProcessAttributes(reader, prefixStack, data, AddAttributePair);

                var preNodeType = reader.NodeType;
                while (reader.Read())
                {
                    switch (reader.NodeType)
                    {
                    case XmlNodeType.Element:
                        prefixStack.Push(reader.LocalName);
                        ProcessAttributes(reader, prefixStack, data, AddNamePrefix);
                        ProcessAttributes(reader, prefixStack, data, AddAttributePair);

                        // If current element is self-closing
                        if (reader.IsEmptyElement)
                        {
                            prefixStack.Pop();
                        }
                        break;

                    case XmlNodeType.EndElement:
                        if (prefixStack.Any())
                        {
                            // If this EndElement node comes right after an Element node,
                            // it means there is no text/CDATA node in current element
                            if (preNodeType == XmlNodeType.Element)
                            {
                                var key = ConfigurationPath.Combine(prefixStack.Reverse());
                                data[key] = string.Empty;
                            }

                            prefixStack.Pop();
                        }
                        break;

                    case XmlNodeType.CDATA:
                    case XmlNodeType.Text:
                    {
                        var key = ConfigurationPath.Combine(prefixStack.Reverse());
                        if (data.ContainsKey(key))
                        {
                            throw new FormatException(SR.Format(SR.Error_KeyIsDuplicated, key,
                                                                GetLineInfo(reader)));
                        }

                        data[key] = reader.Value;
                        break;
                    }

                    case XmlNodeType.XmlDeclaration:
                    case XmlNodeType.ProcessingInstruction:
                    case XmlNodeType.Comment:
                    case XmlNodeType.Whitespace:
                        // Ignore certain types of nodes
                        break;

                    default:
                        throw new FormatException(SR.Format(SR.Error_UnsupportedNodeType, reader.NodeType,
                                                            GetLineInfo(reader)));
                    }
                    preNodeType = reader.NodeType;
                    // If this element is a self-closing element,
                    // we pretend that we just processed an EndElement node
                    // because a self-closing element contains an end within itself
                    if (preNodeType == XmlNodeType.Element &&
                        reader.IsEmptyElement)
                    {
                        preNodeType = XmlNodeType.EndElement;
                    }
                }
            }
            return(data);
        }
        /// <summary>
        /// Read a stream of XML values into a key/value dictionary.
        /// </summary>
        /// <param name="stream">The stream of XML data.</param>
        /// <param name="decryptor">The <see cref="XmlDocumentDecryptor"/> to use to decrypt.</param>
        /// <returns>The <see cref="IDictionary{String, String}"/> which was read from the stream.</returns>
        public static IDictionary <string, string?> Read(Stream stream, XmlDocumentDecryptor decryptor)
        {
            var readerSettings = new XmlReaderSettings()
            {
                CloseInput       = false, // caller will close the stream
                DtdProcessing    = DtdProcessing.Prohibit,
                IgnoreComments   = true,
                IgnoreWhitespace = true
            };

            XmlConfigurationElement?root = null;

            using (XmlReader reader = decryptor.CreateDecryptingXmlReader(stream, readerSettings))
            {
                // keep track of the tree we followed to get where we are (breadcrumb style)
                var currentPath = new Stack <XmlConfigurationElement>();

                XmlNodeType preNodeType = reader.NodeType;

                while (reader.Read())
                {
                    switch (reader.NodeType)
                    {
                    case XmlNodeType.Element:
                        var element = new XmlConfigurationElement(reader.LocalName, GetName(reader));

                        if (currentPath.Count == 0)
                        {
                            root = element;
                        }
                        else
                        {
                            var parent = currentPath.Peek();

                            // If parent already has a dictionary of children, update the collection accordingly
                            if (parent.ChildrenBySiblingName != null)
                            {
                                // check if this element has appeared before, elements are considered siblings if their SiblingName properties match
                                if (!parent.ChildrenBySiblingName.TryGetValue(element.SiblingName, out var siblings))
                                {
                                    siblings = new List <XmlConfigurationElement>();
                                    parent.ChildrenBySiblingName.Add(element.SiblingName, siblings);
                                }
                                siblings.Add(element);
                            }
                            else
                            {
                                // Performance optimization: parents with a single child don't even initialize a dictionary
                                if (parent.SingleChild == null)
                                {
                                    parent.SingleChild = element;
                                }
                                else
                                {
                                    // If we encounter a second child after assigning "SingleChild", we clear SingleChild and initialize the dictionary
                                    var children = new Dictionary <string, List <XmlConfigurationElement> >(StringComparer.OrdinalIgnoreCase);

                                    // Special case: the first and second child have the same sibling name
                                    if (string.Equals(parent.SingleChild.SiblingName, element.SiblingName, StringComparison.OrdinalIgnoreCase))
                                    {
                                        children.Add(element.SiblingName, new List <XmlConfigurationElement>
                                        {
                                            parent.SingleChild,
                                            element
                                        });
                                    }
                                    else
                                    {
                                        children.Add(parent.SingleChild.SiblingName, new List <XmlConfigurationElement> {
                                            parent.SingleChild
                                        });
                                        children.Add(element.SiblingName, new List <XmlConfigurationElement> {
                                            element
                                        });
                                    }

                                    parent.ChildrenBySiblingName = children;
                                    parent.SingleChild           = null;
                                }
                            }
                        }

                        currentPath.Push(element);

                        ReadAttributes(reader, element);

                        // If current element is self-closing
                        if (reader.IsEmptyElement)
                        {
                            currentPath.Pop();
                        }
                        break;

                    case XmlNodeType.EndElement:
                        if (currentPath.Count != 0)
                        {
                            XmlConfigurationElement parent = currentPath.Pop();

                            // If this EndElement node comes right after an Element node,
                            // it means there is no text/CDATA node in current element
                            if (preNodeType == XmlNodeType.Element)
                            {
                                var lineInfo     = reader as IXmlLineInfo;
                                var lineNumber   = lineInfo?.LineNumber;
                                var linePosition = lineInfo?.LinePosition;
                                parent.TextContent = new XmlConfigurationElementTextContent(string.Empty, lineNumber, linePosition);
                            }
                        }
                        break;

                    case XmlNodeType.CDATA:
                    case XmlNodeType.Text:
                        if (currentPath.Count != 0)
                        {
                            var lineInfo     = reader as IXmlLineInfo;
                            var lineNumber   = lineInfo?.LineNumber;
                            var linePosition = lineInfo?.LinePosition;

                            XmlConfigurationElement parent = currentPath.Peek();

                            parent.TextContent = new XmlConfigurationElementTextContent(reader.Value, lineNumber, linePosition);
                        }
                        break;

                    case XmlNodeType.XmlDeclaration:
                    case XmlNodeType.ProcessingInstruction:
                    case XmlNodeType.Comment:
                    case XmlNodeType.Whitespace:
                        // Ignore certain types of nodes
                        break;

                    default:
                        throw new FormatException(SR.Format(SR.Error_UnsupportedNodeType, reader.NodeType, GetLineInfo(reader)));
                    }
                    preNodeType = reader.NodeType;

                    // If this element is a self-closing element,
                    // we pretend that we just processed an EndElement node
                    // because a self-closing element contains an end within itself
                    if (preNodeType == XmlNodeType.Element && reader.IsEmptyElement)
                    {
                        preNodeType = XmlNodeType.EndElement;
                    }
                }
            }

            return(ProvideConfiguration(root));
        }
Пример #4
0
 internal XmlConfigurationProvider(string path, XmlDocumentDecryptor xmlDocumentDecryptor)
     : this(path, xmlDocumentDecryptor, optional : false)
 {
 }