Exemple #1
0
        internal bool SkipChildElementsAndCopyOuterXmlToNextElement(XmlUtilWriter utilWriter)
        {
            bool isEmptyElement = this._reader.IsEmptyElement;
            int  lineNumber     = this._reader.LineNumber;

            this.CopyXmlNode(utilWriter);
            if (!isEmptyElement)
            {
                while (this._reader.NodeType != XmlNodeType.EndElement)
                {
                    if (this._reader.NodeType == XmlNodeType.Element)
                    {
                        this._reader.Skip();
                        if (this._reader.NodeType == XmlNodeType.Whitespace)
                        {
                            this._reader.Skip();
                        }
                    }
                    else
                    {
                        this.CopyXmlNode(utilWriter);
                    }
                }
                if (this._reader.LineNumber != lineNumber)
                {
                    utilWriter.AppendSpacesToLinePosition(this.TrueLinePosition);
                }
                this.CopyXmlNode(utilWriter);
            }
            return(this.CopyReaderToNextElement(utilWriter, true));
        }
Exemple #2
0
        //
        // Copy a configuration section to a string, and advance the reader.
        //
        internal string CopySection()
        {
            ResetCachedStringWriter();

            // Preserve whitespace for sections for backcompat
            WhitespaceHandling originalHandling = _reader.WhitespaceHandling;

            _reader.WhitespaceHandling = WhitespaceHandling.All;

            // Create string writer to write to
            XmlUtilWriter utilWriter = new XmlUtilWriter(_cachedStringWriter, false);

            // Copy the element
            CopyElement(utilWriter);

            // Reset whitespace handling
            _reader.WhitespaceHandling = originalHandling;

            if ((originalHandling == WhitespaceHandling.None) &&
                (Reader.NodeType == XmlNodeType.Whitespace))
            {
                // If we were previously suppose to skip whitespace, and now we
                // are at it, then lets jump to the next item
                _reader.Read();
            }

            utilWriter.Flush();
            string s = ((StringWriter)utilWriter.Writer).ToString();

            return(s);
        }
Exemple #3
0
        //
        // Copy an XML element, then continue copying until we've hit the next element
        // or exited this depth.
        //
        internal bool CopyOuterXmlToNextElement(XmlUtilWriter utilWriter, bool limitDepth)
        {
            CopyElement(utilWriter);

            // Copy until reaching the next element, or if limitDepth == true until we've exited this depth.
            return(CopyReaderToNextElement(utilWriter, limitDepth));
        }
Exemple #4
0
        internal bool CopyReaderToNextElement(XmlUtilWriter utilWriter, bool limitDepth)
        {
            int  depth;
            bool flag = true;

            if (limitDepth)
            {
                if (this._reader.NodeType == XmlNodeType.EndElement)
                {
                    return(true);
                }
                depth = this._reader.Depth;
            }
            else
            {
                depth = 0;
            }
Label_0026:
            if ((this._reader.NodeType != XmlNodeType.Element) && (this._reader.Depth >= depth))
            {
                flag = this.CopyXmlNode(utilWriter);
                if (flag)
                {
                    goto Label_0026;
                }
            }
            return(flag);
        }
Exemple #5
0
        // Skip over the current element and copy until the next element.
        // This function removes the one blank line that would otherwise
        // be inserted by simply skipping and copying to the next element
        // in a situation like this:
        //
        //      <!-- end of previous configSection -->
        //      <configSectionToDelete>
        //          <content />
        //          <moreContent />
        //      </configSectionToDelete>
        //      <!-- end of configSectionToDelete -->
        //      <nextConfigSection />
        internal bool SkipAndCopyReaderToNextElement(XmlUtilWriter utilWriter, bool limitDepth)
        {
            Debug.Assert(Reader.NodeType == XmlNodeType.Element, "_reader.NodeType == XmlNodeType.Element");

            // If the last line before the element is not blank, then we do not have to
            // remove the blank line.
            if (!utilWriter.IsLastLineBlank)
            {
                Reader.Skip();
                return(CopyReaderToNextElement(utilWriter, limitDepth));
            }

            // Set the depth if we limit copying to this depth
            int depth = limitDepth ? Reader.Depth : 0;

            // Skip over the element
            Reader.Skip();

            int lineNumberOfEndElement = Reader.LineNumber;

            // Read until we hit a a non-whitespace node or reach the end
            while (!Reader.EOF)
            {
                if (Reader.NodeType != XmlNodeType.Whitespace)
                {
                    //
                    // If the next non-whitepace node is on another line,
                    // seek back to the beginning of the current blank line,
                    // skip a blank line of whitespace, and copy the remaining whitespace.
                    //
                    if (Reader.LineNumber > lineNumberOfEndElement)
                    {
                        utilWriter.SeekToLineStart();
                        utilWriter.AppendWhiteSpace(lineNumberOfEndElement + 1, 1, LineNumber, TrueLinePosition);
                    }

                    break;
                }

                Reader.Read();
            }

            // Copy nodes until we've reached the desired depth, or until we hit an element.
            while (!Reader.EOF)
            {
                if (Reader.NodeType == XmlNodeType.Element)
                {
                    break;
                }

                if (Reader.Depth < depth)
                {
                    break;
                }

                CopyXmlNode(utilWriter);
            }

            return(!Reader.EOF);
        }
Exemple #6
0
        //
        // Copy or replace an element node.
        // If the element is an empty element, replace it with a formatted start element if either:
        //   * The contents of the start element string need updating.
        //   * The element needs to contain child elements.
        //
        // If the element is empty and is replaced with a start/end element pair, return a
        // end element string with whitespace formatting; otherwise return null.
        //
        internal string UpdateStartElement(XmlUtilWriter utilWriter, string updatedStartElement, bool needsChildren,
                                           int linePosition, int indent)
        {
            Debug.Assert(Reader.NodeType == XmlNodeType.Element, "_reader.NodeType == NodeType.Element");

            string endElement      = null;
            bool   needsEndElement = false;

            string elementName = Reader.Name;

            // If the element is empty, determine if a new end element is needed.
            if (Reader.IsEmptyElement)
            {
                if ((updatedStartElement == null) && needsChildren)
                {
                    updatedStartElement = RetrieveFullOpenElementTag();
                }

                needsEndElement = updatedStartElement != null;
            }

            if (updatedStartElement == null)
            {
                // If no changes to the start element are required, just copy it.
                CopyXmlNode(utilWriter);
            }
            else
            {
                // Format a new start element/end element pair
                string updatedEndElement = "</" + elementName + ">";
                string updatedElement    = updatedStartElement + updatedEndElement;
                string formattedElement  = FormatXmlElement(updatedElement, linePosition, indent, true);

                // Get the start and end element strings from the formatted element.
                int    iEndElement = formattedElement.LastIndexOf('\n') + 1;
                string startElement;
                if (needsEndElement)
                {
                    endElement = formattedElement.Substring(iEndElement);

                    // Include a newline in the start element as we are expanding an empty element.
                    startElement = formattedElement.Substring(0, iEndElement);
                }
                else
                {
                    // Omit the newline from the start element.
                    startElement = formattedElement.Substring(0, iEndElement - 2);
                }

                // Write the new start element.
                utilWriter.Write(startElement);

                // Skip over the existing start element.
                Reader.Read();
            }

            return(endElement);
        }
Exemple #7
0
        //
        // Copy an XML element but skip all its child elements, then continue copying until we've hit the next element.
        //
        internal bool SkipChildElementsAndCopyOuterXmlToNextElement(XmlUtilWriter utilWriter)
        {
            bool isEmptyElement = _reader.IsEmptyElement;
            int  startingLine   = _reader.LineNumber;

#if DBG
            int depth = _reader.Depth;
#endif

            Debug.Assert(_reader.NodeType == XmlNodeType.Element, "_reader.NodeType == XmlNodeType.Element");

            CopyXmlNode(utilWriter);

            // See if we need to skip any child element
            if (!isEmptyElement)
            {
                while (_reader.NodeType != XmlNodeType.EndElement)
                {
                    // Skip all the inner child elements
                    if (_reader.NodeType == XmlNodeType.Element)
                    {
                        _reader.Skip();

                        // We need to skip all the whitespaces following a skipped element.
                        // - If the whitespaces don't contain /r/n, then it's okay to skip them
                        //   as part of the element.
                        // - If the whitespaces contain /r/n, not skipping them will result
                        //   in a redundant emtpy line being copied.
                        if (_reader.NodeType == XmlNodeType.Whitespace)
                        {
                            _reader.Skip();
                        }
                    }
                    else
                    {
                        // We want to preserve other content, e.g. comments.
                        CopyXmlNode(utilWriter);
                    }
                }

                if (_reader.LineNumber != startingLine)
                {
                    // The whitespace in front of the EndElement was skipped above.
                    // We need to append spaces to compensate for that.
                    utilWriter.AppendSpacesToLinePosition(TrueLinePosition);
                }


#if DBG
                Debug.Assert(_reader.Depth == depth, "We should be at the same depth as the opening Element");
#endif

                // Copy the end element.
                CopyXmlNode(utilWriter);
            }

            return(CopyReaderToNextElement(utilWriter, true));
        }
Exemple #8
0
 internal StreamWriterCheckpoint(XmlUtilWriter writer)
 {
     writer.Flush();
     this._lineNumber      = writer._lineNumber;
     this._linePosition    = writer._linePosition;
     this._isLastLineBlank = writer._isLastLineBlank;
     writer._baseStream.Flush();
     this._streamPosition = writer._baseStream.Position;
     this._streamLength   = writer._baseStream.Length;
 }
Exemple #9
0
        private void CopyElement(XmlUtilWriter utilWriter)
        {
            int  depth          = this._reader.Depth;
            bool isEmptyElement = this._reader.IsEmptyElement;

            this.CopyXmlNode(utilWriter);
            while (this._reader.Depth > depth)
            {
                this.CopyXmlNode(utilWriter);
            }
            if (!isEmptyElement)
            {
                this.CopyXmlNode(utilWriter);
            }
        }
Exemple #10
0
        internal string CopySection()
        {
            this.ResetCachedStringWriter();
            WhitespaceHandling whitespaceHandling = this._reader.WhitespaceHandling;

            this._reader.WhitespaceHandling = WhitespaceHandling.All;
            XmlUtilWriter utilWriter = new XmlUtilWriter(this._cachedStringWriter, false);

            this.CopyElement(utilWriter);
            this._reader.WhitespaceHandling = whitespaceHandling;
            if ((whitespaceHandling == WhitespaceHandling.None) && (this.Reader.NodeType == XmlNodeType.Whitespace))
            {
                this._reader.Read();
            }
            utilWriter.Flush();
            return(((StringWriter)utilWriter.Writer).ToString());
        }
Exemple #11
0
        internal bool SkipAndCopyReaderToNextElement(XmlUtilWriter utilWriter, bool limitDepth)
        {
            int depth;

            if (!utilWriter.IsLastLineBlank)
            {
                this._reader.Skip();
                return(this.CopyReaderToNextElement(utilWriter, limitDepth));
            }
            if (limitDepth)
            {
                depth = this._reader.Depth;
            }
            else
            {
                depth = 0;
            }
            this._reader.Skip();
            int lineNumber = this._reader.LineNumber;

            while (!this._reader.EOF)
            {
                if (this._reader.NodeType != XmlNodeType.Whitespace)
                {
                    if (this._reader.LineNumber > lineNumber)
                    {
                        utilWriter.SeekToLineStart();
                        utilWriter.AppendWhiteSpace(lineNumber + 1, 1, this.LineNumber, this.TrueLinePosition);
                    }
                    break;
                }
                this._reader.Read();
            }
            while (!this._reader.EOF)
            {
                if ((this._reader.NodeType == XmlNodeType.Element) || (this._reader.Depth < depth))
                {
                    break;
                }
                this.CopyXmlNode(utilWriter);
            }
            return(!this._reader.EOF);
        }
Exemple #12
0
        //
        // Copy the reader until we hit an element, or we've exited the current depth.
        //
        internal bool CopyReaderToNextElement(XmlUtilWriter utilWriter, bool limitDepth)
        {
            bool moreToRead = true;

            // Set the depth if we limit copying to this depth
            int depth;

            if (limitDepth)
            {
                // there is nothing in the element
                if (_reader.NodeType == XmlNodeType.EndElement)
                {
                    return(true);
                }

                depth = _reader.Depth;
            }
            else
            {
                depth = 0;
            }

            // Copy nodes until we've reached the desired depth, or until we hit an element.
            do
            {
                if (_reader.NodeType == XmlNodeType.Element)
                {
                    break;
                }

                if (_reader.Depth < depth)
                {
                    break;
                }

                moreToRead = CopyXmlNode(utilWriter);
            } while (moreToRead);

            return(moreToRead);
        }
Exemple #13
0
        //
        // Copy an XML element and its children, up to and including the end element.
        //
        private void CopyElement(XmlUtilWriter utilWriter)
        {
            Debug.Assert(_reader.NodeType == XmlNodeType.Element, "_reader.NodeType== XmlNodeType.Element");

            int  depth          = _reader.Depth;
            bool isEmptyElement = _reader.IsEmptyElement;

            // Copy current node
            CopyXmlNode(utilWriter);

            // Copy nodes while the depth is greater than the current depth.
            while (_reader.Depth > depth)
            {
                CopyXmlNode(utilWriter);
            }

            // Copy the end element.
            if (!isEmptyElement)
            {
                CopyXmlNode(utilWriter);
            }
        }
Exemple #14
0
        internal string UpdateStartElement(XmlUtilWriter utilWriter, string updatedStartElement, bool needsChildren, int linePosition, int indent)
        {
            string str = null;
            string str6;
            bool   flag = false;
            string name = this._reader.Name;

            if (this._reader.IsEmptyElement)
            {
                if ((updatedStartElement == null) && needsChildren)
                {
                    updatedStartElement = this.RetrieveFullOpenElementTag();
                }
                flag = updatedStartElement != null;
            }
            if (updatedStartElement == null)
            {
                this.CopyXmlNode(utilWriter);
                return(str);
            }
            string str5       = FormatXmlElement(updatedStartElement + ("</" + name + ">"), linePosition, indent, true);
            int    startIndex = str5.LastIndexOf('\n') + 1;

            if (flag)
            {
                str  = str5.Substring(startIndex);
                str6 = str5.Substring(0, startIndex);
            }
            else
            {
                str6 = str5.Substring(0, startIndex - 2);
            }
            utilWriter.Write(str6);
            this._reader.Read();
            return(str);
        }
Exemple #15
0
            internal StreamWriterCheckpoint(XmlUtilWriter writer)
            {
                writer.Flush();
                _lineNumber = writer.LineNumber;
                _linePosition = writer.LinePosition;
                _isLastLineBlank = writer.IsLastLineBlank;

                writer._baseStream.Flush();
                _streamPosition = writer._baseStream.Position;
                _streamLength = writer._baseStream.Length;
            }
        private void CopyConfigSource(XmlUtilWriter utilWriter, string updatedXml, string configSourceStreamName, byte[] buffer) {
            // only copy the byte order mark if it exists in the current web.config
            byte[] preamble;
            using (Stream stream = new MemoryStream(buffer)) {
                using (XmlUtil xmlUtil = new XmlUtil(stream, configSourceStreamName, true)) {
                    preamble = ConfigStreamInfo.StreamEncoding.GetPreamble();
                }
            }

            CheckPreamble(preamble, utilWriter, buffer);

            using (Stream stream = new MemoryStream(buffer)) {
                using (XmlUtil xmlUtil = new XmlUtil(stream, configSourceStreamName, false)) {
                    XmlTextReader reader = xmlUtil.Reader;

                    // copy up to the first element
                    reader.WhitespaceHandling = WhitespaceHandling.All;
                    reader.Read();

                    // determine the indent to use for the element
                    int indent = DEFAULT_INDENT;
                    int linePosition = 1;
                    bool hasElement = xmlUtil.CopyReaderToNextElement(utilWriter, false);
                    if (hasElement) {
                        // find the indent of the first attribute, if any
                        int lineNumber = reader.LineNumber;
                        linePosition = reader.LinePosition - 1;
                        int attributeIndent = 0;
                        while (reader.MoveToNextAttribute()) {
                            if (reader.LineNumber > lineNumber) {
                                attributeIndent =   reader.LinePosition - linePosition;
                                break;
                            }
                        }

                        // find the indent of the first sub element, if any
                        int elementIndent = 0;
                        reader.Read();
                        while (reader.Depth >= 1) {
                            if (reader.NodeType == XmlNodeType.Element) {
                                elementIndent = (reader.LinePosition - 1) - linePosition;
                                break;
                            }

                            reader.Read();
                        }

                        if (elementIndent > 0) {
                            indent = elementIndent;
                        }
                        else if (attributeIndent > 0) {
                            indent = attributeIndent;
                        }
                    }

                    // Write the config source
                    string formattedXml = XmlUtil.FormatXmlElement(updatedXml, linePosition, indent, true);
                    utilWriter.Write(formattedXml);

                    // Copy remaining contents
                    if (hasElement) {
                        // Skip over the existing element
                        while (reader.Depth > 0) {
                            reader.Read();
                        }

                        if (reader.IsEmptyElement || reader.NodeType == XmlNodeType.EndElement) {
                            reader.Read();
                        }

                        // Copy remainder of file
                        while (xmlUtil.CopyXmlNode(utilWriter)) {
                        }
                    }
                }
            }
        }
        private void WriteSectionUpdate(XmlUtilWriter utilWriter, DefinitionUpdate update, int linePosition, int indent, bool skipFirstIndent) {
            ConfigurationSection configSection = (ConfigurationSection) update.SectionRecord.Result;
            string updatedXml;

            if (!String.IsNullOrEmpty(configSection.SectionInformation.ConfigSource)) {
                updatedXml = string.Format(CultureInfo.InvariantCulture, FORMAT_SECTION_CONFIGSOURCE, configSection.SectionInformation.Name, configSection.SectionInformation.ConfigSource);
            }
            else {
                updatedXml = update.UpdatedXml;
            }

            string formattedXml = XmlUtil.FormatXmlElement(updatedXml, linePosition, indent, skipFirstIndent);
            utilWriter.Write(formattedXml);
        }
        private bool CopyConfigDeclarationsRecursive(
                SectionUpdates declarationUpdates, XmlUtil xmlUtil, XmlUtilWriter utilWriter, string group,
                int parentLinePosition, int parentIndent) {

            bool wroteASection = false;
            XmlTextReader reader = xmlUtil.Reader;
            int linePosition;
            int indent;
            int startingLinePosition;

            indent = UpdateIndent(parentIndent, xmlUtil, utilWriter, parentLinePosition);

            if (reader.NodeType == XmlNodeType.Element) {
                linePosition = xmlUtil.TrueLinePosition;
                startingLinePosition = linePosition;
            }
            else if (reader.NodeType == XmlNodeType.EndElement) {
                linePosition = parentLinePosition + indent;
                if (utilWriter.IsLastLineBlank) {
                    startingLinePosition = xmlUtil.TrueLinePosition;
                }
                else {
                    startingLinePosition = parentLinePosition;
                }
            }
            else {
                linePosition = parentLinePosition + indent;
                startingLinePosition = 0;
            }

            //
            // Write any new section declarations that apply to this group
            //
            if (declarationUpdates != null) {
                string[] movedSectionNames = declarationUpdates.GetMovedSectionNames();
                if (movedSectionNames != null) {
                    if (!utilWriter.IsLastLineBlank) {
                        utilWriter.AppendNewLine();
                    }

                    foreach (string configKey in movedSectionNames) {
                        DeclarationUpdate sectionUpdate = declarationUpdates.GetDeclarationUpdate(configKey);
                        Debug.Assert(!IsImplicitSection(configKey), "We should never write out an implicit section");

                        // Write the one line section declaration.
                        utilWriter.AppendSpacesToLinePosition(linePosition);
                        utilWriter.Write(sectionUpdate.UpdatedXml);
                        utilWriter.AppendNewLine();

                        wroteASection = true;
                    }

                    // Restore the whitespace we used for the first element, which is either a start or an end element.
                    utilWriter.AppendSpacesToLinePosition(startingLinePosition);
                }
            }

            if (reader.NodeType == XmlNodeType.Element) {
                //
                // For each element at this depth, either:
                // - Write the element verbatim and recurse due to a group hierarchy element.
                // - Write the element verbatim because it is unchanged
                // - Write the updated XML for the section.
                // - Skip it because the section has been removed.
                //
                int depth = reader.Depth;
                while (reader.Depth == depth) {
                    bool                recurse = false;
                    DeclarationUpdate   sectionUpdate = null;
                    DeclarationUpdate   groupUpdate = null;
                    SectionUpdates      declarationUpdatesChild = null;
                    SectionUpdates      recurseDeclarationUpdates = declarationUpdates;
                    string              recurseGroup = group;

                    // update the lineposition and indent for each element
                    indent = UpdateIndent(indent, xmlUtil, utilWriter, parentLinePosition);
                    linePosition = xmlUtil.TrueLinePosition;

                    string directive = reader.Name;
                    string name = reader.GetAttribute(KEYWORD_SECTIONGROUP_NAME);
                    string configKey = CombineConfigKey(group, name);
                    if (directive == KEYWORD_SECTIONGROUP) {
                        // it's a group - get the updates for children
                        declarationUpdatesChild = declarationUpdates.GetSectionUpdatesForGroup(name);
                        if (declarationUpdatesChild != null) {
                            // get the group update
                            groupUpdate = declarationUpdatesChild.GetSectionGroupUpdate();

                            // recurse if there are more sections to copy
                            if (declarationUpdatesChild.HasUnretrievedSections()) {
                                recurse = true;
                                recurseGroup = configKey;
                                recurseDeclarationUpdates = declarationUpdatesChild;
                            }
                        }
                    }
                    else {
                        // it is a section - get the update
                        Debug.Assert(!IsImplicitSection(configKey), "We should never write out an implicit section");
                        sectionUpdate = declarationUpdates.GetDeclarationUpdate(configKey);
                    }

                    bool writeGroupUpdate = (groupUpdate != null && groupUpdate.UpdatedXml != null);
                    if (recurse) {
#if DBG
                        string startElementName = reader.Name;
#endif

                        // create a checkpoint that we can revert to if no children are written
                        object checkpoint = utilWriter.CreateStreamCheckpoint();
                        string closingElement = null;

                        // Copy this element node and up to the first subelement
                        if (writeGroupUpdate) {
                            // replace the element with the updated xml
                            utilWriter.Write(groupUpdate.UpdatedXml);

                            // skip over the start element
                            reader.Read();
                        }
                        else {
                            closingElement= xmlUtil.UpdateStartElement(utilWriter, null, true, linePosition, indent);
                        }

                        if (closingElement == null) {
                            // Only if there is a closing element should
                            // we move to it
                            xmlUtil.CopyReaderToNextElement(utilWriter, true);
                        }

                        // Recurse
                        bool recurseWroteASection = CopyConfigDeclarationsRecursive(
                                recurseDeclarationUpdates, xmlUtil, utilWriter, recurseGroup, linePosition, indent);

                        if (closingElement != null) {
                            utilWriter.AppendSpacesToLinePosition(linePosition);
                            utilWriter.Write(closingElement);

                            // Since we already got to </configSections> in reader, lets
                            // indent so we can copy the element in the right place
                            utilWriter.AppendSpacesToLinePosition(parentLinePosition);
                        } else {
                            // Copy the end element
                            xmlUtil.CopyXmlNode(utilWriter);
                        }

                        if (recurseWroteASection || writeGroupUpdate) {
                            wroteASection = true;
                        }
                        else {
                            // back out the change
                            utilWriter.RestoreStreamCheckpoint(checkpoint);
                        }

                        // Copy up to the next element, or exit this level.
                        xmlUtil.CopyReaderToNextElement(utilWriter, true);
                    }
                    else {
                        bool    skip;
                        bool    skipChildElements = false;
                        if (sectionUpdate == null) {
                            skip = true;
                            if (writeGroupUpdate) {
                                // Insert an empty <sectionGroup type="typename" > node, to introduce the type
                                wroteASection = true;
                                utilWriter.Write(groupUpdate.UpdatedXml);
                                utilWriter.AppendNewLine();
                                utilWriter.AppendSpacesToLinePosition(linePosition);
                                utilWriter.Write(FORMAT_SECTIONGROUP_ENDELEMENT);
                                utilWriter.AppendNewLine();
                                utilWriter.AppendSpacesToLinePosition(linePosition);
                            }
                            else if (groupUpdate != null) {
                                // VSWhidbey 522450
                                // If groupUpdate exists, that means we've decided in GetConfigDeclarationUpdates
                                // that the section group should stay in the file.
                                Debug.Assert(groupUpdate.UpdatedXml == null, "groupUpdate.UpdatedXml == null");
                                Debug.Assert(!declarationUpdatesChild.HasUnretrievedSections(),
                                    "If the group has any unretrieved section, we should have chosen the recursive code path above.");

                                wroteASection = true;
                                skip = false;

                                // We should skip all the child sections.  If we indeed need to keep any child
                                // section, we should have chosen the recursive code path above.
                                skipChildElements = true;
                            }
                        }
                        else {
                            wroteASection = true;
                            if (sectionUpdate.UpdatedXml == null) {
                                skip = false;
                            }
                            else {
                                skip = true;

                                // Write the updated XML on a single line
                                utilWriter.Write(sectionUpdate.UpdatedXml);
                            }
                        }

                        if (skip) {
                            //
                            // Skip over the existing element, then
                            // copy up to the next element, or exit this level.
                            //
                            xmlUtil.SkipAndCopyReaderToNextElement(utilWriter, true);
                        }
                        else {
                            if (skipChildElements) {
                                xmlUtil.SkipChildElementsAndCopyOuterXmlToNextElement(utilWriter);
                            }
                            else {
                                // Copy this entire contents of this element and then to the next element, or exit this level.
                                xmlUtil.CopyOuterXmlToNextElement(utilWriter, true);
                            }
                        }
                    }
                }
            }

            return wroteASection;
        }
        //
        // Calculate a new indent based on the position of the parent element and the current node.
        //
        private int UpdateIndent(int oldIndent, XmlUtil xmlUtil, XmlUtilWriter utilWriter, int parentLinePosition) {
            int indent = oldIndent;
            if (xmlUtil.Reader.NodeType == XmlNodeType.Element && utilWriter.IsLastLineBlank) {
                int childLinePosition = xmlUtil.TrueLinePosition;
                if (parentLinePosition < childLinePosition && childLinePosition <= parentLinePosition + MAX_INDENT) {
                    indent = childLinePosition - parentLinePosition;
                }
            }

            return indent;
        }
        // Recursively write new sections for each section group.
        private bool WriteNewConfigDefinitionsRecursive(XmlUtilWriter utilWriter, SectionUpdates sectionUpdates, int linePosition, int indent, bool skipFirstIndent) {
            bool wroteASection = false;

            string[] movedSectionNames = sectionUpdates.GetMovedSectionNames();
            if (movedSectionNames != null) {
                wroteASection = true;
                foreach (string configKey in movedSectionNames) {
                    DefinitionUpdate update = sectionUpdates.GetDefinitionUpdate(configKey);
                    WriteSectionUpdate(utilWriter, update, linePosition, indent, skipFirstIndent);
                    utilWriter.AppendNewLine();
                    skipFirstIndent = false;
                }
            }

            string[] newGroupNames = sectionUpdates.GetNewGroupNames();
            if (newGroupNames != null) {
                foreach (string group in newGroupNames) {

                    if (TargetFramework != null) {
                        ConfigurationSectionGroup g = GetSectionGroup(group);
                        if (g != null && !g.ShouldSerializeSectionGroupInTargetVersion(TargetFramework)){
                            sectionUpdates.MarkGroupAsRetrieved(group);
                            continue;
                        }
                    }

                    if (!skipFirstIndent) {
                        utilWriter.AppendSpacesToLinePosition(linePosition);
                    }
                    skipFirstIndent = false;

                    utilWriter.Write("<" + group + ">\r\n");
                    bool recurseWroteASection = WriteNewConfigDefinitionsRecursive(
                            utilWriter, sectionUpdates.GetSectionUpdatesForGroup(group), linePosition + indent, indent, false);

                    if (recurseWroteASection) {
                        wroteASection = true;
                    }

                    utilWriter.AppendSpacesToLinePosition(linePosition);
                    utilWriter.Write("</" + group + ">\r\n");
                }
            }

            sectionUpdates.IsNew = false;

            return wroteASection;
        }
        private void WriteUnwrittenConfigDeclarationsRecursive(SectionUpdates declarationUpdates, XmlUtilWriter utilWriter, int linePosition, int indent, bool skipFirstIndent) {
            string[] unretrievedSectionNames = declarationUpdates.GetUnretrievedSectionNames();
            if (unretrievedSectionNames != null) {
                foreach (string configKey in unretrievedSectionNames) {
                    Debug.Assert(!IsImplicitSection(configKey), "We should never write out an implicit section");
                    if (!skipFirstIndent) {
                        utilWriter.AppendSpacesToLinePosition(linePosition);
                    }
                    skipFirstIndent = false;

                    DeclarationUpdate update = declarationUpdates.GetDeclarationUpdate(configKey);
                    if (update != null && !string.IsNullOrEmpty(update.UpdatedXml)) {
                        utilWriter.Write(update.UpdatedXml);
                        utilWriter.AppendNewLine();
                    }
                }
            }

            string[] unretrievedGroupNames = declarationUpdates.GetUnretrievedGroupNames();
            if (unretrievedGroupNames != null) {
                foreach (string group in unretrievedGroupNames) {
                    if (TargetFramework != null) {
                        ConfigurationSectionGroup g = GetSectionGroup(group);
                        if (g != null && !g.ShouldSerializeSectionGroupInTargetVersion(TargetFramework)){
                            declarationUpdates.MarkGroupAsRetrieved(group);
                            continue;
                        }
                    }
                    if (!skipFirstIndent) {
                        utilWriter.AppendSpacesToLinePosition(linePosition);
                    }
                    skipFirstIndent = false;

                    SectionUpdates declarationUpdatesChild = declarationUpdates.GetSectionUpdatesForGroup(group);
                    DeclarationUpdate groupUpdate = declarationUpdatesChild.GetSectionGroupUpdate();
                    if (groupUpdate == null) {
                        utilWriter.Write("<sectionGroup name=\"" + group + "\">");
                    }
                    else {
                        utilWriter.Write(groupUpdate.UpdatedXml);
                    }
                    utilWriter.AppendNewLine();

                    WriteUnwrittenConfigDeclarationsRecursive(declarationUpdatesChild, utilWriter, linePosition + indent, indent, false);
                    utilWriter.AppendSpacesToLinePosition(linePosition);
                    utilWriter.Write("</sectionGroup>\r\n");
                }
            }
        }
        private void WriteNewConfigDeclarations(SectionUpdates declarationUpdates, XmlUtilWriter utilWriter, int linePosition, int indent, bool skipFirstIndent) {
            if (!skipFirstIndent) {
                utilWriter.AppendSpacesToLinePosition(linePosition);
            }

            utilWriter.Write("<configSections>\r\n");
            WriteUnwrittenConfigDeclarations(declarationUpdates, utilWriter, linePosition + indent, indent, false);
            utilWriter.AppendSpacesToLinePosition(linePosition);
            utilWriter.Write("</configSections>\r\n");

            if (skipFirstIndent) {
                utilWriter.AppendSpacesToLinePosition(linePosition);
            }
        }
        //
        // Update the config file with the changes in each ConfigurationSection
        //
        internal void SaveAs(string filename, ConfigurationSaveMode saveMode, bool forceUpdateAll) {

            // Get the updates.
            SectionUpdates declarationUpdates = GetConfigDeclarationUpdates(saveMode, forceUpdateAll);

            ConfigDefinitionUpdates definitionUpdates;
            ArrayList configSourceUpdates;
            bool checkedConfigForUpdates = false;
            bool requireUpdates = (filename != null);
            GetConfigDefinitionUpdates(requireUpdates, saveMode, forceUpdateAll, out definitionUpdates, out configSourceUpdates);

            if (filename != null) {
                Debug.Assert(filename.Length > 0, "The caller should make sure that filename is not empty");

                //
                // Verify that the filename is not being used.
                //
                // Note that if we are using a remote host, all the streamName's in _streamInfoUpdates
                // are actually fullpaths on the remote machine.  In this case there is no way to
                // detect if we have a conflict or not.
                if (!Host.IsRemote && _streamInfoUpdates.Contains(filename)) {
                    throw new ArgumentException(SR.GetString(SR.Filename_in_SaveAs_is_used_already, filename));
                }

                //
                // If there was no config file for this config record,
                // record the new stream name and version.
                //
                if (String.IsNullOrEmpty(ConfigStreamInfo.StreamName)) {
                    StreamInfo streamInfo = new StreamInfo(null, null, filename);
                    _streamInfoUpdates.Add(filename, streamInfo);

                    ConfigStreamInfo.StreamName = filename;
                    ConfigStreamInfo.StreamVersion = MonitorStream(null, null, ConfigStreamInfo.StreamName);
                }

                //
                // Update the host to redirect filenames
                //
                UpdateConfigHost.AddStreamname(ConfigStreamInfo.StreamName, filename, Host.IsRemote);

                // Redirect also all configSource filenames
                foreach (StreamInfo streamInfo in _streamInfoUpdates.Values) {
                    if (!String.IsNullOrEmpty(streamInfo.SectionName)) {
                        // Get the new configSource streamName based on the new filename path
                        string newStreamName = InternalConfigHost.StaticGetStreamNameForConfigSource(
                            filename, streamInfo.ConfigSource);

                    // Ask UpdateConfigHost to intercept them.
                    UpdateConfigHost.AddStreamname(streamInfo.StreamName, newStreamName, Host.IsRemote);
                    }
                }

            }

            if (!requireUpdates) {
                // Check if there are any updates needed for the
                // configuration record itself.
                requireUpdates = RecordItselfRequiresUpdates;
            }

            if (declarationUpdates != null || definitionUpdates != null || requireUpdates) {
                // Copy the input stream before opening the output stream.
                byte[] readBuffer = null;
                Encoding encoding = null;
                if (ConfigStreamInfo.HasStream) {
                    using (Stream streamRead = Host.OpenStreamForRead(ConfigStreamInfo.StreamName)) {
                        if (streamRead == null) {
                            throw new ConfigurationErrorsException(SR.GetString(SR.Config_file_has_changed), ConfigStreamInfo.StreamName, 0);
                        }

                        readBuffer = new byte[streamRead.Length];
                        int count = streamRead.Read(readBuffer, 0, (int) streamRead.Length);
                        if (count != streamRead.Length) {
                            throw new ConfigurationErrorsException(SR.GetString(SR.Config_data_read_count_mismatch));
                        }
                    }
                    // Read the first byte so that we can determine the encoding.
                    try {
                        using (StreamReader reader = new StreamReader(ConfigStreamInfo.StreamName)) {
                            if (reader.Peek() >= 0) {
                                reader.Read();
                            }

                            // Dev10 bug 687017 - Handle only UTF-16 explicitly, so that handling of other 
                            // encodings are not affected.
                            if (reader.CurrentEncoding is UnicodeEncoding) {
                                encoding = reader.CurrentEncoding;
                            }
                        }
                    }
                    catch {
                        // Ignore any errors, encoding will remain null.
                    }
                }

                string changedStreamName = FindChangedConfigurationStream();
                if (changedStreamName != null) {
                    throw new ConfigurationErrorsException(SR.GetString(SR.Config_file_has_changed), changedStreamName, 0);
                }

                checkedConfigForUpdates = true;

                // Write the changes to the output stream.
                object writeContext = null;
                bool streamOpened = false;
                try {
                    try {
                        using (Stream streamWrite = Host.OpenStreamForWrite(ConfigStreamInfo.StreamName, null, ref writeContext)) {
                            streamOpened = true;
                            // Use the default StreamWriter constructor if encoding is null,
                            // otherwise specify the encoding.
                            using (StreamWriter streamWriter = encoding == null ? new StreamWriter(streamWrite) : new StreamWriter(streamWrite, encoding)) {
                                XmlUtilWriter utilWriter = new XmlUtilWriter(streamWriter, true);
                                if (ConfigStreamInfo.HasStream) {
                                    CopyConfig(declarationUpdates, definitionUpdates, readBuffer,
                                            ConfigStreamInfo.StreamName, NamespaceChangeNeeded, utilWriter);
                                }
                                else {
                                    CreateNewConfig(declarationUpdates, definitionUpdates, NamespaceChangeNeeded, utilWriter);
                                }
                            }
                        }
                    }
                    catch {
                        if (streamOpened) {
                            Host.WriteCompleted(ConfigStreamInfo.StreamName, false, writeContext);
                        }

                        throw;
                    }
                }
                //
                // Guarantee that exceptions contain at least the name of the stream by wrapping them
                // in a ConfigurationException.
                //
                catch (Exception e) {
                    throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_error_loading_XML_file), e, ConfigStreamInfo.StreamName, 0);
                }

                Host.WriteCompleted(ConfigStreamInfo.StreamName, true, writeContext);

                // Update stream information for the config file
                ConfigStreamInfo.HasStream = true;
                ConfigStreamInfo.ClearStreamInfos();
                ConfigStreamInfo.StreamVersion = MonitorStream(null, null, ConfigStreamInfo.StreamName);
            }

            if (configSourceUpdates != null) {
                // If we haven't checked before, check now
                if (!checkedConfigForUpdates) {
                    string changedStreamName = FindChangedConfigurationStream();
                    if (changedStreamName != null) {
                        throw new ConfigurationErrorsException(SR.GetString(SR.Config_file_has_changed), changedStreamName, 0);
                    }
                }

                // write updates
                foreach (DefinitionUpdate update in configSourceUpdates) {
                    SaveConfigSource(update);
                }
            }

            // Update state to reflect the changes to the config file
            UpdateRecords();
        }
 private void CopyElement(XmlUtilWriter utilWriter)
 {
     int depth = this._reader.Depth;
     bool isEmptyElement = this._reader.IsEmptyElement;
     this.CopyXmlNode(utilWriter);
     while (this._reader.Depth > depth)
     {
         this.CopyXmlNode(utilWriter);
     }
     if (!isEmptyElement)
     {
         this.CopyXmlNode(utilWriter);
     }
 }
Exemple #25
0
        internal bool CopyXmlNode(XmlUtilWriter utilWriter)
        {
            string s = null;
            int    fromLineNumber   = -1;
            int    fromLinePosition = -1;
            int    lineNumber       = 0;
            int    linePosition     = 0;
            int    num5             = 0;
            int    num6             = 0;

            if (utilWriter.TrackPosition)
            {
                lineNumber   = this._reader.LineNumber;
                linePosition = this._reader.LinePosition;
                num5         = utilWriter.LineNumber;
                num6         = utilWriter.LinePosition;
            }
            XmlNodeType nodeType = this._reader.NodeType;

            switch (nodeType)
            {
            case XmlNodeType.Whitespace:
                utilWriter.Write(this._reader.Value);
                break;

            case XmlNodeType.Element:
                s = this._reader.IsEmptyElement ? "/>" : ">";
                fromLineNumber   = this._reader.LineNumber;
                fromLinePosition = this._reader.LinePosition + this._reader.Name.Length;
                utilWriter.Write('<');
                utilWriter.Write(this._reader.Name);
                while (this._reader.MoveToNextAttribute())
                {
                    int toLineNumber   = this._reader.LineNumber;
                    int toLinePosition = this._reader.LinePosition;
                    utilWriter.AppendRequiredWhiteSpace(fromLineNumber, fromLinePosition, toLineNumber, toLinePosition);
                    int num9 = utilWriter.Write(this._reader.Name) + utilWriter.Write('=');
                    num9            += utilWriter.AppendAttributeValue(this._reader);
                    fromLineNumber   = toLineNumber;
                    fromLinePosition = toLinePosition + num9;
                }
                break;

            case XmlNodeType.EndElement:
                s = ">";
                fromLineNumber   = this._reader.LineNumber;
                fromLinePosition = this._reader.LinePosition + this._reader.Name.Length;
                utilWriter.Write("</");
                utilWriter.Write(this._reader.Name);
                break;

            case XmlNodeType.Comment:
                utilWriter.AppendComment(this._reader.Value);
                break;

            case XmlNodeType.Text:
                utilWriter.AppendEscapeTextString(this._reader.Value);
                break;

            case XmlNodeType.XmlDeclaration:
                s = "?>";
                fromLineNumber   = this._reader.LineNumber;
                fromLinePosition = this._reader.LinePosition + 3;
                utilWriter.Write("<?xml");
                while (this._reader.MoveToNextAttribute())
                {
                    int num10 = this._reader.LineNumber;
                    int num11 = this._reader.LinePosition;
                    utilWriter.AppendRequiredWhiteSpace(fromLineNumber, fromLinePosition, num10, num11);
                    int num12 = utilWriter.Write(this._reader.Name) + utilWriter.Write('=');
                    num12           += utilWriter.AppendAttributeValue(this._reader);
                    fromLineNumber   = num10;
                    fromLinePosition = num11 + num12;
                }
                this._reader.MoveToElement();
                break;

            case XmlNodeType.SignificantWhitespace:
                utilWriter.Write(this._reader.Value);
                break;

            case XmlNodeType.ProcessingInstruction:
                utilWriter.AppendProcessingInstruction(this._reader.Name, this._reader.Value);
                break;

            case XmlNodeType.EntityReference:
                utilWriter.AppendEntityRef(this._reader.Name);
                break;

            case XmlNodeType.CDATA:
                utilWriter.AppendCData(this._reader.Value);
                break;

            default:
                if (nodeType == XmlNodeType.DocumentType)
                {
                    int num13 = utilWriter.Write("<!DOCTYPE");
                    utilWriter.AppendRequiredWhiteSpace(this._lastLineNumber, this._lastLinePosition + num13, this._reader.LineNumber, this._reader.LinePosition);
                    utilWriter.Write(this._reader.Name);
                    string str2 = null;
                    if (this._reader.HasValue)
                    {
                        str2 = this._reader.Value;
                    }
                    fromLineNumber   = this._reader.LineNumber;
                    fromLinePosition = this._reader.LinePosition + this._reader.Name.Length;
                    if (this._reader.MoveToFirstAttribute())
                    {
                        utilWriter.AppendRequiredWhiteSpace(fromLineNumber, fromLinePosition, this._reader.LineNumber, this._reader.LinePosition);
                        string name = this._reader.Name;
                        utilWriter.Write(name);
                        utilWriter.AppendSpace();
                        utilWriter.AppendAttributeValue(this._reader);
                        this._reader.MoveToAttribute(0);
                        if (name == "PUBLIC")
                        {
                            this._reader.MoveToAttribute(1);
                            utilWriter.AppendSpace();
                            utilWriter.AppendAttributeValue(this._reader);
                            this._reader.MoveToAttribute(1);
                        }
                    }
                    if ((str2 != null) && (str2.Length > 0))
                    {
                        utilWriter.Write(" [");
                        utilWriter.Write(str2);
                        utilWriter.Write(']');
                    }
                    utilWriter.Write('>');
                }
                break;
            }
            bool flag = this._reader.Read();

            nodeType = this._reader.NodeType;
            if (s != null)
            {
                int positionOffset = GetPositionOffset(nodeType);
                int num15          = this._reader.LineNumber;
                int num16          = (this._reader.LinePosition - positionOffset) - s.Length;
                utilWriter.AppendWhiteSpace(fromLineNumber, fromLinePosition, num15, num16);
                utilWriter.Write(s);
            }
            if (utilWriter.TrackPosition)
            {
                this._lastLineNumber = (lineNumber - num5) + utilWriter.LineNumber;
                if (num5 == utilWriter.LineNumber)
                {
                    this._lastLinePosition = (linePosition - num6) + utilWriter.LinePosition;
                    return(flag);
                }
                this._lastLinePosition = utilWriter.LinePosition;
            }
            return(flag);
        }
Exemple #26
0
        // Format an Xml element to be written to the config file.
        // Params:
        //   xmlElement      - the element
        //   linePosition    - start position of the element
        //   indent          - indent for each depth
        //   skipFirstIndent - skip indent for the first element?
        //
        static internal string FormatXmlElement(string xmlElement, int linePosition, int indent, bool skipFirstIndent)
        {
            XmlParserContext context = new XmlParserContext(null, null, null, XmlSpace.Default, Encoding.Unicode);
            XmlTextReader    reader  = new XmlTextReader(xmlElement, XmlNodeType.Element, context);

            StringWriter  stringWriter = new StringWriter(new StringBuilder(64), CultureInfo.InvariantCulture);
            XmlUtilWriter utilWriter   = new XmlUtilWriter(stringWriter, false);

            // append newline before indent?
            bool newLine = false;

            // last node visited was text?
            bool lastWasText = false;

            // width of line from end of indentation
            int lineWidth;

            // length of the stringbuilder after last indent with newline
            int sbLengthLastNewLine = 0;

            while (reader.Read())
            {
                XmlNodeType nodeType = reader.NodeType;

                if (lastWasText)
                {
                    utilWriter.Flush();
                    lineWidth = sbLengthLastNewLine - ((StringWriter)utilWriter.Writer).GetStringBuilder().Length;
                }
                else
                {
                    lineWidth = 0;
                }

                switch (nodeType)
                {
                case XmlNodeType.CDATA:
                case XmlNodeType.Element:
                case XmlNodeType.EndElement:
                case XmlNodeType.Comment:
                    // Do not indent if the last node was text - doing so would add whitespace
                    // that is included as part of the text.
                    if (!skipFirstIndent && !lastWasText)
                    {
                        utilWriter.AppendIndent(linePosition, indent, reader.Depth, newLine);

                        if (newLine)
                        {
                            utilWriter.Flush();
                            sbLengthLastNewLine = ((StringWriter)utilWriter.Writer).GetStringBuilder().Length;
                        }
                    }
                    break;

                default:
                    break;
                }

                lastWasText = false;
                switch (nodeType)
                {
                case XmlNodeType.Whitespace:
                    break;

                case XmlNodeType.SignificantWhitespace:
                    utilWriter.Write(reader.Value);
                    break;

                case XmlNodeType.CDATA:
                    utilWriter.AppendCData(reader.Value);
                    break;

                case XmlNodeType.ProcessingInstruction:
                    utilWriter.AppendProcessingInstruction(reader.Name, reader.Value);
                    break;

                case XmlNodeType.Comment:
                    utilWriter.AppendComment(reader.Value);
                    break;

                case XmlNodeType.Text:
                    utilWriter.AppendEscapeTextString(reader.Value);
                    lastWasText = true;
                    break;

                case XmlNodeType.Element:
                {
                    // Write "<elem"
                    utilWriter.Write('<');
                    utilWriter.Write(reader.Name);

                    lineWidth += reader.Name.Length + 2;

                    int c = reader.AttributeCount;
                    for (int i = 0; i < c; i++)
                    {
                        // Add new line if we've exceeded the line width
                        bool writeSpace;
                        if (lineWidth > MAX_LINE_WIDTH)
                        {
                            utilWriter.AppendIndent(linePosition, indent, reader.Depth - 1, true);
                            lineWidth  = indent;
                            writeSpace = false;
                            utilWriter.Flush();
                            sbLengthLastNewLine = ((StringWriter)utilWriter.Writer).GetStringBuilder().Length;
                        }
                        else
                        {
                            writeSpace = true;
                        }

                        // Write the attribute
                        reader.MoveToNextAttribute();
                        utilWriter.Flush();
                        int startLength = ((StringWriter)utilWriter.Writer).GetStringBuilder().Length;
                        if (writeSpace)
                        {
                            utilWriter.AppendSpace();
                        }

                        utilWriter.Write(reader.Name);
                        utilWriter.Write('=');
                        utilWriter.AppendAttributeValue(reader);
                        utilWriter.Flush();
                        lineWidth += ((StringWriter)utilWriter.Writer).GetStringBuilder().Length - startLength;
                    }
                }

                    // position reader back on element
                    reader.MoveToElement();

                    // write closing tag
                    if (reader.IsEmptyElement)
                    {
                        utilWriter.Write(" />");
                    }
                    else
                    {
                        utilWriter.Write('>');
                    }

                    break;

                case XmlNodeType.EndElement:
                    utilWriter.Write("</");
                    utilWriter.Write(reader.Name);
                    utilWriter.Write('>');
                    break;

                case XmlNodeType.EntityReference:
                    utilWriter.AppendEntityRef(reader.Name);
                    break;

                // Ignore <?xml and <!DOCTYPE nodes
                case XmlNodeType.XmlDeclaration:
                case XmlNodeType.DocumentType:
                default:
                    break;
                }

                // put each new element on a new line
                newLine = true;

                // do not skip any more indents
                skipFirstIndent = false;
            }

            utilWriter.Flush();
            string s = ((StringWriter)utilWriter.Writer).ToString();

            return(s);
        }
Exemple #27
0
        internal static string FormatXmlElement(string xmlElement, int linePosition, int indent, bool skipFirstIndent)
        {
            XmlParserContext context = new XmlParserContext(null, null, null, XmlSpace.Default, Encoding.Unicode);
            XmlTextReader    reader  = new XmlTextReader(xmlElement, XmlNodeType.Element, context);
            StringWriter     writer  = new StringWriter(new StringBuilder(0x40), CultureInfo.InvariantCulture);
            XmlUtilWriter    writer2 = new XmlUtilWriter(writer, false);
            bool             newLine = false;
            bool             flag2   = false;
            int num2 = 0;

            while (reader.Read())
            {
                int         num;
                int         attributeCount;
                int         num4;
                bool        flag3;
                XmlNodeType nodeType = reader.NodeType;
                if (flag2)
                {
                    writer2.Flush();
                    num = num2 - ((StringWriter)writer2.Writer).GetStringBuilder().Length;
                }
                else
                {
                    num = 0;
                }
                XmlNodeType type2 = nodeType;
                if (type2 <= XmlNodeType.CDATA)
                {
                    switch (type2)
                    {
                    case XmlNodeType.Element:
                    case XmlNodeType.CDATA:
                        goto Label_0091;
                    }
                    goto Label_00CA;
                }
                if ((type2 != XmlNodeType.Comment) && (type2 != XmlNodeType.EndElement))
                {
                    goto Label_00CA;
                }
Label_0091:
                if (!skipFirstIndent && !flag2)
                {
                    writer2.AppendIndent(linePosition, indent, reader.Depth, newLine);
                    if (newLine)
                    {
                        writer2.Flush();
                        num2 = ((StringWriter)writer2.Writer).GetStringBuilder().Length;
                    }
                }
Label_00CA:
                flag2 = false;
                switch (nodeType)
                {
                case XmlNodeType.Element:
                    writer2.Write('<');
                    writer2.Write(reader.Name);
                    num           += reader.Name.Length + 2;
                    attributeCount = reader.AttributeCount;
                    num4           = 0;
                    goto Label_0274;

                case XmlNodeType.Text:
                    writer2.AppendEscapeTextString(reader.Value);
                    flag2 = true;
                    goto Label_02D6;

                case XmlNodeType.CDATA:
                    writer2.AppendCData(reader.Value);
                    goto Label_02D6;

                case XmlNodeType.EntityReference:
                    writer2.AppendEntityRef(reader.Name);
                    goto Label_02D6;

                case XmlNodeType.ProcessingInstruction:
                    writer2.AppendProcessingInstruction(reader.Name, reader.Value);
                    goto Label_02D6;

                case XmlNodeType.Comment:
                    writer2.AppendComment(reader.Value);
                    goto Label_02D6;

                case XmlNodeType.SignificantWhitespace:
                    writer2.Write(reader.Value);
                    goto Label_02D6;

                case XmlNodeType.EndElement:
                    writer2.Write("</");
                    writer2.Write(reader.Name);
                    writer2.Write('>');
                    goto Label_02D6;

                default:
                    goto Label_02D6;
                }
Label_01BE:
                if (num > 60)
                {
                    writer2.AppendIndent(linePosition, indent, reader.Depth - 1, true);
                    num   = indent;
                    flag3 = false;
                    writer2.Flush();
                    num2 = ((StringWriter)writer2.Writer).GetStringBuilder().Length;
                }
                else
                {
                    flag3 = true;
                }
                reader.MoveToNextAttribute();
                writer2.Flush();
                int length = ((StringWriter)writer2.Writer).GetStringBuilder().Length;
                if (flag3)
                {
                    writer2.AppendSpace();
                }
                writer2.Write(reader.Name);
                writer2.Write('=');
                writer2.AppendAttributeValue(reader);
                writer2.Flush();
                num += ((StringWriter)writer2.Writer).GetStringBuilder().Length - length;
                num4++;
Label_0274:
                if (num4 < attributeCount)
                {
                    goto Label_01BE;
                }
                reader.MoveToElement();
                if (reader.IsEmptyElement)
                {
                    writer2.Write(" />");
                }
                else
                {
                    writer2.Write('>');
                }
Label_02D6:
                newLine         = true;
                skipFirstIndent = false;
            }
            writer2.Flush();
            return(((StringWriter)writer2.Writer).ToString());
        }
 private void CreateNewConfigSource(XmlUtilWriter utilWriter, string updatedXml, int indent)
 {
     string formattedXml = XmlUtil.FormatXmlElement(updatedXml, 0, indent, true);
     utilWriter.Write(string.Format(CultureInfo.InvariantCulture, FormatConfigsourceFile,
         ConfigStreamInfo.StreamEncoding.WebName));
     utilWriter.Write(formattedXml + NewLine);
 }
        // Create a new config file.
        private void CreateNewConfig(
            SectionUpdates declarationUpdates,
            ConfigDefinitionUpdates definitionUpdates,
            NamespaceChange namespaceChange,
            XmlUtilWriter utilWriter)
        {
            // Write Header
            utilWriter.Write(string.Format(CultureInfo.InvariantCulture,
                FormatNewconfigfile,
                ConfigStreamInfo.StreamEncoding.WebName));

            // Write <configuration> tag
            if (namespaceChange == NamespaceChange.Add)
            {
                utilWriter.Write(string.Format(CultureInfo.InvariantCulture,
                    FormatConfigurationNamespace,
                    KeywordConfigurationNamespace));
            }
            else utilWriter.Write(FormatConfiguration);

            const int LineIndent = DefaultIndent + 1;

            if (declarationUpdates != null)
                WriteNewConfigDeclarations(declarationUpdates, utilWriter, LineIndent, DefaultIndent, false);

            WriteNewConfigDefinitions(definitionUpdates, utilWriter, LineIndent, DefaultIndent);

            utilWriter.Write(FormatConfigurationEndelement);
        }
        //
        // Copy a configuration section to a string, and advance the reader.
        //
        internal string CopySection() {
            ResetCachedStringWriter();

            // Preserve whitespace for sections for backcompat
            WhitespaceHandling originalHandling = _reader.WhitespaceHandling;
            _reader.WhitespaceHandling = WhitespaceHandling.All;

            // Create string writer to write to
            XmlUtilWriter utilWriter = new XmlUtilWriter(_cachedStringWriter, false);

            // Copy the element
            CopyElement(utilWriter);

            // Reset whitespace handling
            _reader.WhitespaceHandling = originalHandling;

            if ((originalHandling == WhitespaceHandling.None) &&
                 (Reader.NodeType  == XmlNodeType.Whitespace))  {
                // If we were previously suppose to skip whitespace, and now we
                // are at it, then lets jump to the next item
                _reader.Read();
            }

            utilWriter.Flush();
            string s = ((StringWriter)utilWriter.Writer).ToString();
            return s;
        }
Exemple #31
0
        //
        // Copy a single XML node, attempting to preserve whitespace.
        // A side effect of this method is to advance the reader to the next node.
        //
        // PERFORMANCE NOTE: this function is used at runtime to copy a configuration section,
        // and at designtime to copy an entire XML document.
        //
        // At designtime, this function needs to be able to copy a <!DOCTYPE declaration.
        // Copying a <!DOCTYPE declaration is expensive, because due to limitations of the
        // XmlReader API, we must track the position of the writer to accurately format it.
        // Tracking the position of the writer is expensive, as it requires examining every
        // character that is written for newline characters, and maintaining the seek position
        // of the underlying stream at each new line, which in turn requires a stream flush.
        //
        // This function must NEVER require tracking the writer position to copy the Xml nodes
        // that are used in a configuration section.
        //
        internal bool CopyXmlNode(XmlUtilWriter utilWriter)
        {
            //
            // For nodes that have a closing string, such as "<element  >"
            // the XmlReader API does not give us the location of the closing string, e.g. ">".
            // To correctly determine the location of the closing part, we advance the reader,
            // determine the position of the next node, then work backwards to add whitespace
            // and add the closing string.
            //
            string close        = null;
            int    lineNumber   = -1;
            int    linePosition = -1;

            int readerLineNumber   = 0;
            int readerLinePosition = 0;
            int writerLineNumber   = 0;
            int writerLinePosition = 0;

            if (utilWriter.TrackPosition)
            {
                readerLineNumber   = _reader.LineNumber;
                readerLinePosition = _reader.LinePosition;
                writerLineNumber   = utilWriter.LineNumber;
                writerLinePosition = utilWriter.LinePosition;
            }

            // We test the node type in the likely order of decreasing occurrence.
            XmlNodeType nodeType = _reader.NodeType;

            if (nodeType == XmlNodeType.Whitespace)
            {
                utilWriter.Write(_reader.Value);
            }
            else if (nodeType == XmlNodeType.Element)
            {
                close = (_reader.IsEmptyElement) ? "/>" : ">";

                // get the line position after the element declaration:
                //      <element    attr="value"
                //              ^
                //              linePosition
                //
                lineNumber   = _reader.LineNumber;
                linePosition = _reader.LinePosition + _reader.Name.Length;

                utilWriter.Write('<');
                utilWriter.Write(_reader.Name);

                //
                // Note that there is no way to get spacing between attribute name and value
                // For example:
                //
                //          <elem attr="value" />
                //
                // is reported with the same position as
                //
                //          <elem attr = "value" />
                //
                // The first example has no spaces around '=', the second example does.
                //
                while (_reader.MoveToNextAttribute())
                {
                    // get line position of the attribute declaration
                    //      <element attr="value"
                    //               ^
                    //               attrLinePosition
                    //
                    int attrLineNumber   = _reader.LineNumber;
                    int attrLinePosition = _reader.LinePosition;

                    // Write the whitespace before the attribute
                    utilWriter.AppendRequiredWhiteSpace(lineNumber, linePosition, attrLineNumber, attrLinePosition);

                    // Write the attribute and value
                    int charactersWritten = utilWriter.Write(_reader.Name);
                    charactersWritten += utilWriter.Write('=');
                    charactersWritten += utilWriter.AppendAttributeValue(_reader);

                    // Update position. Note that the attribute value is escaped to always be on a single line.
                    lineNumber   = attrLineNumber;
                    linePosition = attrLinePosition + charactersWritten;
                }
            }
            else if (nodeType == XmlNodeType.EndElement)
            {
                close = ">";

                // get line position after the end element declaration:
                //      </element    >
                //               ^
                //               linePosition
                //
                lineNumber   = _reader.LineNumber;
                linePosition = _reader.LinePosition + _reader.Name.Length;

                utilWriter.Write("</");
                utilWriter.Write(_reader.Name);
            }
            else if (nodeType == XmlNodeType.Comment)
            {
                utilWriter.AppendComment(_reader.Value);
            }
            else if (nodeType == XmlNodeType.Text)
            {
                utilWriter.AppendEscapeTextString(_reader.Value);
            }
            else if (nodeType == XmlNodeType.XmlDeclaration)
            {
                close = "?>";

                // get line position after the xml declaration:
                //      <?xml    version="1.0"
                //           ^
                //           linePosition
                //
                lineNumber   = _reader.LineNumber;
                linePosition = _reader.LinePosition + 3;

                utilWriter.Write("<?xml");

                //
                // Note that there is no way to get spacing between attribute name and value
                // For example:
                //
                //          <?xml attr="value" ?>
                //
                // is reported with the same position as
                //
                //          <?xml attr = "value" ?>
                //
                // The first example has no spaces around '=', the second example does.
                //
                while (_reader.MoveToNextAttribute())
                {
                    // get line position of the attribute declaration
                    //      <?xml    version="1.0"
                    //               ^
                    //               attrLinePosition
                    //
                    int attrLineNumber   = _reader.LineNumber;
                    int attrLinePosition = _reader.LinePosition;

                    // Write the whitespace before the attribute
                    utilWriter.AppendRequiredWhiteSpace(lineNumber, linePosition, attrLineNumber, attrLinePosition);

                    // Write the attribute and value
                    int charactersWritten = utilWriter.Write(_reader.Name);
                    charactersWritten += utilWriter.Write('=');
                    charactersWritten += utilWriter.AppendAttributeValue(_reader);

                    // Update position. Note that the attribute value is escaped to always be on a single line.
                    lineNumber   = attrLineNumber;
                    linePosition = attrLinePosition + charactersWritten;
                }

                // Position reader at beginning of node
                _reader.MoveToElement();
            }
            else if (nodeType == XmlNodeType.SignificantWhitespace)
            {
                utilWriter.Write(_reader.Value);
            }
            else if (nodeType == XmlNodeType.ProcessingInstruction)
            {
                //
                // Note that there is no way to get spacing between attribute name and value
                // For example:
                //
                //          <?pi "value" ?>
                //
                // is reported with the same position as
                //
                //          <?pi    "value" ?>
                //
                // The first example has one space between 'pi' and "value", the second has multiple spaces.
                //
                utilWriter.AppendProcessingInstruction(_reader.Name, _reader.Value);
            }
            else if (nodeType == XmlNodeType.EntityReference)
            {
                utilWriter.AppendEntityRef(_reader.Name);
            }
            else if (nodeType == XmlNodeType.CDATA)
            {
                utilWriter.AppendCData(_reader.Value);
            }
            else if (nodeType == XmlNodeType.DocumentType)
            {
                //
                // XmlNodeType.DocumentType has the following format:
                //
                //      <!DOCTYPE rootElementName {(SYSTEM uriRef)|(PUBLIC id uriRef)} {[ dtdDecls ]} >
                //
                // The reader only gives us the position of 'rootElementName', so we must track what was
                // written before "<!DOCTYPE" in order to correctly determine the position of the
                // <!DOCTYPE tag
                //
                Debug.Assert(utilWriter.TrackPosition, "utilWriter.TrackPosition");
                int c = utilWriter.Write("<!DOCTYPE");

                // Write the space between <!DOCTYPE and the rootElementName
                utilWriter.AppendRequiredWhiteSpace(_lastLineNumber, _lastLinePosition + c, _reader.LineNumber, _reader.LinePosition);

                // Write the rootElementName
                utilWriter.Write(_reader.Name);

                // Get the dtd declarations, if any
                string dtdValue = null;
                if (_reader.HasValue)
                {
                    dtdValue = _reader.Value;
                }

                // get line position after the !DOCTYPE declaration:
                //      <!DOCTYPE  rootElement     SYSTEM rootElementDtdUri >
                //                            ^
                //                            linePosition
                lineNumber   = _reader.LineNumber;
                linePosition = _reader.LinePosition + _reader.Name.Length;

                // Note that there is no way to get the spacing after PUBLIC or SYSTEM attributes and their values
                if (_reader.MoveToFirstAttribute())
                {
                    // Write the space before SYSTEM or PUBLIC
                    utilWriter.AppendRequiredWhiteSpace(lineNumber, linePosition, _reader.LineNumber, _reader.LinePosition);

                    // Write SYSTEM or PUBLIC and the 1st value of the attribute
                    string attrName = _reader.Name;
                    utilWriter.Write(attrName);
                    utilWriter.AppendSpace();
                    utilWriter.AppendAttributeValue(_reader);
                    _reader.MoveToAttribute(0);

                    // If PUBLIC, write the second value of the attribute
                    if (attrName == "PUBLIC")
                    {
                        _reader.MoveToAttribute(1);
                        utilWriter.AppendSpace();
                        utilWriter.AppendAttributeValue(_reader);
                        _reader.MoveToAttribute(1);
                    }
                }

                // If there is a dtd, write it
                if (dtdValue != null && dtdValue.Length > 0)
                {
                    utilWriter.Write(" [");
                    utilWriter.Write(dtdValue);
                    utilWriter.Write(']');
                }

                utilWriter.Write('>');
            }

            // Advance the _reader so we can get the position of the next node.
            bool moreToRead = _reader.Read();

            nodeType = _reader.NodeType;

            // Close the node we are copying.
            if (close != null)
            {
                //
                // Find the position of the close string, for example:
                //
                //          <element      >  <subElement />
                //                        ^
                //                        closeLinePosition
                //
                int startOffset       = GetPositionOffset(nodeType);
                int closeLineNumber   = _reader.LineNumber;
                int closeLinePosition = _reader.LinePosition - startOffset - close.Length;

                // Add whitespace up to the position of the close string
                utilWriter.AppendWhiteSpace(lineNumber, linePosition, closeLineNumber, closeLinePosition);

                // Write the close string
                utilWriter.Write(close);
            }

            //
            // Track the position of the reader based on the position of the reader
            // before we copied this node and what we have written in copying the node.
            // This allows us to determine the position of the <!DOCTYPE tag.
            //
            if (utilWriter.TrackPosition)
            {
                _lastLineNumber = (readerLineNumber - writerLineNumber) + utilWriter.LineNumber;

                if (writerLineNumber == utilWriter.LineNumber)
                {
                    _lastLinePosition = (readerLinePosition - writerLinePosition) + utilWriter.LinePosition;
                }
                else
                {
                    _lastLinePosition = utilWriter.LinePosition;
                }
            }

            return(moreToRead);
        }
        // Create a new config file.
        private void CreateNewConfig(
                SectionUpdates          declarationUpdates,
                ConfigDefinitionUpdates definitionUpdates,
                NamespaceChange         namespaceChange,
                XmlUtilWriter           utilWriter) {
            int linePosition = DEFAULT_INDENT + 1;
            int indent = DEFAULT_INDENT;

            // Write Header
            utilWriter.Write(string.Format(CultureInfo.InvariantCulture,
                    FORMAT_NEWCONFIGFILE,
                    ConfigStreamInfo.StreamEncoding.WebName));

            // Write <configuration> tag
            if (namespaceChange == NamespaceChange.Add) {
                utilWriter.Write(string.Format(CultureInfo.InvariantCulture,
                        FORMAT_CONFIGURATION_NAMESPACE,
                        KEYWORD_CONFIGURATION_NAMESPACE));
            }
            else {
                utilWriter.Write(FORMAT_CONFIGURATION);
            }


            if (declarationUpdates != null) {
                WriteNewConfigDeclarations(declarationUpdates, utilWriter, linePosition, indent, false);
            }

            WriteNewConfigDefinitions(definitionUpdates, utilWriter, linePosition, indent);

            utilWriter.Write(FORMAT_CONFIGURATION_ENDELEMENT);
        }
        // Format an Xml element to be written to the config file.
        // Params:
        //   xmlElement      - the element
        //   linePosition    - start position of the element
        //   indent          - indent for each depth
        //   skipFirstIndent - skip indent for the first element?
        //
        static internal string FormatXmlElement(string xmlElement, int linePosition, int indent, bool skipFirstIndent) {

            XmlParserContext context = new XmlParserContext(null, null, null, XmlSpace.Default, Encoding.Unicode);
            XmlTextReader reader = new XmlTextReader(xmlElement, XmlNodeType.Element, context);

            StringWriter stringWriter = new StringWriter(new StringBuilder(64), CultureInfo.InvariantCulture);
            XmlUtilWriter utilWriter = new XmlUtilWriter(stringWriter, false);

            // append newline before indent?
            bool newLine = false;

            // last node visited was text?
            bool lastWasText = false;

            // width of line from end of indentation
            int lineWidth;

            // length of the stringbuilder after last indent with newline
            int sbLengthLastNewLine = 0;

            while (reader.Read()) {
                XmlNodeType nodeType = reader.NodeType;

                if (lastWasText) {
                    utilWriter.Flush();
                    lineWidth = sbLengthLastNewLine - ((StringWriter)utilWriter.Writer).GetStringBuilder().Length;
                }
                else {
                    lineWidth = 0;
                }

                switch (nodeType) {
                    case XmlNodeType.CDATA:
                    case XmlNodeType.Element:
                    case XmlNodeType.EndElement:
                    case XmlNodeType.Comment:
                        // Do not indent if the last node was text - doing so would add whitespace
                        // that is included as part of the text.
                        if (!skipFirstIndent && !lastWasText) {
                            utilWriter.AppendIndent(linePosition, indent, reader.Depth, newLine);

                            if (newLine) {
                                utilWriter.Flush();
                                sbLengthLastNewLine = ((StringWriter)utilWriter.Writer).GetStringBuilder().Length;
                            }
                        }
                        break;

                    default:
                        break;
                }

                lastWasText = false;
                switch (nodeType) {
                    case XmlNodeType.Whitespace:
                        break;

                    case XmlNodeType.SignificantWhitespace:
                        utilWriter.Write(reader.Value);
                        break;

                    case XmlNodeType.CDATA:
                        utilWriter.AppendCData(reader.Value);
                        break;

                    case XmlNodeType.ProcessingInstruction:
                        utilWriter.AppendProcessingInstruction(reader.Name, reader.Value);
                        break;

                    case XmlNodeType.Comment:
                        utilWriter.AppendComment(reader.Value);
                        break;

                    case XmlNodeType.Text:
                        utilWriter.AppendEscapeTextString(reader.Value);
                        lastWasText = true;
                        break;

                    case XmlNodeType.Element:
                        {
                            // Write "<elem"
                            utilWriter.Write('<');
                            utilWriter.Write(reader.Name);

                            lineWidth += reader.Name.Length + 2;

                            int c = reader.AttributeCount;
                            for (int i = 0; i < c; i++) {
                                // Add new line if we've exceeded the line width
                                bool writeSpace;
                                if (lineWidth > MAX_LINE_WIDTH) {
                                    utilWriter.AppendIndent(linePosition, indent, reader.Depth - 1, true);
                                    lineWidth = indent;
                                    writeSpace = false;
                                    utilWriter.Flush();
                                    sbLengthLastNewLine = ((StringWriter)utilWriter.Writer).GetStringBuilder().Length;
                                }
                                else {
                                    writeSpace = true;
                                }

                                // Write the attribute
                                reader.MoveToNextAttribute();
                                utilWriter.Flush();
                                int startLength = ((StringWriter)utilWriter.Writer).GetStringBuilder().Length;
                                if (writeSpace) {
                                    utilWriter.AppendSpace();
                                }

                                utilWriter.Write(reader.Name);
                                utilWriter.Write('=');
                                utilWriter.AppendAttributeValue(reader);
                                utilWriter.Flush();
                                lineWidth += ((StringWriter)utilWriter.Writer).GetStringBuilder().Length - startLength;
                            }
                        }

                        // position reader back on element
                        reader.MoveToElement();

                        // write closing tag
                        if (reader.IsEmptyElement) {
                            utilWriter.Write(" />");
                        }
                        else {
                            utilWriter.Write('>');
                        }

                        break;

                    case XmlNodeType.EndElement:
                        utilWriter.Write("</");
                        utilWriter.Write(reader.Name);
                        utilWriter.Write('>');
                        break;

                    case XmlNodeType.EntityReference:
                        utilWriter.AppendEntityRef(reader.Name);
                        break;

                    // Ignore <?xml and <!DOCTYPE nodes
                    case XmlNodeType.XmlDeclaration:
                    case XmlNodeType.DocumentType:
                    default:
                        break;
                }

                // put each new element on a new line
                newLine = true;

                // do not skip any more indents
                skipFirstIndent = false;
            }

            utilWriter.Flush();
            string s = ((StringWriter)utilWriter.Writer).ToString();
            return s;
        }
 private void WriteUnwrittenConfigDeclarations(SectionUpdates declarationUpdates, XmlUtilWriter utilWriter, int linePosition, int indent, bool skipFirstIndent) {
     WriteUnwrittenConfigDeclarationsRecursive(declarationUpdates, utilWriter, linePosition, indent, skipFirstIndent);
 }
        //
        // Copy an XML element, then continue copying until we've hit the next element
        // or exited this depth.
        //
        internal bool CopyOuterXmlToNextElement(XmlUtilWriter utilWriter, bool limitDepth) {
            CopyElement(utilWriter);

            // Copy until reaching the next element, or if limitDepth == true until we've exited this depth.
            return CopyReaderToNextElement(utilWriter, limitDepth);
        }
        private void WriteNewConfigDefinitions(ConfigDefinitionUpdates configDefinitionUpdates, XmlUtilWriter utilWriter, int linePosition, int indent) {
            if (configDefinitionUpdates == null)
                return;

            foreach (LocationUpdates locationUpdates in configDefinitionUpdates.LocationUpdatesList) {
                SectionUpdates sectionUpdates = locationUpdates.SectionUpdates;
                if (sectionUpdates.IsEmpty || !sectionUpdates.IsNew)
                    continue;

                configDefinitionUpdates.FlagLocationWritten();
                bool writeLocationTag = _locationSubPath != null || !locationUpdates.IsDefault;
                int recurseLinePosition = linePosition;

                utilWriter.AppendSpacesToLinePosition(linePosition);

                if (writeLocationTag) {
                    // write the <location> start tag
                    if (_locationSubPath == null) {
                        utilWriter.Write(String.Format(CultureInfo.InvariantCulture, FORMAT_LOCATION_NOPATH, locationUpdates.OverrideMode.LocationTagXmlString, BoolToString(locationUpdates.InheritInChildApps)));
                    }
                    else {
                        utilWriter.Write(String.Format(CultureInfo.InvariantCulture, FORMAT_LOCATION_PATH, locationUpdates.OverrideMode.LocationTagXmlString, BoolToString(locationUpdates.InheritInChildApps), _locationSubPath));
                    }

                    recurseLinePosition += indent;
                    utilWriter.AppendSpacesToLinePosition(recurseLinePosition);
                }

                // Invoke the recursive write.
                WriteNewConfigDefinitionsRecursive(utilWriter, locationUpdates.SectionUpdates, recurseLinePosition, indent, true);

                if (writeLocationTag) {
                    // Write the location end tag
                    utilWriter.AppendSpacesToLinePosition(linePosition);
                    utilWriter.Write(FORMAT_LOCATION_ENDELEMENT);
                    utilWriter.AppendNewLine();
                }
            }

            if (configDefinitionUpdates.RequireLocation) {
                Debug.Assert(IsLocationConfig, "IsLocationConfig");

                // If we still require this to be written, then we must write it out now
                configDefinitionUpdates.FlagLocationWritten();

                utilWriter.AppendSpacesToLinePosition(linePosition);

                utilWriter.Write(String.Format(CultureInfo.InvariantCulture, FORMAT_LOCATION_PATH, OverrideModeSetting.LocationDefault.LocationTagXmlString, KEYWORD_TRUE, _locationSubPath));
                utilWriter.AppendSpacesToLinePosition(linePosition);
                utilWriter.Write(FORMAT_LOCATION_ENDELEMENT);
                utilWriter.AppendNewLine();
            }
        }
Exemple #37
0
 internal bool CopyOuterXmlToNextElement(XmlUtilWriter utilWriter, bool limitDepth)
 {
     this.CopyElement(utilWriter);
     return(this.CopyReaderToNextElement(utilWriter, limitDepth));
 }
        private void CheckPreamble(byte[] preamble, XmlUtilWriter utilWriter, byte[] buffer) {
            bool hasByteOrderMark = false;
            using (Stream preambleStream = new MemoryStream(buffer)) {
                byte[] streamStart = new byte[preamble.Length];
                if (preambleStream.Read(streamStart, 0, streamStart.Length) == streamStart.Length) {
                    hasByteOrderMark = true;
                    for (int i = 0; i < streamStart.Length; i++) {
                        if (streamStart[i] != preamble[i]) {
                            hasByteOrderMark = false;
                            break;
                        }
                    }
                }
            }

            if (!hasByteOrderMark) {
                // Force the writer to emit byte order mark, then reset the stream
                // so that it is written over.
                object checkpoint = utilWriter.CreateStreamCheckpoint();
                utilWriter.Write('x');
                utilWriter.RestoreStreamCheckpoint(checkpoint);
            }
        }
        //
        // Copy the reader until we hit an element, or we've exited the current depth.
        //
        internal bool CopyReaderToNextElement(XmlUtilWriter utilWriter, bool limitDepth) {
            bool moreToRead = true;

            // Set the depth if we limit copying to this depth
            int depth;
            if (limitDepth) {
                // there is nothing in the element
                if (_reader.NodeType == XmlNodeType.EndElement)
                    return true;

                depth = _reader.Depth;
            }
            else {
                depth = 0;
            }

            // Copy nodes until we've reached the desired depth, or until we hit an element.
            do {
                if (_reader.NodeType == XmlNodeType.Element)
                    break;

                if (_reader.Depth < depth) {
                    break;
                }

                moreToRead = CopyXmlNode(utilWriter);
            } while (moreToRead);

            return moreToRead;
        }
        // Copy a config file, replacing sections with updates.
        private void CopyConfig(SectionUpdates declarationUpdates, ConfigDefinitionUpdates definitionUpdates,
                byte[] buffer, string filename, NamespaceChange namespaceChange, XmlUtilWriter utilWriter) {

            CheckPreamble(ConfigStreamInfo.StreamEncoding.GetPreamble(), utilWriter, buffer);

            using (Stream stream = new MemoryStream(buffer)) {
                using (XmlUtil xmlUtil = new XmlUtil(stream, filename, false)) {
                    // copy up to the <configuration> node
                    XmlTextReader reader = xmlUtil.Reader;
                    reader.WhitespaceHandling = WhitespaceHandling.All;
                    reader.Read();
                    xmlUtil.CopyReaderToNextElement(utilWriter, false);

                    Debug.Assert(reader.NodeType == XmlNodeType.Element && reader.Name == KEYWORD_CONFIGURATION,
                                 "reader.NodeType == XmlNodeType.Element && reader.Name == KEYWORD_CONFIGURATION");

                    int indent = DEFAULT_INDENT;
                    int configurationElementLinePosition = xmlUtil.TrueLinePosition;
                    bool isEmptyConfigurationElement = reader.IsEmptyElement;

                    // copy <configuration> node
                    // if the node is an empty element, we may need to open it.
                    string configurationStartElement;
                    if (namespaceChange == NamespaceChange.Add) {
                        configurationStartElement = string.Format(
                            CultureInfo.InvariantCulture, FORMAT_CONFIGURATION_NAMESPACE, KEYWORD_CONFIGURATION_NAMESPACE);
                    }
                    else if (namespaceChange == NamespaceChange.Remove) {
                        configurationStartElement = FORMAT_CONFIGURATION;
                    }
                    else {
                        configurationStartElement = null;
                    }

                    bool needsChildren = (declarationUpdates != null || definitionUpdates  != null);
                    string configurationEndElement = xmlUtil.UpdateStartElement(utilWriter, configurationStartElement, needsChildren, configurationElementLinePosition, indent);

                    bool foundConfigSectionsElement = false;
                    if (!isEmptyConfigurationElement) {
                        // copy up to the first element under <configuration>
                        xmlUtil.CopyReaderToNextElement(utilWriter, true);

                        // updateIndent
                        indent = UpdateIndent(indent, xmlUtil, utilWriter, configurationElementLinePosition);

                        if (reader.NodeType == XmlNodeType.Element && reader.Name == KEYWORD_CONFIGSECTIONS) {
                            foundConfigSectionsElement = true;

                            int configSectionsElementLinePosition = xmlUtil.TrueLinePosition;
                            bool isEmptyConfigSectionsElement = reader.IsEmptyElement;

                            // if no updates, copy the entire <configSections> element
                            if (declarationUpdates == null) {
                                xmlUtil.CopyOuterXmlToNextElement(utilWriter, true);
                            }
                            else {
                                // copy <configSections>, and open it if it is an empty element
                                string configSectionsEndElement = xmlUtil.UpdateStartElement(
                                    utilWriter, null, true, configSectionsElementLinePosition, indent);

                                if (!isEmptyConfigSectionsElement) {
                                    // copy to next element under <configSections>, or up to closing </configSections>
                                    xmlUtil.CopyReaderToNextElement(utilWriter, true);

                                    // copy config declarations
                                    CopyConfigDeclarationsRecursive(declarationUpdates, xmlUtil, utilWriter, string.Empty,
                                            configSectionsElementLinePosition, indent);

                                    Debug.Assert(reader.NodeType == XmlNodeType.EndElement && reader.Name == KEYWORD_CONFIGSECTIONS,
                                                 "reader.NodeType == XmlNodeType.EndElement && reader.Name == \"KEYWORD_CONFIGSECTIONS\"");
                                }

                                // write declarations not written by above copy
                                if (declarationUpdates.HasUnretrievedSections()) {

                                    // determine the line position of the end element
                                    int endElementLinePosition = 0;
                                    if (configSectionsEndElement == null) {
                                        endElementLinePosition = xmlUtil.TrueLinePosition;
                                    }

                                    // indent a new line
                                    if (!utilWriter.IsLastLineBlank) {
                                        utilWriter.AppendNewLine();
                                    }

                                    WriteUnwrittenConfigDeclarations(declarationUpdates, utilWriter, configSectionsElementLinePosition + indent, indent, false);

                                    // restore spaces to end element
                                    if (configSectionsEndElement == null) {
                                        utilWriter.AppendSpacesToLinePosition(endElementLinePosition);
                                    }
                                }

                                // Copy the </configSections> element
                                if (configSectionsEndElement == null) {
                                    xmlUtil.CopyXmlNode(utilWriter);
                                }
                                else {
                                    // note that configSectionsEndElement already contains the proper indenting
                                    utilWriter.Write(configSectionsEndElement);
                                }

                                // copy up to the next element under <configuration>, or up to closing </configSections>
                                xmlUtil.CopyReaderToNextElement(utilWriter, true);
                            }
                        }
                    }

                    // Write new declarations
                    if (!foundConfigSectionsElement && declarationUpdates != null) {
                        bool skipFirstIndent = reader.Depth > 0 && reader.NodeType == XmlNodeType.Element;
                        int newConfigSectionsLinePosition;
                        if (skipFirstIndent) {
                            newConfigSectionsLinePosition = xmlUtil.TrueLinePosition;
                        }
                        else {
                            newConfigSectionsLinePosition = configurationElementLinePosition + indent;
                        }

                        WriteNewConfigDeclarations(declarationUpdates, utilWriter, newConfigSectionsLinePosition, indent, skipFirstIndent);
                    }

                    if (definitionUpdates != null) {
                        //
                        // Copy sections recursively. In the file we copy we start out at
                        //     location path="." allowOverride="true" inheritInChildApps="true"
                        //
                        bool locationPathApplies = false;
                        LocationUpdates locationUpdates = null;
                        SectionUpdates sectionUpdates = null;
                        if (!IsLocationConfig) {
                            locationPathApplies = true;
                            locationUpdates = definitionUpdates.FindLocationUpdates(OverrideModeSetting.LocationDefault, true);
                            if (locationUpdates != null) {
                                sectionUpdates = locationUpdates.SectionUpdates;
                            }
                        }

                        CopyConfigDefinitionsRecursive(definitionUpdates, xmlUtil, utilWriter, locationPathApplies,
                            locationUpdates, sectionUpdates, true, string.Empty, configurationElementLinePosition, indent);

                        // Write new config sections from new groups.
                        WriteNewConfigDefinitions(definitionUpdates, utilWriter, configurationElementLinePosition + indent, indent);

#if DBG
                        Debug.Assert(configurationEndElement != null || (reader.NodeType == XmlNodeType.EndElement && reader.Name == KEYWORD_CONFIGURATION),
                                     "configurationEndElement != null || (reader.NodeType == XmlNodeType.EndElement && reader.Name == KEYWORD_CONFIGURATION)");
#endif



#if DBG
                        {
                            foreach (LocationUpdates l in definitionUpdates.LocationUpdatesList) {
                                Debug.Assert(!l.SectionUpdates.HasUnretrievedSections(), "!l.SectionUpdates.HasUnretrievedSections()");
                            }
                        }
#endif
                    }


                    if (configurationEndElement != null) {
                        // If we have to add closing config tag, then do it now
                        // before copying extra whitespace/comments
                        if (!utilWriter.IsLastLineBlank) {
                            utilWriter.AppendNewLine();
                        }

                        utilWriter.Write(configurationEndElement);
                    }

                    //
                    // Copy the remainder of the file, the closing </configuration> node plus any whitespace
                    // and comments
                    //
                    while (xmlUtil.CopyXmlNode(utilWriter)) {
                    }
                }
            }
        }
        //
        // Skip over the current element and copy until the next element.
        // This function removes the one blank line that would otherwise
        // be inserted by simply skipping and copying to the next element
        // in a situation like this:
        //
        //      <!-- end of previous configSection -->
        //      <configSectionToDelete>
        //          <content />
        //          <moreContent />
        //      </configSectionToDelete>
        //      <!-- end of configSectionToDelete -->
        //      <nextConfigSection />
        //
        internal bool SkipAndCopyReaderToNextElement(XmlUtilWriter utilWriter, bool limitDepth) {
            Debug.Assert(_reader.NodeType == XmlNodeType.Element, "_reader.NodeType == XmlNodeType.Element");

            // If the last line before the element is not blank, then we do not have to
            // remove the blank line.
            if (!utilWriter.IsLastLineBlank) {
                _reader.Skip();
                return CopyReaderToNextElement(utilWriter, limitDepth);
            }

            // Set the depth if we limit copying to this depth
            int depth;
            if (limitDepth) {
                depth = _reader.Depth;
            }
            else {
                depth = 0;
            }

            // Skip over the element
            _reader.Skip();

            int lineNumberOfEndElement = _reader.LineNumber;

            // Read until we hit a a non-whitespace node or reach the end
            while (!_reader.EOF) {
                if (_reader.NodeType != XmlNodeType.Whitespace) {
                    //
                    // If the next non-whitepace node is on another line,
                    // seek back to the beginning of the current blank line,
                    // skip a blank line of whitespace, and copy the remaining whitespace.
                    //
                    if (_reader.LineNumber > lineNumberOfEndElement) {
                        utilWriter.SeekToLineStart();
                        utilWriter.AppendWhiteSpace(lineNumberOfEndElement + 1, 1, LineNumber, TrueLinePosition);
                    }

                    break;
                }

                _reader.Read();
            }

            // Copy nodes until we've reached the desired depth, or until we hit an element.
            while (!_reader.EOF) {
                if (_reader.NodeType == XmlNodeType.Element)
                    break;

                if (_reader.Depth < depth) {
                    break;
                }

                CopyXmlNode(utilWriter);
            };

            return !_reader.EOF;
        }
        // Copy configuration sections from the original configuration file.
        private bool CopyConfigDefinitionsRecursive(
                ConfigDefinitionUpdates configDefinitionUpdates, XmlUtil xmlUtil, XmlUtilWriter utilWriter,
                bool locationPathApplies, LocationUpdates locationUpdates, SectionUpdates sectionUpdates,
                bool addNewSections, string group, int parentLinePosition, int parentIndent) {

            bool wroteASection = false;
            XmlTextReader reader = xmlUtil.Reader;
            int linePosition;
            int indent;
            int startingLinePosition;

            indent = UpdateIndent(parentIndent, xmlUtil, utilWriter, parentLinePosition);

            if (reader.NodeType == XmlNodeType.Element) {
                linePosition = xmlUtil.TrueLinePosition;
                startingLinePosition = linePosition;
            }
            else if (reader.NodeType == XmlNodeType.EndElement) {
                linePosition = parentLinePosition + indent;
                if (utilWriter.IsLastLineBlank) {
                    startingLinePosition = xmlUtil.TrueLinePosition;
                }
                else {
                    startingLinePosition = parentLinePosition;
                }
            }
            else {
                linePosition = parentLinePosition + indent;
                startingLinePosition = 0;
            }

            //
            // Write any new sections that apply to this group
            //
            if (sectionUpdates != null && addNewSections) {
                // Remove newness, so we won't write again
                sectionUpdates.IsNew = false;

                Debug.Assert(locationPathApplies, "locationPathApplies");
                string[] movedSectionNames = sectionUpdates.GetMovedSectionNames();
                if (movedSectionNames != null) {
                    if (!utilWriter.IsLastLineBlank) {
                        utilWriter.AppendNewLine();
                    }

                    utilWriter.AppendSpacesToLinePosition(linePosition);
                    bool skipFirstIndent = true;

                    foreach (string configKey in movedSectionNames) {
                        DefinitionUpdate update = sectionUpdates.GetDefinitionUpdate(configKey);

                        WriteSectionUpdate(utilWriter, update, linePosition, indent, skipFirstIndent);
                        skipFirstIndent = false;
                        utilWriter.AppendNewLine();
                        wroteASection = true;
                    }

                    // Restore the whitespace we used for the first element, which is either a start or an end element.
                    utilWriter.AppendSpacesToLinePosition(startingLinePosition);
                }
            }

            if (reader.NodeType == XmlNodeType.Element) {
                //
                // For each element at this depth, either:
                // - Write the element verbatim and recurse due to a location section or group hierarchy element.
                // - Write the element verbatim because it is unchanged, or because the current location does
                //   not apply.
                // - Write the updated XML for the section.
                // - Skip it because the section has been removed.
                //
                int depth = reader.Depth;
                while (reader.Depth == depth) {
                    bool                recurse = false;
                    DefinitionUpdate    update = null;
                    bool                elementLocationPathApplies = locationPathApplies;
                    LocationUpdates     recurseLocationUpdates = locationUpdates;
                    SectionUpdates      recurseSectionUpdates = sectionUpdates;
                    bool                recurseAddNewSections = addNewSections;
                    string              recurseGroup = group;
                    bool                removedSectionOrGroup = false;

                    // update the lineposition and indent for each element
                    indent = UpdateIndent(indent, xmlUtil, utilWriter, parentLinePosition);
                    linePosition = xmlUtil.TrueLinePosition;

                    string elementName = reader.Name;
                    if (elementName == KEYWORD_LOCATION) {
                        string locationSubPathAttribute = reader.GetAttribute(KEYWORD_LOCATION_PATH);
                        locationSubPathAttribute = NormalizeLocationSubPath(locationSubPathAttribute, xmlUtil);
                        elementLocationPathApplies = false;
                        OverrideModeSetting overrideMode = OverrideModeSetting.LocationDefault;
                        bool inheritInChildApps = true;

                        if (IsLocationConfig) {
                            // For location config we will compare config paths instead of location strings
                            // so that we dont end up comparing "1" with "Default Web Site" and ending up with the wrong result
                            if (locationSubPathAttribute == null) {
                                elementLocationPathApplies = false;
                            }
                            else {
                                elementLocationPathApplies = StringUtil.EqualsIgnoreCase(ConfigPath, Host.GetConfigPathFromLocationSubPath(Parent.ConfigPath, locationSubPathAttribute));
                            }
                        }
                        else {
                            Debug.Assert(LocationSubPath == null);

                            // This is the same as doing StringUtil.EqualsIgnoreCase(_locationSubPath, locationSubPathAttribute)
                            // but remember the first one is null. Also remember locationSubPathAttribute is already normalized
                            elementLocationPathApplies = (locationSubPathAttribute == null);
                        }

                        if (elementLocationPathApplies) {
                            // Retrieve overrideMode and InheritInChildApps

                            string allowOverrideAttribute = reader.GetAttribute(KEYWORD_LOCATION_ALLOWOVERRIDE);
                            if (allowOverrideAttribute != null) {
                                overrideMode = OverrideModeSetting.CreateFromXmlReadValue(Boolean.Parse(allowOverrideAttribute));
                            }

                            string overrideModeAttribute = reader.GetAttribute(KEYWORD_LOCATION_OVERRIDEMODE);
                            if (overrideModeAttribute != null) {
                                overrideMode = OverrideModeSetting.CreateFromXmlReadValue(OverrideModeSetting.ParseOverrideModeXmlValue(overrideModeAttribute, null));

                                Debug.Assert(allowOverrideAttribute == null, "allowOverride and overrideMode both detected in a <location> tag");
                            }

                            string inheritInChildAppsAttribute = reader.GetAttribute(KEYWORD_LOCATION_INHERITINCHILDAPPLICATIONS);
                            if (inheritInChildAppsAttribute != null) {
                                inheritInChildApps = Boolean.Parse(inheritInChildAppsAttribute);
                            }

                            // Flag that we already have one of these locations
                            configDefinitionUpdates.FlagLocationWritten();
                        }

                        if (reader.IsEmptyElement) {
                            if (elementLocationPathApplies &&
                                 (configDefinitionUpdates.FindLocationUpdates(overrideMode,
                                                                              inheritInChildApps) != null)) {
                                // If we are going to make updates here, then
                                // delete the one that is here (so we can update later)
                                elementLocationPathApplies = true;
                            }
                            else {
                                // If not lets leave it
                                elementLocationPathApplies = false;
                            }
                        }
                        else {
                            // recurse if this location applies to us
                            if (elementLocationPathApplies) {
                                if (configDefinitionUpdates != null) {
                                    recurseLocationUpdates = configDefinitionUpdates.FindLocationUpdates(overrideMode, inheritInChildApps);
                                    if (recurseLocationUpdates != null) {
                                        recurse = true;
                                        recurseSectionUpdates = recurseLocationUpdates.SectionUpdates;

                                        // If this is <location path=".">, we don't want to add moved sections
                                        // to it.
                                        if (_locationSubPath == null && recurseLocationUpdates.IsDefault) {
                                            recurseAddNewSections = false;
                                        }
                                    }
                                }
                            }
                            else {
                                // recurse if necessary to remove items in _removedSections and _removedGroups
                                if (HasRemovedSectionsOrGroups && !IsLocationConfig && Host.SupportsLocation) {
                                    recurse = true;
                                    recurseLocationUpdates = null;
                                    recurseSectionUpdates = null;
                                    recurseAddNewSections = false;
                                }
                            }
                        }
                    }
                    else {
                        string configKey = CombineConfigKey(group, elementName);
                        FactoryRecord factoryRecord = FindFactoryRecord(configKey, false);
                        if (factoryRecord == null) {
                            // The factory was deleted, so regardless of whether this is a
                            // section or sectionGroup, it can be skipped.
                            if (!elementLocationPathApplies && !IsLocationConfig) {
                                removedSectionOrGroup = true;
                            }
                        }
                        else if (factoryRecord.IsGroup) {
                            if (reader.IsEmptyElement) {
                                if (!elementLocationPathApplies && !IsLocationConfig) {
                                    removedSectionOrGroup = true;
                                }
                            }
                            else {
                                // if the location path applies, recurse if there are updates
                                if (sectionUpdates != null) {
                                    SectionUpdates sectionUpdatesChild = sectionUpdates.GetSectionUpdatesForGroup(elementName);
                                    if (sectionUpdatesChild != null) {
                                        recurse = true;
                                        recurseGroup = configKey;
                                        recurseSectionUpdates = sectionUpdatesChild;
                                    }
                                }
                                else if (!elementLocationPathApplies && !IsLocationConfig) {
                                    if (_removedSectionGroups != null && _removedSectionGroups.Contains(configKey)) {
                                        removedSectionOrGroup = true;
                                    }
                                    else {
                                        recurse = true;
                                        recurseGroup = configKey;
                                        recurseLocationUpdates = null;
                                        recurseSectionUpdates = null;
                                        recurseAddNewSections = false;
                                    }
                                }
                            }
                        }
                        else {
                            // it is a section - get the update
                            if (sectionUpdates != null) {
                                update = sectionUpdates.GetDefinitionUpdate(configKey);
                            }
                            else if (!elementLocationPathApplies && !IsLocationConfig) {
                                if (_removedSections != null && _removedSections.Contains(configKey)) {
                                    removedSectionOrGroup = true;
                                }
                            }
                        }
                    }

                    if (recurse) {
#if DBG
                        string startElementName = reader.Name;
#endif

                        // flush, and get length of underlying stream
                        object checkpoint = utilWriter.CreateStreamCheckpoint();

                        // Copy this element node and up to the first subelement
                        xmlUtil.CopyXmlNode(utilWriter);
                        xmlUtil.CopyReaderToNextElement(utilWriter, true);

                        // Recurse
                        bool recurseWroteASection = CopyConfigDefinitionsRecursive(
                                configDefinitionUpdates, xmlUtil, utilWriter, elementLocationPathApplies, recurseLocationUpdates, recurseSectionUpdates,
                                recurseAddNewSections, recurseGroup, linePosition, indent);

                        // Copy the end element
                        xmlUtil.CopyXmlNode(utilWriter);

                        if (recurseWroteASection) {
                            wroteASection = true;
                        }
                        else {
                            // back out the change
                            utilWriter.RestoreStreamCheckpoint(checkpoint);
                        }

                        // Copy up to the next element, or exit this level.
                        xmlUtil.CopyReaderToNextElement(utilWriter, true);
                    }
                    else {
                        bool skip;
                        if (update == null) {
                            // remove the section from the file if we're in the correct location,
                            // or if the section or group should be removed from all locations
                            skip = elementLocationPathApplies || removedSectionOrGroup;
                        }
                        else {
                            // replace the section if the xml for it has been updated
                            // if it is a configSource, don't write it unless the configSource parameters have changed
                            skip = false;
                            if (update.UpdatedXml != null) {
                                ConfigurationSection configSection = (ConfigurationSection) update.SectionRecord.Result;
                                if (    String.IsNullOrEmpty(configSection.SectionInformation.ConfigSource) ||
                                        configSection.SectionInformation.ConfigSourceModified) {
                                    skip = true;
                                    WriteSectionUpdate(utilWriter, update, linePosition, indent, true);
                                    wroteASection = true;
                                }
                            }
                        }

                        if (skip) {
                            //
                            // Skip over the existing element, then
                            // copy up to the next element, or exit this level.
                            //
                            xmlUtil.SkipAndCopyReaderToNextElement(utilWriter, true);
                        }
                        else {
                            // Copy this entire contents of this element and then to the next element, or exit this level.
                            xmlUtil.CopyOuterXmlToNextElement(utilWriter, true);
                            wroteASection = true;
                        }
                    }
                }
            }

            //
            // Write new section groups
            //
            if (sectionUpdates != null && addNewSections && sectionUpdates.HasNewSectionGroups()) {
                // Add whitespace to align us with the other elements in this group
                linePosition = parentLinePosition + indent;
                if (reader.NodeType == XmlNodeType.EndElement) {
                    if (utilWriter.IsLastLineBlank) {
                        startingLinePosition = xmlUtil.TrueLinePosition;
                    }
                    else {
                        startingLinePosition = parentLinePosition;
                    }
                }
                else {
                    startingLinePosition = 0;
                }

                utilWriter.AppendSpacesToLinePosition(linePosition);

                bool wroteNewSection = WriteNewConfigDefinitionsRecursive(utilWriter, sectionUpdates, linePosition, indent, true);
                if (wroteNewSection) {
                    wroteASection = true;
                }

                // Restore the whitespace of the end element
                utilWriter.AppendSpacesToLinePosition(startingLinePosition);
            }

            return wroteASection;
        }
        //
        // Copy an XML element and its children, up to and including the end element.
        //
        private void CopyElement(XmlUtilWriter utilWriter) {
            Debug.Assert(_reader.NodeType== XmlNodeType.Element, "_reader.NodeType== XmlNodeType.Element");

            int depth = _reader.Depth;
            bool isEmptyElement = _reader.IsEmptyElement;

            // Copy current node
            CopyXmlNode(utilWriter);

            // Copy nodes while the depth is greater than the current depth.
            while (_reader.Depth > depth) {
                CopyXmlNode(utilWriter);
            }

            // Copy the end element.
            if (!isEmptyElement) {
                CopyXmlNode(utilWriter);
            }
        }
        //
        // SaveConfigSource
        //
        private void SaveConfigSource(DefinitionUpdate update) {

            string configSourceStreamName;

            if (update.SectionRecord.HasResult) {
                ConfigurationSection configSection = (ConfigurationSection) update.SectionRecord.Result;
                configSourceStreamName = configSection.SectionInformation.ConfigSourceStreamName;
            }
            else {
                Debug.Assert(update.SectionRecord.HasFileInput, "update.SectionRecord.HasFileInput");
                SectionInput fileInput = update.SectionRecord.FileInput;
                configSourceStreamName = fileInput.SectionXmlInfo.ConfigSourceStreamName;
            }

            // Copy the input stream before opening the output stream.
            byte[] readBuffer = null;
            using (Stream streamRead = Host.OpenStreamForRead(configSourceStreamName)) {
                if (streamRead != null) {
                    readBuffer = new byte[streamRead.Length];
                    int count = streamRead.Read(readBuffer, 0, (int) streamRead.Length);
                    if (count != streamRead.Length) {
                        throw new ConfigurationErrorsException();
                    }
                }
            }

            // Write the changes to the output stream.
            bool hasFile = (readBuffer != null);
            object writeContext = null;
            bool streamOpened = false;

            try {
                try {
                    string templateStreamName;

                    if (Host.IsRemote) {
                        // templateStreamName is used by OpenStreamForWrite for copying file attributes during saving.
                        // (for details, see WriteFileContext.Complete.)
                        //
                        // If we're using a remote host, then ConfigStreamInfo.StreamName is actually pointing to a
                        // full filepath on a remote machine.  In this case, it's impossible to copy the attributes
                        // over, and thus we won't do it.
                        templateStreamName = null;
                    }
                    else {
                        templateStreamName = ConfigStreamInfo.StreamName;
                    }

                    using (Stream streamWrite = Host.OpenStreamForWrite(configSourceStreamName, templateStreamName, ref writeContext)) {
                        streamOpened = true;
                        if (update.UpdatedXml == null) {
                            Debug.Assert(hasFile, "hasFile");
                            if (hasFile) {
                                streamWrite.Write(readBuffer, 0, readBuffer.Length);
                            }
                        }
                        else {
                            using (StreamWriter streamWriter = new StreamWriter(streamWrite)) {
                                XmlUtilWriter utilWriter = new XmlUtilWriter(streamWriter, true);
                                if (hasFile) {
                                    CopyConfigSource(utilWriter, update.UpdatedXml, configSourceStreamName, readBuffer);
                                }
                                else {
                                    CreateNewConfigSource(utilWriter, update.UpdatedXml, DEFAULT_INDENT);
                                }
                            }
                        }
                    }
                }
                catch {
                    if (streamOpened) {
                        Host.WriteCompleted(configSourceStreamName, false, writeContext);
                    }

                    throw;
                }
            }
            //
            // Guarantee that exceptions contain at least the name of the stream by wrapping them
            // in a ConfigurationException.
            //
            catch (Exception e) {
                throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_error_loading_XML_file), e, configSourceStreamName, 0);
            }

            Host.WriteCompleted(configSourceStreamName, true, writeContext);
        }
        //
        // Copy a single XML node, attempting to preserve whitespace.
        // A side effect of this method is to advance the reader to the next node.
        //
        // PERFORMANCE NOTE: this function is used at runtime to copy a configuration section,
        // and at designtime to copy an entire XML document.
        //
        // At designtime, this function needs to be able to copy a <!DOCTYPE declaration.
        // Copying a <!DOCTYPE declaration is expensive, because due to limitations of the 
        // XmlReader API, we must track the position of the writer to accurately format it. 
        // Tracking the position of the writer is expensive, as it requires examining every
        // character that is written for newline characters, and maintaining the seek position
        // of the underlying stream at each new line, which in turn requires a stream flush.
        //
        // This function must NEVER require tracking the writer position to copy the Xml nodes
        // that are used in a configuration section.
        // 
        internal bool CopyXmlNode(XmlUtilWriter utilWriter) {
            //
            // For nodes that have a closing string, such as "<element  >"
            // the XmlReader API does not give us the location of the closing string, e.g. ">".
            // To correctly determine the location of the closing part, we advance the reader,
            // determine the position of the next node, then work backwards to add whitespace
            // and add the closing string.
            //
            string close = null;
            int lineNumber = -1;
            int linePosition = -1;

            int readerLineNumber = 0;
            int readerLinePosition = 0;
            int writerLineNumber = 0;
            int writerLinePosition = 0;
            if (utilWriter.TrackPosition) {
                readerLineNumber = _reader.LineNumber;
                readerLinePosition = _reader.LinePosition;
                writerLineNumber = utilWriter.LineNumber;
                writerLinePosition = utilWriter.LinePosition;
            }

            // We test the node type in the likely order of decreasing occurrence.
            XmlNodeType nodeType = _reader.NodeType;
            if (nodeType == XmlNodeType.Whitespace) {
                utilWriter.Write(_reader.Value);
            }
            else if (nodeType == XmlNodeType.Element) {
                close = (_reader.IsEmptyElement) ? "/>" : ">";

                // get the line position after the element declaration:
                //      <element    attr="value"
                //              ^
                //              linePosition
                //
                lineNumber = _reader.LineNumber;
                linePosition = _reader.LinePosition + _reader.Name.Length;

                utilWriter.Write('<');
                utilWriter.Write(_reader.Name);

                //
                // Note that there is no way to get spacing between attribute name and value
                // For example:
                //
                //          <elem attr="value" />
                //
                // is reported with the same position as
                //
                //          <elem attr = "value" />
                //
                // The first example has no spaces around '=', the second example does.
                //
                while (_reader.MoveToNextAttribute()) {
                    // get line position of the attribute declaration
                    //      <element attr="value"
                    //               ^
                    //               attrLinePosition
                    //
                    int attrLineNumber = _reader.LineNumber;
                    int attrLinePosition = _reader.LinePosition;

                    // Write the whitespace before the attribute
                    utilWriter.AppendRequiredWhiteSpace(lineNumber, linePosition, attrLineNumber, attrLinePosition);

                    // Write the attribute and value
                    int charactersWritten = utilWriter.Write(_reader.Name);
                    charactersWritten += utilWriter.Write('=');
                    charactersWritten += utilWriter.AppendAttributeValue(_reader);

                    // Update position. Note that the attribute value is escaped to always be on a single line.
                    lineNumber = attrLineNumber;
                    linePosition = attrLinePosition + charactersWritten;
                }
            }
            else if (nodeType == XmlNodeType.EndElement) {
                close = ">";

                // get line position after the end element declaration:
                //      </element    >
                //               ^
                //               linePosition
                //
                lineNumber = _reader.LineNumber;
                linePosition = _reader.LinePosition + _reader.Name.Length;

                utilWriter.Write("</");
                utilWriter.Write(_reader.Name);
            }
            else if (nodeType == XmlNodeType.Comment) {
                utilWriter.AppendComment(_reader.Value);
            }
            else if (nodeType == XmlNodeType.Text) {
                utilWriter.AppendEscapeTextString(_reader.Value);
            }
            else if (nodeType == XmlNodeType.XmlDeclaration) {
                close = "?>";

                // get line position after the xml declaration:
                //      <?xml    version="1.0"
                //           ^
                //           linePosition
                //
                lineNumber = _reader.LineNumber;
                linePosition = _reader.LinePosition + 3;

                utilWriter.Write("<?xml");

                //
                // Note that there is no way to get spacing between attribute name and value
                // For example:
                //
                //          <?xml attr="value" ?>
                //
                // is reported with the same position as
                //
                //          <?xml attr = "value" ?>
                //
                // The first example has no spaces around '=', the second example does.
                //
                while (_reader.MoveToNextAttribute()) {
                    // get line position of the attribute declaration
                    //      <?xml    version="1.0"
                    //               ^
                    //               attrLinePosition
                    //
                    int attrLineNumber = _reader.LineNumber;
                    int attrLinePosition = _reader.LinePosition;

                    // Write the whitespace before the attribute
                    utilWriter.AppendRequiredWhiteSpace(lineNumber, linePosition, attrLineNumber, attrLinePosition);

                    // Write the attribute and value
                    int charactersWritten = utilWriter.Write(_reader.Name);
                    charactersWritten += utilWriter.Write('=');
                    charactersWritten += utilWriter.AppendAttributeValue(_reader);

                    // Update position. Note that the attribute value is escaped to always be on a single line.
                    lineNumber = attrLineNumber;
                    linePosition = attrLinePosition + charactersWritten;
                }

                // Position reader at beginning of node
                _reader.MoveToElement();
            }
            else if (nodeType == XmlNodeType.SignificantWhitespace) {
                utilWriter.Write(_reader.Value);
            }
            else if (nodeType == XmlNodeType.ProcessingInstruction) {
                //
                // Note that there is no way to get spacing between attribute name and value
                // For example:
                //
                //          <?pi "value" ?>
                //
                // is reported with the same position as
                //
                //          <?pi    "value" ?>
                //
                // The first example has one space between 'pi' and "value", the second has multiple spaces.
                //
                utilWriter.AppendProcessingInstruction(_reader.Name, _reader.Value);
            }
            else if (nodeType == XmlNodeType.EntityReference) {
                utilWriter.AppendEntityRef(_reader.Name);
            }
            else if (nodeType == XmlNodeType.CDATA) {
                utilWriter.AppendCData(_reader.Value);
            }
            else if (nodeType == XmlNodeType.DocumentType) {
                // 
                // XmlNodeType.DocumentType has the following format:
                //
                //      <!DOCTYPE rootElementName {(SYSTEM uriRef)|(PUBLIC id uriRef)} {[ dtdDecls ]} >
                //
                // The reader only gives us the position of 'rootElementName', so we must track what was
                // written before "<!DOCTYPE" in order to correctly determine the position of the
                // <!DOCTYPE tag
                //
                Debug.Assert(utilWriter.TrackPosition, "utilWriter.TrackPosition");
                int c = utilWriter.Write("<!DOCTYPE");

                // Write the space between <!DOCTYPE and the rootElementName
                utilWriter.AppendRequiredWhiteSpace(_lastLineNumber, _lastLinePosition + c, _reader.LineNumber, _reader.LinePosition);

                // Write the rootElementName
                utilWriter.Write(_reader.Name);

                // Get the dtd declarations, if any
                string dtdValue = null;
                if (_reader.HasValue) {
                    dtdValue = _reader.Value;
                }

                // get line position after the !DOCTYPE declaration:
                //      <!DOCTYPE  rootElement     SYSTEM rootElementDtdUri >
                //                            ^
                //                            linePosition
                lineNumber = _reader.LineNumber;
                linePosition = _reader.LinePosition + _reader.Name.Length;

                // Note that there is no way to get the spacing after PUBLIC or SYSTEM attributes and their values
                if (_reader.MoveToFirstAttribute()) {
                    // Write the space before SYSTEM or PUBLIC
                    utilWriter.AppendRequiredWhiteSpace(lineNumber, linePosition, _reader.LineNumber, _reader.LinePosition); 

                    // Write SYSTEM or PUBLIC and the 1st value of the attribute
                    string attrName = _reader.Name;
                    utilWriter.Write(attrName);
                    utilWriter.AppendSpace();
                    utilWriter.AppendAttributeValue(_reader);
                    _reader.MoveToAttribute(0);
                    
                    // If PUBLIC, write the second value of the attribute
                    if (attrName == "PUBLIC") {
                        _reader.MoveToAttribute(1);
                        utilWriter.AppendSpace();
                        utilWriter.AppendAttributeValue(_reader);
                        _reader.MoveToAttribute(1);
                    }
                }

                // If there is a dtd, write it
                if (dtdValue != null && dtdValue.Length > 0) {
                    utilWriter.Write(" [");
                    utilWriter.Write(dtdValue);
                    utilWriter.Write(']');
                }

                utilWriter.Write('>');
            }

            // Advance the _reader so we can get the position of the next node.
            bool moreToRead = _reader.Read();
            nodeType = _reader.NodeType;

            // Close the node we are copying.
            if (close != null) {
                //
                // Find the position of the close string, for example:
                //
                //          <element      >  <subElement />
                //                        ^
                //                        closeLinePosition
                //
                int startOffset = GetPositionOffset(nodeType);
                int closeLineNumber = _reader.LineNumber;
                int closeLinePosition = _reader.LinePosition - startOffset - close.Length;

                // Add whitespace up to the position of the close string
                utilWriter.AppendWhiteSpace(lineNumber, linePosition, closeLineNumber, closeLinePosition);

                // Write the close string
                utilWriter.Write(close);
            }

            //
            // Track the position of the reader based on the position of the reader
            // before we copied this node and what we have written in copying the node.
            // This allows us to determine the position of the <!DOCTYPE tag.
            //
            if (utilWriter.TrackPosition) {
                _lastLineNumber = (readerLineNumber - writerLineNumber) + utilWriter.LineNumber;

                if (writerLineNumber == utilWriter.LineNumber) {
                    _lastLinePosition = (readerLinePosition - writerLinePosition) + utilWriter.LinePosition;
                }
                else {
                    _lastLinePosition = utilWriter.LinePosition;
                }
            }

            return moreToRead;
        }
 private void CreateNewConfigSource(XmlUtilWriter utilWriter, string updatedXml, int indent) {
     string formattedXml = XmlUtil.FormatXmlElement(updatedXml, 0, indent, true);
     utilWriter.Write(string.Format(CultureInfo.InvariantCulture, FORMAT_CONFIGSOURCE_FILE, ConfigStreamInfo.StreamEncoding.WebName));
     utilWriter.Write(formattedXml + NL);
 }
        //
        // Copy or replace an element node.
        // If the element is an empty element, replace it with a formatted start element if either:
        //   * The contents of the start element string need updating.
        //   * The element needs to contain child elements.
        //
        // If the element is empty and is replaced with a start/end element pair, return a 
        // end element string with whitespace formatting; otherwise return null.
        //
        internal string UpdateStartElement(XmlUtilWriter utilWriter, string updatedStartElement, bool needsChildren, int linePosition, int indent) {
            Debug.Assert(_reader.NodeType == XmlNodeType.Element, "_reader.NodeType == NodeType.Element");

            string  endElement = null;
            bool    needsEndElement = false;
            string  elementName;

            elementName = _reader.Name;

            // If the element is empty, determine if a new end element is needed.
            if (_reader.IsEmptyElement) {
                if (updatedStartElement == null && needsChildren) {
                    updatedStartElement = RetrieveFullOpenElementTag();
                }

                needsEndElement = (updatedStartElement != null);
            }

            if (updatedStartElement == null) {
                //
                // If no changes to the start element are required, just copy it.
                //
                CopyXmlNode(utilWriter);
            }
            else {
                //
                // Format a new start element/end element pair
                //
                string updatedEndElement = "</" + elementName + ">";
                string updatedElement = updatedStartElement + updatedEndElement;
                string formattedElement = FormatXmlElement(updatedElement, linePosition, indent, true);

                //
                // Get the start and end element strings from the formatted element.
                //
                int iEndElement = formattedElement.LastIndexOf('\n') + 1;
                string startElement;
                if (needsEndElement) {
                    endElement = formattedElement.Substring(iEndElement);

                    // Include a newline in the start element as we are expanding an empty element.
                    startElement = formattedElement.Substring(0, iEndElement);
                }
                else {
                    // Omit the newline from the start element.
                    startElement = formattedElement.Substring(0, iEndElement - 2);
                }

                // Write the new start element.
                utilWriter.Write(startElement);

                // Skip over the existing start element.
                _reader.Read();
            }

            return endElement;
        }
        //
        // Copy an XML element but skip all its child elements, then continue copying until we've hit the next element.
        //
        internal bool SkipChildElementsAndCopyOuterXmlToNextElement(XmlUtilWriter utilWriter) {
            bool    isEmptyElement = _reader.IsEmptyElement;
            int     startingLine = _reader.LineNumber;
#if DBG
            int     depth = _reader.Depth;
#endif

            Debug.Assert(_reader.NodeType == XmlNodeType.Element, "_reader.NodeType == XmlNodeType.Element");

            CopyXmlNode(utilWriter);

            // See if we need to skip any child element
            if (!isEmptyElement) {
                while (_reader.NodeType != XmlNodeType.EndElement) {
                    
                    // Skip all the inner child elements
                    if (_reader.NodeType == XmlNodeType.Element) {
                        _reader.Skip();

                        // We need to skip all the whitespaces following a skipped element.
                        // - If the whitespaces don't contain /r/n, then it's okay to skip them 
                        //   as part of the element.
                        // - If the whitespaces contain /r/n, not skipping them will result
                        //   in a redundant emtpy line being copied.
                        if (_reader.NodeType == XmlNodeType.Whitespace) {
                            _reader.Skip();
                        }
                    }
                    else {
                        // We want to preserve other content, e.g. comments.
                        CopyXmlNode(utilWriter);
                    }
                }

                if (_reader.LineNumber != startingLine) {
                    // The whitespace in front of the EndElement was skipped above.
                    // We need to append spaces to compensate for that.
                    utilWriter.AppendSpacesToLinePosition(TrueLinePosition);
                }


#if DBG                
                Debug.Assert(_reader.Depth == depth, "We should be at the same depth as the opening Element");
#endif
                    
                // Copy the end element.
                CopyXmlNode(utilWriter);
            }                

            return CopyReaderToNextElement(utilWriter, true);
        }
 internal string UpdateStartElement(XmlUtilWriter utilWriter, string updatedStartElement, bool needsChildren, int linePosition, int indent)
 {
     string str = null;
     string str6;
     bool flag = false;
     string name = this._reader.Name;
     if (this._reader.IsEmptyElement)
     {
         if ((updatedStartElement == null) && needsChildren)
         {
             updatedStartElement = this.RetrieveFullOpenElementTag();
         }
         flag = updatedStartElement != null;
     }
     if (updatedStartElement == null)
     {
         this.CopyXmlNode(utilWriter);
         return str;
     }
     string str5 = FormatXmlElement(updatedStartElement + ("</" + name + ">"), linePosition, indent, true);
     int startIndex = str5.LastIndexOf('\n') + 1;
     if (flag)
     {
         str = str5.Substring(startIndex);
         str6 = str5.Substring(0, startIndex);
     }
     else
     {
         str6 = str5.Substring(0, startIndex - 2);
     }
     utilWriter.Write(str6);
     this._reader.Read();
     return str;
 }