//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ // HtmlTextWriter.cs // namespace System.Web.UI { using System; using System.Collections; using System.Collections.Specialized; using System.IO; using System.Text; using System.Globalization; using System.Security.Permissions; using System.Web.UI.WebControls; using System.Web.Util; public class HtmlTextWriter : TextWriter { private Layout _currentLayout = new Layout(HorizontalAlign.NotSet, true /* wrap */); private Layout _currentWrittenLayout = null; internal virtual bool RenderDivAroundHiddenInputs { get { return true; } } public virtual void EnterStyle(Style style, HtmlTextWriterTag tag) { if (!style.IsEmpty || tag != HtmlTextWriterTag.Span) { style.AddAttributesToRender(this); RenderBeginTag(tag); } } public virtual void ExitStyle(System.Web.UI.WebControls.Style style, HtmlTextWriterTag tag) { // Review: This requires that the style doesn't change between beginstyle/endstyle. if (!style.IsEmpty || tag != HtmlTextWriterTag.Span) { RenderEndTag(); } } internal virtual void OpenDiv() { OpenDiv(_currentLayout, (_currentLayout != null) && (_currentLayout.Align != HorizontalAlign.NotSet), (_currentLayout != null) && !_currentLayout.Wrap); } private void OpenDiv(Layout layout, bool writeHorizontalAlign, bool writeWrapping) { WriteBeginTag("div"); if (writeHorizontalAlign) { String alignment; switch (layout.Align) { case HorizontalAlign.Right: alignment = "text-align:right"; break; case HorizontalAlign.Center: alignment = "text-align:center"; break; default: alignment = "text-align:left"; break; } WriteAttribute("style", alignment); } if (writeWrapping) { WriteAttribute("mode", layout.Wrap == true ? "wrap" : "nowrap"); } Write('>'); _currentWrittenLayout = layout; } public virtual bool IsValidFormAttribute(String attribute) { return true; } private TextWriter writer; private int indentLevel; private bool tabsPending; private string tabString; public const char TagLeftChar = '<'; public const char TagRightChar = '>'; public const string SelfClosingChars = " /"; public const string SelfClosingTagEnd = " />"; public const string EndTagLeftChars = "= 0, "Bogus Indent... probably caused by mismatched Indent++ and Indent--"); if (value < 0) { value = 0; } indentLevel = value; } } //Gets or sets the TextWriter to use. public TextWriter InnerWriter { get { return writer; } set { writer = value; _httpWriter = value as HttpWriter; } } /* // */ public virtual void BeginRender() { } //Closes the document being written to. public override void Close() { writer.Close(); } public virtual void EndRender() { } public virtual void EnterStyle(System.Web.UI.WebControls.Style style) { EnterStyle(style, HtmlTextWriterTag.Span); } public virtual void ExitStyle(System.Web.UI.WebControls.Style style) { ExitStyle(style, HtmlTextWriterTag.Span); } public override void Flush() { writer.Flush(); } protected virtual void OutputTabs() { if (tabsPending) { for (int i=0; i < indentLevel; i++) { writer.Write(tabString); } tabsPending = false; } } //Writes a string to the text stream. public override void Write(string s) { if (tabsPending) { OutputTabs(); } writer.Write(s); } //Writes the text representation of a Boolean value to the text stream. public override void Write(bool value) { if (tabsPending) { OutputTabs(); } writer.Write(value); } //Writes a character to the text stream. public override void Write(char value) { if (tabsPending) { OutputTabs(); } writer.Write(value); } // Writes a character array to the text stream. public override void Write(char[] buffer) { if (tabsPending) { OutputTabs(); } writer.Write(buffer); } // Writes a subarray of characters to the text stream. public override void Write(char[] buffer, int index, int count) { if (tabsPending) { OutputTabs(); } writer.Write(buffer, index, count); } // Writes the text representation of a Double to the text stream. public override void Write(double value) { if (tabsPending) { OutputTabs(); } writer.Write(value); } // Writes the text representation of a Single to the text stream. public override void Write(float value) { if (tabsPending) { OutputTabs(); } writer.Write(value); } // Writes the text representation of an integer to the text stream. public override void Write(int value) { if (tabsPending) { OutputTabs(); } writer.Write(value); } // Writes the text representation of an 8-byte integer to the text stream. public override void Write(long value) { if (tabsPending) { OutputTabs(); } writer.Write(value); } // Writes the text representation of an object to the text stream. public override void Write(object value) { if (tabsPending) { OutputTabs(); } writer.Write(value); } // Writes out a formatted string, using the same semantics as specified. public override void Write(string format, object arg0) { if (tabsPending) { OutputTabs(); } writer.Write(format, arg0); } // Writes out a formatted string, using the same semantics as specified. public override void Write(string format, object arg0, object arg1) { if (tabsPending) { OutputTabs(); } writer.Write(format, arg0, arg1); } // Writes out a formatted string, using the same semantics as specified. public override void Write(string format, params object[] arg) { if (tabsPending) { OutputTabs(); } writer.Write(format, arg); } // Writes the specified string to a line without tabs. public void WriteLineNoTabs(string s) { writer.WriteLine(s); tabsPending = true; } // Writes the specified string followed by a line terminator to the text stream. public override void WriteLine(string s) { if (tabsPending) { OutputTabs(); } writer.WriteLine(s); tabsPending = true; } // Writes a line terminator. public override void WriteLine() { writer.WriteLine(); tabsPending = true; } // Writes the text representation of a Boolean followed by a line terminator to the text stream. public override void WriteLine(bool value) { if (tabsPending) { OutputTabs(); } writer.WriteLine(value); tabsPending = true; } public override void WriteLine(char value) { if (tabsPending) { OutputTabs(); } writer.WriteLine(value); tabsPending = true; } public override void WriteLine(char[] buffer) { if (tabsPending) { OutputTabs(); } writer.WriteLine(buffer); tabsPending = true; } public override void WriteLine(char[] buffer, int index, int count) { if (tabsPending) { OutputTabs(); } writer.WriteLine(buffer, index, count); tabsPending = true; } public override void WriteLine(double value) { if (tabsPending) { OutputTabs(); } writer.WriteLine(value); tabsPending = true; } public override void WriteLine(float value) { if (tabsPending) { OutputTabs(); } writer.WriteLine(value); tabsPending = true; } public override void WriteLine(int value) { if (tabsPending) { OutputTabs(); } writer.WriteLine(value); tabsPending = true; } public override void WriteLine(long value) { if (tabsPending) { OutputTabs(); } writer.WriteLine(value); tabsPending = true; } public override void WriteLine(object value) { if (tabsPending) { OutputTabs(); } writer.WriteLine(value); tabsPending = true; } public override void WriteLine(string format, object arg0) { if (tabsPending) { OutputTabs(); } writer.WriteLine(format, arg0); tabsPending = true; } public override void WriteLine(string format, object arg0, object arg1) { if (tabsPending) { OutputTabs(); } writer.WriteLine(format, arg0, arg1); tabsPending = true; } public override void WriteLine(string format, params object[] arg) { if (tabsPending) { OutputTabs(); } writer.WriteLine(format, arg); tabsPending = true; } [CLSCompliant(false)] public override void WriteLine(UInt32 value) { if (tabsPending) { OutputTabs(); } writer.WriteLine(value); tabsPending = true; } protected static void RegisterTag(string name, HtmlTextWriterTag key) { RegisterTag(name, key, TagType.Other); } private static void RegisterTag(string name, HtmlTextWriterTag key, TagType type) { string nameLCase = name.ToLower(CultureInfo.InvariantCulture); _tagKeyLookupTable.Add(nameLCase, key); // Pre-resolve the end tag string endTag = null; if (type != TagType.NonClosing && key != HtmlTextWriterTag.Unknown) { endTag = EndTagLeftChars + nameLCase + TagRightChar.ToString(CultureInfo.InvariantCulture); } if ((int)key < _tagNameLookupArray.Length) { _tagNameLookupArray[(int)key] = new TagInformation(name, type, endTag); } } protected static void RegisterAttribute(string name, HtmlTextWriterAttribute key) { RegisterAttribute(name, key, false); } private static void RegisterAttribute(string name, HtmlTextWriterAttribute key, bool encode) { RegisterAttribute(name, key, encode, false); } private static void RegisterAttribute(string name, HtmlTextWriterAttribute key, bool encode, bool isUrl) { string nameLCase = name.ToLower(CultureInfo.InvariantCulture); _attrKeyLookupTable.Add(nameLCase, key); if ((int)key < _attrNameLookupArray.Length) { _attrNameLookupArray[(int)key] = new AttributeInformation(name, encode, isUrl); } } protected static void RegisterStyle(string name, HtmlTextWriterStyle key) { CssTextWriter.RegisterAttribute(name, key); } public HtmlTextWriter(TextWriter writer) : this(writer, DefaultTabString) { } public HtmlTextWriter(TextWriter writer, string tabString) : base(CultureInfo.InvariantCulture) { this.writer = writer; this.tabString = tabString; indentLevel = 0; tabsPending = false; // If it's an http writer, save it _httpWriter = writer as HttpWriter; _isDescendant = (GetType() != typeof(HtmlTextWriter)); _attrCount = 0; _styleCount = 0; _endTagCount = 0; _inlineCount = 0; } protected HtmlTextWriterTag TagKey { get { return _tagKey; } set { _tagIndex = (int) value; if (_tagIndex < 0 || _tagIndex >= _tagNameLookupArray.Length) { throw new ArgumentOutOfRangeException("value"); } _tagKey = value; // If explicitly setting to uknown, keep the old tag name. This allows a string tag // to be set without clobbering it if setting TagKey to itself. if (value != HtmlTextWriterTag.Unknown) { _tagName = _tagNameLookupArray[_tagIndex].name; } } } protected string TagName { get { return _tagName; } set { _tagName = value; _tagKey = GetTagKey(_tagName); _tagIndex = (int) _tagKey; Debug.Assert(_tagIndex >= 0 && _tagIndex < _tagNameLookupArray.Length); } } public virtual void AddAttribute(string name,string value) { HtmlTextWriterAttribute attributeKey = GetAttributeKey(name); value = EncodeAttributeValue(attributeKey, value); AddAttribute(name, value, attributeKey); } //do not fix this spelling error //believe it or not, it is a backwards breaking change for languages that //support late binding with named parameters VB.Net public virtual void AddAttribute(string name,string value, bool fEndode) { value = EncodeAttributeValue(value, fEndode); AddAttribute(name, value, GetAttributeKey(name)); } public virtual void AddAttribute(HtmlTextWriterAttribute key,string value) { int attributeIndex = (int) key; if (attributeIndex >= 0 && attributeIndex < _attrNameLookupArray.Length) { AttributeInformation info = _attrNameLookupArray[attributeIndex]; AddAttribute(info.name,value,key, info.encode, info.isUrl); } } public virtual void AddAttribute(HtmlTextWriterAttribute key,string value, bool fEncode) { int attributeIndex = (int) key; if (attributeIndex >= 0 && attributeIndex < _attrNameLookupArray.Length) { AttributeInformation info = _attrNameLookupArray[attributeIndex]; AddAttribute(info.name,value,key, fEncode, info.isUrl); } } protected virtual void AddAttribute(string name, string value, HtmlTextWriterAttribute key) { AddAttribute(name, value, key, false, false); } private void AddAttribute(string name, string value, HtmlTextWriterAttribute key, bool encode, bool isUrl) { if(_attrList == null) { _attrList = new RenderAttribute[20]; } else if (_attrCount >= _attrList.Length) { RenderAttribute[] newArray = new RenderAttribute[_attrList.Length * 2]; Array.Copy(_attrList, newArray, _attrList.Length); _attrList = newArray; } RenderAttribute attr; attr.name = name; attr.value = value; attr.key = key; attr.encode = encode; attr.isUrl = isUrl; _attrList[_attrCount] = attr; _attrCount++; } public virtual void AddStyleAttribute(string name, string value) { AddStyleAttribute(name, value, CssTextWriter.GetStyleKey(name)); } public virtual void AddStyleAttribute(HtmlTextWriterStyle key, string value) { AddStyleAttribute(CssTextWriter.GetStyleName(key), value, key); } protected virtual void AddStyleAttribute(string name, string value, HtmlTextWriterStyle key) { if(_styleList == null) { _styleList = new RenderStyle[20]; } else if (_styleCount > _styleList.Length) { RenderStyle[] newArray = new RenderStyle[_styleList.Length * 2]; Array.Copy(_styleList, newArray, _styleList.Length); _styleList = newArray; } RenderStyle style; style.name = name; style.key = key; string attributeValue = value; if (CssTextWriter.IsStyleEncoded(key)) { // note that only css attributes in an inline style value need to be attribute encoded // since CssTextWriter is used to render both embedded stylesheets and style attributes // the attribute encoding is done here. attributeValue = HttpUtility.HtmlAttributeEncode(value); } style.value = attributeValue; _styleList[_styleCount] = style; _styleCount++; } protected string EncodeAttributeValue(string value, bool fEncode) { if (value == null) { return null; } if (!fEncode) return value; return HttpUtility.HtmlAttributeEncode(value); } protected virtual string EncodeAttributeValue(HtmlTextWriterAttribute attrKey, string value) { bool encode = true; if (0 <= (int)attrKey && (int)attrKey < _attrNameLookupArray.Length) { encode = _attrNameLookupArray[(int)attrKey].encode; } return EncodeAttributeValue(value, encode); } // This does minimal URL encoding by converting spaces in the url to "%20". protected string EncodeUrl(string url) { // VSWhidbey 454348: escaped spaces in UNC share paths don't work in IE, so // we're not going to encode if it's a share. if (!UrlPath.IsUncSharePath(url)) { return HttpUtility.UrlPathEncode(url); } return url; } protected HtmlTextWriterAttribute GetAttributeKey(string attrName) { if (!String.IsNullOrEmpty(attrName)) { object key = _attrKeyLookupTable[attrName.ToLower(CultureInfo.InvariantCulture)]; if (key != null) return(HtmlTextWriterAttribute)key; } return(HtmlTextWriterAttribute)(-1); } protected string GetAttributeName(HtmlTextWriterAttribute attrKey) { if ((int)attrKey >= 0 && (int)attrKey < _attrNameLookupArray.Length) return _attrNameLookupArray[(int)attrKey].name; return string.Empty; } protected HtmlTextWriterStyle GetStyleKey(string styleName) { return CssTextWriter.GetStyleKey(styleName); } protected string GetStyleName(HtmlTextWriterStyle styleKey) { return CssTextWriter.GetStyleName(styleKey); } protected virtual HtmlTextWriterTag GetTagKey(string tagName) { if (!String.IsNullOrEmpty(tagName)) { object key = _tagKeyLookupTable[tagName.ToLower(CultureInfo.InvariantCulture)]; if (key != null) return(HtmlTextWriterTag)key; } return HtmlTextWriterTag.Unknown; } protected virtual string GetTagName(HtmlTextWriterTag tagKey) { int tagIndex = (int) tagKey; if (tagIndex >= 0 && tagIndex < _tagNameLookupArray.Length) return _tagNameLookupArray[tagIndex].name; return string.Empty; } protected bool IsAttributeDefined(HtmlTextWriterAttribute key) { for (int i = 0; i < _attrCount; i++) { if (_attrList[i].key == key) { return true; } } return false; } protected bool IsAttributeDefined(HtmlTextWriterAttribute key, out string value) { value = null; for (int i = 0; i < _attrCount; i++) { if (_attrList[i].key == key) { value = _attrList[i].value; return true; } } return false; } protected bool IsStyleAttributeDefined(HtmlTextWriterStyle key) { for (int i = 0; i < _styleCount; i++) { if (_styleList[i].key == key) { return true; } } return false; } protected bool IsStyleAttributeDefined(HtmlTextWriterStyle key, out string value) { value = null; for (int i = 0; i < _styleCount; i++) { if (_styleList[i].key == key) { value = _styleList[i].value; return true; } } return false; } protected virtual bool OnAttributeRender(string name, string value, HtmlTextWriterAttribute key) { return true; } protected virtual bool OnStyleAttributeRender(string name, string value, HtmlTextWriterStyle key) { return true; } protected virtual bool OnTagRender(string name, HtmlTextWriterTag key) { return true; } protected string PopEndTag() { if (_endTagCount <= 0) { throw new InvalidOperationException(SR.GetString(SR.HTMLTextWriterUnbalancedPop)); } _endTagCount--; TagKey = _endTags[_endTagCount].tagKey; return _endTags[_endTagCount].endTagText; } protected void PushEndTag(string endTag) { if(_endTags == null) { _endTags = new TagStackEntry[16]; } else if (_endTagCount >= _endTags.Length) { TagStackEntry[] newArray = new TagStackEntry[_endTags.Length * 2]; Array.Copy(_endTags, newArray, _endTags.Length); _endTags = newArray; } _endTags[_endTagCount].tagKey = _tagKey; _endTags[_endTagCount].endTagText= endTag; _endTagCount++; } // This calls filers out all attributes and style attributes by calling OnAttributeRender // and OnStyleAttributeRender on all properites and updates the lists protected virtual void FilterAttributes() { // Create the filtered list of styles int newStyleCount = 0; for (int i = 0; i < _styleCount; i++) { RenderStyle style = _styleList[i]; if (OnStyleAttributeRender(style.name, style.value, style.key)) { // Update the list. This can be done in place _styleList[newStyleCount] = style; newStyleCount++; } } // Update the count _styleCount = newStyleCount; // Create the filtered list of attributes int newAttrCount = 0; for (int i = 0; i < _attrCount; i++) { RenderAttribute attr = _attrList[i]; if (OnAttributeRender(attr.name, attr.value, attr.key)) { // Update the list. This can be done in place _attrList[newAttrCount] = attr; newAttrCount++; } } // Update the count _attrCount = newAttrCount; } public virtual void RenderBeginTag(string tagName) { this.TagName = tagName; RenderBeginTag(_tagKey); } public virtual void RenderBeginTag(HtmlTextWriterTag tagKey) { this.TagKey = tagKey; bool renderTag = true; if (_isDescendant) { renderTag = OnTagRender(_tagName, _tagKey); // Inherited renderers will be expecting to be able to filter any of the attributes at this point FilterAttributes(); // write text before begin tag string textBeforeTag = RenderBeforeTag(); if (textBeforeTag != null) { if (tabsPending) { OutputTabs(); } writer.Write(textBeforeTag); } } // gather information about this tag. TagInformation tagInfo = _tagNameLookupArray[_tagIndex]; TagType tagType = tagInfo.tagType; bool renderEndTag = renderTag && (tagType != TagType.NonClosing); string endTag = renderEndTag? tagInfo.closingTag : null; // write the begin tag if (renderTag) { if (tabsPending) { OutputTabs(); } writer.Write(TagLeftChar); writer.Write(_tagName); string styleValue = null; for (int i = 0; i < _attrCount; i++) { RenderAttribute attr = _attrList[i]; if (attr.key == HtmlTextWriterAttribute.Style) { // append style attribute in with other styles styleValue = attr.value; } else { writer.Write(SpaceChar); writer.Write(attr.name); if (attr.value != null) { writer.Write(EqualsDoubleQuoteString); string attrValue = attr.value; if (attr.isUrl) { if (attr.key != HtmlTextWriterAttribute.Href || !attrValue.StartsWith("javascript:", StringComparison.Ordinal)) { attrValue = EncodeUrl(attrValue); } } if (attr.encode) { WriteHtmlAttributeEncode(attrValue); } else { writer.Write(attrValue); } writer.Write(DoubleQuoteChar); } } } if (_styleCount > 0 || styleValue != null) { writer.Write(SpaceChar); writer.Write("style"); writer.Write(EqualsDoubleQuoteString); CssTextWriter.WriteAttributes(writer, _styleList, _styleCount); if (styleValue != null) { writer.Write(styleValue); } writer.Write(DoubleQuoteChar); } if (tagType == TagType.NonClosing) { writer.Write(SelfClosingTagEnd); } else { writer.Write(TagRightChar); } } string textBeforeContent = RenderBeforeContent(); if (textBeforeContent != null) { if (tabsPending) { OutputTabs(); } writer.Write(textBeforeContent); } // write text before the content if (renderEndTag) { if (tagType == TagType.Inline) { _inlineCount += 1; } else { // writeline and indent before rendering content WriteLine(); Indent++; } // Manually build end tags for unknown tag types. if (endTag == null) { endTag = EndTagLeftChars + _tagName + TagRightChar.ToString(CultureInfo.InvariantCulture); } } if (_isDescendant) { // append text after the tag string textAfterTag = RenderAfterTag(); if (textAfterTag != null) { endTag = (endTag == null) ? textAfterTag : textAfterTag + endTag; } // build end content and push it on stack to write in RenderEndTag // prepend text after the content string textAfterContent = RenderAfterContent(); if (textAfterContent != null) { endTag = (endTag == null) ? textAfterContent : textAfterContent + endTag; } } // push end tag onto stack PushEndTag(endTag); // flush attribute and style lists for next tag _attrCount = 0; _styleCount = 0; } public virtual void RenderEndTag() { string endTag = PopEndTag(); if (endTag != null) { if (_tagNameLookupArray[_tagIndex].tagType == TagType.Inline) { _inlineCount -= 1; // Never inject crlfs at end of inline tags. // Write(endTag); } else { // unindent if not an inline tag WriteLine(); this.Indent--; Write(endTag); } } } protected virtual string RenderBeforeTag() { return null; } protected virtual string RenderBeforeContent() { return null; } protected virtual string RenderAfterContent() { return null; } protected virtual string RenderAfterTag() { return null; } public virtual void WriteAttribute(string name, string value) { WriteAttribute(name, value, false /*encode*/); } public virtual void WriteAttribute(string name, string value, bool fEncode) { writer.Write(SpaceChar); writer.Write(name); if (value != null) { writer.Write(EqualsDoubleQuoteString); if (fEncode) { WriteHtmlAttributeEncode(value); } else { writer.Write(value); } writer.Write(DoubleQuoteChar); } } public virtual void WriteBeginTag(string tagName) { if (tabsPending) { OutputTabs(); } writer.Write(TagLeftChar); writer.Write(tagName); } public virtual void WriteBreak() { // Space between br and / is for improved html compatibility. See XHTML 1.0 specification, section C.2. Write("
"); } // DevDiv 33149: A backward compat. switch for Everett rendering internal void WriteObsoleteBreak() { Write("
"); } public virtual void WriteFullBeginTag(string tagName) { if (tabsPending) { OutputTabs(); } writer.Write(TagLeftChar); writer.Write(tagName); writer.Write(TagRightChar); } public virtual void WriteEndTag(string tagName) { if (tabsPending) { OutputTabs(); } writer.Write(TagLeftChar); writer.Write(SlashChar); writer.Write(tagName); writer.Write(TagRightChar); } public virtual void WriteStyleAttribute(string name, string value) { WriteStyleAttribute(name, value, false /*encode*/); } public virtual void WriteStyleAttribute(string name, string value, bool fEncode) { writer.Write(name); writer.Write(StyleEqualsChar); if (fEncode) { WriteHtmlAttributeEncode(value); } else { writer.Write(value); } writer.Write(SemicolonChar); } internal void WriteUTF8ResourceString(IntPtr pv, int offset, int size, bool fAsciiOnly) { // If we have an http writer, we can use the faster code path. Otherwise, // get a String out of the resource and write it. if (_httpWriter != null) { if (tabsPending) { OutputTabs(); } _httpWriter.WriteUTF8ResourceString(pv, offset, size, fAsciiOnly); } else { Write(StringResourceManager.ResourceToString(pv, offset, size)); } } public virtual void WriteEncodedUrl(String url) { int i = url.IndexOf('?'); if (i != -1) { WriteUrlEncodedString(url.Substring(0, i), false); Write(url.Substring(i)); } else { WriteUrlEncodedString(url, false); } } public virtual void WriteEncodedUrlParameter(String urlText) { WriteUrlEncodedString(urlText, true); } public virtual void WriteEncodedText(String text) { if (text == null) { throw new ArgumentNullException("text"); } const char NBSP = '\u00A0'; // When inner text is retrieved for a text control,   is // decoded to 0x00A0 (code point for nbsp in Unicode). // HtmlEncode doesn't encode 0x00A0 to  , we need to do it // manually here. int length = text.Length; int pos = 0; while (pos < length) { int nbsp = text.IndexOf(NBSP, pos); if (nbsp < 0) { HttpUtility.HtmlEncode(pos == 0 ? text : text.Substring(pos, length - pos), this); pos = length; } else { if (nbsp > pos) { HttpUtility.HtmlEncode(text.Substring(pos, nbsp - pos), this); } Write(" "); pos = nbsp + 1; } } } protected void WriteUrlEncodedString(String text, bool argument) { int length = text.Length; for (int i = 0; i < length; i++) { char ch = text[i]; if (HttpEncoderUtility.IsUrlSafeChar(ch)) { Write(ch); } else if ( !argument && (ch == '/' || ch == ':' || ch == '#' || ch == ',' ) ) { Write(ch); } else if (ch == ' ' && argument) { Write('+'); } // for chars that their code number is less than 128 and have // not been handled above else if ((ch & 0xff80) == 0) { Write('%'); Write(HttpEncoderUtility.IntToHex((ch >> 4) & 0xf)); Write(HttpEncoderUtility.IntToHex((ch) & 0xf)); } else { // VSWhidbey 448625: For DBCS characters, use UTF8 encoding // which can be handled by IIS5 and above. Write(HttpUtility.UrlEncodeNonAscii(Char.ToString(ch), Encoding.UTF8)); } } } internal void WriteHtmlAttributeEncode(string s) { HttpUtility.HtmlAttributeEncode(s, _httpWriter ?? writer); } internal class Layout { private bool _wrap; private HorizontalAlign _align; /* public Layout(Layout currentLayout) { Align = currentLayout.Align; Wrap = currentLayout.Wrap; } */ public Layout(HorizontalAlign alignment, bool wrapping) { Align = alignment; Wrap = wrapping; } public bool Wrap { get { return _wrap; } set { _wrap = value; } } public HorizontalAlign Align { get { return _align; } set { _align = value; } } /* public bool Compare(Layout layout) { return Wrap == layout.Wrap && Align == layout.Align; } public void MergeWith(Layout layout) { if (Align == HorizontalAlign.NotSet) { Align = layout.Align; } if (Wrap) { Wrap = layout.Wrap; } } */ } private struct TagStackEntry { public HtmlTextWriterTag tagKey; public string endTagText; } private struct RenderAttribute { public string name; public string value; public HtmlTextWriterAttribute key; public bool encode; public bool isUrl; } private struct AttributeInformation { public string name; public bool isUrl; public bool encode; public AttributeInformation(string name, bool encode, bool isUrl) { this.name = name; this.encode = encode; this.isUrl = isUrl; } } private enum TagType { Inline, NonClosing, Other, } private struct TagInformation { public string name; public TagType tagType; public string closingTag; public TagInformation(string name, TagType tagType, string closingTag) { this.name = name; this.tagType = tagType; this.closingTag = closingTag; } } } }