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
);