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(true, 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)) {
}
}
}
}