+/*
+ * 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, maxx;
+ int maxy;
- getmaxyx(win, maxy, maxx);
+ maxy = getmaxy(win);
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 *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, const void *data,
+ size_t sz)
{
+ WERROR rv;
struct hexedit *buf;
buf = talloc_zero(ctx, struct hexedit);
return NULL;
}
- talloc_set_destructor(buf, hexedit_free);
+ 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) {
- goto fail;
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ if (data != NULL) {
+ memcpy(buf->data, data, sz);
}
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->cursor_y = 0;
+ buf->cursor_offset = 0;
+ buf->cursor_line_offset = 0;
+ buf->nibble = 0;
- 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;
+ return WERR_OK;
+}
-fail:
- talloc_free(buf);
+const void *hexedit_get_buf(struct hexedit *buf)
+{
+ return buf->data;
+}
- return NULL;
+size_t hexedit_get_buf_len(struct hexedit *buf)
+{
+ return buf->len;
}
static size_t bytes_per_screen(WINDOW *win)
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, 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 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) {
+ 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);
+ wprintw(buf->win, "%08zX ", off);
endline = BYTES_PER_LINE;
static void calc_cursor_offset(struct hexedit *buf)
{
- buf->cursor_offset = buf->offset + buf->cursor_y * BYTES_PER_LINE + buf->cursor_line_offset;
+ buf->cursor_offset = buf->offset + buf->cursor_y * BYTES_PER_LINE +
+ buf->cursor_line_offset;
}
static int offset_to_hex_col(size_t pos)
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) {
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)) {
- if (scroll_down(buf)) {
- hexedit_refresh(buf);
- }
+ buf->offset += BYTES_PER_LINE;
+ need_refresh = true;
} else {
- if (buf->cursor_offset + BYTES_PER_LINE >= buf->len) {
- return;
- }
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);
}
} 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;
+ size_t lastpos = buf->len - off;
buf->cursor_x = offset_to_hex_col(lastpos) + 1;
buf->cursor_line_offset = lastpos;
} else {
return;
}
if ((buf->cursor_x >= ASCII_COL || buf->nibble == 1) &&
- buf->cursor_offset + 1 == buf->len) {
+ buf->cursor_offset == buf->len) {
if (buf->cursor_x < ASCII_COL) {
new_x = ASCII_COL;
buf->cursor_line_offset = 0;
{
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) {
if (!isprint(c)) {
c = '.';
}
- mvwaddch(buf->win, buf->cursor_y, ASCII_COL + buf->cursor_line_offset, c);
- cursor_right(buf);
+ 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;
if (!isprint(c)) {
c = '.';
}
- mvwaddch(buf->win, buf->cursor_y, ASCII_COL + buf->cursor_line_offset, 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)
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) {
+ if (buf->cursor_offset > newsz) {
buf->cursor_y = 0;
buf->cursor_x = HEX_COL1;
buf->offset = 0;
if (newsz > buf->len) {
if (newsz > buf->alloc_size) {
uint8_t *d;
- d = talloc_realloc(buf, buf->data, uint8_t, newsz);
+ 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_NOMEM;
+ return WERR_NOT_ENOUGH_MEMORY;
}
buf->data = d;
- buf->alloc_size = newsz;
}
memset(buf->data + buf->len, '\0', newsz - buf->len);
buf->len = newsz;