1 /**
2 	HTML character entity escaping.
3 
4 	TODO: Make things @safe once Appender is.
5 
6 	Copyright: © 2012-2014 RejectedSoftware e.K.
7 	License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
8 	Authors: Sönke Ludwig
9 */
10 module dmarkdown.html;
11 
12 import std.array;
13 import std.conv;
14 import std.range;
15 
16 
17 package:
18 
19 
20 /** Writes the HTML escaped version of a given string to an output range.
21 */
22 void filterHTMLEscape(R, S)(ref R dst, S str, HTMLEscapeFlags flags = HTMLEscapeFlags.escapeNewline)
23 	if (isOutputRange!(R, dchar) && isInputRange!S)
24 {
25 	for (;!str.empty;str.popFront())
26 		filterHTMLEscape(dst, str.front, flags);
27 }
28 
29 /** Writes the HTML escaped version of a given string to an output range (also escapes double quotes).
30 */
31 void filterHTMLAttribEscape(R, S)(ref R dst, S str)
32 	if (isOutputRange!(R, dchar) && isInputRange!S)
33 {
34 	for (; !str.empty; str.popFront())
35 		filterHTMLEscape(dst, str.front, HTMLEscapeFlags.escapeNewline|HTMLEscapeFlags.escapeQuotes);
36 }
37 
38 /** Writes the HTML escaped version of a given string to an output range (escapes every character).
39 */
40 void filterHTMLAllEscape(R, S)(ref R dst, S str)
41 	if (isOutputRange!(R, dchar) && isInputRange!S)
42 {
43 	for (; !str.empty; str.popFront()) {
44 		dst.put("&#");
45 		dst.put(to!string(cast(uint)str.front));
46 		dst.put(';');
47 	}
48 }
49 
50 /**
51 	Writes the HTML escaped version of a character to an output range.
52 */
53 void filterHTMLEscape(R)(ref R dst, dchar ch, HTMLEscapeFlags flags = HTMLEscapeFlags.escapeNewline )
54 {
55 	switch (ch) {
56 		default:
57 			if (flags & HTMLEscapeFlags.escapeUnknown) {
58 				dst.put("&#");
59 				dst.put(to!string(cast(uint)ch));
60 				dst.put(';');
61 			} else dst.put(ch);
62 			break;
63 		case '"':
64 			if (flags & HTMLEscapeFlags.escapeQuotes) dst.put(""");
65 			else dst.put('"');
66 			break;
67 		case '\'':
68 			if (flags & HTMLEscapeFlags.escapeQuotes) dst.put("'");
69 			else dst.put('\'');
70 			break;
71 		case '\r', '\n':
72 			if (flags & HTMLEscapeFlags.escapeNewline) {
73 				dst.put("&#");
74 				dst.put(to!string(cast(uint)ch));
75 				dst.put(';');
76 			} else dst.put(ch);
77 			break;
78 		case 'a': .. case 'z': goto case;
79 		case 'A': .. case 'Z': goto case;
80 		case '0': .. case '9': goto case;
81 		case ' ', '\t', '-', '_', '.', ':', ',', ';',
82 		     '#', '+', '*', '?', '=', '(', ')', '/', '!',
83 		     '%' , '{', '}', '[', ']', '`', '´', '$', '^', '~':
84 		    dst.put(cast(char)ch);
85 			break;
86 		case '<': dst.put("&lt;"); break;
87 		case '>': dst.put("&gt;"); break;
88 		case '&': dst.put("&amp;"); break;
89 	}
90 }
91 
92 
93 enum HTMLEscapeFlags {
94 	escapeMinimal = 0,
95 	escapeQuotes = 1<<0,
96 	escapeNewline = 1<<1,
97 	escapeUnknown = 1<<2
98 }