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"
24 offset hex1 hex2 ascii
25 00000000 FF FF FF FF FF FF FF FF ........
29 #define HEX_COL1_END 21
31 #define HEX_COL2_END 34
33 #define ASCII_COL_END LINE_WIDTH
34 #define BYTES_PER_LINE 8
43 size_t cursor_line_offset;
49 static int max_rows(WINDOW *win)
58 struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, const void *data,
64 buf = talloc_zero(ctx, struct hexedit);
71 rv = hexedit_set_buf(buf, data, sz);
72 if (!W_ERROR_IS_OK(rv)) {
84 WERROR hexedit_set_buf(struct hexedit *buf, const void *data, size_t sz)
86 TALLOC_FREE(buf->data);
88 buf->data = talloc_zero_array(buf, uint8_t, sz);
89 if (buf->data == NULL) {
90 return WERR_NOT_ENOUGH_MEMORY;
94 memcpy(buf->data, data, sz);
99 buf->cursor_x = HEX_COL1;
101 buf->cursor_offset = 0;
102 buf->cursor_line_offset = 0;
108 const void *hexedit_get_buf(struct hexedit *buf)
113 size_t hexedit_get_buf_len(struct hexedit *buf)
118 static size_t bytes_per_screen(WINDOW *win)
120 return max_rows(win) * BYTES_PER_LINE;
123 void hexedit_set_cursor(struct hexedit *buf)
125 wmove(buf->win, max_rows(buf->win), 0);
126 wattron(buf->win, A_REVERSE | A_STANDOUT);
128 if (buf->cursor_offset < buf->len) {
129 wprintw(buf->win, "Len:%lu Off:%lu Val:0x%X", buf->len,
130 buf->cursor_offset, buf->data[buf->cursor_offset]);
132 wprintw(buf->win, "Len:%lu Off:%lu", buf->len,
135 wattroff(buf->win, A_REVERSE | A_STANDOUT);
136 wmove(buf->win, buf->cursor_y, buf->cursor_x);
137 wcursyncup(buf->win);
139 untouchwin(buf->win);
142 void hexedit_refresh(struct hexedit *buf)
150 mvwprintw(buf->win, 0, 0, "%08X", 0);
154 end = buf->offset + bytes_per_screen(buf->win);
155 if (end > buf->len) {
159 for (off = buf->offset, lineno = 0;
161 off += BYTES_PER_LINE, ++lineno) {
162 uint8_t *line = buf->data + off;
165 wmove(buf->win, lineno, 0);
166 wprintw(buf->win, "%08X ", off);
168 endline = BYTES_PER_LINE;
170 if (off + BYTES_PER_LINE > buf->len) {
171 endline = buf->len - off;
174 for (i = 0; i < endline; ++i) {
175 wprintw(buf->win, "%02X", line[i]);
176 if (i + 1 < endline) {
178 wprintw(buf->win, " ");
180 wprintw(buf->win, " ");
185 wmove(buf->win, lineno, ASCII_COL);
186 for (i = 0; i < endline; ++i) {
187 if (isprint(line[i])) {
188 waddch(buf->win, line[i]);
190 waddch(buf->win, '.');
196 static void calc_cursor_offset(struct hexedit *buf)
198 buf->cursor_offset = buf->offset + buf->cursor_y * BYTES_PER_LINE +
199 buf->cursor_line_offset;
202 static int offset_to_hex_col(size_t pos)
227 static bool scroll_up(struct hexedit *buf)
229 if (buf->offset == 0) {
233 buf->offset -= BYTES_PER_LINE;
238 static void cursor_down(struct hexedit *buf)
241 bool need_refresh = false;
243 space = buf->offset + (buf->cursor_y + 1) * BYTES_PER_LINE;
244 if (space > buf->len) {
248 if (buf->cursor_y + 1 == max_rows(buf->win)) {
249 buf->offset += BYTES_PER_LINE;
255 if (buf->cursor_offset + BYTES_PER_LINE > buf->len) {
257 buf->cursor_offset = buf->len;
258 buf->cursor_line_offset = buf->len - space;
259 if (buf->cursor_x >= ASCII_COL) {
260 buf->cursor_x = ASCII_COL + buf->cursor_line_offset;
262 buf->cursor_x = offset_to_hex_col(buf->cursor_line_offset);
266 hexedit_refresh(buf);
268 calc_cursor_offset(buf);
271 static void cursor_up(struct hexedit *buf)
273 if (buf->cursor_y == 0) {
274 if (scroll_up(buf)) {
275 hexedit_refresh(buf);
281 calc_cursor_offset(buf);
284 static bool is_over_gap(struct hexedit *buf)
288 if (buf->cursor_x < ASCII_COL) {
289 if (buf->cursor_x >= HEX_COL2) {
290 col = buf->cursor_x - HEX_COL2;
292 col = buf->cursor_x - HEX_COL1;
306 static void cursor_left(struct hexedit *buf)
308 if (buf->cursor_x == HEX_COL1) {
311 if (buf->cursor_x == HEX_COL2) {
312 buf->cursor_x = HEX_COL1_END - 1;
313 buf->cursor_line_offset = 3;
315 } else if (buf->cursor_x == ASCII_COL) {
316 size_t off = buf->offset + buf->cursor_y * BYTES_PER_LINE;
317 if (off + 7 >= buf->len) {
318 size_t lastpos = buf->len - off;
319 buf->cursor_x = offset_to_hex_col(lastpos) + 1;
320 buf->cursor_line_offset = lastpos;
322 buf->cursor_x = HEX_COL2_END - 1;
323 buf->cursor_line_offset = 7;
327 if (buf->cursor_x > ASCII_COL || buf->nibble == 0) {
328 buf->cursor_line_offset--;
331 buf->nibble = !buf->nibble;
334 if (is_over_gap(buf)) {
338 calc_cursor_offset(buf);
341 static void cursor_right(struct hexedit *buf)
343 int new_x = buf->cursor_x + 1;
345 if (new_x == ASCII_COL_END) {
348 if ((buf->cursor_x >= ASCII_COL || buf->nibble == 1) &&
349 buf->cursor_offset == buf->len) {
350 if (buf->cursor_x < ASCII_COL) {
352 buf->cursor_line_offset = 0;
358 if (new_x == HEX_COL1_END) {
360 buf->cursor_line_offset = 4;
362 } else if (new_x == HEX_COL2_END) {
364 buf->cursor_line_offset = 0;
367 if (buf->cursor_x >= ASCII_COL || buf->nibble == 1) {
368 buf->cursor_line_offset++;
370 buf->nibble = !buf->nibble;
373 buf->cursor_x = new_x;
375 if (is_over_gap(buf)) {
379 calc_cursor_offset(buf);
382 static void do_edit(struct hexedit *buf, int c)
386 if (buf->cursor_offset == buf->len) {
387 hexedit_resize_buffer(buf, buf->len + 1);
390 byte = buf->data + buf->cursor_offset;
392 if (buf->cursor_x >= ASCII_COL) {
395 mvwprintw(buf->win, buf->cursor_y,
396 offset_to_hex_col(buf->cursor_line_offset), "%X", c);
400 mvwaddch(buf->win, buf->cursor_y,
401 ASCII_COL + buf->cursor_line_offset, c);
402 if (buf->cursor_x + 1 != ASCII_COL_END) {
419 if (buf->nibble == 0) {
420 *byte = (*byte & 0x0f) | c << 4;
422 *byte = (*byte & 0xf0) | c;
429 mvwaddch(buf->win, buf->cursor_y,
430 ASCII_COL + buf->cursor_line_offset, c);
432 if (buf->cursor_x + 1 != HEX_COL2_END) {
439 hexedit_refresh(buf);
442 static void erase_at(struct hexedit *buf, size_t pos)
444 if (pos >= buf->len) {
448 if (pos < buf->len - 1) {
449 /* squeeze the character out of the buffer */
450 uint8_t *p = buf->data + pos;
451 uint8_t *end = buf->data + buf->len;
452 memmove(p, p + 1, end - p - 1);
456 hexedit_refresh(buf);
459 static void do_backspace(struct hexedit *buf)
462 bool do_erase = true;
464 if (buf->cursor_offset == 0) {
468 off = buf->cursor_offset;
469 if (buf->cursor_x == ASCII_COL) {
471 buf->cursor_line_offset = 7;
472 buf->cursor_x = ASCII_COL_END - 1;
473 calc_cursor_offset(buf);
474 } else if (buf->cursor_x == HEX_COL1) {
476 buf->cursor_line_offset = 7;
477 buf->cursor_x = HEX_COL2_END - 1;
479 calc_cursor_offset(buf);
481 if (buf->cursor_x < ASCII_COL && buf->nibble) {
487 erase_at(buf, off - 1);
491 static void do_delete(struct hexedit *buf)
493 erase_at(buf, buf->cursor_offset);
496 void hexedit_driver(struct hexedit *buf, int c)
508 case HE_CURSOR_RIGHT:
522 do_edit(buf, c & 0xff);
526 hexedit_set_cursor(buf);
529 WERROR hexedit_resize_buffer(struct hexedit *buf, size_t newsz)
531 /* reset the cursor if it'll be out of bounds
533 if (buf->cursor_offset > newsz) {
535 buf->cursor_x = HEX_COL1;
537 buf->cursor_offset = 0;
538 buf->cursor_line_offset = 0;
542 if (newsz > buf->len) {
543 if (newsz > buf->alloc_size) {
545 buf->alloc_size *= 2;
546 if (newsz > buf->alloc_size) {
547 buf->alloc_size = newsz;
549 d = talloc_realloc(buf, buf->data, uint8_t,
552 return WERR_NOT_ENOUGH_MEMORY;
556 memset(buf->data + buf->len, '\0', newsz - buf->len);