/// <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); } } }