2 * Samba Unix/Linux SMB client library
4 * Copyright (C) Christopher Davis 2012
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "regedit_hexedit.h"
23 static int max_rows(WINDOW *win)
27 getmaxyx(win, maxy, maxx);
32 static int hexedit_free(struct hexedit *buf)
34 if (buf->status_line) {
35 delwin(buf->status_line);
44 struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, int nlines,
45 int y, int x, const void *data, size_t sz)
49 buf = talloc_zero(ctx, struct hexedit);
54 talloc_set_destructor(buf, hexedit_free);
56 buf->data = talloc_zero_array(buf, uint8_t, sz);
57 if (buf->data == NULL) {
62 memcpy(buf->data, data, sz);
67 buf->win = derwin(parent, nlines, LINE_WIDTH, y, x);
68 if (buf->win == NULL) {
71 buf->cursor_x = HEX_COL1;
73 buf->status_line = derwin(buf->win, 1, LINE_WIDTH, max_rows(buf->win),
75 if (buf->status_line == NULL) {
78 wattron(buf->status_line, A_REVERSE | A_STANDOUT);
88 static size_t bytes_per_screen(WINDOW *win)
90 return max_rows(win) * BYTES_PER_LINE;
93 void hexedit_set_cursor(struct hexedit *buf)
95 werase(buf->status_line);
97 wprintw(buf->status_line, "Len:%lu Off:%lu Val:0x%X", buf->len,
98 buf->cursor_offset, buf->data[buf->cursor_offset]);
100 wprintw(buf->status_line, "Len:%lu (empty)", buf->len);
102 wmove(buf->win, buf->cursor_y, buf->cursor_x);
103 wcursyncup(buf->win);
105 untouchwin(buf->win);
108 void hexedit_refresh(struct hexedit *buf)
116 mvwprintw(buf->win, 0, 0, "%08X", 0);
120 end = buf->offset + bytes_per_screen(buf->win);
121 if (end > buf->len) {
125 for (off = buf->offset, lineno = 0;
127 off += BYTES_PER_LINE, ++lineno) {
128 uint8_t *line = buf->data + off;
131 wmove(buf->win, lineno, 0);
132 wprintw(buf->win, "%08X ", off);
134 endline = BYTES_PER_LINE;
136 if (off + BYTES_PER_LINE > buf->len) {
137 endline = buf->len - off;
140 for (i = 0; i < endline; ++i) {
141 wprintw(buf->win, "%02X", line[i]);
142 if (i + 1 < endline) {
144 wprintw(buf->win, " ");
146 wprintw(buf->win, " ");
151 wmove(buf->win, lineno, ASCII_COL);
152 for (i = 0; i < endline; ++i) {
153 if (isprint(line[i])) {
154 waddch(buf->win, line[i]);
156 waddch(buf->win, '.');
162 static void calc_cursor_offset(struct hexedit *buf)
164 buf->cursor_offset = buf->offset + buf->cursor_y * BYTES_PER_LINE +
165 buf->cursor_line_offset;
168 static int offset_to_hex_col(size_t pos)
193 static bool scroll_down(struct hexedit *buf)
195 if (buf->offset + bytes_per_screen(buf->win) >= buf->len) {
199 buf->offset += BYTES_PER_LINE;
204 static bool scroll_up(struct hexedit *buf)
206 if (buf->offset == 0) {
210 buf->offset -= BYTES_PER_LINE;
215 static void cursor_down(struct hexedit *buf)
217 if (buf->cursor_y + 1 == max_rows(buf->win)) {
218 if (scroll_down(buf)) {
219 hexedit_refresh(buf);
222 if (buf->cursor_offset + BYTES_PER_LINE >= buf->len) {
228 calc_cursor_offset(buf);
231 static void cursor_up(struct hexedit *buf)
233 if (buf->cursor_y == 0) {
234 if (scroll_up(buf)) {
235 hexedit_refresh(buf);
241 calc_cursor_offset(buf);
244 static bool is_over_gap(struct hexedit *buf)
248 if (buf->cursor_x < ASCII_COL) {
249 if (buf->cursor_x >= HEX_COL2) {
250 col = buf->cursor_x - HEX_COL2;
252 col = buf->cursor_x - HEX_COL1;
266 static void cursor_left(struct hexedit *buf)
268 if (buf->cursor_x == HEX_COL1) {
271 if (buf->cursor_x == HEX_COL2) {
272 buf->cursor_x = HEX_COL1_END - 1;
273 buf->cursor_line_offset = 3;
275 } else if (buf->cursor_x == ASCII_COL) {
276 size_t off = buf->offset + buf->cursor_y * BYTES_PER_LINE;
277 if (off + 7 >= buf->len) {
278 size_t lastpos = buf->len - off - 1;
279 buf->cursor_x = offset_to_hex_col(lastpos) + 1;
280 buf->cursor_line_offset = lastpos;
282 buf->cursor_x = HEX_COL2_END - 1;
283 buf->cursor_line_offset = 7;
287 if (buf->cursor_x > ASCII_COL || buf->nibble == 0) {
288 buf->cursor_line_offset--;
291 buf->nibble = !buf->nibble;
294 if (is_over_gap(buf)) {
298 calc_cursor_offset(buf);
301 static void cursor_right(struct hexedit *buf)
303 int new_x = buf->cursor_x + 1;
308 if (new_x == ASCII_COL_END) {
311 if ((buf->cursor_x >= ASCII_COL || buf->nibble == 1) &&
312 buf->cursor_offset + 1 == buf->len) {
313 if (buf->cursor_x < ASCII_COL) {
315 buf->cursor_line_offset = 0;
321 if (new_x == HEX_COL1_END) {
323 buf->cursor_line_offset = 4;
325 } else if (new_x == HEX_COL2_END) {
327 buf->cursor_line_offset = 0;
330 if (buf->cursor_x >= ASCII_COL || buf->nibble == 1) {
331 buf->cursor_line_offset++;
333 buf->nibble = !buf->nibble;
336 buf->cursor_x = new_x;
338 if (is_over_gap(buf)) {
342 calc_cursor_offset(buf);
345 static void do_edit(struct hexedit *buf, int c)
353 byte = buf->data + buf->cursor_offset;
355 if (buf->cursor_x >= ASCII_COL) {
358 mvwprintw(buf->win, buf->cursor_y,
359 offset_to_hex_col(buf->cursor_line_offset), "%X", c);
363 mvwaddch(buf->win, buf->cursor_y,
364 ASCII_COL + buf->cursor_line_offset, c);
378 if (buf->nibble == 0) {
379 *byte = (*byte & 0x0f) | c << 4;
381 *byte = (*byte & 0xf0) | c;
388 mvwaddch(buf->win, buf->cursor_y,
389 ASCII_COL + buf->cursor_line_offset, c);
391 if (buf->cursor_x + 1 != HEX_COL2_END) {
397 void hexedit_driver(struct hexedit *buf, int c)
409 case HE_CURSOR_RIGHT:
417 do_edit(buf, c & 0xff);
422 WERROR hexedit_resize_buffer(struct hexedit *buf, size_t newsz)
424 /* reset the cursor if it'll be out of bounds
426 if (buf->cursor_offset >= newsz) {
428 buf->cursor_x = HEX_COL1;
430 buf->cursor_offset = 0;
431 buf->cursor_line_offset = 0;
435 if (newsz > buf->len) {
436 if (newsz > buf->alloc_size) {
438 d = talloc_realloc(buf, buf->data, uint8_t, newsz);
443 buf->alloc_size = newsz;
445 memset(buf->data + buf->len, '\0', newsz - buf->len);