2016-08-13 03:57:40 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2016-08-13 04:16:14 +00:00
|
|
|
#include <stdlib.h>
|
2016-08-13 03:57:40 +00:00
|
|
|
#include "hescape.h"
|
|
|
|
|
2016-08-13 04:16:14 +00:00
|
|
|
static const char *ESCAPED_STRING[] = {
|
2016-08-13 03:57:40 +00:00
|
|
|
"",
|
|
|
|
""",
|
|
|
|
"&",
|
|
|
|
"'",
|
|
|
|
"<",
|
|
|
|
">",
|
|
|
|
};
|
|
|
|
|
|
|
|
// This is strlen(ESCAPED_STRING[x]) optimized specially.
|
|
|
|
// Mapping: 1 => 6, 2 => 5, 3 => 5, 4 => 4, 5 => 4
|
|
|
|
#define ESC_LEN(x) ((13 - x) / 2)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Given ASCII-compatible character, return index of ESCAPED_STRING.
|
|
|
|
*
|
|
|
|
* " (34) => 1 (")
|
|
|
|
* & (38) => 2 (&)
|
|
|
|
* ' (39) => 3 (')
|
|
|
|
* < (60) => 4 (<)
|
|
|
|
* > (62) => 5 (>)
|
|
|
|
*/
|
|
|
|
static const char HTML_ESCAPE_TABLE[] = {
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 5, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
};
|
|
|
|
|
2016-08-13 04:16:14 +00:00
|
|
|
static char*
|
|
|
|
ensure_allocated(char *buf, size_t size, size_t *asize)
|
2016-08-13 03:57:40 +00:00
|
|
|
{
|
2016-08-13 04:16:14 +00:00
|
|
|
size_t new_size;
|
|
|
|
|
2016-08-13 03:57:40 +00:00
|
|
|
if (size < *asize)
|
|
|
|
return buf;
|
|
|
|
|
|
|
|
if (*asize == 0) {
|
|
|
|
new_size = size;
|
|
|
|
} else {
|
|
|
|
new_size = *asize;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Increase buffer size by 1.5x if realloced multiple times.
|
|
|
|
while (new_size < size)
|
|
|
|
new_size = (new_size << 1) - (new_size >> 1);
|
|
|
|
|
|
|
|
// Round allocation up to multiple of 8.
|
|
|
|
new_size = (new_size + 7) & ~7;
|
|
|
|
|
|
|
|
*asize = new_size;
|
|
|
|
return realloc(buf, new_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
2016-08-13 04:16:14 +00:00
|
|
|
hesc_escape_html(char **dest, const char *buf, size_t size)
|
2016-08-13 03:57:40 +00:00
|
|
|
{
|
|
|
|
size_t asize = 0, esc_i, esize = 0, i = 0, rbuf_end = 0;
|
2016-08-13 04:16:14 +00:00
|
|
|
const char *esc;
|
|
|
|
char *rbuf = NULL;
|
2016-08-13 03:57:40 +00:00
|
|
|
|
|
|
|
while (i < size) {
|
|
|
|
// Loop here to skip non-escaped characters fast.
|
2016-08-14 13:56:18 +00:00
|
|
|
while (i < size && (esc_i = HTML_ESCAPE_TABLE[(unsigned char)buf[i]]) == 0)
|
2016-08-13 03:57:40 +00:00
|
|
|
i++;
|
|
|
|
|
2016-08-13 04:16:14 +00:00
|
|
|
if (i < size && esc_i) {
|
2016-08-13 03:57:40 +00:00
|
|
|
esc = ESCAPED_STRING[esc_i];
|
2016-08-13 04:16:14 +00:00
|
|
|
rbuf = ensure_allocated(rbuf, sizeof(char) * (size + esize + ESC_LEN(esc_i) + 1), &asize);
|
2016-08-13 03:57:40 +00:00
|
|
|
|
|
|
|
// Copy pending characters and escaped string.
|
|
|
|
memmove(rbuf + rbuf_end, buf + (rbuf_end - esize), i - (rbuf_end - esize));
|
|
|
|
memmove(rbuf + i + esize, esc, ESC_LEN(esc_i));
|
|
|
|
rbuf_end = i + esize + ESC_LEN(esc_i);
|
|
|
|
esize += ESC_LEN(esc_i) - 1;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rbuf_end == 0) {
|
|
|
|
// Return given buf and size if there are no escaped characters.
|
2016-08-13 04:16:14 +00:00
|
|
|
*dest = (char *)buf;
|
2016-08-13 03:57:40 +00:00
|
|
|
return size;
|
|
|
|
} else {
|
|
|
|
// Copy pending characters including NULL character.
|
|
|
|
memmove(rbuf + rbuf_end, buf + (rbuf_end - esize), (size + 1) - (rbuf_end - esize));
|
|
|
|
|
|
|
|
*dest = rbuf;
|
|
|
|
return size + esize;
|
|
|
|
}
|
|
|
|
}
|