CMSDK 2.0.1
Cross-platform C++ base library and SDK for the Psyclone AIOS platform
Loading...
Searching...
No Matches
HTML.cpp
Go to the documentation of this file.
1
5#include "HTML.h"
6#include "PsyTime.h"
7#include "UnitTestFramework.h"
8
9namespace cmlabs {
10namespace html {
11
12std::string DecodeHTML(std::string str) {
13
14 size_t p = 0, c;
15 while ((p = str.find("+", p)) != std::string::npos) {
16 str.replace(p, 1, 1, ' ');
17 }
18
19 char ch;
20 p = 0;
21 while ((p = str.find("&", p)) != std::string::npos) {
22 if ( (c = str.find(";", p)) != std::string::npos ) {
23 // Check string between p - c
24 if (str[p+1] == '#') {
25 if (str[p+2] == 'x')
26 ch = (char) strtol(str.substr(p+3, c-p-3).c_str(), NULL, 16);
27 else
28 ch = (char) strtol(str.substr(p+2, c-p-2).c_str(), NULL, 10);
29 if (ch == 0)
30 ch = ' ';
31 str.replace(p, c-p+1, 1, ch);
32 }
33 else {
34 str.replace(p, c-p+1, 1, (char)html::HTML2Char(str.substr(p+1, c-p-1).c_str()));
35 }
36 }
37 p++;
38 }
39
40 p = 0;
41 while ((p = str.find("%", p)) != std::string::npos) {
42 ch = (char) strtol(str.substr(p+1, 2).c_str(), NULL, 16);
43 if (ch == 0)
44 ch = ' ';
45 str.replace(p, 3, 1, ch);
46 }
47
48 return str;
49}
50
51std::string EncodeHTML(std::string str) {
52 if (str.size() == 0)
53 return str;
54 std::string result = str;
55 char c;
56 char* tmp = (char*)malloc(20);
57
58 for (uint32 n=0; n<result.size(); n++) {
59 switch(c = result[n]) {
60 case '\n':
61 result.replace(n, 1, "<br>\n");
62 n+=4;
63 break;
64 case '\r':
65 result.replace(n, 1, "");
66 n-=1;
67 break;
68 case '\t':
69 result.replace(n, 1, "&nbsp;&nbsp;&nbsp;");
70 n+=17;
71 break;
72 default:
73 if ( (c < 32) || (c > 122) ||
74 ( (c > 90) && (c < 97) ) ||
75 ( (c > 57) && (c < 65) ) ||
76 ( (c > 33) && (c < 48) ) ) {
77 snprintf(tmp, 20, "&#x%x;", (int) c & 0xFF);
78 result.replace(n, 1, tmp);
79 n+=(uint32)strlen(tmp)-1;
80 }
81 break;
82 }
83 }
84
85 free((char*)tmp);
86
87 return result;
88}
89
90unsigned char HTML2Char(const char* str) {
91 if (strcmp(str, "amp") == 0)
92 return '&';
93 else if (strcmp(str, "lt") == 0)
94 return '<';
95 else if (strcmp(str, "gt") == 0)
96 return '>';
97 else if (strcmp(str, "quot") == 0)
98 return '"';
99 else if (strcmp(str, "apos") == 0)
100 return '\'';
101 else if (strcmp(str, "lsquo") == 0)
102 return (unsigned char)0x91;
103 else if (strcmp(str, "rsquo") == 0)
104 return (unsigned char)0x92;
105 else if (strcmp(str, "sbquo") == 0)
106 return (unsigned char)0x82;
107 else if (strcmp(str, "ldquo") == 0)
108 return (unsigned char)0x93;
109 else if (strcmp(str, "rdquo") == 0)
110 return (unsigned char)0x94;
111 else if (strcmp(str, "bdquo") == 0)
112 return (unsigned char)0x84;
113 else if (strcmp(str, "dagger") == 0)
114 return (unsigned char)0x86;
115 else if (strcmp(str, "Dagger") == 0)
116 return (unsigned char)0x87;
117 else if (strcmp(str, "permil") == 0)
118 return (unsigned char)0x89;
119 else if (strcmp(str, "lsaquo") == 0)
120 return (unsigned char)0x8B;
121 else if (strcmp(str, "rsaquo") == 0)
122 return (unsigned char)0x9B;
123 else if (strcmp(str, "trade") == 0)
124 return (unsigned char)0x99;
125 else
126 return ' ';
127}
128
129
130bool IsMimeBinary(const char* type) {
131 if (utils::stristr(type, "text") || utils::stristr(type, "json"))
132 return false;
133 else
134 return true;
135}
136
137bool GetMimeType(char* dest, const char* filename, uint32 maxsize) {
138 bool isBinary;
139 return GetMimeType(dest, filename, maxsize, isBinary);
140}
141
142bool GetMimeType(char* dest, const char* filename, uint32 maxsize, bool &isBinary) {
143
144 isBinary = true;
145 if (maxsize < 5) {
146 utils::strcpyavail(dest, "", maxsize, false);
147 return false;
148 }
149 else if (!filename) {
150 return (utils::strcpyavail(dest, "application/octet-stream", maxsize, false) != 0);
151 }
152
153 if (utils::TextEndsWith(filename, ".bmp"))
154 return (utils::strcpyavail(dest, "image/bmp", maxsize, false) != 0);
155 else if (utils::TextEndsWith(filename, ".gif"))
156 return (utils::strcpyavail(dest, "image/gif", maxsize, false) != 0);
157 else if (utils::TextEndsWith(filename, ".jpg"))
158 return (utils::strcpyavail(dest, "image/jpeg", maxsize, false) != 0);
159 else if (utils::TextEndsWith(filename, ".png"))
160 return (utils::strcpyavail(dest, "image/png", maxsize, false) != 0);
161 else if (utils::TextEndsWith(filename, ".svg"))
162 return (utils::strcpyavail(dest, "image/svg+xml", maxsize, false) != 0);
163 else if (utils::TextEndsWith(filename, ".tif"))
164 return (utils::strcpyavail(dest, "image/tiff", maxsize, false) != 0);
165 else if (utils::TextEndsWith(filename, ".ico"))
166 return (utils::strcpyavail(dest, "image/x-icon", maxsize, false) != 0);
167 else if (utils::TextEndsWith(filename, ".apk"))
168 return (utils::strcpyavail(dest, "application/vnd.android.package-archive", maxsize, false) != 0);
169
170 else if ( (utils::TextEndsWith(filename, ".html")) || (utils::TextEndsWith(filename, ".htm")) ) {
171 isBinary = false;
172 return (utils::strcpyavail(dest, "text/html", maxsize, false) != 0);
173 }
174 else if (utils::TextEndsWith(filename, ".css")) {
175 isBinary = false;
176 return (utils::strcpyavail(dest, "text/css", maxsize, false) != 0);
177 }
178 else if (utils::TextEndsWith(filename, ".js")) {
179 isBinary = false;
180 return (utils::strcpyavail(dest, "text/javascript", maxsize, false) != 0);
181 }
182 else if (utils::TextEndsWith(filename, ".json")) { // should ideally be 'application/json', but IE <= 8 doesn't work :-)
183 isBinary = false;
184 return (utils::strcpyavail(dest, "application/json", maxsize, false) != 0);
185 //return (utils::strcpyavail(dest, "text/html", maxsize, false) != 0);
186 }
187 else if (utils::TextEndsWith(filename, ".xml")) {
188 isBinary = false;
189 return (utils::strcpyavail(dest, "text/xml", maxsize, false) != 0);
190 }
191 else if (utils::TextEndsWith(filename, ".txt")) {
192 isBinary = false;
193 return (utils::strcpyavail(dest, "text/plain", maxsize, false) != 0);
194 }
195 else if (utils::TextEndsWith(filename, ".log")) {
196 isBinary = false;
197 return (utils::strcpyavail(dest, "text/plain", maxsize, false) != 0);
198 }
199 else if (utils::TextEndsWith(filename, ".bin"))
200 return (utils::strcpyavail(dest, "application/octet-stream", maxsize, false) != 0);
201
202 else if ( (utils::TextEndsWith(filename, ".mp3"))
203 || (utils::TextEndsWith(filename, ".mpg"))
204 || (utils::TextEndsWith(filename, ".mpa")) )
205 return (utils::strcpyavail(dest, "audio/mpeg", maxsize, false) != 0);
206 else if (utils::TextEndsWith(filename, ".wav"))
207 return (utils::strcpyavail(dest, "audio/x-wav", maxsize, false) != 0);
208 else if ( (utils::TextEndsWith(filename, ".mpeg"))
209 || (utils::TextEndsWith(filename, ".mpe"))
210 || (utils::TextEndsWith(filename, ".mp2"))
211 || (utils::TextEndsWith(filename, ".mpv2")) )
212 return (utils::strcpyavail(dest, "video/mpeg", maxsize, false) != 0);
213 else if (utils::TextEndsWith(filename, ".mp4"))
214 return (utils::strcpyavail(dest, "video/mp4", maxsize, false) != 0);
215 else if (utils::TextEndsWith(filename, ".avi"))
216 return (utils::strcpyavail(dest, "video/msvideo", maxsize, false) != 0);
217 else if (utils::TextEndsWith(filename, ".h263"))
218 return (utils::strcpyavail(dest, "video/h263", maxsize, false) != 0);
219 else if (utils::TextEndsWith(filename, ".h264"))
220 return (utils::strcpyavail(dest, "video/h264", maxsize, false) != 0);
221 else if ( (utils::TextEndsWith(filename, ".qt")) || (utils::TextEndsWith(filename, ".mov")) )
222 return (utils::strcpyavail(dest, "video/quicktime", maxsize, false) != 0);
223
224 else if (utils::TextEndsWith(filename, ".zip"))
225 return (utils::strcpyavail(dest, "application/zip", maxsize, false) != 0);
226 else if (utils::TextEndsWith(filename, ".gz"))
227 return (utils::strcpyavail(dest, "application/x-gzip", maxsize, false) != 0);
228 else if (utils::TextEndsWith(filename, ".tar"))
229 return (utils::strcpyavail(dest, "application/x-tar", maxsize, false) != 0);
230 else if (utils::TextEndsWith(filename, ".pdf"))
231 return (utils::strcpyavail(dest, "application/pdf", maxsize, false) != 0);
232 else if (utils::TextEndsWith(filename, ".doc"))
233 return (utils::strcpyavail(dest, "application/msword", maxsize, false) != 0);
234 else if (utils::TextEndsWith(filename, ".xls"))
235 return (utils::strcpyavail(dest, "application/vnd.ms-excel", maxsize, false) != 0);
236 else if (utils::TextEndsWith(filename, ".ppt"))
237 return (utils::strcpyavail(dest, "application/vnd.ms-powerpoint", maxsize, false) != 0);
238
239 else if (utils::TextEndsWith(filename, ".eot"))
240 return (utils::strcpyavail(dest, "application/vnd.ms-fontobject", maxsize, false) != 0);
241 else if (utils::TextEndsWith(filename, ".woff"))
242 return (utils::strcpyavail(dest, "application/font-woff", maxsize, false) != 0);
243 else if (utils::TextEndsWith(filename, ".woff2"))
244 return (utils::strcpyavail(dest, "application/font-woff2", maxsize, false) != 0);
245 else if (utils::TextEndsWith(filename, ".ttf"))
246 return (utils::strcpyavail(dest, "application/x-font-truetype", maxsize, false) != 0);
247 else if (utils::TextEndsWith(filename, ".otf"))
248 return (utils::strcpyavail(dest, "application/x-font-opentype", maxsize, false) != 0);
249
250 else
251 return (utils::strcpyavail(dest, "application/octet-stream", maxsize, false) != 0);
252}
253
254
255std::string GetUsernameFromURL(std::string url) {
256 std::string auth = GetAuthenticationFromURL(url);
257 if (!auth.size())
258 return "";
259
260 size_t colon = url.find(':');
261 if (colon == std::string::npos)
262 return auth;
263 else
264 return url.substr(0, colon);
265}
266
267std::string GetPasswordFromURL(std::string url) {
268 std::string auth = GetAuthenticationFromURL(url);
269 if (!auth.size())
270 return "";
271
272 size_t colon = url.find(':');
273 if (colon == std::string::npos)
274 return "";
275 else
276 return url.substr(colon+1);
277}
278
279std::string GetAuthenticationFromURL(std::string url) {
280 size_t start = url.find("//");
281 if (start == std::string::npos)
282 return "";
283
284 size_t offset = url.find("@");
285 if (offset == std::string::npos)
286 return "";
287
288 return url.substr(start, offset-start);
289}
290
291std::string GetHostFromURL(std::string url) {
292 size_t offset = url.find("@");
293 if (offset == std::string::npos) {
294 offset = url.find("//");
295 if (offset == std::string::npos)
296 return "";
297 else
298 offset += 2;
299 }
300 else
301 offset++;
302
303 size_t end = url.find(':', offset);
304 if (end != std::string::npos)
305 return url.substr(offset, end-offset);
306
307 end = url.find('/', offset);
308 if (end != std::string::npos)
309 return url.substr(offset, end-offset);
310
311 return url.substr(offset);
312}
313
314uint16 GetPortFromURL(std::string url) {
315 size_t offset = url.find("@");
316 if (offset == std::string::npos) {
317 offset = url.find("//");
318 if (offset == std::string::npos)
319 return 0;
320 else
321 offset += 2;
322 }
323 else
324 offset++;
325
326 size_t colon = url.find(':', offset);
327 if (colon == std::string::npos)
328 return 0;
329
330 return (uint16) utils::Ascii2Uint32(url.substr(colon+1).c_str());
331}
332
333std::string GetProtocolFromURL(std::string url) {
334 if (url.find("http:") == 0)
335 return "http";
336 else if (url.find("https:") == 0)
337 return "https";
338 else if (url.find("ftp:") == 0)
339 return "ftp";
340
341 size_t offset = url.find("//");
342 if (offset == std::string::npos)
343 return "";
344
345 return url.substr(0, offset);
346}
347
348std::string GetURIFromURL(std::string url) {
349 size_t offset = url.find("//");
350 if (offset == std::string::npos)
351 return "";
352
353 offset += 2;
354
355 size_t end = url.find('/', offset);
356 if (end != std::string::npos)
357 return url.substr(end);
358 else
359 return "/";
360}
361
363
364 // 1. HTML entity decoding of named entities via HTML2Char
365 unittest::progress(5, "named entity decoding");
366 {
367 if (HTML2Char("amp") != '&') { unittest::fail("HTML test: HTML2Char amp mismatch\n"); return false; }
368 if (HTML2Char("lt") != '<') { unittest::fail("HTML test: HTML2Char lt mismatch\n"); return false; }
369 if (HTML2Char("gt") != '>') { unittest::fail("HTML test: HTML2Char gt mismatch\n"); return false; }
370 if (HTML2Char("quot") != '"') { unittest::fail("HTML test: HTML2Char quot mismatch\n"); return false; }
371 if (HTML2Char("apos") != '\'') { unittest::fail("HTML test: HTML2Char apos mismatch\n"); return false; }
372 // Unknown entity falls back to space
373 if (HTML2Char("notanentity") != ' ') { unittest::fail("HTML test: HTML2Char unknown not space\n"); return false; }
374 }
375
376 // 2. EncodeHTML escaping of special characters
377 unittest::progress(20, "encode escaping");
378 {
379 // Plain alphanumerics are left untouched
380 if (EncodeHTML("Hello123") != "Hello123") { unittest::fail("HTML test: EncodeHTML altered plain text\n"); return false; }
381 // Empty string stays empty
382 if (EncodeHTML("") != "") { unittest::fail("HTML test: EncodeHTML empty not empty\n"); return false; }
383 // Special chars are escaped to numeric hex entities
384 if (EncodeHTML("<") != "&#x3c;") { unittest::fail("HTML test: EncodeHTML '<' mismatch\n"); return false; }
385 if (EncodeHTML(">") != "&#x3e;") { unittest::fail("HTML test: EncodeHTML '>' mismatch\n"); return false; }
386 if (EncodeHTML("&") != "&#x26;") { unittest::fail("HTML test: EncodeHTML '&' mismatch\n"); return false; }
387 // Newline becomes a line break, carriage return is stripped, tab becomes spaces
388 if (EncodeHTML("\n") != "<br>\n") { unittest::fail("HTML test: EncodeHTML newline mismatch\n"); return false; }
389 if (EncodeHTML("\r") != "") { unittest::fail("HTML test: EncodeHTML carriage return not stripped\n"); return false; }
390 if (EncodeHTML("\t") != "&nbsp;&nbsp;&nbsp;") { unittest::fail("HTML test: EncodeHTML tab mismatch\n"); return false; }
391 unittest::detail("EncodeHTML('a<b>c') = '%s'", EncodeHTML("a<b>c").c_str());
392 }
393
394 // 3. DecodeHTML of named, decimal, hex and percent encodings
395 unittest::progress(40, "decode decoding");
396 {
397 // Named entities
398 if (DecodeHTML("a&amp;b") != "a&b") { unittest::fail("HTML test: DecodeHTML &amp; mismatch\n"); return false; }
399 if (DecodeHTML("&lt;tag&gt;") != "<tag>") { unittest::fail("HTML test: DecodeHTML lt/gt mismatch\n"); return false; }
400 // Decimal numeric entity (65 == 'A')
401 if (DecodeHTML("&#65;") != "A") { unittest::fail("HTML test: DecodeHTML decimal mismatch\n"); return false; }
402 // Hex numeric entity (0x42 == 'B')
403 if (DecodeHTML("&#x42;") != "B") { unittest::fail("HTML test: DecodeHTML hex mismatch\n"); return false; }
404 // Plus signs decode to spaces
405 if (DecodeHTML("hello+world") != "hello world") { unittest::fail("HTML test: DecodeHTML plus mismatch\n"); return false; }
406 // Percent encoding (%20 == space)
407 if (DecodeHTML("a%20b") != "a b") { unittest::fail("HTML test: DecodeHTML percent mismatch\n"); return false; }
408 // Round-trip of encoded special characters back through decode
409 if (DecodeHTML(EncodeHTML("<>&")) != "<>&") { unittest::fail("HTML test: encode/decode round-trip mismatch\n"); return false; }
410 }
411
412 // 4. MIME type lookup by file extension
413 unittest::progress(55, "mime type lookup");
414 {
415 char mime[128];
416 bool isBinary = true;
417 if (!GetMimeType(mime, "page.html", sizeof(mime), isBinary) || strcmp(mime, "text/html") != 0) {
418 unittest::fail("HTML test: GetMimeType html mismatch\n"); return false;
419 }
420 if (isBinary) { unittest::fail("HTML test: GetMimeType html flagged binary\n"); return false; }
421 if (!GetMimeType(mime, "image.png", sizeof(mime), isBinary) || strcmp(mime, "image/png") != 0) {
422 unittest::fail("HTML test: GetMimeType png mismatch\n"); return false;
423 }
424 if (!isBinary) { unittest::fail("HTML test: GetMimeType png not flagged binary\n"); return false; }
425 if (!GetMimeType(mime, "data.json", sizeof(mime), isBinary) || strcmp(mime, "application/json") != 0) {
426 unittest::fail("HTML test: GetMimeType json mismatch\n"); return false;
427 }
428 // Unknown extension falls back to octet-stream
429 if (!GetMimeType(mime, "file.unknownext", sizeof(mime), isBinary) || strcmp(mime, "application/octet-stream") != 0) {
430 unittest::fail("HTML test: GetMimeType unknown fallback mismatch\n"); return false;
431 }
432 // Three-arg overload should agree with the four-arg form
433 if (!GetMimeType(mime, "doc.txt", sizeof(mime)) || strcmp(mime, "text/plain") != 0) {
434 unittest::fail("HTML test: GetMimeType 3-arg txt mismatch\n"); return false;
435 }
436 // Binary classification of MIME strings
437 if (IsMimeBinary("text/html")) { unittest::fail("HTML test: IsMimeBinary text/html true\n"); return false; }
438 if (IsMimeBinary("application/json")) { unittest::fail("HTML test: IsMimeBinary json true\n"); return false; }
439 if (!IsMimeBinary("image/png")) { unittest::fail("HTML test: IsMimeBinary image/png false\n"); return false; }
440 }
441
442 // 5. URL component parsing
443 unittest::progress(70, "URL parsing");
444 {
445 std::string url = "http://user:pass@example.com:8080/path/to/page";
446 if (GetProtocolFromURL(url) != "http") { unittest::fail("HTML test: GetProtocolFromURL mismatch\n"); return false; }
447 if (GetHostFromURL(url) != "example.com") { unittest::fail("HTML test: GetHostFromURL mismatch\n"); return false; }
448 if (GetPortFromURL(url) != 8080) { unittest::fail("HTML test: GetPortFromURL mismatch\n"); return false; }
449 if (GetURIFromURL(url) != "/path/to/page") { unittest::fail("HTML test: GetURIFromURL mismatch\n"); return false; }
450
451 // https protocol detection
452 if (GetProtocolFromURL("https://secure.example.com/") != "https") { unittest::fail("HTML test: GetProtocolFromURL https mismatch\n"); return false; }
453
454 // Host without credentials or port
455 std::string simple = "http://host.example.org/";
456 if (GetHostFromURL(simple) != "host.example.org") { unittest::fail("HTML test: GetHostFromURL simple mismatch\n"); return false; }
457 if (GetPortFromURL(simple) != 0) { unittest::fail("HTML test: GetPortFromURL simple not zero\n"); return false; }
458
459 // URL with no path returns root URI
460 if (GetURIFromURL("http://host.example.org") != "/") { unittest::fail("HTML test: GetURIFromURL root mismatch\n"); return false; }
461 unittest::detail("parsed host=%s port=%u", GetHostFromURL(url).c_str(), (unsigned)GetPortFromURL(url));
462 }
463
464 // 6. Throughput metric for encode/decode
465 unittest::progress(85, "throughput");
466 {
467 const int N = 20000;
468 std::string sample = "Tom & Jerry <said> \"hi\"\nwith\ttabs";
469 uint64 t0 = GetTimeNow();
470 std::string enc;
471 for (int i = 0; i < N; i++)
472 enc = EncodeHTML(sample);
473 double encUs = (double)(GetTimeNow() - t0);
474 if (enc.empty()) { unittest::fail("HTML test: EncodeHTML produced empty result\n"); return false; }
475
476 t0 = GetTimeNow();
477 std::string dec;
478 for (int i = 0; i < N; i++)
479 dec = DecodeHTML(enc);
480 double decUs = (double)(GetTimeNow() - t0);
481 if (dec.empty()) { unittest::fail("HTML test: DecodeHTML produced empty result\n"); return false; }
482
483 if (encUs > 0)
484 unittest::metric("encode_throughput", (double)N / encUs * 1e6, "ops/s", true);
485 if (decUs > 0)
486 unittest::metric("decode_throughput", (double)N / decUs * 1e6, "ops/s", true);
487 }
488
489 unittest::progress(100, "done");
490 return true;
491}
492
493} // namespace html
494
497 "HTML entity encode/decode, MIME type lookup, URL parsing", "util");
498}
499
500} // namespace cmlabs
501
502
HTML/URL helper utilities: entity encoding/decoding, MIME type lookup and URL component parsing.
CMSDK time: µs-resolution 64-bit timestamps and the Time Mapping Constant (TMC).
Small, dependency-free unit test harness used by all CMSDK object tests.
static UnitTestRunner & instance()
Access the singleton (created on first use).
void registerTest(const char *name, UnitTestFunc func, const char *description="", const char *category="", bool inDefaultRun=true)
Register a test with the runner.
uint64 GetTimeNow()
Return the current absolute time (µs since year 0) according to the TMC.
Definition PsyTime.cpp:69
uint32 Ascii2Uint32(const char *ascii, uint32 start=0, uint32 end=0)
Parse an unsigned 32-bit decimal integer from a substring.
Definition Utils.cpp:7526
const char * stristr(const char *str, const char *substr, uint32 len=0)
Case-insensitive strstr.
Definition Utils.cpp:6035
bool TextEndsWith(const char *str, const char *end, bool caseSensitive=true)
Test whether str ends with end.
Definition Utils.cpp:7233
uint32 strcpyavail(char *dst, const char *src, uint32 maxlen, bool copyAvailable)
Bounded strcpy that always NUL-terminates.
Definition Utils.cpp:6056
bool HTML_UnitTest()
Self-contained unit test of the HTML/URL helpers.
Definition HTML.cpp:362
std::string GetURIFromURL(std::string url)
Extract the URI (path plus query) from a URL.
Definition HTML.cpp:348
std::string GetProtocolFromURL(std::string url)
Extract the protocol/scheme from a URL.
Definition HTML.cpp:333
bool GetMimeType(char *dest, const char *filename, uint32 maxsize)
Look up the MIME type for a filename based on its extension.
Definition HTML.cpp:137
bool IsMimeBinary(const char *type)
Determine whether a MIME type denotes binary content.
Definition HTML.cpp:130
std::string GetUsernameFromURL(std::string url)
Extract the username from a URL of the form scheme://user:pass@host/...
Definition HTML.cpp:255
unsigned char HTML2Char(const char *str)
Convert a single HTML entity (e.g.
Definition HTML.cpp:90
std::string EncodeHTML(std::string str)
Encode a plain string for safe embedding in HTML (e.g.
Definition HTML.cpp:51
std::string GetPasswordFromURL(std::string url)
Extract the password from a URL of the form scheme://user:pass@host/...
Definition HTML.cpp:267
std::string GetHostFromURL(std::string url)
Extract the host name (or IP literal) from a URL.
Definition HTML.cpp:291
uint16 GetPortFromURL(std::string url)
Extract the port number from a URL.
Definition HTML.cpp:314
std::string DecodeHTML(std::string str)
Decode HTML entities in a string (e.g.
Definition HTML.cpp:12
std::string GetAuthenticationFromURL(std::string url)
Extract the full "user:pass" authentication section from a URL.
Definition HTML.cpp:279
void fail(const char *fmt,...)
Set an explanatory reason shown on the FAIL line.
void metric(const char *name, double value, const char *unit="", bool higherIsBetter=true)
Record a performance metric.
void detail(const char *fmt,...)
Verbose-only indented diagnostic line (shown only when verbose=1).
void progress(int percent, const char *action)
Report progress with a short description of the current action.
void Register_HTML_Tests()
Definition HTML.cpp:495