public void TestArgumentExceptions () { Assert.Throws<ArgumentNullException> (() => new HtmlWriter (null, Encoding.UTF8)); Assert.Throws<ArgumentNullException> (() => new HtmlWriter (new MemoryStream (), null)); Assert.Throws<ArgumentNullException> (() => new HtmlWriter (null)); using (var html = new HtmlWriter (new StringWriter ())) { Assert.Throws<ArgumentNullException> (() => html.WriteAttribute (null)); Assert.Throws<ArgumentNullException> (() => html.WriteAttribute (null, string.Empty)); Assert.Throws<ArgumentNullException> (() => html.WriteAttribute ("name", null)); Assert.Throws<ArgumentException> (() => html.WriteAttribute (string.Empty, null)); Assert.Throws<ArgumentException> (() => html.WriteAttribute ("a b c", null)); Assert.Throws<ArgumentNullException> (() => html.WriteAttribute (null, new char[1], 0, 1)); Assert.Throws<ArgumentNullException> (() => html.WriteAttribute ("name", null, 0, 0)); Assert.Throws<ArgumentOutOfRangeException> (() => html.WriteAttribute ("name", new char[0], -1, 0)); Assert.Throws<ArgumentOutOfRangeException> (() => html.WriteAttribute ("name", new char[0], 0, 1)); Assert.Throws<ArgumentException> (() => html.WriteAttribute (HtmlAttributeId.Unknown, new char[1], 0, 1)); Assert.Throws<ArgumentNullException> (() => html.WriteAttribute (HtmlAttributeId.Alt, null, 0, 0)); Assert.Throws<ArgumentOutOfRangeException> (() => html.WriteAttribute (HtmlAttributeId.Alt, new char[0], -1, 0)); Assert.Throws<ArgumentOutOfRangeException> (() => html.WriteAttribute (HtmlAttributeId.Alt, new char[0], 0, 1)); Assert.Throws<ArgumentException> (() => html.WriteAttributeName (HtmlAttributeId.Unknown)); Assert.Throws<ArgumentNullException> (() => html.WriteAttributeName (null)); Assert.Throws<ArgumentNullException> (() => html.WriteAttributeValue (null)); Assert.Throws<ArgumentNullException> (() => html.WriteAttributeValue (null, 0, 0)); Assert.Throws<ArgumentOutOfRangeException> (() => html.WriteAttributeValue (new char[0], -1, 0)); Assert.Throws<ArgumentOutOfRangeException> (() => html.WriteAttributeValue (new char[0], 0, 1)); Assert.Throws<ArgumentException> (() => html.WriteEmptyElementTag (HtmlTagId.Unknown)); Assert.Throws<ArgumentNullException> (() => html.WriteEmptyElementTag (null)); Assert.Throws<ArgumentException> (() => html.WriteEmptyElementTag (string.Empty)); Assert.Throws<ArgumentException> (() => html.WriteEmptyElementTag ("a b c")); Assert.Throws<ArgumentException> (() => html.WriteEndTag (HtmlTagId.Unknown)); Assert.Throws<ArgumentNullException> (() => html.WriteEndTag (null)); Assert.Throws<ArgumentException> (() => html.WriteEndTag (string.Empty)); Assert.Throws<ArgumentException> (() => html.WriteEndTag ("a b c")); Assert.Throws<ArgumentNullException> (() => html.WriteMarkupText (null)); Assert.Throws<ArgumentNullException> (() => html.WriteMarkupText (null, 0, 0)); Assert.Throws<ArgumentOutOfRangeException> (() => html.WriteMarkupText (new char[0], -1, 0)); Assert.Throws<ArgumentOutOfRangeException> (() => html.WriteMarkupText (new char[0], 0, 1)); Assert.Throws<ArgumentException> (() => html.WriteStartTag (HtmlTagId.Unknown)); Assert.Throws<ArgumentNullException> (() => html.WriteStartTag (null)); Assert.Throws<ArgumentException> (() => html.WriteStartTag (string.Empty)); Assert.Throws<ArgumentException> (() => html.WriteStartTag ("a b c")); Assert.Throws<ArgumentNullException> (() => html.WriteText (null)); Assert.Throws<ArgumentNullException> (() => html.WriteText (null, 0, 0)); Assert.Throws<ArgumentOutOfRangeException> (() => html.WriteText (new char[0], -1, 0)); Assert.Throws<ArgumentOutOfRangeException> (() => html.WriteText (new char[0], 0, 1)); Assert.Throws<ArgumentNullException> (() => html.WriteToken (null)); } }
public void HtmlTagCallback (HtmlTagContext ctx, HtmlWriter htmlWriter) { if (ctx.TagId != HtmlTagId.Image || ctx.IsEndTag) { ctx.WriteTag (htmlWriter, true); return; } // write the IMG tag, but don't write out the attributes. ctx.WriteTag (htmlWriter, false); // manually write the attributes so that we can replace the SRC attributes foreach (var attribute in ctx.Attributes) { if (attribute.Id == HtmlAttributeId.Src) { int index; Uri uri; // parse the <img src=...> attribute value into a Uri if (Uri.IsWellFormedUriString (attribute.Value, UriKind.Absolute)) uri = new Uri (attribute.Value, UriKind.Absolute); else uri = new Uri (attribute.Value, UriKind.Relative); // locate the index of the attachment within the multipart/related (if it exists) if ((index = related.IndexOf (uri)) != -1) { var attachment = related[index] as MimePart; if (attachment == null) { // the body part is not a basic leaf part (IOW it's a multipart or message-part) htmlWriter.WriteAttribute (attribute); continue; } var data = GetDataUri (attachment); htmlWriter.WriteAttributeName (attribute.Name); htmlWriter.WriteAttributeValue (data); } else { htmlWriter.WriteAttribute (attribute); } } } }
void WriteParagraph (HtmlWriter htmlWriter, IList<FlowedToHtmlTagContext> stack, ref int currentQuoteDepth, StringBuilder para, int quoteDepth) { var callback = HtmlTagCallback ?? DefaultHtmlTagCallback; FlowedToHtmlTagContext ctx; while (currentQuoteDepth < quoteDepth) { ctx = new FlowedToHtmlTagContext (HtmlTagId.BlockQuote); callback (ctx, htmlWriter); currentQuoteDepth++; stack.Add (ctx); } while (quoteDepth < currentQuoteDepth) { ctx = stack[stack.Count - 1]; stack.RemoveAt (stack.Count - 1); if (!SuppressContent (stack) && !ctx.DeleteEndTag) { ctx.SetIsEndTag (true); if (ctx.InvokeCallbackForEndTag) callback (ctx, htmlWriter); else ctx.WriteTag (htmlWriter); } if (ctx.TagId == HtmlTagId.BlockQuote) currentQuoteDepth--; } if (SuppressContent (stack)) return; ctx = new FlowedToHtmlTagContext (para.Length == 0 ? HtmlTagId.Br : HtmlTagId.P); callback (ctx, htmlWriter); if (para.Length > 0) { if (!ctx.SuppressInnerContent) WriteText (htmlWriter, para.ToString ()); if (!ctx.DeleteEndTag) { ctx.SetIsEndTag (true); if (ctx.InvokeCallbackForEndTag) callback (ctx, htmlWriter); else ctx.WriteTag (htmlWriter); } } if (!ctx.DeleteTag) htmlWriter.WriteMarkupText (Environment.NewLine); }
void WriteText (HtmlWriter htmlWriter, string text) { var callback = HtmlTagCallback ?? DefaultHtmlTagCallback; var content = text.ToCharArray (); int endIndex = content.Length; int startIndex = 0; UrlMatch match; int count; do { count = endIndex - startIndex; if (scanner.Scan (content, startIndex, count, out match)) { count = match.EndIndex - match.StartIndex; if (match.StartIndex > startIndex) { // write everything up to the match htmlWriter.WriteText (content, startIndex, match.StartIndex - startIndex); } var href = match.Prefix + new string (content, match.StartIndex, count); var ctx = new FlowedToHtmlTagContext (HtmlTagId.A, new HtmlAttribute (HtmlAttributeId.Href, href)); callback (ctx, htmlWriter); if (!ctx.SuppressInnerContent) htmlWriter.WriteText (content, match.StartIndex, count); if (!ctx.DeleteEndTag) { ctx.SetIsEndTag (true); if (ctx.InvokeCallbackForEndTag) callback (ctx, htmlWriter); else ctx.WriteTag (htmlWriter); } startIndex = match.EndIndex; } else { htmlWriter.WriteText (content, startIndex, count); break; } } while (startIndex < endIndex); }
/// <summary> /// Convert the contents of <paramref name="reader"/> from the <see cref="InputFormat"/> to the /// <see cref="OutputFormat"/> and uses the <paramref name="writer"/> to write the resulting text. /// </summary> /// <remarks> /// Converts the contents of <paramref name="reader"/> from the <see cref="InputFormat"/> to the /// <see cref="OutputFormat"/> and uses the <paramref name="writer"/> to write the resulting text. /// </remarks> /// <param name="reader">The text reader.</param> /// <param name="writer">The text writer.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="reader"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="writer"/> is <c>null</c>.</para> /// </exception> public override void Convert (TextReader reader, TextWriter writer) { if (reader == null) throw new ArgumentNullException (nameof (reader)); if (writer == null) throw new ArgumentNullException (nameof (writer)); if (!string.IsNullOrEmpty (Header)) { if (HeaderFormat == HeaderFooterFormat.Text) { var converter = new TextToHtml (); using (var sr = new StringReader (Header)) converter.Convert (sr, writer); } else { writer.Write (Header); } } using (var htmlWriter = new HtmlWriter (writer)) { var callback = HtmlTagCallback ?? DefaultHtmlTagCallback; var stack = new List<TextToHtmlTagContext> (); int currentQuoteDepth = 0, quoteDepth; TextToHtmlTagContext ctx; string line; while ((line = reader.ReadLine ()) != null) { line = Unquote (line, out quoteDepth); while (currentQuoteDepth < quoteDepth) { ctx = new TextToHtmlTagContext (HtmlTagId.BlockQuote); callback (ctx, htmlWriter); currentQuoteDepth++; stack.Add (ctx); } while (quoteDepth < currentQuoteDepth) { ctx = stack[stack.Count - 1]; stack.RemoveAt (stack.Count - 1); if (!SuppressContent (stack) && !ctx.DeleteEndTag) { ctx.SetIsEndTag (true); if (ctx.InvokeCallbackForEndTag) callback (ctx, htmlWriter); else ctx.WriteTag (htmlWriter); } if (ctx.TagId == HtmlTagId.BlockQuote) currentQuoteDepth--; } if (!SuppressContent (stack)) { WriteText (htmlWriter, line); ctx = new TextToHtmlTagContext (HtmlTagId.Br); callback (ctx, htmlWriter); } } for (int i = stack.Count; i > 0; i--) { ctx = stack[i - 1]; ctx.SetIsEndTag (true); if (ctx.InvokeCallbackForEndTag) callback (ctx, htmlWriter); else ctx.WriteTag (htmlWriter); } htmlWriter.Flush (); } if (!string.IsNullOrEmpty (Footer)) { if (FooterFormat == HeaderFooterFormat.Text) { var converter = new TextToHtml (); using (var sr = new StringReader (Footer)) converter.Convert (sr, writer); } else { writer.Write (Footer); } } }
void ReplaceUrlsWithFileNames (HtmlTagContext ctx, HtmlWriter htmlWriter) { if (ctx.TagId == HtmlTagId.Image) { htmlWriter.WriteEmptyElementTag (ctx.TagName); ctx.DeleteEndTag = true; for (int i = 0; i < ctx.Attributes.Count; i++) { var attr = ctx.Attributes[i]; if (attr.Id == HtmlAttributeId.Src) { var fileName = Path.GetFileName (attr.Value); htmlWriter.WriteAttributeName (attr.Name); htmlWriter.WriteAttributeValue (fileName); } else { htmlWriter.WriteAttribute (attr); } } } else { ctx.WriteTag (htmlWriter, true); } }
void HtmlTagCallback (HtmlTagContext ctx, HtmlWriter htmlWriter) { if (ctx.TagId == HtmlTagId.Body && !ctx.IsEmptyElementTag) { if (ctx.IsEndTag) { // end our opening <blockquote> htmlWriter.WriteEndTag (HtmlTagId.BlockQuote); // pass the </body> tag through to the output ctx.WriteTag (htmlWriter, true); } else { // pass the <body> tag through to the output ctx.WriteTag (htmlWriter, true); // prepend the HTML reply with "On {DATE}, {SENDER} wrote:" htmlWriter.WriteStartTag (HtmlTagId.P); htmlWriter.WriteText (GetOnDateSenderWrote (message)); htmlWriter.WriteEndTag (HtmlTagId.P); // Wrap the original content in a <blockquote> htmlWriter.WriteStartTag (HtmlTagId.BlockQuote); htmlWriter.WriteAttribute (HtmlAttributeId.Style, "border-left: 1px #ccc solid; margin: 0 0 0 .8ex; padding-left: 1ex;"); ctx.InvokeCallbackForEndTag = true; } } else { // pass the tag through to the output ctx.WriteTag (htmlWriter, true); } }
/// <summary> /// Convert the contents of <paramref name="reader"/> from the <see cref="InputFormat"/> to the /// <see cref="OutputFormat"/> and uses the <paramref name="writer"/> to write the resulting text. /// </summary> /// <remarks> /// Converts the contents of <paramref name="reader"/> from the <see cref="InputFormat"/> to the /// <see cref="OutputFormat"/> and uses the <paramref name="writer"/> to write the resulting text. /// </remarks> /// <param name="reader">The text reader.</param> /// <param name="writer">The text writer.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="reader"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="writer"/> is <c>null</c>.</para> /// </exception> public override void Convert(TextReader reader, TextWriter writer) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } if (writer == null) { throw new ArgumentNullException(nameof(writer)); } if (!string.IsNullOrEmpty(Header)) { if (HeaderFormat == HeaderFooterFormat.Text) { var converter = new TextToHtml { OutputHtmlFragment = true }; using (var sr = new StringReader(Header)) converter.Convert(sr, writer); } else { writer.Write(Header); } } using (var htmlWriter = new HtmlWriter(writer)) { var callback = HtmlTagCallback ?? DefaultHtmlTagCallback; var stack = new List <HtmlToHtmlTagContext> (); var tokenizer = new HtmlTokenizer(reader); HtmlToHtmlTagContext ctx; HtmlToken token; while (tokenizer.ReadNextToken(out token)) { switch (token.Kind) { default: if (!SuppressContent(stack)) { htmlWriter.WriteToken(token); } break; case HtmlTokenKind.Comment: if (!FilterComments && !SuppressContent(stack)) { htmlWriter.WriteToken(token); } break; case HtmlTokenKind.Tag: var tag = (HtmlTagToken)token; if (!tag.IsEndTag) { //if (NormalizeHtml && AutoClosingTags.Contains (startTag.TagName) && // (ctx = Pop (stack, startTag.TagName)) != null && // ctx.InvokeCallbackForEndTag && !SuppressContent (stack)) { // var value = string.Format ("</{0}>", ctx.TagName); // var name = ctx.TagName; // // ctx = new HtmlToHtmlTagContext (new HtmlTokenTag (HtmlTokenKind.EndTag, name, value)) { // InvokeCallbackForEndTag = ctx.InvokeCallbackForEndTag, // SuppressInnerContent = ctx.SuppressInnerContent, // DeleteEndTag = ctx.DeleteEndTag, // DeleteTag = ctx.DeleteTag // }; // callback (ctx, htmlWriter); //} if (!tag.IsEmptyElement) { ctx = new HtmlToHtmlTagContext(tag); if (FilterHtml && ctx.TagId == HtmlTagId.Script) { ctx.SuppressInnerContent = true; ctx.DeleteEndTag = true; ctx.DeleteTag = true; } else if (!SuppressContent(stack)) { callback(ctx, htmlWriter); } stack.Add(ctx); } else if (!SuppressContent(stack)) { ctx = new HtmlToHtmlTagContext(tag); if (!FilterHtml || ctx.TagId != HtmlTagId.Script) { callback(ctx, htmlWriter); } } } else { if ((ctx = Pop(stack, tag.Name)) != null) { if (!SuppressContent(stack)) { if (ctx.InvokeCallbackForEndTag) { ctx = new HtmlToHtmlTagContext(tag) { InvokeCallbackForEndTag = ctx.InvokeCallbackForEndTag, SuppressInnerContent = ctx.SuppressInnerContent, DeleteEndTag = ctx.DeleteEndTag, DeleteTag = ctx.DeleteTag }; callback(ctx, htmlWriter); } else if (!ctx.DeleteEndTag) { htmlWriter.WriteEndTag(tag.Name); } } } else if (!SuppressContent(stack)) { ctx = new HtmlToHtmlTagContext(tag); callback(ctx, htmlWriter); } } break; } } htmlWriter.Flush(); } if (!string.IsNullOrEmpty(Footer)) { if (FooterFormat == HeaderFooterFormat.Text) { var converter = new TextToHtml { OutputHtmlFragment = true }; using (var sr = new StringReader(Footer)) converter.Convert(sr, writer); } else { writer.Write(Footer); } } }
static void DefaultHtmlTagCallback (HtmlTagContext tagContext, HtmlWriter htmlWriter) { tagContext.WriteTag (htmlWriter, true); }
public void TestHtmlWriter () { const string expected = "<html ltr=\"true\"><head/><body><p class=\"paragraph\">" + "special characters in this text should get encoded: <>'&\n" + "special characters should not get encoded: <>" + "</p></body></html>"; var actual = new StringBuilder (); using (var html = new HtmlWriter (new StringWriter (actual))) { Assert.AreEqual (HtmlWriterState.Default, html.WriterState); // make sure we can't start by writing an attribute since we are in the wrong state Assert.Throws<InvalidOperationException> (() => html.WriteAttribute (new HtmlAttribute (HtmlAttributeId.Action, "invalid state"))); Assert.Throws<InvalidOperationException> (() => html.WriteAttribute (HtmlAttributeId.Action, "invalid state")); Assert.Throws<InvalidOperationException> (() => html.WriteAttribute ("action", "invalid state")); // write a tag html.WriteStartTag (HtmlTagId.Html); Assert.AreEqual (HtmlWriterState.Tag, html.WriterState); // *now* we should be able to write an attribute html.WriteAttribute (new HtmlAttribute ("ltr", "true")); // write en empty element tag, this should change the state to Default html.WriteEmptyElementTag (HtmlTagId.Head); Assert.AreEqual (HtmlWriterState.Tag, html.WriterState); html.WriteStartTag ("body"); Assert.AreEqual (HtmlWriterState.Tag, html.WriterState); html.WriteStartTag (HtmlTagId.P); Assert.AreEqual (HtmlWriterState.Tag, html.WriterState); // make sure that we can't write an attribute value yet Assert.Throws<InvalidOperationException> (() => html.WriteAttributeValue ("attrValue")); Assert.Throws<InvalidOperationException> (() => html.WriteAttributeValue ("attrValue".ToCharArray (), 0, 9)); html.WriteAttributeName (HtmlAttributeId.Class); Assert.AreEqual (HtmlWriterState.Attribute, html.WriterState); html.WriteAttributeValue ("paragraph"); Assert.AreEqual (HtmlWriterState.Tag, html.WriterState); html.WriteText ("special characters in this text should get encoded: <>'&\n"); html.WriteMarkupText ("special characters should not get encoded: <>"); Assert.AreEqual (HtmlWriterState.Default, html.WriterState); html.WriteEndTag (HtmlTagId.P); html.WriteEndTag (HtmlTagId.Body); html.WriteEndTag ("html"); } Assert.AreEqual (expected, actual.ToString ()); }
/// <summary> /// Convert the contents of <paramref name="reader"/> from the <see cref="InputFormat"/> to the /// <see cref="OutputFormat"/> and uses the <paramref name="writer"/> to write the resulting text. /// </summary> /// <remarks> /// Converts the contents of <paramref name="reader"/> from the <see cref="InputFormat"/> to the /// <see cref="OutputFormat"/> and uses the <paramref name="writer"/> to write the resulting text. /// </remarks> /// <param name="reader">The text reader.</param> /// <param name="writer">The text writer.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="reader"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="writer"/> is <c>null</c>.</para> /// </exception> public override void Convert(TextReader reader, TextWriter writer) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } if (writer == null) { throw new ArgumentNullException(nameof(writer)); } if (!OutputHtmlFragment) { writer.Write("<html><body>"); } if (!string.IsNullOrEmpty(Header)) { if (HeaderFormat == HeaderFooterFormat.Text) { var converter = new TextToHtml { OutputHtmlFragment = true }; using (var sr = new StringReader(Header)) converter.Convert(sr, writer); } else { writer.Write(Header); } } using (var htmlWriter = new HtmlWriter(writer)) { var callback = HtmlTagCallback ?? DefaultHtmlTagCallback; var stack = new List <TextToHtmlTagContext> (); int currentQuoteDepth = 0, quoteDepth; TextToHtmlTagContext ctx; string line; while ((line = reader.ReadLine()) != null) { line = Unquote(line, out quoteDepth); while (currentQuoteDepth < quoteDepth) { ctx = new TextToHtmlTagContext(HtmlTagId.BlockQuote); callback(ctx, htmlWriter); currentQuoteDepth++; stack.Add(ctx); } while (quoteDepth < currentQuoteDepth) { ctx = stack[stack.Count - 1]; stack.RemoveAt(stack.Count - 1); if (!SuppressContent(stack) && !ctx.DeleteEndTag) { ctx.SetIsEndTag(true); if (ctx.InvokeCallbackForEndTag) { callback(ctx, htmlWriter); } else { ctx.WriteTag(htmlWriter); } } if (ctx.TagId == HtmlTagId.BlockQuote) { currentQuoteDepth--; } } if (!SuppressContent(stack)) { WriteText(htmlWriter, line); ctx = new TextToHtmlTagContext(HtmlTagId.Br); callback(ctx, htmlWriter); } } for (int i = stack.Count; i > 0; i--) { ctx = stack[i - 1]; ctx.SetIsEndTag(true); if (ctx.InvokeCallbackForEndTag) { callback(ctx, htmlWriter); } else { ctx.WriteTag(htmlWriter); } } htmlWriter.Flush(); } if (!string.IsNullOrEmpty(Footer)) { if (FooterFormat == HeaderFooterFormat.Text) { var converter = new TextToHtml { OutputHtmlFragment = true }; using (var sr = new StringReader(Footer)) converter.Convert(sr, writer); } else { writer.Write(Footer); } } if (!OutputHtmlFragment) { writer.Write("</body></html>"); } }
static void DefaultHtmlTagCallback(HtmlTagContext tagContext, HtmlWriter htmlWriter) { tagContext.WriteTag(htmlWriter, true); }
/// <summary> /// Convert the contents of <paramref name="reader"/> from the <see cref="InputFormat"/> to the /// <see cref="OutputFormat"/> and uses the <paramref name="writer"/> to write the resulting text. /// </summary> /// <remarks> /// Converts the contents of <paramref name="reader"/> from the <see cref="InputFormat"/> to the /// <see cref="OutputFormat"/> and uses the <paramref name="writer"/> to write the resulting text. /// </remarks> /// <param name="reader">The text reader.</param> /// <param name="writer">The text writer.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="reader"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="writer"/> is <c>null</c>.</para> /// </exception> public override void Convert(TextReader reader, TextWriter writer) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } if (writer == null) { throw new ArgumentNullException(nameof(writer)); } if (!OutputHtmlFragment) { writer.Write("<html><body>"); } if (!string.IsNullOrEmpty(Header)) { if (HeaderFormat == HeaderFooterFormat.Text) { var converter = new TextToHtml { OutputHtmlFragment = true }; using (var sr = new StringReader(Header)) converter.Convert(sr, writer); } else { writer.Write(Header); } } using (var htmlWriter = new HtmlWriter(writer)) { var callback = HtmlTagCallback ?? DefaultHtmlTagCallback; var stack = new List <FlowedToHtmlTagContext> (); var para = new StringBuilder(); int currentQuoteDepth = 0; int paraQuoteDepth = -1; int quoteDepth; string line; while ((line = reader.ReadLine()) != null) { // unquote the line line = Unquote(line, out quoteDepth); // remove space-stuffing if (line.Length > 0 && line[0] == ' ') { line = line.Substring(1); } if (para.Length == 0) { paraQuoteDepth = quoteDepth; } else if (quoteDepth != paraQuoteDepth) { // Note: according to rfc3676, when a folded line has a different quote // depth than the previous line, then quote-depth rules win and we need // to treat this as a new paragraph. WriteParagraph(htmlWriter, stack, ref currentQuoteDepth, para, paraQuoteDepth); paraQuoteDepth = quoteDepth; para.Length = 0; } para.Append(line); if (line.Length == 0 || line[line.Length - 1] != ' ') { // line did not end with a space, so the next line will start a new paragraph WriteParagraph(htmlWriter, stack, ref currentQuoteDepth, para, paraQuoteDepth); paraQuoteDepth = 0; para.Length = 0; } else if (DeleteSpace) { // Note: lines ending with a space mean that the next line is a continuation para.Length--; } } for (int i = stack.Count; i > 0; i--) { var ctx = stack[i - 1]; ctx.SetIsEndTag(true); if (ctx.InvokeCallbackForEndTag) { callback(ctx, htmlWriter); } else { ctx.WriteTag(htmlWriter); } } htmlWriter.Flush(); } if (!string.IsNullOrEmpty(Footer)) { if (FooterFormat == HeaderFooterFormat.Text) { var converter = new TextToHtml { OutputHtmlFragment = true }; using (var sr = new StringReader(Footer)) converter.Convert(sr, writer); } else { writer.Write(Footer); } } if (!OutputHtmlFragment) { writer.Write("</body></html>"); } }
void WriteParagraph(HtmlWriter htmlWriter, IList <FlowedToHtmlTagContext> stack, ref int currentQuoteDepth, StringBuilder para, int quoteDepth) { var callback = HtmlTagCallback ?? DefaultHtmlTagCallback; FlowedToHtmlTagContext ctx; while (currentQuoteDepth < quoteDepth) { ctx = new FlowedToHtmlTagContext(HtmlTagId.BlockQuote); callback(ctx, htmlWriter); currentQuoteDepth++; stack.Add(ctx); } while (quoteDepth < currentQuoteDepth) { ctx = stack[stack.Count - 1]; stack.RemoveAt(stack.Count - 1); if (!SuppressContent(stack) && !ctx.DeleteEndTag) { ctx.SetIsEndTag(true); if (ctx.InvokeCallbackForEndTag) { callback(ctx, htmlWriter); } else { ctx.WriteTag(htmlWriter); } } if (ctx.TagId == HtmlTagId.BlockQuote) { currentQuoteDepth--; } } if (SuppressContent(stack)) { return; } ctx = new FlowedToHtmlTagContext(para.Length == 0 ? HtmlTagId.Br : HtmlTagId.P); callback(ctx, htmlWriter); if (para.Length > 0) { if (!ctx.SuppressInnerContent) { WriteText(htmlWriter, para.ToString()); } if (!ctx.DeleteEndTag) { ctx.SetIsEndTag(true); if (ctx.InvokeCallbackForEndTag) { callback(ctx, htmlWriter); } else { ctx.WriteTag(htmlWriter); } } } if (!ctx.DeleteTag) { htmlWriter.WriteMarkupText(Environment.NewLine); } }
/// <summary> /// Convert the contents of <paramref name="reader"/> from the <see cref="InputFormat"/> to the /// <see cref="OutputFormat"/> and uses the <paramref name="writer"/> to write the resulting text. /// </summary> /// <remarks> /// Converts the contents of <paramref name="reader"/> from the <see cref="InputFormat"/> to the /// <see cref="OutputFormat"/> and uses the <paramref name="writer"/> to write the resulting text. /// </remarks> /// <param name="reader">The text reader.</param> /// <param name="writer">The text writer.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="reader"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="writer"/> is <c>null</c>.</para> /// </exception> public override void Convert (TextReader reader, TextWriter writer) { if (reader == null) throw new ArgumentNullException (nameof (reader)); if (writer == null) throw new ArgumentNullException (nameof (writer)); if (!string.IsNullOrEmpty (Header)) { if (HeaderFormat == HeaderFooterFormat.Text) { var converter = new TextToHtml (); using (var sr = new StringReader (Header)) converter.Convert (sr, writer); } else { writer.Write (Header); } } using (var htmlWriter = new HtmlWriter (writer)) { var callback = HtmlTagCallback ?? DefaultHtmlTagCallback; var stack = new List<FlowedToHtmlTagContext> (); var para = new StringBuilder (); int currentQuoteDepth = 0; int paraQuoteDepth = -1; int quoteDepth; string line; while ((line = reader.ReadLine ()) != null) { // unquote the line line = Unquote (line, out quoteDepth); // remove space-stuffing if (line.Length > 0 && line[0] == ' ') line = line.Substring (1); if (para.Length == 0) { paraQuoteDepth = quoteDepth; } else if (quoteDepth != paraQuoteDepth) { // Note: according to rfc3676, when a folded line has a different quote // depth than the previous line, then quote-depth rules win and we need // to treat this as a new paragraph. WriteParagraph (htmlWriter, stack, ref currentQuoteDepth, para, paraQuoteDepth); paraQuoteDepth = quoteDepth; para.Length = 0; } para.Append (line); if (line.Length == 0 || line[line.Length - 1] != ' ') { // line did not end with a space, so the next line will start a new paragraph WriteParagraph (htmlWriter, stack, ref currentQuoteDepth, para, paraQuoteDepth); paraQuoteDepth = 0; para.Length = 0; } else if (DeleteSpace) { // Note: lines ending with a space mean that the next line is a continuation para.Length--; } } for (int i = stack.Count; i > 0; i--) { var ctx = stack[i - 1]; ctx.SetIsEndTag (true); if (ctx.InvokeCallbackForEndTag) callback (ctx, htmlWriter); else ctx.WriteTag (htmlWriter); } htmlWriter.Flush (); } if (!string.IsNullOrEmpty (Footer)) { if (FooterFormat == HeaderFooterFormat.Text) { var converter = new TextToHtml (); using (var sr = new StringReader (Footer)) converter.Convert (sr, writer); } else { writer.Write (Footer); } } }
/// <summary> /// Write the HTML tag. /// </summary> /// <remarks> /// Writes the HTML tag to the given <see cref="HtmlWriter"/>. /// </remarks> /// <param name="htmlWriter">The HTML writer.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="htmlWriter"/> is <c>null</c>. /// </exception> public void WriteTag (HtmlWriter htmlWriter) { WriteTag (htmlWriter, false); }
void HtmlTagCallback(HtmlTagContext ctx, HtmlWriter htmlWriter) { if (ctx.TagId == HtmlTagId.Image && !ctx.IsEndTag && _stack.Count > 0) { ctx.WriteTag(htmlWriter, false); // replace the src attribute with a file:// URL foreach (var attribute in ctx.Attributes) { if (attribute.Id == HtmlAttributeId.Src) { MimePart image; if (!TryGetImage(attribute.Value, out image)) { htmlWriter.WriteAttribute(attribute); continue; } var url = SaveImage(image, attribute.Value); htmlWriter.WriteAttributeName(attribute.Name); htmlWriter.WriteAttributeValue(url); } else htmlWriter.WriteAttribute(attribute); } } else if (ctx.TagId == HtmlTagId.Body && !ctx.IsEndTag) { ctx.WriteTag(htmlWriter, false); // add and/or replace oncontextmenu="return false;" foreach (var attribute in ctx.Attributes) { if (attribute.Name.ToLowerInvariant() == "oncontextmenu") continue; htmlWriter.WriteAttribute(attribute); } htmlWriter.WriteAttribute("oncontextmenu", "return false;"); } else { // pass the tag through to the output ctx.WriteTag(htmlWriter, true); } }
/// <summary> /// Write the HTML tag. /// </summary> /// <remarks> /// Writes the HTML tag to the given <see cref="HtmlWriter"/>. /// </remarks> /// <example> /// <code language="c#" source="Examples\MimeVisitorExamples.cs" region="HtmlPreviewVisitor" /> /// </example> /// <param name="htmlWriter">The HTML writer.</param> /// <param name="writeAttributes"><c>true</c> if the <see cref="Attributes"/> should also be written; otherwise, <c>false</c>.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="htmlWriter"/> is <c>null</c>. /// </exception> public void WriteTag (HtmlWriter htmlWriter, bool writeAttributes) { if (htmlWriter == null) throw new ArgumentNullException ("htmlWriter"); if (IsEndTag) { htmlWriter.WriteEndTag (TagName); return; } if (IsEmptyElementTag) htmlWriter.WriteEmptyElementTag (TagName); else htmlWriter.WriteStartTag (TagName); if (writeAttributes) { for (int i = 0; i < Attributes.Count; i++) htmlWriter.WriteAttribute (Attributes[i]); } }
/// <summary> /// Convert the contents of <paramref name="reader"/> from the <see cref="InputFormat"/> to the /// <see cref="OutputFormat"/> and uses the <paramref name="writer"/> to write the resulting text. /// </summary> /// <remarks> /// Converts the contents of <paramref name="reader"/> from the <see cref="InputFormat"/> to the /// <see cref="OutputFormat"/> and uses the <paramref name="writer"/> to write the resulting text. /// </remarks> /// <param name="reader">The text reader.</param> /// <param name="writer">The text writer.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="reader"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="writer"/> is <c>null</c>.</para> /// </exception> public override void Convert (TextReader reader, TextWriter writer) { if (reader == null) throw new ArgumentNullException (nameof (reader)); if (writer == null) throw new ArgumentNullException (nameof (writer)); if (!string.IsNullOrEmpty (Header)) { if (HeaderFormat == HeaderFooterFormat.Text) { var converter = new TextToHtml (); using (var sr = new StringReader (Header)) converter.Convert (sr, writer); } else { writer.Write (Header); } } using (var htmlWriter = new HtmlWriter (writer)) { var callback = HtmlTagCallback ?? DefaultHtmlTagCallback; var stack = new List<HtmlToHtmlTagContext> (); var tokenizer = new HtmlTokenizer (reader); HtmlToHtmlTagContext ctx; HtmlToken token; while (tokenizer.ReadNextToken (out token)) { switch (token.Kind) { default: if (!SuppressContent (stack)) htmlWriter.WriteToken (token); break; case HtmlTokenKind.Tag: var tag = (HtmlTagToken) token; if (!tag.IsEndTag) { //if (NormalizeHtml && AutoClosingTags.Contains (startTag.TagName) && // (ctx = Pop (stack, startTag.TagName)) != null && // ctx.InvokeCallbackForEndTag && !SuppressContent (stack)) { // var value = string.Format ("</{0}>", ctx.TagName); // var name = ctx.TagName; // // ctx = new HtmlToHtmlTagContext (new HtmlTokenTag (HtmlTokenKind.EndTag, name, value)) { // InvokeCallbackForEndTag = ctx.InvokeCallbackForEndTag, // SuppressInnerContent = ctx.SuppressInnerContent, // DeleteEndTag = ctx.DeleteEndTag, // DeleteTag = ctx.DeleteTag // }; // callback (ctx, htmlWriter); //} if (!tag.IsEmptyElement) { ctx = new HtmlToHtmlTagContext (tag); if (FilterHtml && ctx.TagId == HtmlTagId.Script) { ctx.SuppressInnerContent = true; ctx.DeleteEndTag = true; ctx.DeleteTag = true; } else if (!SuppressContent (stack)) { callback (ctx, htmlWriter); } stack.Add (ctx); } else if (!SuppressContent (stack)) { ctx = new HtmlToHtmlTagContext (tag); if (!FilterHtml || ctx.TagId != HtmlTagId.Script) callback (ctx, htmlWriter); } } else { if ((ctx = Pop (stack, tag.Name)) != null) { if (!SuppressContent (stack)) { if (ctx.InvokeCallbackForEndTag) { ctx = new HtmlToHtmlTagContext (tag) { InvokeCallbackForEndTag = ctx.InvokeCallbackForEndTag, SuppressInnerContent = ctx.SuppressInnerContent, DeleteEndTag = ctx.DeleteEndTag, DeleteTag = ctx.DeleteTag }; callback (ctx, htmlWriter); } else if (!ctx.DeleteEndTag) { htmlWriter.WriteEndTag (tag.Name); } } } else if (!SuppressContent (stack)) { ctx = new HtmlToHtmlTagContext (tag); callback (ctx, htmlWriter); } } break; } } htmlWriter.Flush (); } if (!string.IsNullOrEmpty (Footer)) { if (FooterFormat == HeaderFooterFormat.Text) { var converter = new TextToHtml (); using (var sr = new StringReader (Footer)) converter.Convert (sr, writer); } else { writer.Write (Footer); } } }
/// <summary> /// Convert the contents of <paramref name="reader"/> from the <see cref="InputFormat"/> to the /// <see cref="OutputFormat"/> and uses the <paramref name="writer"/> to write the resulting text. /// </summary> /// <remarks> /// Converts the contents of <paramref name="reader"/> from the <see cref="InputFormat"/> to the /// <see cref="OutputFormat"/> and uses the <paramref name="writer"/> to write the resulting text. /// </remarks> /// <param name="reader">The text reader.</param> /// <param name="writer">The text writer.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="reader"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="writer"/> is <c>null</c>.</para> /// </exception> public override void Convert(TextReader reader, TextWriter writer) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } if (writer == null) { throw new ArgumentNullException(nameof(writer)); } if (!string.IsNullOrEmpty(Header)) { if (HeaderFormat == HeaderFooterFormat.Text) { var converter = new TextToHtml(); using (var sr = new StringReader(Header)) converter.Convert(sr, writer); } else { writer.Write(Header); } } using (var htmlWriter = new HtmlWriter(writer)) { var callback = HtmlTagCallback ?? DefaultHtmlTagCallback; var stack = new List <HtmlToHtmlTagContext> (); var tokenizer = new HtmlTokenizer(reader); HtmlToHtmlTagContext ctx; HtmlToken token; while (tokenizer.ReadNextToken(out token)) { switch (token.Kind) { default: if (!SuppressContent(stack)) { htmlWriter.WriteToken(token); } break; case HtmlTokenKind.Tag: var tag = (HtmlTagToken)token; if (!tag.IsEndTag) { if (!tag.IsEmptyElement) { ctx = new HtmlToHtmlTagContext(tag); if (FilterHtml && ctx.TagId == HtmlTagId.Script) { ctx.SuppressInnerContent = true; ctx.DeleteEndTag = true; ctx.DeleteTag = true; } else if (!SuppressContent(stack)) { callback(ctx, htmlWriter); } stack.Add(ctx); } else if (!SuppressContent(stack)) { ctx = new HtmlToHtmlTagContext(tag); if (!FilterHtml || ctx.TagId != HtmlTagId.Script) { callback(ctx, htmlWriter); } } } else { if ((ctx = Pop(stack, tag.Name)) != null) { if (!SuppressContent(stack)) { if (ctx.InvokeCallbackForEndTag) { ctx = new HtmlToHtmlTagContext(tag) { InvokeCallbackForEndTag = ctx.InvokeCallbackForEndTag, SuppressInnerContent = ctx.SuppressInnerContent, DeleteEndTag = ctx.DeleteEndTag, DeleteTag = ctx.DeleteTag }; callback(ctx, htmlWriter); } else if (!ctx.DeleteEndTag) { htmlWriter.WriteEndTag(tag.Name); } } } else if (!SuppressContent(stack)) { ctx = new HtmlToHtmlTagContext(tag); callback(ctx, htmlWriter); } } break; case HtmlTokenKind.Comment: if (!StripComments) { htmlWriter.WriteToken(token); } break; } } htmlWriter.Flush(); } if (!string.IsNullOrEmpty(Footer)) { if (FooterFormat == HeaderFooterFormat.Text) { var converter = new TextToHtml(); using (var sr = new StringReader(Footer)) converter.Convert(sr, writer); } else { writer.Write(Footer); } } }