regedit: Import hex editor.
[Samba.git] / source3 / utils / regedit_hexedit.c
blob69ed622c7ea871fe4a8c65c259e325068ae4c37d
1 #include "includes.h"
2 #include "regedit_hexedit.h"
4 static int max_rows(WINDOW *win)
6 int maxy, maxx;
8 getmaxyx(win, maxy, maxx);
10 return maxy - 1;
13 static int hexedit_free(struct hexedit *buf)
15 if (buf->status_line) {
16 delwin(buf->status_line);
18 if (buf->win) {
19 delwin(buf->win);
22 return 0;
25 struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, int nlines,
26 int y, int x, size_t sz)
28 struct hexedit *buf;
30 buf = talloc_zero(ctx, struct hexedit);
31 if (buf == NULL) {
32 return NULL;
35 talloc_set_destructor(buf, hexedit_free);
37 buf->data = talloc_zero_array(buf, uint8_t, sz);
38 if (buf->data == NULL) {
39 goto fail;
42 buf->len = sz;
43 buf->alloc_size = sz;
44 buf->win = derwin(parent, nlines, LINE_WIDTH, y, x);
45 if (buf->win == NULL) {
46 goto fail;
48 buf->cursor_x = HEX_COL1;
50 buf->status_line = derwin(buf->win, 1, LINE_WIDTH, max_rows(buf->win), 0);
51 if (buf->status_line == NULL) {
52 goto fail;
54 wattron(buf->status_line, A_REVERSE | A_STANDOUT);
56 return buf;
58 fail:
59 talloc_free(buf);
61 return NULL;
64 static size_t bytes_per_screen(WINDOW *win)
66 return max_rows(win) * BYTES_PER_LINE;
69 void hexedit_set_cursor(struct hexedit *buf)
71 werase(buf->status_line);
72 wprintw(buf->status_line, "Len:%lu Off:%lu Val:0x%X", buf->len,
73 buf->cursor_offset, buf->data[buf->cursor_offset]);
74 wrefresh(buf->status_line);
75 wmove(buf->win, buf->cursor_y, buf->cursor_x);
78 void hexedit_refresh(struct hexedit *buf)
80 size_t end;
81 size_t lineno;
82 size_t off;
84 werase(buf->win);
86 end = buf->offset + bytes_per_screen(buf->win);
87 if (end > buf->len) {
88 end = buf->len;
91 for (off = buf->offset, lineno = 0; off < end; off += BYTES_PER_LINE, ++lineno) {
92 uint8_t *line = buf->data + off;
93 size_t i, endline;
95 wmove(buf->win, lineno, 0);
96 wprintw(buf->win, "%08X ", off);
98 endline = BYTES_PER_LINE;
100 if (off + BYTES_PER_LINE > buf->len) {
101 endline = buf->len - off;
104 for (i = 0; i < endline; ++i) {
105 wprintw(buf->win, "%02X", line[i]);
106 if (i + 1 < endline) {
107 if (i == 3) {
108 wprintw(buf->win, " ");
109 } else {
110 wprintw(buf->win, " ");
115 wmove(buf->win, lineno, ASCII_COL);
116 for (i = 0; i < endline; ++i) {
117 if (isprint(line[i])) {
118 waddch(buf->win, line[i]);
119 } else {
120 waddch(buf->win, '.');
126 static void calc_cursor_offset(struct hexedit *buf)
128 buf->cursor_offset = buf->offset + buf->cursor_y * BYTES_PER_LINE + buf->cursor_line_offset;
131 static int offset_to_hex_col(size_t pos)
133 switch (pos) {
134 case 0:
135 return HEX_COL1;
136 case 1:
137 return HEX_COL1 + 3;
138 case 2:
139 return HEX_COL1 + 6;
140 case 3:
141 return HEX_COL1 + 9;
143 case 4:
144 return HEX_COL2;
145 case 5:
146 return HEX_COL2 + 3;
147 case 6:
148 return HEX_COL2 + 6;
149 case 7:
150 return HEX_COL2 + 9;
153 return -1;
156 static bool scroll_down(struct hexedit *buf)
158 if (buf->offset + bytes_per_screen(buf->win) >= buf->len) {
159 return false;
162 buf->offset += BYTES_PER_LINE;
164 return true;
167 static bool scroll_up(struct hexedit *buf)
169 if (buf->offset == 0) {
170 return false;
173 buf->offset -= BYTES_PER_LINE;
175 return true;
178 static void cursor_down(struct hexedit *buf)
180 if (buf->cursor_y + 1 == max_rows(buf->win)) {
181 if (scroll_down(buf)) {
182 hexedit_refresh(buf);
184 } else {
185 if (buf->cursor_offset + BYTES_PER_LINE >= buf->len) {
186 return;
188 buf->cursor_y++;
191 calc_cursor_offset(buf);
194 static void cursor_up(struct hexedit *buf)
196 if (buf->cursor_y == 0) {
197 if (scroll_up(buf)) {
198 hexedit_refresh(buf);
200 } else {
201 buf->cursor_y--;
204 calc_cursor_offset(buf);
207 static bool is_over_gap(struct hexedit *buf)
209 int col;
211 if (buf->cursor_x < ASCII_COL) {
212 if (buf->cursor_x >= HEX_COL2) {
213 col = buf->cursor_x - HEX_COL2;
214 } else {
215 col = buf->cursor_x - HEX_COL1;
218 switch (col) {
219 case 2:
220 case 5:
221 case 8:
222 return true;
226 return false;
229 static void cursor_left(struct hexedit *buf)
231 if (buf->cursor_x == HEX_COL1) {
232 return;
234 if (buf->cursor_x == HEX_COL2) {
235 buf->cursor_x = HEX_COL1_END - 1;
236 buf->cursor_line_offset = 3;
237 buf->nibble = 1;
238 } else if (buf->cursor_x == ASCII_COL) {
239 size_t off = buf->offset + buf->cursor_y * BYTES_PER_LINE;
240 if (off + 7 >= buf->len) {
241 size_t lastpos = buf->len - off - 1;
242 buf->cursor_x = offset_to_hex_col(lastpos) + 1;
243 buf->cursor_line_offset = lastpos;
244 } else {
245 buf->cursor_x = HEX_COL2_END - 1;
246 buf->cursor_line_offset = 7;
248 buf->nibble = 1;
249 } else {
250 if (buf->cursor_x > ASCII_COL || buf->nibble == 0) {
251 buf->cursor_line_offset--;
253 buf->cursor_x--;
254 buf->nibble = !buf->nibble;
257 if (is_over_gap(buf)) {
258 buf->cursor_x--;
261 calc_cursor_offset(buf);
264 static void cursor_right(struct hexedit *buf)
266 int new_x = buf->cursor_x + 1;
268 if (new_x == ASCII_COL_END) {
269 return;
271 if ((buf->cursor_x >= ASCII_COL || buf->nibble == 1) &&
272 buf->cursor_offset + 1 == buf->len) {
273 if (buf->cursor_x < ASCII_COL) {
274 new_x = ASCII_COL;
275 buf->cursor_line_offset = 0;
276 buf->nibble = 0;
277 } else {
278 return;
281 if (new_x == HEX_COL1_END) {
282 new_x = HEX_COL2;
283 buf->cursor_line_offset = 4;
284 buf->nibble = 0;
285 } else if (new_x == HEX_COL2_END) {
286 new_x = ASCII_COL;
287 buf->cursor_line_offset = 0;
288 buf->nibble = 0;
289 } else {
290 if (buf->cursor_x >= ASCII_COL || buf->nibble == 1) {
291 buf->cursor_line_offset++;
293 buf->nibble = !buf->nibble;
296 buf->cursor_x = new_x;
298 if (is_over_gap(buf)) {
299 buf->cursor_x++;
302 calc_cursor_offset(buf);
305 static void do_edit(struct hexedit *buf, int c)
307 uint8_t *byte;
309 byte = buf->data + buf->cursor_offset;
311 if (buf->cursor_x >= ASCII_COL) {
312 *byte = (uint8_t)c;
314 mvwprintw(buf->win, buf->cursor_y,
315 offset_to_hex_col(buf->cursor_line_offset), "%X", c);
316 if (!isprint(c)) {
317 c = '.';
319 mvwaddch(buf->win, buf->cursor_y, ASCII_COL + buf->cursor_line_offset, c);
320 cursor_right(buf);
321 } else {
322 if (!isxdigit(c)) {
323 return;
325 c = toupper(c);
326 waddch(buf->win, c);
328 if (isdigit(c)) {
329 c = c - '0';
330 } else {
331 c = c - 'A' + 10;
333 if (buf->nibble == 0) {
334 *byte = (*byte & 0x0f) | c << 4;
335 } else {
336 *byte = (*byte & 0xf0) | c;
339 c = *byte;
340 if (!isprint(c)) {
341 c = '.';
343 mvwaddch(buf->win, buf->cursor_y, ASCII_COL + buf->cursor_line_offset, c);
345 if (buf->cursor_x + 1 != HEX_COL2_END) {
346 cursor_right(buf);
351 void hexedit_driver(struct hexedit *buf, int c)
353 switch (c) {
354 case HE_CURSOR_UP:
355 cursor_up(buf);
356 break;
357 case HE_CURSOR_DOWN:
358 cursor_down(buf);
359 break;
360 case HE_CURSOR_LEFT:
361 cursor_left(buf);
362 break;
363 case HE_CURSOR_RIGHT:
364 cursor_right(buf);
365 break;
366 case HE_CURSOR_PGUP:
367 break;
368 case HE_CURSOR_PGDN:
369 break;
370 default:
371 do_edit(buf, c & 0xff);
372 break;
376 WERROR hexedit_resize_buffer(struct hexedit *buf, size_t newsz)
378 /* reset the cursor if it'll be out of bounds
379 after the resize */
380 if (buf->cursor_offset >= newsz) {
381 buf->cursor_y = 0;
382 buf->cursor_x = HEX_COL1;
383 buf->offset = 0;
384 buf->cursor_offset = 0;
385 buf->cursor_line_offset = 0;
386 buf->nibble = 0;
389 if (newsz > buf->len) {
390 if (newsz > buf->alloc_size) {
391 uint8_t *d;
392 d = talloc_realloc(buf, buf->data, uint8_t, newsz);
393 if (d == NULL) {
394 return WERR_NOMEM;
396 buf->data = d;
397 buf->alloc_size = newsz;
399 memset(buf->data + buf->len, '\0', newsz - buf->len);
400 buf->len = newsz;
401 } else {
402 buf->len = newsz;
405 return WERR_OK;