rizin/librz/cons/html.c

217 lines
5.3 KiB
C

// SPDX-FileCopyrightText: 2009-2020 pancake <pancake@nopcode.org>
// SPDX-FileCopyrightText: 2009-2020 nibble <nibble.ds@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_cons.h>
static bool gethtmlrgb(const char *str, char *buf) {
ut8 r = 0, g = 0, b = 0;
if (rz_cons_rgb_parse(str, &r, &g, &b, 0)) {
sprintf(buf, "#%02x%02x%02x", r, g, b);
return true;
}
buf[0] = '\0';
return false;
}
static const char *gethtmlcolor(const char ptrch) {
switch (ptrch) {
case '0': return "#000"; // BLACK
case '1': return "#f00"; // RED
case '2': return "#0f0"; // GREEN
case '3': return "#ff0"; // YELLOW
case '4': return "#00f"; // BLUE
case '5': return "#f0f"; // MAGENTA
case '6': return "#aaf"; // TURQOISE
case '7': return "#fff"; // WHITE
case '8': return "#777"; // GREY
case '9': break; // default
}
return "";
}
// TODO: move into rz_util/str
RZ_API char *rz_cons_html_filter(const char *ptr, int *newlen) {
const char *str = ptr;
int esc = 0;
bool inv = false;
char text_color[16] = { 0 };
char background_color[16] = { 0 };
bool has_set = false;
bool need_to_set = false;
bool first_style;
int tmp;
if (!ptr) {
return NULL;
}
RzStrBuf *res = rz_strbuf_new("");
if (!res) {
return NULL;
}
for (; ptr[0]; ptr = ptr + 1) {
if (esc == 0 && ptr[0] != 0x1b && need_to_set) {
if (has_set) {
rz_strbuf_append(res, "</font>");
has_set = false;
}
if (text_color[0] || background_color[0] || inv) {
first_style = true;
rz_strbuf_append(res, "<font");
if (text_color[0]) {
rz_strbuf_appendf(res, " color='%s'", text_color);
}
if (background_color[0]) {
rz_strbuf_append(res, " style='");
rz_strbuf_appendf(res, "background-color:%s", background_color);
first_style = false;
}
if (inv) {
rz_strbuf_append(res, first_style ? " style='" : ";");
rz_strbuf_append(res, "text-decoration:underline overline");
first_style = false;
}
rz_strbuf_append(res, first_style ? ">" : "'>");
has_set = true;
}
need_to_set = false;
}
if (ptr[0] == '\n') {
tmp = (int)(size_t)(ptr - str);
rz_strbuf_append_n(res, str, tmp);
if (!ptr[1]) {
// write new line if it's the end of the output
rz_strbuf_append(res, "\n");
} else {
rz_strbuf_append(res, "<br />");
}
str = ptr + 1;
continue;
} else if (ptr[0] == '<') {
tmp = (int)(size_t)(ptr - str);
rz_strbuf_append_n(res, str, tmp);
rz_strbuf_append(res, "&lt;");
str = ptr + 1;
continue;
} else if (ptr[0] == '>') {
tmp = (int)(size_t)(ptr - str);
rz_strbuf_append_n(res, str, tmp);
rz_strbuf_append(res, "&gt;");
str = ptr + 1;
continue;
} else if (ptr[0] == ' ') {
tmp = (int)(size_t)(ptr - str);
rz_strbuf_append_n(res, str, tmp);
rz_strbuf_append(res, "&nbsp;");
str = ptr + 1;
continue;
}
if (ptr[0] == 0x1b) {
esc = 1;
tmp = (int)(size_t)(ptr - str);
rz_strbuf_append_n(res, str, tmp);
str = ptr + 1;
continue;
}
if (esc == 1) {
// \x1b[2J
if (ptr[0] != '[') {
eprintf("Oops invalid escape char\n");
esc = 0;
str = ptr + 1;
continue;
}
esc = 2;
continue;
} else if (esc == 2) {
// TODO: use dword comparison here
if (ptr[0] == '0' && ptr[1] == 'J') { // RZ_CONS_CLEAR_FROM_CURSOR_TO_END
ptr += 2;
esc = 0;
str = ptr;
} else if (!memcmp(ptr, "2K", 2)) {
ptr += 2;
esc = 0;
str = ptr;
continue;
} else if (ptr[0] == '2' && ptr[1] == 'J') {
rz_strbuf_append(res, "<hr />");
ptr++;
esc = 0;
str = ptr;
continue;
} else if (!strncmp(ptr, "48;5;", 5) || !strncmp(ptr, "48;2;", 5)) {
const char *end = strchr(ptr, 'm');
gethtmlrgb(ptr, background_color);
need_to_set = true;
ptr = end;
str = ptr + 1;
esc = 0;
} else if (!strncmp(ptr, "38;5;", 5) || !strncmp(ptr, "38;2;", 5)) {
const char *end = strchr(ptr, 'm');
gethtmlrgb(ptr, text_color);
need_to_set = true;
ptr = end;
str = ptr + 1;
esc = 0;
} else if (ptr[0] == '0' && ptr[1] == ';' && ptr[2] == '0') {
rz_cons_gotoxy(0, 0);
ptr += 4;
esc = 0;
str = ptr;
continue;
} else if (ptr[0] == '0' && ptr[1] == 'm') {
str = (++ptr) + 1;
esc = 0;
inv = false;
text_color[0] = '\0';
background_color[0] = '\0';
need_to_set = true;
continue;
// reset color
} else if (!strncmp(ptr, "27m", 3)) {
inv = false;
need_to_set = true;
ptr = ptr + 2;
str = ptr + 1;
esc = 0;
continue;
// reset invert color
} else if (ptr[0] == '7' && ptr[1] == 'm') {
str = (++ptr) + 1;
inv = true;
need_to_set = true;
esc = 0;
continue;
// invert color
} else if (ptr[0] == '3' && ptr[2] == 'm') {
const char *htmlColor = gethtmlcolor(ptr[1]);
if (htmlColor) {
rz_str_ncpy(text_color, htmlColor, sizeof(text_color));
}
need_to_set = true;
ptr = ptr + 2;
str = ptr + 1;
esc = 0;
continue;
} else if (ptr[0] == '4' && ptr[2] == 'm') {
const char *htmlColor = gethtmlcolor(ptr[1]);
if (htmlColor) {
rz_str_ncpy(background_color, htmlColor, sizeof(background_color));
}
need_to_set = true;
ptr = ptr + 2;
str = ptr + 1;
esc = 0;
continue;
}
}
}
rz_strbuf_append_n(res, str, ptr - str);
if (has_set) {
rz_strbuf_append(res, "</font>");
}
if (newlen) {
*newlen = res->len;
}
return rz_strbuf_drain(res);
}