You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@ -0,0 +1,459 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="XmlUtilWriter.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Configuration {
|
||||
using System.Configuration.Internal;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Net;
|
||||
|
||||
//
|
||||
// A utility class for writing XML to a TextWriter.
|
||||
//
|
||||
// When this class is used to copy an XML document that may include a "<!DOCTYPE" directive,
|
||||
// we must track what is written until the "<!DOCTYPE" or first document element is found.
|
||||
// This is needed because the XML reader does not give us accurate spacing information
|
||||
// for the beginning of the "<!DOCTYPE" element.
|
||||
//
|
||||
// Note that tracking this information is expensive, as it requires a scan of everything that is written
|
||||
// until "<!DOCTYPE" or the first element is found.
|
||||
//
|
||||
// Note also that this class is used at runtime to copy sections, so performance of all
|
||||
// writing functions directly affects application startup time.
|
||||
//
|
||||
internal class XmlUtilWriter {
|
||||
private const char SPACE = ' ';
|
||||
private const string NL = "\r\n";
|
||||
|
||||
private static string SPACES_8;
|
||||
private static string SPACES_4;
|
||||
private static string SPACES_2;
|
||||
|
||||
private TextWriter _writer; // the wrapped text writer
|
||||
private Stream _baseStream; // stream under TextWriter when tracking position
|
||||
private bool _trackPosition; // should write position be tracked?
|
||||
private int _lineNumber; // line number
|
||||
private int _linePosition; // line position
|
||||
private bool _isLastLineBlank; // is the last line blank?
|
||||
private object _lineStartCheckpoint; // checkpoint taken at the start of each line
|
||||
|
||||
static XmlUtilWriter() {
|
||||
SPACES_8 = new String(SPACE, 8);
|
||||
SPACES_4 = new String(SPACE, 4);
|
||||
SPACES_2 = new String(SPACE, 2);
|
||||
}
|
||||
|
||||
internal XmlUtilWriter(TextWriter writer, bool trackPosition) {
|
||||
_writer = writer;
|
||||
_trackPosition = trackPosition;
|
||||
_lineNumber = 1;
|
||||
_linePosition = 1;
|
||||
_isLastLineBlank = true;
|
||||
|
||||
if (_trackPosition) {
|
||||
_baseStream = ((StreamWriter)_writer).BaseStream;
|
||||
_lineStartCheckpoint = CreateStreamCheckpoint();
|
||||
}
|
||||
}
|
||||
|
||||
internal TextWriter Writer {
|
||||
get {
|
||||
return _writer;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool TrackPosition {
|
||||
get {
|
||||
return _trackPosition;
|
||||
}
|
||||
}
|
||||
|
||||
internal int LineNumber {
|
||||
get {
|
||||
return _lineNumber;
|
||||
}
|
||||
}
|
||||
|
||||
internal int LinePosition {
|
||||
get {
|
||||
return _linePosition;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsLastLineBlank {
|
||||
get {
|
||||
return _isLastLineBlank;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Update the position after the character is written to the stream.
|
||||
//
|
||||
private void UpdatePosition(char ch) {
|
||||
switch (ch) {
|
||||
case '\r':
|
||||
_lineNumber++;
|
||||
_linePosition = 1;
|
||||
_isLastLineBlank = true;
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
_lineStartCheckpoint = CreateStreamCheckpoint();
|
||||
break;
|
||||
|
||||
case SPACE:
|
||||
case '\t':
|
||||
_linePosition++;
|
||||
break;
|
||||
|
||||
default:
|
||||
_linePosition++;
|
||||
_isLastLineBlank = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Write a string to _writer.
|
||||
// If we are tracking position, determine the line number and position
|
||||
//
|
||||
internal int Write(string s) {
|
||||
if (_trackPosition) {
|
||||
for (int i = 0; i < s.Length; i++) {
|
||||
char ch = s[i];
|
||||
_writer.Write(ch);
|
||||
UpdatePosition(ch);
|
||||
}
|
||||
}
|
||||
else {
|
||||
_writer.Write(s);
|
||||
}
|
||||
|
||||
#if DEBUG_WRITE
|
||||
Flush();
|
||||
#endif
|
||||
|
||||
return s.Length;
|
||||
}
|
||||
|
||||
//
|
||||
// Write a character to _writer.
|
||||
// If we are tracking position, determine the line number and position
|
||||
//
|
||||
internal int Write(char ch) {
|
||||
_writer.Write(ch);
|
||||
if (_trackPosition) {
|
||||
UpdatePosition(ch);
|
||||
}
|
||||
#if DEBUG_WRITE
|
||||
Flush();
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
internal void Flush() {
|
||||
_writer.Flush();
|
||||
}
|
||||
|
||||
// Escape a text string
|
||||
internal int AppendEscapeTextString(string s) {
|
||||
return AppendEscapeXmlString(s, false, 'A');
|
||||
}
|
||||
|
||||
// Escape a XML string to preserve XML markup.
|
||||
internal int AppendEscapeXmlString(string s, bool inAttribute, char quoteChar) {
|
||||
int charactersWritten = 0;
|
||||
for (int i = 0; i < s.Length; i++) {
|
||||
char ch = s[i];
|
||||
|
||||
bool appendCharEntity = false;
|
||||
string entityRef = null;
|
||||
if ((ch < 32 && ch != '\t' && ch != '\r' && ch != '\n') || (ch > 0xFFFD)) {
|
||||
appendCharEntity = true;
|
||||
}
|
||||
else {
|
||||
switch (ch)
|
||||
{
|
||||
case '<':
|
||||
entityRef = "lt";
|
||||
break;
|
||||
|
||||
case '>':
|
||||
entityRef = "gt";
|
||||
break;
|
||||
|
||||
case '&':
|
||||
entityRef = "amp";
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
if (inAttribute && quoteChar == ch) {
|
||||
entityRef = "apos";
|
||||
}
|
||||
break;
|
||||
|
||||
case '"':
|
||||
if (inAttribute && quoteChar == ch) {
|
||||
entityRef = "quot";
|
||||
}
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
case '\r':
|
||||
appendCharEntity = inAttribute;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (appendCharEntity) {
|
||||
charactersWritten += AppendCharEntity(ch);
|
||||
}
|
||||
else if (entityRef != null) {
|
||||
charactersWritten += AppendEntityRef(entityRef);
|
||||
}
|
||||
else {
|
||||
charactersWritten += Write(ch);
|
||||
}
|
||||
}
|
||||
|
||||
return charactersWritten;
|
||||
}
|
||||
|
||||
internal int AppendEntityRef(string entityRef) {
|
||||
Write('&');
|
||||
Write(entityRef);
|
||||
Write(';');
|
||||
return entityRef.Length + 2;
|
||||
}
|
||||
|
||||
internal int AppendCharEntity(char ch) {
|
||||
string numberToWrite = ((int)ch).ToString("X", CultureInfo.InvariantCulture);
|
||||
Write('&');
|
||||
Write('#');
|
||||
Write('x');
|
||||
Write(numberToWrite);
|
||||
Write(';');
|
||||
return numberToWrite.Length + 4;
|
||||
}
|
||||
|
||||
internal int AppendCData(string cdata) {
|
||||
Write("<![CDATA[");
|
||||
Write(cdata);
|
||||
Write("]]>");
|
||||
return cdata.Length + 12;
|
||||
}
|
||||
|
||||
internal int AppendProcessingInstruction(string name, string value) {
|
||||
Write("<?");
|
||||
Write(name);
|
||||
AppendSpace();
|
||||
Write(value);
|
||||
Write("?>");
|
||||
return name.Length + value.Length + 5;
|
||||
}
|
||||
|
||||
internal int AppendComment(string comment) {
|
||||
Write("<!--");
|
||||
Write(comment);
|
||||
Write("-->");
|
||||
return comment.Length + 7;
|
||||
}
|
||||
|
||||
internal int AppendAttributeValue(XmlTextReader reader) {
|
||||
int charactersWritten = 0;
|
||||
char quote = reader.QuoteChar;
|
||||
|
||||
//
|
||||
// In !DOCTYPE, quote is '\0' for second public attribute.
|
||||
// Protect ourselves from writing invalid XML by always
|
||||
// supplying a valid quote char.
|
||||
//
|
||||
if (quote != '"' && quote != '\'') {
|
||||
quote = '"';
|
||||
}
|
||||
|
||||
charactersWritten += Write(quote);
|
||||
while (reader.ReadAttributeValue()) {
|
||||
if (reader.NodeType == XmlNodeType.Text) {
|
||||
charactersWritten += AppendEscapeXmlString(reader.Value, true, quote);
|
||||
}
|
||||
else {
|
||||
charactersWritten += AppendEntityRef(reader.Name);
|
||||
}
|
||||
}
|
||||
|
||||
charactersWritten += Write(quote);
|
||||
return charactersWritten;
|
||||
}
|
||||
|
||||
// Append whitespace, ensuring there is at least one space.
|
||||
internal int AppendRequiredWhiteSpace(int fromLineNumber, int fromLinePosition, int toLineNumber, int toLinePosition) {
|
||||
int charactersWritten = AppendWhiteSpace(fromLineNumber, fromLinePosition, toLineNumber, toLinePosition);
|
||||
if (charactersWritten == 0) {
|
||||
charactersWritten += AppendSpace();
|
||||
}
|
||||
|
||||
return charactersWritten;
|
||||
}
|
||||
|
||||
|
||||
// Append whitespce
|
||||
internal int AppendWhiteSpace(int fromLineNumber, int fromLinePosition, int toLineNumber, int toLinePosition) {
|
||||
int charactersWritten = 0;
|
||||
while (fromLineNumber++ < toLineNumber) {
|
||||
charactersWritten += AppendNewLine();
|
||||
fromLinePosition = 1;
|
||||
}
|
||||
|
||||
charactersWritten += AppendSpaces(toLinePosition - fromLinePosition);
|
||||
return charactersWritten;
|
||||
}
|
||||
|
||||
//
|
||||
// Append indent
|
||||
// linePosition - starting line position
|
||||
// indent - number of spaces to indent each unit of depth
|
||||
// depth - depth to indent
|
||||
// newLine - insert new line before indent?
|
||||
//
|
||||
internal int AppendIndent(int linePosition, int indent, int depth, bool newLine) {
|
||||
int charactersWritten = 0;
|
||||
if (newLine) {
|
||||
charactersWritten += AppendNewLine();
|
||||
}
|
||||
|
||||
int c = (linePosition - 1) + (indent * depth);
|
||||
charactersWritten += AppendSpaces(c);
|
||||
return charactersWritten;
|
||||
}
|
||||
|
||||
//
|
||||
// AppendSpacesToLinePosition
|
||||
//
|
||||
// Write spaces up to the line position, taking into account the
|
||||
// current line position of the writer.
|
||||
//
|
||||
internal int AppendSpacesToLinePosition(int linePosition) {
|
||||
Debug.Assert(_trackPosition, "_trackPosition");
|
||||
|
||||
if (linePosition <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int delta = linePosition - _linePosition;
|
||||
if (delta < 0 && IsLastLineBlank) {
|
||||
SeekToLineStart();
|
||||
}
|
||||
|
||||
return AppendSpaces(linePosition - _linePosition);
|
||||
}
|
||||
|
||||
//
|
||||
// Append a new line
|
||||
//
|
||||
internal int AppendNewLine() {
|
||||
return Write(NL);
|
||||
}
|
||||
|
||||
//
|
||||
// AppendSpaces
|
||||
//
|
||||
// Write spaces to the writer provided. Since we do not want waste
|
||||
// memory by allocating do not use "new String(' ', count)".
|
||||
//
|
||||
internal int AppendSpaces(int count) {
|
||||
int c = count;
|
||||
while (c > 0) {
|
||||
if (c >= 8) {
|
||||
Write(SPACES_8);
|
||||
c -= 8;
|
||||
}
|
||||
else if (c >= 4) {
|
||||
Write(SPACES_4);
|
||||
c -= 4;
|
||||
}
|
||||
else if (c >= 2) {
|
||||
Write(SPACES_2);
|
||||
c -= 2;
|
||||
}
|
||||
else {
|
||||
Write(SPACE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (count > 0) ? count : 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Append a single space character
|
||||
//
|
||||
internal int AppendSpace() {
|
||||
return Write(SPACE);
|
||||
}
|
||||
|
||||
//
|
||||
// Reset the stream to the beginning of the current blank line.
|
||||
//
|
||||
internal void SeekToLineStart() {
|
||||
Debug.Assert(_isLastLineBlank, "_isLastLineBlank");
|
||||
RestoreStreamCheckpoint(_lineStartCheckpoint);
|
||||
}
|
||||
|
||||
// Create a checkpoint that can be restored with RestoreStreamCheckpoint().
|
||||
internal object CreateStreamCheckpoint() {
|
||||
return new StreamWriterCheckpoint(this);
|
||||
}
|
||||
|
||||
// Restore the writer state that was recorded with CreateStreamCheckpoint().
|
||||
internal void RestoreStreamCheckpoint(object o) {
|
||||
StreamWriterCheckpoint checkpoint = (StreamWriterCheckpoint) o;
|
||||
|
||||
Flush();
|
||||
|
||||
_lineNumber = checkpoint._lineNumber;
|
||||
_linePosition = checkpoint._linePosition;
|
||||
_isLastLineBlank = checkpoint._isLastLineBlank;
|
||||
|
||||
_baseStream.Seek(checkpoint._streamPosition, SeekOrigin.Begin);
|
||||
_baseStream.SetLength(checkpoint._streamLength);
|
||||
_baseStream.Flush();
|
||||
}
|
||||
|
||||
// Class that contains the state of the writer and its underlying stream.
|
||||
private class StreamWriterCheckpoint {
|
||||
internal int _lineNumber; // line number
|
||||
internal int _linePosition; // line position
|
||||
internal bool _isLastLineBlank; // is the last line blank?
|
||||
internal long _streamLength; // length of the stream
|
||||
internal long _streamPosition; // position of the stream pointer
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user