docs: Avoid mentioning a possibly misleading option.
[Samba/bjacke.git] / source3 / utils / regedit_hexedit.c
blob8f1c2c72f878abb4d0e386edc6b69c096673c9ff
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"
23 static int max_rows(WINDOW *win)
25 int maxy, maxx;
27 getmaxyx(win, maxy, maxx);
29 return maxy - 1;
32 static int hexedit_free(struct hexedit *buf)
34 if (buf->status_line) {
35 delwin(buf->status_line);
37 if (buf->win) {
38 delwin(buf->win);
41 return 0;
44 struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, int nlines,
45 int y, int x, const void *data, size_t sz)
47 struct hexedit *buf;
49 buf = talloc_zero(ctx, struct hexedit);
50 if (buf == NULL) {
51 return NULL;
54 talloc_set_destructor(buf, hexedit_free);
56 buf->data = talloc_zero_array(buf, uint8_t, sz);
57 if (buf->data == NULL) {
58 goto fail;
61 if (data) {
62 memcpy(buf->data, data, sz);
65 buf->len = sz;
66 buf->alloc_size = sz;
67 buf->win = derwin(parent, nlines, LINE_WIDTH, y, x);
68 if (buf->win == NULL) {
69 goto fail;
71 buf->cursor_x = HEX_COL1;
73 buf->status_line = derwin(buf->win, 1, LINE_WIDTH, max_rows(buf->win),
74 0);
75 if (buf->status_line == NULL) {
76 goto fail;
78 wattron(buf->status_line, A_REVERSE | A_STANDOUT);
80 return buf;
82 fail:
83 talloc_free(buf);
85 return NULL;
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);
96 if (buf->len) {
97 wprintw(buf->status_line, "Len:%lu Off:%lu Val:0x%X", buf->len,
98 buf->cursor_offset, buf->data[buf->cursor_offset]);
99 } else {
100 wprintw(buf->status_line, "Len:%lu (empty)", buf->len);
102 wmove(buf->win, buf->cursor_y, buf->cursor_x);
103 wcursyncup(buf->win);
104 wsyncup(buf->win);
105 untouchwin(buf->win);
108 void hexedit_refresh(struct hexedit *buf)
110 size_t end;
111 size_t lineno;
112 size_t off;
114 werase(buf->win);
115 if (buf->len == 0) {
116 mvwprintw(buf->win, 0, 0, "%08X", 0);
117 return;
120 end = buf->offset + bytes_per_screen(buf->win);
121 if (end > buf->len) {
122 end = buf->len;
125 for (off = buf->offset, lineno = 0;
126 off < end;
127 off += BYTES_PER_LINE, ++lineno) {
128 uint8_t *line = buf->data + off;
129 size_t i, endline;
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) {
143 if (i == 3) {
144 wprintw(buf->win, " ");
145 } else {
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]);
155 } else {
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)
170 switch (pos) {
171 case 0:
172 return HEX_COL1;
173 case 1:
174 return HEX_COL1 + 3;
175 case 2:
176 return HEX_COL1 + 6;
177 case 3:
178 return HEX_COL1 + 9;
180 case 4:
181 return HEX_COL2;
182 case 5:
183 return HEX_COL2 + 3;
184 case 6:
185 return HEX_COL2 + 6;
186 case 7:
187 return HEX_COL2 + 9;
190 return -1;
193 static bool scroll_down(struct hexedit *buf)
195 if (buf->offset + bytes_per_screen(buf->win) >= buf->len) {
196 return false;
199 buf->offset += BYTES_PER_LINE;
201 return true;
204 static bool scroll_up(struct hexedit *buf)
206 if (buf->offset == 0) {
207 return false;
210 buf->offset -= BYTES_PER_LINE;
212 return true;
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);
221 } else {
222 if (buf->cursor_offset + BYTES_PER_LINE >= buf->len) {
223 return;
225 buf->cursor_y++;
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);
237 } else {
238 buf->cursor_y--;
241 calc_cursor_offset(buf);
244 static bool is_over_gap(struct hexedit *buf)
246 int col;
248 if (buf->cursor_x < ASCII_COL) {
249 if (buf->cursor_x >= HEX_COL2) {
250 col = buf->cursor_x - HEX_COL2;
251 } else {
252 col = buf->cursor_x - HEX_COL1;
255 switch (col) {
256 case 2:
257 case 5:
258 case 8:
259 return true;
263 return false;
266 static void cursor_left(struct hexedit *buf)
268 if (buf->cursor_x == HEX_COL1) {
269 return;
271 if (buf->cursor_x == HEX_COL2) {
272 buf->cursor_x = HEX_COL1_END - 1;
273 buf->cursor_line_offset = 3;
274 buf->nibble = 1;
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;
281 } else {
282 buf->cursor_x = HEX_COL2_END - 1;
283 buf->cursor_line_offset = 7;
285 buf->nibble = 1;
286 } else {
287 if (buf->cursor_x > ASCII_COL || buf->nibble == 0) {
288 buf->cursor_line_offset--;
290 buf->cursor_x--;
291 buf->nibble = !buf->nibble;
294 if (is_over_gap(buf)) {
295 buf->cursor_x--;
298 calc_cursor_offset(buf);
301 static void cursor_right(struct hexedit *buf)
303 int new_x = buf->cursor_x + 1;
305 if (buf->len == 0) {
306 return;
308 if (new_x == ASCII_COL_END) {
309 return;
311 if ((buf->cursor_x >= ASCII_COL || buf->nibble == 1) &&
312 buf->cursor_offset + 1 == buf->len) {
313 if (buf->cursor_x < ASCII_COL) {
314 new_x = ASCII_COL;
315 buf->cursor_line_offset = 0;
316 buf->nibble = 0;
317 } else {
318 return;
321 if (new_x == HEX_COL1_END) {
322 new_x = HEX_COL2;
323 buf->cursor_line_offset = 4;
324 buf->nibble = 0;
325 } else if (new_x == HEX_COL2_END) {
326 new_x = ASCII_COL;
327 buf->cursor_line_offset = 0;
328 buf->nibble = 0;
329 } else {
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)) {
339 buf->cursor_x++;
342 calc_cursor_offset(buf);
345 static void do_edit(struct hexedit *buf, int c)
347 uint8_t *byte;
349 if (buf->len == 0) {
350 return;
353 byte = buf->data + buf->cursor_offset;
355 if (buf->cursor_x >= ASCII_COL) {
356 *byte = (uint8_t)c;
358 mvwprintw(buf->win, buf->cursor_y,
359 offset_to_hex_col(buf->cursor_line_offset), "%X", c);
360 if (!isprint(c)) {
361 c = '.';
363 mvwaddch(buf->win, buf->cursor_y,
364 ASCII_COL + buf->cursor_line_offset, c);
365 cursor_right(buf);
366 } else {
367 if (!isxdigit(c)) {
368 return;
370 c = toupper(c);
371 waddch(buf->win, c);
373 if (isdigit(c)) {
374 c = c - '0';
375 } else {
376 c = c - 'A' + 10;
378 if (buf->nibble == 0) {
379 *byte = (*byte & 0x0f) | c << 4;
380 } else {
381 *byte = (*byte & 0xf0) | c;
384 c = *byte;
385 if (!isprint(c)) {
386 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) {
392 cursor_right(buf);
397 void hexedit_driver(struct hexedit *buf, int c)
399 switch (c) {
400 case HE_CURSOR_UP:
401 cursor_up(buf);
402 break;
403 case HE_CURSOR_DOWN:
404 cursor_down(buf);
405 break;
406 case HE_CURSOR_LEFT:
407 cursor_left(buf);
408 break;
409 case HE_CURSOR_RIGHT:
410 cursor_right(buf);
411 break;
412 case HE_CURSOR_PGUP:
413 break;
414 case HE_CURSOR_PGDN:
415 break;
416 default:
417 do_edit(buf, c & 0xff);
418 break;
422 WERROR hexedit_resize_buffer(struct hexedit *buf, size_t newsz)
424 /* reset the cursor if it'll be out of bounds
425 after the resize */
426 if (buf->cursor_offset >= newsz) {
427 buf->cursor_y = 0;
428 buf->cursor_x = HEX_COL1;
429 buf->offset = 0;
430 buf->cursor_offset = 0;
431 buf->cursor_line_offset = 0;
432 buf->nibble = 0;
435 if (newsz > buf->len) {
436 if (newsz > buf->alloc_size) {
437 uint8_t *d;
438 d = talloc_realloc(buf, buf->data, uint8_t, newsz);
439 if (d == NULL) {
440 return WERR_NOMEM;
442 buf->data = d;
443 buf->alloc_size = newsz;
445 memset(buf->data + buf->len, '\0', newsz - buf->len);
446 buf->len = newsz;
447 } else {
448 buf->len = newsz;
451 return WERR_OK;