1 module html.utils;
2 
3 
4 import std.ascii;
5 import std.typecons;
6 
7 
8 bool isAllWhite(Char)(Char[] value) {
9 	auto ptr = value.ptr;
10 	const end = ptr + value.length;
11 
12 	while (ptr != end) {
13 		if (!isWhite(*ptr++))
14 			return false;
15 	}
16 	return true;
17 }
18 
19 
20 bool requiresQuotes(Char)(Char[] value) {
21 	auto ptr = value.ptr;
22 	const end = ptr + value.length;
23 
24 	while (ptr != end) {
25 		switch (*ptr++) {
26 		case 'a': .. case 'z':
27 		case 'A': .. case 'Z':
28 		case '0': .. case '9':
29 		case '-':
30 		case '_':
31 		case '.':
32 		case ':':
33 			continue;
34 		default:
35 			return true;
36 		}
37 	}
38 	return false;
39 }
40 
41 
42 bool equalsCI(CharA, CharB)(const(CharA)[] a, const(CharB)[] b) {
43 	if (a.length == b.length) {
44 		for (size_t i; i < a.length; ++i) {
45 			if (std.ascii.toLower(a.ptr[i]) != std.ascii.toLower(b.ptr[i]))
46 				return false;
47 		}
48 		return true;
49 	}
50 	return false;
51 }
52 
53 
54 enum QuickHash64Seed = 14695981039346656037u;
55 enum QuickHash64Scale = 1099511628211u;
56 
57 
58 ulong quickHash64(const(char)* p, const(char)* pend, ulong hash = QuickHash64Seed) {
59 	while (p != pend)
60 		hash = (hash ^ cast(ulong)(*p++)) * QuickHash64Scale;
61 	return hash;
62 }
63 
64 
65 ulong quickHash64i(const(char)* p, const(char)* pend, ulong hash = QuickHash64Seed) {
66 	while (p != pend)
67 		hash = (hash ^ cast(ulong)(std.ascii.toLower(*p++))) * QuickHash64Scale;
68 	return hash;
69 }
70 
71 
72 hash_t quickHashOf(const(char)[] x) {
73 	return cast(hash_t)quickHash64(x.ptr, x.ptr + x.length);
74 }
75 
76 
77 hash_t tagHashOf(const(char)[] x) {
78 	return cast(hash_t)quickHash64i(x.ptr, x.ptr + x.length);
79 }
80 
81 
82 void writeQuotesEscaped(Appender)(ref Appender app, const(char)[] x) {
83 	auto ptr = x.ptr;
84 	const end = x.ptr + x.length;
85 
86 	while (ptr != end) {
87 		const ch = *ptr++;
88 		if (ch != '"') {
89 			app.put(ch);
90 		} else {
91 			app.put("&#34;"); // shorter than &quot;
92 		}
93 	}
94 }
95 
96 
97 void writeHTMLEscaped(Flag!q{escapeQuotes} escapeQuotes, Appender)(ref Appender app, const(char)[] x) {
98 	auto ptr = x.ptr;
99 	const end = x.ptr + x.length;
100 
101 	while (ptr != end) {
102 		const ch = *ptr++;
103 		switch (ch) {
104 			static if (escapeQuotes) {
105 				case '"':
106 					app.put("&#34;"); // shorter than &quot;
107 					break;
108 			}
109 			case '<':
110 				app.put("&lt;");
111 				break;
112 			case '>':
113 				app.put("&gt;");
114 				break;
115 			case '&':
116 				app.put("&amp;");
117 				break;
118 			default:
119 				app.put(ch);
120 				break;
121 		}
122 	}
123 }