1
1
mc/src/viewer/hex.c
2009-12-30 11:06:09 +02:00

350 строки
12 KiB
C

/*
Internal file viewer for the Midnight Commander
Function for hex view
Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
Written by: 1994, 1995, 1998 Miguel de Icaza
1994, 1995 Janne Kukonlehto
1995 Jakub Jelinek
1996 Joseph M. Hinkle
1997 Norbert Warmuth
1998 Pavel Machek
2004 Roland Illig <roland.illig@gmx.de>
2005 Roland Illig <roland.illig@gmx.de>
2009 Slava Zanko <slavazanko@google.com>
2009 Andrew Borodin <aborodin@vmail.ru>
2009 Ilia Maslakov <il.smind@gmail.com>
This file is part of the Midnight Commander.
The Midnight Commander 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 2 of the
License, or (at your option) any later version.
The Midnight Commander 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
*/
#include <config.h>
#include <errno.h>
#include <fcntl.h>
#include "../src/global.h"
#include "../src/tty/tty.h"
#include "../src/skin/skin.h"
#include "../src/main.h"
#include "../src/wtools.h"
#include "../src/charsets.h"
#include "../../vfs/vfs.h"
#include "internal.h"
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
typedef enum {
MARK_NORMAL,
MARK_SELECTED,
MARK_CURSOR,
MARK_CHANGED
} mark_t;
/*** file scope variables ************************************************************************/
static const char hex_char[] = "0123456789ABCDEF";
/*** file scope functions ************************************************************************/
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
void
mcview_display_hex (mcview_t * view)
{
const screen_dimen top = view->data_area.top;
const screen_dimen left = view->data_area.left;
const screen_dimen height = view->data_area.height;
const screen_dimen width = view->data_area.width;
const int ngroups = view->bytes_per_line / 4;
const screen_dimen text_start = 8 + 13 * ngroups + ((width < 80) ? 0 : (ngroups - 1 + 1));
/* 8 characters are used for the file offset, and every hex group
* takes 13 characters. On ``big'' screens, the groups are separated
* by an extra vertical line, and there is an extra space before the
* text column.
*/
screen_dimen row, col;
off_t from;
int c;
mark_t boldflag = MARK_NORMAL;
struct hexedit_change_node *curr = view->change_list;
size_t i;
int ch = 0;
char hex_buff[10]; /* A temporary buffer for sprintf and mvwaddstr */
int bytes; /* Number of bytes already printed on the line */
mcview_display_clean (view);
/* Find the first displayable changed byte */
from = view->dpy_start;
while (curr && (curr->offset < from)) {
curr = curr->next;
}
for (row = 0; mcview_get_byte (view, from, NULL) == TRUE && row < height; row++) {
col = 0;
/* Print the hex offset */
g_snprintf (hex_buff, sizeof (hex_buff), "%08" OFFSETTYPE_PRIX " ",
(long unsigned int) from);
widget_move (view, top + row, left);
tty_setcolor (MARKED_COLOR);
for (i = 0; col < width && hex_buff[i] != '\0'; i++) {
tty_print_char (hex_buff[i]);
/* tty_print_char(hex_buff[i]);*/
col += 1;
}
tty_setcolor (NORMAL_COLOR);
for (bytes = 0; bytes < view->bytes_per_line; bytes++, from++) {
#ifdef HAVE_CHARSET
if (view->utf8) {
int cw = 1;
gboolean read_res = TRUE;
ch = mcview_get_utf (view, from, &cw, &read_res);
if (!read_res)
break;
}
#endif
if (! mcview_get_byte (view, from, &c))
break;
/* Save the cursor position for mcview_place_cursor() */
if (from == view->hex_cursor && !view->hexview_in_text) {
view->cursor_row = row;
view->cursor_col = col;
}
/* Determine the state of the current byte */
boldflag =
(from == view->hex_cursor) ? MARK_CURSOR
: (curr != NULL && from == curr->offset) ? MARK_CHANGED
: (view->search_start <= from &&
from < view->search_end) ? MARK_SELECTED : MARK_NORMAL;
/* Determine the value of the current byte */
if (curr != NULL && from == curr->offset) {
c = curr->value;
curr = curr->next;
}
/* Select the color for the hex number */
tty_setcolor (boldflag == MARK_NORMAL ? NORMAL_COLOR :
boldflag == MARK_SELECTED ? MARKED_COLOR :
boldflag == MARK_CHANGED ? VIEW_UNDERLINED_COLOR :
/* boldflag == MARK_CURSOR */
view->hexview_in_text ? MARKED_SELECTED_COLOR : VIEW_UNDERLINED_COLOR);
/* Print the hex number */
widget_move (view, top + row, left + col);
if (col < width) {
tty_print_char (hex_char[c / 16]);
col += 1;
}
if (col < width) {
tty_print_char (hex_char[c % 16]);
col += 1;
}
/* Print the separator */
tty_setcolor (NORMAL_COLOR);
if (bytes != view->bytes_per_line - 1) {
if (col < width) {
tty_print_char (' ');
col += 1;
}
/* After every four bytes, print a group separator */
if (bytes % 4 == 3) {
if (view->data_area.width >= 80 && col < width) {
tty_print_one_vline ();
col += 1;
}
if (col < width) {
tty_print_char (' ');
col += 1;
}
}
}
/* Select the color for the character; this differs from the
* hex color when boldflag == MARK_CURSOR */
tty_setcolor (boldflag == MARK_NORMAL ? NORMAL_COLOR :
boldflag == MARK_SELECTED ? MARKED_COLOR :
boldflag == MARK_CHANGED ? VIEW_UNDERLINED_COLOR :
/* boldflag == MARK_CURSOR */
view->hexview_in_text ? VIEW_UNDERLINED_COLOR : MARKED_SELECTED_COLOR);
#ifdef HAVE_CHARSET
if (utf8_display) {
if (!view->utf8) {
ch = convert_from_8bit_to_utf_c ((unsigned char) ch, view->converter);
}
if (!g_unichar_isprint (ch))
ch = '.';
} else {
if (view->utf8) {
ch = convert_from_utf_to_current_c (ch, view->converter);
} else {
#endif
ch = convert_to_display_c (ch);
#ifdef HAVE_CHARSET
}
}
#endif
c = convert_to_display_c (c);
if (!g_ascii_isprint (c))
c = '.';
/* Print corresponding character on the text side */
if (text_start + bytes < width) {
widget_move (view, top + row, left + text_start + bytes);
if (!view->utf8) {
tty_print_char (c);
} else {
tty_print_anychar (ch);
}
}
/* Save the cursor position for mcview_place_cursor() */
if (from == view->hex_cursor && view->hexview_in_text) {
view->cursor_row = row;
view->cursor_col = text_start + bytes;
}
}
}
/* Be polite to the other functions */
tty_setcolor (NORMAL_COLOR);
mcview_place_cursor (view);
view->dpy_end = from;
}
/* --------------------------------------------------------------------------------------------- */
gboolean
mcview_hexedit_save_changes (mcview_t * view)
{
struct hexedit_change_node *curr, *next;
int fp, answer;
char *text, *error;
if (view->change_list == NULL)
return TRUE;
retry_save:
assert (view->filename != NULL);
fp = mc_open (view->filename, O_WRONLY);
if (fp == -1)
goto save_error;
for (curr = view->change_list; curr != NULL; curr = next) {
next = curr->next;
if (mc_lseek (fp, curr->offset, SEEK_SET) == -1 || mc_write (fp, &(curr->value), 1) != 1)
goto save_error;
/* delete the saved item from the change list */
view->change_list = next;
view->dirty++;
mcview_set_byte (view, curr->offset, curr->value);
g_free (curr);
}
if (mc_close (fp) == -1) {
error = g_strdup (strerror (errno));
message (D_ERROR, _(" Save file "),
_(" Error while closing the file: \n %s \n"
" Data may have been written or not. "), error);
g_free (error);
}
mcview_update (view);
return TRUE;
save_error:
error = g_strdup (strerror (errno));
text = g_strdup_printf (_(" Cannot save file: \n %s "), error);
g_free (error);
(void) mc_close (fp);
answer = query_dialog (_(" Save file "), text, D_ERROR, 2, _("&Retry"), _("&Cancel"));
g_free (text);
if (answer == 0)
goto retry_save;
return FALSE;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_toggle_hexedit_mode (mcview_t * view)
{
view->hexedit_mode = !view->hexedit_mode;
view->dpy_bbar_dirty = TRUE;
view->dirty++;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_hexedit_free_change_list (mcview_t * view)
{
struct hexedit_change_node *curr, *next;
for (curr = view->change_list; curr != NULL; curr = next) {
next = curr->next;
g_free (curr);
}
view->change_list = NULL;
view->dirty++;
}
/* --------------------------------------------------------------------------------------------- */
void
mcview_enqueue_change (struct hexedit_change_node **head, struct hexedit_change_node *node)
{
/* chnode always either points to the head of the list or
* to one of the ->next fields in the list. The value at
* this location will be overwritten with the new node. */
struct hexedit_change_node **chnode = head;
while (*chnode != NULL && (*chnode)->offset < node->offset)
chnode = &((*chnode)->next);
node->next = *chnode;
*chnode = node;
}
/* --------------------------------------------------------------------------------------------- */