An HTML writer.
An HTML writer.
Наследование: IDisposable
Пример #1
0
		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));
			}
		}
Пример #2
0
			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);
						}
					}
				}
			}
Пример #3
0
		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);
		}
Пример #4
0
		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);
		}
Пример #5
0
		/// <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);
				}
			}
		}
Пример #6
0
		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);
			}
		}
Пример #7
0
		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);
			}
		}
Пример #8
0
        /// <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);
                }
            }
        }
Пример #9
0
		static void DefaultHtmlTagCallback (HtmlTagContext tagContext, HtmlWriter htmlWriter)
		{
			tagContext.WriteTag (htmlWriter, true);
		}
Пример #10
0
		public void TestHtmlWriter ()
		{
			const string expected = "<html ltr=\"true\"><head/><body><p class=\"paragraph\">" +
				"special characters in this text should get encoded: &lt;&gt;&#39;&amp;\n" +
				"special characters should not get encoded: &lt;&gt;" +
				"</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: &lt;&gt;");
				Assert.AreEqual (HtmlWriterState.Default, html.WriterState);

				html.WriteEndTag (HtmlTagId.P);

				html.WriteEndTag (HtmlTagId.Body);
				html.WriteEndTag ("html");
			}

			Assert.AreEqual (expected, actual.ToString ());
		}
Пример #11
0
        /// <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>");
            }
        }
Пример #12
0
 static void DefaultHtmlTagCallback(HtmlTagContext tagContext, HtmlWriter htmlWriter)
 {
     tagContext.WriteTag(htmlWriter, true);
 }
Пример #13
0
        /// <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>");
            }
        }
Пример #14
0
        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);
            }
        }
Пример #15
0
		/// <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);
				}
			}
		}
Пример #16
0
		/// <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);
		}
Пример #17
0
        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);
            }
        }
Пример #18
0
		/// <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]);
			}
		}
Пример #19
0
		/// <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);
				}
			}
		}
Пример #20
0
        /// <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);
                }
            }
        }