werror: replace WERR_NOMEM with WERR_NOT_ENOUGH_MEMORY in source3/utils/
[Samba.git] / source3 / utils / regedit_hexedit.c
blob383736ae2bcd907fc611131a0b4aa808a7962da4
1 /*
2 * Samba Unix/Linux SMB client library
3 * Registry Editor
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/>.
20 #include "includes.h"
21 #include "regedit_hexedit.h"
24 offset hex1 hex2 ascii
25 00000000 FF FF FF FF FF FF FF FF ........
28 #define HEX_COL1 10
29 #define HEX_COL1_END 21
30 #define HEX_COL2 23
31 #define HEX_COL2_END 34
32 #define ASCII_COL 36
33 #define ASCII_COL_END LINE_WIDTH
34 #define BYTES_PER_LINE 8
36 struct hexedit {
37 size_t offset;
38 size_t len;
39 size_t alloc_size;
40 int cursor_y;
41 int cursor_x;
42 size_t cursor_offset;
43 size_t cursor_line_offset;
44 int nibble;
45 uint8_t *data;
46 WINDOW *win;
49 static int max_rows(WINDOW *win)
51 int maxy;
53 maxy = getmaxy(win);
55 return maxy - 1;
58 struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, const void *data,
59 size_t sz)
61 WERROR rv;
62 struct hexedit *buf;
64 buf = talloc_zero(ctx, struct hexedit);
65 if (buf == NULL) {
66 return NULL;
69 buf->win = parent;
71 rv = hexedit_set_buf(buf, data, sz);
72 if (!W_ERROR_IS_OK(rv)) {
73 goto fail;
76 return buf;
78 fail:
79 talloc_free(buf);
81 return NULL;
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;
93 if (data != NULL) {
94 memcpy(buf->data, data, sz);
97 buf->len = sz;
98 buf->alloc_size = sz;
99 buf->cursor_x = HEX_COL1;
100 buf->cursor_y = 0;
101 buf->cursor_offset = 0;
102 buf->cursor_line_offset = 0;
103 buf->nibble = 0;
105 return WERR_OK;
108 const void *hexedit_get_buf(struct hexedit *buf)
110 return buf->data;
113 size_t hexedit_get_buf_len(struct hexedit *buf)
115 return buf->len;
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);
127 wclrtoeol(buf->win);
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]);
131 } else {
132 wprintw(buf->win, "Len:%lu Off:%lu", buf->len,
133 buf->cursor_offset);
135 wattroff(buf->win, A_REVERSE | A_STANDOUT);
136 wmove(buf->win, buf->cursor_y, buf->cursor_x);
137 wcursyncup(buf->win);
138 wsyncup(buf->win);
139 untouchwin(buf->win);
142 void hexedit_refresh(struct hexedit *buf)
144 size_t end;
145 size_t lineno;
146 size_t off;
148 werase(buf->win);
149 if (buf->len == 0) {
150 mvwprintw(buf->win, 0, 0, "%08X", 0);
151 return;
154 end = buf->offset + bytes_per_screen(buf->win);
155 if (end > buf->len) {
156 end = buf->len;
159 for (off = buf->offset, lineno = 0;
160 off < end;
161 off += BYTES_PER_LINE, ++lineno) {
162 uint8_t *line = buf->data + off;
163 size_t i, endline;
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) {
177 if (i == 3) {
178 wprintw(buf->win, " ");
179 } else {
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]);
189 } else {
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)
204 switch (pos) {
205 case 0:
206 return HEX_COL1;
207 case 1:
208 return HEX_COL1 + 3;
209 case 2:
210 return HEX_COL1 + 6;
211 case 3:
212 return HEX_COL1 + 9;
214 case 4:
215 return HEX_COL2;
216 case 5:
217 return HEX_COL2 + 3;
218 case 6:
219 return HEX_COL2 + 6;
220 case 7:
221 return HEX_COL2 + 9;
224 return -1;
227 static bool scroll_up(struct hexedit *buf)
229 if (buf->offset == 0) {
230 return false;
233 buf->offset -= BYTES_PER_LINE;
235 return true;
238 static void cursor_down(struct hexedit *buf)
240 size_t space;
241 bool need_refresh = false;
243 space = buf->offset + (buf->cursor_y + 1) * BYTES_PER_LINE;
244 if (space > buf->len) {
245 return;
248 if (buf->cursor_y + 1 == max_rows(buf->win)) {
249 buf->offset += BYTES_PER_LINE;
250 need_refresh = true;
251 } else {
252 buf->cursor_y++;
255 if (buf->cursor_offset + BYTES_PER_LINE > buf->len) {
256 buf->nibble = 0;
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;
261 } else {
262 buf->cursor_x = offset_to_hex_col(buf->cursor_line_offset);
265 if (need_refresh) {
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);
277 } else {
278 buf->cursor_y--;
281 calc_cursor_offset(buf);
284 static bool is_over_gap(struct hexedit *buf)
286 int col;
288 if (buf->cursor_x < ASCII_COL) {
289 if (buf->cursor_x >= HEX_COL2) {
290 col = buf->cursor_x - HEX_COL2;
291 } else {
292 col = buf->cursor_x - HEX_COL1;
295 switch (col) {
296 case 2:
297 case 5:
298 case 8:
299 return true;
303 return false;
306 static void cursor_left(struct hexedit *buf)
308 if (buf->cursor_x == HEX_COL1) {
309 return;
311 if (buf->cursor_x == HEX_COL2) {
312 buf->cursor_x = HEX_COL1_END - 1;
313 buf->cursor_line_offset = 3;
314 buf->nibble = 1;
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;
321 } else {
322 buf->cursor_x = HEX_COL2_END - 1;
323 buf->cursor_line_offset = 7;
325 buf->nibble = 1;
326 } else {
327 if (buf->cursor_x > ASCII_COL || buf->nibble == 0) {
328 buf->cursor_line_offset--;
330 buf->cursor_x--;
331 buf->nibble = !buf->nibble;
334 if (is_over_gap(buf)) {
335 buf->cursor_x--;
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) {
346 return;
348 if ((buf->cursor_x >= ASCII_COL || buf->nibble == 1) &&
349 buf->cursor_offset == buf->len) {
350 if (buf->cursor_x < ASCII_COL) {
351 new_x = ASCII_COL;
352 buf->cursor_line_offset = 0;
353 buf->nibble = 0;
354 } else {
355 return;
358 if (new_x == HEX_COL1_END) {
359 new_x = HEX_COL2;
360 buf->cursor_line_offset = 4;
361 buf->nibble = 0;
362 } else if (new_x == HEX_COL2_END) {
363 new_x = ASCII_COL;
364 buf->cursor_line_offset = 0;
365 buf->nibble = 0;
366 } else {
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)) {
376 buf->cursor_x++;
379 calc_cursor_offset(buf);
382 static void do_edit(struct hexedit *buf, int c)
384 uint8_t *byte;
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) {
393 *byte = (uint8_t)c;
395 mvwprintw(buf->win, buf->cursor_y,
396 offset_to_hex_col(buf->cursor_line_offset), "%X", c);
397 if (!isprint(c)) {
398 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) {
403 cursor_right(buf);
404 } else {
405 cursor_down(buf);
407 } else {
408 if (!isxdigit(c)) {
409 return;
411 c = toupper(c);
412 waddch(buf->win, c);
414 if (isdigit(c)) {
415 c = c - '0';
416 } else {
417 c = c - 'A' + 10;
419 if (buf->nibble == 0) {
420 *byte = (*byte & 0x0f) | c << 4;
421 } else {
422 *byte = (*byte & 0xf0) | c;
425 c = *byte;
426 if (!isprint(c)) {
427 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) {
433 cursor_right(buf);
434 } else {
435 cursor_down(buf);
439 hexedit_refresh(buf);
442 static void erase_at(struct hexedit *buf, size_t pos)
444 if (pos >= buf->len) {
445 return;
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);
455 buf->len--;
456 hexedit_refresh(buf);
459 static void do_backspace(struct hexedit *buf)
461 size_t off;
462 bool do_erase = true;
464 if (buf->cursor_offset == 0) {
465 return;
468 off = buf->cursor_offset;
469 if (buf->cursor_x == ASCII_COL) {
470 cursor_up(buf);
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) {
475 cursor_up(buf);
476 buf->cursor_line_offset = 7;
477 buf->cursor_x = HEX_COL2_END - 1;
478 buf->nibble = 1;
479 calc_cursor_offset(buf);
480 } else {
481 if (buf->cursor_x < ASCII_COL && buf->nibble) {
482 do_erase = false;
484 cursor_left(buf);
486 if (do_erase) {
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)
498 switch (c) {
499 case HE_CURSOR_UP:
500 cursor_up(buf);
501 break;
502 case HE_CURSOR_DOWN:
503 cursor_down(buf);
504 break;
505 case HE_CURSOR_LEFT:
506 cursor_left(buf);
507 break;
508 case HE_CURSOR_RIGHT:
509 cursor_right(buf);
510 break;
511 case HE_CURSOR_PGUP:
512 break;
513 case HE_CURSOR_PGDN:
514 break;
515 case HE_BACKSPACE:
516 do_backspace(buf);
517 break;
518 case HE_DELETE:
519 do_delete(buf);
520 break;
521 default:
522 do_edit(buf, c & 0xff);
523 break;
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
532 after the resize */
533 if (buf->cursor_offset > newsz) {
534 buf->cursor_y = 0;
535 buf->cursor_x = HEX_COL1;
536 buf->offset = 0;
537 buf->cursor_offset = 0;
538 buf->cursor_line_offset = 0;
539 buf->nibble = 0;
542 if (newsz > buf->len) {
543 if (newsz > buf->alloc_size) {
544 uint8_t *d;
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,
550 buf->alloc_size);
551 if (d == NULL) {
552 return WERR_NOT_ENOUGH_MEMORY;
554 buf->data = d;
556 memset(buf->data + buf->len, '\0', newsz - buf->len);
557 buf->len = newsz;
558 } else {
559 buf->len = newsz;
562 return WERR_OK;