All pastes #249153 Raw Edit

Kiryn

public text v1 · immutable
#249153 ·published 2006-11-15 13:54 UTC
rendered paste body
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;

namespace Frost
{
	/// <summary>
	/// 
	/// </summary>
	public class Xhtml : Page
	{
		#region Private Variables
		private string _xhtml;
		private string _language;
		private XHtmlFormat _xhtmlFormat;
		private Encoding _encoding;
		private bool _xmlCDATA;
		#endregion
		#region Constructor
		/// <summary>
		/// Default Constructor.
		/// </summary>
		public Xhtml( )
		{
			_xhtml = "";
			_xhtmlFormat = XHtmlFormat.XHtml10_Strict;
			_language = "en-GB";
			_xmlCDATA = false;
		}
		#endregion
		#region Overriding Methods
		/// <summary>
		/// 
		/// </summary>
		/// <param name="writer"></param>
		protected override void Render( HtmlTextWriter writer )
		{
			StringWriter sw = new StringWriter( );
			HtmlTextWriter output = new HtmlTextWriter( sw );
			base.Render( output );
			output.Close( );

			_xhtml = sw.GetStringBuilder( ).ToString( );

			ReplaceDocType( );
			switch ( _xhtmlFormat )
			{
				case XHtmlFormat.XHtml10_Frameset:
					ConvertToXHtmlFrameset( );
					break;
				case XHtmlFormat.XHtml10_Strict:
					ConvertToXHtmlStrict( );
					break;
				case XHtmlFormat.XHtml10_Transitional:
					ConvertToXHtmlTransitional( );
					break;
			}
			writer.Write( _xhtml );
		}
		#endregion
		#region Private Methods
		/// <summary>
		/// 
		/// </summary>
		/// <param name="TagName"></param>
		private void AddSelfClose( string TagName )
		{
			int start = 0;
			int pos = 0;

			while ( pos >= 0 )
			{
				string search = "<" + TagName;
				pos = _xhtml.IndexOf( search, start );
				if ( pos > 0 )
				{
					start = pos + 1;
					int end = _xhtml.IndexOf( ">", start );
					if ( _xhtml[ end - 1 ] != '/' )
					{
						_xhtml = _xhtml.Insert( end, "/>" );
					}
				}
			}
		}
		/// <summary>
		/// 
		/// </summary>
		private void ConvertToLowerCase( )
		{
			_xhtml = Regex.Replace( _xhtml, "<(/?)([a-zA-Z]+)(\\s*)>", new MatchEvaluator( SingleTagToLowerCase ), RegexOptions.IgnoreCase );
			_xhtml = Regex.Replace( _xhtml, "<(/?)([a-zA-Z0-9]+)[ ]*(.*?)>", new MatchEvaluator( PropertiesToLowerCase ), RegexOptions.IgnoreCase );
			_xhtml = Regex.Replace( _xhtml, "<([a-zA-Z0-9]+)(\\s+[a-zA-Z]+)(=\".+?>)", new MatchEvaluator( PropertiesToLowerCase ), RegexOptions.IgnoreCase );
		}
		/// <summary>
		/// 
		/// </summary>
		private void ConvertToXHtmlFrameset( )
		{
			ConvertToLowerCase( );
			AddSelfClose( "meta" );
			FixHtml( );
		}
		/// <summary>
		/// 
		/// </summary>
		private void ConvertToXHtmlStrict( )
		{
			ConvertToLowerCase( );
			AddSelfClose( "meta" );
			AddSelfClose( "link" );
			AddSelfClose( "img" );
			AddSelfClose( "hr" );

			FixScript( );
			RemoveAttribute( "form", "name" );
			FixInput( );
			FixBr( );
			FixStyle( );
			FixHtml( );
			MaskScript( );
		}
		/// <summary>
		/// 
		/// </summary>
		private void ConvertToXHtmlTransitional( )
		{
			ConvertToLowerCase( );
			AddSelfClose( "meta" );
			AddSelfClose( "link" );
			AddSelfClose( "img" );
			AddSelfClose( "hr" );

			FixScript( );
			FixBr( );
			FixStyle( );
			FixHtml( );
		}
		/// <summary>
		/// 
		/// </summary>
		private void FixBr( )
		{
			_xhtml = _xhtml.Replace( "<br>", "<br />" );
		}
		/// <summary>
		/// 
		/// </summary>
		private void FixHtml( )
		{
			_xhtml = Regex.Replace( _xhtml, "<html>", new MatchEvaluator( HTMLTag ), RegexOptions.IgnoreCase );
		}
		/// <summary>
		/// 
		/// </summary>
		private void FixInput( )
		{
			int start = 0;
			int pos = 0;

			while ( pos >= 0 )
			{
				string search = "<input type=\"hidden\"";
				pos = _xhtml.IndexOf(search, start);
				if(pos > 0)
				{
					start = pos + search .Length;
					_xhtml = _xhtml.Insert(pos, "<pre>");

					int end = _xhtml.IndexOf(">", start);
					if(end > 0)
					{
						_xhtml = _xhtml.Insert(end + 1, "</pre>");
					}
				}
			}
		}
		/// <summary>
		/// 
		/// </summary>
		private void FixScript( )
		{
			_xhtml = _xhtml.Replace( "<script language=\"javascript\">", "<script type=\"text/javascript\">" );
		}
		/// <summary>
		/// 
		/// </summary>
		private void FixStyle( )
		{
			_xhtml = Regex.Replace( _xhtml, @"(<style[^<]*>){1}(?(?=\s*<!--)(\s*<!--)(\s*.*?)(//\s*-->)|(\s*.*?))\s*(</style>){1}", new MatchEvaluator( FixStyleAndScript ), RegexOptions.IgnoreCase | RegexOptions.Singleline );
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="m"></param>
		/// <returns></returns>
		private string FixStyleAndScript( Match m )
		{
			string ret = "";
			string st;
			string ed;

			if ( _xmlCDATA )
			{
				st = "\r\n<![CDATA[\r\n";
				ed = "\r\n]]>\r\n";
			}
			else
			{
				st = "\r\n<!-\r\n";
				ed = "\r\n//-->\r\n";
			}

			if ( m.Groups[ 2 ].ToString( ).Trim( ) == "" && m.Groups[ 4 ].ToString( ).Trim( ) == "" )
			{
				st = "";
				ed = "";
			}
			ret = m.Groups[ 1 ].ToString( ) + st;
			ret += m.Groups[ 2 ].ToString( ) + m.Groups[ 4 ].ToString( ) + ed + m.Groups[ 5 ].ToString( );
			return ret;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="m"></param>
		/// <returns></returns>
		private string HTMLTag( Match m )
		{
			return "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"" + _language + "\">";
		}
		/// <summary>
		/// 
		/// </summary>
		private void MaskScript( )
		{
			_xhtml = Regex.Replace( _xhtml, @"(<script[^<]*>){1}(?(?=\s*<!--)(\s*<!--)(\s*.*?)(//\s*-->)|(\s*.*?))\s*(</script>){1}", new MatchEvaluator( FixStyleAndScript ), RegexOptions.IgnoreCase | RegexOptions.Singleline );
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="m"></param>
		/// <returns></returns>
		private string NextProperty( Match m )
		{
			string replace = m.Groups[ 1 ].ToString( ) + m.Groups[ 2 ].ToString( ).ToLower( );
			if ( Regex.Match( m.Groups[ 3 ].ToString( ), "(.*?\")(\\s+\\w+)(=\".+>)", RegexOptions.IgnoreCase ).Success && m.Groups[ 3 ].ToString( ).IndexOf( "__VIEWSTATE" ) == -1 )
			{
				Debug.WriteLine( "Match OK", "NextProperty" );
				replace += Regex.Replace( m.Groups[ 3 ].ToString( ), "(.*?\")(\\s+\\w+)(=\".+>)", new MatchEvaluator( NextProperty ), RegexOptions.IgnoreCase );
			}
			else
			{
				Debug.WriteLine( "Match Not OK", "NextProperty" );
				replace += m.Groups[ 3 ].ToString( );
			}
			return replace;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="m"></param>
		/// <returns></returns>
		private string PropertiesToLowerCase( Match m )
		{
			string replace = "<" + m.Groups[ 1 ].ToString( ) + m.Groups[ 2 ].ToString( ).ToLower( );

			if ( Regex.Match( m.Groups[ 3 ].ToString( ), "(.*?\")(\\s+\\w+)(=\".+>)", RegexOptions.IgnoreCase ).Success )
			{
				replace += Regex.Replace( m.Groups[ 3 ].ToString( ), "(.*?\")(\\s+\\w+)(=\".+>)", new MatchEvaluator( NextProperty ), RegexOptions.IgnoreCase );
			}
			else
			{
				replace += m.Groups[ 3 ].ToString( );
			}
			return replace;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="TagName"></param>
		/// <param name="AttributeName"></param>
		private void RemoveAttribute( string TagName, string AttributeName )
		{
			int start = 0;
			int pos = 0;

			while ( pos >= 0 )
			{
				string search = "<" + TagName + "" + AttributeName + "=\"";
				pos = _xhtml.IndexOf( search, start );
				if ( pos > 0 )
				{
					start = pos + TagName.Length + 1;

					int end = _xhtml.IndexOf( "\"", pos + search.Length + 1 );
					if ( end > 0 )
					{
						_xhtml = _xhtml.Remove( start, end - start + 1 );
					}
				}
			}
		}
		/// <summary>
		/// 
		/// </summary>
		private void ReplaceDocType( )
		{
			int start = _xhtml.IndexOf( "<!DOCTYPE", 0 );
			if(start > 0)
			{
				int end = _xhtml.IndexOf(">", start + 1);
				if(end > 0)
				{
					_xhtml = _xhtml.Remove(start, end - start + 1);
					switch(_xhtmlFormat)
					{
						case XHtmlFormat.XHtml10_Frameset:
							_xhtml = _xhtml.Insert(0, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">");
							break;
						case XHtmlFormat.XHtml10_Strict:
							_xhtml = _xhtml.Insert(0, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
							break;
						case XHtmlFormat.XHtml10_Transitional:
							_xhtml = _xhtml.Insert(0, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
							break;
					}
				}
			}
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="m"></param>
		/// <returns></returns>
		private string SingleTagToLowerCase(Match m)
		{
			if(m.Groups[3].ToString().Trim() == string.Empty)
				return "<" + m.Groups[1].ToString().ToLower() + m.Groups[2].ToString().ToLower() + ">";
			else
				return "<" + m.Groups[1].ToString().ToLower() + m.Groups[2].ToString().ToLower() + "" + m.Groups[3].ToString() + ">";
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="m"></param>
		/// <returns></returns>
		private string ToLowerCase( Match m )
		{
			return m.ToString( ).ToLower( );
		}
		#endregion
		#region Properties
		/// <summary>
		/// 
		/// </summary>
		public XHtmlFormat XHTMLFormat
		{
			get { return _xhtmlFormat; }
			set { _xhtmlFormat = value; }
		}
		/// <summary>
		/// 
		/// </summary>
		public Encoding Encoding
		{
			get { return _encoding; }
			set { _encoding = value; }
		}
		/// <summary>
		/// 
		/// </summary>
		public string Language
		{
			get { return _language; }
			set { _language = value; }
		}
		/// <summary>
		/// 
		/// </summary>
		public bool XMLCDATA
		{
			get { return _xmlCDATA; }
			set { _xmlCDATA = value; }
		}
		#endregion
	}
}