2012-08-18 06:03:12 +04:00
/*
* Samba Unix / Linux SMB client library
* Registry Editor
* Copyright ( C ) Christopher Davis 2012
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2012-08-07 06:06:15 +04:00
# include "includes.h"
# include "regedit_hexedit.h"
2014-07-26 10:16:52 +04:00
/*
offset hex1 hex2 ascii
00000000 FF FF FF FF FF FF FF FF . . . . . . . .
*/
# define HEX_COL1 10
# define HEX_COL1_END 21
# define HEX_COL2 23
# define HEX_COL2_END 34
# define ASCII_COL 36
# define ASCII_COL_END LINE_WIDTH
# define BYTES_PER_LINE 8
struct hexedit {
size_t offset ;
size_t len ;
size_t alloc_size ;
int cursor_y ;
int cursor_x ;
size_t cursor_offset ;
size_t cursor_line_offset ;
int nibble ;
uint8_t * data ;
WINDOW * win ;
} ;
2012-08-07 06:06:15 +04:00
static int max_rows ( WINDOW * win )
{
2014-07-29 10:23:32 +04:00
int maxy ;
2012-08-07 06:06:15 +04:00
2014-07-29 10:23:32 +04:00
maxy = getmaxy ( win ) ;
2012-08-07 06:06:15 +04:00
return maxy - 1 ;
}
2014-07-29 10:23:32 +04:00
struct hexedit * hexedit_new ( TALLOC_CTX * ctx , WINDOW * parent , const void * data ,
size_t sz )
2012-08-07 06:06:15 +04:00
{
2014-07-26 10:16:52 +04:00
WERROR rv ;
2012-08-07 06:06:15 +04:00
struct hexedit * buf ;
buf = talloc_zero ( ctx , struct hexedit ) ;
if ( buf = = NULL ) {
return NULL ;
}
2014-07-29 10:23:32 +04:00
buf - > win = parent ;
2012-08-07 06:06:15 +04:00
2014-07-26 10:16:52 +04:00
rv = hexedit_set_buf ( buf , data , sz ) ;
if ( ! W_ERROR_IS_OK ( rv ) ) {
goto fail ;
}
2012-08-07 06:06:15 +04:00
return buf ;
fail :
talloc_free ( buf ) ;
return NULL ;
}
2014-07-26 10:16:52 +04:00
WERROR hexedit_set_buf ( struct hexedit * buf , const void * data , size_t sz )
{
TALLOC_FREE ( buf - > data ) ;
buf - > data = talloc_zero_array ( buf , uint8_t , sz ) ;
if ( buf - > data = = NULL ) {
2015-12-03 17:24:17 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2014-07-26 10:16:52 +04:00
}
if ( data ! = NULL ) {
memcpy ( buf - > data , data , sz ) ;
}
buf - > len = sz ;
buf - > alloc_size = sz ;
buf - > cursor_x = HEX_COL1 ;
buf - > cursor_y = 0 ;
buf - > cursor_offset = 0 ;
buf - > cursor_line_offset = 0 ;
buf - > nibble = 0 ;
return WERR_OK ;
}
const void * hexedit_get_buf ( struct hexedit * buf )
{
return buf - > data ;
}
size_t hexedit_get_buf_len ( struct hexedit * buf )
{
return buf - > len ;
}
2012-08-07 06:06:15 +04:00
static size_t bytes_per_screen ( WINDOW * win )
{
return max_rows ( win ) * BYTES_PER_LINE ;
}
void hexedit_set_cursor ( struct hexedit * buf )
{
2014-07-29 10:23:32 +04:00
wmove ( buf - > win , max_rows ( buf - > win ) , 0 ) ;
wattron ( buf - > win , A_REVERSE | A_STANDOUT ) ;
wclrtoeol ( buf - > win ) ;
2014-08-10 04:11:00 +04:00
if ( buf - > cursor_offset < buf - > len ) {
2014-07-29 10:23:32 +04:00
wprintw ( buf - > win , " Len:%lu Off:%lu Val:0x%X " , buf - > len ,
2012-08-20 06:11:16 +04:00
buf - > cursor_offset , buf - > data [ buf - > cursor_offset ] ) ;
} else {
2014-08-10 04:11:00 +04:00
wprintw ( buf - > win , " Len:%lu Off:%lu " , buf - > len ,
buf - > cursor_offset ) ;
2012-08-20 06:11:16 +04:00
}
2014-07-29 10:23:32 +04:00
wattroff ( buf - > win , A_REVERSE | A_STANDOUT ) ;
2012-08-07 06:06:15 +04:00
wmove ( buf - > win , buf - > cursor_y , buf - > cursor_x ) ;
2012-08-09 07:06:13 +04:00
wcursyncup ( buf - > win ) ;
wsyncup ( buf - > win ) ;
untouchwin ( buf - > win ) ;
2012-08-07 06:06:15 +04:00
}
void hexedit_refresh ( struct hexedit * buf )
{
size_t end ;
size_t lineno ;
size_t off ;
werase ( buf - > win ) ;
2012-08-20 06:11:16 +04:00
if ( buf - > len = = 0 ) {
mvwprintw ( buf - > win , 0 , 0 , " %08X " , 0 ) ;
return ;
}
2012-08-07 06:06:15 +04:00
end = buf - > offset + bytes_per_screen ( buf - > win ) ;
if ( end > buf - > len ) {
end = buf - > len ;
}
2012-08-19 10:44:59 +04:00
for ( off = buf - > offset , lineno = 0 ;
off < end ;
off + = BYTES_PER_LINE , + + lineno ) {
2012-08-07 06:06:15 +04:00
uint8_t * line = buf - > data + off ;
size_t i , endline ;
wmove ( buf - > win , lineno , 0 ) ;
wprintw ( buf - > win , " %08X " , off ) ;
endline = BYTES_PER_LINE ;
if ( off + BYTES_PER_LINE > buf - > len ) {
endline = buf - > len - off ;
}
for ( i = 0 ; i < endline ; + + i ) {
wprintw ( buf - > win , " %02X " , line [ i ] ) ;
if ( i + 1 < endline ) {
if ( i = = 3 ) {
wprintw ( buf - > win , " " ) ;
} else {
wprintw ( buf - > win , " " ) ;
}
}
}
wmove ( buf - > win , lineno , ASCII_COL ) ;
for ( i = 0 ; i < endline ; + + i ) {
if ( isprint ( line [ i ] ) ) {
waddch ( buf - > win , line [ i ] ) ;
} else {
waddch ( buf - > win , ' . ' ) ;
}
}
}
}
static void calc_cursor_offset ( struct hexedit * buf )
{
2012-08-19 10:44:59 +04:00
buf - > cursor_offset = buf - > offset + buf - > cursor_y * BYTES_PER_LINE +
buf - > cursor_line_offset ;
2012-08-07 06:06:15 +04:00
}
static int offset_to_hex_col ( size_t pos )
{
switch ( pos ) {
case 0 :
return HEX_COL1 ;
case 1 :
return HEX_COL1 + 3 ;
case 2 :
return HEX_COL1 + 6 ;
case 3 :
return HEX_COL1 + 9 ;
case 4 :
return HEX_COL2 ;
case 5 :
return HEX_COL2 + 3 ;
case 6 :
return HEX_COL2 + 6 ;
case 7 :
return HEX_COL2 + 9 ;
}
return - 1 ;
}
static bool scroll_up ( struct hexedit * buf )
{
if ( buf - > offset = = 0 ) {
return false ;
}
buf - > offset - = BYTES_PER_LINE ;
return true ;
}
static void cursor_down ( struct hexedit * buf )
{
2014-08-10 00:39:59 +04:00
size_t space ;
bool need_refresh = false ;
space = buf - > offset + ( buf - > cursor_y + 1 ) * BYTES_PER_LINE ;
if ( space > buf - > len ) {
return ;
}
2012-08-07 06:06:15 +04:00
if ( buf - > cursor_y + 1 = = max_rows ( buf - > win ) ) {
2014-08-10 00:39:59 +04:00
buf - > offset + = BYTES_PER_LINE ;
need_refresh = true ;
2012-08-07 06:06:15 +04:00
} else {
buf - > cursor_y + + ;
}
2014-08-10 00:39:59 +04:00
if ( buf - > cursor_offset + BYTES_PER_LINE > buf - > len ) {
buf - > nibble = 0 ;
buf - > cursor_offset = buf - > len ;
buf - > cursor_line_offset = buf - > len - space ;
if ( buf - > cursor_x > = ASCII_COL ) {
buf - > cursor_x = ASCII_COL + buf - > cursor_line_offset ;
} else {
buf - > cursor_x = offset_to_hex_col ( buf - > cursor_line_offset ) ;
}
}
if ( need_refresh ) {
hexedit_refresh ( buf ) ;
}
2012-08-07 06:06:15 +04:00
calc_cursor_offset ( buf ) ;
}
static void cursor_up ( struct hexedit * buf )
{
if ( buf - > cursor_y = = 0 ) {
if ( scroll_up ( buf ) ) {
hexedit_refresh ( buf ) ;
}
} else {
buf - > cursor_y - - ;
}
calc_cursor_offset ( buf ) ;
}
static bool is_over_gap ( struct hexedit * buf )
{
int col ;
if ( buf - > cursor_x < ASCII_COL ) {
if ( buf - > cursor_x > = HEX_COL2 ) {
col = buf - > cursor_x - HEX_COL2 ;
} else {
col = buf - > cursor_x - HEX_COL1 ;
}
switch ( col ) {
case 2 :
case 5 :
case 8 :
return true ;
}
}
return false ;
}
static void cursor_left ( struct hexedit * buf )
{
if ( buf - > cursor_x = = HEX_COL1 ) {
return ;
}
if ( buf - > cursor_x = = HEX_COL2 ) {
buf - > cursor_x = HEX_COL1_END - 1 ;
buf - > cursor_line_offset = 3 ;
buf - > nibble = 1 ;
} else if ( buf - > cursor_x = = ASCII_COL ) {
size_t off = buf - > offset + buf - > cursor_y * BYTES_PER_LINE ;
if ( off + 7 > = buf - > len ) {
2014-08-10 00:39:59 +04:00
size_t lastpos = buf - > len - off ;
2012-08-07 06:06:15 +04:00
buf - > cursor_x = offset_to_hex_col ( lastpos ) + 1 ;
buf - > cursor_line_offset = lastpos ;
} else {
buf - > cursor_x = HEX_COL2_END - 1 ;
buf - > cursor_line_offset = 7 ;
}
buf - > nibble = 1 ;
} else {
if ( buf - > cursor_x > ASCII_COL | | buf - > nibble = = 0 ) {
buf - > cursor_line_offset - - ;
}
buf - > cursor_x - - ;
buf - > nibble = ! buf - > nibble ;
}
if ( is_over_gap ( buf ) ) {
buf - > cursor_x - - ;
}
calc_cursor_offset ( buf ) ;
}
static void cursor_right ( struct hexedit * buf )
{
int new_x = buf - > cursor_x + 1 ;
if ( new_x = = ASCII_COL_END ) {
return ;
}
if ( ( buf - > cursor_x > = ASCII_COL | | buf - > nibble = = 1 ) & &
2014-08-10 00:39:59 +04:00
buf - > cursor_offset = = buf - > len ) {
2012-08-07 06:06:15 +04:00
if ( buf - > cursor_x < ASCII_COL ) {
new_x = ASCII_COL ;
buf - > cursor_line_offset = 0 ;
buf - > nibble = 0 ;
} else {
return ;
}
}
if ( new_x = = HEX_COL1_END ) {
new_x = HEX_COL2 ;
buf - > cursor_line_offset = 4 ;
buf - > nibble = 0 ;
} else if ( new_x = = HEX_COL2_END ) {
new_x = ASCII_COL ;
buf - > cursor_line_offset = 0 ;
buf - > nibble = 0 ;
} else {
if ( buf - > cursor_x > = ASCII_COL | | buf - > nibble = = 1 ) {
buf - > cursor_line_offset + + ;
}
buf - > nibble = ! buf - > nibble ;
}
buf - > cursor_x = new_x ;
if ( is_over_gap ( buf ) ) {
buf - > cursor_x + + ;
}
calc_cursor_offset ( buf ) ;
}
static void do_edit ( struct hexedit * buf , int c )
{
uint8_t * byte ;
2014-08-10 00:39:59 +04:00
if ( buf - > cursor_offset = = buf - > len ) {
hexedit_resize_buffer ( buf , buf - > len + 1 ) ;
}
2012-08-07 06:06:15 +04:00
byte = buf - > data + buf - > cursor_offset ;
if ( buf - > cursor_x > = ASCII_COL ) {
* byte = ( uint8_t ) c ;
mvwprintw ( buf - > win , buf - > cursor_y ,
offset_to_hex_col ( buf - > cursor_line_offset ) , " %X " , c ) ;
if ( ! isprint ( c ) ) {
c = ' . ' ;
}
2012-08-19 10:44:59 +04:00
mvwaddch ( buf - > win , buf - > cursor_y ,
ASCII_COL + buf - > cursor_line_offset , c ) ;
2014-08-10 00:39:59 +04:00
if ( buf - > cursor_x + 1 ! = ASCII_COL_END ) {
cursor_right ( buf ) ;
} else {
cursor_down ( buf ) ;
}
2012-08-07 06:06:15 +04:00
} else {
if ( ! isxdigit ( c ) ) {
return ;
}
c = toupper ( c ) ;
waddch ( buf - > win , c ) ;
if ( isdigit ( c ) ) {
c = c - ' 0 ' ;
} else {
c = c - ' A ' + 10 ;
}
if ( buf - > nibble = = 0 ) {
* byte = ( * byte & 0x0f ) | c < < 4 ;
} else {
* byte = ( * byte & 0xf0 ) | c ;
}
c = * byte ;
if ( ! isprint ( c ) ) {
c = ' . ' ;
}
2012-08-19 10:44:59 +04:00
mvwaddch ( buf - > win , buf - > cursor_y ,
ASCII_COL + buf - > cursor_line_offset , c ) ;
2012-08-07 06:06:15 +04:00
if ( buf - > cursor_x + 1 ! = HEX_COL2_END ) {
cursor_right ( buf ) ;
2014-08-10 00:39:59 +04:00
} else {
cursor_down ( buf ) ;
2012-08-07 06:06:15 +04:00
}
}
2014-08-10 00:39:59 +04:00
hexedit_refresh ( buf ) ;
2012-08-07 06:06:15 +04:00
}
2014-08-10 04:11:00 +04:00
static void erase_at ( struct hexedit * buf , size_t pos )
{
if ( pos > = buf - > len ) {
return ;
}
if ( pos < buf - > len - 1 ) {
/* squeeze the character out of the buffer */
uint8_t * p = buf - > data + pos ;
uint8_t * end = buf - > data + buf - > len ;
memmove ( p , p + 1 , end - p - 1 ) ;
}
buf - > len - - ;
hexedit_refresh ( buf ) ;
}
static void do_backspace ( struct hexedit * buf )
{
size_t off ;
2014-11-13 11:12:56 +03:00
bool do_erase = true ;
2014-08-10 04:11:00 +04:00
if ( buf - > cursor_offset = = 0 ) {
return ;
}
off = buf - > cursor_offset ;
if ( buf - > cursor_x = = ASCII_COL ) {
cursor_up ( buf ) ;
buf - > cursor_line_offset = 7 ;
buf - > cursor_x = ASCII_COL_END - 1 ;
calc_cursor_offset ( buf ) ;
} else if ( buf - > cursor_x = = HEX_COL1 ) {
cursor_up ( buf ) ;
buf - > cursor_line_offset = 7 ;
buf - > cursor_x = HEX_COL2_END - 1 ;
buf - > nibble = 1 ;
calc_cursor_offset ( buf ) ;
} else {
if ( buf - > cursor_x < ASCII_COL & & buf - > nibble ) {
2014-11-13 11:12:56 +03:00
do_erase = false ;
2014-08-10 04:11:00 +04:00
}
cursor_left ( buf ) ;
}
2014-11-13 11:12:56 +03:00
if ( do_erase ) {
2014-08-10 04:11:00 +04:00
erase_at ( buf , off - 1 ) ;
}
}
static void do_delete ( struct hexedit * buf )
{
erase_at ( buf , buf - > cursor_offset ) ;
}
2012-08-07 06:06:15 +04:00
void hexedit_driver ( struct hexedit * buf , int c )
{
switch ( c ) {
case HE_CURSOR_UP :
cursor_up ( buf ) ;
break ;
case HE_CURSOR_DOWN :
cursor_down ( buf ) ;
break ;
case HE_CURSOR_LEFT :
cursor_left ( buf ) ;
break ;
case HE_CURSOR_RIGHT :
cursor_right ( buf ) ;
break ;
case HE_CURSOR_PGUP :
break ;
case HE_CURSOR_PGDN :
break ;
2014-08-10 04:11:00 +04:00
case HE_BACKSPACE :
do_backspace ( buf ) ;
break ;
case HE_DELETE :
do_delete ( buf ) ;
break ;
2012-08-07 06:06:15 +04:00
default :
do_edit ( buf , c & 0xff ) ;
break ;
}
2014-07-26 10:16:52 +04:00
hexedit_set_cursor ( buf ) ;
2012-08-07 06:06:15 +04:00
}
WERROR hexedit_resize_buffer ( struct hexedit * buf , size_t newsz )
{
/* reset the cursor if it'll be out of bounds
after the resize */
2014-08-10 00:39:59 +04:00
if ( buf - > cursor_offset > newsz ) {
2012-08-07 06:06:15 +04:00
buf - > cursor_y = 0 ;
buf - > cursor_x = HEX_COL1 ;
buf - > offset = 0 ;
buf - > cursor_offset = 0 ;
buf - > cursor_line_offset = 0 ;
buf - > nibble = 0 ;
}
if ( newsz > buf - > len ) {
if ( newsz > buf - > alloc_size ) {
uint8_t * d ;
2014-08-10 00:39:59 +04:00
buf - > alloc_size * = 2 ;
if ( newsz > buf - > alloc_size ) {
buf - > alloc_size = newsz ;
}
d = talloc_realloc ( buf , buf - > data , uint8_t ,
buf - > alloc_size ) ;
2012-08-07 06:06:15 +04:00
if ( d = = NULL ) {
2015-12-03 17:24:17 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-08-07 06:06:15 +04:00
}
buf - > data = d ;
}
memset ( buf - > data + buf - > len , ' \0 ' , newsz - buf - > len ) ;
buf - > len = newsz ;
} else {
buf - > len = newsz ;
}
return WERR_OK ;
}