diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
commit | 4f5791ebd03eaec1c7da0865a383175b05102712 (patch) | |
tree | 8ce7b00f7a76baa386372422adebbe64510812d4 /source3/utils/regedit_hexedit.c | |
parent | Initial commit. (diff) | |
download | samba-4f5791ebd03eaec1c7da0865a383175b05102712.tar.xz samba-4f5791ebd03eaec1c7da0865a383175b05102712.zip |
Adding upstream version 2:4.17.12+dfsg.upstream/2%4.17.12+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source3/utils/regedit_hexedit.c')
-rw-r--r-- | source3/utils/regedit_hexedit.c | 563 |
1 files changed, 563 insertions, 0 deletions
diff --git a/source3/utils/regedit_hexedit.c b/source3/utils/regedit_hexedit.c new file mode 100644 index 0000000..413e563 --- /dev/null +++ b/source3/utils/regedit_hexedit.c @@ -0,0 +1,563 @@ +/* + * Samba Unix/Linux SMB client library + * Registry Editor + * Copyright (C) Christopher Davis 2012 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "includes.h" +#include "regedit_hexedit.h" + +/* + offset hex1 hex2 ascii + 00000000 FF FF FF FF FF FF FF FF ........ +*/ + +#define HEX_COL1 10 +#define HEX_COL1_END 21 +#define HEX_COL2 23 +#define HEX_COL2_END 34 +#define ASCII_COL 36 +#define ASCII_COL_END LINE_WIDTH +#define BYTES_PER_LINE 8 + +struct hexedit { + size_t offset; + size_t len; + size_t alloc_size; + int cursor_y; + int cursor_x; + size_t cursor_offset; + size_t cursor_line_offset; + int nibble; + uint8_t *data; + WINDOW *win; +}; + +static int max_rows(WINDOW *win) +{ + int maxy; + + maxy = getmaxy(win); + + return maxy - 1; +} + +struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, const void *data, + size_t sz) +{ + WERROR rv; + struct hexedit *buf; + + buf = talloc_zero(ctx, struct hexedit); + if (buf == NULL) { + return NULL; + } + + buf->win = parent; + + rv = hexedit_set_buf(buf, data, sz); + if (!W_ERROR_IS_OK(rv)) { + goto fail; + } + + return buf; + +fail: + talloc_free(buf); + + return NULL; +} + +WERROR hexedit_set_buf(struct hexedit *buf, const void *data, size_t sz) +{ + TALLOC_FREE(buf->data); + + buf->data = talloc_zero_array(buf, uint8_t, sz); + if (buf->data == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + if (data != NULL) { + memcpy(buf->data, data, sz); + } + + buf->len = sz; + buf->alloc_size = sz; + buf->cursor_x = HEX_COL1; + buf->cursor_y = 0; + buf->cursor_offset = 0; + buf->cursor_line_offset = 0; + buf->nibble = 0; + + return WERR_OK; +} + +const void *hexedit_get_buf(struct hexedit *buf) +{ + return buf->data; +} + +size_t hexedit_get_buf_len(struct hexedit *buf) +{ + return buf->len; +} + +static size_t bytes_per_screen(WINDOW *win) +{ + return max_rows(win) * BYTES_PER_LINE; +} + +void hexedit_set_cursor(struct hexedit *buf) +{ + wmove(buf->win, max_rows(buf->win), 0); + wattron(buf->win, A_REVERSE | A_STANDOUT); + wclrtoeol(buf->win); + if (buf->cursor_offset < buf->len) { + wprintw(buf->win, "Len:%lu Off:%lu Val:0x%X", buf->len, + buf->cursor_offset, buf->data[buf->cursor_offset]); + } else { + wprintw(buf->win, "Len:%lu Off:%lu", buf->len, + buf->cursor_offset); + } + wattroff(buf->win, A_REVERSE | A_STANDOUT); + wmove(buf->win, buf->cursor_y, buf->cursor_x); + wcursyncup(buf->win); + wsyncup(buf->win); + untouchwin(buf->win); +} + +void hexedit_refresh(struct hexedit *buf) +{ + size_t end; + size_t lineno; + size_t off; + + werase(buf->win); + if (buf->len == 0) { + mvwprintw(buf->win, 0, 0, "%08X", 0); + return; + } + + end = buf->offset + bytes_per_screen(buf->win); + if (end > buf->len) { + end = buf->len; + } + + for (off = buf->offset, lineno = 0; + off < end; + off += BYTES_PER_LINE, ++lineno) { + uint8_t *line = buf->data + off; + size_t i, endline; + + wmove(buf->win, lineno, 0); + wprintw(buf->win, "%08zX ", off); + + endline = BYTES_PER_LINE; + + if (off + BYTES_PER_LINE > buf->len) { + endline = buf->len - off; + } + + for (i = 0; i < endline; ++i) { + wprintw(buf->win, "%02X", line[i]); + if (i + 1 < endline) { + if (i == 3) { + wprintw(buf->win, " "); + } else { + wprintw(buf->win, " "); + } + } + } + + wmove(buf->win, lineno, ASCII_COL); + for (i = 0; i < endline; ++i) { + if (isprint(line[i])) { + waddch(buf->win, line[i]); + } else { + waddch(buf->win, '.'); + } + } + } +} + +static void calc_cursor_offset(struct hexedit *buf) +{ + buf->cursor_offset = buf->offset + buf->cursor_y * BYTES_PER_LINE + + buf->cursor_line_offset; +} + +static int offset_to_hex_col(size_t pos) +{ + switch (pos) { + case 0: + return HEX_COL1; + case 1: + return HEX_COL1 + 3; + case 2: + return HEX_COL1 + 6; + case 3: + return HEX_COL1 + 9; + + case 4: + return HEX_COL2; + case 5: + return HEX_COL2 + 3; + case 6: + return HEX_COL2 + 6; + case 7: + return HEX_COL2 + 9; + } + + return -1; +} + +static bool scroll_up(struct hexedit *buf) +{ + if (buf->offset == 0) { + return false; + } + + buf->offset -= BYTES_PER_LINE; + + return true; +} + +static void cursor_down(struct hexedit *buf) +{ + size_t space; + bool need_refresh = false; + + space = buf->offset + (buf->cursor_y + 1) * BYTES_PER_LINE; + if (space > buf->len) { + return; + } + + if (buf->cursor_y + 1 == max_rows(buf->win)) { + buf->offset += BYTES_PER_LINE; + need_refresh = true; + } else { + buf->cursor_y++; + } + + if (buf->cursor_offset + BYTES_PER_LINE > buf->len) { + buf->nibble = 0; + buf->cursor_offset = buf->len; + buf->cursor_line_offset = buf->len - space; + if (buf->cursor_x >= ASCII_COL) { + buf->cursor_x = ASCII_COL + buf->cursor_line_offset; + } else { + buf->cursor_x = offset_to_hex_col(buf->cursor_line_offset); + } + } + if (need_refresh) { + hexedit_refresh(buf); + } + calc_cursor_offset(buf); +} + +static void cursor_up(struct hexedit *buf) +{ + if (buf->cursor_y == 0) { + if (scroll_up(buf)) { + hexedit_refresh(buf); + } + } else { + buf->cursor_y--; + } + + calc_cursor_offset(buf); +} + +static bool is_over_gap(struct hexedit *buf) +{ + int col; + + if (buf->cursor_x < ASCII_COL) { + if (buf->cursor_x >= HEX_COL2) { + col = buf->cursor_x - HEX_COL2; + } else { + col = buf->cursor_x - HEX_COL1; + } + + switch (col) { + case 2: + case 5: + case 8: + return true; + } + } + + return false; +} + +static void cursor_left(struct hexedit *buf) +{ + if (buf->cursor_x == HEX_COL1) { + return; + } + if (buf->cursor_x == HEX_COL2) { + buf->cursor_x = HEX_COL1_END - 1; + buf->cursor_line_offset = 3; + buf->nibble = 1; + } else if (buf->cursor_x == ASCII_COL) { + size_t off = buf->offset + buf->cursor_y * BYTES_PER_LINE; + if (off + 7 >= buf->len) { + size_t lastpos = buf->len - off; + buf->cursor_x = offset_to_hex_col(lastpos) + 1; + buf->cursor_line_offset = lastpos; + } else { + buf->cursor_x = HEX_COL2_END - 1; + buf->cursor_line_offset = 7; + } + buf->nibble = 1; + } else { + if (buf->cursor_x > ASCII_COL || buf->nibble == 0) { + buf->cursor_line_offset--; + } + buf->cursor_x--; + buf->nibble = !buf->nibble; + } + + if (is_over_gap(buf)) { + buf->cursor_x--; + } + + calc_cursor_offset(buf); +} + +static void cursor_right(struct hexedit *buf) +{ + int new_x = buf->cursor_x + 1; + + if (new_x == ASCII_COL_END) { + return; + } + if ((buf->cursor_x >= ASCII_COL || buf->nibble == 1) && + buf->cursor_offset == buf->len) { + if (buf->cursor_x < ASCII_COL) { + new_x = ASCII_COL; + buf->cursor_line_offset = 0; + buf->nibble = 0; + } else { + return; + } + } + if (new_x == HEX_COL1_END) { + new_x = HEX_COL2; + buf->cursor_line_offset = 4; + buf->nibble = 0; + } else if (new_x == HEX_COL2_END) { + new_x = ASCII_COL; + buf->cursor_line_offset = 0; + buf->nibble = 0; + } else { + if (buf->cursor_x >= ASCII_COL || buf->nibble == 1) { + buf->cursor_line_offset++; + } + buf->nibble = !buf->nibble; + } + + buf->cursor_x = new_x; + + if (is_over_gap(buf)) { + buf->cursor_x++; + } + + calc_cursor_offset(buf); +} + +static void do_edit(struct hexedit *buf, int c) +{ + uint8_t *byte; + + if (buf->cursor_offset == buf->len) { + hexedit_resize_buffer(buf, buf->len + 1); + } + + byte = buf->data + buf->cursor_offset; + + if (buf->cursor_x >= ASCII_COL) { + *byte = (uint8_t)c; + + mvwprintw(buf->win, buf->cursor_y, + offset_to_hex_col(buf->cursor_line_offset), "%X", c); + if (!isprint(c)) { + c = '.'; + } + mvwaddch(buf->win, buf->cursor_y, + ASCII_COL + buf->cursor_line_offset, c); + if (buf->cursor_x + 1 != ASCII_COL_END) { + cursor_right(buf); + } else { + cursor_down(buf); + } + } else { + if (!isxdigit(c)) { + return; + } + c = toupper(c); + waddch(buf->win, c); + + if (isdigit(c)) { + c = c - '0'; + } else { + c = c - 'A' + 10; + } + if (buf->nibble == 0) { + *byte = (*byte & 0x0f) | c << 4; + } else { + *byte = (*byte & 0xf0) | c; + } + + c = *byte; + if (!isprint(c)) { + c = '.'; + } + mvwaddch(buf->win, buf->cursor_y, + ASCII_COL + buf->cursor_line_offset, c); + + if (buf->cursor_x + 1 != HEX_COL2_END) { + cursor_right(buf); + } else { + cursor_down(buf); + } + } + + hexedit_refresh(buf); +} + +static void erase_at(struct hexedit *buf, size_t pos) +{ + if (pos >= buf->len) { + return; + } + + if (pos < buf->len - 1) { + /* squeeze the character out of the buffer */ + uint8_t *p = buf->data + pos; + uint8_t *end = buf->data + buf->len; + memmove(p, p + 1, end - p - 1); + } + + buf->len--; + hexedit_refresh(buf); +} + +static void do_backspace(struct hexedit *buf) +{ + size_t off; + bool do_erase = true; + + if (buf->cursor_offset == 0) { + return; + } + + off = buf->cursor_offset; + if (buf->cursor_x == ASCII_COL) { + cursor_up(buf); + buf->cursor_line_offset = 7; + buf->cursor_x = ASCII_COL_END - 1; + calc_cursor_offset(buf); + } else if (buf->cursor_x == HEX_COL1) { + cursor_up(buf); + buf->cursor_line_offset = 7; + buf->cursor_x = HEX_COL2_END - 1; + buf->nibble = 1; + calc_cursor_offset(buf); + } else { + if (buf->cursor_x < ASCII_COL && buf->nibble) { + do_erase = false; + } + cursor_left(buf); + } + if (do_erase) { + erase_at(buf, off - 1); + } +} + +static void do_delete(struct hexedit *buf) +{ + erase_at(buf, buf->cursor_offset); +} + +void hexedit_driver(struct hexedit *buf, int c) +{ + switch (c) { + case HE_CURSOR_UP: + cursor_up(buf); + break; + case HE_CURSOR_DOWN: + cursor_down(buf); + break; + case HE_CURSOR_LEFT: + cursor_left(buf); + break; + case HE_CURSOR_RIGHT: + cursor_right(buf); + break; + case HE_CURSOR_PGUP: + break; + case HE_CURSOR_PGDN: + break; + case HE_BACKSPACE: + do_backspace(buf); + break; + case HE_DELETE: + do_delete(buf); + break; + default: + do_edit(buf, c & 0xff); + break; + } + + hexedit_set_cursor(buf); +} + +WERROR hexedit_resize_buffer(struct hexedit *buf, size_t newsz) +{ + /* reset the cursor if it'll be out of bounds + after the resize */ + if (buf->cursor_offset > newsz) { + buf->cursor_y = 0; + buf->cursor_x = HEX_COL1; + buf->offset = 0; + buf->cursor_offset = 0; + buf->cursor_line_offset = 0; + buf->nibble = 0; + } + + if (newsz > buf->len) { + if (newsz > buf->alloc_size) { + uint8_t *d; + buf->alloc_size *= 2; + if (newsz > buf->alloc_size) { + buf->alloc_size = newsz; + } + d = talloc_realloc(buf, buf->data, uint8_t, + buf->alloc_size); + if (d == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + buf->data = d; + } + memset(buf->data + buf->len, '\0', newsz - buf->len); + buf->len = newsz; + } else { + buf->len = newsz; + } + + return WERR_OK; +} |