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"
23 static int max_rows(WINDOW
*win
)
27 getmaxyx(win
, maxy
, maxx
);
32 static int hexedit_free(struct hexedit
*buf
)
34 if (buf
->status_line
) {
35 delwin(buf
->status_line
);
44 struct hexedit
*hexedit_new(TALLOC_CTX
*ctx
, WINDOW
*parent
, int nlines
,
45 int y
, int x
, const void *data
, size_t sz
)
49 buf
= talloc_zero(ctx
, struct hexedit
);
54 talloc_set_destructor(buf
, hexedit_free
);
56 buf
->data
= talloc_zero_array(buf
, uint8_t, sz
);
57 if (buf
->data
== NULL
) {
62 memcpy(buf
->data
, data
, sz
);
67 buf
->win
= derwin(parent
, nlines
, LINE_WIDTH
, y
, x
);
68 if (buf
->win
== NULL
) {
71 buf
->cursor_x
= HEX_COL1
;
73 buf
->status_line
= derwin(buf
->win
, 1, LINE_WIDTH
, max_rows(buf
->win
),
75 if (buf
->status_line
== NULL
) {
78 wattron(buf
->status_line
, A_REVERSE
| A_STANDOUT
);
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
);
101 untouchwin(buf
->win
);
104 void hexedit_refresh(struct hexedit
*buf
)
112 end
= buf
->offset
+ bytes_per_screen(buf
->win
);
113 if (end
> buf
->len
) {
117 for (off
= buf
->offset
, lineno
= 0;
119 off
+= BYTES_PER_LINE
, ++lineno
) {
120 uint8_t *line
= buf
->data
+ off
;
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
) {
136 wprintw(buf
->win
, " ");
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
]);
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
)
185 static bool scroll_down(struct hexedit
*buf
)
187 if (buf
->offset
+ bytes_per_screen(buf
->win
) >= buf
->len
) {
191 buf
->offset
+= BYTES_PER_LINE
;
196 static bool scroll_up(struct hexedit
*buf
)
198 if (buf
->offset
== 0) {
202 buf
->offset
-= BYTES_PER_LINE
;
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
);
214 if (buf
->cursor_offset
+ BYTES_PER_LINE
>= buf
->len
) {
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
);
233 calc_cursor_offset(buf
);
236 static bool is_over_gap(struct hexedit
*buf
)
240 if (buf
->cursor_x
< ASCII_COL
) {
241 if (buf
->cursor_x
>= HEX_COL2
) {
242 col
= buf
->cursor_x
- HEX_COL2
;
244 col
= buf
->cursor_x
- HEX_COL1
;
258 static void cursor_left(struct hexedit
*buf
)
260 if (buf
->cursor_x
== HEX_COL1
) {
263 if (buf
->cursor_x
== HEX_COL2
) {
264 buf
->cursor_x
= HEX_COL1_END
- 1;
265 buf
->cursor_line_offset
= 3;
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
;
274 buf
->cursor_x
= HEX_COL2_END
- 1;
275 buf
->cursor_line_offset
= 7;
279 if (buf
->cursor_x
> ASCII_COL
|| buf
->nibble
== 0) {
280 buf
->cursor_line_offset
--;
283 buf
->nibble
= !buf
->nibble
;
286 if (is_over_gap(buf
)) {
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
) {
300 if ((buf
->cursor_x
>= ASCII_COL
|| buf
->nibble
== 1) &&
301 buf
->cursor_offset
+ 1 == buf
->len
) {
302 if (buf
->cursor_x
< ASCII_COL
) {
304 buf
->cursor_line_offset
= 0;
310 if (new_x
== HEX_COL1_END
) {
312 buf
->cursor_line_offset
= 4;
314 } else if (new_x
== HEX_COL2_END
) {
316 buf
->cursor_line_offset
= 0;
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
)) {
331 calc_cursor_offset(buf
);
334 static void do_edit(struct hexedit
*buf
, int c
)
338 byte
= buf
->data
+ buf
->cursor_offset
;
340 if (buf
->cursor_x
>= ASCII_COL
) {
343 mvwprintw(buf
->win
, buf
->cursor_y
,
344 offset_to_hex_col(buf
->cursor_line_offset
), "%X", c
);
348 mvwaddch(buf
->win
, buf
->cursor_y
,
349 ASCII_COL
+ buf
->cursor_line_offset
, c
);
363 if (buf
->nibble
== 0) {
364 *byte
= (*byte
& 0x0f) | c
<< 4;
366 *byte
= (*byte
& 0xf0) | 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
) {
382 void hexedit_driver(struct hexedit
*buf
, int c
)
394 case HE_CURSOR_RIGHT
:
402 do_edit(buf
, c
& 0xff);
407 WERROR
hexedit_resize_buffer(struct hexedit
*buf
, size_t newsz
)
409 /* reset the cursor if it'll be out of bounds
411 if (buf
->cursor_offset
>= newsz
) {
413 buf
->cursor_x
= HEX_COL1
;
415 buf
->cursor_offset
= 0;
416 buf
->cursor_line_offset
= 0;
420 if (newsz
> buf
->len
) {
421 if (newsz
> buf
->alloc_size
) {
423 d
= talloc_realloc(buf
, buf
->data
, uint8_t, newsz
);
428 buf
->alloc_size
= newsz
;
430 memset(buf
->data
+ buf
->len
, '\0', newsz
- buf
->len
);