// Copyright � 2007 Jeffrey Bazinet, http://www.vwd-cms.com/
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Text.RegularExpressions;
using System.Text;
using System.Collections;
using System;
using System.IO;
using VwdCms.Html;
using System.Collections.Specialized;
namespace VwdCms
{
public class CodeViewer : System.Web.UI.WebControls.Panel
{
public enum CodeLanguages
{
Html,
CSharp
}
public enum CodeSources
{
File,
Text
}
private const string fileHeader = "\r\n<div style=\"background-color:lightsteelblue;"
+ "font-weight:bold;width:98%;padding-left:2px;\"> {0}</div>\r\n";
private string _codeFile;
private CodeLanguages _codeLanguage = CodeLanguages.Html;
private CodeSources _codeSource = CodeSources.Text;
private bool _codeIsHtmlEncoded = false;
private bool _showCodeFileHeader = true;
private Hashtable _htExtensions = null;
private string _csharpColorDefault = ConfigurationManager.AppSettings["CSharpColorDefault"];
private string _csharpColorStrings = ConfigurationManager.AppSettings["CSharpColorStrings"];
private string _csharpColorKeywords = ConfigurationManager.AppSettings["CSharpColorKeywords"];
private string _csharpColorComments = ConfigurationManager.AppSettings["CSharpColorComments"];
private string _htmlColorDefault = ConfigurationManager.AppSettings["HtmlColorDefault"];
private string _htmlColorTagNames = ConfigurationManager.AppSettings["HtmlColorTagNames"];
private string _htmlColorComments = ConfigurationManager.AppSettings["HtmlColorComments"];
private string _htmlColorAttributeNames = ConfigurationManager.AppSettings["HtmlColorAttributeNames"];
private string _htmlColorAttributeValues = ConfigurationManager.AppSettings["HtmlColorAttributeValues"];
private string _htmlColorAspCodeTags = ConfigurationManager.AppSettings["HtmlColorAspCodeTags"];
private string _htmlColorAspCode = ConfigurationManager.AppSettings["HtmlColorAspCode"];
private string _htmlColorText = ConfigurationManager.AppSettings["HtmlColorText"];
private string _htmlColorScriptCode = ConfigurationManager.AppSettings["HtmlColorScriptCode"];
private StringCollection _scKeywords = null;
private bool _codeRendered = false;
public StringCollection Keywords
{
get { return _scKeywords; }
}
protected override void OnLoad(EventArgs e)
{
RenderCode();
base.OnLoad(e);
}
public void RenderCode()
{
if (!_codeRendered)
{
_codeRendered = true;
StringBuilder sbCode = new StringBuilder();
string startTag = "<pre style=\"color:{0};\">";
string endTag = "</pre>";
string defaultColor = null;
string codelanguage = null;
string code = null;
// determine the source and load the code
if (this.CodeSource == CodeSources.File !string.IsNullOrEmpty(this.CodeFile))
{
StreamReader sr = null;
string filename = this.CodeFile;
int index = filename.LastIndexOf('\\');
if (index != -1)
{
filename = filename.Substring(index + 1);
}
filename = filename.Replace(".exclude", string.Empty);
this.LoadFileExenstions();
string extension = this.GetExtension(filename);
codelanguage = Convert.ToString(_htExtensions[extension]);
if (this.ShowCodeFileHeader)
{
sbCode.Append(string.Format(fileHeader, filename));
}
try
{
sr = new StreamReader(this.CodeFile);
code = sr.ReadToEnd();
}
finally
{
if (sr != null)
{
sr.Close();
sr = null;
}
}
}
else if (this.CodeSource == CodeSources.Text)
{
if (this.CodeLanguage == CodeLanguages.CSharp)
{
codelanguage = "csharp";
}
else if (this.CodeLanguage == CodeLanguages.Html)
{
codelanguage = "html";
}
code = this.Text;
}
// process and render the code
if (code != null codelanguage != null)
{
if (this.CodeIsHtmlEncoded)
{
code = HttpUtility.HtmlDecode(code);
}
if (codelanguage == "csharp")
{
defaultColor = _csharpColorDefault;
code = FormatCSharpCode(code);
}
else if (codelanguage == "html")
{
defaultColor = _htmlColorDefault;
code = FormatHtmlCode(code);
}
}
// add the formatted code to the control
this.Controls.Clear();
if (code != null)
{
sbCode.Append(string.Format(startTag, defaultColor));
sbCode.Append(code);
sbCode.Append(endTag);
sbCode.Replace("\t", " ");
this.Controls.Add(new LiteralControl(sbCode.ToString()));
}
}
}
public string Text
{
get
{
string text = Convert.ToString(this.ViewState["text"]);
if (string.IsNullOrEmpty(text))
{
if (this.IsLiteralContent())
{
StringBuilder sbText = new StringBuilder();
foreach (LiteralControl lit in this.Controls)
{
sbText.Append(lit.Text);
}
text = sbText.ToString();
this.ViewState["text"] = text;
}
}
return text;
}
set { this.ViewState["text"] = value; }
}
public CodeSources CodeSource
{
get { return _codeSource; }
set { _codeSource = value; }
}
public CodeLanguages CodeLanguage
{
get { return _codeLanguage; }
set { _codeLanguage = value; }
}
public string CodeFile
{
get { return _codeFile; }
set { _codeFile = value; }
}
public bool CodeIsHtmlEncoded
{
get { return _codeIsHtmlEncoded; }
set { _codeIsHtmlEncoded = value; }
}
public bool ShowCodeFileHeader
{
get { return _showCodeFileHeader; }
set { _showCodeFileHeader = value; }
}
private void LoadFileExenstions()
{
string csharp = System.Configuration.ConfigurationManager.AppSettings["CSharpParserExtensions"];
string html = System.Configuration.ConfigurationManager.AppSettings["HtmlParserExtensions"];
_htExtensions = new Hashtable();
string[] extensions = null;
extensions = csharp.Split(';');
if (extensions != null extensions.Length 0)
{
foreach (string ext in extensions)
{
if (_htExtensions[ext] == null)
{
_htExtensions.Add(ext, "csharp");
}
}
}
extensions = html.Split(';');
if (extensions != null extensions.Length 0)
{
foreach (string ext in extensions)
{
if (_htExtensions[ext] == null)
{
_htExtensions.Add(ext, "html");
}
}
}
}
private string GetExtension(string filename)
{
string extension = string.Empty;
if (filename != null)
{
int index = filename.LastIndexOf(".");
if (index != -1)
{
extension = filename.Substring(index);
}
}
return extension.ToLower();
}
public string FormatHtmlCode(string source)
{
Html.HtmlParser parser = new HtmlParser();
HtmlTagCollection tags = parser.GetHtmlTags(source);
HtmlNode docNode = parser.GetDocumentNode(tags);
StringBuilder sbOut = new StringBuilder();
this.ProcessNode(docNode, sbOut);
return sbOut.ToString();
}
private void ProcessNode(HtmlNode node, StringBuilder sbCode)
{
string outerHtml = null;
StringBuilder sbTagFormat = new StringBuilder(node.TagFormat);
switch (node.NodeType)
{
case HtmlNodeTypes.AspCodeBlock:
outerHtml = node.Text.Substring(2, node.Text.Length-4);
outerHtml = HttpUtility.HtmlEncode(outerHtml);
sbCode.Append("<span style=\"background-color:"
+ _htmlColorAspCodeTags + ";\"><%</span>");
sbCode.Append("<span style=\"color:" + _htmlColorAspCode + ";\">");
sbCode.Append(outerHtml);
sbCode.Append("</span>");
sbCode.Append("<span style=\"background-color:"
+ _htmlColorAspCodeTags + ";\">%></span>");
break;
case HtmlNodeTypes.AspDirective:
ProcessAttributes(node, sbTagFormat);
sbTagFormat.Remove(0, node.StartsWith.Length);
sbTagFormat.Insert(0, "<span style=\"background-color:"
+ _htmlColorAspCodeTags + ";\"><%</span>@");
sbTagFormat.Replace("{tagname}", "<span style=\"color:"
+ _htmlColorTagNames + ";\">" + node.TagName + "</span>");
sbTagFormat.Remove(sbTagFormat.Length - node.EndsWith.Length, node.EndsWith.Length);
sbTagFormat.Append("<span style=\"background-color:"
+ _htmlColorAspCodeTags + ";\">%></span>");
sbCode.Append(sbTagFormat.ToString());
break;
case HtmlNodeTypes.AspComment:
case HtmlNodeTypes.Comment:
outerHtml = node.OuterHtml;
outerHtml = HttpUtility.HtmlEncode(outerHtml);
sbCode.Append("<span style=\"color:" + _htmlColorComments + ";\">");
sbCode.Append(outerHtml);
sbCode.Append("</span>");
break;
case HtmlNodeTypes.Document:
// do nothing
break;
case HtmlNodeTypes.DocType:
sbTagFormat = new StringBuilder(HttpUtility.HtmlEncode(sbTagFormat.ToString()));
ProcessAttributes(node, sbTagFormat);
sbTagFormat.Replace("{tagname}", "<span style=\"color:"
+ _htmlColorTagNames + ";\">" + node.TagName + "</span>");
sbCode.Append(sbTagFormat.ToString());
break;
case HtmlNodeTypes.Element:
ProcessAttributes(node, sbTagFormat);
sbTagFormat.Replace("{tagname}", "<span style=\"color:"
+ _htmlColorTagNames + ";\">" + node.TagName + "</span>");
sbCode.Append(sbTagFormat.ToString());
break;
case HtmlNodeTypes.XmlDocumentDeclaration:
sbTagFormat = new StringBuilder(HttpUtility.HtmlEncode(sbTagFormat.ToString()));
ProcessAttributes(node, sbTagFormat);
sbTagFormat.Replace("{tagname}", "<span style=\"color:"
+ _htmlColorTagNames + ";\">xml</span>");
sbCode.Append(sbTagFormat.ToString());
break;
case HtmlNodeTypes.Literal:
if (node.ParentNode.TagName.ToLower() == "script")
{
sbCode.Append("<span style=\"color:" + _htmlColorScriptCode + ";\">");
}
else
{
sbCode.Append("<span style=\"color:" + _htmlColorText + ";\">");
}
sbCode.Append(FormatText(node.Text));
sbCode.Append("</span>");
break;
}
if ( node.HasChildren )
{
foreach (HtmlNode child in node.ChildNodes)
{
ProcessNode(child, sbCode);
}
}
if ( node.NodeType == HtmlNodeTypes.Element !node.SelfClosing)
{
string endTag = HttpUtility.HtmlEncode(node.EndTagFormat);
if (string.IsNullOrEmpty(endTag))
{
endTag = "</{tagname}>";
}
endTag = endTag.Replace("{tagname}", "<span style=\"color:"
+ _htmlColorTagNames + ";\">" + node.TagName + "</span>");
sbCode.Append(endTag);
}
}
private string FormatText(string text)
{
StringBuilder sb = new StringBuilder(text);
sb.Replace("\r\n", "<br/>");
sb.Replace("\r", "<br/>");
sb.Replace("\n", "<br/>");
sb.Replace("\t", " ");
return sb.ToString();
}
private void ProcessAttributes(HtmlNode node, StringBuilder sbTagFormat)
{
HtmlAttribute attrib = null;
int index = 0;
string name = null;
string val = null;
if ( node.HasAttributes )
{
for ( index = 0; index node.Attributes.Count; index++ )
{
attrib = node.Attributes[index];
if (attrib.Name != null attrib.Value != null )
{
name = "<span style=\"color:" + _htmlColorAttributeNames
+ ";\">" + attrib.Name + "</span>";
sbTagFormat.Replace("{name" + index.ToString() + "}", name);
val = "<span style=\"color:" + _htmlColorAttributeValues
+ ";\">" + attrib.Value + "</span>";
sbTagFormat.Replace("{val" + index.ToString() + "}", val);
}
else if ( attrib.Name != null )
{
name = "<span style=\"color:" + _htmlColorAttributeNames
+ ";\">" + attrib.Name + "</span>";
sbTagFormat.Replace("{name" + index.ToString() + "}", name);
}
else if ( attrib.Value != null )
{
val = "<span style=\"color:" + _htmlColorAttributeValues
+ ";\">" + attrib.Value + "</span>";
sbTagFormat.Replace("{val" + index.ToString() + "}", val);
}
}
}
}
public string FormatCSharpCode(string source)
{
Hashtable htKeywords = GetCSharpKeywords();
string reComments = @"(/\*.*(\*/){0}\*/){1}|(//[^\n]*\n){1}";
string reStrings = @"(@""(("""")|[^""])*"")|(""((\\"")|[^""])*"")|((""[\""]*[^""]*"")+|(""{2})+)+";
string reChars = @"('[^']*')+";
string reStuff = @"[!,@:%; \t\r\n\.\$\^\{\}\[\]\(\)\|\*\+\?\=\\]{1}";
string reMinuses = @"(-){1}";
string reDivisions = @"((/){1})+";
string reEncodings = @"(&\w+;)+";
string reWords = @"([\w+\.*])+";
string reQuery = "(" + reComments + "|" + reStrings + "|"
+ reChars + "|" + reStuff + "|" + reMinuses + "|"
+ reDivisions + "|" + reEncodings + "|" + reWords + ")";
Regex regexCode = new Regex(reQuery, RegexOptions.Singleline);
StringBuilder sbOut = new StringBuilder();
MatchCollection wordMatches = null;
// get all individual words/characters in the source
wordMatches = regexCode.Matches(source);
string text = null;
string[] words = null;
string word = null;
string dot = null;
foreach (Match wordMatch in wordMatches)
{
text = wordMatch.Value;
if ( ( text.StartsWith("@\"") || text.StartsWith("\"")) text.EndsWith("\"")) // it's a string
{
text = "<span style=\"color:" + _csharpColorStrings
+ ";\">" + HttpUtility.HtmlEncode(text) + "</span>";
sbOut.Append(text);
}
else if (text.StartsWith("//") || text.StartsWith("/*")) // it's a comment
{
text = "<span style=\"color:" + _csharpColorComments
+ ";\">" + HttpUtility.HtmlEncode(text) + "</span>";
sbOut.Append(text);
}
else
{
words = text.Split('.');
for (int i = 0; i words.Length; i++)
{
word = words[i];
dot = (i 0) ? "." : string.Empty;
if (word.StartsWith("\"")) // it's a string
{
word = "<span style=\"color:" + _csharpColorStrings
+ ";\">" + dot + HttpUtility.HtmlEncode(word) + "</span>";
}
else if (htKeywords[word] != null) // it's C# a keyword
{
word = "<span style=\"color:" + _csharpColorKeywords
+ ";\">" + dot + word + "</span>";
}
else if (word.IndexOf("//") != -1 word.EndsWith("\n")) // it's a comment
{
word = "<span style=\"color:" + _csharpColorComments
+ ";\">" + dot + HttpUtility.HtmlEncode(word) + "</span>";
}
else // unrecognized word
{
word = dot + HttpUtility.HtmlEncode(word);
}
sbOut.Append(word);
}
}
}
return sbOut.ToString();
}
private static Hashtable GetCSharpKeywords()
{
string[] cskeywords =
{
"abstract","event","new","struct","as","explicit","null","switch","base","extern","object","this","get",
"bool","false","operator","throw","break","finally","out","true","byte","fixed","override","try","set",
"case","float","params","typeof","catch","for","private","uint","char","foreach","protected","ulong",
"checked","goto","public","unchecked","class","if","readonly","unsafe","const","implicit","ref","ushort",
"continue","in","return","using","decimal","int","sbyte","virtual","default","interface","sealed","volatile",
"delegate","internal","short","void","do","is","sizeof","while","double","lock","stackalloc","else",
"long","static","enum","namespace","string"};
Hashtable htKeywords = new Hashtable();
foreach (string keyword in cskeywords)
{
htKeywords.Add(keyword, keyword);
}
return htKeywords;
}
public void SetCodeLanguage(string filename)
{
this.LoadFileExenstions();
string extension = this.GetExtension(filename);
string codelanguage = Convert.ToString(_htExtensions[extension]);
if ( codelanguage == "csharp")
{
this.CodeLanguage = CodeLanguages.CSharp ;
}
else if ( codelanguage == "html" )
{
this.CodeLanguage = CodeLanguages.Html;
}
}
}
}