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
);
97 wprintw(buf
->status_line
, "Len:%lu Off:%lu Val:0x%X", buf
->len
,
98 buf
->cursor_offset
, buf
->data
[buf
->cursor_offset
]);
100 wprintw(buf
->status_line
, "Len:%lu (empty)", buf
->len
);
102 wmove(buf
->win
, buf
->cursor_y
, buf
->cursor_x
);
103 wcursyncup(buf
->win
);
105 untouchwin(buf
->win
);
108 void hexedit_refresh(struct hexedit
*buf
)
116 mvwprintw(buf
->win
, 0, 0, "%08X", 0);
120 end
= buf
->offset
+ bytes_per_screen(buf
->win
);
121 if (end
> buf
->len
) {
125 for (off
= buf
->offset
, lineno
= 0;
127 off
+= BYTES_PER_LINE
, ++lineno
) {
128 uint8_t *line
= buf
->data
+ off
;
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
) {
144 wprintw(buf
->win
, " ");
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
]);
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
)
193 static bool scroll_down(struct hexedit
*buf
)
195 if (buf
->offset
+ bytes_per_screen(buf
->win
) >= buf
->len
) {
199 buf
->offset
+= BYTES_PER_LINE
;
204 static bool scroll_up(struct hexedit
*buf
)
206 if (buf
->offset
== 0) {
210 buf
->offset
-= BYTES_PER_LINE
;
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
);
222 if (buf
->cursor_offset
+ BYTES_PER_LINE
>= buf
->len
) {
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
);
241 calc_cursor_offset(buf
);
244 static bool is_over_gap(struct hexedit
*buf
)
248 if (buf
->cursor_x
< ASCII_COL
) {
249 if (buf
->cursor_x
>= HEX_COL2
) {
250 col
= buf
->cursor_x
- HEX_COL2
;
252 col
= buf
->cursor_x
- HEX_COL1
;
266 static void cursor_left(struct hexedit
*buf
)
268 if (buf
->cursor_x
== HEX_COL1
) {
271 if (buf
->cursor_x
== HEX_COL2
) {
272 buf
->cursor_x
= HEX_COL1_END
- 1;
273 buf
->cursor_line_offset
= 3;
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
;
282 buf
->cursor_x
= HEX_COL2_END
- 1;
283 buf
->cursor_line_offset
= 7;
287 if (buf
->cursor_x
> ASCII_COL
|| buf
->nibble
== 0) {
288 buf
->cursor_line_offset
--;
291 buf
->nibble
= !buf
->nibble
;
294 if (is_over_gap(buf
)) {
298 calc_cursor_offset(buf
);
301 static void cursor_right(struct hexedit
*buf
)
303 int new_x
= buf
->cursor_x
+ 1;
308 if (new_x
== ASCII_COL_END
) {
311 if ((buf
->cursor_x
>= ASCII_COL
|| buf
->nibble
== 1) &&
312 buf
->cursor_offset
+ 1 == buf
->len
) {
313 if (buf
->cursor_x
< ASCII_COL
) {
315 buf
->cursor_line_offset
= 0;
321 if (new_x
== HEX_COL1_END
) {
323 buf
->cursor_line_offset
= 4;
325 } else if (new_x
== HEX_COL2_END
) {
327 buf
->cursor_line_offset
= 0;
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
)) {
342 calc_cursor_offset(buf
);
345 static void do_edit(struct hexedit
*buf
, int c
)
353 byte
= buf
->data
+ buf
->cursor_offset
;
355 if (buf
->cursor_x
>= ASCII_COL
) {
358 mvwprintw(buf
->win
, buf
->cursor_y
,
359 offset_to_hex_col(buf
->cursor_line_offset
), "%X", c
);
363 mvwaddch(buf
->win
, buf
->cursor_y
,
364 ASCII_COL
+ buf
->cursor_line_offset
, c
);
378 if (buf
->nibble
== 0) {
379 *byte
= (*byte
& 0x0f) | c
<< 4;
381 *byte
= (*byte
& 0xf0) | 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
) {
397 void hexedit_driver(struct hexedit
*buf
, int c
)
409 case HE_CURSOR_RIGHT
:
417 do_edit(buf
, c
& 0xff);
422 WERROR
hexedit_resize_buffer(struct hexedit
*buf
, size_t newsz
)
424 /* reset the cursor if it'll be out of bounds
426 if (buf
->cursor_offset
>= newsz
) {
428 buf
->cursor_x
= HEX_COL1
;
430 buf
->cursor_offset
= 0;
431 buf
->cursor_line_offset
= 0;
435 if (newsz
> buf
->len
) {
436 if (newsz
> buf
->alloc_size
) {
438 d
= talloc_realloc(buf
, buf
->data
, uint8_t, newsz
);
443 buf
->alloc_size
= newsz
;
445 memset(buf
->data
+ buf
->len
, '\0', newsz
- buf
->len
);