summaryrefslogtreecommitdiff
path: root/source3/utils
diff options
context:
space:
mode:
Diffstat (limited to 'source3/utils')
-rw-r--r--source3/utils/regedit_hexedit.c406
-rw-r--r--source3/utils/regedit_hexedit.h50
2 files changed, 456 insertions, 0 deletions
diff --git a/source3/utils/regedit_hexedit.c b/source3/utils/regedit_hexedit.c
new file mode 100644
index 0000000000..69ed622c7e
--- /dev/null
+++ b/source3/utils/regedit_hexedit.c
@@ -0,0 +1,406 @@
+#include "includes.h"
+#include "regedit_hexedit.h"
+
+static int max_rows(WINDOW *win)
+{
+ int maxy, maxx;
+
+ getmaxyx(win, maxy, maxx);
+
+ return maxy - 1;
+}
+
+static int hexedit_free(struct hexedit *buf)
+{
+ if (buf->status_line) {
+ delwin(buf->status_line);
+ }
+ if (buf->win) {
+ delwin(buf->win);
+ }
+
+ return 0;
+}
+
+struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, int nlines,
+ int y, int x, size_t sz)
+{
+ struct hexedit *buf;
+
+ buf = talloc_zero(ctx, struct hexedit);
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ talloc_set_destructor(buf, hexedit_free);
+
+ buf->data = talloc_zero_array(buf, uint8_t, sz);
+ if (buf->data == NULL) {
+ goto fail;
+ }
+
+ buf->len = sz;
+ buf->alloc_size = sz;
+ buf->win = derwin(parent, nlines, LINE_WIDTH, y, x);
+ if (buf->win == NULL) {
+ goto fail;
+ }
+ buf->cursor_x = HEX_COL1;
+
+ buf->status_line = derwin(buf->win, 1, LINE_WIDTH, max_rows(buf->win), 0);
+ if (buf->status_line == NULL) {
+ goto fail;
+ }
+ wattron(buf->status_line, A_REVERSE | A_STANDOUT);
+
+ return buf;
+
+fail:
+ talloc_free(buf);
+
+ return NULL;
+}
+
+static size_t bytes_per_screen(WINDOW *win)
+{
+ return max_rows(win) * BYTES_PER_LINE;
+}
+
+void hexedit_set_cursor(struct hexedit *buf)
+{
+ werase(buf->status_line);
+ wprintw(buf->status_line, "Len:%lu Off:%lu Val:0x%X", buf->len,
+ buf->cursor_offset, buf->data[buf->cursor_offset]);
+ wrefresh(buf->status_line);
+ wmove(buf->win, buf->cursor_y, buf->cursor_x);
+}
+
+void hexedit_refresh(struct hexedit *buf)
+{
+ size_t end;
+ size_t lineno;
+ size_t off;
+
+ werase(buf->win);
+
+ 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, "%08X ", 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_down(struct hexedit *buf)
+{
+ if (buf->offset + bytes_per_screen(buf->win) >= buf->len) {
+ return false;
+ }
+
+ buf->offset += BYTES_PER_LINE;
+
+ return true;
+}
+
+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)
+{
+ if (buf->cursor_y + 1 == max_rows(buf->win)) {
+ if (scroll_down(buf)) {
+ hexedit_refresh(buf);
+ }
+ } else {
+ if (buf->cursor_offset + BYTES_PER_LINE >= buf->len) {
+ return;
+ }
+ buf->cursor_y++;
+ }
+
+ 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 - 1;
+ 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 + 1 == 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;
+
+ 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);
+ cursor_right(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);
+ }
+ }
+}
+
+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;
+ default:
+ do_edit(buf, c & 0xff);
+ break;
+ }
+}
+
+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;
+ d = talloc_realloc(buf, buf->data, uint8_t, newsz);
+ if (d == NULL) {
+ return WERR_NOMEM;
+ }
+ buf->data = d;
+ buf->alloc_size = newsz;
+ }
+ memset(buf->data + buf->len, '\0', newsz - buf->len);
+ buf->len = newsz;
+ } else {
+ buf->len = newsz;
+ }
+
+ return WERR_OK;
+}
diff --git a/source3/utils/regedit_hexedit.h b/source3/utils/regedit_hexedit.h
new file mode 100644
index 0000000000..1a2db912be
--- /dev/null
+++ b/source3/utils/regedit_hexedit.h
@@ -0,0 +1,50 @@
+#ifndef _HEXEDIT_H_
+#define _HEXEDIT_H_
+
+#include <ncurses.h>
+
+enum {
+ HE_CURSOR_UP = 0x1000,
+ HE_CURSOR_DOWN = 0x1100,
+ HE_CURSOR_LEFT = 0x1200,
+ HE_CURSOR_RIGHT = 0x1300,
+ HE_CURSOR_PGUP = 0x1400,
+ HE_CURSOR_PGDN = 0x1500
+};
+
+/*
+ offset hex1 hex2 ascii
+ 00000000 FF FF FF FF FF FF FF FF ........
+*/
+
+#define LINE_WIDTH 44
+#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;
+ WINDOW *status_line;
+};
+
+struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, int nlines,
+ int y, int x, size_t sz);
+void hexedit_set_cursor(struct hexedit *buf);
+void hexedit_refresh(struct hexedit *buf);
+void hexedit_driver(struct hexedit *buf, int c);
+WERROR hexedit_resize_buffer(struct hexedit *buf, size_t newsz);
+
+#endif