regedit: Fix white space and wrap long lines.
[Samba/wip.git] / source3 / utils / regedit_hexedit.c
blobe2864e3fae368a301a55f435dfde07cb032f1a71
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 wprintw(buf->status_line, "Len:%lu Off:%lu Val:0x%X", buf->len,
97 buf->cursor_offset, buf->data[buf->cursor_offset]);
98 wmove(buf->win, buf->cursor_y, buf->cursor_x);
99 wcursyncup(buf->win);
100 wsyncup(buf->win);
101 untouchwin(buf->win);
104 void hexedit_refresh(struct hexedit *buf)
106 size_t end;
107 size_t lineno;
108 size_t off;
110 werase(buf->win);
112 end = buf->offset + bytes_per_screen(buf->win);
113 if (end > buf->len) {
114 end = buf->len;
117 for (off = buf->offset, lineno = 0;
118 off < end;
119 off += BYTES_PER_LINE, ++lineno) {
120 uint8_t *line = buf->data + off;
121 size_t i, endline;
123 wmove(buf->win, lineno, 0);
124 wprintw(buf->win, "%08X ", off);
126 endline = BYTES_PER_LINE;
128 if (off + BYTES_PER_LINE > buf->len) {
129 endline = buf->len - off;
132 for (i = 0; i < endline; ++i) {
133 wprintw(buf->win, "%02X", line[i]);
134 if (i + 1 < endline) {
135 if (i == 3) {
136 wprintw(buf->win, " ");
137 } else {
138 wprintw(buf->win, " ");
143 wmove(buf->win, lineno, ASCII_COL);
144 for (i = 0; i < endline; ++i) {
145 if (isprint(line[i])) {
146 waddch(buf->win, line[i]);
147 } else {
148 waddch(buf->win, '.');
154 static void calc_cursor_offset(struct hexedit *buf)
156 buf->cursor_offset = buf->offset + buf->cursor_y * BYTES_PER_LINE +
157 buf->cursor_line_offset;
160 static int offset_to_hex_col(size_t pos)
162 switch (pos) {
163 case 0:
164 return HEX_COL1;
165 case 1:
166 return HEX_COL1 + 3;
167 case 2:
168 return HEX_COL1 + 6;
169 case 3:
170 return HEX_COL1 + 9;
172 case 4:
173 return HEX_COL2;
174 case 5:
175 return HEX_COL2 + 3;
176 case 6:
177 return HEX_COL2 + 6;
178 case 7:
179 return HEX_COL2 + 9;
182 return -1;
185 static bool scroll_down(struct hexedit *buf)
187 if (buf->offset + bytes_per_screen(buf->win) >= buf->len) {
188 return false;
191 buf->offset += BYTES_PER_LINE;
193 return true;
196 static bool scroll_up(struct hexedit *buf)
198 if (buf->offset == 0) {
199 return false;
202 buf->offset -= BYTES_PER_LINE;
204 return true;
207 static void cursor_down(struct hexedit *buf)
209 if (buf->cursor_y + 1 == max_rows(buf->win)) {
210 if (scroll_down(buf)) {
211 hexedit_refresh(buf);
213 } else {
214 if (buf->cursor_offset + BYTES_PER_LINE >= buf->len) {
215 return;
217 buf->cursor_y++;
220 calc_cursor_offset(buf);
223 static void cursor_up(struct hexedit *buf)
225 if (buf->cursor_y == 0) {
226 if (scroll_up(buf)) {
227 hexedit_refresh(buf);
229 } else {
230 buf->cursor_y--;
233 calc_cursor_offset(buf);
236 static bool is_over_gap(struct hexedit *buf)
238 int col;
240 if (buf->cursor_x < ASCII_COL) {
241 if (buf->cursor_x >= HEX_COL2) {
242 col = buf->cursor_x - HEX_COL2;
243 } else {
244 col = buf->cursor_x - HEX_COL1;
247 switch (col) {
248 case 2:
249 case 5:
250 case 8:
251 return true;
255 return false;
258 static void cursor_left(struct hexedit *buf)
260 if (buf->cursor_x == HEX_COL1) {
261 return;
263 if (buf->cursor_x == HEX_COL2) {
264 buf->cursor_x = HEX_COL1_END - 1;
265 buf->cursor_line_offset = 3;
266 buf->nibble = 1;
267 } else if (buf->cursor_x == ASCII_COL) {
268 size_t off = buf->offset + buf->cursor_y * BYTES_PER_LINE;
269 if (off + 7 >= buf->len) {
270 size_t lastpos = buf->len - off - 1;
271 buf->cursor_x = offset_to_hex_col(lastpos) + 1;
272 buf->cursor_line_offset = lastpos;
273 } else {
274 buf->cursor_x = HEX_COL2_END - 1;
275 buf->cursor_line_offset = 7;
277 buf->nibble = 1;
278 } else {
279 if (buf->cursor_x > ASCII_COL || buf->nibble == 0) {
280 buf->cursor_line_offset--;
282 buf->cursor_x--;
283 buf->nibble = !buf->nibble;
286 if (is_over_gap(buf)) {
287 buf->cursor_x--;
290 calc_cursor_offset(buf);
293 static void cursor_right(struct hexedit *buf)
295 int new_x = buf->cursor_x + 1;
297 if (new_x == ASCII_COL_END) {
298 return;
300 if ((buf->cursor_x >= ASCII_COL || buf->nibble == 1) &&
301 buf->cursor_offset + 1 == buf->len) {
302 if (buf->cursor_x < ASCII_COL) {
303 new_x = ASCII_COL;
304 buf->cursor_line_offset = 0;
305 buf->nibble = 0;
306 } else {
307 return;
310 if (new_x == HEX_COL1_END) {
311 new_x = HEX_COL2;
312 buf->cursor_line_offset = 4;
313 buf->nibble = 0;
314 } else if (new_x == HEX_COL2_END) {
315 new_x = ASCII_COL;
316 buf->cursor_line_offset = 0;
317 buf->nibble = 0;
318 } else {
319 if (buf->cursor_x >= ASCII_COL || buf->nibble == 1) {
320 buf->cursor_line_offset++;
322 buf->nibble = !buf->nibble;
325 buf->cursor_x = new_x;
327 if (is_over_gap(buf)) {
328 buf->cursor_x++;
331 calc_cursor_offset(buf);
334 static void do_edit(struct hexedit *buf, int c)
336 uint8_t *byte;
338 byte = buf->data + buf->cursor_offset;
340 if (buf->cursor_x >= ASCII_COL) {
341 *byte = (uint8_t)c;
343 mvwprintw(buf->win, buf->cursor_y,
344 offset_to_hex_col(buf->cursor_line_offset), "%X", c);
345 if (!isprint(c)) {
346 c = '.';
348 mvwaddch(buf->win, buf->cursor_y,
349 ASCII_COL + buf->cursor_line_offset, c);
350 cursor_right(buf);
351 } else {
352 if (!isxdigit(c)) {
353 return;
355 c = toupper(c);
356 waddch(buf->win, c);
358 if (isdigit(c)) {
359 c = c - '0';
360 } else {
361 c = c - 'A' + 10;
363 if (buf->nibble == 0) {
364 *byte = (*byte & 0x0f) | c << 4;
365 } else {
366 *byte = (*byte & 0xf0) | c;
369 c = *byte;
370 if (!isprint(c)) {
371 c = '.';
373 mvwaddch(buf->win, buf->cursor_y,
374 ASCII_COL + buf->cursor_line_offset, c);
376 if (buf->cursor_x + 1 != HEX_COL2_END) {
377 cursor_right(buf);
382 void hexedit_driver(struct hexedit *buf, int c)
384 switch (c) {
385 case HE_CURSOR_UP:
386 cursor_up(buf);
387 break;
388 case HE_CURSOR_DOWN:
389 cursor_down(buf);
390 break;
391 case HE_CURSOR_LEFT:
392 cursor_left(buf);
393 break;
394 case HE_CURSOR_RIGHT:
395 cursor_right(buf);
396 break;
397 case HE_CURSOR_PGUP:
398 break;
399 case HE_CURSOR_PGDN:
400 break;
401 default:
402 do_edit(buf, c & 0xff);
403 break;
407 WERROR hexedit_resize_buffer(struct hexedit *buf, size_t newsz)
409 /* reset the cursor if it'll be out of bounds
410 after the resize */
411 if (buf->cursor_offset >= newsz) {
412 buf->cursor_y = 0;
413 buf->cursor_x = HEX_COL1;
414 buf->offset = 0;
415 buf->cursor_offset = 0;
416 buf->cursor_line_offset = 0;
417 buf->nibble = 0;
420 if (newsz > buf->len) {
421 if (newsz > buf->alloc_size) {
422 uint8_t *d;
423 d = talloc_realloc(buf, buf->data, uint8_t, newsz);
424 if (d == NULL) {
425 return WERR_NOMEM;
427 buf->data = d;
428 buf->alloc_size = newsz;
430 memset(buf->data + buf->len, '\0', newsz - buf->len);
431 buf->len = newsz;
432 } else {
433 buf->len = newsz;
436 return WERR_OK;