// SPDX-FileCopyrightText: 2009-2020 pancake // SPDX-FileCopyrightText: 2009-2020 nibble // SPDX-License-Identifier: LGPL-3.0-only #include 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; int len = 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, ""); has_set = false; } if (text_color[0] || background_color[0] || inv) { first_style = true; rz_strbuf_append(res, "" : "'>"); 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, "
"); } 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, "<"); 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, ">"); 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, " "); 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, "
"); ptr++; esc = 0; str = ptr; continue; } else if (!strncmp(ptr, "48;5;", 5) || !strncmp(ptr, "48;2;", 5)) { 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)) { 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; } } len++; } rz_strbuf_append_n(res, str, ptr - str); if (has_set) { rz_strbuf_append(res, ""); } if (newlen) { *newlen = res->len; } return rz_strbuf_drain(res); }